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.

757 lines
20 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. else
  335. {
  336. g_pFileXferApplet->RegisterWindow(pWindow);
  337. }
  338. }
  339. else
  340. {
  341. ERROR_OUT(("FTBringUIToFrong: cannot allocate CAppletWindow"));
  342. hr = E_OUTOFMEMORY;
  343. }
  344. }
  345. m_WindowList.Reset();
  346. while (NULL != (pWindow = m_WindowList.Iterate()))
  347. {
  348. pWindow->BringToFront();
  349. }
  350. return 0;
  351. }
  352. BOOL CFileTransferApplet::Has2xNodeInConf(void)
  353. {
  354. MBFTEngine *pEngine;
  355. m_EngineList.Reset();
  356. while (NULL != (pEngine = m_EngineList.Iterate()))
  357. {
  358. if (pEngine->Has2xNodeInConf())
  359. {
  360. return TRUE;
  361. }
  362. }
  363. return FALSE;
  364. }
  365. BOOL CFileTransferApplet::InConf(void)
  366. {
  367. MBFTEngine *pEngine;
  368. m_EngineList.Reset();
  369. while (NULL != (pEngine = m_EngineList.Iterate()))
  370. {
  371. if (pEngine->GetPeerCount() > 1)
  372. {
  373. return TRUE;
  374. }
  375. }
  376. return FALSE;
  377. }
  378. BOOL CFileTransferApplet::HasSDK(void)
  379. {
  380. MBFTEngine *pEngine;
  381. m_EngineList.Reset();
  382. while (NULL != (pEngine = m_EngineList.Iterate()))
  383. {
  384. if (pEngine->HasSDK())
  385. {
  386. return TRUE;
  387. }
  388. }
  389. return FALSE;
  390. }
  391. MBFTEngine * CEngineList::FindByConfID(T120ConfID nConfID)
  392. {
  393. MBFTEngine *p;
  394. Reset();
  395. while (NULL != (p = Iterate()))
  396. {
  397. if (nConfID == p->GetConfID())
  398. {
  399. return p;
  400. }
  401. }
  402. return NULL;
  403. }
  404. #ifdef ENABLE_HEARTBEAT_TIMER
  405. MBFTEngine * CEngineList::FindByTimerID(UINT_PTR nTimerID)
  406. {
  407. MBFTEngine *p;
  408. Reset();
  409. while (NULL != (p = Iterate()))
  410. {
  411. if (nTimerID == p->GetTimerID())
  412. {
  413. return p;
  414. }
  415. }
  416. return NULL;
  417. }
  418. #endif
  419. //
  420. // File Transfer Capabilities
  421. //
  422. static GCCAppCap s_CapArray[4];
  423. const GCCAppCap* g_aAppletCaps[4] = { &s_CapArray[0], &s_CapArray[1], &s_CapArray[2], &s_CapArray[3] };
  424. static GCCNonCollCap s_NCCapArray[2];
  425. const GCCNonCollCap* g_aAppletNonCollCaps[2] = { &s_NCCapArray[0], &s_NCCapArray[1] };
  426. static const OSTR s_AppData[2] =
  427. {
  428. {
  429. sizeof(PROSHARE_STRING) + sizeof(MY_APP_STR),
  430. (LPBYTE) PROSHARE_STRING "\0" MY_APP_STR
  431. },
  432. {
  433. sizeof(PROSHARE_FILE_END_STRING),
  434. (LPBYTE) PROSHARE_FILE_END_STRING
  435. },
  436. };
  437. void BuildAppletCapabilities(void)
  438. {
  439. //
  440. // Capabilities
  441. //
  442. //Say that we can handle a max. of 4GBs...
  443. s_CapArray[0].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  444. s_CapArray[0].capability_id.standard_capability = _MBFT_MAX_FILE_SIZE_ID;
  445. s_CapArray[0].capability_class.eType = GCC_UNSIGNED_MAXIMUM_CAPABILITY;
  446. s_CapArray[0].capability_class.nMinOrMax = _iMBFT_MAX_FILE_SIZE;
  447. s_CapArray[0].number_of_entities = 0;
  448. //And that we can handle only about 25K of data per
  449. //FileData PDU
  450. s_CapArray[1].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  451. s_CapArray[1].capability_id.standard_capability = _MBFT_MAX_DATA_PAYLOAD_ID;
  452. s_CapArray[1].capability_class.eType = GCC_UNSIGNED_MAXIMUM_CAPABILITY;
  453. s_CapArray[1].capability_class.nMinOrMax = _iMBFT_MAX_FILEDATA_PDU_LENGTH;
  454. s_CapArray[1].number_of_entities = 0;
  455. //and that we don't support V.42..
  456. s_CapArray[2].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  457. s_CapArray[2].capability_id.standard_capability = _MBFT_V42_COMPRESSION_ID;
  458. s_CapArray[2].capability_class.eType = GCC_LOGICAL_CAPABILITY;
  459. s_CapArray[2].capability_class.nMinOrMax = 0;
  460. s_CapArray[2].number_of_entities = 0;
  461. //Tell other node about this node's version number
  462. s_CapArray[3].capability_id.capability_id_type = GCC_NON_STANDARD_CAPABILITY;
  463. s_CapArray[3].capability_id.non_standard_capability.key_type = GCC_H221_NONSTANDARD_KEY;
  464. s_CapArray[3].capability_id.non_standard_capability.h221_non_standard_id = FT_VERSION_ID;
  465. //s_CapArray[3].capability_id.non_standard_capability.h221_non_standard_id.value = (unsigned char *)FT_VERSION_ID;
  466. s_CapArray[3].capability_class.eType = GCC_UNSIGNED_MINIMUM_CAPABILITY;
  467. s_CapArray[3].capability_class.nMinOrMax = VER_PRODUCTVERSION_DW;
  468. s_CapArray[3].number_of_entities = 0;
  469. //
  470. // Non-Collapsed Capabilities
  471. //
  472. s_NCCapArray[0].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  473. s_NCCapArray[0].capability_id.standard_capability = _iMBFT_FIRST_PROSHARE_CAPABILITY_ID;
  474. s_NCCapArray[0].application_data = (OSTR *) &s_AppData[0];
  475. s_NCCapArray[1].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
  476. s_NCCapArray[1].capability_id.standard_capability = _iMBFT_PROSHARE_FILE_EOF_ACK_ID;
  477. s_NCCapArray[1].application_data = (OSTR *) &s_AppData[1];
  478. }
  479. GCCSessionKey g_AppletSessionKey;
  480. static ULONG s_MBFTKeyNodes[] = {0,0,20,127,0,1};
  481. void BuildDefaultAppletSessionKey(void)
  482. {
  483. ::ZeroMemory(&g_AppletSessionKey, sizeof(g_AppletSessionKey)); // SessionID is zero
  484. g_AppletSessionKey.application_protocol_key.key_type = GCC_OBJECT_KEY;
  485. g_AppletSessionKey.application_protocol_key.object_id.long_string = s_MBFTKeyNodes;
  486. g_AppletSessionKey.application_protocol_key.object_id.long_string_length = sizeof(s_MBFTKeyNodes) / sizeof(s_MBFTKeyNodes[0]);
  487. }
  488. void ReadSettingsFromRegistry(void)
  489. {
  490. static BOOL s_fReadAlready = FALSE;
  491. if (! s_fReadAlready)
  492. {
  493. s_fReadAlready = TRUE;
  494. RegEntry rePolicies(POLICIES_KEY, HKEY_CURRENT_USER);
  495. g_fSendAllowed = (0 == rePolicies.GetNumber(REGVAL_POL_NO_FILETRANSFER_SEND,
  496. DEFAULT_POL_NO_FILETRANSFER_SEND));
  497. g_fRecvAllowed = (0 == rePolicies.GetNumber(REGVAL_POL_NO_FILETRANSFER_RECEIVE,
  498. DEFAULT_POL_NO_FILETRANSFER_RECEIVE));
  499. g_cbMaxSendFileSize = rePolicies.GetNumber(REGVAL_POL_MAX_SENDFILESIZE,
  500. DEFAULT_POL_MAX_FILE_SIZE);
  501. // initialize the delays
  502. RegEntry reFt(FILEXFER_KEY, HKEY_CURRENT_USER);
  503. g_nSendDisbandDelay = reFt.GetNumber(REGVAL_FILEXFER_DISBAND, g_nSendDisbandDelay);
  504. g_nChannelResponseDelay = reFt.GetNumber(REGVAL_FILEXFER_CH_RESPONSE, g_nChannelResponseDelay);
  505. }
  506. }
  507. /////////////////////////////////////////////////////////////////
  508. //
  509. // Hidden windows procedure
  510. //
  511. LRESULT CFtHiddenWindow::ProcessMessage(HWND hwnd, UINT uMsg,
  512. WPARAM wParam, LPARAM lParam)
  513. {
  514. LRESULT rc = T120_NO_ERROR;
  515. MBFTEngine *pEngine = (MBFTEngine *) lParam;
  516. MBFTMsg *pMsg = (MBFTMsg *) wParam;
  517. MBFTInterface *pIntf;
  518. switch(uMsg)
  519. {
  520. case WM_BRING_TO_FRONT:
  521. g_pFileXferApplet->BringUIToFront();
  522. break;
  523. case MBFTMSG_CREATE_ENGINE:
  524. pIntf = (MBFTInterface *) lParam;
  525. pEngine = g_pFileXferApplet->FindEngineWithNoIntf();
  526. if (NULL == pEngine)
  527. {
  528. DBG_SAVE_FILE_LINE
  529. pEngine = new MBFTEngine(NULL, MBFT_STATIC_MODE, _iMBFT_DEFAULT_SESSION);
  530. ASSERT(NULL != pEngine);
  531. }
  532. if (NULL != pEngine)
  533. {
  534. pIntf->SetEngine(pEngine);
  535. pEngine->SetInterfacePointer(pIntf);
  536. }
  537. ::SetEvent((HANDLE) wParam);
  538. break;
  539. case MBFTMSG_DELETE_ENGINE:
  540. ASSERT(NULL != g_pFileXferApplet);
  541. pIntf = pEngine->GetInterfacePointer();
  542. g_pFileXferApplet->UnregisterEngine(pEngine);
  543. break;
  544. case MBFTMSG_HEART_BEAT:
  545. pEngine->DoStateMachine(NULL);
  546. break;
  547. case MBFTMSG_BASIC:
  548. ASSERT(NULL != pMsg);
  549. if (pEngine->DoStateMachine(pMsg))
  550. {
  551. delete pMsg;
  552. pEngine->Release();
  553. }
  554. else
  555. {
  556. // put it back to the queue
  557. ::PostMessage(g_pFileXferApplet->GetHiddenWnd(), uMsg, wParam, lParam);
  558. }
  559. break;
  560. default:
  561. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  562. }
  563. return FALSE;
  564. }
  565. DWORD __stdcall FTWorkThreadProc(LPVOID lpv)
  566. {
  567. HRESULT hr;
  568. CAppletWindow *pAppletWnd;
  569. // allocate the applet object first
  570. DBG_SAVE_FILE_LINE
  571. g_pFileXferApplet = new CFileTransferApplet(&hr);
  572. ::SetEvent((HANDLE) lpv); // signaling that the work hread has been started
  573. if (NULL != g_pFileXferApplet)
  574. {
  575. if (S_OK == hr)
  576. {
  577. // CAppletWindow's constructor will register itself to g_pFileXferApplet
  578. DBG_SAVE_FILE_LINE
  579. CAppletWindow *pWindow = new CAppletWindow(g_fNoUI, &hr);
  580. if (NULL != pWindow)
  581. {
  582. if (S_OK != hr)
  583. {
  584. ERROR_OUT(("FTWorkThreadProc: cannot create CAppletWindow"));
  585. pWindow->Release();
  586. pWindow = NULL;
  587. }
  588. else
  589. {
  590. g_pFileXferApplet->RegisterWindow(pWindow);
  591. }
  592. }
  593. else
  594. {
  595. ERROR_OUT(("FTWorkThreadProc: cannot allocate CAppletWindow"));
  596. hr = E_OUTOFMEMORY;
  597. }
  598. }
  599. else
  600. {
  601. ERROR_OUT(("FTWorkThreadProc: cannot create CFileTransferApplet"));
  602. delete g_pFileXferApplet;
  603. g_pFileXferApplet = NULL;
  604. }
  605. }
  606. else
  607. {
  608. ERROR_OUT(("FTWorkThreadProc: cannot allocate CFileTransferApplet"));
  609. hr = E_OUTOFMEMORY;
  610. }
  611. ::T120_AppletStatus(APPLET_ID_FT, APPLET_WORK_THREAD_STARTED);
  612. // the work thread loop
  613. if (S_OK == hr)
  614. {
  615. ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  616. MSG msg;
  617. while (::GetMessage(&msg, NULL, 0, 0))
  618. {
  619. ::EnterCriticalSection(&g_csWorkThread);
  620. pAppletWnd = g_pFileXferApplet->GetMainUI();
  621. if (!pAppletWnd || !pAppletWnd->FilterMessage(&msg))
  622. {
  623. ::TranslateMessage(&msg);
  624. ::DispatchMessage(&msg);
  625. }
  626. ::LeaveCriticalSection(&g_csWorkThread);
  627. }
  628. CGenWindow::DeleteStandardPalette();
  629. delete g_pFileXferApplet;
  630. g_pFileXferApplet = NULL;
  631. ::CoUninitialize();
  632. }
  633. ::T120_AppletStatus(APPLET_ID_FT, APPLET_WORK_THREAD_EXITED);
  634. g_dwWorkThreadID = 0;
  635. if (! g_fShutdownByT120)
  636. {
  637. // Wait for other dependent threads to finish their work
  638. ::Sleep(100);
  639. ::FreeLibraryAndExitThread(g_hDllInst, 0);
  640. }
  641. return 0;
  642. }