2012-12-29 50 views
1

我在VS中創建了新的Win32項目,併爲此選擇了動態庫(* .dll)。Dumpbin顯示奇怪的方法名稱(在MS Visual C++中生成導出函數)

我在主文件中定義的一些出口函數:

__declspec(dllexport) 
int TestCall(void) 
{ 
    int value = 4/2; 
    std::cout << typeid(value).name() << std::endl; 
    return value; 
} 

__declspec(dllexport) 
void SwapMe(int *first, int *second) 
{ 
    int tmp = *first; 
    *first = *second; 
    *second = tmp; 
} 

當我已經看過了dumpin /出口,我有:

ordinal hint RVA  name 

     1 0 00001010 [email protected]@[email protected] 
     2 1 00001270 [email protected]@YAHXZ 

我打電話C#版本是這樣的:

[DllImport(@"lib1.dll", EntryPoint = "[email protected]@YAHXZ", 
CallingConvention = CallingConvention.Cdecl)] 
static extern int TestCall(); 

這不是使用導出方法的正確形式。我在C++ dll項目中爲導出方法生成此類名稱失敗的地方在哪裏?

回答

5

這是正常的,C++編譯器適用名稱修飾給函數。 C++語言支持函數重載,就像C#一樣。所以你可以寫一個Foo(int)和一個Foo(double)函數。顯然,它們不能作爲名爲「Foo」的函數導出,客戶端代碼不知道要調用哪一個。所以額外的字符對名稱進行編碼,以便它對於過載是唯一的。

你可以通過聲明函數extern "C"來關閉它,C語言不支持重載,因此不需要相同類型的裝飾。

但實際上如果你不這樣做會更好。因爲這也是一個很好的抓錯的方法。就像在C++代碼中更改函數聲明一樣,但忘記修改C#代碼中的pinvoke聲明。您現在可以輕鬆診斷出「找不到Entrypoint」異常,而不是非描述性的,並且很難診斷AccessViolationException。這不一定必須在C++代碼中提出,堆棧不平衡也會導致C#代碼崩潰。查找裝飾後的名稱有點痛苦,但通過要求鏈接器創建一個映射文件(/ MAP選項)可以改善這一點。

2

使用外部的「C」,以指定的聯動,以避免名稱重整:

extern "C" __declspec(dllexport) int TestCall(void); 
extern "C" __declspec(dllexport) void SwapMe(int *first, int *second);