通過CLR API實現C++調用C#代碼交互


對於某些跨平台程序,這也就意味着只能在windows下使用了

不過最近.Net開源或許以后可以跨平台

 

之前花了一些時間研究COM方式調用,太繁瑣不推薦。 COM方式調用總結

后來嘗試使用CLR C++,雖然可以用.Net的接口直接載入,但他只是一層C++的皮,最終沒能運用在實際項目中。

最后使用MS提供的CLR API接口,完成調用 MSDN CLR接口介紹

 

=======================================================

有幾個注意點:

1.官方一直強調的簽名格式static int pwzMethodName (String pwzArgument),並非某個C#特性,而是函數格式必須是帶一個string參數返回int型。否則在調用時會報找不到方法。

2.ExecuteInDefaultAppDomain中,dll路徑支持相對路徑格式,"xx.dll"是可以被識別的。

3.GetRuntime方法獲得的.Net版本號,需要去c:/windows/Microsoft.NET下找,64位對應Framework64,普通版對應Framework。如果目標機器沒有該文件夾,說明對應版本的.net未安裝。那么程序就會報錯。版本號第三位數字似乎是死的,應該都是統一的發行版。

4.在創建測試項目時,需要點掉預編譯頭選項,否則會出現許多莫名其妙的錯誤。

5.需要在管理員權限下使用

6.類可以是靜態類或者非靜態,但函數必須是靜態函數

 

參考代碼摘自github:

https://github.com/entice/client/blob/42f388d68b1954ef244c379560eeb4867ae80b7e/Loader/Loader/DllMain.cpp

 

具體上代碼

 

C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ClassLibrary1
{
    public class Class1
    {
        public static int EntryPoint(string arg)
        {
            File.AppendAllText("C:/xx.txt", "qweqwe");
            return 0;
        }
    }
}
View Code

 

 

C++

//Reference From GitHub entice:https://github.com/entice/client/blob/42f388d68b1954ef244c379560eeb4867ae80b7e/Loader/Loader/DllMain.cpp

#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <mscoree.h>
#include <metahost.h>
#include <assert.h>

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

#define BUFFER_SIZE 500
#include "stdafx.h"


void StartTheDotNetRuntime(LPCWSTR runtimeVersion, LPCWSTR dllPath, LPCWSTR startClass, LPCWSTR startMethod, LPCWSTR startArgument)
{
    ICLRMetaHost *pMetaHost = NULL;
    ICLRMetaHostPolicy *pMetaHostPolicy = NULL;
    ICLRDebugging *pCLRDebugging = NULL;

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

    DWORD dwVersion = 0;
    DWORD dwImageVersion = 0;
    ICLRRuntimeInfo *pRuntimeInfo;
    HRESULT result;
    result = pMetaHost->GetRuntime(runtimeVersion, IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
    assert(SUCCEEDED(result));

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

    result = pRuntimeHost->Start();
    assert(SUCCEEDED(result));

    DWORD dwRetCode = 0;
    result = pRuntimeHost->ExecuteInDefaultAppDomain(dllPath, startClass, startMethod, startArgument, &dwRetCode);
    assert(SUCCEEDED(result));
    pRuntimeHost->Stop();
    pRuntimeHost->Release();
    pRuntimeInfo->Release();
    pCLRDebugging->Release();
    pMetaHostPolicy->Release();
    pMetaHost->Release();
}

void Loader()
{
    wchar_t* runtimeVersionSpace = new wchar_t[BUFFER_SIZE];
    wchar_t* dllPathSpace = new wchar_t[BUFFER_SIZE];
    wchar_t* currentDir = new wchar_t[BUFFER_SIZE];

    GetCurrentDirectoryW(BUFFER_SIZE, currentDir);

    StartTheDotNetRuntime(L"v4.0.30319", L"ClassLibrary1.dll", L"ClassLibrary1.Class1", L"EntryPoint", L"");

    free(runtimeVersionSpace);
    free(dllPathSpace);
    free(currentDir);
}


int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loader, NULL, 0, NULL);

    for (size_t i = 0; i < 10; i++)
    {
        Sleep(100);
    }

    TerminateThread(handle, 0);

    return 0;
}
View Code

 

 

然后把c#生成的dll,放到c++的build目錄下,再以管理員權限執行即可。

最后會在c盤根目錄下創建一個xx.txt文件。說明調用C#成功


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM