先感慨一下,研究这个问题研究了四个工作日才解决,实在是太不容易了,现在很开心很得意,叉会腰哈哈~
虽然就是一件看起来很简单的事情,我相信你在看到我这篇文章之前也已经看过许多相关文章了,但是很多细节需要注意,哪一步没有做好可能就走入了一个无尽的陷阱绕许多弯路,把我的经验分享出来如果能帮助到也遇到相同问题的小伙伴,就真的太好不过了。(我的开发环境:WinXP-VC++6.0 C++ & Win7-VS2015 C#)
用C++调用C#dll一般是两个方式:
①C++直接调用C#生成的DLL。这个方法要求C++在编译时要选择公共运行时支持(CLR),因为我最终需要用VC6编译程序,我没在VC6中找到有关CLR的设置,又考虑到这个方法以后可能会存在很多平台的限制,就放弃了。
②C++以COM形式调用C#生成的DLL。我用的是这个方法,下面具体来阐述一下。
首先,在C#方面的操作:
一、新建类库工程
上方选择.NET版本,建议选择2.0-4.0之间的,因为XP环境最高支持4.0,这个版本选择很重要,之后注册COM会有影响,要注意。
二、添加C#代码
在类文件里面编辑代码,写一个加法例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;//需要添加这个命名空间
namespace MyCom5
{
[Guid("36A57710-4EA3-4EA1-9AA1-3EF1EB6209C4")]//菜单栏-工具-创建GUID-选5.[Guid(xxxx...)]后复制粘贴到此处
public interface MyCom5_Interface
{
[DispId(1)]//说是每多一个方法就要写一个这个(1)、(2)...不写好像也没事
int Add(int a, int b);
}
[Guid("90316C3B-6305-41D7-B5DB-28F62DDCC728"),InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
//Guid的生成同上,是不同的Guid哈,后面的一段代码是我copy来的,暂时不知道什么用处,似乎不加也没事的
public interface MyCom5_Events
{
//C++调用方法需要走接口形式,这个方法接口虽然没写东西但是先写在这了吧,不知道啥用
}
[Guid("65498AC7-646B-445B-825F-309D308F04F6"),ClassInterface(ClassInterfaceType.None),ComSourceInterfaces(typeof(MyCom5_Events))]
//同上
public class Class1 : MyCom5_Interface
{
public int Add(int a, int b)
{
return a + b;
}
}
}
三、配置及生成COM
代码写好以后需要做以下配置:
1)菜单-项目-属性-应用程序-程序集信息-使程序集COM可见(要勾选上),大概就是封装为一个COM并可见的意思
2)菜单-项目-属性-生成-为COM互操作注册(要勾选上),勾选这个就在本机注册了这个COM组件。
(说道注册,多说几句,以前一直不太懂注册组件是什么意思,我的理解是,COM组件不能够像有的DLL可以直接调用,需要告诉电脑COM组件的位置和一些数据信息,所以就需要将COM组件注册到注册表,这样当程序调用了这个COM组件的时候,系统就会自己去找到这个COM组件。一般用regsvr32在cmd中进行注册)
3)菜单-项目-属性-生成-目标平台改为x86,这个真的很重要啊,因为之后要用到XP中去
4)强名称密钥文件
封装为COM组件就需要给COM加密的意思,具体的操作是,首先运行VS的命令提示符,在开始菜单-Visual Studio 2015 -Visual Studio Tools - VS2015开发人员命令提示,和运行cmd是一样的界面,但是指令不一样一定要用这个哈。以管理员权限运行后,
输入 sn -k D:\MyCom5.snk
即可在D盘根目录生成强名称密钥文件,可以自己换路径和名字。再拷贝到C#工程和.csproj相同的目录下。
然后回到C#代码,打开AssemblyInfo.cs,在里面添加一句:
[assembly:AssemblyKeyFile("MyCom5.snk")]
5)生成类库文件
选择全部重新生成,就会在Debug下面生成三个文件分别是: .dll .tlb .pdb 最后一个没啥用,可以不管了
到此为止,C#的工作就完成了。
好了下面我们来到XP的VC6:
1)新建一个C++程序,选择一个控制台程序作为例子。
2)将之前在C#生成的.dll和.tlb文件拷贝到C++工程的和Debug文件相同目录下
3)编写代码
#include "stdafx.h"
#import "MyCom5.tlb"//添加调用tlb文件
using namespace MyCom5;//声明COM文件的命名空间
int main(int argc, char* argv[])
{
CoInitialize(NULL); //初始化函数
MyCom5_InterfacePtr p(__uuidof(Class1));//定义一个智能指针
int a = p->Add(4, 5);//使用COM中函数
printf("%d\n",a);
getchar();
return 0;
}
这个时候编译的话是会报错的,因为我们还没有注册这个COM
4)注册COM
以往注册COM都是用指令regsvr32,但是C#写的COM需要在使用.NET中自带的Regsam.exe来注册,具体方法是:管理员权限打开cmd,先定位到Regasm.exe的目录,C:\Windows\Microsoft.NET\Framework\v2.0.50727,这个目录有两个要注意的地方,因为我是在XP中运行,并且.NET版本之前选的2.0,所以是Framework\v2.0.50727,如果是想要在64位机器上运行或者其他.NET版本生成的就要相应改一下,要不无法注册成功。输入regasm 路径\MyCom5.dll,注册成功会有提示信息。
好啦,一切就绪,激动人心的时刻要到了,先重新生成一下C++项目,编译链接运行。。。
什么??执行不了??运行错误??很头疼啊,为什么一切都是按照步骤好好做的,哪里出问题了呢。这个问题折磨了我好几天,最后发现是.dll文件不只是要拷贝到Debug同目录文件下,还要拷贝到和exe同目录下!疏忽了,后来听别人说是注册后的DLL文件是需要放在和exe同目录下的,不是说注册过后就可以不管它路径了,系统只会去和exe相同的路径下找。
好啦,最后终于成功了,开心心~~下班回家!