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.

747 lines
19 KiB

  1. #include "mbftpch.h"
  2. #include <it120app.h>
  3. #include <regentry.h>
  4. #include <iappldr.h>
  5. #include <version.h>
  6. HINSTANCE g_hDllInst;
  7. DWORD g_dwWorkThreadID = 0;
  8. HANDLE g_hWorkThread = NULL;
  9. CFileTransferApplet *g_pFileXferApplet = NULL;
  10. CRITICAL_SECTION g_csWorkThread;
  11. TCHAR g_szMBFTWndClassName[32];
  12. const TCHAR g_cszFtHiddenWndClassName[] = _TEXT("FtHiddenWindow");
  13. extern CFtLoader *g_pFtLoader;
  14. extern T120Error CALLBACK CreateAppletLoaderInterface(IAppletLoader**);
  15. BOOL g_fSendAllowed = FALSE;
  16. BOOL g_fRecvAllowed = FALSE;
  17. UINT_PTR g_cbMaxSendFileSize = 0;
  18. BOOL g_fShutdownByT120 = FALSE;
  19. // Local functions
  20. void ReadSettingsFromRegistry(void);
  21. void BuildAppletCapabilities(void);
  22. void BuildDefaultAppletSessionKey(void);
  23. DWORD __stdcall FTWorkThreadProc(LPVOID lpv);
  24. #define FT_VERSION_STR "MS FT Version"
  25. OSTR FT_VERSION_ID = {sizeof(FT_VERSION_STR), (unsigned char*)FT_VERSION_STR};
  26. BOOL WINAPI DllMain(HINSTANCE hDllInst, DWORD fdwReason, LPVOID lpv)
  27. {
  28. switch (fdwReason)
  29. {
  30. case DLL_PROCESS_ATTACH:
  31. g_hDllInst = hDllInst;
  32. ::DisableThreadLibraryCalls(hDllInst);
  33. InitDebug();
  34. DBG_INIT_MEMORY_TRACKING(hDllInst);
  35. ::InitializeCriticalSection(&g_csWorkThread);
  36. ::wsprintf(&g_szMBFTWndClassName[0], TEXT("MBFTWnd%0X_%0X"), ::GetCurrentProcessId(), ::GetTickCount());
  37. ASSERT(::lstrlenA(&g_szMBFTWndClassName[0]) < sizeof(g_szMBFTWndClassName));
  38. ::BuildAppletCapabilities();
  39. ::BuildDefaultAppletSessionKey();
  40. TRACE_OUT(("*** MSCONFFT.DLL: Attached process thread %X", GetCurrentThreadId()));
  41. ::T120_AppletStatus(APPLET_ID_FT, APPLET_LIBRARY_LOADED);
  42. break;
  43. case DLL_PROCESS_DETACH:
  44. TRACE_OUT(("*** NMFT.DLL: Detaching process thread %X", GetCurrentThreadId()));
  45. if (NULL != g_hWorkThread)
  46. {
  47. ::CloseHandle(g_hWorkThread);
  48. }
  49. ::T120_AppletStatus(APPLET_ID_FT, APPLET_LIBRARY_FREED);
  50. ::DeleteCriticalSection(&g_csWorkThread);
  51. DBG_CHECK_MEMORY_TRACKING(hDllInst);
  52. DeInitDebugMbft();
  53. break;
  54. default:
  55. break;
  56. }
  57. return TRUE;
  58. }
  59. HRESULT WINAPI FT_CreateInterface(IMbftControl **ppMbft, IMbftEvents *pEvents)
  60. {
  61. HRESULT hr;
  62. if (NULL != ppMbft && NULL != pEvents)
  63. {
  64. if (NULL != g_pFileXferApplet)
  65. {
  66. ReadSettingsFromRegistry();
  67. DBG_SAVE_FILE_LINE
  68. MBFTInterface *pObject = new MBFTInterface(pEvents, &hr);
  69. if (NULL != pObject)
  70. {
  71. if (S_OK == hr)
  72. {
  73. *ppMbft = (IMbftControl *) pObject;
  74. return S_OK;
  75. }
  76. ERROR_OUT(("CreateMbftObject: cannot create MBFTInterface"));
  77. pObject->Release();
  78. *ppMbft = NULL;
  79. return hr;
  80. }
  81. ERROR_OUT(("CreateMbftObject: cannot allocate MBFTInterface"));
  82. return E_OUTOFMEMORY;
  83. }
  84. WARNING_OUT(("CreateMbftObject: applet object is not created"));
  85. }
  86. else
  87. {
  88. ERROR_OUT(("CreateMbftObject: invalid pointer, ppMbft=0x%x, pEvents=0x%x", ppMbft, pEvents));
  89. }
  90. return E_POINTER;
  91. }
  92. void CALLBACK FileXferAppletCallback
  93. (
  94. T120AppletMsg *pMsg
  95. )
  96. {
  97. CFileTransferApplet *pThisApplet = (CFileTransferApplet *) pMsg->pAppletContext;
  98. if (pThisApplet == g_pFileXferApplet && NULL != g_pFileXferApplet)
  99. {
  100. pThisApplet->T120Callback(pMsg);
  101. }
  102. }
  103. BOOL CFtHiddenWindow::Create(void)
  104. {
  105. return(CGenWindow::Create(NULL, NULL,
  106. WS_POPUP, // not visible!
  107. 0,
  108. 0, 0, 0, 0,
  109. g_hDllInst,
  110. NULL,
  111. g_cszFtHiddenWndClassName
  112. ));
  113. }
  114. CFileTransferApplet::CFileTransferApplet(HRESULT *pHr)
  115. : m_pHwndHidden(NULL)
  116. {
  117. T120Error rc = ::T120_CreateAppletSAP(&m_pAppletSAP);
  118. if (T120_NO_ERROR == rc)
  119. {
  120. m_pAppletSAP->Advise(FileXferAppletCallback, this);
  121. *pHr = S_OK;
  122. }
  123. else
  124. {
  125. ERROR_OUT(("CFileTransferApplet::CFileTransferApplet: cannot create app sap, rc=%u", rc));
  126. *pHr = E_OUTOFMEMORY;
  127. }
  128. // Create Hidden Window for processing MBFTMSG
  129. DBG_SAVE_FILE_LINE
  130. m_pHwndHidden = new CFtHiddenWindow();
  131. if (m_pHwndHidden)
  132. {
  133. *pHr = (m_pHwndHidden->Create())?S_OK:E_FAIL;
  134. }
  135. else
  136. {
  137. *pHr = E_OUTOFMEMORY;
  138. }
  139. }
  140. CFileTransferApplet::~CFileTransferApplet(void)
  141. {
  142. m_EngineList.Clear();
  143. CAppletWindow *pWindow;
  144. while (NULL != (pWindow = m_WindowList.Get()))
  145. {
  146. pWindow->Release(); // add ref while being put to the list
  147. pWindow->OnExit();
  148. }
  149. if (NULL != m_pAppletSAP)
  150. {
  151. m_pAppletSAP->ReleaseInterface();
  152. }
  153. if (NULL != m_pHwndHidden)
  154. {
  155. HWND hwndHidden = m_pHwndHidden->GetWindow();
  156. DestroyWindow(hwndHidden);
  157. m_pHwndHidden->Release();
  158. m_pHwndHidden = NULL;
  159. }
  160. }
  161. BOOL CFileTransferApplet::QueryShutdown(BOOL fGoAheadShutdown)
  162. {
  163. CAppletWindow *pWindow;
  164. m_WindowList.Reset();
  165. while (NULL != (pWindow = m_WindowList.Iterate()))
  166. {
  167. if (! pWindow->QueryShutdown(fGoAheadShutdown))
  168. {
  169. return FALSE; // do not shut down now
  170. }
  171. }
  172. return TRUE;
  173. }
  174. void CFileTransferApplet::T120Callback
  175. (
  176. T120AppletMsg *pMsg
  177. )
  178. {
  179. switch (pMsg->eMsgType)
  180. {
  181. case GCC_PERMIT_TO_ENROLL_INDICATION:
  182. {
  183. MBFTEngine *pEngine = m_EngineList.FindByConfID(pMsg->PermitToEnrollInd.nConfID);
  184. if (NULL == pEngine)
  185. {
  186. pEngine = m_EngineList.FindByConfID(0);
  187. if (NULL == pEngine)
  188. {
  189. if (pMsg->PermitToEnrollInd.fPermissionGranted)
  190. {
  191. DBG_SAVE_FILE_LINE
  192. pEngine = new MBFTEngine(NULL, MBFT_STATIC_MODE, _iMBFT_DEFAULT_SESSION);
  193. ASSERT(NULL != pEngine);
  194. }
  195. }
  196. }
  197. if (NULL != pEngine)
  198. {
  199. pEngine->OnPermitToEnrollIndication(&pMsg->PermitToEnrollInd);
  200. }
  201. // deal with unattended conference
  202. if (pMsg->PermitToEnrollInd.fPermissionGranted)
  203. {
  204. if (NULL == pEngine)
  205. {
  206. m_UnattendedConfList.Append(pMsg->PermitToEnrollInd.nConfID);
  207. }
  208. }
  209. else
  210. {
  211. m_UnattendedConfList.Remove(pMsg->PermitToEnrollInd.nConfID);
  212. }
  213. }
  214. break;
  215. case T120_JOIN_SESSION_CONFIRM:
  216. break;
  217. default:
  218. ERROR_OUT(("CFileTransferApplet::T120Callback: unknown t120 msg type=%u", pMsg->eMsgType));
  219. break;
  220. }
  221. }
  222. void CFileTransferApplet::RegisterEngine(MBFTEngine *p)
  223. {
  224. m_EngineList.Append(p);
  225. // relay any unattended conference
  226. if (! m_UnattendedConfList.IsEmpty())
  227. {
  228. GCCAppPermissionToEnrollInd Ind;
  229. Ind.nConfID = m_UnattendedConfList.Get();
  230. Ind.fPermissionGranted = TRUE;
  231. p->OnPermitToEnrollIndication(&Ind);
  232. }
  233. }
  234. void CFileTransferApplet::UnregisterEngine(MBFTEngine *p)
  235. {
  236. if (m_EngineList.Remove(p))
  237. {
  238. CAppletWindow *pWindow;
  239. m_WindowList.Reset();
  240. while (NULL != (pWindow = m_WindowList.Iterate()))
  241. {
  242. if (pWindow->GetEngine() == p)
  243. {
  244. pWindow->UnregisterEngine();
  245. break;
  246. }
  247. }
  248. p->Release(); // AddRef in MBFTEngine()
  249. }
  250. }
  251. MBFTEngine * CFileTransferApplet::FindEngineWithIntf(void)
  252. {
  253. MBFTEngine *pEngine;
  254. m_EngineList.Reset();
  255. while (NULL != (pEngine = m_EngineList.Iterate()))
  256. {
  257. if (pEngine->GetInterfacePointer())
  258. {
  259. break;
  260. }
  261. }
  262. return pEngine;
  263. }
  264. MBFTEngine * CFileTransferApplet::FindEngineWithNoIntf(void)
  265. {
  266. MBFTEngine *pEngine;
  267. m_EngineList.Reset();
  268. while (NULL != (pEngine = m_EngineList.Iterate()))
  269. {
  270. if (! pEngine->GetInterfacePointer())
  271. {
  272. break;
  273. }
  274. }
  275. return pEngine;
  276. }
  277. void CFileTransferApplet::RegisterWindow(CAppletWindow *pWindow)
  278. {
  279. pWindow->AddRef();
  280. m_WindowList.Append(pWindow);
  281. if (1 == m_WindowList.GetCount() && 1 == m_EngineList.GetCount())
  282. {
  283. MBFTEngine *pEngine = m_EngineList.PeekHead();
  284. pWindow->RegisterEngine(pEngine);
  285. pEngine->SetWindow(pWindow);
  286. pEngine->AddAllPeers();
  287. }
  288. }
  289. void CFileTransferApplet::UnregisterWindow(CAppletWindow *pWindow)
  290. {
  291. if (m_WindowList.Remove(pWindow))
  292. {
  293. pWindow->Release();
  294. }
  295. if (m_WindowList.IsEmpty())
  296. {
  297. g_fNoUI = FALSE;
  298. ::T120_AppletStatus(APPLET_ID_FT, APPLET_CLOSING);
  299. BOOL fRet = ::PostMessage(GetHiddenWnd(), WM_QUIT, 0, 0);
  300. ASSERT(fRet);
  301. }
  302. }
  303. CAppletWindow *CFileTransferApplet::GetUnattendedWindow(void)
  304. {
  305. CAppletWindow *pWindow;
  306. m_WindowList.Reset();
  307. while (NULL != (pWindow = m_WindowList.Iterate()))
  308. {
  309. if (! pWindow->IsInConference())
  310. {
  311. return pWindow;
  312. }
  313. }
  314. return NULL;
  315. }
  316. LRESULT CFileTransferApplet::BringUIToFront(void)
  317. {
  318. CAppletWindow *pWindow;
  319. if (m_WindowList.IsEmpty())
  320. {
  321. // The g_pFileXferApplet was created by fNoUI == TRUE,
  322. // Now we need to create the UI
  323. HRESULT hr;
  324. DBG_SAVE_FILE_LINE
  325. pWindow = new CAppletWindow(g_fNoUI, &hr);
  326. if (NULL != pWindow)
  327. {
  328. if (S_OK != hr)
  329. {
  330. ERROR_OUT(("BringUIToFrong: cannot create CAppletWindow"));
  331. pWindow->Release();
  332. pWindow = NULL;
  333. }
  334. }
  335. else
  336. {
  337. ERROR_OUT(("FTBringUIToFrong: cannot allocate CAppletWindow"));
  338. hr = E_OUTOFMEMORY;
  339. }
  340. }
  341. m_WindowList.Reset();
  342. while (NULL != (pWindow = m_WindowList.Iterate()))
  343. {
  344. pWindow->BringToFront();
  345. }
  346. return 0;
  347. }
  348. BOOL CFileTransferApplet::Has2xNodeInConf(void)
  349. {
  350. MBFTEngine *pEngine;
  351. m_EngineList.Reset();
  352. while (NULL != (pEngine = m_EngineList.Iterate()))
  353. {
  354. if (pEngine->Has2xNodeInConf())
  355. {
  356. return TRUE;
  357. }
  358. }
  359. return FALSE;
  360. }
  361. BOOL CFileTransferApplet::InConf(void)
  362. {
  363. MBFTEngine *pEngine;
  364. m_EngineList.Reset();
  365. while (NULL != (pEngine = m_EngineList.Iterate()))
  366. {
  367. if (pEngine->GetPeerCount() > 1)
  368. {
  369. return TRUE;
  370. }
  371. }
  372. return FALSE;
  373. }
  374. BOOL CFileTransferApplet::HasSDK(void)
  375. {
  376. MBFTEngine *pEngine;
  377. m_EngineList.Reset();
  378. while (NULL != (pEngine = m_EngineList.Iterate()))
  379. {
  380. if (pEngine->HasSDK())
  381. {
  382. return TRUE;
  383. }
  384. }
  385. return FALSE;
  386. }
  387. MBFTEngine * CEngineList::FindByConfID(T120ConfID nConfID)
  388. {
  389. MBFTEngine *p;
  390. Reset();
  391. while (NULL != (p = Iterate()))
  392. {
  393. if (nConfID == p->GetConfID())
  394. {
  395. return p;
  396. }
  397. }
  398. return NULL;
  399. }
  400. #ifdef ENABLE_HEARTBEAT_TIMER
  401. MBFTEngine * CEngineList::FindByTimerID(UINT_PTR nTimerID)
  402. {
  403. MBFTEngine *p;
  404. Reset();
  405. while (NULL != (p = Iterate()))
  406. {
  407. if (nTimerID == p->GetTimerID())
  408. {
  409. return p;
  410. }
  411. }
  412. return NULL;
  413. }
  414. #endif
  415. //
  416. // File Transfer Capabilities
  417. //
  418. static GCCAppCap s_CapArray[4];
  419. const GCCAppCap* g_aAppletCaps[4] = { &s_CapArray[0], &s_CapArray[1], &s_CapArray[2], &s_CapArray[3] };
  420. static GCCNonCollCap s_NCCapArray[2];
  421. const GCCNonCollCap* g_aAppletNonCollCaps[2] = { &s_NCCapArray[0], &s_NCCapArray[1] };
  422. static const OSTR s_AppData[2] =
  423. {
  424. {
  425. sizeof(PROSHARE_STRING) + sizeof(MY_APP_STR),
  426. (LPBYTE) PROSHARE_STRING "\0" MY_APP_STR
  427. },
  428. {
  429. sizeof(PROSHARE_FILE_END_STRING),
  430. (LPBYTE) PROSHARE_FILE_END_STRING
  431. },
  432. };
  433. void BuildAppletCapabilities(void)
  434. {
  435. //
  436. // Capabilities
  437. //
  438. //Say that we can handle a max. of 4GBs...
  439. s_CapArray[0].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  440. s_CapArray[0].capability_id.standard_capability = _MBFT_MAX_FILE_SIZE_ID;
  441. s_CapArray[0].capability_class.eType = GCC_UNSIGNED_MAXIMUM_CAPABILITY;
  442. s_CapArray[0].capability_class.nMinOrMax = _iMBFT_MAX_FILE_SIZE;
  443. s_CapArray[0].number_of_entities = 0;
  444. //And that we can handle only about 25K of data per
  445. //FileData PDU
  446. s_CapArray[1].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  447. s_CapArray[1].capability_id.standard_capability = _MBFT_MAX_DATA_PAYLOAD_ID;
  448. s_CapArray[1].capability_class.eType = GCC_UNSIGNED_MAXIMUM_CAPABILITY;
  449. s_CapArray[1].capability_class.nMinOrMax = _iMBFT_MAX_FILEDATA_PDU_LENGTH;
  450. s_CapArray[1].number_of_entities = 0;
  451. //and that we don't support V.42..
  452. s_CapArray[2].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  453. s_CapArray[2].capability_id.standard_capability = _MBFT_V42_COMPRESSION_ID;
  454. s_CapArray[2].capability_class.eType = GCC_LOGICAL_CAPABILITY;
  455. s_CapArray[2].capability_class.nMinOrMax = 0;
  456. s_CapArray[2].number_of_entities = 0;
  457. //Tell other node about this node's version number
  458. s_CapArray[3].capability_id.capability_id_type = GCC_NON_STANDARD_CAPABILITY;
  459. s_CapArray[3].capability_id.non_standard_capability.key_type = GCC_H221_NONSTANDARD_KEY;
  460. s_CapArray[3].capability_id.non_standard_capability.h221_non_standard_id = FT_VERSION_ID;
  461. //s_CapArray[3].capability_id.non_standard_capability.h221_non_standard_id.value = (unsigned char *)FT_VERSION_ID;
  462. s_CapArray[3].capability_class.eType = GCC_UNSIGNED_MINIMUM_CAPABILITY;
  463. s_CapArray[3].capability_class.nMinOrMax = VER_PRODUCTVERSION_DW;
  464. s_CapArray[3].number_of_entities = 0;
  465. //
  466. // Non-Collapsed Capabilities
  467. //
  468. s_NCCapArray[0].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  469. s_NCCapArray[0].capability_id.standard_capability = _iMBFT_FIRST_PROSHARE_CAPABILITY_ID;
  470. s_NCCapArray[0].application_data = (OSTR *) &s_AppData[0];
  471. s_NCCapArray[1].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  472. s_NCCapArray[1].capability_id.standard_capability = _iMBFT_PROSHARE_FILE_EOF_ACK_ID;
  473. s_NCCapArray[1].application_data = (OSTR *) &s_AppData[1];
  474. }
  475. GCCSessionKey g_AppletSessionKey;
  476. static ULONG s_MBFTKeyNodes[] = {0,0,20,127,0,1};
  477. void BuildDefaultAppletSessionKey(void)
  478. {
  479. ::ZeroMemory(&g_AppletSessionKey, sizeof(g_AppletSessionKey)); // SessionID is zero
  480. g_AppletSessionKey.application_protocol_key.key_type = GCC_OBJECT_KEY;
  481. g_AppletSessionKey.application_protocol_key.object_id.long_string = s_MBFTKeyNodes;
  482. g_AppletSessionKey.application_protocol_key.object_id.long_string_length = sizeof(s_MBFTKeyNodes) / sizeof(s_MBFTKeyNodes[0]);
  483. }
  484. void ReadSettingsFromRegistry(void)
  485. {
  486. static BOOL s_fReadAlready = FALSE;
  487. if (! s_fReadAlready)
  488. {
  489. s_fReadAlready = TRUE;
  490. RegEntry rePolicies(POLICIES_KEY, HKEY_CURRENT_USER);
  491. g_fSendAllowed = (0 == rePolicies.GetNumber(REGVAL_POL_NO_FILETRANSFER_SEND,
  492. DEFAULT_POL_NO_FILETRANSFER_SEND));
  493. g_fRecvAllowed = (0 == rePolicies.GetNumber(REGVAL_POL_NO_FILETRANSFER_RECEIVE,
  494. DEFAULT_POL_NO_FILETRANSFER_RECEIVE));
  495. g_cbMaxSendFileSize = rePolicies.GetNumber(REGVAL_POL_MAX_SENDFILESIZE,
  496. DEFAULT_POL_MAX_FILE_SIZE);
  497. // initialize the delays
  498. RegEntry reFt(FILEXFER_KEY, HKEY_CURRENT_USER);
  499. g_nSendDisbandDelay = reFt.GetNumber(REGVAL_FILEXFER_DISBAND, g_nSendDisbandDelay);
  500. g_nChannelResponseDelay = reFt.GetNumber(REGVAL_FILEXFER_CH_RESPONSE, g_nChannelResponseDelay);
  501. }
  502. }
  503. /////////////////////////////////////////////////////////////////
  504. //
  505. // Hidden windows procedure
  506. //
  507. LRESULT CFtHiddenWindow::ProcessMessage(HWND hwnd, UINT uMsg,
  508. WPARAM wParam, LPARAM lParam)
  509. {
  510. LRESULT rc = T120_NO_ERROR;
  511. MBFTEngine *pEngine = (MBFTEngine *) lParam;
  512. MBFTMsg *pMsg = (MBFTMsg *) wParam;
  513. MBFTInterface *pIntf;
  514. switch(uMsg)
  515. {
  516. case WM_BRING_TO_FRONT:
  517. g_pFileXferApplet->BringUIToFront();
  518. break;
  519. case MBFTMSG_CREATE_ENGINE:
  520. pIntf = (MBFTInterface *) lParam;
  521. pEngine = g_pFileXferApplet->FindEngineWithNoIntf();
  522. if (NULL == pEngine)
  523. {
  524. DBG_SAVE_FILE_LINE
  525. pEngine = new MBFTEngine(NULL, MBFT_STATIC_MODE, _iMBFT_DEFAULT_SESSION);
  526. ASSERT(NULL != pEngine);
  527. }
  528. if (NULL != pEngine)
  529. {
  530. pIntf->SetEngine(pEngine);
  531. pEngine->SetInterfacePointer(pIntf);
  532. }
  533. ::SetEvent((HANDLE) wParam);
  534. break;
  535. case MBFTMSG_DELETE_ENGINE:
  536. ASSERT(NULL != g_pFileXferApplet);
  537. g_pFileXferApplet->UnregisterEngine(pEngine);
  538. break;
  539. case MBFTMSG_HEART_BEAT:
  540. pEngine->DoStateMachine(NULL);
  541. break;
  542. case MBFTMSG_BASIC:
  543. ASSERT(NULL != pMsg);
  544. if (pEngine->DoStateMachine(pMsg))
  545. {
  546. delete pMsg;
  547. pEngine->Release();
  548. }
  549. else
  550. {
  551. // put it back to the queue
  552. ::PostMessage(g_pFileXferApplet->GetHiddenWnd(), uMsg, wParam, lParam);
  553. }
  554. break;
  555. default:
  556. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  557. }
  558. return FALSE;
  559. }
  560. DWORD __stdcall FTWorkThreadProc(LPVOID lpv)
  561. {
  562. HRESULT hr;
  563. CAppletWindow *pAppletWnd;
  564. // allocate the applet object first
  565. DBG_SAVE_FILE_LINE
  566. g_pFileXferApplet = new CFileTransferApplet(&hr);
  567. ::SetEvent((HANDLE) lpv); // signaling that the work hread has been started
  568. if (NULL != g_pFileXferApplet)
  569. {
  570. if (S_OK == hr)
  571. {
  572. // CAppletWindow's constructor will register itself to g_pFileXferApplet
  573. DBG_SAVE_FILE_LINE
  574. CAppletWindow *pWindow = new CAppletWindow(g_fNoUI, &hr);
  575. if (NULL != pWindow)
  576. {
  577. if (S_OK != hr)
  578. {
  579. ERROR_OUT(("FTWorkThreadProc: cannot create CAppletWindow"));
  580. pWindow->Release();
  581. pWindow = NULL;
  582. }
  583. }
  584. else
  585. {
  586. ERROR_OUT(("FTWorkThreadProc: cannot allocate CAppletWindow"));
  587. hr = E_OUTOFMEMORY;
  588. }
  589. }
  590. else
  591. {
  592. ERROR_OUT(("FTWorkThreadProc: cannot create CFileTransferApplet"));
  593. delete g_pFileXferApplet;
  594. g_pFileXferApplet = NULL;
  595. }
  596. }
  597. else
  598. {
  599. ERROR_OUT(("FTWorkThreadProc: cannot allocate CFileTransferApplet"));
  600. hr = E_OUTOFMEMORY;
  601. }
  602. ::T120_AppletStatus(APPLET_ID_FT, APPLET_WORK_THREAD_STARTED);
  603. // the work thread loop
  604. if (S_OK == hr)
  605. {
  606. ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  607. MSG msg;
  608. while (::GetMessage(&msg, NULL, 0, 0))
  609. {
  610. ::EnterCriticalSection(&g_csWorkThread);
  611. pAppletWnd = g_pFileXferApplet->GetMainUI();
  612. if (!pAppletWnd || !pAppletWnd->FilterMessage(&msg))
  613. {
  614. ::TranslateMessage(&msg);
  615. ::DispatchMessage(&msg);
  616. }
  617. ::LeaveCriticalSection(&g_csWorkThread);
  618. }
  619. CGenWindow::DeleteStandardPalette();
  620. delete g_pFileXferApplet;
  621. g_pFileXferApplet = NULL;
  622. ::CoUninitialize();
  623. }
  624. ::T120_AppletStatus(APPLET_ID_FT, APPLET_WORK_THREAD_EXITED);
  625. g_dwWorkThreadID = 0;
  626. if (! g_fShutdownByT120)
  627. {
  628. // Wait for other dependent threads to finish their work
  629. ::Sleep(100);
  630. ::FreeLibraryAndExitThread(g_hDllInst, 0);
  631. }
  632. return 0;
  633. }
  634.