2008-08-25 48 views
8

Tôi đang viết một C/C++ DLL và muốn xuất một số chức năng mà tôi đã thực hiện trước khi sử dụng một file .def như thế nàychức năng quá tải trong C++ DLL def nộp

LIBRARY "MyLib" 
EXPORTS 
    Foo 
    Bar 

với mã định nghĩa là này, ví dụ:

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

Tuy nhiên, những gì nếu tôi muốn tuyên bố một phương pháp quá tải của Foo() như:

int Foo(int a, int b); 

khi d ef tập tin chỉ có tên chức năng và không phải là nguyên mẫu đầy đủ Tôi không thể xem làm thế nào nó sẽ xử lý các chức năng quá tải. Bạn chỉ cần sử dụng một mục nhập và sau đó chỉ định phiên bản quá tải nào bạn muốn khi chuyển vào con trỏ hàm mẫu chính xác tới LoadLibrary()?

Edit: Để được rõ ràng, đây là trên Windows sử dụng Visual Studio 2005

Edit: Bị Trầy phương pháp phi def (__declspec) là câu trả lời ... Tôi biết điều này không thực sự giải quyết vấn đề sử dụng def các tập tin như tôi muốn, nhưng có vẻ như là có khả năng không có (chính thức) giải pháp bằng cách sử dụng các tập tin def. Tuy nhiên, sẽ để câu hỏi mở, trong trường hợp ai đó biết điều gì đó mà chúng tôi không có chức năng quá tải và tệp bị lỗi.

Trả lời

9

Trong chính mã, đánh dấu các hàm bạn muốn xuất bằng __declspec (dllexport). Ví dụ:

#define DllExport __declspec(dllexport) 

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

Nếu bạn làm điều này, bạn không cần phải liệt kê các hàm trong tệp .def.

Ngoài ra, bạn có thể sử dụng một giá trị tham số mặc định, như:

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

này giả định rằng có tồn tại một giá trị cho b mà bạn có thể sử dụng để chỉ ra rằng nó là không sử dụng. Nếu -1 là giá trị pháp lý cho b hoặc nếu không có hoặc không phải là giá trị mặc định, thì giá trị này sẽ không hoạt động.

Chỉnh sửa (Adam Haile): Đã sửa chữa sử dụng __declspec dưới dạng __dllspec không chính xác nên tôi có thể đánh dấu đây là câu trả lời chính thức ... nó đủ gần.

Chỉnh sửa (Graeme): Rất tiếc - cảm ơn đã sửa lỗi đánh máy của tôi!

+0

nếu chúng ta sử dụng GetProcAddress() với một DLL động? – null

+2

Sau đó, bạn cần sử dụng các tên bị xáo trộn, hoặc đổi tên một trong các hàm và làm cho chúng trở thành cả hai 'extern" C "', giả sử không có hoặc trả về các đối tượng C++. –

11

Quá tải chức năng là tính năng C++ dựa trên tên mangling (tên hàm bí mật trong thông báo lỗi trình liên kết).

Bằng cách viết tên đọc sai thành file def, tôi có thể nhận dự án thử nghiệm của tôi để liên kết và chạy:

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

dường như làm việc cho

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

Vậy sao chép C tên hàm ++ từ thông báo lỗi và ghi chúng vào tập tin def của bạn. Tuy nhiên, câu hỏi thực sự là: Tại sao bạn muốn sử dụng một tập tin def và không đi với __declspec (dllexport)?

Tên bị xáo trộn không mang tính di động, tôi đã thử nghiệm với VC++ 2008.

+0

Cách tiếp cận thú vị. Bởi không di động, bạn có nghĩa là trên các phiên bản khác nhau của Visual Studio? Mà sẽ đề nghị họ thay đổi tên của họ mangling đề án giữa các phiên bản có lẽ? – jxramos

+0

@jxramos Tôi không chắc chắn liệu họ có thực sự có thể thay đổi tên lược đồ mangling hay không. Nhưng tôi nghi ngờ điều này sẽ làm việc theo cùng một cách khi chuyển sang trình biên dịch khác, trừ khi trình biên dịch đó cố gắng mô phỏng hành vi của VC. – Timbo

