将指向COM接口指针的指针从托管c++传递到.NET c#

Passing a pointer to COM interface pointer from managed c++ to .NET C#

本文关键字:指针 c++ NET COM 接口      更新时间:2023-10-16

我有一个用非托管C++编写的COM Dll,它公开了一个COM接口。idl的琐碎样本如下所示:

import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(A806FAED-FCE2-4F1B-AE67-4B36D398508E),
dual,
nonextensible,
pointer_default(unique)
]
interface IObjectToPass : IDispatch{
[propget, id(1)] HRESULT Name([out, retval] BSTR* pVal);
[propput, id(1)] HRESULT Name([in] BSTR newVal);
};
[
uuid(B99537C0-BEBC-4670-A77E-06AB5350DC23),
version(1.0),
]
library     {
importlib("stdole2.tlb");
[
uuid(FB7C7D08-0E38-40D2-A160-0FC8AE76C3CF)      
]
coclass ObjectToPass
{
[default] interface IObjectToPass;
};
}; 

所以IObjectToPass接口就是暴露的接口。现在我在C#中实现了一个.NET库(ObjectConsumer),它通过tlbimp创建的Interop导入这个COM对象,这样我就可以使用IObjectToPass接口了。下面是这个库的示例代码:

using Interop.ComTest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;ComTestLib
using System.Threading.Tasks;
namespace ObjectConsumer 
{
public class Consumer
{
public void PassObject(IObjectToPass passobj)
{
string str = passobj.Name;
}
}
}

c++和c#模块的编译都没有问题

现在,我在c++中创建了一个简单的控制台应用程序,它支持CLR,可以通过导入导入两个ComTestLib以及Consumer添加了对控制台应用程序项目的引用。我的目标是在控制台应用程序中获得ObjectToPass的实例,并传递给调用公共方法PassObject的使用者,如下所示

#include "stdafx.h"
#import "..DebugComTest.tlb" no_namespace, raw_interfaces_only  
int main()
{
CoInitialize(NULL);
IObjectToPassPtr obj;
HRESULT hr = obj.CreateInstance(__uuidof(IObjectToPass) );
ObjectConsumer::Consumer^ consumer = gcnew ObjectConsumer::Consumer();
obj->put_Name(_T("MyName"));
consumer->PassObject(obj);
CoUninitialize();
return 0;
}

此代码无法编译。编译器无法将参数1从"IObjectToPassPtr"转换为"Interop::ComTest::IObjectToPass ^"。我做了不同的尝试,但IObjectToPass*似乎无法转换为"Interop::ComTest::IObjectToPass^"。有办法做到吗?

跳过COM接口,只导出c++中的工厂函数。

#define MY_API __declspec(dllexport)
#ifdef __cplusplus
#   define EXTERNC    extern "C"
#else
#   define EXTERNC 
#endif
EXTERNC MY_API IObjectToPass* APIENTRY MyFactory(void);
EXTERNC MY_API  void APIENTRY SomeFunction(IObjectToPass* handle);
// Implementation:
MY_API IObjectToPass* APIENTRY MyFactory(void)
{
return new ObjectToPass();
}
MY_API void APIENTRY SomeFunction(IObjectToPass* handle)
{
handle->DoFunction();
}
// And then export any needed functions too. 

现在使用C#:

public class MyWrapper{
IntPtr myReference;
public ObjectWrapper()
{
try
{
this.myReference = MyFactory();
if (myReference == IntPtr.Zero)
{
throw "Error or something";
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw e;
}
}
//Path to dll
[DllImport(lib_path)]
private static extern IntPtr MyFactory();
[DllImport(lib_path)]
private static extern void SomeFunction(IntPtr toTrigger);
}

考虑去掉C的三种形式中的至少一种来简化设计,或者我建议的方法确实有效,我以前也用过!