https://blog.csdn.net/sudazf/article/details/52160514 背景: 用户要求我们提供给他们API,如果这些API都是用C#写的DLL,而用户要求API为C++的 DLL,这种情况下如果不重写API,就需要将C# DLL里面的内容封装成C++ DLL,再将C++DLL提供给他们。
这里针对c#中的事件,记录一下如何使用C++来封装c#的事件:
1.创建一个简单的C# DLL实例: a.新建一个c# DLL项目,取名:TestDotNetDLL,添加一个类:Customer,这个类里面有两个属性、一个自定义委托和三个事件(将要对这三种事件进行封装):
public class Customer
{
private string _surname = "Default";
private int _age = 20;
public string Surname
{
get
{
return _surname;
}
set
{
_surname = value;
}
}
public int Age
{
get { return _age; }
set { _age = value; }
}
public delegate void MyEventHandler(object sender, MyEventArgs e); //自定义委托
//三个事件
public event EventHandler OnMyTestEvent; //默认委托型事件
public event MyEventHandler OnMyTestEvent1; //自定义委托事件
public event EventHandler<MyEventArgs> OnMyTestEvent2; //泛型委托事件
}
b.在添加一个类型:MyEventArgs,继承自:EventArgs,包含两个额外属性:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestDotNetDLL
{
public class MyEventArgs : EventArgs
{
#region Properties
private string _surname="XiaoHong";
private int _age=17;
public string Surname
{
get
{
return _surname;
}
set
{
_surname = value;
}
}
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
#endregion
}
}
2.新建一个C++DLL空项目,取名:CplusplusDLLUsingDotNetDLL,用来封装刚刚新建的C# DLL a.在项目属性中设置一下:Common Language Runtime Support (/clr)

