Yesky首页| 产品报价| 行情| 手机 | 数码 | 笔记本 | 台式机 | DIY硬件 | 外设 | 网络 | 数字家庭 | 评测 | 软件 | e时代 | 游戏 | 图片 | 壁纸 | 群乐 | 社区 | 博客 | 下载
您现在的位置: 天极网 > 开发频道 > Win32位程序设计初步之服务
全文

Win32位程序设计初步之服务

2004-11-07 09:00 作者: QQ新人类编译 出处: 天极网 责任编辑:方舟

  结论

  服务对于Windows NT是很重要的一部分,因为它可让你对操作系统进行扩展。使用列表1的代码作为一个模板,你将会发现要建立一个自己的新服务是非常简单的。

  列表1

  实现可能是最简单NT服务的代码


//***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code implements the simplest possible service.
// It beeps every 2 seconds, or at a user specified interval.
file://***************************************************************

// beepserv.cpp

#include
#include
#include
#include

#define DEFAULT_BEEP_DELAY 2000

// Global variables

// The name of the service
char *SERVICE_NAME = "BeepService";
// Event used to hold ServiceMain from completing
HANDLE terminateEvent = NULL;
// Handle used to communicate status info with
// the SCM. Created by RegisterServiceCtrlHandler
SERVICE_STATUS_HANDLE serviceStatusHandle;
// The beep interval in ms.
int beepDelay = DEFAULT_BEEP_DELAY;
// Flags holding current state of service
BOOL pauseService = FALSE;
BOOL runningService = FALSE;
// Thread for the actual work
HANDLE threadHandle = 0;

void ErrorHandler(char *s, DWORD err)
{
cout << s << endl;
cout << "Error number: " << err << endl;
ExitProcess(err);
}

// This function consolidates the activities of
// updating the service status with
// SetServiceStatus
BOOL SendStatusToSCM (DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint)
{
BOOL success;
SERVICE_STATUS serviceStatus;

// Fill in all of the SERVICE_STATUS fields
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = dwCurrentState;

// If in the process of doing something, then accept
// no control events, else accept anything
if (dwCurrentState == SERVICE_START_PENDING)
serviceStatus.dwControlsAccepted = 0;
else
serviceStatus.dwControlsAccepted =
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;

// if a specific exit code is defined, set up
// the win32 exit code properly
if (dwServiceSpecificExitCode == 0)
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
else
serviceStatus.dwWin32ExitCode =
ERROR_SERVICE_SPECIFIC_ERROR;
serviceStatus.dwServiceSpecificExitCode =
dwServiceSpecificExitCode;

serviceStatus.dwCheckPoint = dwCheckPoint;
serviceStatus.dwWaitHint = dwWaitHint;

// Pass the status record to the SCM
success = SetServiceStatus (serviceStatusHandle,
&serviceStatus);
return success;
}

DWORD ServiceThread(LPDWORD param)
{
while (1)
{
Beep(200,200);
Sleep(beepDelay);
}
return 0;
}

// Initializes the service by starting its thread
BOOL InitService()
{
DWORD id;

// Start the service's thread
threadHandle = CreateThread(0, 0,
(LPTHREAD_START_ROUTINE) ServiceThread,
0, 0, &id);

if (threadHandle==0)
return FALSE;
else
{
runningService = TRUE;
return TRUE;
}
}

// Dispatches events received from the SCM
VOID Handler (DWORD controlCode)
{
DWORD currentState = 0;
BOOL success;

switch(controlCode)
{
// There is no START option because
// ServiceMain gets called on a start

// Stop the service
case SERVICE_CONTROL_STOP:
// Tell the SCM what's happening
success = SendStatusToSCM(SERVICE_STOP_PENDING,
NO_ERROR, 0, 1, 5000);
runningService=FALSE;
// Set the event that is holding ServiceMain
// so that ServiceMain can return
SetEvent(terminateEvent);
return;

// Pause the service
case SERVICE_CONTROL_PAUSE:
if (runningService && !pauseService)
{
// Tell the SCM what's happening
success = SendStatusToSCM(
SERVICE_PAUSE_PENDING,
NO_ERROR, 0, 1, 1000);
pauseService = TRUE;
SuspendThread(threadHandle);
currentState = SERVICE_PAUSED;
}
break;

// Resume from a pause
case SERVICE_CONTROL_CONTINUE:
if (runningService && pauseService)
{
// Tell the SCM what's happening
success = SendStatusToSCM(
SERVICE_CONTINUE_PENDING,
NO_ERROR, 0, 1, 1000);
pauseService=FALSE;
ResumeThread(threadHandle);
currentState = SERVICE_RUNNING;
}
break;

// Update current status
case SERVICE_CONTROL_INTERROGATE:
// it will fall to bottom and send status
break;

// Do nothing in a shutdown. Could do cleanup
// here but it must be very quick.
case SERVICE_CONTROL_SHUTDOWN:
return;

default:
break;
}
SendStatusToSCM(currentState, NO_ERROR, 0, 0, 0);
}

