c++ 调用c#dll (2种方式,com组件和clr工程)

本文介绍了如何创建C#COM组件,包括定义接口,生成强名称密钥文件,配置项目属性以生成COM组件,并通过regasm进行注册。同时讨论了.NET版本与运行环境的对应,以及32位和64位系统的兼容性问题。最后提到了C++项目中调用这些组件的方法。
摘要由CSDN通过智能技术生成

创建C#项目

创建C#项目时选择的.net版本需要与运行环境中的.net版本相对应 

1、COM组件方式

COM组件都是通过调用接口的形式实现功能调用,使用编写dll需要定义接口,继承接口实现功能。

C#代码示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ClassLibrary4
{
    //每个接口或类需要一个唯一的uuid,作为调用时的唯一标识
    [Guid("13F7B841-AFA6-4278-AF04-F77E86A5F8D3")]
    public interface myInterface
    {
        [DispId(1)]//说是每多一个方法就要写一个这个(1)、(2)...不写好像也没事
        int add(int a, int b);
    }

    [Guid("543E9431-FE73-43F7-84AA-10687D87603E")]
    public class Class1 : myInterface
    {
        public int add(int a, int b)
        {
            return a + b;
        }
    }
}

调用COM组件时,查找其中方法都是通过唯一的uuid,使用dll中每个接口或类都需要唯一的uuid。uuid创建:【工具】——》【创建GUID】,选择5,复制即可

生成强名称密钥文件

这一步时为了给COM组件加密

以管理员权限运行VS的命令提示符,在开始菜单 —> developer for PowerShell for VS 2019,输入 sn -k D:\ClassLibrary3.snk,(输出目录可以更换),运行成功得到加密文件,将加密文件复制到项目的解决方案同级目录下。

 配置生成COM组件

a)【项目】—>【属性】—>【应用程序】—>【程序集信息】—>勾选【使程序集COM可见】,也可以到AssemblyInfo.cs文件中,将[assembly: ComVisible(false)]属性改为true

b)【项目】—>【属性】—>【生成】—>勾选【为COM互操作注册】

c)【项目】—>【属性】—>【签名】—>勾选【为程序集签名】—>【选择强名称密钥文件】—>【浏览】,选择②中生成的强名称密钥文件,在AssemblyInfo.cs文件中添加[assembly:AssemblyKeyFile("ClassLibrary4.snk")]

 配置完成后,点击运行在debug目录下就会生成dll文件和tlb文件

将COM组件注册到注册表中(把GUID导入注册表) 

a)以管理员方式运行命令提示符,到目录C:\Windows\Microsoft.NET\Framework64\v4.0.30319(根据自己的.net版本调整)输入

regasm dll路径\dllName.dll
regasm dll路径\dllName.dll /tlb:dllName.tlb

显示注册成功即可,每个.net版本都有对应的regasm.exe程序,.net版本不对会导致注册不成功。

b)以管理员方式运行命令提示符,到目录C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools(注意区分版本),输入gacutil 指令,将dl加入到缓存中,显示Assembly successfully added to the cache,即成功。

gacutil /i dll路径\dllName.dll

另外还有regasm  /regfile指令可以生成COM组件的注册表文件,可以使用该注册表文件在其他电脑上直接注册COM组件(该步骤可选)

regasm dll路径\dllName.dll /regfile: CalcClass.reg

 到此完成dll文件生成。

调用

C++项目示例代码

#include <iostream>
#include<Windows.h>
#include<atlcomcli.h> //导入tlb文件关键引用
#import "ClassLibrary4.tlb"
using namespace ClassLibrary4;
int main()
{
    CoInitialize(NULL);
    myInterfacePtr dll(__uuidof(Class1));//根据Class1的GUID生成一个智能指针
    int a = dll->add(4, 5);//使用COM中函数
    std::cout << a ;
    getchar();
    return 0;
}

项目配置

【项目】——》【属性】——》【配置属性】——》【高级】——》【启用托管增量生成】——》【否】

 配置完成后将C#项目中生成的.tlb文件复制到C++项目解决方案同级目录下,启动程序,在debug目录下会生成.tlb对应的.tlh和.tli文件

 运行结果

 2、clr工程方式

项目创建方式与COM组件方式一致

C#示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassLibrary3
{
    public class Class1
    {
        public Class1() { }//必须声明构造函数
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
}

编写完成后成功运行项目,即dll生成完成,将生成的dll文件复制到调用该dll文件项目的exe文件同级目录下。

C++项目示例代码

#include <iostream>
//通过绝对路径引入dll文件
#using "D:\ProjectP\VS\dllConnectTest1\x64\Debug\ClassLibrary3.dll"
using namespace ClassLibrary3;
int main()
{
    Class1^ dll = gcnew(Class1); //创建dll中的对象指针
    int result = dll->Add(4,5);//调用dll对象中的方法
    std::cout << result;
    getchar();
    return 0;
}

配置C++项目

a)【项目】-》【属性】-》【配置】-》【配置】-》【高级】-》【公共语言运行时支持】-》【公共语言运行时支持 (/clr)】

