如何通过 COM 接口调用 C# 方法传递函数指针

Posted

技术标签:

【中文标题】如何通过 COM 接口调用 C# 方法传递函数指针【英文标题】:How pass function pointer by call C# method via COM interfaces 【发布时间】:2012-01-04 14:11:26 【问题描述】:

我有这个用于调用方法 WpfApplication1.NetLauncher.Launch(IntPtr cb) 的 CLI c++ 代码 通过反射:

#include "stdafx.h"

using namespace System;
using namespace System::Reflection;

typedef int (__stdcall *PMyBeep)(); 

int __stdcall MyBeep()

return 123;


[STAThreadAttribute]
int main(array<System::String ^> ^args)


Assembly^ asmbl = Assembly::Load("WpfDemo");
    Type^ type = asmbl->GetType("WpfApplication1.NetLauncher");
Object^ obj = asmbl->CreateInstance("WpfApplication1.NetLauncher");
    MethodInfo^ method = type->GetMethod("Launch");

IntPtr pp=(IntPtr)MyBeep;

   Object^ magicValue = method->Invoke(obj, gcnew array<Object^>(1)pp);


    return 0;

还有c#代码:

namespace WpfApplication1

public class NetLauncher

    delegate int Mydelegate();

    [System.STAThreadAttribute()]

    public int Launch( IntPtr dwData)
    //public int Launch(string path)
    



        Mydelegate codeToRun = null;
        codeToRun = (Mydelegate)Marshal.GetDelegateForFunctionPointer(dwData,     typeof(Mydelegate));


        int res = codeToRun.Invoke();

      // ....
    
  

现在我尝试通过 COM 接口从 Win32 C++ 调用此方法:

    //   ....

    CComPtr<IDispatch> disp = launcher.pdispVal;
DISPID dispid;
OLECHAR FAR* methodName = L"Launch";
hr = disp->GetIDsOfNames(IID_NULL, &methodName, 1, LOCALE_SYSTEM_DEFAULT, &dispid);

    //   ?????  DWORD nData=(DWORD)MyBeep;
   //   ?????  CComVariant *func = new CComVariant(nData);


CComVariant FAR args[] = *func;
DISPPARAMS noArgs = args, NULL, 1, 0;

hr = disp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &noArgs, NULL, NULL, NULL); 

我想我必须将函数指针(MyBeep)保存为 DISPPARAMS 中的 CComVariant,但我不知道怎么做???

【问题讨论】:

你不能只使用 void* 指针,因为你的托管代码无论如何都需要 IntPtr 吗? 你介意吗:CComVariant func = new CComVariant((void)MyBeep); ???它不起作用:( void* 和 IntPtr 都不是 COM 自动化兼容类型。通过不透明指针调用函数从根本上说是不安全且不可移植的。你可以抛开问题,但你不应该首先编写这样的代码。 【参考方案1】:

我不在我的 Windows 机器前...你能帮我试试吗?

DISPPARAMS dispparams; 
memset(&dispparams, 0, sizeof dispparams);
dispparams.cNamedArgs = 0;
dispparams.cArgs = 1;
dispparams.rgvarg = new VARIANTARG[dispparams.cArgs];
dispparams.rgvarg[0].vt =  VT_I4;
dispparams.rgvarg[0].iVal =   reinterpret_cast<int>(MyBeep);

【讨论】:

不幸的是它不起作用:Microsoft C++ 异常:内存位置 0x0019e678 处的 EEResourceException ..

以上是关于如何通过 COM 接口调用 C# 方法传递函数指针的主要内容,如果未能解决你的问题,请参考以下文章

通过非默认 AppDomain 中的 C# 函数调用编组 C++ 指针接口

如何将委托或函数指针从 C# 传递到 C++ 并使用 InternalCall 调用它

从 C++ 传递函数指针以由 C# 调用 - 函数参数包括宽字符字符串 (LPCWSTR)

如何将指向 C# 结构的指针传递给 C 中的方法

c#调用c++的DLL,接口函数参数有函数指针,在线等解决办法

如何从 C# 将双指针传递给 COM 并在 COM 中初始化它