http://blog.csdn.net/FlowShell/archive/2010/11/14/6008279.aspx我们知道,Windows以事件驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供的内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环。基本消息循环如下:
view plaincopy to clipboardprint?
while(GetMessage(&msg,0,0,0))
{
//转换消息参数
时过境迁之后,还有多少人会在原地等你?!时过境迁之后,你还会在原地等谁?!
http://www.vckbase.com/document/viewdoc/?id=1447原文出处:Creating a Simple Win32 Service in C++ 下载 NTService 例子源代码下载 NTServCpl 例子源代码下载 NTServCtrl 例子源代码摘要 本文描述如何用 Visual C++ 创建 Windows NT 服务程序。创建该服务仅用到一个 C++ 类,这个类提供服务与操作系统之间一个简单的接口。使用这个类实现自己的服务非常简单,只要改写少数几个基类中的
if (ps[i] != NULL) iStr++;
}
// Check to see if the event source has been registered,
// and if not then register it now.
if (!m_hEventSource) {
m_hEventSource = ::RegisterEventSource(NULL, // local machine
m_szServiceName); // source name
}
if (m_hEventSource) {
::ReportEvent(m_hEventSource,
wType,
0,
dwID,
NULL, // sid
iStr,
0,
ps,
NULL);
}
} 如你所见,其主要工作是由 ReportEvent 系统函数处理。 至此,我们已经可以通过调用 CNTService::LogEvent 在系统日志中记录事件了。接下来我们将考虑创建服务本身的一些代码。 编写服务代码 为了建构一个简单的 Win32 服务,你需要知道的大多数信息都可以在 Platform SDK 中找到。其中的范例代码都是用C语言写的,并且很好理解。我的 CNTService 类就是基于这些代码。 一个服务主要包括三个函数:
main函数,这是代码的入口。我们正是在这里解析任何命令行参数并进行服务的安装,移除,启动等等。
在例子中,提供真正服务代码的入口函数叫 ServiceMain。你可以随便叫它什么。在服务第一次启动的恶时候,将该函数的地址传递给服务管理器。
处理来自服务管理器命令消息的函数。在例子中,这个函数叫 Handler,这个名字可以随意取。
服务回调函数 因为 ServiceMain 和 Handler 函数都是由系统来调用,所以它们必须遵循操作系统的参数传递规范和调用规范。也就是说,它们不能简单地作为某个 C++ 类的成员函数。这样就给封装带来一些不便,因为我们想把 Win32 服务的功能封装在一个 C++ 类中。为了解决这个问题,我将 ServiceMain 和 Handler 函数创建成 CNTService 类的静态成员。这样就使我得以创建可以由操作系统调用的函数。 但是,这样做还没有完全解决问题,因为系统不允许给被调用的函数传递任何形式的用户数据,所以我们无法确定对 C++ 对象特定实例的 ServiceMain 或 Handler 的调用。用了一个非常简单但有局限的方法来解决这个问题。我创建一个包含 C++ 对象指针的静态变量。这个变量是在该对象首次创建是进行初始化的。这样便限制你每个服务应用只有一个C++对象。我觉得这个限制并不过分。下面是 NTService.h 文件中的声明:
class CNTService
{
[...]
// 静态数据
static CNTService* m_pThis; // nasty hack to get object ptr
[...]
}; 下面是初始化 m_pThis 指针的方法:
CNTService::CNTService(const char* szServiceName)
{
// Copy the address of the current object so we can access it from
// the static member callback functions.
// WARNING: This limits the application to only one CNTService object.
m_pThis = this;
[...]
} CNTService 类 当我创建 C++ 对象封装 Windows 函数时,我尝试为我封装的每个 Windows API 除了创建成员函数外,还做一些别的工作,我尝试让对象更容易使用,降低实现特定项目所需的代码行数。因此我的对象是基于“我想让这个对象做什么?”而不是“Windows 用这些 APIs 做什么?” CNTService 类包含一些用来解析命令行的成员函数,为了处理服务的安装和拆卸以及事件日志的记录,你得在派生类中重写一些虚拟函数来处理服务控制管理器的请求。下面我们将通过本文的例子服务实现来研究这些函数的使用。 如果你想创建尽可能简单的服务,只需要重写 CNTService::Run 即可,它是你编写代码实现具体服务任务的地方。你还需要实现 main 函数。如果服务需要实现一些初始化。如从注册表读取数据,还需重写 CNTService::OnInit。如果你要向服务发送命令消息 ,那么可以在服务中使用系统函数 ControlService,重写 CNTService::OnUserControl 来处理请求。在例子应用程序中使用 CNTService NTService 在 CMyService 类中实现了它的大多数功能,CMyService 由 CNTService 派生。 MyService.h 头文件如下:
// myservice.h
#include "ntservice.h"
class CMyService : public CNTService
{
public:
CMyService();
virtual BOOL OnInit();
virtual void Run();
virtual BOOL OnUserControl(DWORD dwOpcode);
void SaveStatus();
// Control parameters
int m_iStartParam;
int m_iIncParam;
// Current state
int m_iState;
}; 正像你所看到的,CMyService 改写了 CNTService 的 OnInit、Run 和 OnUserControl。它还有一个函数叫 SaveStatus,这个函数被用于将数据写入注册表,那些成员变量用来保存当前状态。例子服务每隔一定的时间对一个整型变量进行增量处理。开始值和增 量值都存在注册表的参数中。这样做并没有别的意图。只是为了简单示范。下面我们看看这个服务是如何实现的。 实现 main 函数 有了从 CNTService 派生的 CMyService,实现 main 函数很简单,请看 NTServApp.cpp 文件:
int main(int argc, char* argv[])
{
// 创建服务对象
CMyService MyService;
// 解析标准参数 (安装, 卸载, 版本等.)
if (!MyService.ParseStandardArgs(argc, argv)) {
// 未发现任何标准参数,所以启动服务,
// 取消下面 DebugBreak 代码行的注释,
// 当服务启动后进入调试器,
//DebugBreak();
MyService.StartService();
}
// 到这里,服务已经停止
return MyService.m_Status.dwWin32ExitCode;
} 这里代码不多,但执行后却发生了很多事情,让我们一步一步来看。首先,我们创建一个 MyService 类的实例。构造函数设置初始化状态和服务名字(MyService.cpp):
CMyService::CMyService():CNTService("NT Service Demonstration")
{
m_iStartParam = 0;
m_iIncParam = 1;
m_iState = m_iStartParam;
} 接着调用 ParseStandardArgs 检查命令行是否包含服务安装(-i)、卸载(-u)以及报告其版本号(-v)的请求。CNTService::ParseStandardArgs 分别调用 CNTService::IsInstalled,CNTService::Install 和 CNTService::Uninstall 来处理这些请求。如果没有可识别的命令行参数,则假设该服务控制管理器试图启动该服务并调用 StartService。该函数直到服务停止运行才返回。当你调试完代码,即可把用于调试的代码行注释掉或删除。安装和卸载服务 服务的安装由 CNTService::Install 处理,它用 Win32 服务管理器注册服务并在注册表中建立一个条目以支持服务运行时日志消息。 服务的卸载由 CNTService::Uninstall 处理,它仅仅通知服务管理器该服务已经不再需要。CNTService::Uninstall 不会删除服务实际的可执行文件。 编写服务代码 现在我们来编写实现服务的具体代码。对于 NTService 例子,有三个函数要写。他们涉及初始化,运行服务的细节和响应控制请求。初始化 注册表有一个给服务用来存储参数的地方:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices 我就是选择这里来存储我的服务配置信息。我创建了一个 Parameters 键,并在此存储我要保存的值。所以当服务启动时,OnInit 函数被调用;这个函数从注册表中读取初始设置。
BOOL CMyService::OnInit()
{
// Read the registry parameters.
// Try opening the registry key:
// HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices\Parameters
HKEY hkey;
char szKey[1024];
strcpy(szKey, "SYSTEM\CurrentControlSet\Services\");
strcat(szKey, m_szServiceName);
strcat(szKey, "\Parameters");
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szKey,
0,
KEY_QUERY_VALUE,
&hkey) == ERROR_SUCCESS) {
// Yes we are installed.
DWORD dwType = 0;
DWORD dwSize = sizeof(m_iStartParam);
RegQueryValueEx(hkey,
"Start",
NULL,
&dwType,
(BYTE*)&m_iStartParam,
&dwSize);
dwSize = sizeof(m_iIncParam);
RegQueryValueEx(hkey,
"Inc",
NULL,
&dwType,
(BYTE*)&m_iIncParam,
&dwSize);
RegCloseKey(hkey);
}
// Set the initial state.
m_iState = m_iStartParam;
return TRUE;
} 现在我们有了服务参数,我们便可以运行服务了。运行服务 当 Run 函数被调用时将执行服务的主体代码。本文例子的这部分很简单:
void CMyService::Run()
{
while (m_bIsRunning) {
// Sleep for a while.
DebugMsg("My service is sleeping (%lu)...", m_iState);
Sleep(1000);
// Update the current state.
m_iState += m_iIncParam;
}
} 注意,只要服务不终止,这个函数就不会退出。当有终止服务的请求时,CNTService::m_bIsRunning 标志被置成 FALSE。如果在服务终止时,你要实现清除操作,那么你还可以改写 OnStop 和/或 OnShutdown。响应控制请求 你可以用任何适合的方式与服务通讯——命名管道,思想交流,便条等等——对于一些简单的请求,用系统函数 ControlService 很容易实现。CNTService 提供了一个处理器专门用于通过 ControlService 函数发送的非标准消息(也就是用户发送的消息)。本文例子用单一消息在注册表中保存当前服务的状态,以便其它应用程序能看到它。我不建议用这种方法来监控服务,因为它不是最佳方法,这只是比较容易编码实现而已。ControlService 所能处理的用户消息必须在 128 到 255 这个范围。我定义了一个常量 SERVICE_CONTROL_USER,128 作为基值。范围内的用户消息被发送到 CNTService:: OnUserControl,在例子服务中,处理此消息的细节如下:
BOOL CMyService::OnUserControl(DWORD dwOpcode)
{
switch (dwOpcode) {
case SERVICE_CONTROL_USER + 0:
// Save the current status in the registry.
SaveStatus();
return TRUE;
default:
break;
}
return FALSE; // say not handled
} SaveStatus 是一个局部函数,用来在注册表中存储服务状态。 调试 Win32 服务 main 函数中包含一个对 DebugBreak 的调用,当服务第一次被启动时,它会激活系统调试器。你可以监控来自调试器命令窗口中的服务调试信息。你可以在服务中用 CNTService::DebugMsg 来报告调试期间感兴趣的事件。 为了调试服务代码,你需要按照 Platform SDK 文档中的要求安装 系统调试器(WinDbg)。你也可以用 Visual Studio 自带的调试器调试 Win32 服务。 有一点很重要,那就是 当它被服务管理器控制时,你不能终止服务和单步执行,因为服务管理器会让服务请求 超时并终止服务线程。所以你只能让服务吐出消息,跟踪其过程并在调试器窗口查看它们。 当服务启动后(例如,从控制面板的“服务”中),调试器将在服务线程的挂起后启动。你需要通过单击“Go”按钮或按 F5 让继续运行。然后在调试器中观察服务的运行过程。 下面是启动和终止服务的调试输出例子:
Module Load: WinDebug/NTService.exe (symbol loading deferred)
Thread Create: Process=0, Thread=0
Module Load: C:NT351system32NTDLL.DLL (symbol loading deferred)
Module Load: C:NT351system32KERNEL32.DLL (symbol loading deferred)
Module Load: C:NT351system32ADVAPI32.DLL (symbol loading deferred)
Module Load: C:NT351system32RPCRT4.DLL (symbol loading deferred)
Thread Create: Process=0, Thread=1
*** WARNING: symbols checksum is wrong 0x0005830f 0x0005224f for C:NT351symbolsdllNTDLL.DBG
Module Load: C:NT351symbolsdllNTDLL.DBG (symbols loaded)
Thread Terminate: Process=0, Thread=1, Exit Code=0
Hard coded breakpoint hit
Hard coded breakpoint hit
[](130): CNTService::CNTService()
Module Load: C:NT351SYSTEM32RPCLTC1.DLL (symbol loading deferred)
[NT Service Demonstration](130): Calling StartServiceCtrlDispatcher()
Thread Create: Process=0, Thread=2
[NT Service Demonstration](174): Entering CNTService::ServiceMain()
[NT Service Demonstration](174): Entering CNTService::Initialize()
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 2)
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 4)
[NT Service Demonstration](174): Entering CNTService::Run()
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](130): CNTService::Handler(1)
[NT Service Demonstration](130): Entering CNTService::Stop()
[NT Service Demonstration](130): CNTService::SetStatus(3026680, 3)
[NT Service Demonstration](130): Leaving CNTService::Stop()
[NT Service Demonstration](130): Updating status (3026680, 3)
[NT Service Demonstration](174): Leaving CNTService::Run()
[NT Service Demonstration](174): Leaving CNTService::Initialize()
[NT Service Demonstration](174): Leaving CNTService::ServiceMain()
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 1)
Thread Terminate: Process=0, Thread=2, Exit Code=0
[NT Service Demonstration](130): Returned from StartServiceCtrlDispatcher()
Module Unload: WinDebug/NTService.exe
Module Unload: C:NT351system32NTDLL.DLL
Module Unload: C:NT351system32KERNEL32.DLL
Module Unload: C:NT351system32ADVAPI32.DLL
Module Unload: C:NT351system32RPCRT4.DLL
Module Unload: C:NT351SYSTEM32RPCLTC1.DLL
Thread Terminate: Process=0, Thread=0, Exit Code=0
Process Terminate: Process=0, Exit Code=0
>
#include
原文出处:Five Steps to Writing Windows Services in C http://www.vckbase.com/document/viewdoc/?id=1474摘要 Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并 实现一个简单的服务程序,其功能是查询系统中可用物理内存数量,然后将结果写入一个文本文件。最后,你可以用所学知识编写自己的 Windows 服务。 当初我写第一个 NT 服务时
http://hi.baidu.com/b5000/blog/item/b4f9138291e123a10df4d243.html运行时库是程序在运行时所需要的库文件,通常运行时库是以LIB或DLL形式提供的。C运行时库诞生于20世纪70年代,当时的程序世界还很单纯,应用程序都是单线程的,多任务或多线程机制在此时还属于新观念。所以这个时期的C运行时库都是单线程的。
随着操作系统多线程技术的发展,最初的C运行时库无法满足程序的需求,出现了严重的问题。C运行时库使用了多个全局变量(例如errno)和静 态变量,这可能在多线程程序中引起冲突。假设两个线程都同时设置errno,<< 8) + _winminor; _osver = (_osver >
http://xujingli88.blog.163.com/blog/static/4117861920098212402275/当一个任务想要与另一任务“谈话”时,它创建一个消息,并将此消息放入它想要与之谈话的任务的消息队列生产者任务生成数据,将它发送给消费者任务;消费者任务随后消费这个数据,例如
#include “stdafx.h” #include “TaskOne.h” #include “Consumer.h” #include “Producer.h” int _tmain(int argc, _TCHAR* argv[]) {
(4040) Producer task opened(3844) Sending msg 0 to remote task(4040) consumer task opened(3844) Sending msg 1 to remote task(2556) Get message:1 from remote task(2556) Get message:1 from remote task请按任意键继续. . . (3844) Sending msg 2 to remote task(2556) Get message:2 from remote task(3844) Sending msg 3 to remote task(2556) Get message:3 from remote task(3844) Sending msg 4 to remote task(2556) Get message:4 from remote task(3844) Sending msg 5 to remote task(2556) Get message:5 from remote task(3844) Sending msg 6 to remote task(2556) Get message:6 from remote task(3844) Sending msg 7 to remote task(2556) Get message:7 from remote task(3844) Sending msg 8 to remote task(2556) Get message:8 from remote task(3844) Sending msg 9 to remote task(2556) Get message:9 from remote task(3844) Sending msg 10 to remote task(2556) Get message:10 from remote task(2556) consumer task closed(3844) Producer task closed
http://blog.csdn.net/yjh4866/archive/2011/03/26/6279536.aspx下面这段代码是用ACE从百度的Web服务器取网页数据的代码
#include “ace/INET_Addr.h”#include “ace/SOCK_Connector.h”#include “ace/SOCK_Stream.h”#include “ace/Time_Value.h” int main (int argc, char *argv[]){ const char *pathname = “index.html”;< 4; i++) { iov[i].iov_base = header[i]; iov[i].iov_len = strlen(header[i]); } // Wait no more than 5 seconds to send or receive data. ACE_Time_Value timeout(5); peer.sendv_n(iov, 4, &timeout); ssize_t lenRecv = peer.recv(buf, sizeof buf, &timeout); while (lenRecv >
一、简介
以前曾介绍过一个开源日志系统log4cplus,ACE也有自己的Logging Facility,与log4cplus相似,ACE日志系统
也具有线程安全、灵活、分级显示等特点,可以面向程序调试、运行、测试、和维护等全生命周期,可以选择将
信息输出到屏幕、文件、系统日志(如Windows下的Event log)、甚至是远程服务器。除此之外,ACE日志系统
支持回调函数以及运行时刻动态配置(Runtime Configuration ),本文主要参考了《ACE Programmer’s Guide,
The: Practical Design Pa< ace/Log_Msg.h >< ace/Log_Msg.h >< ace/Task.h >< ace/Log_Msg.h >