Source code of Windows XP (NT5)
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.

799 lines
22 KiB

  1. //---------------------------------------------------------------------
  2. // Copyright (C)1998 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. //---------------------------------------------------------------------
  15. #include "precomp.h"
  16. #include <mbstring.h>
  17. #include "irrecv.h"
  18. #include "eventlog.h"
  19. #define WSZ_REG_KEY_IRTRANP L"Control Panel\\Infrared\\IrTranP"
  20. #define WSZ_REG_DISABLE_IRCOMM L"DisableIrCOMM"
  21. //---------------------------------------------------------------------
  22. // Listen ports array:
  23. //---------------------------------------------------------------------
  24. typedef struct _LISTEN_PORT
  25. {
  26. char *pszService; // Service to start.
  27. BOOL fIsIrCOMM; // TRUE iff IrCOMM 9-wire mode.
  28. DWORD dwListenStatus; // Status for port.
  29. } LISTEN_PORT;
  30. static LISTEN_PORT aListenPorts[] =
  31. {
  32. // Service Name IrCOMM ListenStatus
  33. {IRTRANP_SERVICE, FALSE, STATUS_STOPPED },
  34. {IRCOMM_9WIRE, TRUE, STATUS_STOPPED },
  35. // {IR_TEST_SERVICE, FALSE, STATUS_STOPPED }, 2nd test listen port.
  36. {0, FALSE, STATUS_STOPPED }
  37. };
  38. #define INDEX_IRTRANPV1 0
  39. #define INDEX_IRCOMM 1
  40. CCONNECTION_MAP *g_pConnectionMap = 0;
  41. CIOSTATUS *g_pIoStatus = 0;
  42. HANDLE g_hShutdownEvent;
  43. //
  44. // The following globals and functions are defined in ..\irxfer\irxfer.cxx
  45. //
  46. extern "C" HINSTANCE ghInstance;
  47. extern "C" HANDLE g_UserToken;
  48. extern HKEY g_hUserKey;
  49. extern BOOL g_fDisableIrTranPv1;
  50. extern BOOL g_fDisableIrCOMM;
  51. extern BOOL g_fExploreOnCompletion;
  52. extern BOOL g_fSaveAsUPF;
  53. extern wchar_t g_DefaultPicturesFolder[];
  54. extern wchar_t g_SpecifiedPicturesFolder[];
  55. extern BOOL g_fAllowReceives;
  56. extern BOOL IrTranPFlagChanged( IN const WCHAR *pwszDisabledValueName,
  57. IN BOOL NotPresentValue,
  58. IN OUT BOOL *pfDisabled );
  59. //---------------------------------------------------------------------
  60. // GetUserToken()
  61. //
  62. // The "main" part of irxfer.dll (in ..\irxfer) maintains a token
  63. // for user that is currently logged in (if any).
  64. //---------------------------------------------------------------------
  65. HANDLE GetUserToken()
  66. {
  67. return g_UserToken;
  68. }
  69. //---------------------------------------------------------------------
  70. // GetUserKey()
  71. //
  72. //---------------------------------------------------------------------
  73. HKEY GetUserKey()
  74. {
  75. return g_hUserKey;
  76. }
  77. //---------------------------------------------------------------------
  78. // GetModule()
  79. //
  80. //---------------------------------------------------------------------
  81. HINSTANCE GetModule()
  82. {
  83. return ghInstance;
  84. }
  85. //---------------------------------------------------------------------
  86. // GetRpcBinding()
  87. //
  88. //---------------------------------------------------------------------
  89. handle_t GetRpcBinding()
  90. {
  91. if (g_pIoStatus)
  92. {
  93. return g_pIoStatus->GetRpcBinding();
  94. }
  95. else
  96. {
  97. return 0;
  98. }
  99. }
  100. //---------------------------------------------------------------------
  101. // CheckSaveAsUPF()
  102. //
  103. // Return TRUE iff pictures need to be saved in .UPF (as opposed to
  104. // .JPEG) format.
  105. //---------------------------------------------------------------------
  106. BOOL CheckSaveAsUPF()
  107. {
  108. return g_fSaveAsUPF;
  109. }
  110. //---------------------------------------------------------------------
  111. // CheckExploreOnCompletion()
  112. //
  113. // Return TRUE iff we want to popup an explorer on the directory
  114. // containing the newly transfered pictures.
  115. //---------------------------------------------------------------------
  116. BOOL CheckExploreOnCompletion()
  117. {
  118. return g_fExploreOnCompletion;
  119. }
  120. //---------------------------------------------------------------------
  121. // GetUserDirectory();
  122. //
  123. // The "main" part of irxfer.dll (in ..\irxfer) maintains the path
  124. // for My Documents\My Pictures for the currently logged in user.
  125. //
  126. // The path is set when the user first logs on.
  127. //---------------------------------------------------------------------
  128. WCHAR *GetUserDirectory()
  129. {
  130. WCHAR *pwszPicturesFolder;
  131. if (g_SpecifiedPicturesFolder[0])
  132. {
  133. pwszPicturesFolder = g_SpecifiedPicturesFolder;
  134. }
  135. else if (g_DefaultPicturesFolder[0])
  136. {
  137. pwszPicturesFolder = g_DefaultPicturesFolder;
  138. }
  139. else
  140. {
  141. DWORD dwLen;
  142. if ( ((dwLen=GetWindowsDirectory(g_DefaultPicturesFolder,MAX_PATH)) > 0)
  143. && (dwLen < MAX_PATH) && (dwLen > 0) )
  144. {
  145. g_DefaultPicturesFolder[2] = 0; // Just want "C:"...
  146. wcscat(g_DefaultPicturesFolder,WSZ_BACKUP_MY_PICTURES);
  147. }
  148. else
  149. {
  150. wcscpy(g_DefaultPicturesFolder,WSZ_BACKUP_DRIVE);
  151. wcscat(g_DefaultPicturesFolder,WSZ_BACKUP_MY_PICTURES);
  152. }
  153. pwszPicturesFolder = g_DefaultPicturesFolder;
  154. }
  155. return pwszPicturesFolder;
  156. }
  157. //---------------------------------------------------------------------
  158. // ReceivesAllowed()
  159. //
  160. // Using the IR configuration window (available from the wireless network
  161. // icon in the control panel) you can disable communications with IR
  162. // devices. This function returns the state of IR communications, FALSE
  163. // is disabled, TRUE is enabled.
  164. //---------------------------------------------------------------------
  165. BOOL ReceivesAllowed()
  166. {
  167. return g_fAllowReceives;
  168. }
  169. //---------------------------------------------------------------------
  170. // SetupListenConnection()
  171. //
  172. //---------------------------------------------------------------------
  173. DWORD SetupListenConnection( IN CHAR *pszService,
  174. IN BOOL fIsIrCOMM,
  175. IN HANDLE hIoCompletionPort )
  176. {
  177. DWORD dwStatus = NO_ERROR;
  178. CIOPACKET *pIoPacket;
  179. CCONNECTION *pConnection;
  180. BOOL fDisabled = FALSE;
  181. if (g_pConnectionMap == NULL) {
  182. return NO_ERROR;
  183. }
  184. // See if the connection already exists:
  185. if (g_pConnectionMap->LookupByServiceName(pszService))
  186. {
  187. return NO_ERROR;
  188. }
  189. #if 0
  190. // Check the registry to see if IrTran-P on this service port is
  191. // enabled. If its disabled, the quit now...
  192. DWORD dwLen = strlen(pszService);
  193. WCHAR wszService[255];
  194. ASSERT(dwLen < 255);
  195. if (0 == MultiByteToWideChar( CP_ACP,
  196. MB_PRECOMPOSED,
  197. pszService,
  198. 1+dwLen,
  199. wszService,
  200. 1+dwLen ))
  201. {
  202. dwStatus = GetLastError();
  203. #ifdef DBG_ERROR
  204. DbgPrint("SetupForListen(): InitializeForListen(%s): MultiByteToWideChar() Failed: %d\n", pszService, dwStatus);
  205. #endif
  206. // Ignore this error and continue on...
  207. }
  208. else
  209. {
  210. IrTranPFlagChanged( wszService, fIsIrCOMM,&fDisabled );
  211. if (fDisabled)
  212. {
  213. return NO_ERROR;
  214. }
  215. }
  216. #endif
  217. // Makeup and initialize a new connection object:
  218. pConnection = new CCONNECTION;
  219. if (!pConnection)
  220. {
  221. return E_OUTOFMEMORY;
  222. }
  223. dwStatus = pConnection->InitializeForListen( pszService,
  224. fIsIrCOMM,
  225. hIoCompletionPort );
  226. if (dwStatus)
  227. {
  228. #ifdef DBG_ERROR
  229. DbgPrint("SetupForListen(): InitializeForListen(%s) failed: %d\n",
  230. pszService, dwStatus );
  231. #endif
  232. return dwStatus;
  233. }
  234. pIoPacket = new CIOPACKET;
  235. if (!pIoPacket)
  236. {
  237. #ifdef DBG_ERROR
  238. DbgPrint("SetupForListen(): new CIOPACKET failed.\n");
  239. #endif
  240. return E_OUTOFMEMORY;
  241. }
  242. // Setup the IO packet:
  243. dwStatus = pIoPacket->Initialize( PACKET_KIND_LISTEN,
  244. pConnection->GetListenSocket(),
  245. INVALID_SOCKET,
  246. hIoCompletionPort );
  247. if (dwStatus != NO_ERROR)
  248. {
  249. return dwStatus;
  250. }
  251. // Post the listen packet on the IO completion port:
  252. dwStatus = pConnection->PostMoreIos(pIoPacket);
  253. if (dwStatus != NO_ERROR)
  254. {
  255. return dwStatus;
  256. }
  257. pConnection->SetSocket(pIoPacket->GetSocket());
  258. if (!g_pConnectionMap->Add(pConnection,pIoPacket->GetListenSocket()))
  259. {
  260. #ifdef DBG_ERROR
  261. DbgPrint("SetupForListen(): Add(pConnection) ConnectionMap Failed.\n");
  262. #endif
  263. return 1;
  264. }
  265. return dwStatus;
  266. }
  267. //---------------------------------------------------------------------
  268. // TeardownListenConnection()
  269. //
  270. //---------------------------------------------------------------------
  271. DWORD TeardownListenConnection( IN char *pszService )
  272. {
  273. DWORD dwStatus = NO_ERROR;
  274. CCONNECTION *pConnection;
  275. // Look for the connection associated with the service name:
  276. if (!g_pConnectionMap)
  277. {
  278. // nothing to tear down...
  279. return dwStatus;
  280. }
  281. pConnection = g_pConnectionMap->LookupByServiceName(pszService);
  282. if (pConnection)
  283. {
  284. g_pConnectionMap->RemoveConnection(pConnection);
  285. pConnection->CloseSocket();
  286. pConnection->CloseListenSocket();
  287. }
  288. return dwStatus;
  289. }
  290. //---------------------------------------------------------------------
  291. // EnableDisableIrCOMM()
  292. //
  293. //---------------------------------------------------------------------
  294. DWORD EnableDisableIrCOMM( IN BOOL fDisable )
  295. {
  296. DWORD dwStatus;
  297. DWORD dwEventStatus = 0;
  298. EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
  299. #ifdef DBG_ERROR
  300. if (dwEventStatus)
  301. {
  302. DbgPrint("IrTranP: Open EventLog failed: %d\n",dwEventStatus);
  303. }
  304. #endif
  305. if (g_pIoStatus == NULL) {
  306. return 0;
  307. }
  308. if (fDisable)
  309. {
  310. dwStatus = TeardownListenConnection(
  311. aListenPorts[INDEX_IRCOMM].pszService);
  312. #ifdef DBG_REGISTRY
  313. DbgPrint("IrTranP: TeardownListenConnection(%s): %d\n",
  314. aListenPorts[INDEX_IRCOMM].pszService,dwStatus);
  315. #endif
  316. if ((dwStatus == 0) && (dwEventStatus == 0))
  317. {
  318. EventLog.ReportInfo(CAT_IRTRANP,
  319. MC_IRTRANP_STOPPED_IRCOMM);
  320. }
  321. }
  322. else
  323. {
  324. dwStatus = SetupListenConnection(
  325. aListenPorts[INDEX_IRCOMM].pszService,
  326. aListenPorts[INDEX_IRCOMM].fIsIrCOMM,
  327. g_pIoStatus->GetIoCompletionPort() );
  328. #ifdef DBG_REGISTRY
  329. DbgPrint("IrTranP: SetupListenConnection(%s): %d\n",
  330. aListenPorts[INDEX_IRCOMM].pszService, dwStatus);
  331. #endif
  332. if (dwEventStatus == 0)
  333. {
  334. if (dwStatus)
  335. {
  336. EventLog.ReportError(CAT_IRTRANP,
  337. MC_IRTRANP_IRCOM_FAILED,
  338. dwStatus);
  339. }
  340. #ifdef DBG
  341. else
  342. {
  343. EventLog.ReportInfo(CAT_IRTRANP,
  344. MC_IRTRANP_STARTED_IRCOMM);
  345. }
  346. #endif
  347. }
  348. }
  349. return dwStatus;
  350. }
  351. //---------------------------------------------------------------------
  352. // EnableDisableIrTranPv1()
  353. //
  354. //---------------------------------------------------------------------
  355. DWORD EnableDisableIrTranPv1( IN BOOL fDisable )
  356. {
  357. DWORD dwStatus;
  358. if (g_pIoStatus == NULL) {
  359. return 0;
  360. }
  361. if (fDisable)
  362. {
  363. dwStatus = TeardownListenConnection(
  364. aListenPorts[INDEX_IRTRANPV1].pszService);
  365. #ifdef DBG_REGISTRY
  366. DbgPrint("IrTranP: TeardownListenConnection(%s): %d\n",
  367. aListenPorts[INDEX_IRCOMM].pszService,dwStatus);
  368. #endif
  369. }
  370. else
  371. {
  372. dwStatus = SetupListenConnection(
  373. aListenPorts[INDEX_IRTRANPV1].pszService,
  374. aListenPorts[INDEX_IRTRANPV1].fIsIrCOMM,
  375. g_pIoStatus->GetIoCompletionPort() );
  376. #ifdef DBG_REGISTRY
  377. DbgPrint("IrTranP: SetupListenConnection(%s): %d\n",
  378. aListenPorts[INDEX_IRCOMM].pszService, dwStatus);
  379. #endif
  380. }
  381. return dwStatus;
  382. }
  383. //---------------------------------------------------------------------
  384. // IrTranp()
  385. //
  386. // Thread function for the IrTran-P service. pvRpcBinding is the RPC
  387. // connection to the IR user interface and is used to display the
  388. // "transmission in progress" dialog when pictures are being received.
  389. //---------------------------------------------------------------------
  390. DWORD WINAPI IrTranP( IN void *pvRpcBinding )
  391. {
  392. int i = 0;
  393. WSADATA wsaData;
  394. WORD wVersion = MAKEWORD(1,1);
  395. DWORD dwStatus;
  396. DWORD dwEventStatus;
  397. CCONNECTION *pConnection;
  398. // Initialize Memory Management:
  399. dwStatus = InitializeMemory();
  400. if (dwStatus)
  401. {
  402. return dwStatus;
  403. }
  404. // Initialize Winsock2:
  405. if (WSAStartup(wVersion,&wsaData) == SOCKET_ERROR)
  406. {
  407. dwStatus = WSAGetLastError();
  408. #ifdef DBG_ERROR
  409. DbgPrint("WSAStartup(0x%x) failed with error %d\n",
  410. wVersion, dwStatus );
  411. #endif
  412. return dwStatus;
  413. }
  414. // Event used to signal back to "main" thread that the
  415. // IrTran-P thread is exiting.
  416. g_hShutdownEvent = CreateEvent( NULL, // No security.
  417. FALSE, // Auto-reset.
  418. FALSE, // Initially not signaled.
  419. NULL ); // No name.
  420. if (!g_hShutdownEvent)
  421. {
  422. dwStatus = GetLastError();
  423. return dwStatus;
  424. }
  425. // Create/initialize a object to keep track of the threading...
  426. g_pIoStatus = new CIOSTATUS;
  427. if (!g_pIoStatus)
  428. {
  429. #ifdef DBG_ERROR
  430. DbgPrint("new CIOSTATUS failed.\n");
  431. #endif
  432. WSACleanup();
  433. return E_OUTOFMEMORY;
  434. }
  435. g_pIoStatus->SaveRpcBinding( (handle_t*)pvRpcBinding );
  436. dwStatus = g_pIoStatus->Initialize();
  437. if (dwStatus != NO_ERROR)
  438. {
  439. #ifdef DBG_ERROR
  440. DbgPrint("g_pIoStatus->Initialize(): Failed: %d\n",dwStatus);
  441. #endif
  442. WSACleanup();
  443. return dwStatus;
  444. }
  445. // Need to keep track of the open sockets and the number of
  446. // pending IOs on each...
  447. g_pConnectionMap = new CCONNECTION_MAP;
  448. if (!g_pConnectionMap)
  449. {
  450. WSACleanup();
  451. return E_OUTOFMEMORY;
  452. }
  453. if (!g_pConnectionMap->Initialize())
  454. {
  455. delete g_pConnectionMap;
  456. g_pConnectionMap = 0;
  457. return 1;
  458. }
  459. #if 0
  460. // Create a CIOPACKET for each defined listen port. These are
  461. // what we will listen on.
  462. while (aListenPorts[i].pszService)
  463. {
  464. dwStatus = SetupListenConnection( aListenPorts[i].pszService,
  465. aListenPorts[i].fIsIrCOMM,
  466. g_pIoStatus->GetIoCompletionPort() );
  467. if (dwStatus)
  468. {
  469. delete g_pConnectionMap;
  470. g_pConnectionMap = 0;
  471. return dwStatus;
  472. }
  473. aListenPorts[i++].dwListenStatus = STATUS_RUNNING;
  474. }
  475. #else
  476. //
  477. // just irtanpv1
  478. //
  479. i=INDEX_IRTRANPV1;
  480. dwStatus = SetupListenConnection( aListenPorts[i].pszService,
  481. aListenPorts[i].fIsIrCOMM,
  482. g_pIoStatus->GetIoCompletionPort() );
  483. if (dwStatus) {
  484. delete g_pConnectionMap;
  485. g_pConnectionMap = 0;
  486. return dwStatus;
  487. }
  488. aListenPorts[i].dwListenStatus = STATUS_RUNNING;
  489. #endif
  490. //
  491. // IrTran-P started, log it to the system log...
  492. //
  493. #ifdef DBG
  494. {
  495. EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
  496. if (dwEventStatus == 0)
  497. {
  498. EventLog.ReportInfo(CAT_IRTRANP,MC_IRTRANP_STARTED);
  499. }
  500. }
  501. #endif
  502. //
  503. // Wait on incomming connections and data, then process it.
  504. //
  505. dwStatus = ProcessIoPackets(g_pIoStatus);
  506. // Cleanup and close any open handles:
  507. while (pConnection=g_pConnectionMap->RemoveNext())
  508. {
  509. delete pConnection;
  510. }
  511. delete g_pConnectionMap;
  512. g_pConnectionMap = 0;
  513. delete g_pIoStatus;
  514. g_pIoStatus = 0;
  515. // Signal the shutdown event that the IrTran-P thread is exiting:
  516. if (g_hShutdownEvent)
  517. {
  518. SetEvent(g_hShutdownEvent);
  519. }
  520. return dwStatus;
  521. }
  522. //---------------------------------------------------------------------
  523. // IrTranPEnableIrCOMMFailed()
  524. //
  525. //---------------------------------------------------------------------
  526. void IrTranPEnableIrCOMMFailed( DWORD dwErrorCode )
  527. {
  528. DWORD dwStatus;
  529. // An error occured on enable, make sure the registry value
  530. // is set to disable (so UI will match the actual state).
  531. HKEY hKey = 0;
  532. HKEY hUserKey = GetUserKey();
  533. HANDLE hUserToken = GetUserToken();
  534. HINSTANCE hInstance = GetModule();
  535. DWORD dwDisposition;
  536. if (RegCreateKeyExW(hUserKey,
  537. WSZ_REG_KEY_IRTRANP,
  538. 0, // reserved MBZ
  539. 0, // class name
  540. REG_OPTION_NON_VOLATILE,
  541. KEY_SET_VALUE,
  542. 0, // security attributes
  543. &hKey,
  544. &dwDisposition))
  545. {
  546. #ifdef DBG_ERROR
  547. DbgPrint("IrTranP: RegCreateKeyEx(): '%S' failed %d",
  548. WSZ_REG_KEY_IRTRANP, GetLastError());
  549. #endif
  550. }
  551. if ( (hKey)
  552. && (hUserToken)
  553. && (::ImpersonateLoggedOnUser(hUserToken)))
  554. {
  555. DWORD dwDisableIrCOMM = TRUE;
  556. dwStatus = RegSetValueExW(hKey,
  557. WSZ_REG_DISABLE_IRCOMM,
  558. 0,
  559. REG_DWORD,
  560. (UCHAR*)&dwDisableIrCOMM,
  561. sizeof(dwDisableIrCOMM) );
  562. #ifdef DBG_ERROR
  563. if (dwStatus != ERROR_SUCCESS)
  564. {
  565. DbgPrint("IrTranP: Can't set DisableIrCOMM to TRUE in registry. Error: %d\n",dwStatus);
  566. }
  567. #endif
  568. ::RevertToSelf();
  569. }
  570. if (hKey)
  571. {
  572. RegCloseKey(hKey);
  573. }
  574. WCHAR *pwszMessage = NULL;
  575. WCHAR *pwszCaption = NULL;
  576. DWORD dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
  577. | FORMAT_MESSAGE_IGNORE_INSERTS
  578. | FORMAT_MESSAGE_FROM_HMODULE);
  579. dwStatus = FormatMessageW(dwFlags,
  580. hInstance,
  581. CAT_IRTRANP,
  582. MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  583. (LPTSTR)(&pwszCaption),
  584. 0, // Minimum size to allocate.
  585. NULL); // va_list args...
  586. if (dwStatus == 0)
  587. {
  588. #ifdef DBG_ERROR
  589. DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
  590. #endif
  591. return;
  592. }
  593. //
  594. // Hack: Make sure the caption doesn't end with newline-formfeed...
  595. //
  596. WCHAR *pwsz = pwszCaption;
  597. while (*pwsz)
  598. {
  599. if (*pwsz < 0x20) // 0x20 is always a space...
  600. {
  601. *pwsz = 0;
  602. break;
  603. }
  604. else
  605. {
  606. pwsz++;
  607. }
  608. }
  609. WCHAR wszErrorCode[20];
  610. WCHAR *pwszErrorCode = (WCHAR*)wszErrorCode;
  611. wsprintfW(wszErrorCode,L"%d",dwErrorCode);
  612. dwFlags = ( FORMAT_MESSAGE_ALLOCATE_BUFFER
  613. | FORMAT_MESSAGE_ARGUMENT_ARRAY
  614. | FORMAT_MESSAGE_FROM_HMODULE);
  615. dwStatus = FormatMessageW(dwFlags,
  616. hInstance,
  617. MC_IRTRANP_IRCOM_FAILED,
  618. MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  619. (LPTSTR)(&pwszMessage),
  620. 0, // Minimum size to allocate.
  621. (va_list*)&pwszErrorCode);
  622. if (dwStatus == 0)
  623. {
  624. #ifdef DBG_ERROR
  625. DbgPrint("IrTranP: FormatMessage() failed: %d\n",GetLastError() );
  626. #endif
  627. if (pwszMessage)
  628. {
  629. LocalFree(pwszMessage);
  630. }
  631. return;
  632. }
  633. dwStatus = MessageBoxW( NULL,
  634. pwszMessage,
  635. pwszCaption,
  636. (MB_OK|MB_ICONERROR|MB_SETFOREGROUND|MB_TOPMOST) );
  637. if (pwszMessage)
  638. {
  639. LocalFree(pwszMessage);
  640. }
  641. if (pwszCaption)
  642. {
  643. LocalFree(pwszCaption);
  644. }
  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. if (hIoCP != INVALID_HANDLE_VALUE)
  656. {
  657. if (!PostQueuedCompletionStatus(hIoCP,0,IOKEY_SHUTDOWN,0))
  658. {
  659. // Unexpected error...
  660. dwStatus = GetLastError();
  661. #ifdef DBG_IO
  662. DbgPrint("UninitializeIrTranP(): PostQueuedCompletionStatus() Failed: %d\n",dwStatus);
  663. #endif
  664. }
  665. while (WAIT_TIMEOUT == WaitForSingleObject(g_hShutdownEvent,0))
  666. {
  667. Sleep(100);
  668. }
  669. CloseHandle(g_hShutdownEvent);
  670. }
  671. // Shutdown memory management:
  672. dwStatus = UninitializeMemory();
  673. return fSuccess;
  674. }
  675. #if FALSE
  676. //---------------------------------------------------------------------
  677. // main()
  678. //
  679. //---------------------------------------------------------------------
  680. int __cdecl main( int argc, char **argv )
  681. {
  682. DWORD dwStatus;
  683. dwStatus = IrTranP( NULL );
  684. return 0;
  685. }
  686. #endif