字体: | 推荐给好友 上一篇 | 下一篇

Windows2000 服务器端应用程序开发设计指南-服务应用程序(2)

发布: 2008-5-06 20:10 | 作者: Jeffrey Richter Jaso | 来源: 本站原创 | 查看: 169次


TimeService.cpp 

/********************************************************************

/模组:TimeService.cpp

通告:Copyright (c)2000 Jeffrey Richter

********************************************************************/

#include "..\CmnHdr.h"    /* 请参阅附录A */

#include "..\ClassLib\IOCP.h"   /* 请参阅附录B */

#include "..\ClassLib\EnsureCleanup.h" /* 请参阅附录B */

#define SERVICESTATUS_IMPL

#include "ServiceStatus.h"

//////////////////////////////////////////////////////////////////////////////

TCHAR g_szServiceName[] = TEXT("Programming Server-Side Applications Time");

CServiceStatus g_ssTime;

//////////////////////////////////////////////////////////////////////////////

// 完成连接埠因为以下二个原因之一而醒来

enum COMPKEY {

CK_SERVICECONTROL, // 一个服务控制码

CK_PIPE       // 一个客户端连接至我们的管道

};

//////////////////////////////////////////////////////////////////////////////

DWORD WINAPI TimeHandlerEx(DWORD dwControl, DWORD dwEventType,

PVOID pvEventData, PVOID pvContext) {

DWORD dwReturn = ERROR_CALL_NOT_IMPLEMENTED;

BOOL fPostControlToServiceThread = FALSE;

switch (dwControl) {

case SERVICE_CONTROL_STOP:

case SERVICE_CONTROL_SHUTDOWN:

  g_ssTime.SetUltimateState(SERVICE_STOPPED, 2000);

  fPostControlToServiceThread = TRUE;

  break;

case SERVICE_CONTROL_PAUSE:

  g_ssTime.SetUltimateState(SERVICE_PAUSED, 2000);

  fPostControlToServiceThread = TRUE;

  break;

case SERVICE_CONTROL_CONTINUE:

  g_ssTime.SetUltimateState(SERVICE_RUNNING, 2000);

  fPostControlToServiceThread = TRUE;

  break;

case SERVICE_CONTROL_INTERROGATE:

  g_ssTime.ReportStatus();

  break;

case SERVICE_CONTROL_PARAMCHANGE:

  break;

case SERVICE_CONTROL_DEVICEEVENT:

case SERVICE_CONTROL_HARDWAREPROFILECHANGE:

case SERVICE_CONTROL_POWEREVENT:

  break;

case 128: // 一个测试用的使用者定义控制码

  // 注意:正常的情况下,一个服务不该显示使用者介面

  MessageBox(NULL, TEXT("In HandlerEx processing user-defined code."),

   g_szServiceName, MB_OK |MB_SERVICE_NOTIFICATION);

  break;

}

if (fPostControlToServiceThread) {

  // Handler线程非常简单而且执行的非常快速

  // 它只传递控制码以离开ServiceMain线程

  CIOCP* piocp = (CIOCP*) pvContext;

  piocp->PostStatus(CK_SERVICECONTROL, dwControl);

  dwReturn = NO_ERROR;

}

return(dwReturn);

}

//////////////////////////////////////////////////////////////////////////////

