介绍 这篇文章展示了一种结合ACE和ATL的方法。它不打算作为功能演示,而是作为一个小型的“入门”解决方案,展示实现此目标的可行方法。 我假设熟悉ACE的开发人员会对本文感兴趣,因此本文对如何设置项目的ATL部分进行了冗长的描述。 ACE在多线程和同步方面提供了丰富的功能。它拥有功能最完整的api之一,可以用c++开发快速可靠的网络解决方案。该框架为编写实时软件解决方案提供了最先进的功能。 在本文中,我们将构建一个简单的COM服务应用程序,演示一种集成ACE和ATL的可能方法。ACE将用于实现从服务到COM客户端的异步回调。 ACE是一个c++库,在开发可靠的解决方案方面有着良好的记录。有关使用ACE的公司和项目列表,请查看谁在使用ACE。 虽然ACE主要用于开发可移植的、高效的网络解决方案,但将它与ATL集成是一个有趣的概念。同样的方法也可以用于实现与TAO的集成,使我们能够轻松地开发Corba和COM服务的组合。 按照ACE的发明者Douglas C. Schmidt的说法,ACE就是为了便于携带、灵活、可扩展、可预测、可靠和负担得起而编写的。 因为它是一个开源项目,所以它当然是负担得起的,而且它有一个活跃的、响应迅速的开发人员社区。 作为一名开发人员,我也欣赏“灵活、可扩展、可预测、可靠”的部分。 如果你对ACE一无所知,不妨看看这个教程。 先决条件 从http://download.dre.vanderbilt.edu下载ACE,并根据包含的说明构建项目——或者查看http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ACE-INSTALL.html获得详细说明。 本文假设“config”。“h”的ACE图书馆包括: 隐藏,复制Code

#define ACE_NTRACE 0

之前: 隐藏,复制Code

#include <spanclass="code-string">"ace/config-win32.h"</span>

将“ACE_NTRACE”定义为0可以在执行期间通过打开“ACE_TRACE”宏输出大量的跟踪信息。 请记住设置“ACE_ROOT”环境变量并将“%ACE_ROOT%\lib”添加到系统路径。 在Windows 7下,以管理员身份运行Visual Studio,以便在构建期间自动注册COM应用程序。 创建项目 我们将从创建一个标准的ATL服务应用程序开始。 记得在ATL项目向导的“应用程序设置”页面选择“服务(EXE)”单选按钮。 单击finish, Visual Studio将创建一个标准的ATL服务应用程序。 现在我们需要告诉Visual Studio在哪里可以找到ACE库。 将"$(ACE_ROOT)\lib"添加到"库目录" 现在,我们已经准备好添加ATL COM对象实现了,所以切换到“类视图”并从项目弹出菜单中选择add ->Class。 这将打开“添加类”对话框,我们将在其中选择“ATL简单对象”。 点击“添加”弹出ATL简单对象向导: 在“短名称”中输入“Demo”,进入“选项”页面: 通过选择“Free”线程模型,我们告诉COM我们将能够自己处理同步问题。在本例中,我们不希望支持聚合,但我们确实希望使用“ISupportErrorInfo”和“连接点”提供错误处理支持,以使用COM事件提供通知。 现在,我们有了一个基本的“不做任何事”的COM服务,是时候开始添加基于ACE的功能了,但首先我们需要告诉Visual Studio在哪里可以找到允许我们使用ACE的包含文件。打开项目的属性对话框,将$(ACE_ROOT)添加到“Include目录”中。 到链接器->System页面,将“子系统”设置为“控制台(/子系统:控制台)”。这在调试期间通常很有用,在生产场景中无害,因为服务无论如何都是不可见的。 这一步还允许我们使用ACE_TMAIN(int argc, ACE_TCHAR* argv[])作为入口点。 “stdafx开放。h”,并在文件末尾添加以下内容: 隐藏,复制Code

#include <spanclass="code-string">"ace/Log_Msg.h"
</span>#include <spanclass="code-string">"ace/Svc_Handler.h"
</span>#include <spanclass="code-string">"ace/Method_Request.h"
</span>#include <spanclass="code-string">"ace/Activation_Queue.h"
</span>#include <spanclass="code-string">"ace/Future.h"
</span>#include <spanclass="code-keyword"><vector></span>

打开ACEATLDemo.cpp并在include部分之后添加以下内容,以告诉链接器关于ACE库的信息: 隐藏,复制Code

#ifndef _DEBUG
#pragma comment(lib,"ace")
#else
#pragma comment(lib,"aced")
#endif

现在,我们的项目看起来是这样的: 重新构建项目,我们就可以开始基于ACE的功能实现COM服务了。 为了让事情变得有趣,我们将把服务的核心实现为活动对象,其中功能在单独的线程上异步执行。班级是这样的: 隐藏,复制Code