// Handle an error from ServiceMain by cleaning up
// and telling SCM that the service didn't start.
VOID terminate(DWORD error)
{
// if terminateEvent has been created, close it.
if (terminateEvent) CloseHandle(terminateEvent);

// Send a message to the scm to tell about stopage
if (serviceStatusHandle)
SendStatusToSCM(SERVICE_STOPPED, error,
0, 0, 0);

// If the thread has started, kill it off
if (threadHandle) CloseHandle(threadHandle);

// Do not need to close serviceStatusHandle
}

// ServiceMain is called when the SCM wants to
// start the service. When it returns, the service
// has stopped. It therefore waits on an event
// just before the end of the function, and
// that event gets set when it is time to stop.
// It also returns on any error because the
// service cannot start if there is an eror.
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{
BOOL success;

// immediately call Registration function
serviceStatusHandle =
RegisterServiceCtrlHandler(
SERVICE_NAME, (LPHANDLER_FUNCTION)Handler);
if (!serviceStatusHandle) {terminate(GetLastError()); return;}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 1, 5000);
if (!success) {terminate(GetLastError()); return;}

// create the termination event
terminateEvent = CreateEvent (0, TRUE, FALSE, 0);
if (!terminateEvent) {terminate(GetLastError()); return;}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 2, 1000);
if (!success) {terminate(GetLastError()); return;}

// Check for startup params
if (argc == 2)
{
int temp = atoi(argv[1]);
if (temp < 1000)
beepDelay = DEFAULT_BEEP_DELAY;
else
beepDelay = temp;
}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 3, 5000);
if (!success) {terminate(GetLastError()); return;}

// Start the service itself
success = InitService();
if (!success) {terminate(GetLastError()); return;}

// The service is now running.
// Notify SCM of progress
success = SendStatusToSCM(SERVICE_RUNNING,
NO_ERROR, 0, 0, 0);
if (!success) {terminate(GetLastError()); return;}

// Wait for stop signal, and then terminate
WaitForSingleObject (terminateEvent, INFINITE);

terminate(0);
}

VOID main(VOID)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ SERVICE_NAME,
(LPSERVICE_MAIN_FUNCTION) ServiceMain},
{ NULL, NULL }
};
BOOL success;

// Register with the SCM
success =
StartServiceCtrlDispatcher(serviceTable);
if (!success)
ErrorHandler("In StartServiceCtrlDispatcher",
GetLastError());
}

列表2
安装NT服务的代码


file://***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code installs a service.
file://***************************************************************

// install.cpp

#include
#include

void ErrorHandler(char *s, DWORD err)
{
cout << s << endl;
cout << "Error number: " << err << endl;
ExitProcess(err);
}

void main(int argc, char *argv[])
{
SC_HANDLE newService, scm;

if (argc != 4)
{
cout << "Usage:\n";
cout << " install service_name \
service_label executable\n";
cout << " service_name is the \
name used internally by the SCM\n";
cout << " service_label is the \
name that appears in the Services applet\n";
cout << " (for multiple \
words, put them in double quotes)\n";
cout << " executable is the \
full path to the EXE\n\n";
return;
}

// open a connection to the SCM
scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (!scm) ErrorHandler("In OpenScManager",
GetLastError());

// Install the new service
newService = CreateService(
scm, argv[1], // eg "beep_srv"
argv[2], // eg "Beep Service"
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
argv[3], // eg "c:\winnt\xxx.exe"
0, 0, 0, 0, 0);
if (!newService) ErrorHandler("In CreateService",
GetLastError());
else cout << "Service installed\n";

// clean up
CloseServiceHandle(newService);
CloseServiceHandle(scm);
}

列表3
移除NT服务的代码
file://***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code removes a service from the Services applet in the
// Control Panel.
file://***************************************************************

// remove.cpp

#include
#include

void ErrorHandler(char *s, DWORD err)
{
cout << s << endl;
cout << "Error number: " << err << endl;
ExitProcess(err);
}

void main(int argc, char *argv[])
{
SC_HANDLE service, scm;
BOOL success;
SERVICE_STATUS status;

if (argc != 2)
{
cout << "Usage:\n remove service_name\n";
return;
}

// Open a connection to the SCM
scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (!scm) ErrorHandler("In OpenScManager",
GetLastError());

// Get the service's handle
service = OpenService(scm, argv[1],
SERVICE_ALL_ACCESS | DELETE);
if (!service) ErrorHandler("In OpenService",
GetLastError());

// Stop the service if necessary
success = QueryServiceStatus(service, &status);
if (!success) ErrorHandler("In QueryServiceStatus",
GetLastError());
if (status.dwCurrentState != SERVICE_STOPPED)
{
cout << "Stopping service...\n";
success = ControlService(service,
SERVICE_CONTROL_STOP, &status);
if (!success) ErrorHandler("In ControlService",
GetLastError());
}

// Remove the service
success = DeleteService(service);
if (success) cout << "Service removed\n";
else ErrorHandler("In DeleteService",
GetLastError());

// Clean up
CloseServiceHandle(service);
CloseServiceHandle(scm);
}

 
共3页。 9 7 1 2 3
文章阅读排行
周排行
月排行
欢迎订阅天极网RSS聚合资讯:http://www.yesky.com/index.xml