//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 2000. // // File: service.cxx // // Contents: CI service // // History: 17-Sep-96 dlee Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include // so we know the value of GUIDs #include #include #include #include #include #include #include #include // // HRESULTTOWIN32() maps an HRESULT to a Win32 error. If the facility code // of the HRESULT is FACILITY_WIN32, then the code portion (i.e. the // original Win32 error) is returned. Otherwise, the original HRESULT is // returned unchagned. // #define HRESULT_CODE(hr) ((hr) & 0xFFFF) #define HRESULTTOWIN32(hres) ((HRESULT_FACILITY(hres) == FACILITY_WIN32) ? HRESULT_CODE(hres) : (hres)) static const DWORD dwServiceWaitHint = 60000; // 60 seconds SERVICE_STATUS_HANDLE g_hTheCiSvc = 0; static DWORD dwCiSvcStatus = SERVICE_START_PENDING; #define DEB_CI_MOUNT DEB_ITRACE // 1: 324666 is fixed // 0: 324666 is not fixed and we need an extra thread to work around it #define SYNC_REGISTER 1 BOOL g_fSCMThreadIsGone = FALSE; //+---------------------------------------------------------------------------- // // Function: UpdateServiceStatus // // Synopsis: Does a SetServiceStatus() to the service manager. // // History: 06-Jun-94 DwightKr Created // //----------------------------------------------------------------------------- void UpdateServiceStatus( DWORD dwWin32ExitCode ) { // note to accept power events, "OR" SERVICE_ACCEPT_POWER_EVENTS here static SERVICE_STATUS CiSvcStatus = { SERVICE_WIN32_OWN_PROCESS | // dwServiceType SERVICE_INTERACTIVE_PROCESS, // add this line for interactive 0, // dwCurrentState SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN, NO_ERROR, // dwWin32ExitCode 0, // dwServiceSpecificExitCode 0, // dwCheckPoint 0 // dwWaitHint }; CiSvcStatus.dwCurrentState = dwCiSvcStatus; CiSvcStatus.dwWin32ExitCode = dwWin32ExitCode; if ( dwCiSvcStatus == SERVICE_START_PENDING || dwCiSvcStatus == SERVICE_STOP_PENDING ) { CiSvcStatus.dwCheckPoint++; CiSvcStatus.dwWaitHint = dwServiceWaitHint; } else // SERVICE_RUNNING, SERVICE_STOPPED, SERVICE_PAUSED, ... { CiSvcStatus.dwCheckPoint = 0; CiSvcStatus.dwWaitHint = 0; } ciDebugOut(( DEB_ITRACE, "service status: %d\n", dwCiSvcStatus )); BOOL fOK = SetServiceStatus(g_hTheCiSvc, &CiSvcStatus); #if CIDBG == 1 if ( !fOK ) ciDebugOut(( DEB_ITRACE, "Ci Service: Error from SetServiceStatus = 0x%x\n", GetLastError() )); #endif } //UpdateServerStatus //+------------------------------------------------------------------------- // // Function: ProcessCustomEvent // // Synopsis: This is a helper for HandleDevNotification. It processes // the device custom events // // Arguments: [pEventData] -- a PDEV_BROADCAST_HDR object // [pContext] -- a CDrvNotifArray * object. // // Return: error code from the StartCatalogOnVol/StopCatalogsOnVol // proceudres // // History: 18-May-98 kitmanh Created // 12-Aug-98 kitmanh Added return value // //-------------------------------------------------------------------------- SCODE ProcessCustomEvent( PVOID pEventData, PVOID pContext ) { SCODE sc = S_OK; DEV_BROADCAST_HDR UNALIGNED *pBroadcastHdr = (PDEV_BROADCAST_HDR) pEventData; ciDebugOut(( DEB_CI_MOUNT, "What is the device type? (%#x)\n", pBroadcastHdr->dbch_devicetype )); // is this a handled event? if ( DBT_DEVTYP_HANDLE != pBroadcastHdr->dbch_devicetype) return ERROR_CALL_NOT_IMPLEMENTED; DEV_BROADCAST_HANDLE UNALIGNED *pDevBroadcastHandle = (PDEV_BROADCAST_HANDLE) pBroadcastHdr; ciDebugOut(( DEB_CI_MOUNT, "It is a handled type, handle %#x\n", pDevBroadcastHandle->dbch_hdevnotify )); CDrvNotifArray * pDrvNotifArray = (CDrvNotifArray *)pContext; CDrvNotificationInfo * pDriveInfo = pDrvNotifArray->FindDriveNotificationByHandle( (HDEVNOTIFY) pDevBroadcastHandle->dbch_hdevnotify); if ( 0 != pDriveInfo ) { if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid ) { // a volume lock occurred ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_LOCK for volume %wc\n", pDriveInfo->GetDrvLetter() )); if ( eVolReady == pDriveInfo->GetVolState() ) { ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol\n" )); sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs\n" )); pDriveInfo->SetVolState( eVolLocked ); } ciDebugOut(( DEB_CI_MOUNT, "Increment Lock Attempts\n" )); pDriveInfo->IncLockAttempts(); ciDebugOut(( DEB_CI_MOUNT, "_cLockAttempts is %d\n", pDriveInfo->GetLockAttempts() )); } else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid ) { // CD-ROMs aren't giving dismount/unlock notifies, // so key off of this instead. This is "by design" apparently. // A media removal occurred. If we have a CD-ROM catalog // open, close it. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_MEDIA_REMOVAL for volume %wc\n", pDriveInfo->GetDrvLetter() )); WCHAR awc[4]; wcscpy( awc, L"C:\\" ); awc[0] = pDriveInfo->GetDrvLetter(); if ( DRIVE_CDROM == GetDriveType( awc ) ) { if ( eVolReady == pDriveInfo->GetVolState() ) { ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol\n" )); sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs\n" )); } } } else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid ) { // This assert is not always true for CD-ROMs. I don't know why //Win4Assert( eVolLocked == pDriveInfo->GetVolState() ); if ( eVolLocked == pDriveInfo->GetVolState() ) { // a volume was unlocked ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_UNLOCK for volume %wc, removable %s, automount %s\n", pDriveInfo->GetDrvLetter(), pDriveInfo->IsRemovable() ? "yes" : "no", pDriveInfo->IsAutoMount() ? "yes" : "no" )); pDriveInfo->ResetLockAttempts(); // Unregister since the _hVol is obsolete pDriveInfo->UnregisterNotification(); // // We can open catalogs on fixed volumes on the unlock, but not on // removable volumes, since we get an unlock once the volume is // ejected. For removable volumes, open the catalog on the mount, // except for the case of chkdsk where the volume will be mountable // immediately and we won't get the mount notification // For Fixed volumes, don't wait for the mount since it may be a // long time until the mount happens. // if ( pDriveInfo->Touch() ) { ciDebugOut(( DEB_CI_MOUNT, "About to start catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() )); sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() ); ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" )); } // // Asynchronously redo RegisterDeviceNotification with a new // volume handle. // If we don't unregister/reregister on Jaz volumes we never get a // mount notify. But on fixed volumes if we unregister/reregister // we miss the mount since it happens before the register succeeds // on an operation like chkdsk. // #if SYNC_REGISTER pDriveInfo->RegisterNotification(); #else pDrvNotifArray->RegisterDormantEntries(); #endif pDriveInfo->SetVolState( eVolReady ); } } else if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid ) { ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_LOCK_FAILED for volume %wc\n", pDriveInfo->GetDrvLetter() )); if ( pDriveInfo->GetLockAttempts() > 0 ) { ciDebugOut(( DEB_CI_MOUNT, "Decrement _cLockAttempts\n" )); pDriveInfo->DecLockAttempts(); } else { Win4Assert( eVolReady == pDriveInfo->GetVolState() ); } ciDebugOut(( DEB_CI_MOUNT, "_cLockAttempts is %d\n", pDriveInfo->GetLockAttempts() )); if ( ( 0 == pDriveInfo->GetLockAttempts() ) && ( eVolLocked == pDriveInfo->GetVolState() ) ) { // unlock the volume, since all attemps to lock the volume have failed. pDriveInfo->UnregisterNotification(); ciDebugOut(( DEB_CI_MOUNT, "About to start(lock_failed) catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() )); sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() ); ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" )); // redo RegisterDeviceNotification with a new volume handle #if SYNC_REGISTER pDriveInfo->RegisterNotification(); #else pDrvNotifArray->RegisterDormantEntries(); #endif pDriveInfo->SetVolState( eVolReady ); ciDebugOut(( DEB_CI_MOUNT, "Done Unlocking for lock_failed\n" )); } } else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid && eVolReady == pDriveInfo->GetVolState() ) { ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_DISMOUNT for volume %wc, removable %s, automount %s\n", pDriveInfo->GetDrvLetter(), pDriveInfo->IsRemovable() ? "yes" : "no", pDriveInfo->IsAutoMount() ? "yes" : "no" )); ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() )); sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() )); pDriveInfo->SetVolState( eVolLocked ); } else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid && eVolReady != pDriveInfo->GetVolState() ) { ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_DISMOUNT_FAILED for volume %wc\n", pDriveInfo->GetDrvLetter() )); pDriveInfo->UnregisterNotification(); ciDebugOut(( DEB_CI_MOUNT, "About to start(dimount_failed) catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() )); sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() ); ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" )); // redo RegisterDeviceNotification with a new volume handle #if SYNC_REGISTER pDriveInfo->RegisterNotification(); #else pDrvNotifArray->RegisterDormantEntries(); #endif pDriveInfo->SetVolState( eVolReady ); } else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid ) { ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_MOUNT for volume %wc, removable %s, automount %s\n", pDriveInfo->GetDrvLetter(), pDriveInfo->IsRemovable() ? "yes" : "no", pDriveInfo->IsAutoMount() ? "yes" : "no" )); // // Mount notifications come at the oddest times -- even after an // eject of a removable volume! Make sure the volume really is // valid by touching it before trying to open a catalog on the // volume. Only start catalogs on mount for removable drives. // Start catalogs for fixed drives on Unlock. This is because // we have to asynchronously re-register for notifications after // an unlock, and by the time we register we've missed the mount. // Lovely piece of design work by the pnp guys. Note: this is // partially fixed in current builds. If we don't re-register // we get everything but mount notifications on removable // drives. // BOOL fOK = pDriveInfo->Touch(); ciDebugOut(( DEB_CI_MOUNT, "drive %wc appears healthy? %d\n", pDriveInfo->GetDrvLetter(), fOK )); if ( fOK && pDriveInfo->IsRemovable() ) { ciDebugOut(( DEB_CI_MOUNT, "About to start catalogs on Vol\n" )); sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() ); ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" )); } } else { ciDebugOut(( DEB_CI_MOUNT, "UNHANDLED but device object was recognized\n" )); if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK_FAILED\n" )); else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT_FAILED\n" )); else if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK\n" )); else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_UNLOCK\n" )); else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT\n" )); else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_MOUNT\n" )); else if ( GUID_IO_MEDIA_ARRIVAL == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_ARRIVAL\n" )); else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_REMOVAL\n" )); else ciDebugOut(( DEB_CI_MOUNT, " eventguid: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", pDevBroadcastHandle->dbch_eventguid.Data1, pDevBroadcastHandle->dbch_eventguid.Data2, pDevBroadcastHandle->dbch_eventguid.Data3, pDevBroadcastHandle->dbch_eventguid.Data4[0], pDevBroadcastHandle->dbch_eventguid.Data4[1], pDevBroadcastHandle->dbch_eventguid.Data4[2], pDevBroadcastHandle->dbch_eventguid.Data4[3], pDevBroadcastHandle->dbch_eventguid.Data4[4], pDevBroadcastHandle->dbch_eventguid.Data4[5], pDevBroadcastHandle->dbch_eventguid.Data4[6], pDevBroadcastHandle->dbch_eventguid.Data4[7] )); } } else { ciDebugOut(( DEB_CI_MOUNT, " handle: %#x\n", pDevBroadcastHandle->dbch_handle )); ciDebugOut(( DEB_CI_MOUNT, " hdev_notify: %#x\n", pDevBroadcastHandle->dbch_hdevnotify )); ciDebugOut(( DEB_CI_MOUNT, " nameoffset: %#x\n", pDevBroadcastHandle->dbch_nameoffset )); if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK_FAILED\n" )); else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT_FAILED\n" )); else if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK\n" )); else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_UNLOCK\n" )); else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT\n" )); else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_MOUNT\n" )); else if ( GUID_IO_MEDIA_ARRIVAL == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_ARRIVAL\n" )); else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid ) ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_REMOVAL\n" )); else ciDebugOut(( DEB_CI_MOUNT, " eventguid: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", pDevBroadcastHandle->dbch_eventguid.Data1, pDevBroadcastHandle->dbch_eventguid.Data2, pDevBroadcastHandle->dbch_eventguid.Data3, pDevBroadcastHandle->dbch_eventguid.Data4[0], pDevBroadcastHandle->dbch_eventguid.Data4[1], pDevBroadcastHandle->dbch_eventguid.Data4[2], pDevBroadcastHandle->dbch_eventguid.Data4[3], pDevBroadcastHandle->dbch_eventguid.Data4[4], pDevBroadcastHandle->dbch_eventguid.Data4[5], pDevBroadcastHandle->dbch_eventguid.Data4[6], pDevBroadcastHandle->dbch_eventguid.Data4[7] )); } return sc; } //ProcessCustomEvent //+---------------------------------------------------------------------------- // // Function: CiSvcMsgProc // // Synopsis: Message handler for Ci service // // Arguments: [dwControl] - the message. // // Returns: Nothing // // History: 06-Jun-94 DwightKr Created // 06-23-98 KitmanH Updated for RegisterServiceCtrlHandlerEx // 07-30-98 KitmanH Return appropriate errors // // Notes: We need to keep the status between calls to this routine // since the service control manager may query the current // status at any time. // //----------------------------------------------------------------------------- DWORD WINAPI CiSvcMsgProc( DWORD dwControl, DWORD dwEventType, PVOID pEventData, PVOID pContext ) { ciDebugOut(( DEB_ITRACE, "Ci 0Service: Executing service control command 0x%x\n", dwControl )); Win4Assert( pContext ); BOOL fShutdown = FALSE; DWORD dwError = NO_ERROR; TRY { switch (dwControl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: UpdateServiceStatus( NO_ERROR ); if ( SERVICE_STOP_PENDING != dwCiSvcStatus ) { ciDebugOut(( DEB_ITRACE, "About to stop\n" )); dwCiSvcStatus = SERVICE_STOP_PENDING; if ( ! g_fSCMThreadIsGone ) StopCiSvcWork( eNetStop ); } ciDebugOut( (DEB_ITRACE, "Ci Service: Done shutting down service\n" )); // // Calling UpdateServiceStatus() after doing the shutdown is // causing the service to hang. Not calling solved the problem // and so I am preventing it from being called. // fShutdown = TRUE; break; case SERVICE_CONTROL_PAUSE: if ( SERVICE_PAUSED != dwCiSvcStatus && SERVICE_STOP_PENDING != dwCiSvcStatus ) { ciDebugOut(( DEB_ITRACE, "About to pause\n" )); if ( ! g_fSCMThreadIsGone ) StopCiSvcWork( eNetPause ); dwCiSvcStatus = SERVICE_PAUSED; ciDebugOut(( DEB_ITRACE, "Ci Service: Done pausing the service\n" )); } break; case SERVICE_CONTROL_CONTINUE: if ( SERVICE_PAUSED == dwCiSvcStatus && SERVICE_STOP_PENDING != dwCiSvcStatus ) { ciDebugOut(( DEB_ITRACE, "About to continue\n" )); if ( ! g_fSCMThreadIsGone ) StopCiSvcWork( eNetContinue ); dwCiSvcStatus = SERVICE_RUNNING; } ciDebugOut(( DEB_ITRACE, "Ci Service: Done continuing the service\n" )); break; case SERVICE_CONTROL_DEVICEEVENT: // a dismount or remount may have occurred ciDebugOut(( DEB_ITRACE, "SERVICE_CONTROL_DEVICEEVENT received, event = %#x\n", dwEventType )); { SCODE sc = S_OK; if ( DBT_CUSTOMEVENT == dwEventType ) { ciDebugOut(( DEB_ITRACE, "It is a custom event\n" )); if ( ! g_fSCMThreadIsGone ) sc = ProcessCustomEvent( pEventData, pContext ); ciDebugOut(( DEB_ITRACE, "Done processing custom event\n" )); } // convert sc into a WIN32 error and return it ciDebugOut(( DEB_ITRACE, "Process Custom Event returned sc = %#x\n", sc )); dwError = HRESULTTOWIN32(sc); } break; case SERVICE_CONTROL_INTERROGATE: break; default: ciDebugOut(( DEB_CI_MOUNT, "service control not implemented %d\n", dwControl )); dwError = ERROR_CALL_NOT_IMPLEMENTED; break; } UpdateServiceStatus( NO_ERROR ); } CATCH (CException, e) { ciDebugOut(( DEB_ITRACE, "Ci Service: Error from callback = 0x%x\n", e.GetErrorCode() )); } END_CATCH ciDebugOut(( DEB_ITRACE, "Getting out of CiSvcMsgProc\n" )); return dwError; } //CiSvcMsgProc //+------------------------------------------------------------------------- // // Function: CiServiceMain, public // // Purpose: Service entry point // // Arguments: [dwNumServiceArgs] - number of arguments passed // [awcsServiceArgs] - arguments // // History: 06-Jun-94 DwightKr Created // //-------------------------------------------------------------------------- extern CEventSem * g_pevtPauseContinue; void CiSvcMain( DWORD dwNumServiceArgs, LPWSTR * awcsServiceArgs ) { // The service control manager crofted up this thread, so we have to // establish the exception state, etc. CTranslateSystemExceptions translate; TRY { CDrvNotifArray DrvNotifArray; ciDebugOut( (DEB_ITRACE, "Ci Service: Attempting to register service\n" )); // Register service handler with service controller g_hTheCiSvc = RegisterServiceCtrlHandlerEx( wcsCiSvcName, CiSvcMsgProc, &DrvNotifArray ); if (0 == g_hTheCiSvc) { ciDebugOut(( DEB_ERROR, "Unable to register ci service\n" )); THROW( CException( E_FAIL ) ); } CEventSem evtPauseContinue; g_pevtPauseContinue = &evtPauseContinue; UpdateServiceStatus( NO_ERROR ); CRegAccess reg( RTL_REGISTRY_CONTROL, wcsRegAdmin ); if ( 1 != reg.Read( wcsPreventCisvcParam, (ULONG) 0 ) ) { dwCiSvcStatus = SERVICE_RUNNING; UpdateServiceStatus( NO_ERROR ); #if CIDBG == 1 BOOL fRun = TRUE; // FALSE --> Stop TRY { ULONG ulVal = reg.Read( L"StopCiSvcOnStartup", (ULONG)0 ); if ( 1 == ulVal ) fRun = FALSE; } CATCH( CException, e ) { } END_CATCH; unsigned long OldWin4AssertLevel = SetWin4AssertLevel(ASSRT_MESSAGE | ASSRT_POPUP); Win4Assert( fRun ); SetWin4AssertLevel( OldWin4AssertLevel ); #endif // CIDBG // Register for pnp notifications on drives used by catalogs DrvNotifArray.RegisterCatForNotifInRegistry(); // // Register for pnp notifications on removable drives not yet // registered if the registry flag says it's appropriate. // if ( 0 != reg.Read( wcsMountRemovableCatalogs, CI_AUTO_MOUNT_CATALOGS_DEFAULT ) ) DrvNotifArray.RegisterRemovableDrives(); StartCiSvcWork( DrvNotifArray ); DrvNotifArray.UnregisterDeviceNotifications(); ciDebugOut(( DEB_ITRACE, "service_stopped from CiSvcMain\n" )); } else { CEventLog eventLog( NULL, wcsCiEventSource ); CEventItem item( EVENTLOG_INFORMATION_TYPE, CI_SERVICE_CATEGORY, MSG_CI_SERVICE_SUPPRESSED, 0 ); eventLog.ReportEvent( item ); } dwCiSvcStatus = SERVICE_STOPPED; UpdateServiceStatus( NO_ERROR ); ciDebugOut(( DEB_ITRACE, "Shutdown is done\n" )); CoFreeUnusedLibraries(); ciDebugOut( (DEB_ITRACE, "Ci Service: Leaving CiSvcMain()\n" )); } CATCH (CException, e) { ciDebugOut( (DEB_ITRACE, "Ci Service: Detected error 0x%x\n", e.GetErrorCode() )); } END_CATCH g_pevtPauseContinue = 0; g_fSCMThreadIsGone = TRUE; } //CiSvcMain //+---------------------------------------------------------------------------- // // Function: SvcEntry_CiSvc // // Synopsis: Entry from services.exe // // This is currently broken since services doesn't unload // query.dll when the service is stopped, and our global // variables don't expect to be used again when the service // is restarted. It's probably a week of work to fix this! // We don't do this anyway so it doesn't matter. // // History: 05-Jan-97 dlee Created // //----------------------------------------------------------------------------- void SvcEntry_CiSvc( DWORD NumArgs, LPWSTR * ArgsArray, void * pSvcsGlobalData, HANDLE SvcRefHandle ) { CiSvcMain( NumArgs, ArgsArray ); } //SvcEntry_CiSvc