void WINAPI TimeServiceMain(DWORD dwArgc, PTSTR* pszArgv) {

ULONG_PTR CompKey = CK_SERVICECONTROL;

DWORD dwControl = SERVICE_CONTROL_CONTINUE;

CEnsureCloseFile hpipe;

OVERLAPPED o, *po;

SYSTEMTIME st;

DWORD dwNumBytes;

// 建立完成端口并储存在整体变数中它的handle

//所以Handler函数可以存取它

CIOCP iocp(0);

g_ssTime.Initialize(g_szServiceName, TimeHandlerEx, (PVOID) &iocp, TRUE);

g_ssTime.AcceptControls(

  SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE);

do {

  switch (CompKey) {

  case CK_SERVICECONTROL:

   // 我们取得一个控制码

   switch (dwControl) {

   case SERVICE_CONTROL_CONTINUE:

    // 当它正在执行时,建立一个管道以让客户端连结

    hpipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\TimeService"),

     PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,

     PIPE_TYPE_BYTE, 1, sizeof(st), sizeof(st), 1000, NULL);

    // 建立管道与完成连接埠之关联

    iocp.AssociateDevice(hpipe, CK_PIPE);

    // 相对于管道,此处悬置了一个非同步连接

    ZeroMemory(&o, sizeof(o));

    ConnectNamedPipe(hpipe, &o);

    g_ssTime.ReportUltimateState();

    break;

   case SERVICE_CONTROL_PAUSE:

   case SERVICE_CONTROL_STOP:

    // 若没有在执行中,则关闭管道以使客户端无法与之连结

    hpipe.Cleanup();

    g_ssTime.ReportUltimateState();

    break;

   }

   break;

  case CK_PIPE:

   if (hpipe.IsValid()) {

    // 我们取得了一个客户端要求:传送我们的系统时间至客户端

    GetSystemTime(&st);

    WriteFile(hpipe, &st, sizeof(st), &dwNumBytes, NULL);

    FlushFileBuffers(hpipe);

    DisconnectNamedPipe(hpipe);

    // 允许另一个客户端连结

    ZeroMemory(&o, sizeof(o));

    ConnectNamedPipe(hpipe, &o);

   } else {

    // 当管道被关闭时,我们会执行到此处

   }

  }

  if (g_ssTime != SERVICE_STOPPED) {

   // 除非一个控制码进来或是有一个客户端连接上来,否则即处于睡眠状态

   iocp.GetStatus(&CompKey, &dwNumBytes, &po);

   dwControl = dwNumBytes;

  }

} while (g_ssTime != SERVICE_STOPPED);

}

/////////////////////////////////////////////////////////////////////////////////////////

void InstallService() {

// 在此机器上开启SCM

CEnsureCloseServiceHandle hSCM =

  OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

// 取得我们的路径名称

TCHAR szModulePathname[_MAX_PATH * 2];

GetModuleFileName(NULL, szModulePathname, chDIMOF(szModulePathname));

// 因为处理程序去执行一个服务,所以增加转换switch

lstrcat(szModulePathname, TEXT(" /service"));

// 将此服务加入SCM的资料库中

CEnsureCloseServiceHandle hService =

  CreateService(hSCM, g_szServiceName, g_szServiceName,

   SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS,

   SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,

   szModulePathname, NULL, NULL, NULL, NULL, NULL);

SERVICE_DESCRIPTION sd = {

  TEXT("Sample Time Service from")

  TEXT("Programming Server-Side Applications for Microsoft Windows Book")

};

ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd);

}

//////////////////////////////////////////////////////////////////////////////

void RemoveService() {

// 在此机器上开启SCM

CEnsureCloseServiceHandle hSCM =

  OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);

// 为了DELETE的存取而开启这个服务

CEnsureCloseServiceHandle hService =

  OpenService(hSCM, g_szServiceName, DELETE);

// 从SCM资料库中移除此服务

DeleteService(hService);

}

//////////////////////////////////////////////////////////////////////////////

int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {

int nArgc = __argc;

#ifdef UNICODE

PCTSTR *ppArgv = (PCTSTR*) CommandLineToArgvW(GetCommandLine(), &nArgc);

#else

PCTSTR *ppArgv = (PCTSTR*) __argv;

#endif

if (nArgc < 2) {

  MessageBox(NULL,

   TEXT("Programming Server-Side Applications for Microsoft Windows:")

   TEXT("Time Service Sample\n\n")

   TEXT("Usage:TimeService.exe [/install] [/remove] [/debug] ")

   TEXT("[/service]\n")

   TEXT(" //install\t\tInstalls the service in the SCM’s database.\n")

   TEXT(" //remove\t\tRemoves the service from the SCM’s database.\n")

   TEXT(" //debug \t \tRuns the service as a normal process for ")

   TEXT("debugging.\n ")

   TEXT(" //service \t\tRuns the process as a service")

   TEXT("(should only be set in the SCM’s database)."),

   g_szServiceName, MB_OK);

} else {

  for (int i = 1; i < nArgc; i++) {

   if ((ppArgv[i][0] == TEXT(’-’)) || (ppArgv[i][0] == TEXT(’/’))) {

   // 命令列开关

   if (lstrcmpi(&ppArgv[i][1], TEXT("install")) == 0)

    InstallService();

   if (lstrcmpi(&ppArgv[i][1], TEXT("remove")) == 0)

    RemoveService();

   if (lstrcmpi(&ppArgv[i][1], TEXT("debug")) == 0) {

    // 执行服务控制码

    TimeServiceMain(0, NULL);

   }

   if (lstrcmpi(&ppArgv[i][1], TEXT("service")) == 0) {

    // 连接至服务控制分发器

    SERVICE_TABLE_ENTRY ServiceTable [] == {

      { g_szServiceName, TimeServiceMain },

      { NULL, NULL }   // End of list

     };

     chVERIFY(StartServiceCtrlDispatcher(ServiceTable));

    }

   }

  }

}

#ifdef UNICODE

HeapFree(GetProcessHeap(), 0, (PVOID) ppArgv);

#endif

return(0);

}

