非托管代码中调用托管代码

Posted 非法关键字

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非托管代码中调用托管代码相关的知识,希望对你有一定的参考价值。

托管类库(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 }

以上是关于非托管代码中调用托管代码的主要内容,如果未能解决你的问题,请参考以下文章

从 C# 线程调用非托管代码

让非托管 c++ 代码调用调用 c# 代码的托管 c++ 代码

托管 C# 代码未发生非托管调用

调试从非托管 C++ 调用的托管 .NET 代码

在托管代码和非托管代码之间传递非托管结构的安全数组

.Net调用非托管代码(P/Invoke与C++InterOP)