2017-02-03 137 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中的至少一個,簡化了設計,否則我建議做的工作,我以前一直用它!