本文实例展示了C++与C#互调dll的实现步骤,在进行大型项目共享dll动态链接库中可以用到。具体方法如下:
一、C#调用C++ dll步骤(只能导出方法):
1. c++建立空项目->源文件文件夹中添加cpp文件和函数
2. c++属性设置中,配置类型设置为动态库dll,公共语言运行时支持改为/clr
3. c#引用c++的dll
4. c#声明c++的方法,并添加 DllImport特性
5. c#工程属性设置为:目标平台x86
6. 注意方法的类型匹配
7. 引发PInvokeStackImbalance异常:注意:C++的"_declspec"和C#的“CallingConvention=CallingConvention.Cdecl”
另外,可以通过VS的异常窗口,取消掉对 PInvokeStackImbalance异常的检测:
点击VS的“调试 - 异常”,打开异常窗口,展开选择“Managed Debugging Assistants\PInvokeStackImbalance”,去掉对应的“引发”可选框。
二、 c++调用 c# dll的步骤(可直接使用C#类):
1. 创建c++控制台应用程序
2. 拷贝c# dll到c++工程根目录
3. 工程属性->配置->常规->公共语言运行时支持->clr
工程属性->配置->c/c++常规->调试信息格式->zi
工程属性->配置->c/c++常规->公共语言运行时支持->clr
1
2
|
#using "CSharpDllProject.dll"
using
namespace
CSharpDllProject;
|
三、 c#调用c++类步骤(c++/cli,可直接使用C++类)
c++/cli简介:C++/CLI标准是基于Microsoft提交的标准C++与通用语言基础结构(Common Language Infrastructure)结合的技术
1.使用c++/cli语法对标准c++类进行包装(可采用聚合模式,引用标准c++类,实现所有标准c++的方法)
2.c#引用c++ dll后,可直接new出一个 c++/cli创建的托管类对象
下面就用一个完整的实例来详细说明怎样用托管C++封装一个C++类以提供给C#使用。
- //
NativeCppDll.h
- #pragma
once
- #ifndef
LX_DLL_CLASS_EXPORTS -
#define LX_DLL_CLASS __declspec(dllexport) - #else
-
#define LX_DLL_CLASS __declspec(dllimport) - #endif
- class
LX_DLL_CLASS CPerson - {
- public:
-
CPerson(); -
CPerson(const wchar_t *pName, const wchar_t cSex, int iAge);
-
void SetName(const wchar_t *pName); -
wchar_t * GetName();
-
void SetSex(const wchar_t cSex); -
wchar_t GetSex();
-
void SetAge(int iAge); -
int GetAge();
-
wchar_t * GetLastError();
- private:
-
wchar_t m_szName[128]; -
wchar_t m_cSex; -
int m_iAge; -
wchar_t m_szLastError[128];
-
void ShowError(); - };
- //
NativeCppDll.cpp
- #include
"stdafx.h"
- #include
"NativeCppDll.h" - #include
<iostream> - #include
<tchar.h>
- using
namespace std;
- CPerson::CPerson()
- {
-
wcscpy_s(m_szName, _T("No Name")); -
m_cSex = 'N'; -
m_iAge = 0;
-
wcscpy_s(m_szLastError, _T("No Error")); - }
- CPerson::CPerson(const
wchar_t *pName, const wchar_t cSex, int iAge) - {
-
wcscpy_s(m_szLastError, _T("No Error"));
-
SetName(pName); -
SetSex(cSex); -
SetAge(iAge); - }
- void
CPerson::SetName(const wchar_t *pName) - {
-
if ((pName == NULL) || (wcslen(pName) == 0) || (wcslen(pName) > 127)) -
{ -
wcscpy_s(m_szName, _T("No Name"));
-
wcscpy_s(m_szLastError, _T("The length of the input name is out of range."));
-
ShowError();
-
return; -
}
-
wcscpy_s(m_szName, pName); - }
- wchar_t
* CPerson::GetName() - {
-
return m_szName; - }
- void
CPerson::SetSex(const wchar_t cSex) - {
-
if ((cSex != 'F') && (cSex != 'M') && (cSex != 'm') && (cSex != 'f')) -
{ -
m_cSex = 'N';
-
wcscpy_s(m_szLastError, _T("The input sex is out of [F/M]."));
-
ShowError(); -
-
return; -
}
-
m_cSex = cSex; - }
- wchar_t
CPerson::GetSex() - {
-
return m_cSex; - }
- void
CPerson::SetAge(int iAge) - {
-
if ((iAge < 0) || (iAge > 150)) -
{ -
m_iAge = 0;
-
wcscpy_s(m_szLastError, _T("The input age is out of range."));
-
ShowError();
-
return; -
}
-
m_iAge = iAge; - }
- int
CPerson::GetAge() - {
-
return m_iAge; - }
- wchar_t
* CPerson::GetLastError() - {
-
return m_szLastError; - }
- void
CPerson::ShowError() - {
-
cerr << m_szLastError << endl; - }
- //
ManageCppDll.h
- #pragma
once - #define
LX_DLL_CLASS_EXPORTS
- #include
"..\NativeCppDll\NativeCppDll.h"
- using
namespace System;
- namespace
ManageCppDll - {
-
public ref class Person -
{ -
// 包装所有类CPerson的公有成员函数 -
public: -
Person(); -
Person(String ^ strName, Char cSex, int iAge);
-
~Person();
-
property String ^ Name -
{ -
void set(String ^ strName); -
String ^ get(); -
}
-
property Char Sex -
{ -
void set(Char cSex); -
Char get(); -
}
-
property int Age -
{ -
void set(int iAge); -
int get(); -
}
-
String ^ GetLastError();
-
private: -
// 类CPerson的指针,用来调用类CPerson的成员函数 -
CPerson *m_pImp; -
}; - };
- //
ManageCppDll.cpp
- #include
"stdafx.h"
- #include
"ManageCppDll.h" - #include
<vcclr.h>
- namespace
ManageCppDll - {
-
// 在构造函数中创建类CPerson的对象并在析构函数中将该对象销毁 -
// 所有的成员函数实现都是通过指针m_pImp调用类CPerson的相应成员函数实现
-
Person::Person() -
{ -
m_pImp = new CPerson(); -
}
-
Person::Person(String ^ strName, Char cSex, int iAge) -
{ -
// 将string转换成C++能识别的指针 -
pin_ptr<const wchar_t> wcName = PtrToStringChars(strName);
-
m_pImp = new CPerson(wcName, cSex, iAge); -
}
-
Person::~Person() -
{ -
// 在析构函数中删除CPerson对象 -
delete m_pImp; -
}
-
void Person::Name::set(String ^ strName) -
{ -
pin_ptr<const wchar_t> wcName = PtrToStringChars(strName);
-
m_pImp->SetName(wcName); -
}
-
String ^ Person::Name::get() -
{ -
return gcnew String(m_pImp->GetName()); -
}
-
void Person::Sex::set(Char cSex) -
{ -
m_pImp->SetSex(cSex); -
}
-
Char Person::Sex::get() -
{ -
return m_pImp->GetSex(); -
}
-
void Person::Age::set(int iAge) -
{ -
m_pImp->SetAge(iAge); -
}
-
int Person::Age::get() -
{ -
return m_pImp->GetAge(); -
}
-
String ^ Person::GetLastError() -
{ -
return gcnew String(m_pImp->GetLastError()); -
} - };
- using
ManageCppDll;
- Person
person = new Person();
- person.Name
= "StarLee"; - person.Sex
= 'M'; - person.Age
= 28;