一般在網上搜C++如何調用C#的函數,出來的結果都是做成COM組件,但是這種方法dll安裝麻煩,需要註冊COM組件,需要管理員許可權,調試麻煩,經常需要重啟機器,反正有諸多不便。 然後在看《CLR via C#》時看到一種方法,可以免去這種苦惱。少廢話,先上代碼。C#類庫的:namespace Cl....
一般在網上搜C++如何調用C#的函數,出來的結果都是做成COM組件,但是這種方法dll安裝麻煩,需要註冊COM組件,需要管理員許可權,調試麻煩,經常需要重啟機器,反正有諸多不便。
然後在看《CLR via C#》時看到一種方法,可以免去這種苦惱。少廢話,先上代碼。
C#類庫的:
namespace ClassLibrary1 { public class Class1 { public static int pwzMethodName(String pwzArgument) { //Thread.Sleep(10000); Console.WriteLine(pwzArgument); Console.WriteLine(Thread.GetDomain().FriendlyName); } } }
C++調用代碼:
#include <metahost.h> #include <fstream> using namespace std; #pragma comment(lib, "mscoree.lib") int _tmain(int argc, _TCHAR* argv[]) { ICLRMetaHost *pMetaHost = nullptr; ICLRMetaHostPolicy *pMetaHostPolicy = nullptr; ICLRRuntimeHost *pRuntimeHost = nullptr; ICLRRuntimeInfo *pRuntimeInfo = nullptr; HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); if(FAILED(hr)) { MessageBox(0,L"啟動出錯",L"Error",MB_OK|MB_ICONERROR); goto cleanup; } hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost)); hr = pRuntimeHost->Start(); DWORD dwRet = 0; hr = pRuntimeHost->ExecuteInDefaultAppDomain(L"ClassLibrary1.dll", //不會產生新的進程 L"ClassLibrary1.Class1", L"pwzMethodName", L"nimei", &dwRet); hr = pRuntimeHost->Stop(); cleanup: if(pRuntimeInfo != nullptr) { pRuntimeInfo->Release(); pRuntimeInfo = nullptr; } if(pRuntimeHost != nullptr) { pRuntimeHost->Release(); pRuntimeHost = nullptr; } if(pMetaHost != nullptr) { pMetaHost->Release(); pMetaHost = nullptr; } }
C#的代碼就不解釋了,就是提供一個int ClassLibrary1.Class1.pwzMethodName(String)的這樣一個方法。
重點看一下C++,它的思路就是通過metahost.h中的函數來操作clr環境。
第一句,CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost) 來初始化CLR環境,得到返回值pMetaHost。
第二句,pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)) 來指定運行時,第一個參數.NET版本號,必須和你的C#dll的版本號相容,而且 此參數必須與顯示在 C:\Windows\Microsoft.NET\Framework 或 C:\Windows\Microsoft.NET\Framework64 下的 .NET Framework 版本目錄名稱相匹配。比如,你的dll是用4.0編譯的,而你的Framework目錄有一下文件夾:v2.0.50727 v3.0 v3.5 v4.0.30319 ,所以這裡的參數就是“v4.0.30319”,而且v是必須的。
第三句,pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost)) 將 CLR 載入到當前進程中,並返回運行時介面指針pRuntimeHost。
第四句,pRuntimeHost->Start() 將公共語言運行時 (CLR) 初始化到進程中。
第五句,pRuntimeHost->ExecuteInDefaultAppDomain
HRESULT ExecuteInDefaultAppDomain ( [in] LPCWSTR pwzAssemblyPath, [in] LPCWSTR pwzTypeName, [in] LPCWSTR pwzMethodName, [in] LPCWSTR pwzArgument, [out] DWORD *pReturnValue );
pwzAssemblyPath是C#類庫的路徑和文件名,pwzTypeName是命名空間和類名,pwzMethodName是要調用的方法名稱,pwzArgument是要傳入的參數名稱,pReturnValue是函數返回值。
後面的都是釋放語句。
一般看來,這種方法只能調用int function(String para)這樣的函數,但是實際上LPCWSTR 是WCHAR *,既然是指針就可以傳遞對象,同樣返回值也可以是結構體或者數組。
本例地址:http://files.cnblogs.com/files/chihirosan/CPPCS%E4%BA%A4%E4%BA%92.rar