拙网论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 215|回复: 0

C++封装C#中的事件

[复制链接]

949

主题

1001

帖子

3736

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3736
发表于 2018-8-21 15:03:23 | 显示全部楼层 |阅读模式

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控制台测试程序,将会看到:



说明已经封装成功了。


需要源码的同学可以点击这里下载


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|抱朴守拙BBS

GMT+8, 2025-5-26 07:36 , Processed in 0.208279 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表