C# COM+ 服务无法接受来自 C# 客户端的事件注册

问题描述

基本上,我有一个 C++ ATL DCOM 服务,我试图用 C# COM+ 服务替换它,但在尝试注册我的事件时遇到了问题。我能够通过以下示例重现该问题

MyInterface.idl:

import "oaidl.idl";
import "ocidl.idl";

[
    object,uuid(993D13F8-5752-4046-9179-3BABD1513A8F),pointer_default(unique)
]
interface MyInterface : Idispatch
{
    HRESULT MyFunc1([in] BSTR lid);
};
[
    uuid(841E7E02-2ED3-412B-928B-F9C01CE300CE),version(1.0)
]
library MyInterfaceLibrary
{
    importlib("stdole2.tlb");

    [
        uuid(6BFA2661-5286-4C7A-973B-5BD14A654B6D)
    ]
    dispinterface MyInterfaceEvents
    {
        properties:
        methods:
            [id(1)] HRESULT MyEvent1([in] BSTR message);
    };
    [
        uuid(0E10489A-4BD0-47FF-9739-843DF8072B0E)
    ]
    coclass MyInterfaceImpl
    {
        [default] interface MyInterface;
        [default,source] dispinterface MyInterfaceEvents;
    };
};

我使用这个 IDL 来生成我的 C++ 和 .Net 互操作库。互操作库经过 GAC 处理,并且据我所知,本机 DLL 已注册正常。

MyComServerCPP.h:

#pragma once

#include "resource.h"       // main symbols
#include "MyInterface.h"
#include "_MyInterfaceEvents_CP.h"

using namespace ATL;

class ATL_NO_VTABLE CMyComServer :
    public CComObjectRootEx<CComMultiThreadModel>,public CComCoClass<CMyComServer,&CLSID_MyInterfaceImpl>,public ISupportErrorInfo,public IConnectionPointContainerImpl<CMyComServer>,public CProxy_MyInterfaceEvents<CMyComServer>,public IdispatchImpl<MyInterface,&IID_MyInterface,&LIBID_MyInterfaceLibrary,1,0>,public IProvideClassInfo2Impl<&__uuidof(MyInterfaceImpl),&__uuidof(MyInterfaceEvents)>
{
public:
    CMyComServer()
    {
    }

    DECLARE_REGISTRY_RESOURCEID(IDR_MYINTERFACEIMPL)
    DECLARE_CLASSFACTORY_SINGLetoN(CMyComServer)

    BEGIN_COM_MAP(CMyComServer)
        COM_INTERFACE_ENTRY(MyInterface)
        COM_INTERFACE_ENTRY(Idispatch)
        COM_INTERFACE_ENTRY(ISupportErrorInfo)
        COM_INTERFACE_ENTRY(IConnectionPointContainer)
        COM_INTERFACE_ENTRY(IProvideClassInfo2)
        COM_INTERFACE_ENTRY(IProvideClassInfo)
    END_COM_MAP()

    BEGIN_CONNECTION_POINT_MAP(CMyComServer)
        CONNECTION_POINT_ENTRY(__uuidof(MyInterfaceEvents))
    END_CONNECTION_POINT_MAP()
    
    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

    STDMETHOD(MyFunc1)(BSTR message);
};

OBJECT_ENTRY_AUTO(__uuidof(MyInterfaceImpl),CMyComServer);

这类似于我的 C++ ATL DCOM 服务的设置方式,这在我的测试中仍然有效。

MyComServer.cs:

using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

using MyExample.Interop;

namespace MyExample
{
    [ComVisible(true)]
    [Guid("7A41F23E-B73A-40E4-A1B7-54B120B5923E")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(MyInterfaceEvents))]
    [ProgId("MyExample.MyComServer")]
    public class MyComServer : ServicedComponent,MyInterface,MyInterfaceEvents_Event
    {
        public event MyInterfaceEvents_MyEvent1EventHandler MyEvent1;

        public void MyFunc1(string message)
        {
            MyEvent1?.Invoke("MyComServer: " + message);
        }
    }
}

这是我的 C# COM+ 服务不起作用。每当我尝试在下面的客户端中注册我的事件处理程序时,它都会给我这个错误

An Exception was encountered: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'MyComClient,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName,String codeBase,Evidence assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark& stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName,Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef,RuntimeAssembly reqAssembly,Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString,Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString,Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.Runtime.Serialization.FormatterServices.LoadAssemblyFromString(String assemblyName)
   at System.Reflection.memberinfoserializationHolder..ctor(SerializationInfo info,StreamingContext context)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.SerializationInvoke(IRuntimeMethodInfo method,Object target,SerializationInfo info,StreamingContext& context)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj,StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler,__BinaryParser serParser,Boolean fCheck,Boolean isCrossAppDomain,IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream,HeaderHandler handler,IMethodCallMessage methodCallMessage)
   at System.EnterpriseServices.ComponentSerializer.UnmarshalFromBuffer(Byte[] b,Object tp)
   at System.EnterpriseServices.ComponentServices.ConvertToMessage(String s,Object tp)
   at System.EnterpriseServices.ServicedComponent.RemotedispatchHelper(String s,Boolean& Failed)
   at System.EnterpriseServices.ServicedComponent.System.EnterpriseServices.IRemotedispatch.RemotedispatchNotAutodone(String s)
   at System.EnterpriseServices.IRemotedispatch.RemotedispatchNotAutodone(String s)
   at System.EnterpriseServices.RemoteServicedComponentProxy.Invoke(IMessage reqMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData,Int32 type)
   at MyExample.Interop.MyInterfaceEvents_Event.add_MyEvent1(MyInterfaceEvents_MyEvent1EventHandler )
   at MyExample.Program.Main(String[] args) in C:\Users\zzsupport\source\repos\MyExample\MyComClient\Program.cs:line 19

MyComClient.cs:

using System;

using MyExample.Interop;

namespace MyExample
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Type t = Type.GetTypeFromProgID(@"MyExample.MyComServer",true);
                //Type t = Type.GetTypeFromProgID(@"MyExample.MyComServerCPP",true);
                MyInterface instance = (MyInterface)Activator.CreateInstance(t);

                MyInterfaceEvents_Event ev = (MyInterfaceEvents_Event)instance;

                ev.MyEvent1 += Ev_MyEvent1;

                System.Threading.Thread.Sleep(1000);

                instance.MyFunc1("Hello?");
            }
            catch (Exception ex)
            {
                Console.WriteLine("An Exception was encountered: " + ex);
            }

            Console.WriteLine("Press Enter to continue...");
            Console.ReadLine();
        }

        private static void Ev_MyEvent1(string message)
        {
            Console.WriteLine("Ev_MyEvent1: " + message);
        }
    }
}

我觉得我遗漏了一些明显的东西,但我还没有弄清楚。有什么建议吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)