是否可以通过 COM 互操作转发委托

本文关键字:转发 互操作 可以通过 COM 是否 | 更新日期: 2023-09-27 18:33:00

我有一个类:

public class A
{
public delegate void SetTextDel(string value);
public void Test()
{
      SetTextDel setText = someInterface.SetText;
      icom.Set(setText);
}
}
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"),   InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface Icom
    {
        void Set(Delegate del);
    }
[ComVisible(true)]
    [Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(Icom))]
    public class B : Icom
    {
         Set(Delegate del)
         {
              del.DynamicInvoke("some text");
         }
    }

并且我在 Set(委托 del)中得到目标调用异常。有没有更好的方法将委托作为参数转发?或者我在这里犯了一些我没有看到的错误。我试图做的是将someInterface.SetText此方法作为参数传递。感谢您的帮助。

是否可以通过 COM 互操作转发委托

以下作品:

public class A
{
    public delegate void SetTextDel(string value);
    void TestSetText(string value)
    {
        MessageBox.Show(value);
    }
    public void Test(Icom icom)
    {
        SetTextDel del = TestSetText;
        icom.Set(del);
    }
}
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Icom
{
    void Set(Delegate del);
}
[ComVisible(true)]
[Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(Icom))]
public class B : Icom
{
    public void Set(Delegate del)
    {
        del.DynamicInvoke("some text");
    }
}
private void buttonTest_Click(object sender, EventArgs e)
{
    var a = new A();
    var b = new B();
    a.Test(b);
}

接下来,如果您希望将回调函数从 C++ 传递Icom.Set ,以下内容也可以工作:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void SetTextDel([MarshalAs(UnmanagedType.BStr)] string value);
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Icom
{
    void Set([MarshalAs(UnmanagedType.FunctionPtr)] SetTextDel del);
}
[ComVisible(true)]
[Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(Icom))]
public class B : Icom
{
    public void Set(SetTextDel del)
    {
        del("some text");
    }
}

请确保将 C# 和C++项目编译为 32 位代码。C++回调函数应声明如下:

static HRESULT __stdcall SetTextDelCallback(BSTR value)
{
    return S_OK;
}

最后,实现这一点的正确方法是IMO,只需定义一个回调接口(如下ISetCallback),并传递实现此类接口的对象,而不是委托。 ISetCallback可以用任何语言实现,可以是 C# 还是C++:

[ComVisible(true), Guid("2FE5D78D-D9F2-4236-9626-226356BA25E7")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISetCallback
{
    void OnSetText(string value);
}
public class A : ISetCallback
{
    public void OnSetText(string value) // ISetCallback
    {
        MessageBox.Show(value);
    }
    public void Test(Icom icom)
    {
        icom.Set(this);
    }
}
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Icom
{
    void Set(ISetCallback callback);
}
[ComVisible(true)]
[Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(Icom))]
public class B : Icom
{
    public void Set(ISetCallback callback)
    {
        callback.OnSetText("some text");
    }
}
private void buttonTest_Click(object sender, EventArgs e)
{
    var a = new A();
    var b = new B();
    a.Test(b);
}