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

  1. /*++ '
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. STISvc.CPP
  5. Abstract:
  6. Code for performing STI service related functions ( Start/Stop etc)
  7. It is separated from main process code make it possible to share process for
  8. multiple services ever needed
  9. Author:
  10. Vlad Sadovsky (vlads) 09-20-97
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. 22-Sep-1997 VladS created
  15. --*/
  16. //
  17. // Include Headers
  18. //
  19. #include "precomp.h"
  20. #include "stiexe.h"
  21. #include "device.h"
  22. #include <stisvc.h>
  23. #include <regstr.h>
  24. #include <devguid.h>
  25. typedef LONG NTSTATUS;
  26. #include <svcs.h>
  27. extern HWND g_hStiServiceWindow;
  28. extern BOOL
  29. StiRefreshWithDelay(
  30. ULONG ulDelay,
  31. WPARAM wParam,
  32. LPARAM lParam);
  33. //
  34. // Delay in milliseconds to wait before processing PnP device event
  35. //
  36. #define DEVICEEVENT_WAIT_TIME 1000
  37. //
  38. // Local variables and types definitions
  39. //
  40. //
  41. // Service status data
  42. //
  43. SERVICE_STATUS g_StiServiceStatus;
  44. //
  45. // Handle of registered service, used for updating running status
  46. //
  47. SERVICE_STATUS_HANDLE g_StiServiceStatusHandle;
  48. //
  49. // Initialization flag
  50. //
  51. BOOL g_fStiServiceInitialized = FALSE;
  52. //
  53. // What type of sink to use
  54. //
  55. #ifdef WINNT
  56. BOOL g_fUseServiceCtrlSink = TRUE;
  57. #else
  58. BOOL g_fUseServiceCtrlSink = FALSE;
  59. #endif
  60. //
  61. // Hidden service window
  62. //
  63. HWND g_hStiServiceWindow = NULL;
  64. //
  65. // Notification sink for PnP notifications
  66. //
  67. HDEVNOTIFY g_hStiServiceNotificationSink = NULL;
  68. //
  69. // Shutdown event
  70. //
  71. HANDLE hShutdownEvent = NULL;
  72. #ifdef WINNT
  73. //
  74. // Local prototypes
  75. //
  76. BOOL
  77. WINAPI
  78. InitializeNTSecurity(
  79. VOID
  80. );
  81. BOOL
  82. WINAPI
  83. TerminateNTSecurity(
  84. VOID
  85. );
  86. #endif
  87. //
  88. // Service status variable dispatch table
  89. //
  90. SERVICE_TABLE_ENTRY ServiceDispatchTable[] = {
  91. { STI_SERVICE_NAME, StiServiceMain },
  92. { NULL, NULL }
  93. };
  94. //
  95. // Code section
  96. //
  97. DWORD
  98. WINAPI
  99. UpdateServiceStatus(
  100. IN DWORD dwState,
  101. IN DWORD dwWin32ExitCode,
  102. IN DWORD dwWaitHint )
  103. /*++
  104. Description:
  105. Updates the local copy status of service controller status
  106. and reports it to the service controller.
  107. Arguments:
  108. dwState - New service state.
  109. dwWin32ExitCode - Service exit code.
  110. dwWaitHint - Wait hint for lengthy state transitions.
  111. Returns:
  112. NO_ERROR on success and returns Win32 error if failure.
  113. On success the status is reported to service controller.
  114. --*/
  115. {
  116. const TCHAR* szStateDbgMsg[] = {
  117. TEXT("SERVICE_UNKNOWN "), // 0x00000000
  118. TEXT("SERVICE_STOPPED "), // 0x00000001
  119. TEXT("SERVICE_START_PENDING "), // 0x00000002
  120. TEXT("SERVICE_STOP_PENDING "), // 0x00000003
  121. TEXT("SERVICE_RUNNING "), // 0x00000004
  122. TEXT("SERVICE_CONTINUE_PENDING "), // 0x00000005
  123. TEXT("SERVICE_PAUSE_PENDING "), // 0x00000006
  124. TEXT("SERVICE_PAUSED "), // 0x00000007
  125. TEXT("SERVICE_UNKNOWN "), // 0x00000008
  126. };
  127. DWORD dwError = NO_ERROR;
  128. //
  129. // If state is changing - save the new one
  130. //
  131. if (dwState) {
  132. g_StiServiceStatus.dwCurrentState = dwState;
  133. }
  134. g_StiServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
  135. g_StiServiceStatus.dwWaitHint = dwWaitHint;
  136. //
  137. // If we are in the middle of lengthy operation, increment checkpoint value
  138. //
  139. if ((g_StiServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  140. (g_StiServiceStatus.dwCurrentState == SERVICE_STOPPED) ) {
  141. g_StiServiceStatus.dwCheckPoint = 0;
  142. }
  143. else {
  144. g_StiServiceStatus.dwCheckPoint++;
  145. }
  146. #ifdef WINNT
  147. //
  148. // Now update SCM running database
  149. //
  150. if ( g_fRunningAsService ) {
  151. DBG_TRC(("Updating service status. CurrentState=%S StateCode=%d",
  152. g_StiServiceStatus.dwCurrentState < (sizeof(szStateDbgMsg) / sizeof(TCHAR *)) ?
  153. szStateDbgMsg[g_StiServiceStatus.dwCurrentState] : szStateDbgMsg[0],
  154. g_StiServiceStatus.dwCurrentState));
  155. if( !SetServiceStatus( g_StiServiceStatusHandle, &g_StiServiceStatus ) ) {
  156. dwError = GetLastError();
  157. } else {
  158. dwError = NO_ERROR;
  159. }
  160. }
  161. #endif
  162. return ( dwError);
  163. } // UpdateServiceStatus()
  164. DWORD
  165. WINAPI
  166. StiServiceInitialize(
  167. VOID
  168. )
  169. /*++
  170. Routine Description:
  171. Service initialization, creates all needed data structures
  172. Nb: This routine has upper limit for execution time, so if it takes too much time
  173. separate thread will have to be created to queue initialization work
  174. Arguments:
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. HRESULT hres;
  180. DWORD dwError;
  181. DBG_FN(StiServiceInitialize);
  182. #ifdef MAXDEBUG
  183. DBG_TRC(("Start service entered"));
  184. #endif
  185. g_StiFileLog->ReportMessage(STI_TRACE_INFORMATION,
  186. MSG_TRACE_SVC_INIT,TEXT("STISVC"),0);
  187. //
  188. // Create shutdown event.
  189. //
  190. hShutdownEvent = CreateEvent( NULL, // lpsaSecurity
  191. TRUE, // fManualReset
  192. FALSE, // fInitialState
  193. NULL ); // lpszEventName
  194. if( hShutdownEvent == NULL ) {
  195. dwError = GetLastError();
  196. return dwError;
  197. }
  198. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  199. //
  200. // Initialize active device list
  201. //
  202. InitializeDeviceList();
  203. //
  204. // Start RPC servicing
  205. //
  206. UpdateServiceStatus(SERVICE_START_PENDING,NOERROR,START_HINT);
  207. if (NOERROR != StartRpcServerListen()) {
  208. dwError = GetLastError();
  209. DBG_ERR(("StiService failed to start RPC listen. ErrorCode=%d", dwError));
  210. goto Cleanup;
  211. }
  212. #ifdef WINNT
  213. //
  214. // Allow setting window to foreground
  215. //
  216. dwError = AllowSetForegroundWindow(GetCurrentProcessId()); // ASFW_ANY
  217. DBG_TRC((" AllowSetForegroundWindow is called for id:%d . Ret code=%d. LastError=%d ",
  218. GetCurrentProcessId(),
  219. dwError,
  220. ::GetLastError()));
  221. #endif
  222. //
  223. // Create hidden window for receiving PnP notifications
  224. //
  225. if (!CreateServiceWindow()) {
  226. dwError = GetLastError();
  227. DBG_ERR(("Failed to create hidden window for PnP notifications. ErrorCode=%d",dwError));
  228. goto Cleanup;
  229. }
  230. #ifdef WINNT
  231. //
  232. // Initialize NT security parameters
  233. //
  234. InitializeNTSecurity();
  235. #endif
  236. // No longer needed - the equivalent exists in CWiaDevMan
  237. // g_pDeviceInfoSet = new DEVICE_INFOSET(GUID_DEVCLASS_IMAGE);
  238. g_pDeviceInfoSet = NULL;
  239. //
  240. // Initiate device list refresh
  241. //
  242. //::PostMessage(g_hStiServiceWindow,
  243. // STIMON_MSG_REFRESH,
  244. // STIMON_MSG_REFRESH_REREAD,
  245. // STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
  246. // | STIMON_MSG_BOOT // This shows this is the first device enumeration - no need to generate events
  247. // );
  248. //
  249. // Finally we are running
  250. //
  251. g_fStiServiceInitialized = TRUE;
  252. UpdateServiceStatus(SERVICE_RUNNING,NOERROR,0);
  253. #ifdef MAXDEBUG
  254. g_EventLog->LogEvent(MSG_STARTUP,
  255. 0,
  256. (LPCSTR *)NULL);
  257. #endif
  258. g_StiFileLog->ReportMessage(STI_TRACE_INFORMATION,MSG_STARTUP);
  259. return NOERROR;
  260. Cleanup:
  261. //
  262. // Something failed , call stop routine to clean up
  263. //
  264. StiServiceStop();
  265. return dwError;
  266. } // StiServiceInitialize
  267. VOID
  268. WINAPI
  269. StiServiceStop(
  270. VOID
  271. )
  272. /*++
  273. Routine Description:
  274. Stopping STI service
  275. Arguments:
  276. Return Value:
  277. None.
  278. --*/
  279. {
  280. DBG_FN(StiServiceStop);
  281. DBG_TRC(("Service is exiting"));
  282. UpdateServiceStatus(SERVICE_STOP_PENDING,NOERROR,START_HINT);
  283. #ifdef WINNT
  284. //
  285. // Clean up PnP notification handles
  286. //
  287. if (g_hStiServiceNotificationSink && g_hStiServiceNotificationSink!=INVALID_HANDLE_VALUE) {
  288. UnregisterDeviceNotification(g_hStiServiceNotificationSink);
  289. g_hStiServiceNotificationSink = NULL;
  290. }
  291. for (UINT uiIndex = 0;
  292. (uiIndex < NOTIFICATION_GUIDS_NUM );
  293. uiIndex++)
  294. {
  295. if (g_phDeviceNotificationsSinkArray[uiIndex] && (g_phDeviceNotificationsSinkArray[uiIndex]!=INVALID_HANDLE_VALUE)) {
  296. UnregisterDeviceNotification(g_phDeviceNotificationsSinkArray[uiIndex]);
  297. g_phDeviceNotificationsSinkArray[uiIndex] = NULL;
  298. }
  299. }
  300. #endif
  301. //
  302. // Stop item scheduler
  303. //
  304. SchedulerSetPauseState(TRUE);
  305. //
  306. // Destroy service window
  307. //
  308. if (g_hStiServiceWindow) {
  309. DestroyWindow(g_hStiServiceWindow);
  310. g_hStiServiceWindow = NULL;
  311. }
  312. #ifdef WINNT
  313. //
  314. // Free security objects
  315. //
  316. if(!TerminateNTSecurity()) {
  317. DBG_ERR(("Failed to clean up security objects"));
  318. }
  319. #endif
  320. //
  321. // Cancel all client calls
  322. //
  323. WiaEventNotifier *pOldWiaEventNotifier = g_pWiaEventNotifier;
  324. InterlockedCompareExchangePointer((VOID**)&g_pWiaEventNotifier, NULL, g_pWiaEventNotifier);
  325. if (pOldWiaEventNotifier)
  326. {
  327. delete pOldWiaEventNotifier;
  328. pOldWiaEventNotifier = NULL;
  329. }
  330. // Since using AsyncRPC, we would rather just exit the process than shut the RPC
  331. // server down. This is becuase even one outstanding AsyncRPC call
  332. // will cause a hang attempting to stop the RPC server.
  333. // It is much more preferable for us to just exit than introduce the
  334. // possiblility of a hang, so we'll just exit and let the OS clean up for us.
  335. //
  336. // Stop RPC servicing
  337. //
  338. //if(NOERROR != StopRpcServerListen()) {
  339. // DBG_ERR(("Failed to stop RpcServerListen"));
  340. //}
  341. //
  342. // Terminate device list
  343. //
  344. TerminateDeviceList();
  345. // Destroy info set
  346. //if (g_pDeviceInfoSet) {
  347. // delete g_pDeviceInfoSet;
  348. // }
  349. //
  350. // Resume scheduling to allow for internal work items to complete
  351. // At this point all device related items should've been purged by
  352. // device object destructors
  353. //
  354. SchedulerSetPauseState(FALSE);
  355. //
  356. // Finish
  357. //
  358. g_fStiServiceInitialized = FALSE;
  359. #ifdef MAXDEBUG
  360. g_EventLog->LogEvent(MSG_STOP,
  361. 0,
  362. (LPCSTR *)NULL);
  363. #endif
  364. //
  365. // UnRegister the WiaDevice manager from the ROT
  366. //
  367. InitWiaDevMan(WiaUninitialize);
  368. //
  369. // Signal shutdown
  370. //
  371. SetEvent(hShutdownEvent);
  372. //UpdateServiceStatus(SERVICE_STOPPED,NOERROR,0);
  373. } // StiServiceStop
  374. VOID
  375. WINAPI
  376. StiServicePause(
  377. VOID
  378. )
  379. /*++
  380. Routine Description:
  381. Pausing STI service
  382. Arguments:
  383. Return Value:
  384. None.
  385. --*/
  386. {
  387. DBG_FN(StiServicePause);
  388. //
  389. // System is suspending - take snapshot of currently active devices
  390. //
  391. UpdateServiceStatus(SERVICE_PAUSE_PENDING,NOERROR,PAUSE_HINT);
  392. if ( (g_StiServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  393. (g_StiServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ){
  394. // Stop running work items queue
  395. //
  396. // Nb: if refresh routine is scheduled to run as work item, this is a problem
  397. //
  398. SchedulerSetPauseState(TRUE);
  399. /* The equivalent done by HandlePowerEvent
  400. SendMessage(g_hStiServiceWindow,
  401. STIMON_MSG_REFRESH,
  402. STIMON_MSG_REFRESH_SUSPEND,
  403. STIMON_MSG_REFRESH_EXISTING
  404. );
  405. */
  406. }
  407. } // StiServicePause
  408. VOID
  409. WINAPI
  410. StiServiceResume(
  411. VOID
  412. )
  413. /*++
  414. Routine Description:
  415. Resuming STI service
  416. Arguments:
  417. Return Value:
  418. None.
  419. --*/
  420. {
  421. DBG_FN(StiServiceResume);
  422. SchedulerSetPauseState(FALSE);
  423. PostMessage(g_hStiServiceWindow,
  424. STIMON_MSG_REFRESH,
  425. STIMON_MSG_REFRESH_RESUME,
  426. STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
  427. );
  428. UpdateServiceStatus(SERVICE_RUNNING,NOERROR,0);
  429. } // StiServiceResume
  430. ULONG
  431. WINAPI
  432. StiServiceCtrlHandler(
  433. IN DWORD dwOperation,
  434. DWORD dwEventType,
  435. PVOID EventData,
  436. PVOID pData
  437. )
  438. /*++
  439. Routine Description:
  440. STI service control dispatch function
  441. Arguments:
  442. SCM OpCode
  443. Return Value:
  444. None.
  445. --*/
  446. {
  447. ULONG retval = NO_ERROR;
  448. DBG_TRC(("Entering CtrlHandler OpCode=%d",dwOperation));
  449. switch (dwOperation) {
  450. case SERVICE_CONTROL_STOP:
  451. StiServiceStop();
  452. break;
  453. case SERVICE_CONTROL_PAUSE:
  454. StiServicePause();
  455. break;
  456. case SERVICE_CONTROL_CONTINUE:
  457. StiServiceResume();
  458. break;
  459. case SERVICE_CONTROL_SHUTDOWN:
  460. StiServiceStop();
  461. break;
  462. case SERVICE_CONTROL_PARAMCHANGE:
  463. //
  464. // Refresh device list.
  465. //
  466. g_pMsgHandler->HandleCustomEvent(SERVICE_CONTROL_PARAMCHANGE);
  467. break;
  468. case SERVICE_CONTROL_INTERROGATE:
  469. // Report current state and status
  470. UpdateServiceStatus(0,NOERROR,0);
  471. break;
  472. case SERVICE_CONTROL_DEVICEEVENT:
  473. //
  474. // PnP event.
  475. //
  476. //
  477. // Until our PnP issues are resolved, keep logging PnP events so we know
  478. // whether we received it or not...
  479. //
  480. DBG_WRN(("::StiServiceCtrlHandler, Received PnP event..."));
  481. g_pMsgHandler->HandlePnPEvent(dwEventType, EventData);
  482. break;
  483. case SERVICE_CONTROL_POWEREVENT:
  484. //
  485. // Power management event
  486. //
  487. retval = g_pMsgHandler->HandlePowerEvent(dwEventType, EventData);
  488. break;
  489. case STI_SERVICE_CONTROL_REFRESH:
  490. //
  491. // Refresh device list.
  492. //
  493. DBG_TRC(("::StiServiceCtrlHandler, Received STI_SERVICE_CONTROL_REFRESH"));
  494. g_pMsgHandler->HandleCustomEvent(STI_SERVICE_CONTROL_REFRESH);
  495. break;
  496. case STI_SERVICE_CONTROL_EVENT_REREAD:
  497. //
  498. // Refresh device list.
  499. //
  500. DBG_TRC(("::StiServiceCtrlHandler, Received STI_SERVICE_CONTROL_EVENT_REREAD"));
  501. g_pMsgHandler->HandleCustomEvent(STI_SERVICE_CONTROL_EVENT_REREAD);
  502. break;
  503. case STI_SERVICE_CONTROL_LPTENUM:
  504. //
  505. // Enumerate LPT port.
  506. //
  507. EnumLpt();
  508. break;
  509. default:
  510. // Unknown opcode
  511. ;
  512. }
  513. DBG_TRC(("Exiting CtrlHandler"));
  514. return retval;
  515. } // StiServiceCtrlHandler
  516. BOOL RegisterServiceControlHandler()
  517. {
  518. DWORD dwError = 0;
  519. #ifdef WINNT
  520. g_StiServiceStatusHandle = RegisterServiceCtrlHandlerEx(
  521. STI_SERVICE_NAME,
  522. StiServiceCtrlHandler,
  523. (LPVOID)STI_SERVICE__DATA
  524. );
  525. if(!g_StiServiceStatusHandle) {
  526. // Could not register with SCM
  527. dwError = GetLastError();
  528. DBG_ERR(("Failed to register CtrlHandler,ErrorCode=%d",dwError));
  529. return FALSE;
  530. }
  531. #endif
  532. return TRUE;
  533. }
  534. VOID
  535. WINAPI
  536. StiServiceMain(
  537. IN DWORD argc,
  538. IN LPTSTR *argv
  539. )
  540. /*++
  541. Routine Description:
  542. This is service main entry, that is called by SCM
  543. Arguments:
  544. Return Value:
  545. None.
  546. --*/
  547. {
  548. DWORD dwError;
  549. DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
  550. DBG_FN(StiServiceMain);
  551. #ifdef MAXDEBUG
  552. DBG_TRC(("StiServiceMain entered"));
  553. #endif
  554. //
  555. // REMOVE: This is not actually an error, but we will use error logging to gurantee
  556. // it always get written to the log. This should be removed as soon as we know what
  557. // causes #347835.
  558. //
  559. SYSTEMTIME SysTime;
  560. GetLocalTime(&SysTime);
  561. DBG_ERR(("*> StiServiceMain entered, Time: %d/%02d/%02d %02d:%02d:%02d:%02d",
  562. SysTime.wYear,
  563. SysTime.wMonth,
  564. SysTime.wDay,
  565. SysTime.wHour,
  566. SysTime.wMinute,
  567. SysTime.wSecond,
  568. SysTime.wMilliseconds));
  569. g_StiServiceStatus.dwServiceType = STI_SVC_SERVICE_TYPE;
  570. g_StiServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  571. g_StiServiceStatus.dwControlsAccepted= SERVICE_ACCEPT_STOP |
  572. SERVICE_ACCEPT_SHUTDOWN |
  573. SERVICE_ACCEPT_PARAMCHANGE |
  574. SERVICE_ACCEPT_POWEREVENT;
  575. g_StiServiceStatus.dwWin32ExitCode = NO_ERROR;
  576. g_StiServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
  577. g_StiServiceStatus.dwCheckPoint = 0;
  578. g_StiServiceStatus.dwWaitHint = 0;
  579. dwError = StiServiceInitialize();
  580. if (NOERROR == dwError) {
  581. #ifdef WINNT
  582. if (g_fUseServiceCtrlSink && !g_hStiServiceNotificationSink) {
  583. DBG_WRN(("::StiServiceMain, About to register for PnP..."));
  584. //
  585. // Register for the PnP Device Interface change notifications
  586. //
  587. memset(&PnPFilter, 0, sizeof(PnPFilter));
  588. PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  589. PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  590. PnPFilter.dbcc_reserved = 0x0;
  591. PnPFilter.dbcc_classguid = *g_pguidDeviceNotificationsGuid;
  592. //memcpy(&PnPFilter.dbcc_classguid,
  593. // (LPGUID) g_pguidDeviceNotificationsGuid,
  594. // sizeof(GUID));
  595. g_hStiServiceNotificationSink = RegisterDeviceNotification(
  596. (HANDLE) g_StiServiceStatusHandle,
  597. &PnPFilter,
  598. DEVICE_NOTIFY_SERVICE_HANDLE
  599. );
  600. if (NULL == g_hStiServiceNotificationSink) {
  601. //
  602. // Could not register with PnP - attempt to use window handle
  603. //
  604. g_fUseServiceCtrlSink = FALSE;
  605. }
  606. //
  607. // Separately from main Image interface , register list of optional device interfaces
  608. // we will monitor to allow parameters refresh.
  609. //
  610. for (UINT uiIndex = 0;
  611. (uiIndex < NOTIFICATION_GUIDS_NUM ) && (!::IsEqualGUID(g_pguidDeviceNotificationsGuidArray[uiIndex],GUID_NULL));
  612. uiIndex++)
  613. {
  614. ::ZeroMemory(&PnPFilter, sizeof(PnPFilter));
  615. PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  616. PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  617. PnPFilter.dbcc_reserved = 0x0;
  618. PnPFilter.dbcc_classguid = g_pguidDeviceNotificationsGuidArray[uiIndex];
  619. g_phDeviceNotificationsSinkArray[uiIndex] = RegisterDeviceNotification(
  620. (HANDLE) g_StiServiceStatusHandle,
  621. &PnPFilter,
  622. DEVICE_NOTIFY_SERVICE_HANDLE
  623. );
  624. DBG_TRC(("Registering optional interface #%d . Returned handle=%X",
  625. uiIndex,g_phDeviceNotificationsSinkArray[uiIndex]));
  626. }
  627. }
  628. #else
  629. // Windows 98 case
  630. g_fUseServiceCtrlSink = FALSE;
  631. #endif
  632. //
  633. // Service initialized , process command line arguments
  634. //
  635. BOOL fVisualize = FALSE;
  636. BOOL fVisualizeRequest = FALSE;
  637. TCHAR cOption;
  638. UINT iCurrentOption = 0;
  639. for (iCurrentOption=0;
  640. iCurrentOption < argc ;
  641. iCurrentOption++ ) {
  642. cOption = *argv[iCurrentOption];
  643. // pszT = argv[iCurrentOption]+ 2 * sizeof(TCHAR);
  644. switch ((TCHAR)LOWORD(::CharUpper((LPTSTR)cOption))) {
  645. case 'V':
  646. fVisualizeRequest = TRUE;
  647. fVisualize = TRUE;
  648. break;
  649. case 'H':
  650. fVisualizeRequest = TRUE;
  651. fVisualize = FALSE;
  652. break;
  653. default:
  654. break;
  655. }
  656. if (fVisualizeRequest ) {
  657. VisualizeServer(fVisualizeRequest);
  658. }
  659. }
  660. //
  661. // Wait for shutdown processing messages. We make ourselves alertable so we
  662. // can receive Shell's Volume notifications via APCs. If we're woken
  663. // up to process the APC, then we must wait again.
  664. //
  665. while(WaitForSingleObjectEx(hShutdownEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION);
  666. #ifndef WINNT
  667. //Don't use windows messaging on NT
  668. //
  669. // Close down message pump
  670. //
  671. if (g_dwMessagePumpThreadId) {
  672. // Indicate we are entering shutdown
  673. g_fServiceInShutdown = TRUE;
  674. PostThreadMessage(g_dwMessagePumpThreadId, WM_QUIT, 0, 0L );
  675. }
  676. #endif
  677. CloseHandle( hShutdownEvent );
  678. hShutdownEvent = NULL;
  679. }
  680. else {
  681. // Could not initialize service, service failed to start
  682. }
  683. //
  684. // REMOVE: This is not actually an error, but we will use error logging to gurantee
  685. // it always get written to the log. This should be removed as soon as we know what
  686. // causes #347835.
  687. //
  688. GetLocalTime(&SysTime);
  689. DBG_ERR(("<* StiServiceMain ended, Time: %d/%02d/%02d %02d:%02d:%02d:%02d",
  690. SysTime.wYear,
  691. SysTime.wMonth,
  692. SysTime.wDay,
  693. SysTime.wHour,
  694. SysTime.wMinute,
  695. SysTime.wSecond,
  696. SysTime.wMilliseconds));
  697. return;
  698. } // StiServiceMain
  699. HWND
  700. WINAPI
  701. CreateServiceWindow(
  702. VOID
  703. )
  704. /*++
  705. Routine Description:
  706. Arguments:
  707. Return Value:
  708. None.
  709. --*/
  710. {
  711. #ifndef WINNT
  712. //Don't use windows messaging on NT
  713. WNDCLASSEX wc;
  714. DWORD dwError;
  715. HWND hwnd = FindWindow(g_szStiSvcClassName,NULL);
  716. // Window should NOT exist at this time
  717. if (hwnd) {
  718. DPRINTF(DM_WARNING ,TEXT("Already registered window"));
  719. return NULL;
  720. }
  721. //
  722. // Create class
  723. //
  724. ZeroMemory(&wc, sizeof(wc));
  725. wc.cbSize = sizeof(WNDCLASSEX);
  726. wc.style = CS_GLOBALCLASS;
  727. wc.lpfnWndProc = StiSvcWinProc;
  728. wc.cbClsExtra = 0;
  729. wc.cbWndExtra = 0;
  730. wc.hInstance = g_hInst;
  731. wc.hIcon = NULL;
  732. wc.hCursor = NULL;
  733. wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
  734. wc.lpszClassName = g_szStiSvcClassName;
  735. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
  736. if (!RegisterClassEx(&wc)) {
  737. dwError = GetLastError();
  738. if (dwError != ERROR_CLASS_ALREADY_EXISTS) {
  739. DBG_ERR(("Failed to register window class ErrorCode=%d",dwError));
  740. return NULL;
  741. }
  742. }
  743. #ifndef WINNT
  744. #ifdef FE_IME
  745. // Disable IME processing on Millenium
  746. ImmDisableIME(::GetCurrentThreadId());
  747. #endif
  748. #endif
  749. g_hStiServiceWindow = CreateWindowEx(0, // Style bits
  750. g_szStiSvcClassName, // Class name
  751. g_szTitle, // Title
  752. WS_DISABLED , // Window style bits
  753. CW_USEDEFAULT, // x
  754. CW_USEDEFAULT, // y
  755. CW_USEDEFAULT, // h
  756. CW_USEDEFAULT, // w
  757. NULL, // Parent
  758. NULL, // Menu
  759. g_hInst, // Module instance
  760. NULL); // Options
  761. if (!g_hStiServiceWindow) {
  762. dwError = GetLastError();
  763. DBG_ERR(("Failed to create PnP window ErrorCode=%d"),dwError);
  764. }
  765. #else
  766. g_hStiServiceWindow = (HWND) INVALID_HANDLE_VALUE;
  767. #endif
  768. return g_hStiServiceWindow;
  769. } // CreateServiceWindow
  770. //
  771. // Installation routines.
  772. // They are here to simplify debugging and troubleshooting, called by switches
  773. // on command line
  774. //
  775. DWORD
  776. WINAPI
  777. StiServiceInstall(
  778. LPTSTR lpszUserName,
  779. LPTSTR lpszUserPassword
  780. )
  781. /*++
  782. Routine Description:
  783. Service installation function.
  784. Calls SCM to install STI service, which is running in user security context
  785. Arguments:
  786. Return Value:
  787. None.
  788. --*/
  789. {
  790. DWORD dwError = NOERROR;
  791. #ifdef WINNT
  792. SC_HANDLE hSCM = NULL;
  793. SC_HANDLE hService = NULL;
  794. TCHAR szDisplayName[MAX_PATH];
  795. //
  796. // Write the svchost group binding to stisvc
  797. //
  798. RegEntry SvcHostEntry(STI_SVC_HOST, HKEY_LOCAL_MACHINE);
  799. TCHAR szValue[MAX_PATH];
  800. lstrcpy (szValue, STI_SERVICE_NAME);
  801. // REG_MULTI_SZ is double null terminated
  802. *(szValue+lstrlen(szValue)+1) = TEXT('\0');
  803. SvcHostEntry.SetValue(STI_IMGSVC, STI_SERVICE_NAME, REG_MULTI_SZ);
  804. #endif // winnt
  805. //
  806. // Write parameters key for svchost
  807. //
  808. TCHAR szMyPath[MAX_PATH] = {0};
  809. TCHAR szSvcPath[MAX_PATH] = SYSTEM_PATH;
  810. LONG lLen;
  811. LONG lNameIndex = 0;
  812. if (lLen = ::GetModuleFileName(g_hInst, szMyPath, sizeof(szMyPath)/sizeof(szMyPath[0]) - 1)) {
  813. RegEntry SvcHostParm(STI_SERVICE_PARAMS, HKEY_LOCAL_MACHINE);
  814. //
  815. // Get the name of the service file (not including the path)
  816. //
  817. for (lNameIndex = lLen; lNameIndex > 0; lNameIndex--) {
  818. if (szMyPath[lNameIndex] == '\\') {
  819. lNameIndex++;
  820. break;
  821. }
  822. }
  823. if (lNameIndex) {
  824. #ifndef WINNT
  825. //
  826. // Windows 98 specific entry
  827. //
  828. TCHAR szWinDir[MAX_PATH] = TEXT("\0");
  829. if (!GetWindowsDirectory(szWinDir, MAX_PATH)) {
  830. DPRINTF(DM_ERROR ,TEXT("Error extracting Still Image service filename."));
  831. return dwError;
  832. }
  833. lstrcat(szWinDir, SYSTEM_PATH);
  834. lstrcpy(szSvcPath, szWinDir);
  835. #endif
  836. lstrcat(szSvcPath, &szMyPath[lNameIndex]);
  837. SvcHostParm.SetValue(REGSTR_SERVICEDLL, szSvcPath, PATH_REG_TYPE);
  838. } else {
  839. DBG_ERR(("Error extracting Still Image service filename."));
  840. }
  841. }
  842. else {
  843. DBG_ERR(("Failed to get my own path registering Still Image service . LastError=%d",
  844. ::GetLastError()));
  845. }
  846. // Add registry settings for event logging
  847. RegisterStiEventSources();
  848. return dwError;
  849. } //StiServiceInstall
  850. DWORD
  851. WINAPI
  852. StiServiceRemove(
  853. VOID
  854. )
  855. /*++
  856. Routine Description:
  857. Service removal function. This function calls SCM to remove the STI service.
  858. Arguments:
  859. None.
  860. Return Value:
  861. Return code. Return zero for success
  862. --*/
  863. {
  864. DWORD dwError = NOERROR;
  865. #ifdef WINNT
  866. SC_HANDLE hSCM = NULL;
  867. SC_HANDLE hService = NULL;
  868. SERVICE_STATUS ServiceStatus;
  869. UINT uiRetry = 10;
  870. __try {
  871. hSCM = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  872. if (!hSCM) {
  873. dwError = GetLastError();
  874. __leave;
  875. }
  876. hService = OpenService(
  877. hSCM,
  878. STI_SERVICE_NAME,
  879. SERVICE_ALL_ACCESS
  880. );
  881. if (!hService) {
  882. dwError = GetLastError();
  883. __leave;
  884. }
  885. //
  886. // Stop service first
  887. //
  888. if (ControlService( hService, SERVICE_CONTROL_STOP, &ServiceStatus )) {
  889. //
  890. // Wait a little
  891. //
  892. Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
  893. ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  894. while( QueryServiceStatus( hService, &ServiceStatus ) &&
  895. (SERVICE_STOP_PENDING == ServiceStatus.dwCurrentState)) {
  896. Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
  897. if (!uiRetry--) {
  898. break;
  899. }
  900. }
  901. if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  902. dwError = GetLastError();
  903. __leave;
  904. }
  905. }
  906. else {
  907. dwError = GetLastError();
  908. //
  909. // ERROR_SERVICE_NOT_ACTIVE is fine, since it means that the service has
  910. // already been stopped. If the error is not ERROR_SERVICE_NOT_ACTIVE then
  911. // something has gone wrong, so __leave.
  912. //
  913. if (dwError != ERROR_SERVICE_NOT_ACTIVE) {
  914. __leave;
  915. }
  916. }
  917. if (!DeleteService( hService )) {
  918. dwError = GetLastError();
  919. __leave;
  920. }
  921. else {
  922. DBG_TRC(("StiServiceRemove, removed STI service"));
  923. }
  924. }
  925. __finally {
  926. CloseServiceHandle( hService );
  927. CloseServiceHandle( hSCM );
  928. }
  929. #endif
  930. return dwError;
  931. } // StiServiceRemove
  932. VOID
  933. SvchostPushServiceGlobals(
  934. PSVCHOST_GLOBAL_DATA pGlobals
  935. )
  936. {
  937. //
  938. // For now, we do nothing here. We will need to revisit when we run under
  939. // a shared SvcHost Group.
  940. //
  941. return;
  942. }