Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1248 lines
30 KiB

/*++ '
Copyright (c) 1997 Microsoft Corporation
Module Name:
STISvc.CPP
Abstract:
Code for performing STI service related functions ( Start/Stop etc)
It is separated from main process code make it possible to share process for
multiple services ever needed
Author:
Vlad Sadovsky (vlads) 09-20-97
Environment:
User Mode - Win32
Revision History:
22-Sep-1997 VladS created
--*/
//
// Include Headers
//
#include "precomp.h"
#include "stiexe.h"
#include "device.h"
#include <stisvc.h>
#include <regstr.h>
#include <devguid.h>
typedef LONG NTSTATUS;
#include <svcs.h>
extern HWND g_hStiServiceWindow;
extern BOOL
StiRefreshWithDelay(
ULONG ulDelay,
WPARAM wParam,
LPARAM lParam);
//
// Delay in milliseconds to wait before processing PnP device event
//
#define DEVICEEVENT_WAIT_TIME 1000
//
// Local variables and types definitions
//
//
// Service status data
//
SERVICE_STATUS g_StiServiceStatus;
//
// Handle of registered service, used for updating running status
//
SERVICE_STATUS_HANDLE g_StiServiceStatusHandle;
//
// Initialization flag
//
BOOL g_fStiServiceInitialized = FALSE;
//
// What type of sink to use
//
#ifdef WINNT
BOOL g_fUseServiceCtrlSink = TRUE;
#else
BOOL g_fUseServiceCtrlSink = FALSE;
#endif
//
// Hidden service window
//
HWND g_hStiServiceWindow = NULL;
//
// Notification sink for PnP notifications
//
HDEVNOTIFY g_hStiServiceNotificationSink = NULL;
//
// Shutdown event
//
HANDLE hShutdownEvent = NULL;
#ifdef WINNT
//
// Local prototypes
//
BOOL
WINAPI
InitializeNTSecurity(
VOID
);
BOOL
WINAPI
TerminateNTSecurity(
VOID
);
#endif
//
// Service status variable dispatch table
//
SERVICE_TABLE_ENTRY ServiceDispatchTable[] = {
{ STI_SERVICE_NAME, StiServiceMain },
{ NULL, NULL }
};
//
// Code section
//
DWORD
WINAPI
UpdateServiceStatus(
IN DWORD dwState,
IN DWORD dwWin32ExitCode,
IN DWORD dwWaitHint )
/*++
Description:
Updates the local copy status of service controller status
and reports it to the service controller.
Arguments:
dwState - New service state.
dwWin32ExitCode - Service exit code.
dwWaitHint - Wait hint for lengthy state transitions.
Returns:
NO_ERROR on success and returns Win32 error if failure.
On success the status is reported to service controller.
--*/
{
const TCHAR* szStateDbgMsg[] = {
TEXT("SERVICE_UNKNOWN "), // 0x00000000
TEXT("SERVICE_STOPPED "), // 0x00000001
TEXT("SERVICE_START_PENDING "), // 0x00000002
TEXT("SERVICE_STOP_PENDING "), // 0x00000003
TEXT("SERVICE_RUNNING "), // 0x00000004
TEXT("SERVICE_CONTINUE_PENDING "), // 0x00000005
TEXT("SERVICE_PAUSE_PENDING "), // 0x00000006
TEXT("SERVICE_PAUSED "), // 0x00000007
TEXT("SERVICE_UNKNOWN "), // 0x00000008
};
DWORD dwError = NO_ERROR;
//
// If state is changing - save the new one
//
if (dwState) {
g_StiServiceStatus.dwCurrentState = dwState;
}
g_StiServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
g_StiServiceStatus.dwWaitHint = dwWaitHint;
//
// If we are in the middle of lengthy operation, increment checkpoint value
//
if ((g_StiServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
(g_StiServiceStatus.dwCurrentState == SERVICE_STOPPED) ) {
g_StiServiceStatus.dwCheckPoint = 0;
}
else {
g_StiServiceStatus.dwCheckPoint++;
}
#ifdef WINNT
//
// Now update SCM running database
//
if ( g_fRunningAsService ) {
DBG_TRC(("Updating service status. CurrentState=%S StateCode=%d",
g_StiServiceStatus.dwCurrentState < (sizeof(szStateDbgMsg) / sizeof(TCHAR *)) ?
szStateDbgMsg[g_StiServiceStatus.dwCurrentState] : szStateDbgMsg[0],
g_StiServiceStatus.dwCurrentState));
if( !SetServiceStatus( g_StiServiceStatusHandle, &g_StiServiceStatus ) ) {
dwError = GetLastError();
} else {
dwError = NO_ERROR;
}
}
#endif
return ( dwError);
} // UpdateServiceStatus()
DWORD
WINAPI
StiServiceInitialize(
VOID
)
/*++
Routine Description:
Service initialization, creates all needed data structures
Nb: This routine has upper limit for execution time, so if it takes too much time
separate thread will have to be created to queue initialization work
Arguments:
Return Value:
None.
--*/
{
HRESULT hres;
DWORD dwError;
DBG_FN(StiServiceInitialize);
#ifdef MAXDEBUG
DBG_TRC(("Start service entered"));
#endif
g_StiFileLog->ReportMessage(STI_TRACE_INFORMATION,
MSG_TRACE_SVC_INIT,TEXT("STISVC"),0);
//
// Create shutdown event.
//
hShutdownEvent = CreateEvent( NULL, // lpsaSecurity
TRUE, // fManualReset
FALSE, // fInitialState
NULL ); // lpszEventName
if( hShutdownEvent == NULL ) {
dwError = GetLastError();
return dwError;
}
UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
//
// Initialize active device list
//
InitializeDeviceList();
//
// Start RPC servicing
//
UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
if (NOERROR != StartRpcServerListen()) {
dwError = GetLastError();
DBG_ERR(("StiService failed to start RPC listen. ErrorCode=%d", dwError));
goto Cleanup;
}
#ifdef WINNT
//
// Allow setting window to foreground
//
dwError = AllowSetForegroundWindow(GetCurrentProcessId()); // ASFW_ANY
DBG_TRC((" AllowSetForegroundWindow is called for id:%d . Ret code=%d. LastError=%d ",
GetCurrentProcessId(),
dwError,
::GetLastError()));
#endif
//
// Create hidden window for receiving PnP notifications
//
if (!CreateServiceWindow()) {
dwError = GetLastError();
DBG_ERR(("Failed to create hidden window for PnP notifications. ErrorCode=%d",dwError));
goto Cleanup;
}
#ifdef WINNT
//
// Initialize NT security parameters
//
InitializeNTSecurity();
#endif
// No longer needed - the equivalent exists in CWiaDevMan
// g_pDeviceInfoSet = new DEVICE_INFOSET(GUID_DEVCLASS_IMAGE);
g_pDeviceInfoSet = NULL;
//
// Initiate device list refresh
//
//::PostMessage(g_hStiServiceWindow,
// STIMON_MSG_REFRESH,
// STIMON_MSG_REFRESH_REREAD,
// STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
// | STIMON_MSG_BOOT // This shows this is the first device enumeration - no need to generate events
// );
//
// Finally we are running
//
g_fStiServiceInitialized = TRUE;
UpdateServiceStatus(SERVICE_RUNNING,NOERROR,0);
#ifdef MAXDEBUG
g_EventLog->LogEvent(MSG_STARTUP,
0,
(LPCSTR *)NULL);
#endif
g_StiFileLog->ReportMessage(STI_TRACE_INFORMATION,MSG_STARTUP);
return NOERROR;
Cleanup:
//
// Something failed , call stop routine to clean up
//
StiServiceStop();
return dwError;
} // StiServiceInitialize
VOID
WINAPI
StiServiceStop(
VOID
)
/*++
Routine Description:
Stopping STI service
Arguments:
Return Value:
None.
--*/
{
DBG_FN(StiServiceStop);
DBG_TRC(("Service is exiting"));
UpdateServiceStatus(SERVICE_STOP_PENDING,NOERROR,START_HINT);
#ifdef WINNT
//
// Clean up PnP notification handles
//
if (g_hStiServiceNotificationSink && g_hStiServiceNotificationSink!=INVALID_HANDLE_VALUE) {
UnregisterDeviceNotification(g_hStiServiceNotificationSink);
g_hStiServiceNotificationSink = NULL;
}
for (UINT uiIndex = 0;
(uiIndex < NOTIFICATION_GUIDS_NUM );
uiIndex++)
{
if (g_phDeviceNotificationsSinkArray[uiIndex] && (g_phDeviceNotificationsSinkArray[uiIndex]!=INVALID_HANDLE_VALUE)) {
UnregisterDeviceNotification(g_phDeviceNotificationsSinkArray[uiIndex]);
g_phDeviceNotificationsSinkArray[uiIndex] = NULL;
}
}
#endif
//
// Stop item scheduler
//
SchedulerSetPauseState(TRUE);
//
// Destroy service window
//
if (g_hStiServiceWindow) {
DestroyWindow(g_hStiServiceWindow);
g_hStiServiceWindow = NULL;
}
#ifdef WINNT
//
// Free security objects
//
if(!TerminateNTSecurity()) {
DBG_ERR(("Failed to clean up security objects"));
}
#endif
//
// Cancel all client calls
//
WiaEventNotifier *pOldWiaEventNotifier = g_pWiaEventNotifier;
InterlockedCompareExchangePointer((VOID**)&g_pWiaEventNotifier, NULL, g_pWiaEventNotifier);
if (pOldWiaEventNotifier)
{
delete pOldWiaEventNotifier;
pOldWiaEventNotifier = NULL;
}
// Since using AsyncRPC, we would rather just exit the process than shut the RPC
// server down. This is becuase even one outstanding AsyncRPC call
// will cause a hang attempting to stop the RPC server.
// It is much more preferable for us to just exit than introduce the
// possiblility of a hang, so we'll just exit and let the OS clean up for us.
//
// Stop RPC servicing
//
//if(NOERROR != StopRpcServerListen()) {
// DBG_ERR(("Failed to stop RpcServerListen"));
//}
//
// Terminate device list
//
TerminateDeviceList();
// Destroy info set
//if (g_pDeviceInfoSet) {
// delete g_pDeviceInfoSet;
// }
//
// Resume scheduling to allow for internal work items to complete
// At this point all device related items should've been purged by
// device object destructors
//
SchedulerSetPauseState(FALSE);
//
// Finish
//
g_fStiServiceInitialized = FALSE;
#ifdef MAXDEBUG
g_EventLog->LogEvent(MSG_STOP,
0,
(LPCSTR *)NULL);
#endif
//
// UnRegister the WiaDevice manager from the ROT
//
InitWiaDevMan(WiaUninitialize);
//
// Signal shutdown
//
SetEvent(hShutdownEvent);
//UpdateServiceStatus(SERVICE_STOPPED,NOERROR,0);
} // StiServiceStop
VOID
WINAPI
StiServicePause(
VOID
)
/*++
Routine Description:
Pausing STI service
Arguments:
Return Value:
None.
--*/
{
DBG_FN(StiServicePause);
//
// System is suspending - take snapshot of currently active devices
//
UpdateServiceStatus(SERVICE_PAUSE_PENDING,NOERROR,PAUSE_HINT);
if ( (g_StiServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
(g_StiServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ){
// Stop running work items queue
//
// Nb: if refresh routine is scheduled to run as work item, this is a problem
//
SchedulerSetPauseState(TRUE);
/* The equivalent done by HandlePowerEvent
SendMessage(g_hStiServiceWindow,
STIMON_MSG_REFRESH,
STIMON_MSG_REFRESH_SUSPEND,
STIMON_MSG_REFRESH_EXISTING
);
*/
}
} // StiServicePause
VOID
WINAPI
StiServiceResume(
VOID
)
/*++
Routine Description:
Resuming STI service
Arguments:
Return Value:
None.
--*/
{
DBG_FN(StiServiceResume);
SchedulerSetPauseState(FALSE);
PostMessage(g_hStiServiceWindow,
STIMON_MSG_REFRESH,
STIMON_MSG_REFRESH_RESUME,
STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
);
UpdateServiceStatus(SERVICE_RUNNING,NOERROR,0);
} // StiServiceResume
ULONG
WINAPI
StiServiceCtrlHandler(
IN DWORD dwOperation,
DWORD dwEventType,
PVOID EventData,
PVOID pData
)
/*++
Routine Description:
STI service control dispatch function
Arguments:
SCM OpCode
Return Value:
None.
--*/
{
ULONG retval = NO_ERROR;
DBG_TRC(("Entering CtrlHandler OpCode=%d",dwOperation));
switch (dwOperation) {
case SERVICE_CONTROL_STOP:
StiServiceStop();
break;
case SERVICE_CONTROL_PAUSE:
StiServicePause();
break;
case SERVICE_CONTROL_CONTINUE:
StiServiceResume();
break;
case SERVICE_CONTROL_SHUTDOWN:
StiServiceStop();
break;
case SERVICE_CONTROL_PARAMCHANGE:
//
// Refresh device list.
//
g_pMsgHandler->HandleCustomEvent(SERVICE_CONTROL_PARAMCHANGE);
break;
case SERVICE_CONTROL_INTERROGATE:
// Report current state and status
UpdateServiceStatus(0,NOERROR,0);
break;
case SERVICE_CONTROL_DEVICEEVENT:
//
// PnP event.
//
//
// Until our PnP issues are resolved, keep logging PnP events so we know
// whether we received it or not...
//
DBG_WRN(("::StiServiceCtrlHandler, Received PnP event..."));
g_pMsgHandler->HandlePnPEvent(dwEventType, EventData);
break;
case SERVICE_CONTROL_POWEREVENT:
//
// Power management event
//
retval = g_pMsgHandler->HandlePowerEvent(dwEventType, EventData);
break;
case STI_SERVICE_CONTROL_REFRESH:
//
// Refresh device list.
//
DBG_TRC(("::StiServiceCtrlHandler, Received STI_SERVICE_CONTROL_REFRESH"));
g_pMsgHandler->HandleCustomEvent(STI_SERVICE_CONTROL_REFRESH);
break;
case STI_SERVICE_CONTROL_EVENT_REREAD:
//
// Refresh device list.
//
DBG_TRC(("::StiServiceCtrlHandler, Received STI_SERVICE_CONTROL_EVENT_REREAD"));
g_pMsgHandler->HandleCustomEvent(STI_SERVICE_CONTROL_EVENT_REREAD);
break;
case STI_SERVICE_CONTROL_LPTENUM:
//
// Enumerate LPT port.
//
EnumLpt();
break;
default:
// Unknown opcode
;
}
DBG_TRC(("Exiting CtrlHandler"));
return retval;
} // StiServiceCtrlHandler
BOOL RegisterServiceControlHandler()
{
DWORD dwError = 0;
#ifdef WINNT
g_StiServiceStatusHandle = RegisterServiceCtrlHandlerEx(
STI_SERVICE_NAME,
StiServiceCtrlHandler,
(LPVOID)STI_SERVICE__DATA
);
if(!g_StiServiceStatusHandle) {
// Could not register with SCM
dwError = GetLastError();
DBG_ERR(("Failed to register CtrlHandler,ErrorCode=%d",dwError));
return FALSE;
}
#endif
return TRUE;
}
VOID
WINAPI
StiServiceMain(
IN DWORD argc,
IN LPTSTR *argv
)
/*++
Routine Description:
This is service main entry, that is called by SCM
Arguments:
Return Value:
None.
--*/
{
DWORD dwError;
DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
DBG_FN(StiServiceMain);
#ifdef MAXDEBUG
DBG_TRC(("StiServiceMain entered"));
#endif
//
// REMOVE: This is not actually an error, but we will use error logging to gurantee
// it always get written to the log. This should be removed as soon as we know what
// causes #347835.
//
SYSTEMTIME SysTime;
GetLocalTime(&SysTime);
DBG_ERR(("*> StiServiceMain entered, Time: %d/%02d/%02d %02d:%02d:%02d:%02d",
SysTime.wYear,
SysTime.wMonth,
SysTime.wDay,
SysTime.wHour,
SysTime.wMinute,
SysTime.wSecond,
SysTime.wMilliseconds));
g_StiServiceStatus.dwServiceType = STI_SVC_SERVICE_TYPE;
g_StiServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_StiServiceStatus.dwControlsAccepted= SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN |
SERVICE_ACCEPT_PARAMCHANGE |
SERVICE_ACCEPT_POWEREVENT;
g_StiServiceStatus.dwWin32ExitCode = NO_ERROR;
g_StiServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
g_StiServiceStatus.dwCheckPoint = 0;
g_StiServiceStatus.dwWaitHint = 0;
dwError = StiServiceInitialize();
if (NOERROR == dwError) {
#ifdef WINNT
if (g_fUseServiceCtrlSink && !g_hStiServiceNotificationSink) {
DBG_WRN(("::StiServiceMain, About to register for PnP..."));
//
// Register for the PnP Device Interface change notifications
//
memset(&PnPFilter, 0, sizeof(PnPFilter));
PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
PnPFilter.dbcc_reserved = 0x0;
PnPFilter.dbcc_classguid = *g_pguidDeviceNotificationsGuid;
//memcpy(&PnPFilter.dbcc_classguid,
// (LPGUID) g_pguidDeviceNotificationsGuid,
// sizeof(GUID));
g_hStiServiceNotificationSink = RegisterDeviceNotification(
(HANDLE) g_StiServiceStatusHandle,
&PnPFilter,
DEVICE_NOTIFY_SERVICE_HANDLE
);
if (NULL == g_hStiServiceNotificationSink) {
//
// Could not register with PnP - attempt to use window handle
//
g_fUseServiceCtrlSink = FALSE;
}
//
// Separately from main Image interface , register list of optional device interfaces
// we will monitor to allow parameters refresh.
//
for (UINT uiIndex = 0;
(uiIndex < NOTIFICATION_GUIDS_NUM ) && (!::IsEqualGUID(g_pguidDeviceNotificationsGuidArray[uiIndex],GUID_NULL));
uiIndex++)
{
::ZeroMemory(&PnPFilter, sizeof(PnPFilter));
PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
PnPFilter.dbcc_reserved = 0x0;
PnPFilter.dbcc_classguid = g_pguidDeviceNotificationsGuidArray[uiIndex];
g_phDeviceNotificationsSinkArray[uiIndex] = RegisterDeviceNotification(
(HANDLE) g_StiServiceStatusHandle,
&PnPFilter,
DEVICE_NOTIFY_SERVICE_HANDLE
);
DBG_TRC(("Registering optional interface #%d . Returned handle=%X",
uiIndex,g_phDeviceNotificationsSinkArray[uiIndex]));
}
}
#else
// Windows 98 case
g_fUseServiceCtrlSink = FALSE;
#endif
//
// Service initialized , process command line arguments
//
BOOL fVisualize = FALSE;
BOOL fVisualizeRequest = FALSE;
TCHAR cOption;
UINT iCurrentOption = 0;
for (iCurrentOption=0;
iCurrentOption < argc ;
iCurrentOption++ ) {
cOption = *argv[iCurrentOption];
// pszT = argv[iCurrentOption]+ 2 * sizeof(TCHAR);
switch ((TCHAR)LOWORD(::CharUpper((LPTSTR)cOption))) {
case 'V':
fVisualizeRequest = TRUE;
fVisualize = TRUE;
break;
case 'H':
fVisualizeRequest = TRUE;
fVisualize = FALSE;
break;
default:
break;
}
if (fVisualizeRequest ) {
VisualizeServer(fVisualizeRequest);
}
}
//
// Wait for shutdown processing messages. We make ourselves alertable so we
// can receive Shell's Volume notifications via APCs. If we're woken
// up to process the APC, then we must wait again.
//
while(WaitForSingleObjectEx(hShutdownEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION);
#ifndef WINNT
//Don't use windows messaging on NT
//
// Close down message pump
//
if (g_dwMessagePumpThreadId) {
// Indicate we are entering shutdown
g_fServiceInShutdown = TRUE;
PostThreadMessage(g_dwMessagePumpThreadId, WM_QUIT, 0, 0L );
}
#endif
CloseHandle( hShutdownEvent );
hShutdownEvent = NULL;
}
else {
// Could not initialize service, service failed to start
}
//
// REMOVE: This is not actually an error, but we will use error logging to gurantee
// it always get written to the log. This should be removed as soon as we know what
// causes #347835.
//
GetLocalTime(&SysTime);
DBG_ERR(("<* StiServiceMain ended, Time: %d/%02d/%02d %02d:%02d:%02d:%02d",
SysTime.wYear,
SysTime.wMonth,
SysTime.wDay,
SysTime.wHour,
SysTime.wMinute,
SysTime.wSecond,
SysTime.wMilliseconds));
return;
} // StiServiceMain
HWND
WINAPI
CreateServiceWindow(
VOID
)
/*++
Routine Description:
Arguments:
Return Value:
None.
--*/
{
#ifndef WINNT
//Don't use windows messaging on NT
WNDCLASSEX wc;
DWORD dwError;
HWND hwnd = FindWindow(g_szStiSvcClassName,NULL);
// Window should NOT exist at this time
if (hwnd) {
DPRINTF(DM_WARNING ,TEXT("Already registered window"));
return NULL;
}
//
// Create class
//
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_GLOBALCLASS;
wc.lpfnWndProc = StiSvcWinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wc.lpszClassName = g_szStiSvcClassName;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
if (!RegisterClassEx(&wc)) {
dwError = GetLastError();
if (dwError != ERROR_CLASS_ALREADY_EXISTS) {
DBG_ERR(("Failed to register window class ErrorCode=%d",dwError));
return NULL;
}
}
#ifndef WINNT
#ifdef FE_IME
// Disable IME processing on Millenium
ImmDisableIME(::GetCurrentThreadId());
#endif
#endif
g_hStiServiceWindow = CreateWindowEx(0, // Style bits
g_szStiSvcClassName, // Class name
g_szTitle, // Title
WS_DISABLED , // Window style bits
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
CW_USEDEFAULT, // h
CW_USEDEFAULT, // w
NULL, // Parent
NULL, // Menu
g_hInst, // Module instance
NULL); // Options
if (!g_hStiServiceWindow) {
dwError = GetLastError();
DBG_ERR(("Failed to create PnP window ErrorCode=%d"),dwError);
}
#else
g_hStiServiceWindow = (HWND) INVALID_HANDLE_VALUE;
#endif
return g_hStiServiceWindow;
} // CreateServiceWindow
//
// Installation routines.
// They are here to simplify debugging and troubleshooting, called by switches
// on command line
//
DWORD
WINAPI
StiServiceInstall(
LPTSTR lpszUserName,
LPTSTR lpszUserPassword
)
/*++
Routine Description:
Service installation function.
Calls SCM to install STI service, which is running in user security context
Arguments:
Return Value:
None.
--*/
{
DWORD dwError = NOERROR;
#ifdef WINNT
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
TCHAR szDisplayName[MAX_PATH];
//
// Write the svchost group binding to stisvc
//
RegEntry SvcHostEntry(STI_SVC_HOST, HKEY_LOCAL_MACHINE);
TCHAR szValue[MAX_PATH];
lstrcpy (szValue, STI_SERVICE_NAME);
// REG_MULTI_SZ is double null terminated
*(szValue+lstrlen(szValue)+1) = TEXT('\0');
SvcHostEntry.SetValue(STI_IMGSVC, STI_SERVICE_NAME, REG_MULTI_SZ);
#endif // winnt
//
// Write parameters key for svchost
//
TCHAR szMyPath[MAX_PATH] = {0};
TCHAR szSvcPath[MAX_PATH] = SYSTEM_PATH;
LONG lLen;
LONG lNameIndex = 0;
if (lLen = ::GetModuleFileName(g_hInst, szMyPath, sizeof(szMyPath)/sizeof(szMyPath[0]) - 1)) {
RegEntry SvcHostParm(STI_SERVICE_PARAMS, HKEY_LOCAL_MACHINE);
//
// Get the name of the service file (not including the path)
//
for (lNameIndex = lLen; lNameIndex > 0; lNameIndex--) {
if (szMyPath[lNameIndex] == '\\') {
lNameIndex++;
break;
}
}
if (lNameIndex) {
#ifndef WINNT
//
// Windows 98 specific entry
//
TCHAR szWinDir[MAX_PATH] = TEXT("\0");
if (!GetWindowsDirectory(szWinDir, MAX_PATH)) {
DPRINTF(DM_ERROR ,TEXT("Error extracting Still Image service filename."));
return dwError;
}
lstrcat(szWinDir, SYSTEM_PATH);
lstrcpy(szSvcPath, szWinDir);
#endif
lstrcat(szSvcPath, &szMyPath[lNameIndex]);
SvcHostParm.SetValue(REGSTR_SERVICEDLL, szSvcPath, PATH_REG_TYPE);
} else {
DBG_ERR(("Error extracting Still Image service filename."));
}
}
else {
DBG_ERR(("Failed to get my own path registering Still Image service . LastError=%d",
::GetLastError()));
}
// Add registry settings for event logging
RegisterStiEventSources();
return dwError;
} //StiServiceInstall
DWORD
WINAPI
StiServiceRemove(
VOID
)
/*++
Routine Description:
Service removal function. This function calls SCM to remove the STI service.
Arguments:
None.
Return Value:
Return code. Return zero for success
--*/
{
DWORD dwError = NOERROR;
#ifdef WINNT
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
SERVICE_STATUS ServiceStatus;
UINT uiRetry = 10;
__try {
hSCM = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!hSCM) {
dwError = GetLastError();
__leave;
}
hService = OpenService(
hSCM,
STI_SERVICE_NAME,
SERVICE_ALL_ACCESS
);
if (!hService) {
dwError = GetLastError();
__leave;
}
//
// Stop service first
//
if (ControlService( hService, SERVICE_CONTROL_STOP, &ServiceStatus )) {
//
// Wait a little
//
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
while( QueryServiceStatus( hService, &ServiceStatus ) &&
(SERVICE_STOP_PENDING == ServiceStatus.dwCurrentState)) {
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
if (!uiRetry--) {
break;
}
}
if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
dwError = GetLastError();
__leave;
}
}
else {
dwError = GetLastError();
//
// ERROR_SERVICE_NOT_ACTIVE is fine, since it means that the service has
// already been stopped. If the error is not ERROR_SERVICE_NOT_ACTIVE then
// something has gone wrong, so __leave.
//
if (dwError != ERROR_SERVICE_NOT_ACTIVE) {
__leave;
}
}
if (!DeleteService( hService )) {
dwError = GetLastError();
__leave;
}
else {
DBG_TRC(("StiServiceRemove, removed STI service"));
}
}
__finally {
CloseServiceHandle( hService );
CloseServiceHandle( hSCM );
}
#endif
return dwError;
} // StiServiceRemove
VOID
SvchostPushServiceGlobals(
PSVCHOST_GLOBAL_DATA pGlobals
)
{
//
// For now, we do nothing here. We will need to revisit when we run under
// a shared SvcHost Group.
//
return;
}