2011-12-06 37 views
7

Tôi đang cố gắng tìm phương thức thực hiện tốt nhất để gọi vào mã Managed .NET từ mã C++ không được quản lý. Tôi đã tìm thấy thông tin về Hosting .NET trong ứng dụng C++ của tôi và tôi có thể tạo một pRuntimeHost và khởi động nó mà không gặp vấn đề gì.Cách tốt nhất để gọi mã Managed .NET từ mã không được quản lý

ExecuteInDefaultAppDomain có vẻ rất hạn chế vì tôi thực sự muốn gửi một vài tham số và trả về cấu trúc thông tin. Cách thay thế rõ ràng nhất là sử dụng các phương thức COM nhưng mã C# hiện tại không thực sự được thiết lập như các giao diện với các phương thức.

Dù bằng cách nào tôi muốn trả về số nguyên, chuỗi (char *) s, gấp đôi và các loại C++ lõi khác. Có quá nhiều mã trên cả hai mặt để chuyển đổi C++ thành C# và sử dụng Managed C++ không phải là giải pháp có thể chấp nhận được, vì các nhóm khác sử dụng mã C++ này không muốn bắt đầu sử dụng mã Quản lý vì lý do hiệu suất.

Mục đích là sửa đổi mã C++ và C# hiện tại càng ít càng tốt nhưng vẫn sử dụng các phương thức trong mã C# tại các điểm cụ thể trong C++ mà không ảnh hưởng lớn đến tốc độ của mã C++.

Dựa trên mã được tìm thấy trên Internet khởi động và tắt máy tự để lưu trữ NET là:

#include "stdafx.h" 
#include <metahost.h> 

#pragma comment(lib, "mscoree.lib") 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ICLRMetaHost  *pMetaHost  = NULL; 
    ICLRMetaHostPolicy *pMetaHostPolicy = NULL; 
    ICLRDebugging  *pCLRDebugging = NULL; 

    HRESULT hr; 
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 
    hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy); 
    hr = CLRCreateInstance(CLSID_CLRDebugging, IID_ICLRDebugging, (LPVOID*)&pCLRDebugging); 

    DWORD dwVersion = 0; 
    DWORD dwImageVersion = 0; 
    ICLRRuntimeInfo *pRuntimeInfo; 
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID *)&pRuntimeInfo); 

    ICLRRuntimeHost * pRuntimeHost = NULL; 
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&pRuntimeHost); 

    hr = pRuntimeHost->Start(); 

    DWORD dwRetCode = 0; 
    //hr = pRuntimeHost->ExecuteInDefaultAppDomain(argv[1], L"MyNamespace.MyClass", L"Message", L"Hello World!", &dwRetCode); 

    // Stop the CLR runtime and shutdown cleanly. 
    hr = pRuntimeHost->Stop(); 
    hr = pRuntimeHost->Release(); 
    hr = pRuntimeInfo->Release(); 
    hr = pCLRDebugging->Release(); 
    hr = pMetaHostPolicy->Release(); 
    hr = pMetaHost->Release(); 

    return 0; 
} 

Trả lời

5

Có, tôi đồng ý với John. Bạn không thực sự muốn tạo một thể hiện mới của thời gian chạy và lưu trữ nó một cách rõ ràng. Đầu tiên, hệ thống ống nước đằng sau điều này không được ghi chép đầy đủ và có thể thay đổi trong các phiên bản sau. Thứ hai, C++/CLI được thiết kế để làm chính xác điều này một cách hiệu quả và an toàn nhất.

  1. Viết giao diện C++ gốc đại diện cho yêu cầu .Net funcionality.

  2. Thiết lập dll có hỗ trợ CLR, thực hiện giao diện gốc sử dụng các lớp nhân bản. Bên trong việc thực hiện của họ, bạn có thể tạo và truy cập các loại CLR và lưu các biến mẫu trong các trường gcroot<T>. Sử dụng tính năng interop funcionality clr để so sánh qua lại giữa mã được quản lý/không được quản lý, google hoặc bing cho marshal_as.

  3. Cung cấp chức năng nhà máy (không được quản lý), tạo một phiên bản của thành phần này. + Giao diện C++ không được quản lý này là API mà mã gốc của bạn sẽ thấy. Sử dụng dll chính xác giống như cách bạn sử dụng một dll không được quản lý.

+0

Lý do tạo một AppDomain bổ sung là mã C++ đã sử dụng AppDomain mặc định cho một số thứ và tôi không muốn có thêm .NET Assembly của mình can thiệp vào mã hiện tại và cũng để tránh làm cho công cụ của họ can thiệp vào . BTW Tôi quản lý để các lớp CLI làm việc hoàn hảo nhưng tôi vẫn đang cố gắng tìm ra cách để có được toàn bộ lớp CLI vào một AppDomain riêng biệt mà không phải là AppDomain mặc định. –

+0

Chưa cố gắng thực hiện điều đó, nhưng về mặt lý thuyết, điều này không phải là vấn đề. Tôi hiểu kịch bản của bạn là để gọi vào một thành phần được quản lý từ một bản địa, phải không? Có một tính năng được gọi là "quảng bá chuỗi" (google hoặc bing) khiến cho một chuỗi gốc được quảng bá đến một chuỗi được quản lý, bất cứ khi nào nó cố gắng thực thi mã được quản lý lần đầu tiên. Kể từ khi CLR không có ý tưởng trong đó AppDomain mã được quản lý được gọi theo cách đó nên thực hiện, nó đặt nó vào mặc định. Vì vậy, bạn sẽ phải xử lý rõ ràng quá trình chuyển đổi đó, có thể bằng cách sử dụng họ 'msclr :: call_in_appdomain' của các hàm. –

+0

Tôi đã ghi lại giải pháp cuối cùng của mình ở vị trí này: http://stackoverflow.com/questions/10301727/marshalling-c-pointer-interface-back-though-c-sharp-function-call-in-a-non-def –

3

Nếu đó là chấp nhận được, giải pháp tốt nhất có thể để tạo ra một C++ dll quản lý mà ngồi ở giữa . Mã C++ được quản lý là cách tốt nhất/hiệu quả nhất để bắc cầu mã được quản lý và không được quản lý.

Bạn thực sự không muốn thêm COM vào danh sách kết hợp. Điều đó sẽ làm chậm mọi thứ xuống nhiều hơn nữa.

Ngoài ra, những "lý do hiệu suất" này có để tránh mã được quản lý thực sự được định lượng không? Nghe có vẻ giống như một giai thoại ném ra để tránh cái gì đó mà họ không muốn. Ngoài ra, bạn có thể chỉ ra rằng chúng được đã sử dụng mã được quản lý, vì C# nằm trong danh sách kết hợp.

+0

Hiệu suất được tính bằng micro giây. Vì vậy, sau khi tất cả điều này tôi đã thêm bộ nhớ đệm của yêu cầu/phản ứng như là một bản đồ C++ std ::. Điều này cho phép tra cứu nhanh bất kỳ thứ gì được yêu cầu trước đó mà không cần quay lại lớp C#. Tôi đã đính kèm thông tin bổ sung ở trên. –

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