///////////////////////////////// End of File ////////////////////////////////

ServiceStatus.h

/*******************************************************************

模组:ServiceStatus.h

注意:Copyright (c)2000 Jeffrey Richter

目的:这个类别封装了一个SERVICE_STATUS结构以适当的使用

********************************************************************/

#pragma once

///////////////////////////////////////////////////////////////////////////////

#include "..\CmnHdr.h"            /*See Appendix A. */

#include "Gate.h "

///////////////////////////////////////////////////////////////////////////////

class CServiceStatus : public SERVICE_STATUS {

public:

CServiceStatus();

BOOL Initialize(PCTSTR szServiceName, LPHANDLER_FUNCTION_EX pfnHandler,

  PVOID pvContext, BOOL fOwnProcess, BOOL fInteractWithDesktop = FALSE);

VOID AcceptControls(DWORD dwFlags, BOOL fAccept = TRUE);

BOOL ReportStatus();

BOOL SetUltimateState(DWORD dwUltimateState, DWORD dwWaitHint = 0);

BOOL AdvanceState(DWORD dwWaitHint, DWORD dwCheckPoint = 0);

BOOL ReportUltimateState();

BOOL ReportWin32Error(DWORD dwError);

BOOL ReportServiceSpecificError(DWORD dwError);

operator DWORD() const { return(dwCurrentState); }

private:

SERVICE_STATUS_HANDLE m_hss;

CGate m_gate;

};

///////////////////////////////////////////////////////////////////////////////

inline CServiceStatus::CServiceStatus() {

ZeroMemory(this, sizeof(SERVICE_STATUS));

m_hss = NULL;

}

///////////////////////////////////////////////////////////////////////////////

inline VOID CServiceStatus::AcceptControls(DWORD dwFlags, BOOL fAccept) {

if (fAccept) dwControlsAccepted |= dwFlags;

else dwControlsAccepted &= ~dwFlags;

}

///////////////////////////////////////////////////////////////////////////////

inline BOOL CServiceStatus::ReportStatus() {

BOOL fOk = ::SetServiceStatus(m_hss, this);

chASSERT(fOk);

return(fOk);

}

///////////////////////////////////////////////////////////////////////////////

inline BOOL CServiceStatus::ReportWin32Error(DWORD dwError) {

dwWin32ExitCode = dwError;

dwServiceSpecificExitCode = 0;

return(ReportStatus());

}

inline BOOL CServiceStatus::ReportServiceSpecificError(DWORD dwError) {

dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;

dwServiceSpecificExitCode = dwError;

return(ReportStatus());

}

///////////////////////////////////////////////////////////////////////////////

#ifdef SERVICESTATUS_IMPL

///////////////////////////////////////////////////////////////////////////////

BOOL CServiceStatus::Initialize(PCTSTR szServiceName,

LPHANDLER_FUNCTION_EX pfnHandler, PVOID pvContext,

BOOL fOwnProcess, BOOL fInteractWithDesktop) {

m_hss = RegisterServiceCtrlHandlerEx(szServiceName, pfnHandler, pvContext);

chASSERT(m_hss != NULL);

dwServiceType = fOwnProcess

  ? SERVICE_WIN32_OWN_PROCESS : SERVICE_WIN32_SHARE_PROCESS;

if (fInteractWithDesktop)

  dwServiceType |= SERVICE_INTERACTIVE_PROCESS;

dwCurrentState = SERVICE_START_PENDING;

dwControlsAccepted = 0;

dwWin32ExitCode = NO_ERROR;

dwServiceSpecificExitCode = 0;

dwCheckPoint = 0;

dwWaitHint = 2000;

return(m_hss != NULL);

}

///////////////////////////////////////////////////////////////////////////////

