如何实现并注册一个COM回调(How to Implement and Register to a

2019-10-20 04:01发布

我试图创建一个COM接口,允许回调从COM调用代码。 我似乎无法找到C#这方面的任何适当的解释。

我有一个正常的COM接口的工作,但我不知道如何正确地注册并建立回调的一部分。

我无法找到如何做到这一点适当的在C#中的任何信息,因为大多数谷歌搜索词我能拿出包括“COM”只会导致.COM网站,不包括实际的COM接口谈论回调时和事件,他们只包括默认非COM的。 任何帮助,将不胜感激,哪怕它只是指出在那里我能找到更好的,更有用的信息来源。

我的回调接口看起来是这样的:

using System;
using System.Runtime.InteropServices;

namespace ComAdapter
{
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [Guid("7f176b75-7b66-463a-94ab-493943792f88")]
    public interface INet40Callback
    {
        [PreserveSig]
        void Callback(string data);
    }
}

回调类我想是这样的:

using net40lib;
using System;
using System.Runtime.InteropServices;

namespace ComAdapter
{
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(INet40Callback))]
    [Guid("023e4ad9-77d1-461e-af89-4cfc2b53959c")]
    public class Net40Callback : INet40CallbackRegistration
    {
        [ComVisible(false)]
        public delegate void MyCallbackDelegate(string data);

        public event MyCallbackDelegate Callback;

        public INet40Callback callbackObject;

        public Net40Callback()
        {
            Net40Class.Instance.VersionSent += Instance_VersionSent;
        }

        void Instance_VersionSent(object sender, EventArgs e)
        {
            if (callbackObject != null)
            {
                callbackObject.Callback("blah");
            }

            if (Callback != null)
            {
                Console.WriteLine("Instance_VersionSent Sending Callback");
                Callback("blah");
            }
        }

        public void RegisterCallback(INet40Callback reg)
        {
            if (reg is INet40Callback)
            {
                callbackObject = reg as INet40Callback;
            }
        }
    }
}

调用应用程序,到目前为止是这样的:

using ComAdapter;
using System;
using System.Runtime.InteropServices;

namespace net20lib
{
    class Net40Callback : INet40Callback
    {
        [PreserveSig] 
        public void Callback(string data)
        {
            Console.WriteLine("Callback Called with data {0}", data);
        }
    }
}

注册:

using System;
using System.Runtime.InteropServices;

namespace ComAdapter
{
    [ComVisible(true)]
    [Guid("3b2ab267-9e9a-47be-ab0a-f55db10a971e")]
    public interface INet40CallbackRegistration
    {
        void RegisterCallback(INet40Callback callback);
    }
}

从测试类中的呼唤:接口的实现:

internal class Net40Callback : INet40Callback
{
  [PreserveSig]
  public void Callback(string data)
  {
      Console.WriteLine("Callback Called with data {0}", data);
  }
}

该代码登记:

INet40Callback callback = new Net40Callback();

Type myCallbackType = Type.GetTypeFromProgID("ComAdapter.Net40Callback");
object myCallbackInstance = Activator.CreateInstance(myCallbackType);
INet40CallbackRegistration registration = (INet40CallbackRegistration)myCallbackInstance;
registration.RegisterCallback(callback);

Answer 1:

你真的不应该从C#COM客户测试C#COM服务器,这不是它的工作原理,当它从非托管代码调用。 然后,你就不会需要保持一个参考INet40Callback ,该event的声明应该够COM客户端挂接通过事件IConnectionPointContainer (使用RegAsm生成的类型库)。 除非你真的想支持这两个选项。

总之,让你的当前代码的工作,尝试添加[ComVisible(true)] ,以Net40Callback[ComImport]INet40Callback

[ComImport]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("7f176b75-7b66-463a-94ab-493943792f88")]
public interface INet40Callback
{
    // ..
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]]
[ComDefaultInterface(typeof(INet40Callback))]
internal class Net40Callback : INet40Callback
{
    // ...
}

更新 ,你不需要改变太多C#的方面,除了去掉public INet40Callback callbackObject参考。 但是,你需要一个托管COM客户端来测试事件。 它可以是一个普通的C ++ COM的应用程序,一个ATL / MFC C ++的应用程序,一个VB6应用程序,或甚至一个HTML应用程序(.HTA文件与<object>标记内)。 下面是后者(未测试)的示例。 把它复制到test.hta运行从Windows资源管理器文件:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "">
<html>
<head>
    <title>Managed COM Object Test</title>

    <object id="managedObject"
        classid="clsid:023e4ad9-77d1-461e-af89-4cfc2b53959c"
        codebase="#version=0,0,0,0">
    </object>

    <script for="managedObject" event="Callback(data)" type="text/javascript">
        output.innerText = "Callback(" + data + ") fired";
    </script>
</head>

<body>
    <div id="output">&nbsp;</div>
</body>
</html>


文章来源: How to Implement and Register to a COM Callback
标签: c# com callback