b.在common properties中添加引用C# DLL: 
c.添加两个头文件:CustomerWin32Cls.h,CustomerMiddle.h CustomerWin32Cls.h:
#pragma once
#include <string>
using namespace std;
typedef unsigned int uint;
#ifdef CPLUSPLUSDLLUSINGDOTNETDLL_EXPORTS
#include "CustomerMiddle.h"
using namespace System;
#define DLLSPEC __declspec( dllexport)
#else
class CustomerMiddle;
#define DLLSPEC
#endif
namespace CustomerWrapper {
class DLLSPEC CustomerWin32
{
private:
CustomerMiddle* m_pCustomer;
public:
CustomerWin32();
~CustomerWin32();
//event
__event void OnMyTestEvent(const char* obj, unsigned int e);
void HandleOnMyTestEvent(const char* obj, unsigned int e);
__event void OnMyTestEvent1(const char* obj, unsigned int e);
void HandleOnMyTestEvent1(const char* obj, unsigned int e);
__event void OnMyTestEvent2(const char* obj, unsigned int e);
void HandleOnMyTestEvent2(const char* obj, unsigned int e);
};
}
CustomerMiddle.h:
#pragma once
#include <vcclr.h>
#include <msclr\marshal.h>
#include <msclr\auto_gcroot.h>
typedef unsigned int uint;
using namespace System;
namespace CustomerWrapper {
public class CustomerMiddle
{
private:
public:
msclr::auto_gcroot<TestDotNetDLL::Customer^> obj;
CustomerMiddle();
~CustomerMiddle();
};
class CustomerWin32; // forward declaration
ref class EventHelper
{
private:
CustomerWin32* m_pCustomerWin32;
public:
EventHelper(CustomerWin32* pCustomerWin32);
EventHelper();
~EventHelper();
void OnMyTestEvent(Object^ obj, System::EventArgs^ e);
void OnMyTestEvent1(Object^ obj, TestDotNetDLL::MyEventArgs^ e);
void OnMyTestEvent2(Object^ obj, TestDotNetDLL::MyEventArgs^ e);
};
}
d.添加对应的cpp源文件: CustomerWin32Cls.cpp:
#include "CustomerWin32Cls.h"
#include <string>
#include <stdlib.h>
#include <msclr\marshal.h>
using namespace std;
using namespace msclr::interop;
using namespace System;
using namespace CustomerWrapper;
using namespace TestDotNetDLL;
#define CLRSTRING(stdString) (gcnew String(stdString)) // stdString is a std string variable
#define CUSTOMEROBJ m_pCustomer->obj
CustomerWin32:: CustomerWin32()
{
m_pCustomer=new CustomerMiddle();
CUSTOMEROBJ= gcnew TestDotNetDLL::Customer();
EventHelper^ eventHelper = gcnew EventHelper( this);
CUSTOMEROBJ->OnMyTestEvent+=gcnew System::EventHandler(eventHelper,&EventHelper::OnMyTestEvent);
CUSTOMEROBJ->OnMyTestEvent1+=gcnew TestDotNetDLL::Customer::MyEventHandler(eventHelper,&EventHelper::OnMyTestEvent1);
CUSTOMEROBJ->OnMyTestEvent2+=gcnew System::EventHandler<TestDotNetDLL::MyEventArgs^>(eventHelper,&EventHelper::OnMyTestEvent2);
}
CustomerWin32:: ~CustomerWin32()
{
delete m_pCustomer;
}
void CustomerWin32:: HandleOnMyTestEvent(const char* obj, unsigned int e)
{
__raise OnMyTestEvent( obj, e);
}
void CustomerWin32:: HandleOnMyTestEvent1(const char* obj, unsigned int e)
{
__raise OnMyTestEvent1( obj, e);
}
void CustomerWin32:: HandleOnMyTestEvent2(const char* obj, unsigned int e)
{
__raise OnMyTestEvent2( obj, e);
}
CustomerMiddle.cpp:
#include "CustomerWin32Cls.h"
#include "CustomerMiddle.h"
using namespace System;
using namespace msclr::interop;
using namespace CustomerWrapper;
using namespace TestDotNetDLL;
EventHelper:: EventHelper( CustomerWin32* pCustomerWin32)
{
m_pCustomerWin32 = pCustomerWin32;
}
EventHelper::EventHelper()
{
}
EventHelper:: ~EventHelper()
{
}
void EventHelper:: OnMyTestEvent( Object^ sender, System::EventArgs^ e)
{
m_pCustomerWin32->HandleOnMyTestEvent(0, 1);
}
void EventHelper:: OnMyTestEvent1( Object^ sender, TestDotNetDLL::MyEventArgs^ e)
{
String^ name = e->Surname;
uint age = e->Age;
marshal_context^ context = gcnew marshal_context();
const char * customerName = context->marshal_as<const char*>(name);
m_pCustomerWin32->HandleOnMyTestEvent1( customerName, age);
}
void EventHelper:: OnMyTestEvent2( Object^ sender, TestDotNetDLL::MyEventArgs^ e)
{
String^ name = e->Surname;
uint age = e->Age;
marshal_context^ context = gcnew marshal_context();
const char * customerName = context->marshal_as<const char*>(name);
m_pCustomerWin32->HandleOnMyTestEvent2( customerName, age);
}
CustomerMiddle::CustomerMiddle()
{
}
CustomerMiddle::~CustomerMiddle()
{
}
3.新建c++ DLL测试项目:
a.新建一个C++ win32控制台项目(包含预编译头),取名:App_TestWin32DLL,同样在项目属性中设置一下支持:Common Language Runtime Support (/clr); b.在【C/C++】->【General】->【Additional Include Directories】添加CustomerWin32Cls.h所在的路径(如果没有C/C++选项,随便新建一个cpp文件编译一下就出现了); c.在【Linker】->【General】->【Additional Library Directories】添加CplusplusDLLUsingDotNetDLL.lib所在的路径; d.在【Linker】->【Input】->【Additional Dependencies】添加CplusplusDLLUsingDotNetDLL.lib(包含后缀名);
e.添加一个测试头文件:TestWrapper.h
#include "stdafx.h"
using namespace CustomerWrapper;
typedef unsigned int uint;
class TestWrapper{
private:
CustomerWin32* customer;
public :
TestWrapper();
~TestWrapper();
void OnMyTestEvent(const char* obj, uint e);
void OnMyTestEvent1(const char* obj, uint e);
void OnMyTestEvent2(const char* obj, uint e);
};
f.在头文件stdafx.h中添加需要的头文件引用:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <vcclr.h>
// TODO: reference additional headers your program requires here
#include "CustomerWin32Cls.h"
#include "TestWrapper.h"
#include <iostream>
g.添加头文件TestWrapper.h对应的源文件:
#include "stdafx.h"
TestWrapper::TestWrapper()
{
customer=new CustomerWin32();
__hook( &CustomerWrapper::CustomerWin32::OnMyTestEvent, customer, &TestWrapper::OnMyTestEvent);
__hook( &CustomerWrapper::CustomerWin32::OnMyTestEvent1, customer, &TestWrapper::OnMyTestEvent1);
__hook( &CustomerWrapper::CustomerWin32::OnMyTestEvent2, customer, &TestWrapper::OnMyTestEvent2);
}
void TestWrapper::OnMyTestEvent(const char* obj,uint e)
{
System::Console::WriteLine("OnMyTestEvent : Hello");
}
void TestWrapper::OnMyTestEvent1(const char* obj,uint e)
{
cout<<"OnMyTestEvent1 : name is: "<<obj<<" ,age is: "<<e<<endl;
}
void TestWrapper::OnMyTestEvent2(const char* obj,uint e)
{
cout<<"OnMyTestEvent2 : name is: "<<obj<<" ,age is: "<<e<<endl;
}
TestWrapper:: ~TestWrapper()
{
__unhook( &CustomerWrapper::CustomerWin32::OnMyTestEvent, customer, &TestWrapper::OnMyTestEvent);
__unhook( &CustomerWrapper::CustomerWin32::OnMyTestEvent1, customer, &TestWrapper::OnMyTestEvent1);
__unhook( &CustomerWrapper::CustomerWin32::OnMyTestEvent2, customer, &TestWrapper::OnMyTestEvent2);
delete customer;
}
h.最后在主函数中添加测试代码:
#pragma once
#include "stdafx.h"
using namespace CustomerWrapper;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
TestWrapper wrapper;
while (1)
{
int x;
cin >> x;
}
return 0;
}
注意,这样运行是没有任何结果的,因为事件并没有执行,需要在C# DLL中添加事件执行代码: 在Customer.cs文件中添加一个定时器,每隔1秒,执行一下事件:
public class Customer
{
private System.Timers.Timer Timer;
public Customer()
{
Timer = new System.Timers.Timer();
Timer.Interval = 1000;
Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
Timer.AutoReset = true;
Timer.Enabled = true;
Timer.Start();
}
void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (OnMyTestEvent != null)
{
OnMyTestEvent(sender,e);
}
if (OnMyTestEvent1 != null)
{
MyEventArgs me = new MyEventArgs();
OnMyTestEvent1(sender, me);
}
if (OnMyTestEvent2 != null)
{
MyEventArgs me = new MyEventArgs();
me.Surname = this.Surname;
me.Age = this.Age;
OnMyTestEvent2(sender, me);
}
}
}
最后重新编译一下C# DLL,运行App_TestWin32DLL控制台测试程序,将会看到: 
说明已经封装成功了。
需要源码的同学可以点击这里下载
|