최종완료보고 버전
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
// DebugAssist.h: interface for the DebugAssist class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32) && !defined(_DEBUG)
|
||||
#ifndef DEBUGASSIST_H__
|
||||
#define DEBUGASSIST_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DbgHelp.h> // in Platform SDK
|
||||
//#include <c:\Program Files\Microsoft SDKs\Windows\v5.0\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\Include\DbgHelp.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
TCHAR g_szDbgModulePathName[2048] = {0,};
|
||||
TCHAR g_szDumpPathName[2048] = {0,};
|
||||
|
||||
LONG TopExceptionFilter(LPEXCEPTION_POINTERS pException)
|
||||
{
|
||||
HMODULE hDll = LoadLibrary(g_szDbgModulePathName);
|
||||
if (hDll == NULL)
|
||||
{
|
||||
OutputDebugString(TEXT("tps, ERROR, Can't found DbgHelp.dll file.\n"));
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
||||
exceptionInfo.ThreadId = GetCurrentThreadId();
|
||||
exceptionInfo.ExceptionPointers = pException;
|
||||
exceptionInfo.ClientPointers = NULL;
|
||||
|
||||
BOOL (WINAPI * fnWriteDump)(HANDLE, DWORD, ...);
|
||||
fnWriteDump = (BOOL (WINAPI *)(HANDLE, DWORD, ...))GetProcAddress(hDll, "MiniDumpWriteDump");
|
||||
if (fnWriteDump == NULL)
|
||||
{
|
||||
OutputDebugString(TEXT("tps, ERROR, Can't found MiniDumpWriteDump interface.\n"));
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFile(g_szDumpPathName, GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
fnWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||
MiniDumpNormal, &exceptionInfo, NULL, NULL);
|
||||
|
||||
FreeLibrary(hDll);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void InitialDumpWriting(LPCTSTR pszDir = NULL, LPCTSTR pszPrefix = NULL)
|
||||
{
|
||||
TCHAR szPostFix[32];
|
||||
|
||||
SYSTEMTIME systemTime;
|
||||
GetLocalTime(&systemTime);
|
||||
|
||||
_stprintf(szPostFix, TEXT("_%.4d%.2d%.2d%.2d%.2d%.2d.dmp"), systemTime.wYear,
|
||||
systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
||||
|
||||
if (pszDir && pszPrefix)
|
||||
{
|
||||
// pszDir ex) "C:\\Temp\\"
|
||||
_tcscpy(g_szDbgModulePathName, pszDir);
|
||||
_tcscat(g_szDbgModulePathName, TEXT("dbghelp.dll"));
|
||||
|
||||
_tcscpy(g_szDumpPathName, pszDir);
|
||||
_tcscat(g_szDumpPathName, pszPrefix);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
else
|
||||
{
|
||||
char szModuleFileName[2048];
|
||||
GetModuleFileName(NULL, szModuleFileName, sizeof(szModuleFileName));
|
||||
|
||||
char szDrive[_MAX_DRIVE], szDir[1024], szFileName[1024], szExt[1024];
|
||||
_splitpath_s(szModuleFileName, szDrive, _MAX_DRIVE, szDir, 1024, szFileName, 1024, szExt, 1024);
|
||||
|
||||
if (pszDir)
|
||||
{
|
||||
_tcscpy(g_szDbgModulePathName, pszDir);
|
||||
_tcscpy(g_szDumpPathName, pszDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcscpy(g_szDbgModulePathName, szDrive);
|
||||
_tcscat(g_szDbgModulePathName, szDir);
|
||||
_tcscpy(g_szDumpPathName, g_szDbgModulePathName);
|
||||
}
|
||||
|
||||
_tcscat(g_szDbgModulePathName, TEXT("dbghelp.dll"));
|
||||
|
||||
if (pszPrefix)
|
||||
{
|
||||
_tcscat(g_szDumpPathName, pszPrefix);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcscat(g_szDumpPathName, szFileName);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
}
|
||||
|
||||
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopExceptionFilter);
|
||||
}
|
||||
|
||||
#endif // DEBUGASSIST_H__
|
||||
#endif // defined(_WIN32) && !defined(_DEBUG)
|
||||
@@ -0,0 +1,645 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
|
||||
|
||||
MODULE: service.c
|
||||
|
||||
PURPOSE: Implements functions required by all Windows NT services
|
||||
|
||||
FUNCTIONS:
|
||||
main(int argc, char **argv);
|
||||
service_ctrl(DWORD dwCtrlCode);
|
||||
service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||
CmdInstallService();
|
||||
CmdRemoveService();
|
||||
CmdDebugService(int argc, char **argv);
|
||||
ControlHandler ( DWORD dwCtrlType );
|
||||
GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
#include <tchar.h>
|
||||
#include "WinService.h"
|
||||
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
|
||||
// internal variables
|
||||
SERVICE_STATUS g_ssStatus; // current status of the service
|
||||
SERVICE_STATUS_HANDLE g_sshStatusHandle;
|
||||
DWORD g_dwWinServiceErr = 0;
|
||||
TCHAR g_szWinServiceErr[256];
|
||||
BOOL g_bDebugExecuted = FALSE;
|
||||
|
||||
// internal function prototypes
|
||||
VOID WINAPI service_ctrl(DWORD dwCtrlCode);
|
||||
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||
VOID CmdInstallService();
|
||||
VOID CmdRemoveService();
|
||||
VOID CmdDebugService(int argc, char **argv);
|
||||
BOOL WINAPI ControlHandler(DWORD dwCtrlType);
|
||||
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: main
|
||||
//
|
||||
// PURPOSE: entrypoint for service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// main() either performs the command line task, or
|
||||
// call StartServiceCtrlDispatcher to register the
|
||||
// main service thread. When the this call returns,
|
||||
// the service has stopped, so exit.
|
||||
//
|
||||
#if 0 // original code
|
||||
void __cdecl main(int argc, char **argv)
|
||||
#else
|
||||
void WinServiceMain(int argc, char **argv)
|
||||
#endif
|
||||
{
|
||||
SERVICE_TABLE_ENTRY dispatchTable[] =
|
||||
{
|
||||
{ TEXT((char *)g_szServiceName), (LPSERVICE_MAIN_FUNCTION)service_main}, { NULL, NULL}
|
||||
};
|
||||
|
||||
if ((argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')))
|
||||
{
|
||||
if (_stricmp("install", argv[1] + 1) == 0)
|
||||
{
|
||||
CmdInstallService();
|
||||
}
|
||||
else if (_stricmp("remove", argv[1] + 1) == 0)
|
||||
{
|
||||
CmdRemoveService();
|
||||
}
|
||||
else if (_stricmp("debug", argv[1] + 1) == 0)
|
||||
{
|
||||
g_bDebugExecuted = TRUE;
|
||||
CmdDebugService(argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto dispatch;
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// g_bDebugExecuted = TRUE;
|
||||
// CmdDebugService(argc, argv);
|
||||
//}
|
||||
|
||||
// if it doesn't match any of the above parameters
|
||||
// the service control manager may be starting the service
|
||||
// so we must call StartServiceCtrlDispatcher
|
||||
dispatch:
|
||||
const char * pszAppName = strrchr(argv[0], '\\');
|
||||
if (pszAppName)
|
||||
{
|
||||
pszAppName++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszAppName = strrchr(argv[0], '/');
|
||||
if (pszAppName)
|
||||
pszAppName++;
|
||||
else
|
||||
pszAppName = argv[0];
|
||||
}
|
||||
|
||||
// this is just to be friendly
|
||||
printf("%s -install to install the service\n", pszAppName);
|
||||
printf("%s -remove to remove the service\n", pszAppName);
|
||||
//printf("%s -debug <params> to run as a console app for debugging\n", pszAppName);
|
||||
printf("\nStartServiceCtrlDispatcher being called.\n");
|
||||
printf("This may take several seconds. Please wait.\n");
|
||||
|
||||
#if 1 // original code
|
||||
if (!StartServiceCtrlDispatcher(dispatchTable))
|
||||
AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: service_main
|
||||
//
|
||||
// PURPOSE: To perform actual initialization of the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwArgc - number of command line arguments
|
||||
// lpszArgv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// This routine performs the service initialization and then calls
|
||||
// the user defined ServiceStart() routine to perform majority
|
||||
// of the work.
|
||||
//
|
||||
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||
{
|
||||
// register our service control handler:
|
||||
//
|
||||
g_sshStatusHandle = RegisterServiceCtrlHandler(TEXT(g_szServiceName), service_ctrl);
|
||||
|
||||
if (!g_sshStatusHandle)
|
||||
goto cleanup;
|
||||
|
||||
// SERVICE_STATUS members that don't change in example
|
||||
//
|
||||
g_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_ssStatus.dwServiceSpecificExitCode = 0;
|
||||
|
||||
|
||||
// report the status to the service control manager.
|
||||
//
|
||||
if (!ReportStatusToSCMgr(
|
||||
SERVICE_START_PENDING, // service state
|
||||
NO_ERROR, // exit code
|
||||
3000)) // wait hint
|
||||
goto cleanup;
|
||||
|
||||
|
||||
ServiceStart(dwArgc, lpszArgv, FALSE);
|
||||
|
||||
cleanup:
|
||||
|
||||
// try to report the stopped status to the service control manager.
|
||||
//
|
||||
if (g_sshStatusHandle)
|
||||
ReportStatusToSCMgr(SERVICE_STOPPED, g_dwWinServiceErr, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: service_ctrl
|
||||
//
|
||||
// PURPOSE: This function is called by the SCM whenever
|
||||
// ControlService() is called on this service.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCtrlCode - type of control requested
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
|
||||
{
|
||||
// Handle the requested control code.
|
||||
//
|
||||
switch (dwCtrlCode)
|
||||
{
|
||||
// Stop the service.
|
||||
//
|
||||
// SERVICE_STOP_PENDING should be reported before
|
||||
// setting the Stop Event - hServerStopEvent - in
|
||||
// ServiceStop(). This avoids a race condition
|
||||
// which may result in a 1053 - The Service did not respond...
|
||||
// error.
|
||||
case SERVICE_CONTROL_STOP:
|
||||
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||
ServiceStop();
|
||||
return;
|
||||
|
||||
// Update the service status.
|
||||
//
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
break;
|
||||
|
||||
// invalid control code
|
||||
//
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ReportStatusToSCMgr(g_ssStatus.dwCurrentState, NO_ERROR, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: ReportStatusToSCMgr()
|
||||
//
|
||||
// PURPOSE: Sets the current status of the service and
|
||||
// reports it to the Service Control Manager
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCurrentState - the state of the service
|
||||
// dwWin32ExitCode - error code to report
|
||||
// dwWaitHint - worst case estimate to next checkpoint
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// TRUE - success
|
||||
// FALSE - failure
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
BOOL fResult = TRUE;
|
||||
|
||||
if (!g_bDebugExecuted) // when debugging we don't report to the SCM
|
||||
{
|
||||
if (dwCurrentState == SERVICE_START_PENDING)
|
||||
g_ssStatus.dwControlsAccepted = 0;
|
||||
else
|
||||
g_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
|
||||
g_ssStatus.dwCurrentState = dwCurrentState;
|
||||
g_ssStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||
g_ssStatus.dwWaitHint = dwWaitHint;
|
||||
|
||||
if ((dwCurrentState == SERVICE_RUNNING) ||
|
||||
(dwCurrentState == SERVICE_STOPPED))
|
||||
g_ssStatus.dwCheckPoint = 0;
|
||||
else
|
||||
g_ssStatus.dwCheckPoint = dwCheckPoint++;
|
||||
|
||||
|
||||
// Report the status of the service to the service control manager.
|
||||
//
|
||||
if (!(fResult = SetServiceStatus(g_sshStatusHandle, &g_ssStatus)))
|
||||
{
|
||||
AddToMessageLog(TEXT("SetServiceStatus"));
|
||||
}
|
||||
}
|
||||
return fResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||
//
|
||||
// PURPOSE: Allows any thread to log an error message
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszMsg - text for message
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
VOID AddToMessageLog(LPTSTR lpszMsg)
|
||||
{
|
||||
//TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
|
||||
TCHAR * pszMsg = (TCHAR *)malloc(((strlen(g_szServiceName) / sizeof(TCHAR)) + 100) * sizeof(TCHAR));
|
||||
HANDLE hEventSource;
|
||||
LPTSTR lpszStrings[2];
|
||||
|
||||
if (!g_bDebugExecuted)
|
||||
{
|
||||
g_dwWinServiceErr = GetLastError();
|
||||
|
||||
// Use event logging to log the error.
|
||||
//
|
||||
hEventSource = RegisterEventSource(NULL, TEXT(g_szServiceName));
|
||||
|
||||
_stprintf(pszMsg, TEXT("%s error: %d"), TEXT(g_szServiceName), g_dwWinServiceErr);
|
||||
lpszStrings[0] = pszMsg;
|
||||
lpszStrings[1] = lpszMsg;
|
||||
|
||||
if (hEventSource != NULL)
|
||||
{
|
||||
ReportEvent(hEventSource, // handle of event source
|
||||
EVENTLOG_ERROR_TYPE, // event type
|
||||
0, // event category
|
||||
0, // event ID
|
||||
NULL, // current user's SID
|
||||
2, // strings in lpszStrings
|
||||
0, // no bytes of raw data
|
||||
(LPCTSTR *)lpszStrings, // array of error strings
|
||||
NULL); // no raw data
|
||||
DeregisterEventSource(hEventSource);
|
||||
}
|
||||
}
|
||||
|
||||
free(pszMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following code handles service installation and removal
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdInstallService()
|
||||
//
|
||||
// PURPOSE: Installs the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// none
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdInstallService()
|
||||
{
|
||||
SC_HANDLE schService;
|
||||
SC_HANDLE schSCManager;
|
||||
|
||||
TCHAR szPath[2048];
|
||||
|
||||
if (GetModuleFileName(NULL, szPath, 2048) == 0)
|
||||
{
|
||||
_tprintf(TEXT("Unable to install %s - %s\n"), TEXT(g_szServiceDisplayName), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
return;
|
||||
}
|
||||
|
||||
schSCManager = OpenSCManager(
|
||||
NULL, // machine (NULL == local)
|
||||
NULL, // database (NULL == default)
|
||||
SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required
|
||||
);
|
||||
if (schSCManager)
|
||||
{
|
||||
schService = CreateService(
|
||||
schSCManager, // SCManager database
|
||||
TEXT(g_szServiceName), // name of service
|
||||
TEXT(g_szServiceDisplayName), // name to display
|
||||
SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG | SERVICE_START, // desired access
|
||||
SERVICE_WIN32_OWN_PROCESS, // service type
|
||||
//SERVICE_DEMAND_START, // start type
|
||||
SERVICE_AUTO_START,
|
||||
SERVICE_ERROR_NORMAL, // error control type
|
||||
szPath, // service's binary
|
||||
NULL, // no load ordering group
|
||||
NULL, // no tag identifier
|
||||
TEXT(g_szDependencies), // dependencies
|
||||
NULL, // LocalSystem account
|
||||
NULL); // no password
|
||||
|
||||
if (g_szServiceDesc && g_szServiceDesc[0] != TEXT('\0'))
|
||||
{
|
||||
SERVICE_DESCRIPTION serviceDesc;
|
||||
serviceDesc.lpDescription = (LPSTR)g_szServiceDesc;
|
||||
|
||||
if (ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &serviceDesc) == 0)
|
||||
_tprintf(TEXT("ChangeServiceConfig2 failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
SC_ACTION scAction[1];
|
||||
scAction[0].Type = SC_ACTION_RESTART;
|
||||
scAction[0].Delay = 10000;
|
||||
|
||||
SERVICE_FAILURE_ACTIONS serviceFailAction;
|
||||
serviceFailAction.lpsaActions = (SC_ACTION *)scAction;
|
||||
serviceFailAction.cActions = 1;
|
||||
serviceFailAction.dwResetPeriod = 600;
|
||||
serviceFailAction.lpRebootMsg = TEXT("");
|
||||
serviceFailAction.lpCommand = TEXT("");
|
||||
|
||||
if (ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailAction) == 0)
|
||||
_tprintf(TEXT("ChangeServiceConfig2 failed 2 - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
if (schService)
|
||||
{
|
||||
_tprintf(TEXT("%s installed.\n"), TEXT(g_szServiceDisplayName));
|
||||
CloseServiceHandle(schService);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
CloseServiceHandle(schSCManager);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdRemoveService()
|
||||
//
|
||||
// PURPOSE: Stops and removes the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// none
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdRemoveService()
|
||||
{
|
||||
SC_HANDLE schService;
|
||||
SC_HANDLE schSCManager;
|
||||
|
||||
schSCManager = OpenSCManager(
|
||||
NULL, // machine (NULL == local)
|
||||
NULL, // database (NULL == default)
|
||||
SC_MANAGER_CONNECT // access required
|
||||
);
|
||||
if (schSCManager)
|
||||
{
|
||||
schService = OpenService(schSCManager, TEXT(g_szServiceName), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||
|
||||
if (schService)
|
||||
{
|
||||
// try to stop the service
|
||||
if (ControlService(schService, SERVICE_CONTROL_STOP, &g_ssStatus))
|
||||
{
|
||||
_tprintf(TEXT("Stopping %s."), TEXT(g_szServiceDisplayName));
|
||||
Sleep(1000);
|
||||
|
||||
while (QueryServiceStatus(schService, &g_ssStatus))
|
||||
{
|
||||
if (g_ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
|
||||
{
|
||||
_tprintf(TEXT("."));
|
||||
Sleep(1000);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_ssStatus.dwCurrentState == SERVICE_STOPPED)
|
||||
_tprintf(TEXT("\n%s stopped.\n"), TEXT(g_szServiceDisplayName));
|
||||
else
|
||||
_tprintf(TEXT("\n%s failed to stop.\n"), TEXT(g_szServiceDisplayName));
|
||||
|
||||
}
|
||||
|
||||
// now remove the service
|
||||
if (DeleteService(schService))
|
||||
_tprintf(TEXT("%s removed.\n"), TEXT(g_szServiceDisplayName));
|
||||
else
|
||||
_tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
|
||||
CloseServiceHandle(schService);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
CloseServiceHandle(schSCManager);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following code is for running the service as a console app
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdDebugService(int argc, char ** argv)
|
||||
//
|
||||
// PURPOSE: Runs the service as a console application
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdDebugService(int argc, char ** argv)
|
||||
{
|
||||
DWORD dwArgc;
|
||||
LPTSTR *lpszArgv;
|
||||
|
||||
#ifdef UNICODE
|
||||
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc));
|
||||
if (NULL == lpszArgv)
|
||||
{
|
||||
// CommandLineToArvW failed!!
|
||||
_tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
dwArgc = (DWORD) argc;
|
||||
lpszArgv = argv;
|
||||
#endif
|
||||
|
||||
_tprintf(TEXT("Debugging %s.\n"), TEXT(g_szServiceDisplayName));
|
||||
|
||||
SetConsoleCtrlHandler(ControlHandler, TRUE);
|
||||
|
||||
ServiceStart(dwArgc, lpszArgv, TRUE);
|
||||
|
||||
#ifdef UNICODE
|
||||
// Must free memory allocated for arguments
|
||||
GlobalFree(lpszArgv);
|
||||
#endif // UNICODE
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: ControlHandler ( DWORD dwCtrlType )
|
||||
//
|
||||
// PURPOSE: Handled console control events
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCtrlType - type of control event
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// True - handled
|
||||
// False - unhandled
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
|
||||
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
|
||||
_tprintf(TEXT("Stopping %s.\n"), TEXT(g_szServiceDisplayName));
|
||||
ServiceStop();
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: GetLastErrorText
|
||||
//
|
||||
// PURPOSE: copies error message text to string
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszBuf - destination buffer
|
||||
// dwSize - size of buffer
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// destination buffer
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
|
||||
{
|
||||
DWORD dwRet;
|
||||
LPTSTR lpszTemp = NULL;
|
||||
|
||||
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
LANG_NEUTRAL,
|
||||
(LPTSTR)&lpszTemp,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
// supplied buffer is not long enough
|
||||
if (!dwRet || ((long)dwSize < (long)dwRet + 14))
|
||||
lpszBuf[0] = TEXT('\0');
|
||||
else
|
||||
{
|
||||
lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
|
||||
_stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError());
|
||||
}
|
||||
|
||||
if (lpszTemp)
|
||||
LocalFree((HLOCAL) lpszTemp);
|
||||
|
||||
return lpszBuf;
|
||||
}
|
||||
|
||||
|
||||
#endif _WIN32
|
||||
@@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
|
||||
|
||||
MODULE: service.h
|
||||
|
||||
Comments: The use of this header file and the accompanying service.c
|
||||
file simplifies the process of writting a service. You as a developer
|
||||
simply need to follow the TODO's outlined in this header file, and
|
||||
implement the ServiceStart() and ServiceStop() functions.
|
||||
|
||||
There is no need to modify the code in service.c. Just add service.c
|
||||
to your project and link with the following libraries...
|
||||
|
||||
libcmt.lib kernel32.lib advapi.lib shell32.lib
|
||||
|
||||
This code also supports unicode. Be sure to compile both service.c and
|
||||
and code #include "service.h" with the same Unicode setting.
|
||||
|
||||
Upon completion, your code will have the following command line interface
|
||||
|
||||
<service exe> -? to display this list
|
||||
<service exe> -install to install the service
|
||||
<service exe> -remove to remove the service
|
||||
<service exe> -debug <params> to run as a console app for debugging
|
||||
|
||||
Note: This code also implements Ctrl+C and Ctrl+Break handlers
|
||||
when using the debug option. These console events cause
|
||||
your ServiceStop routine to be called
|
||||
|
||||
Also, this code only handles the OWN_SERVICE service type
|
||||
running in the LOCAL_SYSTEM security context.
|
||||
|
||||
To control your service ( start, stop, etc ) you may use the
|
||||
Services control panel applet or the NET.EXE program.
|
||||
|
||||
To aid in writing/debugging service, the
|
||||
SDK contains a utility (MSTOOLS\BIN\SC.EXE) that
|
||||
can be used to control, configure, or obtain service status.
|
||||
SC displays complete status for any service/driver
|
||||
in the service database, and allows any of the configuration
|
||||
parameters to be easily changed at the command line.
|
||||
For more information on SC.EXE, type SC at the command line.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN_SERVICE__H_
|
||||
#define WIN_SERVICE__H_
|
||||
|
||||
|
||||
extern const char * g_szServiceName; // internal name of the service
|
||||
extern const char * g_szServiceDisplayName; // displayed name of the service
|
||||
extern const char * g_szDependencies; // list of service dependencies - "dep1\0dep2\0\0"
|
||||
extern const char * g_szServiceDesc;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// todo: ServiceStart()must be defined by in your code.
|
||||
//// The service should use ReportStatusToSCMgr to indicate
|
||||
//// progress. This routine must also be used by StartService()
|
||||
//// to report to the SCM when the service is running.
|
||||
////
|
||||
//// If a ServiceStop procedure is going to take longer than
|
||||
//// 3 seconds to execute, it should spawn a thread to
|
||||
//// execute the stop code, and return. Otherwise, the
|
||||
//// ServiceControlManager will believe that the service has
|
||||
//// stopped responding
|
||||
////
|
||||
VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv, BOOL bConsoleMode);
|
||||
VOID ServiceStop();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// The following are procedures which
|
||||
//// may be useful to call within the above procedures,
|
||||
//// but require no implementation by the user.
|
||||
//// They are implemented in service.c
|
||||
|
||||
//
|
||||
// FUNCTION: ReportStatusToSCMgr()
|
||||
//
|
||||
// PURPOSE: Sets the current status of the service and
|
||||
// reports it to the Service Control Manager
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCurrentState - the state of the service
|
||||
// dwWin32ExitCode - error code to report
|
||||
// dwWaitHint - worst case estimate to next checkpoint
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// TRUE - success
|
||||
// FALSE - failure
|
||||
//
|
||||
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||
//
|
||||
// PURPOSE: Allows any thread to log an error message
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszMsg - text for message
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
void AddToMessageLog(LPTSTR lpszMsg);
|
||||
|
||||
|
||||
void WinServiceMain(int argc, char **argv);
|
||||
|
||||
|
||||
#endif // WIN_SERVICE__H_
|
||||
#endif _WIN32
|
||||
Reference in New Issue
Block a user