2012-02-15 25 views
5

Tôi đọc một số tài liệu mà đưa ra ví dụ đơn giản về các chức năng tương thích với C.Làm thế nào tôi có thể nhập dll của một ++ lớp C bên trong một không gian tên

__declspec(dllexport) MyFunction(); 

Tôi okey với điều đó. Tôi viết một ứng dụng nhỏ sử dụng các chức năng của dll này. Tôi đã sử dụng liên kết rõ ràng với

LoadLibrary() 

chức năng. Các chức năng kiểu C hoạt động không có vấn đề gì. Nhưng khi tôi viết lớp của tôi là

namespace DllTest 
{ 
class Test 
{ 
public: 
    __declspec(dllexport) Test(); 
    __declspec(dllexport) void Function(int); 
    __declspec(dllexport) int getBar(void); 
private: 
    int bar; 
}; 

} 
#endif 

nó biên dịch tốt và tạo ra Dll. Trong khi làm việc với các hàm kiểu C, tôi chỉ đơn giản là lấy một con trỏ hàm từ các hàm LoadLibrary() và GetProcAddress (...).

sử dụng trước đây của tôi là

typedef void (*Function)(int); 

int main() 
{ 
    Function _Function; 
    HINSTANCE hInstLibrary = LoadLibrary(TEXT("test.dll")); 

    if (hInstLibrary) 
    { 
     _Function = (Function)GetProcAddress(hInstLibrary,"Function"); 
    if (_Function) 
    { 
     // use the function 

Nhưng bây giờ tôi không có ý tưởng làm thế nào tôi có thể nhanh chóng lớp học của tôi? Tôi có thể sử dụng liên kết rõ ràng hoặc liên kết ngầm như thế nào?

Bất kỳ trợ giúp nào về mẫu mã sẽ được đánh giá cao.

Trả lời

6

Nếu bạn đang cố gắng để khởi tạo một lớp, thì bạn cần phải biết cấu trúc của nó trên thời gian biên dịch. Bạn có thể đạt được điều này bằng cách tạo một lớp trừu tượng định nghĩa các phương thức thể hiện mà lớp đã nhập sẽ phải xác định lại. Ví dụ:

//interface.h 

class TestInterface 
{ 
public: 
    virtual void Function(int) = 0; 
    virtual int getBar(void) = 0; 
}; 

Sau đó, trong DLL của bạn, bạn có thể bao gồm giao diện.h, kế thừa TestInterface và xác định lại phương pháp thuần ảo:

//test.h 
namespace DllTest { 
    class Test : public TestInterface 
    { 
    public: 
     Test(); 
     void Function(int); 
     int getBar(void); 
    private: 
     int bar; 
    }; 
}; 

Sau đó, bạn có thể định nghĩa một hàm trong DLL của bạn mà phân bổ một đối tượng kiểm tra:

extern "C" __declspec(dllexport) TestInterface *allocate_test() { 
    return new DllTest::Test(); 
} 

Và cuối cùng, khi bạn nhập các DLL, tìm biểu tượng "allocate_test" và sử dụng ký hiệu "allocate_test" và sử dụng biểu tượng:

TestInterface *(*test_fun)() = (TestInterface *(*test_fun)())GetProcAddress(hInstLibrary,"allocate_test"); 
TestInterface *test_ptr = test_fun(); 
test_ptr->Function(12); //use you object 
+2

Hai điểm: đầu tiên, 'TestInterface' không cần (cũng không nên có) thành viên dữ liệu cá nhân, và thứ hai, nếu anh ta chuyển tên của hàm vào' GetProcAddress', hàm tốt nhất là 'extern "C" '(nếu không, anh ta phải truyền tên bị xé). Và tất nhiên, trong 'allocate_test', bạn có nghĩa là để làm' trả về kiểm tra mới; ', không phải' trả về TestInterface(); '(mà sẽ không biên dịch). –

+0

Bạn nói đúng, tôi đã làm điều đó một cách nhanh chóng và bỏ lỡ một vài điều. – mfontanini

2

Trước tiên, lưu ý rằng đây là tính đặc thù của Microsoft. Các quy tắc khác nhau sẽ giữ cho các hệ thống khác.

Viết những thứ như bạn đã không làm việc, hoặc ít nhất, là đau đớn. Bạn cần sử dụng __declspec(dllexport) trong DLL xác định các hàm , nhưng __declspec(dllimport) khi biên dịch mã gọi hàm các hàm từ một DLL khác. Cách thông thường xử lý này là để sử dụng một số tên macro cụ thể quy định cụ thể các DLL, và làm điều gì đó như:

#ifdef __WIN32 
#ifdef MYMODULE_DLL 
#define MYMODULE_EXPORT __declspec(dllexport) 
#else 
#define MYMODULE_EXPORT __declspec(dllimport) 
#endif 
#else 
#define MYMODULE_EXPORT 
#endif 

Đặt này trong một tiêu đề được bao gồm trong tất cả các tiêu đề trong DLL của bạn, và xác định MYMODULE_DLL trên dòng lệnh của dự án.

Ngoài ra, nó có thể xuất toàn bộ một lớp:

class MYMODULE_EXPORT DllTest 
{ 
    // ... 
}; 

này có tác dụng xuất khẩu hoặc nhập khẩu tất cả các chức năng và thành viên tĩnh của lớp.

+0

Tôi có đoạn mã này trong khi đặt ở đây tôi tách phần đó. Vẫn không giúp tạo và sử dụng các phiên bản của lớp của tôi, trong khi nhập. – accfews

+1

OK. Tôi chỉ nhận thấy rằng bạn đang sử dụng 'GetProcAddress'. Có nghĩa là các hàm không thể là hàm thành viên, chỉ có 'extern" C "' (nếu không, bạn không thể đặt tên cho chúng). Bạn sẽ phải định nghĩa một giao diện trừu tượng và một hàm 'extern" C "' trả về một cá thể. –

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