非托管代码中调用托管代码
托管类库(CSharp):
1 using System; 2 3 namespace ManagedPerson 4 { 5 public class Person 6 { 7 private string _name; 8 private DateTime _birthday; 9 10 public Person(string name, DateTime birthday) 11 { 12 _name = name; 13 _birthday = birthday; 14 } 15 16 public uint Age 17 { 18 get 19 { 20 DateTime now = DateTime.Now; 21 int age = now.Year - _birthday.Year; 22 if (_birthday.Month > now.Month || 23 (_birthday.Month == now.Month && _birthday.Day > now.Day)) 24 { 25 --age; 26 } 27 28 return (uint) age; 29 } 30 } 31 32 public string Birthdaystr => _birthday.ToShortDateString(); 33 34 public DateTime Birthday => _birthday; 35 } 36 }
C++/CLI包装类库(Managed C++):
1 #pragma once 2 3 #ifdef CLIPERSON_EXPORTS 4 #define CLIPERSON_API __declspec(dllexport) 5 #else 6 #define CLIPERSON_API __declspec(dllimport) 7 #endif 8 9 #include <string> 10 #include <Windows.h> 11 12 using namespace std; 13 14 class CLIPERSON_API CPerson 15 { 16 public: 17 CPerson(string name, const SYSTEMTIME *birthday); 18 virtual ~CPerson(); 19 20 unsigned int getAge() const; 21 string getBirthdaystr() const; 22 SYSTEMTIME getBirthday() const; 23 24 private: 25 void *clrPerson; 26 };
1 // CLIPerson.cpp: 定义 DLL 应用程序的导出函数。 2 // 3 4 #include "stdafx.h" 5 #include "CLIPerson.h" 6 #include <vcclr.h> 7 8 using namespace System; 9 using namespace Runtime::InteropServices; 10 using namespace ManagedPerson; 11 12 CPerson::CPerson(string name, const SYSTEMTIME * birthday) 13 { 14 DateTime ^datetime = gcnew DateTime(birthday->wYear, birthday->wMonth, birthday->wDay); 15 16 //int nu = strlen(name.c_str()); 17 //int n = (size_t)MultiByteToWideChar(CP_ACP, 0, (const char *)name.c_str(), (int)nu, NULL, 0); 18 //wchar_t *pwstr = new wchar_t[n]; 19 //MultiByteToWideChar(CP_ACP, 0, (const char *)name.c_str(), (int)nu, pwstr, (int)n); 20 //String ^str = gcnew String(pwstr); 21 //delete []pwstr; 22 23 String ^str = gcnew String(name.c_str()); 24 25 Person ^person = gcnew Person(str, *datetime); 26 // managed type conversion into unmanaged pointer is not allowed. 27 // we can use gcroot<> wrapper. 28 gcroot<Person ^> *pp = new gcroot<Person ^>(person); 29 clrPerson = static_cast<void *>(pp); 30 } 31 32 CPerson::~CPerson() 33 { 34 if (clrPerson) 35 { 36 gcroot<Person ^> *pp = static_cast<gcroot<Person ^> *>(clrPerson); 37 delete pp; 38 39 clrPerson = 0; 40 } 41 } 42 43 unsigned int CPerson::getAge() const 44 { 45 if (clrPerson != 0) 46 { 47 gcroot<Person ^> *pp = static_cast<gcroot<Person ^> *>(clrPerson); 48 return ((Person ^)*pp)->Age; 49 } 50 51 return 0; 52 } 53 54 string CPerson::getBirthdaystr() const 55 { 56 string strage; 57 if (clrPerson != 0) 58 { 59 gcroot<Person ^> *pp = static_cast<gcroot<Person ^> *>(clrPerson); 60 strage = (const char *)Marshal::StringToHGlobalAnsi(((Person ^)*pp)->Birthdaystr).ToPointer(); 61 } 62 63 return strage; 64 } 65 66 SYSTEMTIME CPerson::getBirthday() const 67 { 68 SYSTEMTIME st; 69 if (clrPerson != 0) 70 { 71 gcroot<Person ^> *pp = static_cast<gcroot<Person ^> *>(clrPerson); 72 DateTime dt = ((Person ^)*pp)->Birthday; 73 st.wYear = dt.Year; 74 st.wMonth = dt.Month; 75 st.wDay = dt.Day; 76 } 77 78 return st; 79 }
此处需要特别注意的地方是Dll入口点不可以编译为MSIL,详细信息:https://msdn.microsoft.com/zh-cn/library/ccthbfk8(v=vs.100).aspx
1 // dllmain.cpp : 定义 DLL 应用程序的入口点。 2 #include "stdafx.h" 3 4 #pragma unmanaged 5 BOOL APIENTRY DllMain( HMODULE hModule, 6 DWORD ul_reason_for_call, 7 LPVOID lpReserved 8 ) 9 { 10 switch (ul_reason_for_call) 11 { 12 case DLL_PROCESS_ATTACH: 13 case DLL_THREAD_ATTACH: 14 case DLL_THREAD_DETACH: 15 case DLL_PROCESS_DETACH: 16 break; 17 } 18 return TRUE; 19 }
传统C++引入Library并测试:
1 // main.cpp: 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "CLIPerson.h" 6 #include <iostream> 7 8 using namespace std; 9 10 int main() 11 { 12 SYSTEMTIME st = { 0 }; 13 const char *name = "native call managed code"; 14 15 st.wYear = 1975; 16 st.wMonth = 8; 17 st.wDay = 15; 18 19 CPerson person(name, &st); 20 21 cout << name << ":" << endl; 22 cout << "age:" << person.getAge() << endl; 23 cout << "birthday:" << person.getBirthdaystr().c_str() << endl; 24 25 system("pause"); 26 27 return 0; 28 }