2010-09-16 10 views

Trả lời

19

Có chủ yếu là ba cách đúng để làm điều đó:

  • Sử dụng C++/CLI. Đây là cách tối ưu nếu DLL này sẽ chỉ được sử dụng bởi .NET.
  • Sử dụng API tương thích "extern "C"", giống như chính API Windows. Đây là di động nhất, nhưng không phải là thuận tiện cho người gọi của bạn như sử dụng một mô hình lớp để đại diện cho các đối tượng của bạn.
    • Đây là tùy chọn tốt nhất nếu bạn thực sự có ý định viết bằng ANSI C (không phải C++).
    • Đối với đường dẫn này, bạn viết các chức năng của mình là extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
    • Bạn cũng nên sử dụng mô hình bộ nhớ "người gọi-cung cấp đệm" thay vì trả lại bộ đệm được cấp phát bên trong thư viện của bạn. Trong trường hợp bạn cần cấp phát bộ nhớ cho trạng thái nội bộ, người gọi sẽ xem bộ nhớ đó dưới dạng tay cầm mờ và bạn nên cung cấp chức năng truy cập cho người gọi để trích xuất dữ liệu. Trong mọi trường hợp người gọi sẽ được dự kiến ​​sẽ deallocate bộ nhớ được phân bổ bên trong thư viện của bạn, tuy nhiên nó là ok cho người gọi để yêu cầu thư viện để làm deallocation.
  • Sử dụng COM hoặc API giống COM. Ở đây bạn quay trở lại (thường thông qua tham số ngoài) một con trỏ tới một giao diện, đó là một lớp với các hàm ảo thuần túy, không có các hàm không phải ảo và không có dữ liệu.
    • Việc triển khai là trong các lớp cụ thể có được từ giao diện trừu tượng này, chúng có thể có dữ liệu và hàm trợ giúp, vì điều đó không ảnh hưởng đến giao diện nhị phân.
    • Đây là công việc nhiều hơn trong thư viện nhưng cực kỳ di động và dễ dàng cho người tiêu dùng sử dụng.

Và có một điều hoàn toàn không nên làm:

  • sử dụng __declspec(dllexport) trên lớp C++.

EDIT: Tôi cũng muốn giải thích một số phương pháp hay cho tùy chọn # 2, sẽ tối đa hóa tính di động và làm cho các phần C/C++ có thể sử dụng được từ các ứng dụng không được quản lý.

Bạn có thể làm điều đó dễ dàng hơn với một vĩ mô, theo cách thông thường để làm việc đó là:

Trong tập tin tiêu đề của bạn, tất cả các tờ khai chức năng giống như

MYPROJECTAPI(returntype) PublicFunc(params); 

Trong dự án của bạn, định nghĩa là

#define MYPROJECTAPI(returntype) \ 
        extern "C" returntype __stdcall __declspec(dllexport) 

Trong các dự án tiêu dùng

#define MYPROJECTAPI(returntype) \ 
        extern "C" returntype __stdcall __declspec(dllimport) 

và sau đó bạn có thể xác định macro khác nhau cho các trình biên dịch khác như gcc không sử dụng __declspec.

Các giải pháp hoàn chỉnh sẽ như thế nào (trong tập tin tiêu đề công cộng myproject.h):

#if _WIN32 
# if BUILDMYPROJECT 
# define MYPROJECTAPI(returntype) \ 
     extern "C" returntype __stdcall __declspec(dllexport) 
# else 
# define MYPROJECTAPI(returntype) \ 
     extern "C" returntype __stdcall __declspec(dllimport) 
# endif 
#else 
# define MYPROJECTAPI(returntype) extern "C" returntype 
#endif 

và sau đó Visual C++ của bạn dự án sẽ gây ra BUILDMYPROJECT phải được xác định khi xây dựng myproject.dll

+0

cách tạo dự án C++/CLI với studio trực quan 2010? –

+0

File -> New -> Project, sau đó Visual C++ -> CLR -> Class Library –

+0

Nó không xây dựng. Tôi có lỗi theo dõi: lỗi TRK0005: Không tìm được: "CL.exe". –

1
+0

Điều này không hỗ trợ quá trình ghi DLL * *, câu hỏi là gì. –

+0

Ok. Sự hiểu biết của tôi là ông đã yêu cầu một cách để giao tiếp với C/C++ dll từ .NET. Lớp P/Invoke làm việc đó. – Adi

+0

Cách tôi phân tích câu hỏi là "Làm cách nào để làm điều đó [viết một DLL có thể tương thích được]?" –

4

Tóm lại:

(1) Tạo một dự án thư viện C++/CLI mới.

(2) Viết mã của bạn. Đối với các lớp học mà cần phải được truy cập từ dự án # C của bạn, hãy chắc chắn để tạo ra chúng như các lớp học CLR:

public ref class R {/*...*/};  // CLR class 
public value class V {/*...*/};  // CLR struct 
public interface class I {/*...*/}; // CLR interface 

(3) Biên dịch dự án và thêm một tham chiếu đến nó trong dự án # C của bạn.

+0

cách tạo dự án thư viện C++/CLI với studio trực quan 2010? –

+0

@tinmaru: Tôi chưa cài đặt VS 2010 ngay bây giờ, nhưng theo MSDN (http://msdn.microsoft.com/en-us/library/0fyc0azh.aspx), cần có một "Thư viện CLR/Lớp học "mẫu dự án có sẵn. – Heinzi

1

Dưới đây là một ví dụ cho một ứng dụng mà tôi phải làm điều đó. Trong trường hợp của tôi, tôi cần một DLL để bọc các cuộc gọi đến các hàm chỉ có sẵn trong một .lib. Phần quan trọng là extern "C" __declspec (dllexport) trong tuyên bố. Đó là cơ bản tất cả những gì bạn cần. Phần còn lại chỉ đơn thuần là sử dụng dllimport trong ứng dụng C# và nhận được quyền sửa đổi.

extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope, 
                LPCVOID pvReserved1, 
                LPCVOID pvReserved2, 
                LPSCARDCONTEXT phContext) 
{ 
    return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext); 
} 
+0

Đừng quên '__stdcall' (hoặc tương đương, sử dụng macro' WINAPI'). Điều này sẽ đơn giản hóa p/gọi khai báo đáng kể. –