.NET C++/CLI与ACE框架的混合编程实践

.NET开发中,经常面临选择使用C#还是C++的问题。C#以其简洁易用而广受欢迎,但C++在性能和底层控制方面具有优势。本文将探讨如何将C++的强大框架ACE与.NET C++/CLI结合,实现混合模式编程。

预备知识

在开始之前,需要确保已经按照ACE的文档编译了ACE框架,并了解如何设置项目的包含路径和库路径,以及如何设置混合模式C++/CLI项目。

首先,需要下载ACE框架。可以通过以下链接下载:

编码实践

接下来,将创建一个Visual C++ Windows Forms应用程序。为了使用ACE框架,需要在stdafx.h中添加一些头文件。

#ifndef STRICT #define STRICT #endif #pragma managed(push,off) #include <sdkddkver.h> #include "ace/Log_Msg.h" #include "ace/Svc_Handler.h" #include "ace/Method_Request.h" #include "ace/Activation_Queue.h" #include "ace/Future.h" #include <vector> #include <string> #pragma managed(pop)

在ACEDotNetDemo.cpp文件中,需要在main方法之前添加一些代码,以告知链接器需要链接到ace.lib或aced.lib。

#pragma managed(push,off) #ifndef _DEBUG #pragma comment(lib,"ace") #else #pragma comment(lib,"aced") #endif #pragma managed(pop)

main方法相对标准,只需要调用ACE::init()和ACE::fini()来初始化和结束框架。

[STAThreadAttribute] int main(array<System::String^>^ args) { int result = ACE::init(); if (result >= 0) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Application::Run(gcnew MainForm()); ACE::fini(); } return result; }

在ACEDotNetDemoTask.hpp中,声明了一个非常简单的类ACEDotNetDemoTask,它继承自ACE_Task_Base。这是线程实现,svc方法将在另一个线程中执行。

#pragma once #pragma managed(push,off) typedef ACE_Future<int> IntFuture; class ACEDotNetDemoTask : public ACE_Task_Base { ACE_Activation_Queue activation_queue_; public: ACEDotNetDemoTask(void); ~ACEDotNetDemoTask(void); virtual int svc(void); int enqueue(ACE_Method_Request *request); IntFuture call_exit(); }; typedef ACE_Singleton<ACEDotNetDemoTask, ACE_Null_Mutex> ACEDOTNETDEMOTASK; class ExitMethodRequest : public ACE_Method_Request { IntFuture result_; public: ExitMethodRequest(IntFuture& result) : result_(result) { ACE_TRACE("ExitMethodRequest::ExitMethodRequest"); } virtual ~ExitMethodRequest() { ACE_TRACE("ExitMethodRequest::~ExitMethodRequest"); } virtual int call(void) { ACE_TRACE("ExitMethodRequest::call"); int result = -1; result_.set(result); return result; } }; #pragma managed(pop)

使用ACE_Singleton声明了一个单例ACEDOTNETDEMOTASK,用于ACEDotNetDemoTask。ACEDotNetDemoTask.cpp包含ACEDotNetDemoTask的实现。

svc方法从激活队列中出列方法请求,并调用出列请求的call方法,直到call方法返回-1,这与标准Windows消息循环非常相似。

int ACEDotNetDemoTask::svc(void) { ACE_TRACE("ACEDotNetDemoTask::svc"); while (1) { auto_ptr<ACE_Method_Request> request(this->activation_queue_.dequeue()); if (request->call() == -1) { break; } } return 0; }

enqueue方法将请求入列到激活队列中,由svc方法进行处理:

int ACEDotNetDemoTask::enqueue(ACE_Method_Request *request) { ACE_TRACE("ACEDotNetDemoTask::enqueue"); return this->activation_queue_.enqueue(request); }

call_exit方法将ExitMethodRequest入列到激活队列中,并返回一个IntFuture,允许调用者从非托管线程中获取结果。

IntFuture ACEDotNetDemoTask::call_exit() { ACE_TRACE("ACEDotNetDemoTask::call_exit"); IntFuture result; ExitMethodRequest *request = new ExitMethodRequest(result); enqueue(request); return result; }

这将处理基于ACE_Task_Base的非托管线程实现。

从托管C++/CLI代码与非托管线程进行交互非常简单。

protected: virtual void OnShown(EventArgs^ e) override { System::Windows::Forms::Form::OnShown(e); // 启动非托管线程 ACEDOTNETDEMOTASK::instance()->activate(); } virtual void OnFormClosing(FormClosingEventArgs^ e) override { // 调用非托管线程,并告诉它退出 IntFuture futureResult = ACEDOTNETDEMOTASK::instance()->call_exit(); // 并获取结果 int result = 0; futureResult.get(result); // 等待非托管线程退出 ACEDOTNETDEMOTASK::instance()->wait(); System::Windows::Forms::MessageBox::Show( String::Format(L"Exit Result:{0}", result), L"Call Exit" ); System::Windows::Forms::Form::OnFormClosing(e); }

毫无疑问,许多人已经知道使用混合模式C++/CLI集成托管和非托管代码的效果非常好。但想有很多人像一样,认为这是一个诱人的想法,甚至可能,但从未真正去验证它。

实现的是一个简单的非托管代码中的活动对象;并成功地从托管代码中与之交互。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485