📄 ntservice.cpp
字号:
BOOL WINAPI CNTService :: ControlHandler(DWORD dwCtrlType) {
_ASSERTE(gpTheService != 0);
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"), gpTheService->m_lpDisplayName);
gpTheService->Stop();
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// class CNTService -- helpers
//!! TCW MOD - added DWORD dwErrExit for error exit value. Defaults to zero
BOOL CNTService :: ReportStatus(
DWORD dwCurrentState,
DWORD dwWaitHint,
DWORD dwErrExit ) {
BOOL fResult = TRUE;
if( !m_bDebug ) { // when debugging we don't report to the SCM
if( dwCurrentState == SERVICE_START_PENDING)
m_ssStatus.dwControlsAccepted = 0;
else
m_ssStatus.dwControlsAccepted = m_dwControlsAccepted;
m_ssStatus.dwCurrentState = dwCurrentState;
m_ssStatus.dwWin32ExitCode = NO_ERROR;
m_ssStatus.dwWaitHint = dwWaitHint;
//!! TCW MOD START - added code to support error exiting
m_ssStatus.dwServiceSpecificExitCode = dwErrExit;
if (dwErrExit!=0)
m_ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
//!! TCW MOD END - added code to support error exiting
if( dwCurrentState == SERVICE_RUNNING ||
dwCurrentState == SERVICE_STOPPED )
m_ssStatus.dwCheckPoint = 0;
else
m_ssStatus.dwCheckPoint = ++m_dwCheckPoint;
// Report the status of the service to the service control manager.
if (!(fResult = SetServiceStatus( m_sshStatusHandle, &m_ssStatus))) {
AddToMessageLog(TEXT("SetServiceStatus() failed"));
}
}
return fResult;
}
void CNTService :: AddToMessageLog(LPTSTR lpszMsg, WORD wEventType, DWORD dwEventID) {
m_dwErr = GetLastError();
// use default message-IDs
if( dwEventID == DWORD(-1) ) {
switch( wEventType ) {
case EVENTLOG_ERROR_TYPE:
dwEventID = MSG_ERROR_1;
break;
case EVENTLOG_WARNING_TYPE:
dwEventID = MSG_WARNING_1;
break;
case EVENTLOG_INFORMATION_TYPE:
dwEventID = MSG_INFO_1;
break;
case EVENTLOG_AUDIT_SUCCESS:
dwEventID = MSG_INFO_1;
break;
case EVENTLOG_AUDIT_FAILURE:
dwEventID = MSG_INFO_1;
break;
default:
dwEventID = MSG_INFO_1;
break;
}
}
// Use event logging to log the error.
HANDLE hEventSource = RegisterEventSource(0, m_lpServiceName);
if( hEventSource != 0 ) {
LPCTSTR lpszMessage = lpszMsg;
ReportEvent(
hEventSource, // handle of event source
wEventType, // event type
0, // event category
dwEventID, // event ID
m_pUserSID, // current user's SID
1, // strings in lpszStrings
0, // no bytes of raw data
&lpszMessage, // array of error strings
0 // no raw data
);
::DeregisterEventSource(hEventSource);
}
}
LPTSTR CNTService :: GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) {
LPTSTR lpszTemp = 0;
DWORD dwRet = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
0,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&lpszTemp,
0,
0
);
if( !dwRet || (dwSize < dwRet+14) )
lpszBuf[0] = TEXT('\0');
else {
lpszTemp[_tcsclen(lpszTemp)-2] = TEXT('\0'); //remove cr/nl characters
_tcscpy(lpszBuf, lpszTemp);
}
if( lpszTemp )
LocalFree(HLOCAL(lpszTemp));
return lpszBuf;
}
/////////////////////////////////////////////////////////////////////////////
// class CNTService -- implementation
void CNTService :: RegisterApplicationLog( LPCTSTR lpszFileName, DWORD dwTypes ) {
TCHAR szKey[256];
_tcscpy(szKey, gszAppRegKey);
_tcscat(szKey, m_lpServiceName);
HKEY hKey = 0;
LONG lRet = ERROR_SUCCESS;
// Create a key for that application and insert values for
// "EventMessageFile" and "TypesSupported"
if( ::RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) == ERROR_SUCCESS ) {
lRet = ::RegSetValueEx(
hKey, // handle of key to set value for
TEXT("EventMessageFile"), // address of value to set
0, // reserved
REG_EXPAND_SZ, // flag for value type
(CONST BYTE*)lpszFileName, // address of value data
_tcslen(lpszFileName) + 1 // size of value data
);
// Set the supported types flags.
lRet = ::RegSetValueEx(
hKey, // handle of key to set value for
TEXT("TypesSupported"), // address of value to set
0, // reserved
REG_DWORD, // flag for value type
(CONST BYTE*)&dwTypes, // address of value data
sizeof(DWORD) // size of value data
);
::RegCloseKey(hKey);
}
// Add the service to the "Sources" value
lRet = ::RegOpenKeyEx(
HKEY_LOCAL_MACHINE, // handle of open key
gszAppRegKey, // address of name of subkey to open
0, // reserved
KEY_ALL_ACCESS, // security access mask
&hKey // address of handle of open key
);
if( lRet == ERROR_SUCCESS ) {
DWORD dwSize;
// retrieve the size of the needed value
lRet = ::RegQueryValueEx(
hKey, // handle of key to query
TEXT("Sources"),// address of name of value to query
0, // reserved
0, // address of buffer for value type
0, // address of data buffer
&dwSize // address of data buffer size
);
if( lRet == ERROR_SUCCESS ) {
DWORD dwType;
DWORD dwNewSize = dwSize+_tcslen(m_lpServiceName)+1;
LPBYTE Buffer = LPBYTE(::GlobalAlloc(GPTR, dwNewSize));
lRet = ::RegQueryValueEx(
hKey, // handle of key to query
TEXT("Sources"),// address of name of value to query
0, // reserved
&dwType, // address of buffer for value type
Buffer, // address of data buffer
&dwSize // address of data buffer size
);
if( lRet == ERROR_SUCCESS ) {
_ASSERTE(dwType == REG_MULTI_SZ);
// check whether this service is already a known source
register LPTSTR p = LPTSTR(Buffer);
for(; *p; p += _tcslen(p)+1 ) {
if( _tcscmp(p, m_lpServiceName) == 0 )
break;
}
if( ! * p ) {
// We're standing at the end of the stringarray
// and the service does still not exist in the "Sources".
// Now insert it at this point.
// Note that we have already enough memory allocated
// (see GlobalAlloc() above). We also don't need to append
// an additional '\0'. This is done in GlobalAlloc() above
// too.
_tcscpy(p, m_lpServiceName);
// OK - now store the modified value back into the
// registry.
lRet = ::RegSetValueEx(
hKey, // handle of key to set value for
TEXT("Sources"),// address of value to set
0, // reserved
dwType, // flag for value type
Buffer, // address of value data
dwNewSize // size of value data
);
}
}
::GlobalFree(HGLOBAL(Buffer));
}
::RegCloseKey(hKey);
}
}
void CNTService :: DeregisterApplicationLog() {
TCHAR szKey[256];
_tcscpy(szKey, gszAppRegKey);
_tcscat(szKey, m_lpServiceName);
HKEY hKey = 0;
LONG lRet = ERROR_SUCCESS;
lRet = ::RegDeleteKey(HKEY_LOCAL_MACHINE, szKey);
// now we have to delete the application from the "Sources" value too.
lRet = ::RegOpenKeyEx(
HKEY_LOCAL_MACHINE, // handle of open key
gszAppRegKey, // address of name of subkey to open
0, // reserved
KEY_ALL_ACCESS, // security access mask
&hKey // address of handle of open key
);
if( lRet == ERROR_SUCCESS ) {
DWORD dwSize;
// retrieve the size of the needed value
lRet = ::RegQueryValueEx(
hKey, // handle of key to query
TEXT("Sources"),// address of name of value to query
0, // reserved
0, // address of buffer for value type
0, // address of data buffer
&dwSize // address of data buffer size
);
if( lRet == ERROR_SUCCESS ) {
DWORD dwType;
LPBYTE Buffer = LPBYTE(::GlobalAlloc(GPTR, dwSize));
LPBYTE NewBuffer = LPBYTE(::GlobalAlloc(GPTR, dwSize));
lRet = ::RegQueryValueEx(
hKey, // handle of key to query
TEXT("Sources"),// address of name of value to query
0, // reserved
&dwType, // address of buffer for value type
Buffer, // address of data buffer
&dwSize // address of data buffer size
);
if( lRet == ERROR_SUCCESS ) {
_ASSERTE(dwType == REG_MULTI_SZ);
// check whether this service is already a known source
register LPTSTR p = LPTSTR(Buffer);
register LPTSTR pNew = LPTSTR(NewBuffer);
BOOL bNeedSave = FALSE; // assume the value is already correct
for(; *p; p += _tcslen(p)+1) {
// except ourself: copy the source string into the destination
if( _tcscmp(p, m_lpServiceName) != 0 ) {
_tcscpy(pNew, p);
pNew += _tcslen(pNew)+1;
} else {
bNeedSave = TRUE; // *this* application found
dwSize -= _tcslen(p)+1; // new size of value
}
}
if( bNeedSave ) {
// OK - now store the modified value back into the
// registry.
lRet = ::RegSetValueEx(
hKey, // handle of key to set value for
TEXT("Sources"),// address of value to set
0, // reserved
dwType, // flag for value type
NewBuffer, // address of value data
dwSize // size of value data
);
}
}
::GlobalFree(HGLOBAL(Buffer));
::GlobalFree(HGLOBAL(NewBuffer));
}
::RegCloseKey(hKey);
}
}
////////////////////////////////////////////////////////
//!! TCW MOD - function to create console for faceless apps if not already there
void CNTService::SetupConsole() {
if( !m_fConsoleReady ) {
AllocConsole(); // you only get 1 console.
// lovely hack to get the standard io (printf, getc, etc) to the new console. Pretty much does what the
// C lib does for us, but when we want it, and inside of a Window'd app.
// The ugly look of this is due to the error checking (bad return values. Remove the if xxx checks if you like it that way.
DWORD astds[3]={STD_OUTPUT_HANDLE,STD_ERROR_HANDLE,STD_INPUT_HANDLE};
FILE *atrgs[3]={stdout,stderr,stdin};
for( register int i=0; i<3; i++ ) {
long hand=(long)GetStdHandle(astds[i]);
if( hand!=(long)INVALID_HANDLE_VALUE ) {
int osf=_open_osfhandle(hand,_O_TEXT);
if( osf!=-1 ) {
FILE *fp=_fdopen(osf,(astds[i]==STD_INPUT_HANDLE) ? "r" : "w");
if( fp!=NULL ) {
*(atrgs[i])=*fp;
setvbuf(fp,NULL,_IONBF,0);
}
}
}
}
m_fConsoleReady=TRUE;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -