2008-08-25 11 views
8

我正在寫一個C/C++ DLL和要導出我已經使用DEF文件這樣重載函數的C++ DLL文件高清

LIBRARY "MyLib" 
EXPORTS 
    Foo 
    Bar 

的代碼定義爲之前完成某些功能此,例如:

int Foo(int a); 
void Bar(int foo); 

但是,如果我想聲明的Foo)等的重載的方法(:

int Foo(int a, int b); 

作爲d ef文件只有函數名,而不是完整的原型,我看不出它將如何處理重載函數。你是否只使用了一個入口,然後指定在將正確的原型函數指針傳遞給LoadLibrary()時需要哪個重載版本?

編輯:要清楚,這是在使用Windows的Visual Studio 2005

編輯:標記非高清(__declspec)方法,作爲答案......我知道這並不實際使用解決問題def文件,但似乎沒有使用def文件的(官方)解決方案。但是,如果有人知道我們沒有重載的函數和def文件,將會留下問題。

回答

9

在代碼本身中,使用__declspec(dllexport)標記要導出的函數。例如:

#define DllExport __declspec(dllexport) 

int DllExport Foo(int a) { 
    // implementation 
} 
int DllExport Foo(int a, int b) { 
    // implementation 
} 

如果你這樣做,你不需要列出.def文件的功能。

或者,你可以使用默認的參數值,如:

int Foo(int a, int b = -1) 

這個假設存在對於b,你可以用它來表明它是未使用的值。如果-1是b的合法值,或者如果不存在或不應該是默認值,則這將不起作用。

編輯(Adam Haile):更正爲使用__declspec,因爲__dllspec不正確,所以我可以將其標記爲正式答案......已經足夠接近了。

編輯(格雷姆):哎呀 - 感謝您糾正我的錯誤!

+0

如果我們在動態DLL中使用GetProcAddress()會怎麼樣? – null 2013-03-21 06:07:13

+2

然後,您需要使用mangled名稱,或者重命名其中一個函數,並使它們都是`extern「C」`,假定它們都不接受或返回C++對象。 – 2013-03-21 19:17:39

11

函數重載是一種C++特性,它依賴於名稱修飾(鏈接器錯誤消息中的隱含函數名稱)。

通過寫錯位的名稱入DEF文件,我可以得到我的測試項目鏈接並運行:

LIBRARY "TestDLL" 
EXPORTS 
    [email protected]@[email protected] 
    [email protected]@[email protected] 

似乎對

void Foo(int x); 
void Foo(int x, int y); 

工作,以便複製從C++函數名錯誤信息並寫入你的def文件。但是,真正的問題是:爲什麼要使用def文件而不是使用__declspec(dllexport)?

破損的名字是不可移植的,我用VC++ 2008測試過。

+0

有趣的方法。通過不可移植,你的意思是跨越不同版本的Visual Studio?這意味着他們可能會在不同版本之間更改其名稱修改方案? – jxramos 2015-10-20 22:03:51

2

導出重載函數時沒有語言或版本不可知的方式,因爲編譯約定可以隨着編譯器的每個版本而改變。

這就是爲什麼大多數WinXX函數都有* Ex或* 2這些有趣的名字的原因之一。

3

沒有官方的做你想做的事,因爲dll接口是C api。

編譯器本身使用錯位的名稱作爲解決方法,所以當您不想在代碼中更改太多時,應該使用名稱修飾。

8

我有一個類似的問題,所以我想發佈這個。

  1. 通常使用

    extern "C" __declspec(dllexport) void Foo(); 
    

    導出函數名是好的。 它會通常導出名稱 unmangled不需要 .def文件。然而,還有一些例外,如__stdcall函數 和重載的函數名稱。

  2. 如果你聲明一個函數使用__stdcall 約定(如許多API函數完成),然後

    extern "C" __declspec(dllexport) void __stdcall Foo(); 
    

    將出口像 _Foo一個錯位的名稱@ 4。在這種情況下,您可能需要將導出的名稱 明確映射到內部損壞的名稱。

A.如何導出未加密名稱。在DEF文件添加

---- 
EXPORTS 
    ; Explicit exports can go here 

    Foo 
----- 

這將試圖找到一個內部函數foo「最佳匹配」和導出。另外,在上述僅存在 一個FOO的情況下,這將創建的映射

美孚= _Foo @ 4

如可以通過DUMPBIN/EXPORTS

可以看到如果重載函數名,那麼您可能需要通過使用entryname [= internalname]語法指定一個損壞的名稱,在.def文件 中明確指出要使用哪個函數。例如

---- 
EXPORTS 
    ; Explicit exports can go here 

    [email protected] 
----- 

B.替代.def文件的是,您可以使用#pragma將名稱「就地」導出。

#pragma comment(linker, "/export:[email protected]") 

C.第三種方法是聲明只有一個版本的Foo作爲extern「C」被導出爲unmangled。有關詳細信息,請參見here

2

Systax出口的定義是:

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA] 

entryname的是,你要導出的函數或變量名。這是必需的。如果您導出的名稱與DLL中的名稱不同,請在帶有內部名稱的DLL中指定導出名稱。

例如,如果你的DLL導出的函數,func1的(),您希望它被用作FUNC2(),應指定:

EXPORTS 
func2=func1 

只看到錯位的名稱(使用的Dependency Walker)並指定您自己的函數名稱。

來源:http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

編輯:這適用於動態的DLL,在這裏我們需要使用GetProcAddress的()中的Dll明確擷取功能。