2012-07-22 40 views
5

Được cung cấp: Sử dụng dll thực thi. Chúng có thời gian chạy c/C++ khác nhau. Những hạn chế nào tồn tại trong giao diện giữa chúng? Bên cạnh đó, họ sử dụng cùng một trình biên dịch, phiên bản Boost tương tự (nhưng các libs được biên dịch sẵn khác nhau).giao diện giữa exe và dll với thư viện thời gian chạy C/C++ khác nhau

Tôi hiểu rằng thời gian chạy khác nhau có thể có các vùng khác nhau. Vì vậy, xóa phải tương ứng với mới từ cùng một đống.

Quan trọng nhất là chúng tôi không thể chuyển qua đối tượng STL giao diện vì khi chúng tôi xây dựng đối tượng STL exe được liên kết với một thời gian chạy và khi xây dựng dll cùng một đối tượng (nếu chúng ta chuyển nó bằng tham chiếu hoặc sao chép qua giao diện) sẽ được liên kết với thời gian chạy khác. Và một thời gian chạy khác có thể có cách triển khai khác nhau của đối tượng đó.

Hãy xem xét trường hợp:

  1. Tôi nghĩ rằng đây là an toàn. Hàm xuất dll có tham số: tham chiếu đến lớp được người dùng định nghĩa xuất khẩu có chứa lớp STL riêng tư làm thành viên. Dll phân bổ bộ nhớ cho đối tượng này. Exe gọi phương thức Release của đối tượng này khi muốn xóa nó.

  2. Tôi nghĩ những điều sau KHÔNG an toàn. Lớp người dùng định nghĩa được khởi tạo trong exe và được truyền qua giao diện exe/dll. Lớp này chứa lớp STL riêng tư làm thành viên. exe và dll chia sẻ các tiêu đề/tệp triển khai của lớp người dùng này. Khi lớp này được xây dựng trong các dự án riêng biệt, việc triển khai STL khác nhau sẽ được sử dụng. Ví dụ thực hiện khác nhau của chuỗi :: size() (từ các thời gian chạy khác nhau) sẽ được áp dụng cho cùng một đối tượng trong bộ nhớ.

  3. Tôi nghĩ những điều sau đây là an toàn. Lớp người dùng định nghĩa được khởi tạo trong exe và được truyền qua giao diện exe/dll. Lớp này không phụ thuộc vào thư viện Chuẩn, nó chỉ sử dụng các kiểu C++ nguyên thủy. exe và dll chia sẻ các tiêu đề/tệp triển khai của lớp người dùng này. Ngoài ra chúng ta phải kiểm soát mới và xóa tương ứng với cùng một đống. Ví dụ, chúng tôi có thể quá tải mới/xóa để họ sử dụng :: GetProcessHeap.

  4. Tôi nghĩ những điều sau đây KHÔNG an toàn: chuyển các đối tượng tăng cường thông qua giao diện exe/dll vì chúng có thể phụ thuộc vào các lớp thư viện chuẩn. Cũng xóa có thể không tương ứng với heap mới. Tôi nghĩ rằng sau đây là không an toàn: ngay cả khi chúng tôi vượt qua các đối tượng tăng thông qua giao diện exe/dll và họ không phụ thuộc vào các lớp thư viện chuẩn nhưng không được thực hiện như là tiêu đề chỉ - hơn đối tượng có thể được tạo ra với một thúc đẩy lib (cho một thời gian chạy) và được sử dụng với một lib tăng (cho một thời gian chạy khác). Cũng xóa có thể không tương ứng với heap mới.

Ngoài ra tôi muốn sử dụng một số hương vị của con trỏ thông minh để chuyển tham chiếu đến các đối tượng (được đề cập trong mục 3) từ exe sang dll và từ dll sang exe. Tôi nghĩ con trỏ thông minh này cũng nên quá tải mới/xóa để phân bổ bộ đếm tham chiếu từ heap quá trình mặc định. Khi nó sẽ cố gắng xóa đối tượng nhọn nó sẽ gọi xóa rằng quá tải bởi đối tượng này (như trong mục 3)

