首页 > 解决方案 > C# COM+ 服务无法接受来自 C# 客户端的事件注册

问题描述

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

我的接口.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 互操作库。据我所知,互操作库是 GACed 并且本机 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, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, 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, SerializationInfo info, 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, Boolean fCheck, Boolean isCrossAppDomain, 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);
        }
    }
}

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

标签: c#c++com+dcom

解决方案


推荐阅读