如何实现和注册到COM回调 [英] How to Implement and Register to a COM Callback

查看:120
本文介绍了如何实现和注册到COM回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个COM接口,允许从COM回调到调用代码。我在C#中似乎找不到任何正确的解释。

I'm trying to create a COM interface that allows for Callback from the COM to the calling code. I can't seem to find any proper explanation for this in C#.

我有一个正常的COM接口工作,但我不知道如何正确地注册和设置

I got a normal COM interface working, but I don't know how to properly register and set up the callback part.

我在C#中找不到任何有关如何正确地这样做的信息,因为大多数google搜索项我可以想出包括com 只导致.com网站,并且在谈论回调和事件时不包括实际的com接口,它们只包括默认的非com。任何帮助将不胜感激,即使它只是指出一个来源,我可以找到更好,更有用的信息。

I can't find any information on how to do this properly in C#, as most google search terms I can come up with that include "com" only lead to .com sites, and don't include actual com interfaces when talking about callbacks and events, they only include the default non-com ones. Any help would be appreciated, even if it's just pointing out to a source where I can find better, more helpful information.

我的回调接口如下所示:

My Callback Interface looks like this:

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);
    }
}

回调类我试着看起来像这样: / p>

The Callback class I tried to look like this:

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;
            }
        }
    }
}

调用应用程序到目前为止:

The calling application so far looks like this:

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);
    }
}

测试类的调用:
执行接口:

The Call from the Test Class: The implementation of the interface:

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);


推荐答案

你真的不应该测试C# C#COM客户端,这是不是它的工作原理,当它从非托管代码调用。然后你不需要保存对 INet40Callback 的引用,事件声明应该足以让COM客户端通过 IConnectionPointContainer (使用由RegAsm生成的类型库)挂接事件。

You really shouldn't be testing C# COM server from C# COM client, this is not how it works when it's called from unmanaged code. Then you wouldn't need to keep a reference to INet40Callback, the event declarations should be enough for a COM client to hook up events via IConnectionPointContainer (using the type library generated by RegAsm). Unless you really want to support both options.

无论如何,为了使当前代码正常工作,请尝试添加 [ComVisible(true)] Net40Callback [ComImport] INet40Callback

Anyway, to make your current code work, try adding [ComVisible(true)] to Net40Callback and [ComImport] to 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
{
    // ...
}

更新,除了删除 public INet40Callback callbackObject 引用之外,您不需要在C#方面做太​​多改动。但是,您需要一个非托管COM客户端来测试事件。它可以是一个简单的C ++ COM应用程序,ATL / MFC C ++应用程序,VB6应用程序,甚至HTML应用程序(.HTA文件与< object> )。这里是后者(未测试)的示例。将它复制到 test.hta 从Windows资源管理器运行此文件:

Updated, you don't need to change much on the C# side, besides removing the public INet40Callback callbackObject reference. However, you need an unmanaged COM client to test the events. It can be a plain C++ COM app, an ATL/MFC C++ app, a VB6 app, or even an HTML App (.HTA file with an <object> tag inside). Here's an example of the latter (untested). Copy it to test.hta run this file from Windows Explorer:

<!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>

这篇关于如何实现和注册到COM回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