+0

Điều này chắc chắn chỉ là một VC + + điều kể từ khi tôi không nghĩ rằng trình biên dịch khác sử dụng các tập tin def. Ngoài ra nếu tôi nhớ những gì một người từng nói với tôi là Microsoft có ý tưởng giao diện dll này, nơi người dùng lựa chọn các phần tử được hiển thị công khai, thông qua tập tin def hoặc __declspec trong khi trong Unix với các tệp * .so. Họ không có sự khác biệt giữa API công cộng hợp lý và API công khai của thư viện. – jxramos

2

Không có ngôn ngữ hoặc phiên bản không thuyết phục cách xuất hàm bị quá tải do quy ước mangling có thể thay đổi với mỗi bản phát hành của trình biên dịch.

Đây là một trong những lý do tại sao hầu hết các hàm WinXX có tên hài hước như * Ex hoặc * 2.

+0

nền thú vị với nhận xét của WinXX! – jxramos

3

Không có cách chính thức để làm những gì bạn muốn, bởi vì giao diện dll là một api C.

Bản thân trình biên dịch sử dụng tên bị xáo trộn như một giải pháp thay thế, vì vậy bạn nên sử dụng tên mangling khi bạn không muốn thay đổi quá nhiều trong mã của mình.

8

Tôi gặp vấn đề tương tự nên tôi cũng muốn đăng bài này.

  1. thường sử dụng

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

    để xuất khẩu một tên hàm là tốt. Nó sẽ thường là xuất tên không bị xáo trộn mà không cần tệp .def. Tuy nhiên, có một số trường hợp ngoại lệ là như __stdcall và tên chức năng quá tải.

  2. Nếu bạn khai báo một chức năng để sử dụng quy ước __stdcall (như được thực hiện đối với nhiều chức năng API) sau đó

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

    sẽ xuất khẩu một tên đọc sai như _Foo @ 4. Trong trường hợp này, bạn có thể cần phải ánh xạ một cách rõ ràng tên đã xuất vào tên bị xáo trộn nội bộ.

A. Cách xuất tên không bị xáo trộn. Trong một tệp .def thêm

---- 
EXPORTS 
    ; Explicit exports can go here 

    Foo 
----- 

Điều này sẽ cố gắng tìm một "kết hợp tốt nhất" cho hàm Foo nội bộ và xuất nó. Trong trường hợp trên, nơi chỉ có một foo này sẽ tạo ra các bản đồ

Foo = _Foo @ 4

như có thể thấy qua dumpbin/XUẤT KHẨU

Nếu bạn đã quá tải một tên hàm sau đó bạn có thể cần phải nói rõ ràng hàm nào bạn muốn trong tệp .def bằng cách chỉ định một tên bị cắt xén bằng cách sử dụng cú pháp entryname [= internalname]. ví dụ.

---- 
EXPORTS 
    ; Explicit exports can go here 

    [email protected] 
----- 

B. Một thay thế cho .def file là bạn có thể xuất khẩu tên "tại chỗ" bằng cách sử dụng #pragma.

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

C. Cách thứ ba là chỉ khai báo một phiên bản của Foo là "C" bên ngoài được xuất. Xem here để biết chi tiết.

2

Systax cho XUẤT KHẨU định nghĩa là:

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

entryname là hàm hoặc tên biến mà bạn muốn xuất. Điều này là bắt buộc. Nếu tên bạn xuất khác với tên trong tệp DLL, hãy chỉ định tên của tệp xuất trong tệp DLL có tên nội bộ.

Ví dụ, nếu DLL của bạn xuất khẩu một chức năng, Func1() và bạn muốn nó được sử dụng như Func2(), bạn sẽ xác định:

EXPORTS 
func2=func1 

Chỉ cần nhìn thấy tên đọc sai (sử dụng Dependency Walker) và chỉ định tên hàm của riêng bạn.

Nguồn: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

Chỉnh sửa: Điều này làm cho DLL năng động, nơi mà chúng ta cần phải sử dụng GetProcAddress() để lấy một cách rõ ràng chức năng trong DLL.

Các vấn đề liên quan