BOOL CServiceStatus::SetUltimateState(DWORD dwUltimateState,

DWORD dwWaitHint) {

DWORD dwPendingState = 0; // 一个无效的状态值

switch (dwUltimateState) {

case SERVICE_STOPPED:

  dwPendingState = SERVICE_STOP_PENDING;

  break;

case SERVICE_RUNNING:

  dwPendingState = (dwCurrentState == SERVICE_PAUSED)

   ? SERVICE_CONTINUE_PENDING :SERVICE_START_PENDING;

  break;

case SERVICE_PAUSED:

  dwPendingState = SERVICE_PAUSE_PENDING;

  break;

default:

  chASSERT(dwPendingState != 0);   // Invalid parameter

  break;

}

// 当建立了一个新的ServiceMain线程,系统假设

// dwCurrentState=SERVICE_START_PENDING, dwCheckPoint=0, dwWaitHint=2000

// So,since we must always increment the checkpoint, let’s start at 1

dwCheckPoint = 1;

this->dwWaitHint = dwWaitHint;

// 没有错误被回报

dwWin32ExitCode = NO_ERROR;

dwServiceSpecificExitCode = 0;

BOOL fOk = FALSE; // 假设失败的情形

if (dwPendingState != 0) {

  // 如果另一个悬置中的作业没有被完成,即等待它

  m_gate.WaitToEnterGate();

  dwCurrentState = dwPendingState; // Update the state in the structure

  // 如果没有等待提示,则到达要求状态

  fOk = (dwWaitHint != 0) ? ReportStatus() : ReportUltimateState();

}

return(fOk);

}

///////////////////////////////////////////////////////////////////////////////

BOOL CServiceStatus::AdvanceState(DWORD dwWaitHint, DWORD dwCheckPoint) {

// 一个为0的检查点为无效的,所以我们会增加检查点至1

this->dwCheckPoint =

  (dwCheckPoint == 0) ? this->dwCheckPoint + 1 : dwCheckPoint;

this->dwWaitHint = dwWaitHint;

// 没有错误被回报

dwWin32ExitCode = NO_ERROR;

dwServiceSpecificExitCode = 0;

return(ReportStatus());

}

///////////////////////////////////////////////////////////////////////////////

BOOL CServiceStatus::ReportUltimateState() {

DWORD dwUltimateState = 0;   // An invalid state value

switch (dwCurrentState) {

case SERVICE_START_PENDING:

case SERVICE_CONTINUE_PENDING:

   dwUltimateState = SERVICE_RUNNING;

   break;

case SERVICE_STOP_PENDING:

   dwUltimateState = SERVICE_STOPPED;

   break;

case SERVICE_PAUSE_PENDING:

   dwUltimateState = SERVICE_PAUSED;

   break;

}

dwCheckPoint = dwWaitHint = 0; // We reached the ultimate state

// 没有错误被回报

dwWin32ExitCode = NO_ERROR;

dwServiceSpecificExitCode = 0;

BOOL fOk = FALSE; // 假设为失败的情形

if (dwUltimateState != 0) [

  dwCurrentState = dwUltimateState;   // 更新结构中的状态

  fOk = ReportStatus();

  // 我们的状态改变完成,允许一个新的状态被改变

  m_gate.LiftGate();

}

return(fOk);

}

///////////////////////////////////////////////////////////////////////////////

#endif   // SERVICESTATUS_IMPL

//////////////////////////////// End of File /////////////////////////////////

Gate.h 

/******************************************************************************

模组:Gate.h

通告:Copyright (c)2000 Jeff, rey Richter

目的:这个类别建立了一个正常开启的通讯闸,同一个时间内只有一个线程由此经过
*******************************************************************************/

#pragma once   // 在完成单元前包含这个标头文件

///////////////////////////////////////////////////////////////////////////////

#include "..\CmnHdr.h" /* 请参阅附录A */

///////////////////////////////////////////////////////////////////////////////

class CGate {

public:

CGate(BOOL fInitiallyUp = TRUE, PCTSTR pszName = NULL) {

  m_hevt = ::CreateEvent(NULL, FALSE, fInitiallyUp, pszName);

}

~CGate() {

  ::CloseHandle(m_hevt);

}

DWORD WaitToEnterGate(DWORD dwTimeout = INFINITE, BOOL fAlertable = FALSE) {

  return(::WaitForSingleObjectEx(m_hevt, dwTimeout, fAlertable));

}

VOID LiftGate() {::SetEvent(m_hevt); }

private:

HANDLE m_hevt;

};

///////////////////////////////// End of File /////////////////////////////////

43/4<1234>
 

评分:0

我来说两句

seccode