class CDemo;
class CDemoImpl : public ACE_Task_Base
{
ACE_Activation_Queue activation_queue_;
std::vector<CDemo*> clients_;
public:
CDemoImpl(void);
~CDemoImpl(void); virtual int svc (void);
int enqueue (ACE_Method_Request *request); int exitImpl();
int postMessageImpl(CComBSTR text);
int registerImpl(CDemo *pDemo);
int unregisterImpl(CDemo *pDemo); IntFuture callExit();
void callPostMessage(BSTR bstr);
IntFuture callRegister(CDemo *pDemo);
IntFuture callUnregister(CDemo *pDemo);
};

IntFuture是一个简单的定义类型: 隐藏,复制Code

typedef ACE_Future<int> IntFuture; 

未来是一种允许我们等待未来可能值的构造。 ACE允许我们使用下面的声明来实现一个单例,它是一个保证通过“DemoImpl”只能访问一个“CDemoImpl”实例的构造。 隐藏,复制Code

typedef ACE_Singleton<CDemoImpl, ACE_Null_Mutex> DemoImpl; 

“CDemoImpl”类的核心是“svc”函数: 隐藏,复制Code

int CDemoImpl::svc (void)
{
ACE_TRACE ("CDemoImpl::svc");
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("CoInitializeEx failed - returned:%d\n"),hr));
return -1;
} while (1)
{
auto_ptr<ace_method_request />
request (this->activation_queue_.dequeue ()); if (request->call () == -1)
{
break;
}
}
return 0;
}

请求从激活队列中脱离,并使用它们的“call”函数执行。 一个“ACE_Method_Request”通常是这样的: 隐藏,复制Code

class CExitMethodRequest : public ACE_Method_Request
{
IntFuture result_;
public:
CExitMethodRequest(IntFuture& result)
: result_(result)
{
ACE_TRACE ("CExitMethodRequest::CExitMethodRequest");
} ~CExitMethodRequest( )
{
ACE_TRACE ("CExitMethodRequest::~CExitMethodRequest");
} virtual int call (void)
{
ACE_TRACE ("CExitMethodRequest::call");
int result = DemoImpl::instance()->exitImpl();
result_.set(result);
return result;
}
};

“call”函数使用了我们的“DemoImpl”单例定义,并设置了“IntFuture”“result_”的值,使得通过“IntFuture”调用线程可以使用结果。 与“svc”函数对应的是“enqueue”函数: 隐藏,复制Code

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

“enqueue”函数是这样使用的: 隐藏,复制Code

IntFuture CDemoImpl::callExit()
{
ACE_TRACE ("CDemoImpl::callExit");
IntFuture result; CExitMethodRequest *request = new CExitMethodRequest(result);
enqueue (request); return result;
}

打开ACEATLDemo.cpp,进入… 隐藏,复制Code

typedef ATL::CAtlServiceModuleT< CACEATLDemoModule, IDS_SERVICENAME > Inherited;

…在“CACEATLDemoModule”类定义的顶部。然后在类中添加以下声明: 隐藏,复制Code

void RunMessageLoop() throw();

void OnStop() throw();

bool ParseCommandLine(LPCTSTR lpCmdLine,HRESULT* pnRetCode) throw();

然后像这样实现它们: 隐藏,收缩,复制Code

void CACEATLDemoModule::RunMessageLoop() throw()
{
ACE_TRACE( "RunMessageLoop" ); ACE_Reactor::instance()->run_reactor_event_loop();
} void CACEATLDemoModule::OnStop() throw()
{
ACE_TRACE( "OnStop" );
ACE_Reactor::instance()->end_reactor_event_loop(); IntFuture futureResult = DemoImpl::instance()->callExit();
int result = 0;
futureResult.get(result); if(result != -1)
{
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("callExit failed - returned:%d\n"),result));
}
DemoImpl::instance()->wait();
} bool CACEATLDemoModule::ParseCommandLine(LPCTSTR lpCmdLine,
HRESULT* pnRetCode) throw()
{
ACE_TRACE( "ParseCommandLine" );
bool result = Inherited::ParseCommandLine(lpCmdLine,pnRetCode);
return result;
}

通过实现RunMessageLoop,我们有效地替换了ATL的默认实现,并使用ACE反应器作为标准消息循环的替代品。为了提供对服务控制管理器停止事件的正确处理,我们还需要实现OnStop方法。由于“DemoImpl”在一个单独的线程上运行“svc”函数,所以我们使用“callExit”告诉“svc”该退出请求处理循环了,并调用wait来确保线程已经完成了它的执行。ParseCommandLine使用我们添加到“CACEATLDemoModule”类定义顶部的“Inherited”调用默认实现。这里展示了如何“挂钩”到命令行的ATLs处理。为了支持服务控制管理器停止事件时的模拟,我们为控制台控制事件(如Ctrl+C和Ctrl+Break)实现了一个应用处理程序例程。 隐藏,复制Code

BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
{
ACE_TRACE( "ConsoleCtrlHandler" );
_AtlModule.OnStop();
return TRUE;
}

现在我们将“_tWinMain”函数更改为: 隐藏,收缩,复制Code

int ACE_TMAIN (int argc, ACE_TCHAR * argv[] )
{
ACE_TRACE("main");
int result = 0;
try
{
STARTUPINFO startupInfo = {sizeof(STARTUPINFO),0,};
GetStartupInfo(&startupInfo);
if(IsDebuggerPresent())
{
SetConsoleCtrlHandler(ConsoleCtrlHandler,TRUE);
HRESULT hr = _AtlModule.InitializeCom(); result = _AtlModule.Run(startupInfo.wShowWindow); _AtlModule.UninitializeCom();
_AtlModule.Term();
SetConsoleCtrlHandler(ConsoleCtrlHandler,FALSE);
}
else
{
result = _AtlModule.WinMain(startupInfo.wShowWindow);
}
}
catch(...)
{
ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
ACE_TEXT ("Unknown exception in main")));
} return result;
}

至此,我们已经创建了一个工作应用程序,它在执行期间为我们提供了一些有用的信息。当应用程序在调试器下执行时,它将始终作为控制台应用程序运行,而不考虑注册表中的“LocalService”设置。ACEATLDemo开放。idl,并添加: 隐藏,复制Code

[id(1)] HRESULT PostMessage(BSTR messageText);

到“IDemo”接口的定义,然后打开Demo.h,添加: 隐藏,复制Code

STDMETHOD(PostMessage)(BSTR messageText);

作为一个公共方法。打开Demo.cpp,实现方法: 隐藏,复制Code

STDMETHODIMP CDemo::PostMessage(BSTR messageText)
{
ACE_TRACE("CDemo::PostMessage"); DemoImpl::instance()->callPostMessage(messageText); return S_OK;
}

callPostMessage函数将CPostMessageMethodRequest请求放入激活队列中。 隐藏,复制Code

void CDemoImpl::callPostMessage(BSTR bstr)
{
ACE_TRACE ("CDemoImpl::callPostMessage");
CPostMessageMethodRequest *request = new CPostMessageMethodRequest(bstr);
enqueue (request);
}

当请求脱离队列时,它的call()函数将调用: 隐藏,复制Code

int CDemoImpl::postMessageImpl(CComBSTR text)
{
ACE_TRACE ("CDemoImpl::postMessageImpl"); for(vector<cdemo* />::iterator it = clients_.begin();
it < clients_.end();
it++)
{
CDemo *pDemo = (*it);
pDemo->Fire_OnPostMessage(text.m_str);
}
return 0;
}

实现测试客户端 要测试我们的服务器,我们需要开发一个小型测试应用程序。使用。net和c#很容易做到这一点。我们这样实现客户端: 隐藏,收缩,复制Code

public partial class MainForm : Form
{
ACEATLDemoLib.Demo demo; public MainForm()
{
InitializeComponent();
} protected override void OnShown(EventArgs e)
{
base.OnShown(e); demo = new ACEATLDemoLib.Demo(); demo.OnPostMessage += new ACEATLDemoLib._IDemoEvents_OnPostMessageEventHandler
(demo_OnPostMessage);
} delegate void demo_OnPostMessageDelegate(string messageText);
void demo_OnPostMessage(string messageText)
{
if (InvokeRequired)
{
BeginInvoke(new demo_OnPostMessageDelegate(demo_OnPostMessage), messageText);
}
else
{
messagesTextBox.AppendText(messageText + Environment.NewLine);
}
} private void sendMessageButtonButton_Click(object sender, EventArgs e)
{
demo.PostMessage(messageTextBox.Text);
}
}

在Visual Studio 2010中,表单是这样的: 现在我们可以启动服务器和客户端应用程序的几个实例。因为我们已经启用了ACE_TRACE宏,所以服务器将提供一个有趣的视图来了解它的行为。把这个项目看作一个起点,将ACE或TAO与ATL结合,可以让我们基于所提供的功能创建软件。浏览文档,您会发现实时软件开发中一些极具挑战性的方面的高质量实现。 进一步的阅读 由Stephen D. Huston、James CE Johnson和Umar Syyid合著的《ACE程序员指南:网络和系统编程的实用设计模式》一书介绍了ACE开发。 历史 2011年1月2日-初始版本 本文转载于:http://www.diyabc.com/frontweb/news30038.html

