介绍
在之前的博文 C#与VC相互调用之C#调用VC的DLL /xinxin_/article/details/86704660 里面讲了C#程序如何调用VC的DLL,这里我们来介绍VC程序调用C#的DLL。
项目创建
打开VS,因为涉及到两个程序,这里先创建一个空的解决方案:
然后往里面添加一个C#的DLL项目:
选择“类库”项目模板:
点击完成后生成如下文件:
默认生成的是Class1类,我们改名为“CSharpDll”,并添加如下代码:
接下来再创建一个VC项目,来测试DLL的调用:
这里创建一个基于对话框的MFC程序:
点击下一步,只选一个粗框架就可以了:
继续下一步,只勾选“公共控件清单”即可:
按照默认的名字生成类文件:
点击完成后,自动生成如下项目文件:
编写测试代码
简单修改下VC页面视图:
其中“调用C#的库”按钮ID为ID_CSHARPDLL_BTN,编辑框的ID为IDC_EDIT_RES。双击按钮,添加处理函数:
上面代码会有很多划红线的错误,因为用到了gcnew和System::String等公共语言运行库,所以得在项目属性中添加“公共语言运行时支持”:
此外注意文件上方要添加C#库的引用:
#using "../CSharpLibrary/bin/Debug/CSharpLibrary.dll"using namespace CSharpLibrary;
这里注意路径的写法,默认当前路径是TestCSharpDll目录,而CSharpLibrary与TestCSharpDll同在一个解决方案目录中,生成的库在CSharpLibrary的bin/Debug目录下,所以这样写。
先别着急编译,因为VC程序要调用DLL必须保证生成的exe和dll文件在同一目录,所以需要改一下VC程序生成exe的路径:
写好后把把VC程序设置为启动项目:
设置好之后就可以编译了,成功后生成如下文件:
看到exe和dll都生成了就可以运行程序进行测试了:
可以看到VC和dll的交互都正常,如果没出现正确结果,请仔细检查路径设置的是否正确。
细节说明
调用测试完了,有些细节需要说明一下,看代码:
System::String ^proName = gcnew System::String(L"张三");
这里的字符串传参为什么是L"张三"呢?因为用到的是Unicode字符集,前面加上L代码是宽字符,如果对字符集不太了解的,可以参见我之前文章 VS下使用多字符集编码和Unicode字符集编码的总结 /xinxin_/article/details/84985083
顺便再提一下字符串变量转换的时候用到的强制转换:
CString str = (CString)res;
那位说这样强制转换觉得不太安全,那么CString有没有构造函数传参System::String呢?因为是宽字符,所以得看CStringT的源代码,CStringT中有一个传入System String的构造函数:
// This template will compile only for // class SystemString == System::String #if defined(__cplusplus_cli) template <class SystemString> CStringT( SystemString^ pString ) : CThisSimpleString( StringTraits::GetDefaultManager() ) { cli::pin_ptr<const System::Char> pChar = PtrToStringChars( pString ); const wchar_t *psz = pChar; *this = psz; } #elif defined(_MANAGED)
好了,既然有这样的构造函数,我们就可以替代强制转换了,改为如下代码:
VC调用C#的Dll显示界面
上面只是介绍了简单的字符串传递,那么VC能不能调用C#的Dll中的界面呢?下面来测试一下,在CSharpLibrary项目中添加一个界面类:
然后编辑窗体视图如下:
然后修改CSharpDll类,添加调用界面的函数:
最后在VC的OnBnClickedCsharpdllBtn函数中添加调用的代码:
看一下运行的结果:
OK,一切正常。