zoukankan      html  css  js  c++  java
  • C++调用C#dll类库中的方法(非显性COM)

            一般在网上搜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 *,既然是指针就可以传递对象,同样返回值也可以是结构体或者数组。

    本例地址:https://files.cnblogs.com/files/chihirosan/CPPCS%E4%BA%A4%E4%BA%92.rar

  • 相关阅读:
    mysql5.5 uuid做主键与int做主键的性能实测
    dom4j解析xml字符串实例
    spring自动注入是单例还是多例?单例如何注入多例?
    Spring中Bean的五个作用域
    【总结】瞬时高并发(秒杀/活动)Redis方案
    浅谈分布式事务
    基于Redis实现分布式锁
    MySQL事务隔离级别详解
    Redis学习手册(Sorted-Sets数据类型)
    Redis的快照持久化-RDB与AOF
  • 原文地址:https://www.cnblogs.com/chihirosan/p/5162724.html
Copyright © 2011-2022 走看看