Đối với các đối tượng từ mục 1 Tôi muốn sử dụng con trỏ thông minh tùy chọn gọi phương thức phát hành của đối tượng nhọn (như boost :: shared_ptr với bản phát hành tùy chỉnh)

Vấn đề nào không được đề cập? Hãy sửa tôi.

Trả lời

4

Câu trả lời chung cho câu hỏi của bạn là: làm một cái gì đó cho một đối tượng nhận được từ một EXE/DLL là an toàn nếu những gì thực sự được thực hiện không phụ thuộc vào thời gian chạy. Ví dụ. các cuộc gọi vtable, các cuộc gọi hàm con trỏ, các cuộc gọi hàm rõ ràng từ DLL.

Những điều phụ thuộc vào thời gian chạy (phương thức nội tuyến từ tệp tiêu đề, bất kỳ điều gì tạo ra bất kỳ giả định nào về bố cục đối tượng STL, v.v.) không an toàn.

Trở lại với ví dụ của bạn:

  1. Nếu bạn gọi phương thức phát hành(), bạn nên cẩn thận và đảm bảo rằng bạn sẽ gọi cho việc thực hiện phát hành() từ các DLL và không khác thực hiện điều đó được tạo bởi trình biên dịch tạo tệp EXE. Cách dễ nhất để đảm bảo nó là tạo ra Release() ảo để cuộc gọi luôn là một cuộc gọi bằng cách sử dụng một con trỏ phương thức từ vtable (do DLL cung cấp).

  2. Phương thức nội tuyến từ STL như chuỗi :: size() sẽ gây ra sự cố tại đây.

  3. Phải. Nếu mới/xóa cả hai bị quá tải để sử dụng GetProcessHeap(), mã sẽ hoạt động.
  4. Nói chung, đúng. Đặc biệt, hãy xem việc thực hiện các lớp tăng cường mà bạn cần.
  5. Nếu chúng không phụ thuộc vào STL và bạn chắc chắn rằng dấu chân bộ nhớ là giống nhau cho cả hai trình biên dịch và bạn đã cung cấp tùy chỉnh mới/delete(), nó thường không phải là vấn đề (xem nhận xét bên dưới).

Ghi chú:

Có một vài xác suất thấp những điều mà có thể gây ra các vấn đề không được đề cập ở trên:

  1. Nếu bạn sử dụng trình biên dịch khác nhau, họ có thể sử dụng công ước gọi khác nhau theo mặc định (cdecl/stdcall).
  2. Tùy chọn căn chỉnh mặc định cũng có thể khác nhau dẫn đến bố cục bộ nhớ khác nhau.
  3. Nếu bạn ném ngoại lệ từ tệp DLL của mình, exe có thời gian chạy khác có thể không bắt được chúng, nhưng thay vào đó là lỗi.
  4. Đánh dấu các phương thức có thuộc tính xuất/nhập DLL và đảm bảo rằng chúng không được gạch chân có thể khá phức tạp. Hơn nữa, nếu bạn đang sử dụng các trình biên dịch khác nhau, thuật toán mangling tên C++ có thể khác nhau.

Có những điều tóm tắt, bạn nên xem cách mọi thứ được triển khai trong Microsoft COM và thiết kế một cái gì đó tương tự. I E. hạn chế tương tác EXE/DLL thành:

  1. Giao diện. I E. Các lớp C++ chỉ với các phương thức ảo thuần túy. Sử dụng Bản phát hành ảo() để xóa các đối tượng.
  2. Cấu trúc đơn giản được xác định rõ ràng. Đảm bảo rằng các tùy chọn căn chỉnh cho tất cả các trình biên dịch khớp nhau. Nếu bạn muốn sử dụng cấu trúc không tầm thường và bạn đang sử dụng trình biên dịch khác nhau, tốt hơn là hoang tưởng và đặt kiểm tra như thế này:

    chức năng
    struct MyStruct 
    { 
        ... 
    }; 
    C_ASSERT(sizeof(MyStruct) == ...); 
    C_ASSERT(FIELD_OFFSET(MyStruct, MyMember) = ...); 
    
  3. C giống như đi qua và/hoặc trả lại con trỏ đến giao diện.

  4. Không ném ngoại lệ từ các phương pháp được gọi là EXE
Các vấn đề liên quan