2013-03-11 34 views
5

Đây là lần đầu tiên tôi xử lý các tệp DLL. Sau khi tài liệu MSDN Tôi tạo ra một tập tin header fooExports.h với các macro được xác định theo một định nghĩa preprocessor:Làm cách nào để xuất/nhập cấu trúc C từ DLL/ứng dụng bảng điều khiển bằng cách sử dụng __declspec (dllexport/import)

#ifdef FOODLL_EXPORTS 
    #define FOO_API __declspec(dllexport) 
#else 
    #define FOO_API __declspec(dllimport) 

Ý định của tôi là sử dụng tiêu đề này cả trong việc thực hiện DLL của tôi cũng như trong việc áp dụng giao diện điều khiển. Cho đến nay chức năng nhập và xuất hoạt động tốt. Vấn đề đặt ra khi tôi cố gắng xuất một cấu trúc đã định nghĩa mà tôi cần làm tham số cho một trong các hàm được xuất. Ví dụ, trong file header nói trên Tôi tuyên bố FOO_API void foo(FooParams *args)args là một cấu trúc được định nghĩa như sau:

typedef struct FooParams 
{ 
    char *a; 
    char *b; 
    void *whatever; //some other type 
} FooParams; 

struct này phải được quy định tại foo.h hơn là trong fooExports.h. Có cách nào để xuất cấu trúc này mà không lấy nó ra khỏi tệp tiêu đề gốc của nó (xem xét rằng tôi muốn giữ cho xuất/nhập tập trung trong fooExports.h). Cách tiếp cận tốt hơn để làm điều này là gì? DLL là tất cả C cũng như ứng dụng khách sử dụng nó.

+0

Bạn không xuất các loại, bạn xuất các ký hiệu liên kết. – aschepler

+1

@aschepler bạn có muốn mở rộng không? – wotann07

+0

Nó không phải là tất cả rõ ràng lý do tại sao bạn sử dụng hai tập tin .h hoặc lý do tại sao bạn chỉ cần không khai báo các loại đối số cho foo(). Không có gì để xuất trong cấu trúc, nó không có bất kỳ mã nào. Cách đơn giản để tránh tình trạng tiến thoái lưỡng nan là chỉ sử dụng một tệp .h và được thực hiện với nó. –

Trả lời

9

Nếu việc sử dụng duy nhất cho khách hàng bao giờ sẽ có cho FooParams là để có được con trỏ tới trở về từ chức năng DLL và để vượt qua những gợi ý để các chức năng DLL khác, bạn có thể làm cho nó trở thành một "đục gõ": Đặt

typedef struct FooParams FooParams; 

trong fooExports.h. Macro FOO_API không thuộc về tuyên bố đó. Loại đục không có nghĩa là mã khách hàng không thể:

  • Tạo bất kỳ biến loại FooParams nào được chấp nhận).
  • Làm gì cả với bất kỳ thành viên nào của FooParams.
  • Tìm sizeof(FooParams) - và do đó không thể chính xác malloc không gian cho một hoặc nhiều đối tượng FooParams.

Bạn cũng không thể hiển thị các macro có thể hiển thị với khách hàng thực hiện bất kỳ thao tác nào ở trên. Vì vậy, DLL của bạn sẽ cần phải có một hoặc nhiều "nhà xây dựng" hoặc "nhà máy" chức năng, có lẽ cái gì đó như

FOO_API FooParams* CreateFooParams(const char * input); 

Nó cũng thực hành tốt để xác định một phù hợp với "destructor" chức năng như

FOO_API void DestroyFooParams(FooParams * p); 

ngay cả khi định nghĩa đơn giản như { free(p); }, vì đôi khi có thể có vấn đề nếu bộ nhớ được cấp phát bên trong DLL được giải phóng bằng mã bên ngoài hoặc ngược lại (vì không phải tất cả mã Windows sử dụng định nghĩa giống hệt nhau của mallocfree).

Nếu tất cả điều này quá khắc nghiệt, lựa chọn duy nhất khác là đặt hoặc #include định nghĩa struct trong tệp tiêu đề đã xuất và hiển thị cho khách hàng.Nếu không có điều đó, bất kỳ nỗ lực nào để thực hiện điều gì đó với một số FooParams, ngoài việc truyền con trỏ xung quanh, sẽ không thể thực hiện được vì trình biên dịch sẽ không biết cái gì trong một số FooParams. Trình biên dịch (trái ngược với trình liên kết) chỉ lấy thông tin từ các đối số dòng lệnh và các tệp tin #include -d, không phải từ các thư viện hoặc các tệp DLL.

+0

cảm ơn bạn rất nhiều. đây là một câu trả lời tuyệt vời! Trong khi chờ đợi một phản ứng, tôi đã trực giác lấy cách tiếp cận của 'bao gồm' các tiêu đề của tôi với các định nghĩa struct trong máy khách. Chỉ muốn chắc chắn không có cách nào khác. Và như bạn vừa giải thích, không có những gì tôi cần làm. Cảm ơn một lần nữa cho thời gian của bạn! – wotann07

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