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.

826 lines
25 KiB

  1. //---------------------------------------------------------------------
  2. // Copyright (c)1998-1999 Microsoft Corporation, All Rights Reserved.
  3. //
  4. // irtranp.cpp
  5. //
  6. // This file holds the main entry points for the IrTran-P service.
  7. // IrTranP() is the entry point that starts the listening, and
  8. // UninitializeIrTranP() shuts it down (and cleans everything up).
  9. //
  10. // Author:
  11. //
  12. // Edward Reus (edwardr) 02-26-98 Initial coding.
  13. //
  14. // Edward Reus (edwardr) 08-27-99 Finish modifications for
  15. // WIA Millennium port.
  16. //
  17. // Note: Currently the Millennium version will only listen on IrCOMM.
  18. //
  19. //---------------------------------------------------------------------
  20. #include "precomp.h"
  21. #include <mbstring.h>
  22. #define SZ_REG_KEY_IRTRANP "Control Panel\\Infrared\\IrTranP"
  23. #define SZ_REG_DISABLE_IRCOMM "DisableIrCOMM"
  24. //---------------------------------------------------------------------
  25. // Listen ports array:
  26. //---------------------------------------------------------------------
  27. typedef struct _LISTEN_PORT
  28. {
  29. char *pszService; // Service to start.
  30. BOOL fIsIrCOMM; // TRUE iff IrCOMM 9-wire mode.
  31. DWORD dwListenStatus; // Status for port.
  32. } LISTEN_PORT;
  33. static LISTEN_PORT aListenPorts[] =
  34. {
  35. // Service Name IrCOMM ListenStatus
  36. {IRCOMM_9WIRE, TRUE, STATUS_STOPPED },
  37. // {IRTRANP_SERVICE, FALSE, STATUS_STOPPED },
  38. // {IR_TEST_SERVICE, FALSE, STATUS_STOPPED }, 2nd test listen port.
  39. {0, FALSE, STATUS_STOPPED }
  40. };
  41. #define INDEX_IRCOMM 0
  42. #define INDEX_IRTRANPV1 1
  43. CCONNECTION_MAP *g_pConnectionMap = 0;
  44. CIOSTATUS *g_pIoStatus = 0;
  45. HANDLE g_hShutdownEvent;
  46. BOOL g_fShuttingDownTRANPThread = FALSE;
  47. DWORD g_dwTRANPThreadId = 0;
  48. extern HINSTANCE g_hInst; // Handle to ircamera.dll USD
  49. //---------------------------------------------------------------------
  50. // Globals:
  51. //---------------------------------------------------------------------
  52. HANDLE g_UserToken = NULL;
  53. HKEY g_hUserKey = NULL;
  54. BOOL g_fDisableIrTranPv1 = FALSE;
  55. BOOL g_fDisableIrCOMM = FALSE;
  56. BOOL g_fExploreOnCompletion = TRUE;
  57. BOOL g_fSaveAsUPF = FALSE;
  58. BOOL g_fAllowReceives = TRUE;
  59. char *g_pszTempPicturesFolder = 0;
  60. BOOL g_fWSAStartupCalled = FALSE;
  61. void *g_pvIrUsdDevice = 0; // WIA IrUsdDevice Object.
  62. //---------------------------------------------------------------------
  63. // GetUserToken()
  64. //
  65. // The "main" part of irxfer.dll (in ..\irxfer) maintains a token
  66. // for user that is currently logged in (if any).
  67. //---------------------------------------------------------------------
  68. HANDLE GetUserToken()
  69. {
  70. return g_UserToken;
  71. }
  72. //---------------------------------------------------------------------
  73. // GetUserKey()
  74. //
  75. //---------------------------------------------------------------------
  76. HKEY GetUserKey()
  77. {
  78. return g_hUserKey;
  79. }
  80. //---------------------------------------------------------------------
  81. // GetModule()
  82. //
  83. //---------------------------------------------------------------------
  84. HINSTANCE GetModule()
  85. {
  86. return g_hInst;
  87. }
  88. //---------------------------------------------------------------------
  89. // CheckSaveAsUPF()
  90. //
  91. // Return TRUE iff pictures need to be saved in .UPF (as opposed to
  92. // .JPEG) format.
  93. //---------------------------------------------------------------------
  94. BOOL CheckSaveAsUPF()
  95. {
  96. return g_fSaveAsUPF;
  97. }
  98. //---------------------------------------------------------------------
  99. // CheckExploreOnCompletion()
  100. //
  101. // Return TRUE iff we want to popup an explorer on the directory
  102. // containing the newly transfered pictures.
  103. //---------------------------------------------------------------------
  104. BOOL CheckExploreOnCompletion()
  105. {
  106. return g_fExploreOnCompletion;
  107. }
  108. /* FlushInputQueue is a private routine to collect and dispatch all
  109. * messages in the input queue. It returns TRUE if a WM_QUIT message
  110. * was detected in the queue, FALSE otherwise.
  111. */
  112. BOOL FlushInputQueue(VOID)
  113. {
  114. MSG msgTemp;
  115. while (PeekMessage(&msgTemp, NULL, 0, 0, PM_REMOVE)) {
  116. DispatchMessage(&msgTemp);
  117. // If we see a WM_QUIT in the queue, we need to do the same
  118. // sort of thing that a modal dialog does: break out of our
  119. // waiting, and repost the WM_QUIT to the queue so that the
  120. // next message loop up in the app will also see it.
  121. if (msgTemp.message == WM_QUIT) {
  122. PostQuitMessage((int)msgTemp.wParam);
  123. return TRUE;
  124. }
  125. }
  126. return FALSE;
  127. }
  128. /* WaitAndYield() waits for the specified object using
  129. * MsgWaitForMultipleObjects. If messages are received,
  130. * they are dispatched and waiting continues. The return
  131. * value is the same as from MsgWaitForMultipleObjects.
  132. */
  133. DWORD WaitAndYield(HANDLE hObject, DWORD dwTimeout)
  134. {
  135. DWORD dwTickCount, dwWakeReason, dwTemp;
  136. do {
  137. /* Flush any messages before we wait. This is because
  138. * MsgWaitForMultipleObjects will only return when NEW
  139. * messages are put in the queue.
  140. */
  141. if (FlushInputQueue()) {
  142. dwWakeReason = WAIT_TIMEOUT;
  143. break;
  144. }
  145. // in case we handle messages, we want close to a true timeout
  146. if ((dwTimeout != 0) &&
  147. (dwTimeout != (DWORD)-1)) {
  148. // if we can timeout, store the current tick count
  149. // every time through
  150. dwTickCount = GetTickCount();
  151. }
  152. dwWakeReason = MsgWaitForMultipleObjects(1,
  153. &hObject,
  154. FALSE,
  155. dwTimeout,
  156. QS_ALLINPUT);
  157. // if we got a message, dispatch it, then try again
  158. if (dwWakeReason == 1) {
  159. // if we can timeout, see if we did before processing the message
  160. // that way, if we haven't timed out yet, we'll get at least one
  161. // more shot at the event
  162. if ((dwTimeout != 0) &&
  163. (dwTimeout != (DWORD)-1)) {
  164. if ((dwTemp = (GetTickCount()-dwTickCount)) >= dwTimeout) {
  165. // if we timed out, make us drop through
  166. dwWakeReason = WAIT_TIMEOUT;
  167. } else {
  168. // subtract elapsed time from timeout and continue
  169. // (we don't count time spent dispatching message)
  170. dwTimeout -= dwTemp;
  171. }
  172. }
  173. if (FlushInputQueue()) {
  174. dwWakeReason = WAIT_TIMEOUT;
  175. break;
  176. }
  177. }
  178. } while (dwWakeReason == 1);
  179. return dwWakeReason;
  180. }
  181. //---------------------------------------------------------------------
  182. // GetImageDirectory();
  183. //
  184. // This is the temporary directory where the pictures sent by the
  185. // camera will be held. WIA will then "down load" these to their
  186. // final destination (usually this will be My Pictures).
  187. //
  188. //---------------------------------------------------------------------
  189. CHAR *GetImageDirectory()
  190. {
  191. char *pszPicturesFolder;
  192. char szTempFolder[1+MAX_PATH];
  193. DWORD dwPicturesFolderLen;
  194. DWORD dwStatus = NO_ERROR;
  195. DWORD dwLen;
  196. if (!g_pszTempPicturesFolder)
  197. {
  198. dwLen = GetTempPath(MAX_PATH,szTempFolder);
  199. if ((!dwLen)||(dwLen > MAX_PATH))
  200. {
  201. dwStatus = GetLastError();
  202. WIAS_TRACE((g_hInst,"GetUserDirectroy(): GetTempPath() failed: %d",dwStatus));
  203. return NULL;
  204. }
  205. //
  206. // Make sure the directory exists:
  207. //
  208. if (!CreateDirectory(szTempFolder,0))
  209. {
  210. dwStatus = GetLastError();
  211. if ( (dwStatus == ERROR_ALREADY_EXISTS)
  212. || (dwStatus == ERROR_ACCESS_DENIED) )
  213. {
  214. dwStatus = NO_ERROR;
  215. }
  216. else if (dwStatus != NO_ERROR)
  217. {
  218. return 0;
  219. }
  220. }
  221. //
  222. // Construct the subdirectory path string that will actually hold the pictures:
  223. // This will be something like: C:\temp\irtranp
  224. //
  225. dwPicturesFolderLen = sizeof(CHAR)*( strlen(szTempFolder)
  226. + sizeof(SZ_SLASH)
  227. + sizeof(SZ_SUBDIRECTORY)
  228. + 1 );
  229. g_pszTempPicturesFolder = (CHAR*)AllocateMemory(dwPicturesFolderLen);
  230. if (!g_pszTempPicturesFolder)
  231. {
  232. return 0; // Memory allocation failed!
  233. }
  234. strcpy(g_pszTempPicturesFolder,szTempFolder);
  235. if (szTempFolder[dwLen-1] != SLASH)
  236. {
  237. strcat(g_pszTempPicturesFolder,SZ_SLASH);
  238. }
  239. strcat(g_pszTempPicturesFolder,SZ_SUBDIRECTORY);
  240. //
  241. // Make sure the subdirectory exists:
  242. //
  243. if (!CreateDirectory(g_pszTempPicturesFolder,0))
  244. {
  245. dwStatus = GetLastError();
  246. if (dwStatus == ERROR_ALREADY_EXISTS)
  247. {
  248. dwStatus = NO_ERROR;
  249. }
  250. else if (dwStatus != NO_ERROR)
  251. {
  252. return 0;
  253. }
  254. }
  255. }
  256. pszPicturesFolder = g_pszTempPicturesFolder;
  257. return pszPicturesFolder;
  258. }
  259. //---------------------------------------------------------------------
  260. // ReceivesAllowed()
  261. //
  262. // Using the IR configuration window (available from the wireless network
  263. // icon in the control panel) you can disable communications with IR
  264. // devices. This function returns the state of IR communications, FALSE
  265. // is disabled, TRUE is enabled.
  266. //---------------------------------------------------------------------
  267. BOOL ReceivesAllowed()
  268. {
  269. return g_fAllowReceives;
  270. }
  271. //---------------------------------------------------------------------
  272. // SetupListenConnection()
  273. //
  274. //---------------------------------------------------------------------
  275. DWORD SetupListenConnection( IN CHAR *pszService,
  276. IN BOOL fIsIrCOMM,
  277. IN HANDLE hIoCompletionPort )
  278. {
  279. DWORD dwStatus = NO_ERROR;
  280. CIOPACKET *pIoPacket;
  281. CCONNECTION *pConnection;
  282. // See if the connection already exists:
  283. if (g_pConnectionMap->LookupByServiceName(pszService))
  284. {
  285. return NO_ERROR;
  286. }
  287. // Makeup and initialize a new connection object:
  288. pConnection = new CCONNECTION;
  289. if (!pConnection)
  290. {
  291. return E_OUTOFMEMORY;
  292. }
  293. dwStatus = pConnection->InitializeForListen( pszService,
  294. fIsIrCOMM,
  295. hIoCompletionPort );
  296. if (dwStatus)
  297. {
  298. WIAS_ERROR((g_hInst,"SetupForListen(): InitializeForListen(%s) failed: %d",pszService, dwStatus));
  299. return dwStatus;
  300. }
  301. pIoPacket = new CIOPACKET;
  302. if (!pIoPacket)
  303. {
  304. WIAS_ERROR((g_hInst,"SetupForListen(): new CIOPACKET failed"));
  305. delete pConnection;
  306. return E_OUTOFMEMORY;
  307. }
  308. // Setup the IO packet:
  309. dwStatus = pIoPacket->Initialize( PACKET_KIND_LISTEN,
  310. pConnection->GetListenSocket(),
  311. INVALID_SOCKET,
  312. hIoCompletionPort );
  313. if (dwStatus != NO_ERROR)
  314. {
  315. return dwStatus;
  316. }
  317. pConnection->SetSocket(pIoPacket->GetSocket());
  318. if (!g_pConnectionMap->Add(pConnection,pIoPacket->GetListenSocket()))
  319. {
  320. WIAS_ERROR((g_hInst,"SetupForListen(): Add(pConnection) ConnectionMap Failed."));
  321. return 1;
  322. }
  323. return dwStatus;
  324. }
  325. //---------------------------------------------------------------------
  326. // TeardownListenConnection()
  327. //
  328. //---------------------------------------------------------------------
  329. DWORD TeardownListenConnection( IN char *pszService )
  330. {
  331. DWORD dwStatus = NO_ERROR;
  332. CCONNECTION *pConnection;
  333. // Look for the connection associated with the service name:
  334. pConnection = g_pConnectionMap->LookupByServiceName(pszService);
  335. if (pConnection)
  336. {
  337. g_pConnectionMap->RemoveConnection(pConnection);
  338. pConnection->CloseSocket();
  339. pConnection->CloseListenSocket();
  340. }
  341. return dwStatus;
  342. }
  343. //---------------------------------------------------------------------
  344. // EnableDisableIrCOMM()
  345. //
  346. //---------------------------------------------------------------------
  347. DWORD EnableDisableIrCOMM( IN BOOL fDisable )
  348. {
  349. DWORD dwStatus;
  350. if (fDisable)
  351. {
  352. dwStatus = TeardownListenConnection(
  353. aListenPorts[INDEX_IRCOMM].pszService);
  354. WIAS_ERROR((g_hInst,"IrTranP: TeardownListenConnection(%s): %d", aListenPorts[INDEX_IRCOMM].pszService,dwStatus));
  355. }
  356. else
  357. {
  358. dwStatus = SetupListenConnection(
  359. aListenPorts[INDEX_IRCOMM].pszService,
  360. aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
  361. g_pIoStatus->GetIoCompletionPort() );
  362. WIAS_TRACE((g_hInst,"IrTranP: SetupListenConnection(%s): %d", aListenPorts[INDEX_IRCOMM].pszService, dwStatus));
  363. }
  364. return dwStatus;
  365. }
  366. //---------------------------------------------------------------------
  367. // EnableDisableIrTranPv1()
  368. //
  369. //---------------------------------------------------------------------
  370. DWORD EnableDisableIrTranPv1( IN BOOL fDisable )
  371. {
  372. DWORD dwStatus;
  373. if (fDisable)
  374. {
  375. dwStatus = TeardownListenConnection(
  376. aListenPorts[INDEX_IRTRANPV1].pszService);
  377. }
  378. else
  379. {
  380. dwStatus = SetupListenConnection(
  381. aListenPorts[INDEX_IRTRANPV1].pszService,
  382. aListenPorts[INDEX_IRTRANPV1].fIsIrCOMM,
  383. g_pIoStatus->GetIoCompletionPort() );
  384. }
  385. return dwStatus;
  386. }
  387. //---------------------------------------------------------------------
  388. // IrTranp()
  389. //
  390. //---------------------------------------------------------------------
  391. DWORD WINAPI IrTranP( IN void *pvIrUsdDevice )
  392. {
  393. int i = 0;
  394. WSADATA wsaData;
  395. WORD wVersion = MAKEWORD(1,1);
  396. DWORD dwStatus;
  397. CCONNECTION *pConnection;
  398. g_dwTRANPThreadId = ::GetCurrentThreadId();
  399. //
  400. // Initialize Memory Management:
  401. //
  402. dwStatus = InitializeMemory();
  403. if (dwStatus)
  404. {
  405. WIAS_ERROR((g_hInst,"IrTranP(): InitializeMemory() failed: %d\n",dwStatus));
  406. return dwStatus;
  407. }
  408. //
  409. // This directory will be set as needed. It is only non-null in the case
  410. // where we are re-starting the IrTran-P thread:
  411. //
  412. if (g_pszTempPicturesFolder)
  413. {
  414. FreeMemory(g_pszTempPicturesFolder);
  415. g_pszTempPicturesFolder = 0;
  416. }
  417. //
  418. // Initialize Winsock2 if neccessary:
  419. //
  420. if (!g_fWSAStartupCalled)
  421. {
  422. if (WSAStartup(wVersion,&wsaData) == SOCKET_ERROR)
  423. {
  424. dwStatus = WSAGetLastError();
  425. WIAS_ERROR((g_hInst,"WSAStartup(0x%x) failed with error %d\n", wVersion, dwStatus ));
  426. return dwStatus;
  427. }
  428. g_fWSAStartupCalled = TRUE;
  429. }
  430. // Event used to signal back to "main" thread that the
  431. // IrTran-P thread is exiting.
  432. //
  433. // NoSecurity, Auto-Reset, Initially Not Signaled, No Name.
  434. //
  435. g_hShutdownEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
  436. if (!g_hShutdownEvent)
  437. {
  438. dwStatus = GetLastError();
  439. WIAS_ERROR((g_hInst,"IrTranP(): CreateEvent() Failed: %d",dwStatus));
  440. return dwStatus;
  441. }
  442. // Create/initialize a object to keep track of the threading...
  443. g_pIoStatus = new CIOSTATUS;
  444. if (!g_pIoStatus)
  445. {
  446. WIAS_ERROR((g_hInst,"new CIOSTATUS failed."));
  447. return E_OUTOFMEMORY;
  448. }
  449. dwStatus = g_pIoStatus->Initialize();
  450. if (dwStatus != NO_ERROR)
  451. {
  452. WIAS_ERROR((g_hInst,"g_pIoStatus->Initialize(): Failed: %d",dwStatus));
  453. return dwStatus;
  454. }
  455. // Need to keep track of the open sockets and the number of
  456. // pending IOs on each...
  457. g_pConnectionMap = new CCONNECTION_MAP;
  458. if (!g_pConnectionMap)
  459. {
  460. WIAS_ERROR((g_hInst,"new CCONNECTION_MAP failed."));
  461. return E_OUTOFMEMORY;
  462. }
  463. if (!g_pConnectionMap->Initialize())
  464. {
  465. return 1;
  466. }
  467. // Create a CIOPACKET for each defined listen port. These are
  468. // what we will listen on.
  469. //
  470. // BUGBUG Should we really loop indefintely setting up connection or establish some limit on retries ? VS
  471. //
  472. while (!g_fShuttingDownTRANPThread )
  473. {
  474. dwStatus = SetupListenConnection(
  475. aListenPorts[INDEX_IRCOMM].pszService,
  476. aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
  477. g_pIoStatus->GetIoCompletionPort() );
  478. if (dwStatus)
  479. {
  480. WIAS_TRACE((g_hInst,"SetupListenConnection(%s) Status: %d",aListenPorts[i].pszService,dwStatus));
  481. //
  482. // BUGBUG Analyze error and stop processing if it doesn't make sense !!! VS
  483. //
  484. }
  485. else
  486. {
  487. WIAS_TRACE((g_hInst,"SetupListenConnection(%s) Ready",aListenPorts[i].pszService));
  488. aListenPorts[INDEX_IRCOMM].dwListenStatus = STATUS_RUNNING;
  489. break;
  490. }
  491. // Wait for timeout period, but wake up if we need to stop
  492. // Sleep(5000);
  493. WaitAndYield(g_hShutdownEvent,5000);
  494. }
  495. if (!g_fShuttingDownTRANPThread) {
  496. //
  497. // Wait on incomming connections and data, then process it.
  498. //
  499. g_pvIrUsdDevice = pvIrUsdDevice;
  500. dwStatus = ProcessIoPackets(g_pIoStatus);
  501. }
  502. //
  503. // Shutting down
  504. //
  505. g_pvIrUsdDevice = 0;
  506. WIAS_TRACE((g_hInst,"ProcessIoPackets(): dwStatus: %d",dwStatus));
  507. //
  508. // Cleanup and close any open handles:
  509. //
  510. while (pConnection=g_pConnectionMap->RemoveNext())
  511. {
  512. delete pConnection;
  513. }
  514. delete g_pConnectionMap;
  515. g_pConnectionMap = 0;
  516. delete g_pIoStatus;
  517. g_pIoStatus = 0;
  518. // Signal the shutdown event that the IrTran-P thread is exiting:
  519. if (g_hShutdownEvent)
  520. {
  521. SetEvent(g_hShutdownEvent);
  522. }
  523. return dwStatus;
  524. }
  525. //---------------------------------------------------------------------
  526. // IrTranPEnableIrCOMMFailed()
  527. //
  528. //---------------------------------------------------------------------
  529. void IrTranPEnableIrCOMMFailed( DWORD dwErrorCode )
  530. {
  531. DWORD dwStatus;
  532. // An error occured on enable, make sure the registry value
  533. // is set to disable (so UI will match the actual state).
  534. HKEY hKey = 0;
  535. HKEY hUserKey = GetUserKey();
  536. HANDLE hUserToken = GetUserToken();
  537. HINSTANCE hInstance = GetModule();
  538. DWORD dwDisposition;
  539. if (RegCreateKeyEx(hUserKey,
  540. SZ_REG_KEY_IRTRANP,
  541. 0, // reserved MBZ
  542. 0, // class name
  543. REG_OPTION_NON_VOLATILE,
  544. KEY_SET_VALUE,
  545. 0, // security attributes
  546. &hKey,
  547. &dwDisposition))
  548. {
  549. WIAS_TRACE((g_hInst,"IrTranP: RegCreateKeyEx(): '%' failed %d", SZ_REG_KEY_IRTRANP, GetLastError()));
  550. }
  551. if ( (hKey)
  552. && (hUserToken)
  553. && (::ImpersonateLoggedOnUser(hUserToken)))
  554. {
  555. DWORD dwDisableIrCOMM = TRUE;
  556. dwStatus = RegSetValueEx(hKey,
  557. SZ_REG_DISABLE_IRCOMM,
  558. 0,
  559. REG_DWORD,
  560. (UCHAR*)&dwDisableIrCOMM,
  561. sizeof(dwDisableIrCOMM) );
  562. if (dwStatus != ERROR_SUCCESS)
  563. {
  564. WIAS_TRACE((g_hInst,"IrTranP: Can't set DisableIrCOMM to TRUE in registry. Error: %d",dwStatus));
  565. }
  566. ::RevertToSelf();
  567. }
  568. if (hKey)
  569. {
  570. RegCloseKey(hKey);
  571. }
  572. #if FALSE
  573. WCHAR *pwszMessage = NULL;
  574. WCHAR *pwszCaption = NULL;
  575. DWORD dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
  576. | FORMAT_MESSAGE_IGNORE_INSERTS
  577. | FORMAT_MESSAGE_FROM_HMODULE);
  578. dwStatus = FormatMessageW(dwFlags,
  579. hInstance,
  580. CAT_IRTRANP,
  581. MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  582. (LPTSTR)(&pwszCaption),
  583. 0, // Minimum size to allocate.
  584. NULL); // va_list args...
  585. if (dwStatus == 0)
  586. {
  587. #ifdef DBG_ERROR
  588. DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
  589. #endif
  590. return;
  591. }
  592. //
  593. // Hack: Make sure the caption doesn't end with newline-formfeed...
  594. //
  595. WCHAR *pwsz = pwszCaption;
  596. while (*pwsz)
  597. {
  598. if (*pwsz < 0x20) // 0x20 is always a space...
  599. {
  600. *pwsz = 0;
  601. break;
  602. }
  603. else
  604. {
  605. pwsz++;
  606. }
  607. }
  608. WCHAR wszErrorCode[20];
  609. WCHAR *pwszErrorCode = (WCHAR*)wszErrorCode;
  610. wsprintfW(wszErrorCode,L"%d",dwErrorCode);
  611. dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
  612. | FORMAT_MESSAGE_ARGUMENT_ARRAY
  613. | FORMAT_MESSAGE_FROM_HMODULE);
  614. dwStatus = FormatMessageW(dwFlags,
  615. hInstance,
  616. MC_IRTRANP_IRCOM_FAILED,
  617. MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  618. (LPTSTR)(&pwszMessage),
  619. 0, // Minimum size to allocate.
  620. (va_list*)&pwszErrorCode);
  621. if (dwStatus == 0)
  622. {
  623. #ifdef DBG_ERROR
  624. DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
  625. #endif
  626. if (pwszMessage)
  627. {
  628. LocalFree(pwszMessage);
  629. }
  630. return;
  631. }
  632. dwStatus = MessageBoxW( NULL,
  633. pwszMessage,
  634. pwszCaption,
  635. (MB_OK|MB_ICONERROR|MB_SETFOREGROUND|MB_TOPMOST) );
  636. if (pwszMessage)
  637. {
  638. LocalFree(pwszMessage);
  639. }
  640. if (pwszCaption)
  641. {
  642. LocalFree(pwszCaption);
  643. }
  644. #endif
  645. }
  646. //---------------------------------------------------------------------
  647. // UninitializeIrTranP()
  648. //
  649. //---------------------------------------------------------------------
  650. BOOL UninitializeIrTranP( HANDLE hThread )
  651. {
  652. BOOL fSuccess = TRUE;
  653. DWORD dwStatus;
  654. HANDLE hIoCP = g_pIoStatus->GetIoCompletionPort();
  655. g_fShuttingDownTRANPThread = TRUE;
  656. // Inform TRANP thread it has to die
  657. ::PostThreadMessage(g_dwTRANPThreadId,WM_QUIT,0,0);
  658. if (hIoCP != INVALID_HANDLE_VALUE)
  659. {
  660. if (!PostQueuedCompletionStatus(hIoCP,0,IOKEY_SHUTDOWN,0))
  661. {
  662. // Unexpected error...
  663. dwStatus = GetLastError();
  664. }
  665. while (WAIT_TIMEOUT == WaitForSingleObject(g_hShutdownEvent,0))
  666. {
  667. Sleep(100);
  668. }
  669. CloseHandle(g_hShutdownEvent);
  670. }
  671. //
  672. // TRANP thread should be dead by now . In case it isn't wait on it's handle and terminate
  673. // Otherwise we have a small chance of unloading DLL before thread is dead, shutting down WIA service
  674. //
  675. dwStatus = ::WaitForSingleObject(hThread,100);
  676. if (dwStatus == WAIT_TIMEOUT) {
  677. // Have to be rude
  678. // BUGBUG Assert
  679. ::TerminateThread(hThread,NOERROR);
  680. }
  681. // Shutdown memory management:
  682. dwStatus = UninitializeMemory();
  683. return fSuccess;
  684. }
  685. #ifdef RUN_AS_EXE
  686. //---------------------------------------------------------------------
  687. // main()
  688. //
  689. //---------------------------------------------------------------------
  690. int __cdecl main( int argc, char **argv )
  691. {
  692. DWORD dwStatus;
  693. printf("IrTran-P: Start\n");
  694. dwStatus = IrTranP( NULL );
  695. if (dwStatus)
  696. {
  697. printf("IrTran-P: Status: 0x%x (%d)\n",dwStatus,dwStatus);
  698. }
  699. return 0;
  700. }
  701. #endif