2017-02-03 108 views
-1

我有一个用非托管C++写的COM Dll,它暴露了一个com接口。 idl的简单示例如下所示:传递从托管c + +到COM接口指针的指针C#

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消费者为控制台应用程序项目添加引用。我的目标是获得ObjectToPass的实例,我的控制台应用程序中,并传递给消费者调用下面

#include "stdafx.h" 
#import "..\Debug\ComTest.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; 
} 

公共方法PassObject作为表演这个代码将无法编译。编译器无法将参数1从'IObjectToPassPtr'转换为'Interop :: ComTest :: IObjectToPass ^'。我做了不同的尝试,但似乎IObjectToPass *不能被转换为'Interop :: ComTest :: IObjectToPass ^。有没有办法做到这一点?

+0

blech!你究竟在做什么?不会直接C++/CLI(没有COM)更容易? –

+0

看起来你可能想要[Marshal.GetUniqueObjectForIUnknown](https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getuniqueobjectforiunknown(v = vs.110).aspx)?这将(出现)给你一个托管的'Object :: Consumer'实例用于你的非托管'obj'接口。 –

+0

我模拟了我要移动的场景,太复杂了,不能在这里解释。我有第三方COM对象,它是从主应用程序传递给一个com unmanaged dll,我需要用一个.NET代替这个unmanged dll,所以我必须通过并使用第三方com对象。 –

回答

0

跳过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中的至少一个,简化了设计,否则我建议做的工作,我以前一直用它!