对ACE和ATL积分的更多相关文章

  1. 【需求设计1】VIP积分系统无聊YY

    RT,想到什么就写什么呗,这是最简单的方式,顺便给自己做一个记录,反正自己记忆力也不太好.本文是仿陆金所的积分系统,自己YY的一套东西. 首先我想做一个VIP兑换投资卷的功能: 我们先来确定一些我知道 ...

  2. 搭建属于自己的VIP积分系统(1)

    很久没写博客了,如果有写得不好的地方,还请多多见谅. 架构设计 需求分析 这篇文章主要是介绍此VIP系统的基础架构.说实在的,我其实对 架构方面也不是很懂,我这套框架 还是拿别人的东西改过来的,并不是 ...

  3. Microsoft ACE OLEDB 12.0 数据库连接字符串

    Excel 97-2003 Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\myFolder\myOldExcelFile.xls;Extended ...

  4. 基于ACE的c++线程封装

    1. 基本需求 1) 一个基类,其某个方法代表一个线程的生命运行周期.之后通过继承自这个基类来实现个性化线程类: 2) 具备类似QObject的定时器设置功能: 3) 提供在线程对象中同步和异步执行方 ...

  5. ATL封装IE内核启示:使用Win32/ATL建立窗口

    开发大型GUI界面程序MFC当仁不让,但如果是开发图形应用程序,并不需要大规模界面控件,没有必要链接庞大的MFC库,直接使用platform sdk会很麻烦,这时ATL中的关于Windows的封装就是 ...

  6. JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)

    前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...

  7. 第3月第11天 vs2005调试 ace编译

    1.vs2005调试 http://blog.csdn.net/u010797208/article/details/40452797 2.macbook ace编译 小坑: 源代码clockid_t ...

  8. .NET读取Excel数据,提示错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序

    解决.NET读取Excel数据时,提示错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序的操作: 1. 检查本机是否安装Office Access,如果未安装去去h ...

  9. ACE bus

    ACE bus增加的内容: 1):5状态的cache model 2):关于coherency的additional signal 3):两个cache master访问shared cache的ad ...

随机推荐

  1. 公共项目开发:我为什么用 JSDoc,而不用 ts

    公共模块,通常会被多个项目.不同的开发人员使用,所以开发公共模块时,你自己会用还不够,要让所有人都能很快的知道怎么去使用,这一点很关键.通常会从3个方面做到这点: 精心分割代码逻辑,遵循开闭原则: 变 ...

  2. 面试【JAVA基础】锁

    1.锁状态 锁的状态只能升级不能降级. 无锁 没有锁对资源进行锁定,所有线程都能访问并修改同一个资源,但同时只有一个线程能修改成功.其他修改失败的线程会不断重试,直到修改成功,如CAS原理和应用是无锁 ...

  3. XmlAnalyzer1.00 源码

    此工程用途:将xml同级属性/子节点按字母序排列重新输出. 源码下载: https://files.cnblogs.com/files/heyang78/XmlAnalyzer-20200526-1. ...

  4. linux vi编辑

    编辑模式 使用vi进入文本后,按i开始编辑文本 退出编辑模式 按ESC键,然后: 退出vi :q! 不保存文件,强制退出vi命令 :w 保存文件,不退出vi命令 :wq 保存文件,退出vi命令 中断v ...

  5. 教会舍友玩 Git (再也不用担心他的学习)

    舍友长大想当程序员,我和他爷爷奶奶都可高兴了,写他最喜欢的喜之郎牌Git文章,学完以后,再也不用担心舍友的学习了(狗头)哪里不会写哪里 ~~~ 一 先来聊一聊 太多东西属于,总在用,但是一直都没整理的 ...

  6. java中整型、浮点型、char型扩展

    怎么区分是什么进制? 二进制:0b开头,eg: int i = 0b10; 八进制:0开头,eg: int k = 010; 十进制: 十六进制:0x开头,eg: int j = 0x10; 浮点数类 ...

  7. Python测试框架pytest命令行参数用法

    在Shell执行pytest -h可以看到pytest的命令行参数有这10大类,共132个 序号 类别 中文名 包含命令行参数数量 1 positional arguments 形参 1 2 gene ...

  8. HTML-CSS-JS Prettify 代码格式化插件

    前提:已经安装 node.js.安装插件 HTML-CSS-JS Prettify,修改node路径,即可通过单击右键 HTML-CSS-JS Prettify 中的 Prettify Code 使用 ...

  9. Java中AQS基本实现原理

    一.AQS概述 AQS全名AbstractQueuedSynchronizer,意为抽象队列同步器,JUC(java.util.concurrent包)下面的Lock和其他一些并发工具类都是基于它来实 ...

  10. 【Flutter 实战】菜单(Menu)功能

    老孟导读:今天介绍下Flutter中的菜单功能. PopupMenuButton 使用PopupMenuButton,点击时弹出菜单,用法如下: PopupMenuButton<String&g ...