2016-04-22 75 views
0

我想從C++調用C#代碼。所以我選擇了COM Interop方式。現在我有C#代碼:從C++調用c#,返回值

namespace ToBeCalled 
{ 
    [Guid("9329feaf-b293-4093-a7d8-6128f52b30a6")] 
    [ComVisible(true)] 
    public interface IInterface 
    { 
     int Write(string toWrite); 
    } 
} 

namespace ToBeCalled 
{ 
    [Guid("e4105e40-2d6b-4b7c-ae42-d2f9c405a2a0")] 
    [ComVisible(true)] 
    public class ClassYouWantToUse : IInterface 
    { 
     public int Write(string toWrite) 
     { 
      System.Console.WriteLine(toWrite); 
      return 1; 
     } 
    } 
} 

和C++代碼

#import "...\\ToBeCalled.tlb" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // Initialize COM. 
    HRESULT hr = CoInitialize(NULL); 

    // Create the interface pointer. 
    ToBeCalled::IInterfacePtr piTest(__uuidof(ToBeCalled::ClassYouWantToUse)); 

    long lResult = 0; 

    // Call the Add method. 
    piTest->Write("hi", &lResult); 

    wprintf(L"The result is %d\n", lResult); 

    // Uninitialize COM. 
    CoUninitialize(); 
    return 0; 
} 

當我嘗試這個編譯,當然它說,寫不採取2個參數。我看到了MSDN,他們有這樣的例子,他們以這種方式獲取返回值。所以我的問題是,我如何獲得函數的返回值?當我更新電話

piTest->Write("hi"); 

比在未處理的異常上執行失敗。當我嘗試這個沒有返回值的例子時,所以方法返回值的聲明是無效的,比一切正常。

+0

我發現需要將參數添加到C#中,然後我可以使用第二個參數來得到結果值的函數。好的,所以對於Int問題已經解決了,但是我怎樣才能發送這樣的字符串呢? –

+0

您應該可以正常返回一個值,而不是通過'[out]'參數。什麼是例外?您是否調試了託管呼叫? –

回答

2

您的服務器代碼是確定的,您不需要使用out參數。

客戶端代碼看起來應該只是這樣的:

long result = piTest->Write("hi"); 

如果你看看內部產生.tlh文件,你會看到簽名是這樣的:

long Write(_bstr_t toWrite); 

這是一個生成的包裝代碼,並且您可能將其與原始COM呼叫混淆,該呼叫也是tlh文件的一部分,並且看起來像這樣:

virtual HRESULT __stdcall raw_Write(BSTR toWrite, long* pRetVal) = 0; 

包裝更方便:它在內部調用原始COM調用並處理返回值 - 因此,返回值通常從函數返回(而不是作爲[out, retval]參數),並且如果原始調用的結果表示錯誤(失敗HRESULT_com_error異常被拋出。

有關詳細信息,可以看看另一個生成的文件,其中包含tli擴展名,其中包含實施封裝器方法。

+0

謝謝,我試了一下。是的,我與HRESULT混淆。當我從c#返回字符串時,需要在這裏做一些釋放嗎?如果是,如何? –

+1

你沒有返回一個字符串,所以沒有任何可以釋放的字符串。如果你創建一個返回一個字符串的新方法(在'idl'定義中定義爲'[out,retval]'參數),它符合標準的COM規則,並且通常你必須通過'SysFreeString' API來釋放它例如,如果你使用原始呼叫)。然而,'#import'也會生成一個'smart'包裝器,它會返回一個'bstr_t',它會爲你取消分配它,所以如果你使用這個方法,就沒有任何東西可以被釋放。 –