windows-nt/Source/XPSP1/NT/inetsrv/query/fsci/dll/service.cxx
2020-09-26 16:20:57 +08:00

696 lines
27 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: service.cxx
//
// Contents: CI service
//
// History: 17-Sep-96 dlee Created
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <dbt.h>
#include <initguid.h> // so we know the value of GUIDs
#include <ioevent.h>
#include <cievtmsg.h>
#include <cisvcex.hxx>
#include <eventlog.hxx>
#include <ciregkey.hxx>
#include <regacc.hxx>
#include <drvnotif.hxx>
#include <notifary.hxx>
//
// 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