b)【项目】-》【属性】-》【配置】-》【C/C++】-》【语言】-》【符合模式】-》【否(/premissive)】

调用成功回生成dll对应的一些文件

 测试结果

后续问题

  1. 后续项目中再次使用C#编写的COM组件时发现有些电脑无法注册成功,原因是电脑的系统版本,COM组件生成时建议生成为32位的版本,比较兼容,相对应的在注册COM组件时,需要修改regasm.exe程序的目录为“C:\Windows\Microsoft.NET\Framework\v4.0.30319”,64位版本为“Framework64”。
    在查找资料的过程中,发现有些文中提到了COM组件的自动注册,比如调用COM组件的DllRegisterServer接口,实现注册,利用regsvr32注册实际上也是调用COM组件的DllRegisterServer接口,但是以上方式都只适用于C++编写的COM组件,C#的COM组件不实现DllRegisterServer接口,所以用regsvr32没办法注册。如果调用COM组件的程序也是C#编写的可以尝试使用IRegistrationServices.RegisterAssembly 方法实现自动注册,否则只能使用regasm.exe手动注册,本文中的方法就是该方法,比较繁琐。
  2. 开发过程中重载了一些接口,但是在调用时发现抱错,无法调用,查看后发现在COM组件中如果方法名一样,会自动为重名的方法接口重命名,如COM组件中有接口Add(int a, int b)和Add(int a, int b, int c),在生成的dll中会将其中一个Add接口重命名为 Add_2()

免注册方案

注册是为了将COM组件写入到注册表中,程序运行时通过CUID到注册表中查找对象或者方法,由此可以通过程序清单文件的方式让程序获取COM组件中的接口。

程序清单文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity name="dllName" version="1.0.0.0" processorArchitecture="msil">
  </assemblyIdentity>
  <clrClass
		clsid="{dllName.接口对应的实现类的GUID}"
		progid="dllName.接口对应的实现类" threadingModel="Both"
		name="dllName.接口对应的实现类" runtimeVersion="v4.0.30319">
  </clrClass>
  <file name="dllName.dll" hashalg="SHA1">
  </file>
</assembly>

程序清单文件需要和dll一起放到调用dll的程序的生产路径下。如果是在VC6构建的mfc项目下,需要把生成的.tlb文件一起放到debug或者release目录下,如果出现“未注册类”,可以尝试用x86环境生成dll再调用。

以上为本人开发过程中的一些总结,理论部分没有深入探索,如果有错误,请各位大佬指正

以下是一个简单的Python实现Taylor Diagram的示例代码: ```python import numpy as np import matplotlib.pyplot as plt def taylor_diagram(std_devs,corrs,colors,markers): # 计算标准差和相关性的平均值 std_dev_r = np.mean(std_devs) corr_r = np.mean(corrs) # 设置图形的大小和边距 plt.figure(figsize=(8,8)) plt.subplots_adjust(wspace=0.3,hspace=0.3) # 绘制标准差和相关性的轴 plt.plot([0,std_dev_r],[0,corr_r],'k-',label='Reference') plt.plot(std_devs,corrs,'ko',markerfacecolor='white') # 绘制每个模型的标准差和相关性 # 绘制每个模型的名称 for i in range(len(std_devs)): plt.text(std_devs[i],corrs[i],str(i+1),color=colors[i],ha='center',va='center') plt.plot(std_devs[i],corrs[i],markers[i],color=colors[i]) # 设置图例和轴标签 plt.legend(loc='best',fontsize=12) plt.xlabel('Standard Deviation',fontsize=14) plt.ylabel('Correlation Coefficient',fontsize=14) plt.title('Taylor Diagram',fontsize=16) # 显示图形 plt.show() # 示例 std_devs = [0.5,0.6,0.7,0.8,0.9] corrs = [0.9,0.8,0.7,0.6,0.5] colors = ['r','g','b','c','m'] markers = ['s','o','^','D','*'] taylor_diagram(std_devs,corrs,colors,markers) ``` 其中,`std_devs`和`corrs`分别是模型的标准差和相关性系数,`colors`和`markers`分别用于绘制不同模型的标记和颜色。函数中还计算了标准差和相关性系数的平均值,并将其作为参考线。最后,将每个模型的标准差和相关性绘制在图上,并用不同的颜色和标记区分不同的模型。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值