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.

1037 lines
26 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. service.cxx
  5. Abstract:
  6. Process init and service controller interaction
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 06-14-95 Cloned RPCSS from the old endpoint mapper.
  11. jroberts 06-29-00 Cloned BITS from RPCSS
  12. --*/
  13. #include "qmgrlib.h"
  14. #include "trust.h"
  15. #include "service.tmh"
  16. //
  17. // This #define allows BITS to load an unsigned replacement qmgr.dll when the appropriate regkey is set.
  18. // Without the #define, BITS only loads certs signed by a Microsoft root authority.
  19. //
  20. // #define ENABLE_TEST_DLL
  21. #define SERVICE_NAME _T("BITS")
  22. #define DEVICE_PREFIX _T("\\\\.\\")
  23. VOID WINAPI ServiceMain(DWORD, LPTSTR*);
  24. VOID UpdateState(DWORD dwNewState);
  25. extern BOOL CatalogDllMain (
  26. HINSTANCE hInst,
  27. DWORD dwReason,
  28. LPVOID lpReserved
  29. );
  30. // Array of service status blocks and pointers to service control
  31. // functions for each component service.
  32. SERVICE_TABLE_ENTRY gaServiceEntryTable[] = {
  33. { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
  34. { NULL, NULL }
  35. };
  36. HINSTANCE g_hInstance;
  37. SERVICE_STATUS gServiceStatus;
  38. SERVICE_STATUS_HANDLE ghServiceHandle;
  39. // This event is set when we receive a SERVICE_CONTROL_STOP/SHUTDOWN
  40. HANDLE g_hServiceStopEvent = NULL;
  41. typedef SERVICE_STATUS_HANDLE (*PREGISTER_FUNC)(
  42. LPCTSTR lpServiceName,
  43. LPHANDLER_FUNCTION_EX lpHandlerProc,
  44. LPVOID lpContext );
  45. typedef VOID (*PSERVICE_MAIN_FUNC)(
  46. DWORD argc,
  47. LPTSTR *lpszArgv,
  48. PREGISTER_FUNC RegisterFunc );
  49. extern "C"
  50. VOID
  51. BITSServiceMain(
  52. DWORD argc,
  53. LPTSTR *argv,
  54. PREGISTER_FUNC lpRegisterFunc
  55. );
  56. BOOL
  57. GetModuleVersion64(
  58. HMODULE hDll,
  59. ULONG64 * pVer
  60. );
  61. BOOL
  62. GetFileVersion64(
  63. LPTSTR szFullPath,
  64. ULONG64 * pVer
  65. );
  66. LPHANDLER_FUNCTION_EX g_RealHandler = NULL;
  67. HINSTANCE g_RealLibrary = NULL;
  68. LONG g_RealLibraryRefs = 0;
  69. ULONG
  70. ServiceHandlerThunk(
  71. DWORD dwCode,
  72. DWORD dwEventType,
  73. PVOID EventData,
  74. PVOID pData )
  75. {
  76. InterlockedIncrement( &g_RealLibraryRefs );
  77. ULONG Result =
  78. g_RealHandler( dwCode, dwEventType, EventData, pData );
  79. if (!InterlockedDecrement( &g_RealLibraryRefs ) )
  80. {
  81. FreeLibrary( g_RealLibrary );
  82. g_RealLibrary = NULL;
  83. }
  84. return Result;
  85. }
  86. SERVICE_STATUS_HANDLE
  87. RegisterServiceHandlerThunk(
  88. LPCTSTR lpServiceName,
  89. LPHANDLER_FUNCTION_EX lpHandlerProc,
  90. LPVOID lpContext )
  91. {
  92. g_RealHandler = lpHandlerProc;
  93. return
  94. RegisterServiceCtrlHandlerEx( lpServiceName,
  95. ServiceHandlerThunk,
  96. lpContext
  97. );
  98. }
  99. bool
  100. JumpToRealDLL(
  101. DWORD argc,
  102. LPTSTR *argv )
  103. {
  104. #define MAX_DLLNAME (MAX_PATH+1)
  105. HKEY BitsKey = NULL;
  106. bool bAllowTestBinaries = false;
  107. LONG Result =
  108. RegOpenKey( HKEY_LOCAL_MACHINE, C_QMGR_REG_KEY, &BitsKey );
  109. if ( Result )
  110. goto noload;
  111. //
  112. // Read the key naming an override DLL.
  113. //
  114. static TCHAR DLLName[MAX_DLLNAME];
  115. DWORD Type;
  116. DWORD NameSize = sizeof(DLLName);
  117. Result = RegQueryValueEx(
  118. BitsKey,
  119. C_QMGR_SERVICEDLL,
  120. NULL,
  121. &Type,
  122. (LPBYTE)DLLName,
  123. &NameSize );
  124. if ( Result ||
  125. (( Type != REG_SZ ) && (Type != REG_EXPAND_SZ)) )
  126. {
  127. goto noload;
  128. }
  129. if (Type == REG_EXPAND_SZ)
  130. {
  131. static TCHAR ExpandedDLLName[MAX_DLLNAME];
  132. DWORD size = ExpandEnvironmentStrings( DLLName, ExpandedDLLName, MAX_DLLNAME );
  133. if (size == 0)
  134. {
  135. // out of resources
  136. return true;
  137. }
  138. HRESULT hr;
  139. hr = StringCchCopy( DLLName, RTL_NUMBER_OF(DLLName), ExpandedDLLName );
  140. if (FAILED(hr))
  141. {
  142. // too long; must be badly formatted. Ignore it.
  143. goto noload;
  144. }
  145. }
  146. #ifdef ENABLE_TEST_DLL
  147. //
  148. // Read the key that controls whether to allow test-signed binaries.
  149. //
  150. {
  151. DWORD b;
  152. DWORD Size = sizeof(b);
  153. DWORD Type;
  154. Result = RegQueryValueEx(
  155. BitsKey,
  156. C_QMGR_ALLOW_TEST_DLL,
  157. NULL,
  158. &Type,
  159. (LPBYTE)&b,
  160. &Size );
  161. if ( (Result ==0) && ( Type == REG_DWORD ) && (b == 1))
  162. {
  163. bAllowTestBinaries = true;
  164. }
  165. }
  166. #endif
  167. RegCloseKey( BitsKey );
  168. BitsKey = NULL;
  169. //
  170. // At this point, we know that the registry specifies an alternate DLL.
  171. // See whether it has a later version than the current one.
  172. //
  173. ULONG64 AlternateDllVersion = 0;
  174. ULONG64 MyDllVersion = 0;
  175. if (!QMgrFileExists( DLLName ))
  176. {
  177. goto noload;
  178. }
  179. if (!GetFileVersion64( DLLName, &AlternateDllVersion ))
  180. {
  181. // can't ascertain the version. Don't start the service at all.
  182. return true;
  183. }
  184. if (!GetModuleVersion64( g_hInstance, &MyDllVersion ))
  185. {
  186. // can't ascertain the version. Don't start the service at all.
  187. return true;
  188. }
  189. if (MyDllVersion >= AlternateDllVersion)
  190. {
  191. goto noload;
  192. }
  193. if (!bAllowTestBinaries)
  194. {
  195. //
  196. // Verify that the file is signed with a Microsoft certificate, using the default cert list and checking the CRL.
  197. //
  198. if (FAILED(VerifyFileTrust( DLLName, NULL, TRUE )))
  199. {
  200. goto noload;
  201. }
  202. }
  203. //
  204. // The file appears valid; load it and call BitsServiceMain.
  205. //
  206. g_RealLibrary = LoadLibrary( DLLName );
  207. if ( !g_RealLibrary )
  208. goto noload;
  209. PSERVICE_MAIN_FUNC ServiceMainFunc =
  210. (PSERVICE_MAIN_FUNC)GetProcAddress( g_RealLibrary, "BITSServiceMain" );
  211. if ( !ServiceMainFunc )
  212. goto noload;
  213. g_RealLibraryRefs = 1;
  214. // Ok to call into real library now.
  215. ( *ServiceMainFunc ) ( argc, argv, RegisterServiceHandlerThunk );
  216. if (!InterlockedDecrement( &g_RealLibraryRefs ) )
  217. {
  218. FreeLibrary( g_RealLibrary );
  219. g_RealLibrary = NULL;
  220. }
  221. return true;
  222. noload:
  223. if ( BitsKey )
  224. RegCloseKey( BitsKey );
  225. if ( g_RealLibrary )
  226. FreeLibrary( g_RealLibrary );
  227. return false;
  228. }
  229. VOID WINAPI
  230. ServiceMain(
  231. DWORD argc,
  232. LPTSTR *argv
  233. )
  234. /*++
  235. Routine Description:
  236. Callback by the service controller when starting this service.
  237. Arguments:
  238. argc - number of arguments, usually 1
  239. argv - argv[0] is the name of the service.
  240. argv[>0] are arguments passed to the service.
  241. Return Value:
  242. None
  243. --*/
  244. {
  245. volatile static LONG ThreadRunning = 0;
  246. if ( InterlockedCompareExchange( &ThreadRunning, 1, 0 ) == 1 )
  247. {
  248. // A thread is already running ServiceMain, just exit.
  249. // The service controller has a bug where it can create multiple
  250. // threads to call ServiceMain in high stress conditions.
  251. return;
  252. }
  253. if (!JumpToRealDLL( argc, argv) )
  254. {
  255. BITSServiceMain(
  256. argc,
  257. argv,
  258. RegisterServiceCtrlHandlerEx );
  259. }
  260. ThreadRunning = 0;
  261. }
  262. DWORD g_LastServiceControl;
  263. ULONG WINAPI
  264. BITSServiceHandler(
  265. DWORD dwCode,
  266. DWORD dwEventType,
  267. PVOID EventData,
  268. PVOID pData
  269. )
  270. /*++
  271. Routine Description:
  272. Lowest level callback from the service controller to
  273. cause this service to change our status. (stop, start, pause, etc).
  274. Arguments:
  275. opCode - One of the service "Controls" value.
  276. SERVICE_CONTROL_{STOP, PAUSE, CONTINUE, INTERROGATE, SHUTDOWN}.
  277. Return Value:
  278. None
  279. --*/
  280. {
  281. switch(dwCode)
  282. {
  283. case SERVICE_CONTROL_STOP:
  284. {
  285. LogService( "STOP request" );
  286. //
  287. // only relevant in running state; damaging if we are stopping
  288. // and g_hServiceStopEvent is deleted.
  289. //
  290. if (gServiceStatus.dwCurrentState == SERVICE_RUNNING)
  291. {
  292. g_LastServiceControl = dwCode;
  293. UpdateState( SERVICE_STOP_PENDING );
  294. SetEvent( g_hServiceStopEvent );
  295. }
  296. break;
  297. }
  298. case SERVICE_CONTROL_INTERROGATE:
  299. // Service controller wants us to call SetServiceStatus.
  300. LogService( "INTERROGATE request" );
  301. UpdateState(gServiceStatus.dwCurrentState);
  302. break ;
  303. case SERVICE_CONTROL_SHUTDOWN:
  304. // The machine is shutting down. We'll be killed once we return.
  305. LogService( "SHUTDOWN request" );
  306. g_LastServiceControl = dwCode;
  307. UpdateState( SERVICE_STOP_PENDING );
  308. SetEvent( g_hServiceStopEvent );
  309. while (gServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
  310. {
  311. LogService( "service pending; sleeping..." );
  312. Sleep(100);
  313. }
  314. break;
  315. case SERVICE_CONTROL_DEVICEEVENT:
  316. {
  317. if (gServiceStatus.dwCurrentState == SERVICE_STOP_PENDING ||
  318. gServiceStatus.dwCurrentState == SERVICE_STOPPED)
  319. {
  320. LogService("ignoring device event due to service shutdown" );
  321. break;
  322. }
  323. return DeviceEventCallback( dwEventType, EventData );
  324. }
  325. case SERVICE_CONTROL_SESSIONCHANGE:
  326. {
  327. WTSSESSION_NOTIFICATION* pswtsi = (WTSSESSION_NOTIFICATION*) EventData;
  328. DWORD dwSessionId = pswtsi->dwSessionId;
  329. if (gServiceStatus.dwCurrentState == SERVICE_STOP_PENDING ||
  330. gServiceStatus.dwCurrentState == SERVICE_STOPPED)
  331. {
  332. LogService("ignoring session change for session %d due to service shutdown", dwSessionId );
  333. break;
  334. }
  335. switch (dwEventType)
  336. {
  337. case WTS_SESSION_LOGON:
  338. {
  339. LogService("logon at session %d", dwSessionId);
  340. SessionLogonCallback( dwSessionId );
  341. break;
  342. }
  343. case WTS_SESSION_LOGOFF:
  344. {
  345. LogService("logoff at session %d", dwSessionId);
  346. SessionLogoffCallback( dwSessionId );
  347. break;
  348. }
  349. default: //Is there a default?
  350. break;
  351. }
  352. break;
  353. }
  354. default:
  355. LogError( "%!ts!: Unexpected service control message %d.\n", SERVICE_NAME, dwCode);
  356. return ERROR_CALL_NOT_IMPLEMENTED;
  357. }
  358. return NO_ERROR;
  359. }
  360. bool
  361. IsServiceShuttingDown()
  362. {
  363. return (gServiceStatus.dwCurrentState == SERVICE_STOP_PENDING);
  364. }
  365. VOID
  366. UpdateState(
  367. DWORD dwNewState
  368. )
  369. /*++
  370. Routine Description:
  371. Updates this services state with the service controller.
  372. Arguments:
  373. dwNewState - The next start for this service. One of
  374. SERVICE_START_PENDING
  375. SERVICE_RUNNING
  376. Return Value:
  377. None
  378. --*/
  379. {
  380. DWORD status = ERROR_SUCCESS;
  381. LogService("state change: old %d new %d", gServiceStatus.dwCurrentState, dwNewState );
  382. switch (dwNewState)
  383. {
  384. case SERVICE_RUNNING:
  385. case SERVICE_STOPPED:
  386. gServiceStatus.dwCheckPoint = 0;
  387. gServiceStatus.dwWaitHint = 0;
  388. break;
  389. case SERVICE_START_PENDING:
  390. case SERVICE_STOP_PENDING:
  391. ++gServiceStatus.dwCheckPoint;
  392. gServiceStatus.dwWaitHint = 30000L;
  393. break;
  394. default:
  395. ASSERT(0);
  396. status = ERROR_INVALID_SERVICE_CONTROL;
  397. break;
  398. }
  399. if (status == ERROR_SUCCESS)
  400. {
  401. gServiceStatus.dwCurrentState = dwNewState;
  402. if (!SetServiceStatus(ghServiceHandle, &gServiceStatus))
  403. {
  404. status = GetLastError();
  405. }
  406. }
  407. if (status != ERROR_SUCCESS)
  408. {
  409. LogError( "%!ts!: Failed to update service state: %d\n", SERVICE_NAME, status);
  410. }
  411. // We could return a status but how would we recover? Ignore it, the
  412. // worst thing is that services will kill us and there's nothing
  413. // we can about it if this call fails.
  414. LogInfo( "Finished updating service state to %u", dwNewState );
  415. return;
  416. }
  417. extern "C"
  418. VOID
  419. BITSServiceMain(
  420. DWORD argc,
  421. LPTSTR *argv,
  422. PREGISTER_FUNC lpRegisterFunc
  423. )
  424. /*++
  425. Routine Description:
  426. Callback by the service controller when starting this service.
  427. Arguments:
  428. argc - number of arguments, usually 1
  429. argv - argv[0] is the name of the service.
  430. argv[>0] are arguments passed to the service.
  431. Return Value:
  432. None
  433. --*/
  434. {
  435. BOOL f = FALSE;
  436. HRESULT hr = S_OK;
  437. bool bGlobals = false;
  438. bool bQmgr = false;
  439. try
  440. {
  441. DWORD status = ERROR_SUCCESS;
  442. FILETIME ftStartTime;
  443. GetSystemTimeAsFileTime( &ftStartTime );
  444. Log_Init();
  445. Log_StartLogger();
  446. LogInfo("Service started at %!TIMESTAMP!", FILETIMEToUINT64( ftStartTime ) );
  447. //
  448. // Set up for service notifications.
  449. //
  450. gServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  451. gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  452. gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  453. // The SESSIONCHANGE notification is only available on WindowsXP
  454. // and the service controller will become confused if this is given on windows 2000
  455. if ( WINDOWSXP_PLATFORM == g_PlatformVersion )
  456. gServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE;
  457. gServiceStatus.dwWin32ExitCode = 0;
  458. gServiceStatus.dwServiceSpecificExitCode = 0;
  459. gServiceStatus.dwCheckPoint = 0;
  460. gServiceStatus.dwWaitHint = 30000L;
  461. ghServiceHandle = (*lpRegisterFunc)( SERVICE_NAME,
  462. BITSServiceHandler,
  463. 0
  464. );
  465. if (0 == ghServiceHandle)
  466. {
  467. status = GetLastError();
  468. ASSERT(status != ERROR_SUCCESS);
  469. LogError( "RegisterServiceCtrlHandlerEx failed %!winerr!", status);
  470. THROW_HRESULT( HRESULT_FROM_WIN32( status ));
  471. }
  472. UpdateState(SERVICE_START_PENDING);
  473. // Set up an event that will be signaled when the service is
  474. // stopped or shutdown.
  475. g_hServiceStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  476. if( NULL == g_hServiceStopEvent )
  477. {
  478. status = GetLastError();
  479. LogError( "CreateEvent failed %!winerr!", status );
  480. THROW_HRESULT( HRESULT_FROM_WIN32( status ));
  481. }
  482. if ( WINDOWS2000_PLATFORM == g_PlatformVersion )
  483. {
  484. HRESULT Hr;
  485. bool CoInitCalled = false;
  486. Hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  487. if ( FAILED( Hr ) &&
  488. ( Hr != RPC_E_CHANGED_MODE ) )
  489. THROW_HRESULT( Hr );
  490. CoInitCalled = true;
  491. Hr =
  492. CoInitializeSecurity(
  493. NULL, // pSecDesc
  494. -1, // cAuthSvc
  495. NULL, // asAuthSvc
  496. NULL, // pReserved
  497. RPC_C_AUTHN_LEVEL_PKT, // dwAuthnLevel
  498. RPC_C_IMP_LEVEL_IDENTIFY, // dwImpLevel
  499. NULL, // pReserved2
  500. EOAC_NO_CUSTOM_MARSHAL | // dwCapabilities
  501. EOAC_DISABLE_AAA |
  502. EOAC_STATIC_CLOAKING,
  503. NULL ); // pReserved3
  504. if ( FAILED( Hr ) &&
  505. ( Hr != RPC_E_TOO_LATE ) )
  506. {
  507. LogError( "Unable to initialize security on Win2k, error %!winerr!", Hr );
  508. if ( CoInitCalled )
  509. CoUninitialize();
  510. THROW_HRESULT( Hr );
  511. }
  512. }
  513. LogInfo( "Initializing globalinfo\n" );
  514. THROW_HRESULT( GlobalInfo::Init() );
  515. bGlobals = true;
  516. LogInfo( "Initializing qmgr\n" );
  517. THROW_HRESULT( InitQmgr() );
  518. bQmgr = true;
  519. LogInfo( "Setting service to running.");
  520. //
  521. // Allow service controller to resume other duties.
  522. //
  523. UpdateState(SERVICE_RUNNING);
  524. //
  525. // wait for the stop signal.
  526. //
  527. if( WAIT_OBJECT_0 != WaitForSingleObject( g_hServiceStopEvent, INFINITE ))
  528. {
  529. status = GetLastError();
  530. LogError( "ServiceMain failed waiting for stop signal %!winerr!", status);
  531. hr = HRESULT_FROM_WIN32( status );
  532. }
  533. hr = S_OK;
  534. }
  535. catch ( ComError exception )
  536. {
  537. hr = exception.Error();
  538. }
  539. if (bQmgr)
  540. {
  541. HRESULT hr2 = UninitQmgr();
  542. if (FAILED(hr2))
  543. {
  544. LogError( "uninit Qmgr failed %!winerr!", hr2);
  545. }
  546. }
  547. if (bGlobals)
  548. {
  549. HRESULT hr2 = GlobalInfo::Uninit();
  550. if (FAILED(hr2))
  551. {
  552. LogError( "uninit GlobalInfo failed %!winerr!", hr2);
  553. }
  554. }
  555. if (g_hServiceStopEvent)
  556. {
  557. CloseHandle( g_hServiceStopEvent );
  558. g_hServiceStopEvent = NULL;
  559. }
  560. if (FAILED(hr))
  561. {
  562. gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  563. gServiceStatus.dwServiceSpecificExitCode = hr;
  564. }
  565. LogService( "ServiceMain returning, hr = %x", hr );
  566. Log_Close();
  567. UpdateState(SERVICE_STOPPED);
  568. }
  569. enum
  570. {
  571. STARTUP_UNKNOWN,
  572. STARTUP_DEMAND,
  573. STARTUP_AUTO
  574. }
  575. g_ServiceStartupState = STARTUP_UNKNOWN;
  576. HRESULT
  577. SetServiceStartup( bool bAutoStart )
  578. {
  579. LogService( "Setting startup to %s", bAutoStart ? ("Auto") : ("Demand") );
  580. HRESULT Hr = S_OK;
  581. //
  582. // Changing the service state is expensive, so avoid it if possible.
  583. //
  584. // No need to monitor external changes to the startup state, though:
  585. //
  586. // If the admin changes our state from AUTO to DEMAND or DISABLED, then
  587. // the consequent lack of progress is his fault, and admins should know that.
  588. //
  589. // If the admin changes our state from DEMAND to AUTO, then we will
  590. // start more often but the result is otherwise harmless.
  591. //
  592. if ((g_ServiceStartupState == STARTUP_DEMAND && bAutoStart == FALSE) ||
  593. (g_ServiceStartupState == STARTUP_AUTO && bAutoStart == TRUE))
  594. {
  595. LogService( "startup state is already correct" );
  596. return S_OK;
  597. }
  598. if (gServiceStatus.dwCurrentState != SERVICE_RUNNING)
  599. {
  600. LogService("can't change startup state in state %d", gServiceStatus.dwCurrentState);
  601. return S_OK;
  602. }
  603. SC_HANDLE hServiceManager = NULL;
  604. SC_HANDLE hService = NULL;
  605. try
  606. {
  607. try
  608. {
  609. hServiceManager =
  610. OpenSCManager( NULL,
  611. NULL,
  612. SC_MANAGER_ALL_ACCESS );
  613. if ( !hServiceManager ) throw (DWORD)GetLastError();
  614. hService =
  615. OpenService( hServiceManager,
  616. SERVICE_NAME,
  617. SERVICE_CHANGE_CONFIG );
  618. if ( !hService ) throw (DWORD)GetLastError();
  619. BOOL bResult =
  620. ChangeServiceConfig( hService, // service handle
  621. SERVICE_NO_CHANGE, // dwServiceType
  622. bAutoStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START, // dwStartType
  623. SERVICE_NO_CHANGE, // dwErrorControl
  624. NULL, // lpBinaryPathName
  625. NULL, // lpLoadOrderGroup
  626. NULL, // lpdwTagId
  627. NULL, // lpDependencies
  628. NULL, // lpServiceStartName
  629. NULL, // lpPassword
  630. NULL); // lpDisplayName
  631. if ( !bResult ) throw (DWORD)GetLastError();
  632. if (bAutoStart)
  633. {
  634. g_ServiceStartupState = STARTUP_AUTO;
  635. }
  636. else
  637. {
  638. g_ServiceStartupState = STARTUP_DEMAND;
  639. }
  640. }
  641. catch( DWORD dwException )
  642. {
  643. throw (HRESULT)HRESULT_FROM_WIN32( dwException );
  644. }
  645. }
  646. catch (HRESULT HrException)
  647. {
  648. Hr = HrException;
  649. LogError( "An error occurred setting service startup, %!winerr!", Hr );
  650. }
  651. if ( hService )
  652. {
  653. CloseServiceHandle( hService );
  654. }
  655. if ( hServiceManager )
  656. {
  657. CloseServiceHandle( hServiceManager );
  658. }
  659. LogService( " HR: %!winerr!", Hr );
  660. return Hr;
  661. }
  662. int InitializeBitsAllocator();
  663. extern "C"
  664. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
  665. {
  666. if (dwReason == DLL_PROCESS_ATTACH)
  667. {
  668. g_hInstance = hInstance;
  669. DisableThreadLibraryCalls(hInstance);
  670. if (!InitCompilerLibrary())
  671. {
  672. return FALSE;
  673. }
  674. if ( !DetectProductVersion() )
  675. {
  676. UninitCompilerLibrary();
  677. return FALSE;
  678. }
  679. if (0 != InitializeBitsAllocator())
  680. {
  681. UninitCompilerLibrary();
  682. return FALSE;
  683. }
  684. }
  685. else if ( dwReason == DLL_PROCESS_DETACH )
  686. {
  687. UninitCompilerLibrary();
  688. }
  689. return TRUE; // ok
  690. }
  691. //
  692. // This ungainly typedef seems to have no global definition. There are several identical
  693. // definitions in the Windows NT sources, each of which has that bizarre bit-stripping
  694. // on szKey. I got mine from \nt\base\ntsetup\srvpack\update\splib\common.h.
  695. //
  696. typedef struct tagVERHEAD {
  697. WORD wTotLen;
  698. WORD wValLen;
  699. WORD wType; /* always 0 */
  700. WCHAR szKey[(sizeof("VS_VERSION_INFO")+3)&~03];
  701. VS_FIXEDFILEINFO vsf;
  702. } VERHEAD ;
  703. /*
  704. ** Purpose:
  705. ** Gets the file version values from the given file and sets the
  706. ** given ULONG64 variable.
  707. ** Arguments:
  708. ** szFullPath: a zero terminated character string containing the fully
  709. ** qualified path (including disk drive) to the file.
  710. ** Returns:
  711. ** fTrue if file and file version resource found and retrieved,
  712. ** fFalse if not.
  713. +++
  714. ** Implementation:
  715. **************************************************************************/
  716. BOOL
  717. GetFileVersion64(
  718. LPTSTR szFullPath,
  719. ULONG64 * pVer
  720. )
  721. {
  722. BOOL fRet = false;
  723. DWORD dwHandle;
  724. DWORD InfoSize;
  725. try
  726. {
  727. //
  728. // Get the file version info size
  729. //
  730. if ((InfoSize = GetFileVersionInfoSize( szFullPath, &dwHandle)) == 0)
  731. {
  732. return (fRet);
  733. }
  734. //
  735. // Allocate enough size to hold version info
  736. //
  737. auto_ptr<TCHAR> lpData ( LPTSTR(new byte[ InfoSize ]));
  738. //
  739. // Get the version info
  740. //
  741. fRet = GetFileVersionInfo( szFullPath, dwHandle, InfoSize, lpData.get());
  742. if (fRet)
  743. {
  744. UINT dwLen;
  745. VS_FIXEDFILEINFO *pvsfi;
  746. fRet = VerQueryValue(
  747. lpData.get(),
  748. L"\\",
  749. (LPVOID *)&pvsfi,
  750. &dwLen
  751. );
  752. //
  753. // Convert two DWORDs into a 64-bit integer.
  754. //
  755. if (fRet)
  756. {
  757. *pVer = ( ULONG64(pvsfi->dwFileVersionMS) << 32) | (pvsfi->dwFileVersionLS);
  758. }
  759. }
  760. return (fRet);
  761. }
  762. catch ( ComError err )
  763. {
  764. return false;
  765. }
  766. }
  767. BOOL
  768. GetModuleVersion64(
  769. HMODULE hDll,
  770. ULONG64 * pVer
  771. )
  772. {
  773. DWORD* pdwTranslation;
  774. VS_FIXEDFILEINFO* pFileInfo;
  775. UINT uiSize;
  776. HRSRC hrsrcVersion = FindResource(
  777. hDll,
  778. MAKEINTRESOURCE(VS_VERSION_INFO),
  779. RT_VERSION);
  780. if (!hrsrcVersion) return false;
  781. HGLOBAL hglobalVersion = LoadResource(hDll, hrsrcVersion);
  782. if (!hglobalVersion) return false;
  783. VERHEAD * pVerHead = (VERHEAD *) LockResource(hglobalVersion);
  784. if (!pVerHead) return false;
  785. // I stole this code from \nt\com\complus\src\shared\util\svcerr.cpp,
  786. // and the comment is theirs:
  787. //
  788. // VerQueryValue will write to the memory, for some reason.
  789. // Therefore we must make a writable copy of the version
  790. // resource info before calling that API.
  791. auto_ptr<char> pvVersionInfo ( new char[pVerHead->wTotLen + pVerHead->wTotLen/2] );
  792. memcpy(pvVersionInfo.get(), pVerHead, pVerHead->wTotLen); // SEC: REVIEWED 2002-03-28
  793. // Retrieve file version info
  794. BOOL fRet = VerQueryValue( pvVersionInfo.get(),
  795. L"\\",
  796. (void**)&pFileInfo,
  797. &uiSize);
  798. if (fRet)
  799. {
  800. *pVer = (ULONG64(pFileInfo->dwFileVersionMS) << 32) | (pFileInfo->dwFileVersionLS);
  801. }
  802. return fRet;
  803. }