2017-08-29 62 views
0

正如標題所暗示的,我很難從C++調用C#代碼。一點上下文:在C#中有一個API調用(在C++版本的API中不存在),我需要將它集成到一個更大的C++項目中。在C++(COM)中使用C#代碼Dll導入不能正常工作

我一直在閱讀this SO post,並且用COM方法取得了最大進展。

我的C#的DLL編譯*。所產生的DLL和TLB文件複製到相應的C++項目目錄後,我打開管理員CMD在同一個C++項目目錄提示符,然後運行:

regasm MyFirstDll.dll /codebase /tlb 

(*我編譯它作爲一個類庫,大會名稱: MyFirstDll,默認命名空間:MyMethods,程序集信息... - >使彙編Com-Visible被選中,Build-> Register for COM interop也被選中。)

使用對象瀏覽器,我能夠看到類我定義了一個具有適當的參數和簽名的方法。 Screenshot of it showing up in Object Browser

我遇到的問題是方法調用(而不是類)。即使該方法在對象瀏覽器中可見,但在我的代碼中,它不會被識別爲對象的方法。

類 「ATL :: _ NoAddRefReleaseOnCComPtr」 沒有成員 「添加」
這裏是我的代碼:

MyFirstDll C#項目:

using System; 
using System.Runtime.InteropServices; 
// 

namespace MyMethods 
{ 
    // Interface declaration. 
    [Guid("8a0f4457-b08f-4124-bc49-18fe11cb108e")] 
    [ComVisible(true)] 
    [InterfaceType(ComInterfaceType.InterfaceIsDual)] 
    public interface Easy_Math 
    { 
     [DispId(1)] 
     long Add(long i, long j); 
    }; 
} 
namespace MyMethods 
{ 
    [Guid("0cb5e240-0df8-4a13-87dc-50823a395ec1")] 
    [ComVisible(true)] 
    [ClassInterface(ClassInterfaceType.None)] 
    [ProgId("MyMethods.AddClass")] 
    public class AddClass: Easy_Math 
    { 
     public AddClass() { } 
     [ComVisible(true)] 

     public long Add(long i, long j) 
     { 
      return (i + j); 
     } 
    } 
} 

NateMath.h:

#include <atlcomcli.h> 
#import "MyFirstDll.tlb" 

class NateMath 
{ 
public: 
    NateMath(void); 
    ~NateMath(void); 
    long Add(long a, long b); 

private: 
    CComPtr<MyFirstDll::AddClass> adder; 
}; 

NateMath.cpp:

#include "stdafx.h" 
#include <atlcomcli.h> 
#import "MyFirstDll.tlb" 
#include "NateMath.h" 

NateMath::NateMath(void) 
{ 
    CoInitialize(NULL); 
    adder.CoCreateInstance(__uuidof(MyFirstDll::AddClass)); 
} 

NateMath::~NateMath(void) 
{ 
    CoUninitialize(); 
} 
long NateMath::Add(long a, long b) { 
    return adder->Add(a,b); 
} 

問題是在「返回加法器 - >添加(a,b)」(NateMath.cpp)添加(a,b)顯示紅色與類「ATL :: _否AddRefReleaseOnCComPtr」沒有成員「添加」

+1

嘗試使用'CComPtr '而不是'CComPtr '。 –

+0

@HansPassant這很好知道!不幸的是,在更新C#AddClass將代碼添加到int Add(int i,int j)中,仍然出現同樣的錯誤。:( –

+0

@MichaelGunter如果我使用CComPtr而不是類,它將如何知道調用我的類的實現方法? –

回答

0

這是因爲您正嘗試在CComPtr而不是界面中使用您的班級名稱。使用COM,所有方法都是在接口上定義的,而不是在實現接口的類上定義的。

您可以CoCreateInstance(__uuidof(YourClass)),因爲意圖是創建一個YourClass(由__uuidof(YourClass)表示的GUID標識)的實例。但是,C++中的YourClass是僅存在的虛擬結構,因此您可以讀取uuid - 從#import生成的C++中的YourClass的定義爲空,並且始終爲空。

要解決此問題,請使用CComPtr<YourInterface>。這告訴C++你想通過該接口與被引用的對象進行通信。這裏有一條規則要記住:CComPtrCComQIPtr的類型參數必須是總是是一個COM接口。該COM接口可以是一個明確定義的接口,也可以是由.NET自動生成的「類接口」。

的類接口說到:如果您用過ClassInterfaceType.AutoDual代替None,你可以使用一個CComPtr<_YourClass>(注意前導下劃線 - _YourClass是類接口,而YourClass將是一流的,我會建議做的。然而,你已經有了這種方法

+0

這是不正確的,他通過明確聲明接口來做到了這一點。他忘了使用它。好的建議可能應該包括建議使用#import自動生成的智能指針類型,在這種情況下應該命名爲'Easy_MathPtr'。 –

+0

@HansPassant啊,謝謝。我忘記了類接口是'_YourClass',而不是'YourClass'。至於使用'CComPtr'和'_com_ptr',這完全取決於消費開發者。如果他們在現有的ATL項目中使用它,沒有理由選擇生成'_com_ptr'而不是'CComPtr'。事實上,這樣做意味着你有一個額外的異常類型來處理('_com_error')。 –