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.

695 lines
28 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: service.cxx
  7. //
  8. // Contents: CI service
  9. //
  10. // History: 17-Sep-96 dlee Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <dbt.h>
  16. #include <initguid.h> // so we know the value of GUIDs
  17. #include <ioevent.h>
  18. #include <cievtmsg.h>
  19. #include <cisvcex.hxx>
  20. #include <eventlog.hxx>
  21. #include <ciregkey.hxx>
  22. #include <regacc.hxx>
  23. #include <drvnotif.hxx>
  24. #include <notifary.hxx>
  25. //
  26. // HRESULTTOWIN32() maps an HRESULT to a Win32 error. If the facility code
  27. // of the HRESULT is FACILITY_WIN32, then the code portion (i.e. the
  28. // original Win32 error) is returned. Otherwise, the original HRESULT is
  29. // returned unchagned.
  30. //
  31. #define HRESULT_CODE(hr) ((hr) & 0xFFFF)
  32. #define HRESULTTOWIN32(hres) ((HRESULT_FACILITY(hres) == FACILITY_WIN32) ? HRESULT_CODE(hres) : (hres))
  33. static const DWORD dwServiceWaitHint = 60000; // 60 seconds
  34. SERVICE_STATUS_HANDLE g_hTheCiSvc = 0;
  35. static DWORD dwCiSvcStatus = SERVICE_START_PENDING;
  36. #define DEB_CI_MOUNT DEB_ITRACE
  37. // 1: 324666 is fixed
  38. // 0: 324666 is not fixed and we need an extra thread to work around it
  39. #define SYNC_REGISTER 1
  40. BOOL g_fSCMThreadIsGone = FALSE;
  41. //+----------------------------------------------------------------------------
  42. //
  43. // Function: UpdateServiceStatus
  44. //
  45. // Synopsis: Does a SetServiceStatus() to the service manager.
  46. //
  47. // History: 06-Jun-94 DwightKr Created
  48. //
  49. //-----------------------------------------------------------------------------
  50. void UpdateServiceStatus( DWORD dwWin32ExitCode )
  51. {
  52. // note to accept power events, "OR" SERVICE_ACCEPT_POWER_EVENTS here
  53. static SERVICE_STATUS CiSvcStatus =
  54. {
  55. SERVICE_WIN32_OWN_PROCESS | // dwServiceType
  56. SERVICE_INTERACTIVE_PROCESS, // add this line for interactive
  57. 0, // dwCurrentState
  58. SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE |
  59. SERVICE_ACCEPT_SHUTDOWN,
  60. NO_ERROR, // dwWin32ExitCode
  61. 0, // dwServiceSpecificExitCode
  62. 0, // dwCheckPoint
  63. 0 // dwWaitHint
  64. };
  65. CiSvcStatus.dwCurrentState = dwCiSvcStatus;
  66. CiSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
  67. if ( dwCiSvcStatus == SERVICE_START_PENDING ||
  68. dwCiSvcStatus == SERVICE_STOP_PENDING )
  69. {
  70. CiSvcStatus.dwCheckPoint++;
  71. CiSvcStatus.dwWaitHint = dwServiceWaitHint;
  72. }
  73. else // SERVICE_RUNNING, SERVICE_STOPPED, SERVICE_PAUSED, ...
  74. {
  75. CiSvcStatus.dwCheckPoint = 0;
  76. CiSvcStatus.dwWaitHint = 0;
  77. }
  78. ciDebugOut(( DEB_ITRACE, "service status: %d\n", dwCiSvcStatus ));
  79. BOOL fOK = SetServiceStatus(g_hTheCiSvc, &CiSvcStatus);
  80. #if CIDBG == 1
  81. if ( !fOK )
  82. ciDebugOut(( DEB_ITRACE, "Ci Service: Error from SetServiceStatus = 0x%x\n", GetLastError() ));
  83. #endif
  84. } //UpdateServerStatus
  85. //+-------------------------------------------------------------------------
  86. //
  87. // Function: ProcessCustomEvent
  88. //
  89. // Synopsis: This is a helper for HandleDevNotification. It processes
  90. // the device custom events
  91. //
  92. // Arguments: [pEventData] -- a PDEV_BROADCAST_HDR object
  93. // [pContext] -- a CDrvNotifArray * object.
  94. //
  95. // Return: error code from the StartCatalogOnVol/StopCatalogsOnVol
  96. // proceudres
  97. //
  98. // History: 18-May-98 kitmanh Created
  99. // 12-Aug-98 kitmanh Added return value
  100. //
  101. //--------------------------------------------------------------------------
  102. SCODE ProcessCustomEvent( PVOID pEventData, PVOID pContext )
  103. {
  104. SCODE sc = S_OK;
  105. DEV_BROADCAST_HDR UNALIGNED *pBroadcastHdr = (PDEV_BROADCAST_HDR) pEventData;
  106. ciDebugOut(( DEB_CI_MOUNT, "What is the device type? (%#x)\n",
  107. pBroadcastHdr->dbch_devicetype ));
  108. // is this a handled event?
  109. if ( DBT_DEVTYP_HANDLE != pBroadcastHdr->dbch_devicetype)
  110. return ERROR_CALL_NOT_IMPLEMENTED;
  111. DEV_BROADCAST_HANDLE UNALIGNED *pDevBroadcastHandle = (PDEV_BROADCAST_HANDLE) pBroadcastHdr;
  112. ciDebugOut(( DEB_CI_MOUNT, "It is a handled type, handle %#x\n",
  113. pDevBroadcastHandle->dbch_hdevnotify ));
  114. CDrvNotifArray * pDrvNotifArray = (CDrvNotifArray *)pContext;
  115. CDrvNotificationInfo * pDriveInfo = pDrvNotifArray->FindDriveNotificationByHandle(
  116. (HDEVNOTIFY) pDevBroadcastHandle->dbch_hdevnotify);
  117. if ( 0 != pDriveInfo )
  118. {
  119. if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid )
  120. {
  121. // a volume lock occurred
  122. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_LOCK for volume %wc\n",
  123. pDriveInfo->GetDrvLetter() ));
  124. if ( eVolReady == pDriveInfo->GetVolState() )
  125. {
  126. ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol\n" ));
  127. sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume
  128. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs\n" ));
  129. pDriveInfo->SetVolState( eVolLocked );
  130. }
  131. ciDebugOut(( DEB_CI_MOUNT, "Increment Lock Attempts\n" ));
  132. pDriveInfo->IncLockAttempts();
  133. ciDebugOut(( DEB_CI_MOUNT, "_cLockAttempts is %d\n", pDriveInfo->GetLockAttempts() ));
  134. }
  135. else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid )
  136. {
  137. // CD-ROMs aren't giving dismount/unlock notifies,
  138. // so key off of this instead. This is "by design" apparently.
  139. // A media removal occurred. If we have a CD-ROM catalog
  140. // open, close it.
  141. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_MEDIA_REMOVAL for volume %wc\n",
  142. pDriveInfo->GetDrvLetter() ));
  143. WCHAR awc[4];
  144. wcscpy( awc, L"C:\\" );
  145. awc[0] = pDriveInfo->GetDrvLetter();
  146. if ( DRIVE_CDROM == GetDriveType( awc ) )
  147. {
  148. if ( eVolReady == pDriveInfo->GetVolState() )
  149. {
  150. ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol\n" ));
  151. sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume
  152. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs\n" ));
  153. }
  154. }
  155. }
  156. else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid )
  157. {
  158. // This assert is not always true for CD-ROMs. I don't know why
  159. //Win4Assert( eVolLocked == pDriveInfo->GetVolState() );
  160. if ( eVolLocked == pDriveInfo->GetVolState() )
  161. {
  162. // a volume was unlocked
  163. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_UNLOCK for volume %wc, removable %s, automount %s\n",
  164. pDriveInfo->GetDrvLetter(),
  165. pDriveInfo->IsRemovable() ? "yes" : "no",
  166. pDriveInfo->IsAutoMount() ? "yes" : "no" ));
  167. pDriveInfo->ResetLockAttempts();
  168. // Unregister since the _hVol is obsolete
  169. pDriveInfo->UnregisterNotification();
  170. //
  171. // We can open catalogs on fixed volumes on the unlock, but not on
  172. // removable volumes, since we get an unlock once the volume is
  173. // ejected. For removable volumes, open the catalog on the mount,
  174. // except for the case of chkdsk where the volume will be mountable
  175. // immediately and we won't get the mount notification
  176. // For Fixed volumes, don't wait for the mount since it may be a
  177. // long time until the mount happens.
  178. //
  179. if ( pDriveInfo->Touch() )
  180. {
  181. ciDebugOut(( DEB_CI_MOUNT, "About to start catalogs on Vol %wc\n",
  182. pDriveInfo->GetDrvLetter() ));
  183. sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() );
  184. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" ));
  185. }
  186. //
  187. // Asynchronously redo RegisterDeviceNotification with a new
  188. // volume handle.
  189. // If we don't unregister/reregister on Jaz volumes we never get a
  190. // mount notify. But on fixed volumes if we unregister/reregister
  191. // we miss the mount since it happens before the register succeeds
  192. // on an operation like chkdsk.
  193. //
  194. #if SYNC_REGISTER
  195. pDriveInfo->RegisterNotification();
  196. #else
  197. pDrvNotifArray->RegisterDormantEntries();
  198. #endif
  199. pDriveInfo->SetVolState( eVolReady );
  200. }
  201. }
  202. else if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid )
  203. {
  204. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_LOCK_FAILED for volume %wc\n",
  205. pDriveInfo->GetDrvLetter() ));
  206. if ( pDriveInfo->GetLockAttempts() > 0 )
  207. {
  208. ciDebugOut(( DEB_CI_MOUNT, "Decrement _cLockAttempts\n" ));
  209. pDriveInfo->DecLockAttempts();
  210. }
  211. else
  212. {
  213. Win4Assert( eVolReady == pDriveInfo->GetVolState() );
  214. }
  215. ciDebugOut(( DEB_CI_MOUNT, "_cLockAttempts is %d\n", pDriveInfo->GetLockAttempts() ));
  216. if ( ( 0 == pDriveInfo->GetLockAttempts() ) &&
  217. ( eVolLocked == pDriveInfo->GetVolState() ) )
  218. {
  219. // unlock the volume, since all attemps to lock the volume have failed.
  220. pDriveInfo->UnregisterNotification();
  221. ciDebugOut(( DEB_CI_MOUNT, "About to start(lock_failed) catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() ));
  222. sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() );
  223. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" ));
  224. // redo RegisterDeviceNotification with a new volume handle
  225. #if SYNC_REGISTER
  226. pDriveInfo->RegisterNotification();
  227. #else
  228. pDrvNotifArray->RegisterDormantEntries();
  229. #endif
  230. pDriveInfo->SetVolState( eVolReady );
  231. ciDebugOut(( DEB_CI_MOUNT, "Done Unlocking for lock_failed\n" ));
  232. }
  233. }
  234. else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid &&
  235. eVolReady == pDriveInfo->GetVolState() )
  236. {
  237. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_DISMOUNT for volume %wc, removable %s, automount %s\n",
  238. pDriveInfo->GetDrvLetter(),
  239. pDriveInfo->IsRemovable() ? "yes" : "no",
  240. pDriveInfo->IsAutoMount() ? "yes" : "no" ));
  241. ciDebugOut(( DEB_CI_MOUNT, "About to stop catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() ));
  242. sc = StopCiSvcWork( eLockVol, pDriveInfo->GetDrvLetter() ); //stop catalog on volume
  243. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done stopping the catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() ));
  244. pDriveInfo->SetVolState( eVolLocked );
  245. }
  246. else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid &&
  247. eVolReady != pDriveInfo->GetVolState() )
  248. {
  249. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_DISMOUNT_FAILED for volume %wc\n",
  250. pDriveInfo->GetDrvLetter() ));
  251. pDriveInfo->UnregisterNotification();
  252. ciDebugOut(( DEB_CI_MOUNT, "About to start(dimount_failed) catalogs on Vol %wc\n", pDriveInfo->GetDrvLetter() ));
  253. sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() );
  254. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" ));
  255. // redo RegisterDeviceNotification with a new volume handle
  256. #if SYNC_REGISTER
  257. pDriveInfo->RegisterNotification();
  258. #else
  259. pDrvNotifArray->RegisterDormantEntries();
  260. #endif
  261. pDriveInfo->SetVolState( eVolReady );
  262. }
  263. else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid )
  264. {
  265. ciDebugOut(( DEB_CI_MOUNT, "GUID_IO_VOLUME_MOUNT for volume %wc, removable %s, automount %s\n",
  266. pDriveInfo->GetDrvLetter(),
  267. pDriveInfo->IsRemovable() ? "yes" : "no",
  268. pDriveInfo->IsAutoMount() ? "yes" : "no" ));
  269. //
  270. // Mount notifications come at the oddest times -- even after an
  271. // eject of a removable volume! Make sure the volume really is
  272. // valid by touching it before trying to open a catalog on the
  273. // volume. Only start catalogs on mount for removable drives.
  274. // Start catalogs for fixed drives on Unlock. This is because
  275. // we have to asynchronously re-register for notifications after
  276. // an unlock, and by the time we register we've missed the mount.
  277. // Lovely piece of design work by the pnp guys. Note: this is
  278. // partially fixed in current builds. If we don't re-register
  279. // we get everything but mount notifications on removable
  280. // drives.
  281. //
  282. BOOL fOK = pDriveInfo->Touch();
  283. ciDebugOut(( DEB_CI_MOUNT, "drive %wc appears healthy? %d\n",
  284. pDriveInfo->GetDrvLetter(),
  285. fOK ));
  286. if ( fOK && pDriveInfo->IsRemovable() )
  287. {
  288. ciDebugOut(( DEB_CI_MOUNT, "About to start catalogs on Vol\n" ));
  289. sc = StopCiSvcWork( eUnLockVol, pDriveInfo->GetDrvLetter() );
  290. ciDebugOut(( DEB_CI_MOUNT, "Ci Service: Done starting the catalogs\n" ));
  291. }
  292. }
  293. else
  294. {
  295. ciDebugOut(( DEB_CI_MOUNT, "UNHANDLED but device object was recognized\n" ));
  296. if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid )
  297. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK_FAILED\n" ));
  298. else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid )
  299. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT_FAILED\n" ));
  300. else if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid )
  301. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK\n" ));
  302. else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid )
  303. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_UNLOCK\n" ));
  304. else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid )
  305. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT\n" ));
  306. else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid )
  307. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_MOUNT\n" ));
  308. else if ( GUID_IO_MEDIA_ARRIVAL == pDevBroadcastHandle->dbch_eventguid )
  309. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_ARRIVAL\n" ));
  310. else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid )
  311. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_REMOVAL\n" ));
  312. else
  313. ciDebugOut(( DEB_CI_MOUNT, " eventguid: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  314. pDevBroadcastHandle->dbch_eventguid.Data1,
  315. pDevBroadcastHandle->dbch_eventguid.Data2,
  316. pDevBroadcastHandle->dbch_eventguid.Data3,
  317. pDevBroadcastHandle->dbch_eventguid.Data4[0], pDevBroadcastHandle->dbch_eventguid.Data4[1],
  318. pDevBroadcastHandle->dbch_eventguid.Data4[2], pDevBroadcastHandle->dbch_eventguid.Data4[3],
  319. pDevBroadcastHandle->dbch_eventguid.Data4[4], pDevBroadcastHandle->dbch_eventguid.Data4[5],
  320. pDevBroadcastHandle->dbch_eventguid.Data4[6], pDevBroadcastHandle->dbch_eventguid.Data4[7] ));
  321. }
  322. }
  323. else
  324. {
  325. ciDebugOut(( DEB_CI_MOUNT, " handle: %#x\n", pDevBroadcastHandle->dbch_handle ));
  326. ciDebugOut(( DEB_CI_MOUNT, " hdev_notify: %#x\n", pDevBroadcastHandle->dbch_hdevnotify ));
  327. ciDebugOut(( DEB_CI_MOUNT, " nameoffset: %#x\n", pDevBroadcastHandle->dbch_nameoffset ));
  328. if ( GUID_IO_VOLUME_LOCK_FAILED == pDevBroadcastHandle->dbch_eventguid )
  329. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK_FAILED\n" ));
  330. else if ( GUID_IO_VOLUME_DISMOUNT_FAILED == pDevBroadcastHandle->dbch_eventguid )
  331. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT_FAILED\n" ));
  332. else if ( GUID_IO_VOLUME_LOCK == pDevBroadcastHandle->dbch_eventguid )
  333. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_LOCK\n" ));
  334. else if ( GUID_IO_VOLUME_UNLOCK == pDevBroadcastHandle->dbch_eventguid )
  335. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_UNLOCK\n" ));
  336. else if ( GUID_IO_VOLUME_DISMOUNT == pDevBroadcastHandle->dbch_eventguid )
  337. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_DISMOUNT\n" ));
  338. else if ( GUID_IO_VOLUME_MOUNT == pDevBroadcastHandle->dbch_eventguid )
  339. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_VOLUME_MOUNT\n" ));
  340. else if ( GUID_IO_MEDIA_ARRIVAL == pDevBroadcastHandle->dbch_eventguid )
  341. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_ARRIVAL\n" ));
  342. else if ( GUID_IO_MEDIA_REMOVAL == pDevBroadcastHandle->dbch_eventguid )
  343. ciDebugOut(( DEB_CI_MOUNT, " GUID_IO_MEDIA_REMOVAL\n" ));
  344. else
  345. ciDebugOut(( DEB_CI_MOUNT, " eventguid: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  346. pDevBroadcastHandle->dbch_eventguid.Data1,
  347. pDevBroadcastHandle->dbch_eventguid.Data2,
  348. pDevBroadcastHandle->dbch_eventguid.Data3,
  349. pDevBroadcastHandle->dbch_eventguid.Data4[0], pDevBroadcastHandle->dbch_eventguid.Data4[1],
  350. pDevBroadcastHandle->dbch_eventguid.Data4[2], pDevBroadcastHandle->dbch_eventguid.Data4[3],
  351. pDevBroadcastHandle->dbch_eventguid.Data4[4], pDevBroadcastHandle->dbch_eventguid.Data4[5],
  352. pDevBroadcastHandle->dbch_eventguid.Data4[6], pDevBroadcastHandle->dbch_eventguid.Data4[7] ));
  353. }
  354. return sc;
  355. } //ProcessCustomEvent
  356. //+----------------------------------------------------------------------------
  357. //
  358. // Function: CiSvcMsgProc
  359. //
  360. // Synopsis: Message handler for Ci service
  361. //
  362. // Arguments: [dwControl] - the message.
  363. //
  364. // Returns: Nothing
  365. //
  366. // History: 06-Jun-94 DwightKr Created
  367. // 06-23-98 KitmanH Updated for RegisterServiceCtrlHandlerEx
  368. // 07-30-98 KitmanH Return appropriate errors
  369. //
  370. // Notes: We need to keep the status between calls to this routine
  371. // since the service control manager may query the current
  372. // status at any time.
  373. //
  374. //-----------------------------------------------------------------------------
  375. DWORD WINAPI CiSvcMsgProc( DWORD dwControl,
  376. DWORD dwEventType,
  377. PVOID pEventData,
  378. PVOID pContext )
  379. {
  380. ciDebugOut(( DEB_ITRACE,
  381. "Ci 0Service: Executing service control command 0x%x\n",
  382. dwControl ));
  383. Win4Assert( pContext );
  384. BOOL fShutdown = FALSE;
  385. DWORD dwError = NO_ERROR;
  386. TRY
  387. {
  388. switch (dwControl)
  389. {
  390. case SERVICE_CONTROL_STOP:
  391. case SERVICE_CONTROL_SHUTDOWN:
  392. UpdateServiceStatus( NO_ERROR );
  393. if ( SERVICE_STOP_PENDING != dwCiSvcStatus )
  394. {
  395. ciDebugOut(( DEB_ITRACE, "About to stop\n" ));
  396. dwCiSvcStatus = SERVICE_STOP_PENDING;
  397. if ( ! g_fSCMThreadIsGone )
  398. StopCiSvcWork( eNetStop );
  399. }
  400. ciDebugOut( (DEB_ITRACE, "Ci Service: Done shutting down service\n" ));
  401. //
  402. // Calling UpdateServiceStatus() after doing the shutdown is
  403. // causing the service to hang. Not calling solved the problem
  404. // and so I am preventing it from being called.
  405. //
  406. fShutdown = TRUE;
  407. break;
  408. case SERVICE_CONTROL_PAUSE:
  409. if ( SERVICE_PAUSED != dwCiSvcStatus &&
  410. SERVICE_STOP_PENDING != dwCiSvcStatus )
  411. {
  412. ciDebugOut(( DEB_ITRACE, "About to pause\n" ));
  413. if ( ! g_fSCMThreadIsGone )
  414. StopCiSvcWork( eNetPause );
  415. dwCiSvcStatus = SERVICE_PAUSED;
  416. ciDebugOut(( DEB_ITRACE, "Ci Service: Done pausing the service\n" ));
  417. }
  418. break;
  419. case SERVICE_CONTROL_CONTINUE:
  420. if ( SERVICE_PAUSED == dwCiSvcStatus &&
  421. SERVICE_STOP_PENDING != dwCiSvcStatus )
  422. {
  423. ciDebugOut(( DEB_ITRACE, "About to continue\n" ));
  424. if ( ! g_fSCMThreadIsGone )
  425. StopCiSvcWork( eNetContinue );
  426. dwCiSvcStatus = SERVICE_RUNNING;
  427. }
  428. ciDebugOut(( DEB_ITRACE, "Ci Service: Done continuing the service\n" ));
  429. break;
  430. case SERVICE_CONTROL_DEVICEEVENT:
  431. // a dismount or remount may have occurred
  432. ciDebugOut(( DEB_ITRACE, "SERVICE_CONTROL_DEVICEEVENT received, event = %#x\n",
  433. dwEventType ));
  434. {
  435. SCODE sc = S_OK;
  436. if ( DBT_CUSTOMEVENT == dwEventType )
  437. {
  438. ciDebugOut(( DEB_ITRACE, "It is a custom event\n" ));
  439. if ( ! g_fSCMThreadIsGone )
  440. sc = ProcessCustomEvent( pEventData, pContext );
  441. ciDebugOut(( DEB_ITRACE, "Done processing custom event\n" ));
  442. }
  443. // convert sc into a WIN32 error and return it
  444. ciDebugOut(( DEB_ITRACE, "Process Custom Event returned sc = %#x\n", sc ));
  445. dwError = HRESULTTOWIN32(sc);
  446. }
  447. break;
  448. case SERVICE_CONTROL_INTERROGATE:
  449. break;
  450. default:
  451. ciDebugOut(( DEB_CI_MOUNT, "service control not implemented %d\n", dwControl ));
  452. dwError = ERROR_CALL_NOT_IMPLEMENTED;
  453. break;
  454. }
  455. UpdateServiceStatus( NO_ERROR );
  456. }
  457. CATCH (CException, e)
  458. {
  459. ciDebugOut(( DEB_ITRACE, "Ci Service: Error from callback = 0x%x\n", e.GetErrorCode() ));
  460. }
  461. END_CATCH
  462. ciDebugOut(( DEB_ITRACE, "Getting out of CiSvcMsgProc\n" ));
  463. return dwError;
  464. } //CiSvcMsgProc
  465. //+-------------------------------------------------------------------------
  466. //
  467. // Function: CiServiceMain, public
  468. //
  469. // Purpose: Service entry point
  470. //
  471. // Arguments: [dwNumServiceArgs] - number of arguments passed
  472. // [awcsServiceArgs] - arguments
  473. //
  474. // History: 06-Jun-94 DwightKr Created
  475. //
  476. //--------------------------------------------------------------------------
  477. extern CEventSem * g_pevtPauseContinue;
  478. void CiSvcMain(
  479. DWORD dwNumServiceArgs,
  480. LPWSTR * awcsServiceArgs )
  481. {
  482. // The service control manager crofted up this thread, so we have to
  483. // establish the exception state, etc.
  484. CTranslateSystemExceptions translate;
  485. TRY
  486. {
  487. CDrvNotifArray DrvNotifArray;
  488. ciDebugOut( (DEB_ITRACE, "Ci Service: Attempting to register service\n" ));
  489. // Register service handler with service controller
  490. g_hTheCiSvc = RegisterServiceCtrlHandlerEx( wcsCiSvcName,
  491. CiSvcMsgProc,
  492. &DrvNotifArray );
  493. if (0 == g_hTheCiSvc)
  494. {
  495. ciDebugOut(( DEB_ERROR, "Unable to register ci service\n" ));
  496. THROW( CException( E_FAIL ) );
  497. }
  498. CEventSem evtPauseContinue;
  499. g_pevtPauseContinue = &evtPauseContinue;
  500. UpdateServiceStatus( NO_ERROR );
  501. CRegAccess reg( RTL_REGISTRY_CONTROL, wcsRegAdmin );
  502. if ( 1 != reg.Read( wcsPreventCisvcParam, (ULONG) 0 ) )
  503. {
  504. dwCiSvcStatus = SERVICE_RUNNING;
  505. UpdateServiceStatus( NO_ERROR );
  506. #if CIDBG == 1
  507. BOOL fRun = TRUE; // FALSE --> Stop
  508. TRY
  509. {
  510. ULONG ulVal = reg.Read( L"StopCiSvcOnStartup", (ULONG)0 );
  511. if ( 1 == ulVal )
  512. fRun = FALSE;
  513. }
  514. CATCH( CException, e )
  515. {
  516. }
  517. END_CATCH;
  518. unsigned long OldWin4AssertLevel = SetWin4AssertLevel(ASSRT_MESSAGE | ASSRT_POPUP);
  519. Win4Assert( fRun );
  520. SetWin4AssertLevel( OldWin4AssertLevel );
  521. #endif // CIDBG
  522. // Register for pnp notifications on drives used by catalogs
  523. DrvNotifArray.RegisterCatForNotifInRegistry();
  524. //
  525. // Register for pnp notifications on removable drives not yet
  526. // registered if the registry flag says it's appropriate.
  527. //
  528. if ( 0 != reg.Read( wcsMountRemovableCatalogs,
  529. CI_AUTO_MOUNT_CATALOGS_DEFAULT ) )
  530. DrvNotifArray.RegisterRemovableDrives();
  531. StartCiSvcWork( DrvNotifArray );
  532. DrvNotifArray.UnregisterDeviceNotifications();
  533. ciDebugOut(( DEB_ITRACE, "service_stopped from CiSvcMain\n" ));
  534. }
  535. else
  536. {
  537. CEventLog eventLog( NULL, wcsCiEventSource );
  538. CEventItem item( EVENTLOG_INFORMATION_TYPE,
  539. CI_SERVICE_CATEGORY,
  540. MSG_CI_SERVICE_SUPPRESSED,
  541. 0 );
  542. eventLog.ReportEvent( item );
  543. }
  544. dwCiSvcStatus = SERVICE_STOPPED;
  545. UpdateServiceStatus( NO_ERROR );
  546. ciDebugOut(( DEB_ITRACE, "Shutdown is done\n" ));
  547. CoFreeUnusedLibraries();
  548. ciDebugOut( (DEB_ITRACE, "Ci Service: Leaving CiSvcMain()\n" ));
  549. }
  550. CATCH (CException, e)
  551. {
  552. ciDebugOut( (DEB_ITRACE, "Ci Service: Detected error 0x%x\n", e.GetErrorCode() ));
  553. }
  554. END_CATCH
  555. g_pevtPauseContinue = 0;
  556. g_fSCMThreadIsGone = TRUE;
  557. } //CiSvcMain
  558. //+----------------------------------------------------------------------------
  559. //
  560. // Function: SvcEntry_CiSvc
  561. //
  562. // Synopsis: Entry from services.exe
  563. //
  564. // This is currently broken since services doesn't unload
  565. // query.dll when the service is stopped, and our global
  566. // variables don't expect to be used again when the service
  567. // is restarted. It's probably a week of work to fix this!
  568. // We don't do this anyway so it doesn't matter.
  569. //
  570. // History: 05-Jan-97 dlee Created
  571. //
  572. //-----------------------------------------------------------------------------
  573. void SvcEntry_CiSvc(
  574. DWORD NumArgs,
  575. LPWSTR * ArgsArray,
  576. void * pSvcsGlobalData,
  577. HANDLE SvcRefHandle )
  578. {
  579. CiSvcMain( NumArgs, ArgsArray );
  580. } //SvcEntry_CiSvc