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.

1100 lines
21 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. STIEXE.CPP
  5. Abstract:
  6. This module contains code for process, running STI+WIA services
  7. Author:
  8. Vlad Sadovsky (vlads) 09-20-97
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. 22-Sep-1997 VladS created
  13. 13-Apr-1999 VladS merged with WIA service code
  14. --*/
  15. //
  16. // Include Headers
  17. //
  18. #include "precomp.h"
  19. #include "stiexe.h"
  20. #include "stirpc.h"
  21. #include "device.h"
  22. #include "wiapriv.h"
  23. #include "lockmgr.h"
  24. #include <shlwapi.h>
  25. #include <regstr.h>
  26. CComModule _Module;
  27. BEGIN_OBJECT_MAP(ObjectMap)
  28. // OBJECT_ENTRY(CLSID_Ubj, CObj)
  29. END_OBJECT_MAP()
  30. extern CRITICAL_SECTION g_semDeviceMan;
  31. extern CRITICAL_SECTION g_semEventNode;
  32. //
  33. // Local variables and types definitions
  34. //
  35. //
  36. // Event used for detecting previously started instance of the server
  37. //
  38. static HANDLE ServerStartedEvent;
  39. //
  40. // Flag to use service controller PnP event sink vs window message based sink
  41. //
  42. extern BOOL g_fUseServiceCtrlSink;
  43. //
  44. // Still Image entry in Registry
  45. //
  46. char* g_szStiKey = "SYSTEM\\CurrentControlSet\\Control\\StillImage";
  47. //
  48. // WIA Debug Window value name
  49. //
  50. char* g_szWiaDebugValue = "ShowWiaDebugWindow";
  51. //
  52. // String value to indicate that debug window should be shown
  53. //
  54. char* g_szShowWiaWinString = "Yes";
  55. //
  56. // Bool values indicating whether Critical Section initialization was successful
  57. //
  58. BOOL g_bEventCritSectInitialized = FALSE;
  59. BOOL g_bDevManCritSectInitialized = FALSE;
  60. //
  61. // Local prototypes
  62. //
  63. DWORD
  64. InitGlobalConfigFromReg(
  65. VOID
  66. );
  67. BOOL
  68. DoGlobalInit(
  69. UINT argc,
  70. LPTSTR *argv
  71. );
  72. BOOL
  73. DoGlobalTermination(
  74. VOID
  75. );
  76. BOOL
  77. UpdateRunningServer(
  78. VOID
  79. );
  80. HWND
  81. CreateMasterWindow(
  82. VOID
  83. );
  84. BOOL
  85. StartMasterLoop(
  86. LPVOID lpv
  87. );
  88. BOOL
  89. StartOperation(
  90. VOID
  91. );
  92. //
  93. // Code section
  94. //
  95. extern "C"
  96. BOOL
  97. APIENTRY
  98. DllEntryPoint(
  99. HINSTANCE hinst,
  100. DWORD dwReason,
  101. LPVOID lpReserved
  102. )
  103. /*++
  104. Routine Description:
  105. DllEntryPoint
  106. Main DLL entry point.
  107. Arguments:
  108. hinst - module instance
  109. dwReason - reason called
  110. lpReserved - reserved
  111. Return Value:
  112. Status
  113. Side effects:
  114. None
  115. --*/
  116. {
  117. switch (dwReason) {
  118. case DLL_PROCESS_ATTACH:
  119. DBG_INIT(hinst);
  120. #if 0
  121. #ifdef DEBUG
  122. StiSetDebugMask(0xffff);
  123. StiSetDebugParameters(TEXT("WIASERVC"),TEXT(""));
  124. #endif
  125. #endif
  126. g_hInst = hinst;
  127. ::DisableThreadLibraryCalls(hinst);
  128. InitializeCriticalSection(&g_RpcEvent.cs);
  129. _Module.Init(ObjectMap,hinst);
  130. break;
  131. case DLL_PROCESS_DETACH:
  132. DeleteCriticalSection(&g_RpcEvent.cs);
  133. _Module.Term();
  134. break;
  135. }
  136. return 1;
  137. }
  138. extern "C"
  139. BOOL
  140. APIENTRY
  141. DllMain(
  142. HINSTANCE hinst,
  143. DWORD dwReason,
  144. LPVOID lpReserved
  145. )
  146. {
  147. return DllEntryPoint(hinst, dwReason, lpReserved );
  148. }
  149. VOID
  150. WINAPI
  151. ServiceMain(
  152. UINT argc,
  153. LPTSTR *argv
  154. )
  155. /*++
  156. Routine Description:
  157. Main initialization point of imaging services library
  158. Arguments:
  159. argc - counter of arguments
  160. argv - arguments array
  161. Return Value:
  162. None
  163. Side effects:
  164. None
  165. --*/
  166. {
  167. DBG_FN(ServiceMain);
  168. //
  169. // Register our Service control handler. Note that we must do this as early as possible.
  170. //
  171. if (!RegisterServiceControlHandler()) {
  172. goto ExitMain;
  173. }
  174. //
  175. // Do global initialization, independent of specific service
  176. //
  177. if (!DoGlobalInit(argc,argv)) {
  178. goto ExitMain;
  179. }
  180. //
  181. // Start running service
  182. //
  183. StartOperation();
  184. ExitMain:
  185. //
  186. // Global cleanup
  187. //
  188. DoGlobalTermination();
  189. UpdateServiceStatus(SERVICE_STOPPED,NOERROR,0);
  190. } /* Endproc ServiceMain */
  191. BOOL
  192. DoGlobalInit(
  193. UINT argc,
  194. LPTSTR *argv
  195. )
  196. /*++
  197. Routine Description:
  198. Perform one time service initialization
  199. Arguments:
  200. None
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. DBG_FN(DoGlobalInit);
  206. //
  207. // To use built-in ATL conversion macros
  208. //
  209. USES_CONVERSION;
  210. #ifdef DEBUG
  211. //
  212. // Create a debug context.
  213. //
  214. #define VALUE_SIZE 5
  215. char valueData[VALUE_SIZE];
  216. DWORD retVal, type = 0, size = VALUE_SIZE;
  217. //
  218. // Search the registry
  219. //
  220. retVal = SHGetValueA(HKEY_LOCAL_MACHINE,
  221. g_szStiKey,
  222. g_szWiaDebugValue,
  223. &type,
  224. valueData,
  225. &size);
  226. //
  227. // Found the entry in the registry
  228. //
  229. BOOLEAN bDisplayUi = FALSE;
  230. if (retVal == ERROR_SUCCESS) {
  231. //
  232. // Compare value found in registry to g_szShowWinString
  233. // If same, then show it
  234. //
  235. if (lstrcmpiA(g_szShowWiaWinString, valueData) == 0) {
  236. bDisplayUi = TRUE;
  237. }
  238. }
  239. //remove
  240. //WIA_DEBUG_CREATE( g_hInst,
  241. // TEXT("OLD Debugging/TRACE Window (STI/WIA Service)"),
  242. // bDisplayUi,
  243. // FALSE);
  244. #endif
  245. //
  246. // Initialize COM.
  247. //
  248. HRESULT hr = CoInitializeEx(0,COINIT_MULTITHREADED);
  249. if (FAILED(hr)) {
  250. #ifdef DEBUG
  251. OutputDebugString(TEXT("DoGlobalInit, CoInitializeEx failed\n"));
  252. #endif
  253. return FALSE;
  254. }
  255. //
  256. // Initialize our global critical sections...
  257. //
  258. __try {
  259. //
  260. // Initialize the critical sections.
  261. //
  262. if (InitializeCriticalSectionAndSpinCount(&g_semDeviceMan, MINLONG)) {
  263. g_bDevManCritSectInitialized = TRUE;
  264. }
  265. if (InitializeCriticalSectionAndSpinCount(&g_semEventNode, MINLONG)) {
  266. g_bEventCritSectInitialized = TRUE;
  267. }
  268. if(!g_bDevManCritSectInitialized || !g_bEventCritSectInitialized)
  269. {
  270. #ifdef DEBUG
  271. OutputDebugString(TEXT("DoGlobalInit, InitializeCriticalSectionAndSpinCount failed\n"));
  272. #endif
  273. return FALSE;
  274. }
  275. }
  276. __except (EXCEPTION_EXECUTE_HANDLER) {
  277. //
  278. // Couldn't initialize critical sections - this is really bad,
  279. // so bail
  280. //
  281. #ifdef DEBUG
  282. OutputDebugString(TEXT("DoGlobalInit, InitializeCriticalSectionAndSpinCount threw an exception!\n"));
  283. #endif
  284. return FALSE;
  285. }
  286. //
  287. // Setup some global variables from the registry.
  288. //
  289. #ifndef WINNT
  290. g_fRunningAsService = FALSE;
  291. #endif
  292. InitGlobalConfigFromReg();
  293. //
  294. // Create event log class object
  295. //
  296. g_EventLog = new EVENT_LOG(TEXT("StillImage"));
  297. if (!g_EventLog) {
  298. #ifdef DEBUG
  299. OutputDebugString(TEXT("DoGlobalInit, unable to allocate EVENT_LOG\n"));
  300. #endif
  301. return FALSE;
  302. }
  303. //
  304. // Create file log class object, requesting truncating file if set by user
  305. //
  306. g_StiFileLog = new STI_FILE_LOG(TEXT("STISVC"),NULL,STIFILELOG_CHECK_TRUNCATE_ON_BOOT, g_hInst);
  307. if (g_StiFileLog) {
  308. if(g_StiFileLog->IsValid()) {
  309. // Set UI bit in reporting
  310. if (g_fUIPermitted) {
  311. g_StiFileLog->SetReportMode(g_StiFileLog->QueryReportMode() | STI_TRACE_LOG_TOUI);
  312. }
  313. }
  314. else {
  315. #ifdef DEBUG
  316. OutputDebugString(TEXT("DoGlobalInit, could not open log file\n"));
  317. #endif
  318. return FALSE;
  319. }
  320. }
  321. else {
  322. #ifdef DEBUG
  323. OutputDebugString(TEXT("DoGlobalInit, unable to allocate STI_FILE_LOG\n"));
  324. #endif
  325. return FALSE;
  326. }
  327. //
  328. // Start Logging object's class factory
  329. //
  330. hr = StartLOGClassFactories();
  331. if (SUCCEEDED(hr)) {
  332. //
  333. // Create COM Logging Object
  334. //
  335. IWiaLog *pWiaLog = NULL;
  336. hr = CWiaLog::CreateInstance(IID_IWiaLog,(void**)&g_pIWiaLog);
  337. if (SUCCEEDED(hr)) {
  338. g_pIWiaLog->InitializeLogEx((BYTE*)g_hInst);
  339. DBG_TRC(("Starting STI/WIA Service..."));
  340. } else {
  341. #ifdef DEBUG
  342. OutputDebugString(TEXT("Failed to QI for IWiaLogEx...\n"));
  343. #endif
  344. return FALSE;
  345. }
  346. } else {
  347. return FALSE;
  348. }
  349. //
  350. // Initialize the lock manager
  351. //
  352. g_pStiLockMgr = new StiLockMgr();
  353. if (g_pStiLockMgr) {
  354. hr = g_pStiLockMgr->Initialize();
  355. if (FAILED(hr)) {
  356. #ifdef DEBUG
  357. OutputDebugString(TEXT("DoGlobalInit, could not initialize Lock Manager\n"));
  358. #endif
  359. return FALSE;
  360. }
  361. } else {
  362. #ifdef DEBUG
  363. OutputDebugString(TEXT("DoGlobalInit, unable to allocate Lock Manager\n"));
  364. #endif
  365. return FALSE;
  366. }
  367. //
  368. // Initialize work item scheduler
  369. //
  370. SchedulerInitialize();
  371. //
  372. // Create DeviceList event.
  373. //
  374. g_hDevListCompleteEvent = CreateEvent( NULL, // lpsaSecurity
  375. TRUE, // fManualReset
  376. FALSE, // fInitialState
  377. NULL ); // lpszEventName
  378. if( g_hDevListCompleteEvent == NULL ) {
  379. return FALSE;
  380. }
  381. //
  382. // Create and initialize global Device Manager
  383. //
  384. g_pDevMan = new CWiaDevMan();
  385. if (g_pDevMan) {
  386. hr = g_pDevMan->Initialize();
  387. if (SUCCEEDED(hr)) {
  388. hr = g_pDevMan->ReEnumerateDevices(DEV_MAN_FULL_REFRESH | DEV_MAN_STATUS_STARTP);
  389. if (FAILED(hr)) {
  390. DBG_ERR(("::DoGlobalInit, unable to enumerate devices"));
  391. }
  392. } else {
  393. DBG_ERR(("::DoGlobalInit, unable to initialize WIA device manager"));
  394. }
  395. } else {
  396. DBG_ERR(("::DoGlobalInit, Out of memory, could not create WIA device manager"));
  397. return FALSE;
  398. }
  399. //
  400. // Create and initialize global message handler
  401. //
  402. g_pMsgHandler = new CMsgHandler();
  403. if (g_pMsgHandler) {
  404. hr = g_pMsgHandler->Initialize();
  405. if (FAILED(hr)) {
  406. DBG_ERR(("::DoGlobalInit, unable to initialize internal Message handler"));
  407. }
  408. } else {
  409. DBG_ERR(("::DoGlobalInit, Out of memory, could not create internal Message handler"));
  410. return FALSE;
  411. }
  412. //
  413. // Create and initialize the object resposible for WIA Runtime event notifications
  414. //
  415. g_pWiaEventNotifier = new WiaEventNotifier();
  416. if (g_pWiaEventNotifier)
  417. {
  418. hr = g_pWiaEventNotifier->Initialize();
  419. if (FAILED(hr))
  420. {
  421. DBG_ERR(("::DoGlobalInit, WIA runtime event notifier failed to initialize...exiting"));
  422. return FALSE;
  423. }
  424. }
  425. else
  426. {
  427. DBG_ERR(("::DoGlobalInit, Out of memory, could not create WIA runtime event notifier...exiting"));
  428. return FALSE;
  429. }
  430. //
  431. // Initialize the Wia Service controller
  432. //
  433. hr = CWiaSvc::Initialize();
  434. if (FAILED(hr)) {
  435. #ifdef DEBUG
  436. OutputDebugString(TEXT("DoGlobalInit, unable to initialize Wia Service controller\n"));
  437. #endif
  438. return FALSE;
  439. }
  440. //
  441. // Read the command line arguments and set global data.
  442. //
  443. for (UINT uiParam = 0; uiParam < argc; uiParam ++ ) {
  444. switch (*argv[uiParam]) {
  445. case TEXT('A'): case TEXT('a'):
  446. // Running as user mode process
  447. g_fRunningAsService = FALSE;
  448. break;
  449. case TEXT('V'): case TEXT('v'):
  450. // Service UI is allowed
  451. g_fUIPermitted = TRUE;
  452. break;
  453. }
  454. }
  455. //
  456. // Do misc. cleanup, which we need to do on startup .
  457. //
  458. // 1. Some shipping packages for Win98 register STIMON entry to Run section, which
  459. // after upgrade creates problem with racing two copies of STIMON. Remove it.
  460. //
  461. {
  462. HKEY hkRun = NULL;
  463. LONG lRet ;
  464. LONG lcbValue = 0;
  465. BOOL fNeedToRegister = FALSE;
  466. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, &hkRun) == NO_ERROR) {
  467. DBG_TRC(("Removing erroneous entry on cleanup: HKLM\\..\\Run\\%S",REGSTR_VAL_MONITOR));
  468. lRet = RegQueryValue(hkRun,REGSTR_VAL_MONITOR,NULL,&lcbValue);
  469. fNeedToRegister = (lRet == NOERROR);
  470. RegDeleteValue (hkRun, REGSTR_VAL_MONITOR);
  471. RegCloseKey(hkRun);
  472. }
  473. // If needed register service
  474. if (fNeedToRegister ) {
  475. StiServiceInstall(NULL,NULL);
  476. }
  477. }
  478. return TRUE;
  479. }
  480. BOOL
  481. DoGlobalTermination(
  482. VOID
  483. )
  484. /*++
  485. Routine Description:
  486. Final termination
  487. Arguments:
  488. None
  489. Return Value:
  490. None.
  491. --*/
  492. {
  493. DBG_FN(DoGlobalTermination);
  494. //
  495. // Terminate work item scheduler
  496. //
  497. SchedulerTerminate();
  498. //
  499. // Delete the lock manager (which also removes it from the ROT)
  500. //
  501. if (g_pStiLockMgr) {
  502. delete g_pStiLockMgr;
  503. g_pStiLockMgr = NULL;
  504. }
  505. //
  506. // Delete global device manager
  507. //
  508. if (g_pDevMan) {
  509. delete g_pDevMan;
  510. g_pDevMan = NULL;
  511. }
  512. //
  513. // Close hDevListRefreshCompleteEvent event handle
  514. //
  515. CloseHandle(g_hDevListCompleteEvent);
  516. g_hDevListCompleteEvent = NULL;
  517. //
  518. // Release WIA Logging object
  519. //
  520. if(g_pIWiaLog) {
  521. DBG_TRC(("Exiting STI/WIA Service..."));
  522. if (g_pIWiaLog) {
  523. g_pIWiaLog->Release();
  524. }
  525. g_pIWiaLog = NULL;
  526. }
  527. if(g_EventLog) {
  528. delete g_EventLog;
  529. g_EventLog = NULL;
  530. }
  531. if (g_StiFileLog) {
  532. delete g_StiFileLog;
  533. g_StiFileLog = NULL;
  534. }
  535. if (ServerStartedEvent) {
  536. ::CloseHandle(ServerStartedEvent);
  537. }
  538. //
  539. // Shut down message loop
  540. //
  541. ::PostQuitMessage(0);
  542. //
  543. // Uninitialize COM.
  544. //
  545. ::CoUninitialize();
  546. if (g_bEventCritSectInitialized) {
  547. DeleteCriticalSection(&g_semEventNode);
  548. }
  549. if (g_bDevManCritSectInitialized) {
  550. DeleteCriticalSection(&g_semDeviceMan);
  551. }
  552. //
  553. // Destroy the debug context.
  554. //
  555. // WIA_DEBUG_DESTROY();
  556. return TRUE;
  557. }
  558. //
  559. // Guard to avoid reentrance in refresh routine
  560. //
  561. static LONG lRunningMessageLoop = 0L;
  562. HANDLE
  563. CreateMessageLoopThread(
  564. VOID
  565. )
  566. /*++
  567. Routine Description:
  568. Running primary service thread.
  569. If process is running as NT service, we don't have any messages to
  570. pump, so call it synchronously.
  571. Arguments:
  572. Return Value:
  573. None.
  574. --*/
  575. {
  576. if (InterlockedExchange(&lRunningMessageLoop,1L)) {
  577. return 0;
  578. }
  579. HANDLE hThread = NULL;
  580. #ifndef WINNT
  581. hThread = ::CreateThread(NULL,
  582. 0,
  583. (LPTHREAD_START_ROUTINE)StartMasterLoop,
  584. (LPVOID)NULL,
  585. 0,
  586. &g_dwMessagePumpThreadId);
  587. #else
  588. StartMasterLoop(NULL);
  589. #endif
  590. return hThread;
  591. }
  592. BOOL
  593. StartMasterLoop(
  594. LPVOID lpParam
  595. )
  596. /*++
  597. Routine Description:
  598. Running primary service thread
  599. Arguments:
  600. Return Value:
  601. None.
  602. --*/
  603. {
  604. MSG msg;
  605. DBG_FN(StartMasterLoop);
  606. //
  607. // If visible create master window
  608. //
  609. CreateMasterWindow();
  610. VisualizeServer(g_fUIPermitted);
  611. //
  612. // Initialize WIA.
  613. //
  614. InitWiaDevMan(WiaInitialize);
  615. #ifndef WINNT
  616. //Don't use windows messaging on NT
  617. //
  618. // Run message pump
  619. //
  620. while(GetMessage(&msg,NULL,0,0)) {
  621. //
  622. // Give WIA the first chance at dispatching messages. Note that
  623. // WIA hooks both message dispatch and the window proc. so that
  624. // both posted and sent messages can be detected.
  625. //
  626. //
  627. // currently there are no cases where sti needs to dispatch messages
  628. // to wia. Events are now dealt with directly.
  629. //
  630. #if 0
  631. if (DispatchWiaMsg(&msg) == S_OK) {
  632. continue;
  633. }
  634. #endif
  635. TranslateMessage(&msg);
  636. DispatchMessage(&msg);
  637. }
  638. // Indicate we are entering shutdown
  639. g_fServiceInShutdown = TRUE;
  640. InterlockedExchange(&lRunningMessageLoop,0L);
  641. #endif
  642. return TRUE;
  643. } // StartMasterLoop
  644. BOOL
  645. StartOperation(
  646. VOID
  647. )
  648. /*++
  649. Routine Description:
  650. Running primary service thread.
  651. If process is running as NT service, separate thread is created to
  652. handle window messages. This is necessary because primary thread becomes
  653. blocked as a control dispatcher , but we still need to have message loop
  654. running to deliver window messages.
  655. Arguments:
  656. Return Value:
  657. None.
  658. --*/
  659. {
  660. DBG_FN(StartOperation);
  661. DWORD dwError;
  662. #ifdef MAXDEBUG
  663. DBG_TRC(("Start operation entered"));
  664. #endif
  665. if (g_fRunningAsService) {
  666. //
  667. // If UI is permitted - create visible window
  668. // Note that we always create window for now, to allow hiding/unhiding it dynamically
  669. //
  670. g_hMessageLoopThread = CreateMessageLoopThread();
  671. // !!!??? need to pass command line args down from svchost.
  672. StiServiceMain(0, NULL);
  673. if ( g_hMessageLoopThread ) {
  674. ::CloseHandle(g_hMessageLoopThread);
  675. g_hMessageLoopThread = NULL;
  676. }
  677. }
  678. else {
  679. //
  680. // Running as application
  681. //
  682. // First thing - allow PnP sink to register properly
  683. g_fUseServiceCtrlSink = FALSE;
  684. dwError = StiServiceInitialize();
  685. g_dwMessagePumpThreadId = GetCurrentThreadId();
  686. StartMasterLoop(NULL);
  687. StiServiceStop();
  688. }
  689. return TRUE;
  690. } // StartOperation
  691. BOOL
  692. VisualizeServer(
  693. BOOL fVisualize
  694. )
  695. /*++
  696. Routine Description:
  697. Arguments:
  698. Return Value:
  699. None.
  700. --*/
  701. {
  702. g_fUIPermitted = fVisualize;
  703. if (::IsWindow(g_hMainWindow)) {
  704. ::ShowWindow(g_hMainWindow,fVisualize ? SW_SHOWNORMAL : SW_HIDE);
  705. }
  706. if (g_StiFileLog) {
  707. if(g_StiFileLog->IsValid()) {
  708. // Set UI bit in reporting
  709. if (g_fUIPermitted) {
  710. g_StiFileLog->SetReportMode(g_StiFileLog->QueryReportMode() | STI_TRACE_LOG_TOUI);
  711. }
  712. }
  713. }
  714. return TRUE;
  715. }
  716. BOOL
  717. UpdateRunningServer(
  718. VOID
  719. )
  720. /*++
  721. Routine Description:
  722. Arguments:
  723. None.
  724. Return Value:
  725. None.
  726. --*/
  727. {
  728. HWND hExistingWindow;
  729. hExistingWindow = FindWindow(g_szClass,NULL);
  730. if (!hExistingWindow) {
  731. return FALSE;
  732. }
  733. DBG_TRC(("Updating running service with refresh parameters"));
  734. //
  735. // Server already running , find it 's window and send a message
  736. // with new values of parameters
  737. //
  738. ::ShowWindow(hExistingWindow,g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE);
  739. // Refresh requested ?
  740. if (g_fRefreshDeviceList) {
  741. // Refresh device list
  742. ::PostMessage(hExistingWindow,STIMON_MSG_REFRESH,1,0L);
  743. }
  744. if (STIMON_AD_DEFAULT_POLL_INTERVAL != g_uiDefaultPollTimeout) {
  745. ::SendMessage(hExistingWindow,STIMON_MSG_SET_PARAMETERS,STIMON_MSG_SET_TIMEOUT,g_uiDefaultPollTimeout);
  746. }
  747. return TRUE;
  748. }
  749. STDAPI
  750. DllRegisterServer(
  751. VOID
  752. )
  753. {
  754. StiServiceInstall(NULL,NULL);
  755. InitWiaDevMan(WiaRegister);
  756. return S_OK;
  757. }
  758. /*****************************************************************************
  759. *
  760. * @doc INTERNAL
  761. *
  762. * @func void | DllUnregisterServer |
  763. *
  764. * Unregister our classes from OLE/COM/ActiveX/whatever its name is.
  765. *
  766. *****************************************************************************/
  767. STDAPI
  768. DllUnregisterServer(
  769. VOID
  770. )
  771. {
  772. InitWiaDevMan(WiaUnregister);
  773. StiServiceRemove();
  774. return S_OK;
  775. }
  776. //
  777. // Methods needed for linking to STIRT (stiobj.c calls these).
  778. // Some of these methods are simply dummies.
  779. //
  780. #ifdef __cplusplus
  781. extern "C" {
  782. #endif
  783. BOOL
  784. EXTERNAL
  785. DllInitializeCOM(
  786. void
  787. )
  788. {
  789. //
  790. // Initialize COM.
  791. //
  792. HRESULT hr = CoInitializeEx(0,COINIT_MULTITHREADED);
  793. if (FAILED(hr)) {
  794. return FALSE;
  795. }
  796. return TRUE;
  797. }
  798. BOOL EXTERNAL
  799. DllUnInitializeCOM(
  800. void
  801. )
  802. {
  803. //
  804. // Uninitialize COM
  805. //
  806. CoUninitialize();
  807. return TRUE;
  808. }
  809. void EXTERNAL
  810. DllAddRef(void)
  811. {
  812. return;
  813. }
  814. void EXTERNAL
  815. DllRelease(void)
  816. {
  817. return;
  818. }
  819. #ifdef __cplusplus
  820. };
  821. #endif