📄 ntservice.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1997 by Joerg Koenig and the ADG mbH, Mannheim, Germany
// All rights reserved
//
// Distribute freely, except: don't remove my name from the source or
// documentation (don't take credit for my work), mark your changes (don't
// get me blamed for your possible bugs), don't alter or remove this
// notice.
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and
// I'll try to keep a version up to date. I can be reached as follows:
// J.Koenig@adg.de (company site)
// Joerg.Koenig@rhein-neckar.de (private site)
/////////////////////////////////////////////////////////////////////////////
//
// MODIFIED BY TODD C. WILSON FOR THE ROAD RUNNER NT LOGIN SERVICE.
// HOWEVER, THESE MODIFICATIONS ARE BROADER IN SCOPE AND USAGE AND CAN BE USED
// IN OTHER PROJECTS WITH NO CHANGES.
// MODIFIED LINES FLAGGED/BRACKETED BY "//!! TCW MOD"
//
/////////////////////////////////////////////////////////////////////////////
// last revised: $Date: 11.05.98 21:09 $, $Revision: 3 $
/////////////////////////////////////////////////////////////////////////////
// Acknoledgements:
// o Thanks to Victor Vogelpoel (VictorV@Telic.nl) for his bug-fixes
// and enhancements.
// o Thanks to Todd C. Wilson (todd@mediatec.com) for the
// "service" on Win95
//
// Changes:
// 01/21/99
// o Bug fixed in "DeregisterApplicationLog()"
// thanks to Grahame Willis (grahamew@questsoftware.com.au):
//
// 04/30/98
// o Added two more switches to handle command line arguments:
// -e will force a running service to stop (corresponding
// method in this class: virtual BOOL EndService();) and
// -s will force the service to start (method:
// virtual BOOL StartupService())
//
// 02/05/98
// o Added the methods "RegisterApplicationLog()" and
// "DeregisterApplicationLog()" (both virtual). The first one will be
// called from "InstallService()" and creates some registry-entries
// for a better event-log. The second one removes these entries when
// the service will uninstall (see "RemoveService()")
// o The service now obtains the security identifier of the current user
// and uses this SID for event-logging.
// o The memory allocated by "CommandLineToArgvW()" will now release
// (UNICODE version only)
// o The service now uses a simple message catalogue for a nicer
// event logging
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <crtdbg.h>
#include <io.h> //!! TCW MOD
#include <fcntl.h> //!! TCW MOD
#include "NTService.h"
#include "NTServiceEventLogMsg.h"
#ifndef RSP_SIMPLE_SERVICE
#define RSP_SIMPLE_SERVICE 1
#endif
#ifndef RSP_UNREGISTER_SERVICE
#define RSP_UNREGISTER_SERVICE 0
#endif
BOOL CNTService :: m_bInstance = FALSE;
static CNTService * gpTheService = 0; // the one and only instance
CNTService * AfxGetService() { return gpTheService; }
static LPCTSTR gszAppRegKey = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
static LPCTSTR gszWin95ServKey=TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"); //!! TCW MOD
/////////////////////////////////////////////////////////////////////////////
// class CNTService -- construction/destruction
CNTService :: CNTService( LPCTSTR lpServiceName, LPCTSTR lpDisplayName )
: m_lpServiceName(lpServiceName)
, m_lpDisplayName(lpDisplayName ? lpDisplayName : lpServiceName)
, m_dwCheckPoint(0)
, m_dwErr(0)
, m_bDebug(FALSE)
, m_sshStatusHandle(0)
, m_dwControlsAccepted(SERVICE_ACCEPT_STOP)
, m_pUserSID(0)
, m_fConsoleReady(FALSE)
// parameters to the "CreateService()" function:
, m_dwDesiredAccess(SERVICE_ALL_ACCESS)
, m_dwServiceType(SERVICE_WIN32_OWN_PROCESS)
, m_dwStartType(SERVICE_AUTO_START)
, m_dwErrorControl(SERVICE_ERROR_NORMAL)
, m_pszLoadOrderGroup(0)
, m_dwTagID(0)
, m_pszDependencies(0)
, m_pszStartName(0)
, m_pszPassword(0)
{
_ASSERTE( ! m_bInstance );
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize=sizeof(vi); // init this.
GetVersionEx(&vi); //lint !e534
m_bWinNT = (vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
m_bInstance = TRUE;
gpTheService = this;
// SERVICE_STATUS members that rarely change
m_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_ssStatus.dwServiceSpecificExitCode = 0;
if( m_bWinNT ) {
/////////////////////////////////////////////////////////////////////////
// Providing a SID (security identifier) was contributed by Victor
// Vogelpoel (VictorV@Telic.nl).
// The code from Victor was slightly modified.
// Get security information of current user
BYTE security_identifier_buffer[ 4096 ];
DWORD dwSizeSecurityIdBuffer = sizeof( security_identifier_buffer );
PSID user_security_identifier = NULL;
TCHAR sUserName[ 256 ];
DWORD dwSizeUserName = 255;
TCHAR sDomainName[ 256 ];
DWORD dwSizeDomainName = 255;
SID_NAME_USE sidTypeSecurityId;
::ZeroMemory( sUserName, sizeof( sUserName ) );
::ZeroMemory( sDomainName, sizeof( sDomainName ) );
::ZeroMemory( security_identifier_buffer, dwSizeSecurityIdBuffer );
::GetUserName( sUserName, &dwSizeUserName );
if( ::LookupAccountName(
0,
sUserName,
&security_identifier_buffer,
&dwSizeSecurityIdBuffer,
sDomainName,
&dwSizeDomainName,
&sidTypeSecurityId
)) {
if( ::IsValidSid( PSID(security_identifier_buffer) ) ) {
DWORD dwSidLen = ::GetLengthSid(PSID(security_identifier_buffer));
m_pUserSID = PSID(new BYTE [dwSidLen]);
::CopySid(dwSidLen, m_pUserSID, security_identifier_buffer);
_ASSERTE(::EqualSid(m_pUserSID, security_identifier_buffer));
}
}
}
/////////////////////////////////////////////////////////////////////////
}
CNTService :: ~CNTService() {
_ASSERTE( m_bInstance );
delete [] LPBYTE(m_pUserSID);
m_bInstance = FALSE;
gpTheService = 0;
}
/////////////////////////////////////////////////////////////////////////////
// class CNTService -- overridables
#define NEXT_ARG ((((*Argv)[2])==TEXT('\0'))?(--Argc,*++Argv):(*Argv)+2)
BOOL CNTService :: RegisterService( int argc, char ** argv ) {
BOOL (CNTService::* fnc)() = &CNTService::StartDispatcher;
DWORD Argc;
LPTSTR * Argv;
#ifdef UNICODE
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc );
#else
Argc = (DWORD) argc;
Argv = argv;
#endif
while( ++Argv, --Argc ) {
if( Argv[0][0] == TEXT('-') ) {
switch( Argv[0][1] ) {
case TEXT('i'): // install the service
fnc = &CNTService::InstallService;
if(Argv[1]) strcpy(m_szDependencies,Argv[1]);
break;
case TEXT('l'): // login-account (only useful with -i)
m_pszStartName = NEXT_ARG;
break;
case TEXT('p'): // password (only useful with -i)
m_pszPassword = NEXT_ARG;
break;
case TEXT('u'): // uninstall the service
fnc = &CNTService::RemoveService;
break;
case TEXT('s'): // start the service
fnc = &CNTService::StartupService;
break;
case TEXT('e'): // end the service
fnc = &CNTService::EndService;
break;
case TEXT('d'): // debug the service
case TEXT('f'): //!! TCW MOD faceless non-service (Win95) mode
#ifdef UNICODE
::GlobalFree(HGLOBAL)Argv);
#endif
m_bDebug = TRUE;
// pass original parameters to DebugService()
return DebugService(argc, argv,(Argv[0][1]==TEXT('f'))); //!! TCW MOD faceless non-service (Win95) mode
}
}
}
#ifdef UNICODE
::GlobalFree(HGLOBAL)Argv);
#endif
//!! TCW MOD START - if Win95, run as faceless app.
if( fnc == &CNTService::StartDispatcher && OsIsWin95() ) {
// act as if -f was passed anyways.
m_bDebug = TRUE;
return DebugService(argc, argv, TRUE);
}
//!! TCW MOD END - if Win95, run as faceless app.
return (this->*fnc)();
}
BOOL CNTService :: StartDispatcher() {
// Default implementation creates a single threaded service.
// Override this method and provide more table entries for
// a multithreaded service (one entry for each thread).
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{ LPTSTR(m_lpServiceName), (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ 0, 0 }
};
BOOL bRet = StartServiceCtrlDispatcher(dispatchTable);
if( ! bRet ) {
TCHAR szBuf[256];
AddToMessageLog(GetLastErrorText(szBuf,255));
}
return bRet;
}
BOOL CNTService :: InstallService() {
TCHAR szPath[1024];
SetupConsole(); //!! TCW MOD - have to show the console here for the
// diagnostic or error reason: orignal class assumed
// that we were using _main for entry (a console app).
// This particular usage is a Windows app (no console),
// so we need to create it. Using SetupConsole with _main
// is ok - does nothing, since you only get one console.
if( GetModuleFileName( 0, szPath, 1023 ) == 0 ) {
TCHAR szErr[256];
_tprintf(TEXT("Unable to install %s - %s\n"), m_lpDisplayName, GetLastErrorText(szErr, 256));
return FALSE;
}
BOOL bRet = FALSE;
if( OsIsWin95() ) { //!! TCW MOD - code added to install as Win95 service
// Create a key for that application and insert values for
// "EventMessageFile" and "TypesSupported"
HKEY hKey = 0;
LONG lRet = ERROR_SUCCESS;
if( ::RegCreateKey(HKEY_LOCAL_MACHINE, gszWin95ServKey , &hKey) == ERROR_SUCCESS ) {
lRet = ::RegSetValueEx(
hKey, // handle of key to set value for
m_lpServiceName, // address of value to set (NAME OF SERVICE)
0, // reserved
REG_EXPAND_SZ, // flag for value type
(CONST BYTE*)szPath,// address of value data
_tcslen(szPath) + 1 // size of value data
);
::RegCloseKey(hKey);
bRet=TRUE;
}
} else {
// Real NT services go here.
SC_HANDLE schSCManager = OpenSCManager(
0, // machine (NULL == local)
0, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if( schSCManager ) {
SC_HANDLE schService = CreateService(
schSCManager,
m_lpServiceName,
m_lpDisplayName,
m_dwDesiredAccess,
m_dwServiceType,
m_dwStartType,
m_dwErrorControl,
szPath,
m_pszLoadOrderGroup,
((m_dwServiceType == SERVICE_KERNEL_DRIVER ||
m_dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) &&
(m_dwStartType == SERVICE_BOOT_START ||
m_dwStartType == SERVICE_SYSTEM_START)) ?
&m_dwTagID : 0,
m_pszDependencies,
m_pszStartName,
m_pszPassword
);
if( schService ) {
_tprintf(TEXT("%s installed.\n"), m_lpDisplayName );
CloseServiceHandle(schService);
bRet = TRUE;
} else {
TCHAR szErr[256];
_tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
}
CloseServiceHandle(schSCManager);
} else {
TCHAR szErr[256];
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -