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.

3805 lines
100 KiB

  1. // File: ftui.h
  2. #include "mbftpch.h"
  3. #include <commctrl.h>
  4. #include <regentry.h>
  5. #include "ftui.h"
  6. #include "version.h"
  7. #include <iappldr.h>
  8. #include <nmhelp.h>
  9. static ULONG s_cMsgBox2Dlg = 0; // for alignment
  10. static ULONG s_cRecvDlg = 0; // for alignment
  11. TCHAR s_szMSFT[64];
  12. static TCHAR s_szScratchText[MAX_PATH*2];
  13. static const TCHAR s_cszHtmlHelpFile[] = TEXT("conf.chm");
  14. #define MAX_FILE_NAME_LENGTH 30
  15. LRESULT CALLBACK FtMainWndProc(HWND, UINT, WPARAM, LPARAM);
  16. INT_PTR CALLBACK RecvDlgProc(HWND, UINT, WPARAM, LPARAM);
  17. LPTSTR PathNameToFileName(LPTSTR pszPathName);
  18. HRESULT GetRecvFolder(LPTSTR pszInFldr, LPTSTR pszOutFldr);
  19. BOOL MsgBox2(CAppletWindow *pWindow, LPTSTR pszText);
  20. void EnsureTrailingSlash(LPTSTR);
  21. int MyLoadString(UINT idStr);
  22. int MyLoadString(UINT idStr, LPTSTR pszDstStr);
  23. int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement);
  24. int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, LPTSTR pszElement2);
  25. __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement)
  26. { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement); }
  27. __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement1, UINT_PTR nElement2)
  28. { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement1, (LPTSTR) nElement2); }
  29. int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, UINT_PTR nElement2)
  30. { return MyLoadString(idStr, pszDstStr, pszElement1, (LPTSTR) nElement2); }
  31. __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement1, LPTSTR pszElement2)
  32. { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement1, pszElement2); }
  33. #define count_of(array) (sizeof(array) / sizeof(array[0]))
  34. void OnChangeFolder(void);
  35. BOOL FBrowseForFolder(LPTSTR pszFolder, UINT cchMax, LPCTSTR pszTitle);
  36. extern BOOL g_fShutdownByT120;
  37. void OPT_GetFTWndPosition(RECT *pRect)
  38. {
  39. int iLeft, iTop, iRight, iBottom;
  40. RegEntry reWnd( FILEXFER_KEY, HKEY_CURRENT_USER);
  41. iLeft = reWnd.GetNumber(REGVAL_WINDOW_XPOS, 0);
  42. iTop = reWnd.GetNumber(REGVAL_WINDOW_YPOS, 0);
  43. iRight = reWnd.GetNumber(REGVAL_WINDOW_WIDTH, 0) + iLeft;
  44. iBottom = reWnd.GetNumber(REGVAL_WINDOW_HEIGHT, 0) + iTop;
  45. // If it was empty, use the new rect
  46. if (!(iBottom || iTop || iLeft || iRight))
  47. {
  48. return;
  49. }
  50. // Make sure that the window rectangle is (at least partially) on
  51. // screen, and not too large. First get the screen size
  52. int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
  53. int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
  54. // Check the window size
  55. if ((iRight - iLeft) > screenWidth)
  56. {
  57. iRight = iLeft + screenWidth;
  58. }
  59. if ((iBottom - iTop) > screenHeight)
  60. {
  61. iTop = screenHeight;
  62. }
  63. // Check the window position
  64. if (iLeft >= screenWidth)
  65. {
  66. // Off screen to the right - keep the width the same
  67. iLeft = screenWidth - (iRight - iLeft);
  68. iRight = screenWidth;
  69. }
  70. if (iRight < 0)
  71. {
  72. // Off screen to the left - keep the width the same
  73. iRight = iRight - iLeft;
  74. iLeft = 0;
  75. }
  76. if (iTop >= screenHeight)
  77. {
  78. // Off screen to the bottom - keep the height the same
  79. iTop = screenHeight - (iBottom - iTop);
  80. iBottom = screenHeight;
  81. }
  82. if (iBottom < 0)
  83. {
  84. // Off screen to the top - keep the height the same
  85. iBottom = (iBottom - iTop);
  86. iTop = 0;
  87. }
  88. pRect->left = iLeft;
  89. pRect->top = iTop;
  90. pRect->right = iRight - iLeft;
  91. pRect->bottom = iBottom - iTop;
  92. }
  93. CAppletWindow::CAppletWindow(BOOL fNoUI, HRESULT *pHr)
  94. :
  95. CRefCount(MAKE_STAMP_ID('F','T','U','I')),
  96. m_hwndMainUI(NULL),
  97. m_pToolbar(NULL),
  98. m_hwndListView(NULL),
  99. m_hwndStatusBar(NULL),
  100. m_pEngine(NULL),
  101. m_fInFileOpenDialog(FALSE),
  102. m_pCurrSendFileInfo(NULL),
  103. m_nCurrSendEventHandle(0),
  104. m_hIconInCall(NULL),
  105. m_hIconNotInCall(NULL)
  106. {
  107. m_UIMode = fNoUI ? FTUIMODE_NOUI : FTUIMODE_UIHIDDEN;
  108. ::GetCurrentDirectory(MAX_PATH, m_szDefaultDir);
  109. *pHr = E_FAIL; // failure, at default
  110. // create window class name
  111. ::wsprintf(&m_szFtMainWndClassName[0], TEXT("FTMainWnd%0X_%0X"), ::GetCurrentProcessId(), ::GetTickCount());
  112. ASSERT(::lstrlenA(&m_szFtMainWndClassName[0]) < sizeof(m_szFtMainWndClassName));
  113. // register window class first
  114. WNDCLASS wc;
  115. ::ZeroMemory(&wc, sizeof(wc));
  116. //wc.style = 0;
  117. wc.lpfnWndProc = FtMainWndProc;
  118. // wc.cbClsExtra = 0;
  119. // wc.cbWndExtra = 0;
  120. wc.hInstance = g_hDllInst;
  121. wc.hIcon = ::LoadIcon(g_hDllInst, MAKEINTRESOURCE(IDI_FILE_TRANSFER));
  122. // wc.hbrBackground = NULL;
  123. // wc.hCursor = NULL;
  124. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_FT);
  125. wc.lpszClassName = m_szFtMainWndClassName;
  126. if (::RegisterClass(&wc))
  127. {
  128. ::MyLoadString(IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION);
  129. m_hwndMainUI = ::CreateWindow(
  130. m_szFtMainWndClassName,
  131. s_szScratchText,
  132. WS_OVERLAPPEDWINDOW,
  133. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  134. NULL, // no parent window
  135. NULL, // use class' menu
  136. g_hDllInst,
  137. (LPVOID) this); // this window is for this object
  138. if (NULL != m_hwndMainUI)
  139. {
  140. ASSERT(NULL != g_pFileXferApplet);
  141. g_pFileXferApplet->RegisterWindow(this);
  142. // success
  143. *pHr = S_OK;
  144. }
  145. }
  146. m_hAccel = ::LoadAccelerators(g_hDllInst, MAKEINTRESOURCE(RECVDLGACCELTABLE));
  147. m_hLVAccel = ::LoadAccelerators(g_hDllInst, MAKEINTRESOURCE(LISTVIEWACCELTABLE));
  148. }
  149. CAppletWindow::~CAppletWindow(void)
  150. {
  151. ASSERT(NULL == m_hwndMainUI);
  152. ::UnregisterClass(m_szFtMainWndClassName, g_hDllInst);
  153. ClearSendInfo(FALSE);
  154. ClearRecvInfo();
  155. if (m_hIconInCall)
  156. ::DestroyIcon(m_hIconInCall);
  157. if (m_hIconNotInCall)
  158. ::DestroyIcon(m_hIconNotInCall);
  159. ASSERT(NULL == m_pEngine);
  160. }
  161. BOOL CAppletWindow::FilterMessage(MSG *pMsg)
  162. {
  163. CRecvDlg *pRecvDlg;
  164. HWND hwndError;
  165. HWND hwndForeground = ::GetForegroundWindow();
  166. m_RecvDlgList.Reset();
  167. while (NULL != (pRecvDlg = m_RecvDlgList.Iterate()))
  168. {
  169. if (::IsDialogMessage(pRecvDlg->GetHwnd(), pMsg))
  170. {
  171. return TRUE;
  172. }
  173. }
  174. if (hwndForeground == m_hwndMainUI)
  175. {
  176. BOOL fRet = ::TranslateAccelerator(m_hwndMainUI, m_hLVAccel, pMsg);
  177. return fRet;
  178. }
  179. m_ErrorDlgList.Reset();
  180. while (NULL != (hwndError = m_ErrorDlgList.Iterate()))
  181. {
  182. if (::IsDialogMessage(hwndError, pMsg))
  183. {
  184. return TRUE;
  185. }
  186. }
  187. return FALSE;
  188. }
  189. BOOL CAppletWindow::QueryShutdown(BOOL fShutdown)
  190. {
  191. if (m_UIMode != FTUIMODE_NOUI)
  192. {
  193. int id = 0;
  194. if (m_nCurrSendEventHandle)
  195. {
  196. id = (fShutdown)?IDS_QUERY_SEND_SHUTDOWN:IDS_QUERY_SEND_HANGUP;
  197. }
  198. else if (IsReceiving())
  199. {
  200. id = (fShutdown)?IDS_QUERY_RECVING_SHUTDOWN:IDS_QUERY_RECVING_HANGUP;
  201. }
  202. if (id)
  203. {
  204. // could be in any thread
  205. TCHAR szText[MAX_PATH];
  206. if (::MyLoadString(id, szText))
  207. {
  208. if (IDNO == ::MessageBox(NULL, szText, s_szMSFT, MB_TASKMODAL | MB_YESNO | MB_ICONQUESTION))
  209. {
  210. return FALSE;
  211. }
  212. }
  213. }
  214. }
  215. if (m_nCurrSendEventHandle)
  216. {
  217. OnStopSending();
  218. }
  219. if (IsReceiving())
  220. {
  221. CRecvDlg *pRecvDlg = NULL;
  222. m_RecvDlgList.Reset();
  223. while (NULL != (pRecvDlg = m_RecvDlgList.Iterate()))
  224. {
  225. DBG_SAVE_FILE_LINE
  226. GetEngine()->SafePostMessage(
  227. new FileTransferControlMsg(
  228. pRecvDlg->GetEventHandle(),
  229. pRecvDlg->GetFileHandle(),
  230. NULL,
  231. NULL,
  232. FileTransferControlMsg::EnumAbortFile));
  233. }
  234. }
  235. return TRUE;
  236. }
  237. void CAppletWindow::RegisterEngine(MBFTEngine *pEngine)
  238. {
  239. ASSERT(NULL == m_pEngine);
  240. pEngine->AddRef();
  241. m_pEngine = pEngine;
  242. UpdateUI();
  243. }
  244. void CAppletWindow::UnregisterEngine(void)
  245. {
  246. if (NULL != m_pEngine)
  247. {
  248. m_pEngine->Release();
  249. m_pEngine = NULL;
  250. ClearSendInfo(TRUE);
  251. ClearRecvInfo();
  252. }
  253. if (UIHidden())
  254. { // exit
  255. ::PostMessage(m_hwndMainUI, WM_CLOSE, 0, 0);
  256. }
  257. else
  258. {
  259. UpdateUI(); // don't quit
  260. }
  261. }
  262. void CAppletWindow::RegisterRecvDlg(CRecvDlg *pDlg)
  263. {
  264. m_RecvDlgList.Prepend(pDlg);
  265. }
  266. void CAppletWindow::UnregisterRecvDlg(CRecvDlg *pDlg)
  267. {
  268. m_RecvDlgList.Remove(pDlg);
  269. FocusNextRecvDlg();
  270. }
  271. BOOL CAppletWindow::IsReceiving(void)
  272. {
  273. BOOL fRet = FALSE;
  274. CRecvDlg *pDlg;
  275. CUiRecvFileInfo *pRecvFile;
  276. m_RecvDlgList.Reset();
  277. while (NULL != (pDlg = m_RecvDlgList.Iterate()))
  278. {
  279. pRecvFile = pDlg->GetRecvFileInfo();
  280. if (pRecvFile && (pRecvFile->GetTotalRecvSize() < pRecvFile->GetSize()))
  281. {
  282. fRet = TRUE;
  283. break;
  284. }
  285. }
  286. return fRet;
  287. }
  288. CRecvDlg * CAppletWindow::FindDlgByHandles(MBFTEVENTHANDLE nEventHandle, MBFTFILEHANDLE nFileHandle)
  289. {
  290. CRecvDlg *pDlg;
  291. m_RecvDlgList.Reset();
  292. while (NULL != (pDlg = m_RecvDlgList.Iterate()))
  293. {
  294. if (nEventHandle == pDlg->GetEventHandle() &&
  295. nFileHandle == pDlg->GetFileHandle())
  296. {
  297. break;
  298. }
  299. }
  300. return pDlg;
  301. }
  302. /////////////////////////////////////////////////////////////////
  303. //
  304. // WM_CREATE
  305. //
  306. LRESULT OnCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
  307. {
  308. CREATESTRUCT *p = (CREATESTRUCT *) lParam;
  309. CAppletWindow *pWindow = (CAppletWindow *) p->lpCreateParams;
  310. ASSERT(NULL != pWindow);
  311. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) p->lpCreateParams);
  312. pWindow->SetHwnd(hwnd);
  313. ::InitCommonControls();
  314. pWindow->CreateToolBar();
  315. pWindow->CreateStatusBar();
  316. pWindow->CreateListView();
  317. ::DragAcceptFiles(hwnd, g_fSendAllowed);
  318. // resize the window
  319. MINMAXINFO mmi;
  320. ::ZeroMemory(&mmi, sizeof(mmi));
  321. pWindow->OnGetMinMaxInfo(&mmi);
  322. RECT rcUI;
  323. ::GetWindowRect(pWindow->GetHwnd(), &rcUI);
  324. rcUI.right = mmi.ptMinTrackSize.x;
  325. rcUI.bottom = mmi.ptMinTrackSize.y + 30;
  326. OPT_GetFTWndPosition(&rcUI);
  327. ::MoveWindow(pWindow->GetHwnd(), rcUI.left, rcUI.top,
  328. rcUI.right, rcUI.bottom, TRUE);
  329. pWindow->UpdateUI();
  330. #if defined(TEST_PLUGABLE) && defined(_DEBUG)
  331. ::OnPluggableBegin(hwnd);
  332. #endif
  333. return 0;
  334. }
  335. enum
  336. {
  337. TB_IDX_ADD_FILES = 0,
  338. TB_IDX_REMOVE_FILES,
  339. TB_IDX_BREAK_1,
  340. TB_IDX_IDM_SEND_ALL,
  341. TB_IDX_IDM_SEND_ONE,
  342. TB_IDX_IDM_STOP_SENDING,
  343. TB_IDX_BREAK_2,
  344. TB_IDX_IDM_OPEN_RECV_FOLDER,
  345. TB_IDX_IDM_CHANGE_FOLDER,
  346. TB_IDX_BREAK_3,
  347. TB_IDX_IDM_HELP,
  348. };
  349. static Buttons buttons [] =
  350. {
  351. {IDB_ADDFILES, CBitmapButton::Disabled+1, 1, IDM_ADD_FILES, (LPCSTR)IDS_MENU_ADD_FILES,},
  352. {IDB_REMOVEFILES, CBitmapButton::Disabled+1, 1, IDM_REMOVE_FILES, (LPCSTR)IDS_MENU_REMOVE_FILES,},
  353. {0, 0, 0, 0, 0,},
  354. {IDB_SENDFILE, CBitmapButton::Disabled+1, 1, IDM_SEND_ALL, (LPCSTR)IDS_MENU_SEND_ALL,},
  355. {IDB_STOPSEND, CBitmapButton::Disabled+1, 1, IDM_STOP_SENDING, (LPCSTR)IDS_MENU_STOP_SENDING,},
  356. {0, 0, 0, 0, 0,},
  357. {IDB_FOLDER, CBitmapButton::Disabled+1, 1, IDM_OPEN_RECV_FOLDER, (LPCSTR)IDS_MENU_OPEN_RECV_FOLDER,},
  358. {0, 0, 0, 0, 0},
  359. };
  360. BOOL CAppletWindow::CreateToolBar(void)
  361. {
  362. DBG_SAVE_FILE_LINE
  363. m_pToolbar = new CComboToolbar();
  364. if (m_pToolbar)
  365. {
  366. m_pToolbar->Create(m_hwndMainUI, &buttons[0], count_of(buttons), this);
  367. m_pToolbar->Release();
  368. return TRUE;
  369. }
  370. return FALSE;
  371. }
  372. BOOL CAppletWindow::CreateStatusBar(void)
  373. {
  374. m_hwndStatusBar = ::CreateWindowEx(0,
  375. STATUSCLASSNAME, // status bar class
  376. TEXT(""), // no default text
  377. WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP,
  378. 0, 0, 0, 0,
  379. m_hwndMainUI,
  380. (HMENU) IDC_STATUS_BAR,
  381. g_hDllInst,
  382. NULL);
  383. ASSERT(NULL != m_hwndStatusBar);
  384. if (NULL != m_hwndStatusBar)
  385. {
  386. // Load Call Icons
  387. m_hIconInCall = (HICON) ::LoadImage(g_hDllInst,
  388. MAKEINTRESOURCE(IDI_INCALL),
  389. IMAGE_ICON,
  390. ::GetSystemMetrics(SM_CXSMICON),
  391. ::GetSystemMetrics(SM_CYSMICON),
  392. LR_DEFAULTCOLOR);
  393. m_hIconNotInCall = (HICON) ::LoadImage(g_hDllInst,
  394. MAKEINTRESOURCE(IDI_NOT_INCALL),
  395. IMAGE_ICON,
  396. ::GetSystemMetrics(SM_CXSMICON),
  397. ::GetSystemMetrics(SM_CYSMICON),
  398. LR_DEFAULTCOLOR);
  399. if (CreateProgressBar())
  400. {
  401. return TRUE;
  402. }
  403. }
  404. return FALSE;
  405. }
  406. BOOL CAppletWindow::CreateProgressBar(void)
  407. {
  408. RECT rcl;
  409. GetClientRect(m_hwndStatusBar, &rcl);
  410. m_hwndProgressBar = ::CreateWindowEx(0, PROGRESS_CLASS, TEXT(""),
  411. WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
  412. rcl.right/2 + 2, 2, rcl.right - rcl.right/2 - 40, rcl.bottom - 8,
  413. m_hwndStatusBar, (HMENU)IDC_PROGRESS_BAR,
  414. g_hDllInst, NULL);
  415. if (m_hwndProgressBar)
  416. {
  417. ::SendMessage(m_hwndProgressBar, PBM_SETRANGE, 0L, MAKELONG(0, 100));
  418. return TRUE;
  419. }
  420. return FALSE;
  421. }
  422. BOOL CAppletWindow::CreateListView(void)
  423. {
  424. // get the size and position of the main window
  425. RECT rcWindow, rcToolBar, rcStatusBar;
  426. SIZE szToolBar;
  427. ::GetClientRect(m_hwndMainUI, &rcWindow);
  428. m_pToolbar->GetDesiredSize(&szToolBar);
  429. ::GetWindowRect(m_hwndStatusBar, &rcStatusBar);
  430. ULONG x = 0;
  431. ULONG y = szToolBar.cy - 1;
  432. ULONG cx = rcWindow.right - rcWindow.left;
  433. ULONG cy = rcWindow.bottom - rcWindow.top - y - (rcStatusBar.bottom - rcStatusBar.top) + 1;
  434. // create the list view window
  435. m_hwndListView = ::CreateWindowEx(WS_EX_CLIENTEDGE, // sunken look
  436. WC_LISTVIEW , // list view class
  437. TEXT(""), // no default text
  438. WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT |
  439. LVS_AUTOARRANGE | WS_CLIPCHILDREN | LVS_SHOWSELALWAYS,
  440. x, y, cx, cy,
  441. m_hwndMainUI,
  442. (HMENU) IDC_LIST_VIEW,
  443. g_hDllInst,
  444. NULL);
  445. ASSERT(NULL != m_hwndListView);
  446. if (NULL != m_hwndListView)
  447. {
  448. // set extended list view styles
  449. DWORD dwExtStyle = ListView_GetExtendedListViewStyle(m_hwndListView);
  450. dwExtStyle |= (LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT);
  451. ListView_SetExtendedListViewStyle(m_hwndListView, dwExtStyle);
  452. // enable window only if we can send files
  453. ::EnableWindow(m_hwndListView, g_fSendAllowed);
  454. // set up the columns
  455. ULONG i;
  456. LVCOLUMN lvc;
  457. LVITEM lvi;
  458. TCHAR szText[64];
  459. int iColumnSize[NUM_LIST_VIEW_COLUMNS] = {150, 80, 70, 130}; // listview column size
  460. // initialize the common part of the columns
  461. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  462. lvc.fmt = LVCFMT_LEFT; // left-aligned column
  463. lvc.pszText = szText;
  464. // initialize columns one by one
  465. for (i = 0; i < NUM_LIST_VIEW_COLUMNS; i++)
  466. {
  467. lvc.iSubItem = i;
  468. ::LoadString(g_hDllInst, IDS_LV_FILE_NAME + i, szText, count_of(szText));
  469. lvc.cx = iColumnSize[i];
  470. int iRet = ListView_InsertColumn(m_hwndListView, lvc.iSubItem, &lvc);
  471. ASSERT(-1 != iRet);
  472. }
  473. return TRUE;
  474. }
  475. return FALSE;
  476. }
  477. BOOL CAppletWindow::DrawItem(LPDRAWITEMSTRUCT pdis)
  478. {
  479. ASSERT(pdis);
  480. if (NULL != (pdis->itemData))
  481. {
  482. int nWidth = pdis->rcItem.right - pdis->rcItem.left;
  483. int nHeight = pdis->rcItem.bottom - pdis->rcItem.top;
  484. int nLeft = pdis->rcItem.left;
  485. int nTop = pdis->rcItem.top;
  486. int xSmIcon = ::GetSystemMetrics(SM_CXSMICON);
  487. int ySmIcon = ::GetSystemMetrics(SM_CYSMICON);
  488. if (nWidth > xSmIcon)
  489. {
  490. nLeft += (nWidth - xSmIcon) / 2 - 5;
  491. nWidth = xSmIcon;
  492. }
  493. if (nHeight > ySmIcon)
  494. {
  495. nTop += (nHeight - ySmIcon) / 2;
  496. nHeight = ySmIcon;
  497. }
  498. ::DrawIconEx( pdis->hDC,
  499. nLeft,
  500. nTop,
  501. (HICON) (pdis->itemData),
  502. nWidth,
  503. nHeight,
  504. 0,
  505. NULL,
  506. DI_NORMAL);
  507. }
  508. return TRUE;
  509. }
  510. void CAppletWindow::OnCommand(WORD wId, HWND hwndCtl, WORD codeNotify)
  511. {
  512. switch (wId)
  513. {
  514. case IDM_ADD_FILES:
  515. OnAddFiles();
  516. UpdateUI();
  517. break;
  518. case IDM_REMOVE_FILES:
  519. OnRemoveFiles();
  520. UpdateUI();
  521. break;
  522. case IDM_SEND_ALL:
  523. s_cMsgBox2Dlg = 0;
  524. SetSendMode(TRUE);
  525. OnSendAll();
  526. UpdateUI();
  527. break;
  528. case IDM_SEND_ONE:
  529. s_cMsgBox2Dlg = 0;
  530. SetSendMode(FALSE);
  531. OnSendOne();
  532. UpdateUI();
  533. break;
  534. case IDM_STOP_SENDING:
  535. OnStopSending();
  536. UpdateUI();
  537. break;
  538. case IDM_OPEN_RECV_FOLDER:
  539. OnOpenRecvFolder();
  540. break;
  541. case IDM_CHANGE_FOLDER:
  542. OnChangeFolder();
  543. break;
  544. case IDM_EXIT:
  545. OnExit();
  546. break;
  547. case IDM_HELP:
  548. OnHelp();
  549. break;
  550. case IDM_ABOUT:
  551. OnAbout();
  552. break;
  553. default:
  554. WARNING_OUT(("FT::OnCommand: unknown command ID=%u", (UINT) wId));
  555. break;
  556. }
  557. return;
  558. }
  559. /////////////////////////////////////////////////////////////////
  560. //
  561. // WM_COMMAND
  562. //
  563. LRESULT OnCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
  564. {
  565. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  566. if (NULL != pWindow)
  567. {
  568. WORD wNotifyCode = GET_WM_COMMAND_CMD(wParam, lParam); // notification code
  569. WORD wID = GET_WM_COMMAND_ID(wParam, lParam); // item, control, or accelerator identifier
  570. HWND hwndCtl = (HWND) lParam; // handle of control
  571. pWindow->OnCommand(wID, hwndCtl, wNotifyCode);
  572. return 0;
  573. }
  574. else
  575. {
  576. WARNING_OUT((" CAppletWindow::OnCommand--Received unhandled window message.\n"));
  577. }
  578. return (DefWindowProc(hwnd, WM_COMMAND, wParam, lParam));
  579. }
  580. //
  581. // OnAddFiles
  582. //
  583. UINT_PTR APIENTRY SendFileDlgHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  584. {
  585. if (WM_INITDIALOG == uMsg)
  586. {
  587. hdlg = ::GetParent(hdlg); // Real dialog is this window's parent
  588. if (::MyLoadString(IDS_FILEDLG_SEND))
  589. {
  590. ::SetDlgItemText(hdlg, IDOK, s_szScratchText);
  591. }
  592. }
  593. return 0;
  594. }
  595. void CAppletWindow::OnAddFiles(void)
  596. {
  597. TCHAR szTitle[MAX_PATH];
  598. TCHAR szFilter[MAX_PATH];
  599. TCHAR szDirSav[MAX_PATH];
  600. TCHAR szSendDir[MAX_PATH];
  601. // Load dialog title and filter strings
  602. if (::MyLoadString(IDS_FILEDLG_TITLE, szTitle) &&
  603. ::MyLoadString(IDS_FILEDLG_FILTER, szFilter))
  604. {
  605. // replace '|' to '\0'
  606. LPTSTR pszFltr = szFilter;
  607. while (TEXT('\0') != *pszFltr)
  608. {
  609. if (TEXT('|') == *pszFltr)
  610. {
  611. *pszFltr = TEXT('\0');
  612. pszFltr++; // cannot use CharNext
  613. }
  614. else
  615. {
  616. pszFltr = ::CharNext(pszFltr);
  617. }
  618. }
  619. // only allow one "Select a file to send" dialog
  620. if (! m_fInFileOpenDialog)
  621. {
  622. m_fInFileOpenDialog = TRUE;
  623. // Allocate a really large buffer to hold the file list
  624. ULONG cbBufSize = 8192;
  625. DBG_SAVE_FILE_LINE
  626. LPTSTR pszBuffer = new TCHAR[cbBufSize];
  627. if (NULL != pszBuffer)
  628. {
  629. *pszBuffer = TEXT('\0'); // start with null string
  630. OPENFILENAME ofn;
  631. ::ZeroMemory(&ofn, sizeof(ofn));
  632. ofn.lStructSize = sizeof(ofn);
  633. ofn.hwndOwner = m_hwndMainUI;
  634. ofn.hInstance = g_hDllInst;
  635. ofn.lpstrFilter = &szFilter[0];
  636. ofn.nFilterIndex = 1L; // FUTURE: remember filter preference
  637. ofn.lpstrFile = pszBuffer;
  638. ofn.nMaxFile = cbBufSize - 1; // Number of TCHAR in pszFiles (not including NULL)
  639. ofn.lpstrTitle = &szTitle[0];
  640. ofn.lpstrInitialDir = m_szDefaultDir;
  641. ofn.lpfnHook = SendFileDlgHookProc;
  642. ofn.Flags = OFN_ALLOWMULTISELECT | OFN_ENABLEHOOK | // OFN_HIDEREADONLY |
  643. OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
  644. // remember current directory
  645. ::ZeroMemory(szSendDir, sizeof(szSendDir));
  646. ::GetCurrentDirectory(count_of(szDirSav), szDirSav);
  647. ::lstrcpyn(szSendDir, szDirSav, count_of(szSendDir));
  648. if (::GetOpenFileName(&ofn))
  649. {
  650. // if there is only a single file, the first string is the full path.
  651. // if there are more than one file, the first string is the directory path
  652. // and followed by a list of file names. terminated by double null
  653. // remember the working directory for next time
  654. ULONG cchDirPath;
  655. LPTSTR pszFileName;
  656. ULONG cchFile = ::lstrlen(ofn.lpstrFile);
  657. if (TEXT('\0') == ofn.lpstrFile[cchFile] && TEXT('\0') == ofn.lpstrFile[cchFile+1])
  658. {
  659. //
  660. // only a single file
  661. //
  662. pszFileName = ::PathNameToFileName(ofn.lpstrFile);
  663. cchDirPath = (ULONG)(pszFileName - ofn.lpstrFile);
  664. if (cchDirPath)
  665. {
  666. cchDirPath--; // back to '\\'
  667. }
  668. ASSERT(TEXT('\\') == ofn.lpstrFile[cchDirPath]);
  669. ofn.lpstrFile[cchDirPath] = TEXT('\0');
  670. }
  671. else
  672. {
  673. //
  674. // multiple files
  675. //
  676. cchDirPath = ::lstrlen(ofn.lpstrFile);
  677. pszFileName = ofn.lpstrFile + cchDirPath + 1;
  678. }
  679. ::lstrcpy(m_szDefaultDir, ofn.lpstrFile);
  680. EnsureTrailingSlash(m_szDefaultDir);
  681. ::ZeroMemory(szSendDir, sizeof(szSendDir));
  682. ::CopyMemory(szSendDir, ofn.lpstrFile, cchDirPath * sizeof(TCHAR));
  683. EnsureTrailingSlash(szSendDir);
  684. // set up the common portion of list view item
  685. LVITEM lvi;
  686. ::ZeroMemory(&lvi, sizeof(lvi));
  687. // lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  688. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  689. // iterate the file name
  690. while ('\0' != *pszFileName)
  691. {
  692. BOOL fRet;
  693. DBG_SAVE_FILE_LINE
  694. CUiSendFileInfo *pFileInfo = new CUiSendFileInfo(this, szSendDir, pszFileName, &fRet);
  695. if (NULL != pFileInfo && fRet)
  696. {
  697. // put it to the list view
  698. lvi.iItem = ListView_GetItemCount(m_hwndListView);
  699. lvi.iSubItem = 0;
  700. // we are responsible for storing the text to display
  701. lvi.pszText = LPSTR_TEXTCALLBACK;
  702. lvi.cchTextMax = MAX_PATH;
  703. lvi.lParam = (LPARAM) pFileInfo;
  704. int iRet = ListView_InsertItem(m_hwndListView, &lvi);
  705. ASSERT(-1 != iRet);
  706. // UpdateListView(pFileInfo);
  707. }
  708. else
  709. {
  710. delete pFileInfo;
  711. }
  712. // get to the next file name
  713. pszFileName += ::lstrlen(pszFileName) + 1;
  714. } // while
  715. }
  716. else
  717. {
  718. // err code for cancel is zero, which is ok.
  719. ASSERT(! ::CommDlgExtendedError());
  720. }
  721. // restore old working directory
  722. ::SetCurrentDirectory(szDirSav);
  723. }
  724. delete pszBuffer;
  725. m_fInFileOpenDialog = FALSE;
  726. }
  727. else
  728. {
  729. // bring the active dialog to the front
  730. BringToFront();
  731. }
  732. } // if LoadString
  733. }
  734. //
  735. // OnRemoveFiles
  736. //
  737. void CAppletWindow::OnRemoveFiles(void)
  738. {
  739. UINT nState;
  740. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  741. LVITEM lvi;
  742. ::ZeroMemory(&lvi, sizeof(lvi));
  743. lvi.mask = LVIF_PARAM | LVIF_STATE;
  744. lvi.stateMask = LVIS_SELECTED;
  745. ULONG i = 0;
  746. while (i < cItems)
  747. {
  748. lvi.iItem = i;
  749. BOOL fRet = ListView_GetItem(m_hwndListView, &lvi);
  750. if (fRet && lvi.state & LVIS_SELECTED)
  751. {
  752. CUiSendFileInfo *pFileInfo = (CUiSendFileInfo *) lvi.lParam;
  753. if (pFileInfo == m_pCurrSendFileInfo)
  754. {
  755. OnStopSending();
  756. ClearSendInfo(FALSE);
  757. }
  758. delete pFileInfo;
  759. fRet = ListView_DeleteItem(m_hwndListView, i);
  760. ASSERT(fRet);
  761. cItems--;
  762. ASSERT((ULONG) ListView_GetItemCount(m_hwndListView) == cItems);
  763. }
  764. else
  765. {
  766. i++;
  767. }
  768. }
  769. if (cItems > 0) // set focus to first remaining item
  770. {
  771. ListView_SetItemState(m_hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED,
  772. LVIS_SELECTED | LVIS_FOCUSED);
  773. }
  774. }
  775. void CAppletWindow::OnRemoveAllFiles(void)
  776. {
  777. BOOL fRet;
  778. CUiSendFileInfo *pFileInfo;
  779. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  780. LVITEM lvi;
  781. ::ZeroMemory(&lvi, sizeof(lvi));
  782. lvi.mask = LVIF_PARAM;
  783. for (ULONG i = 0; i < cItems; i++)
  784. {
  785. lvi.iItem = i;
  786. fRet = ListView_GetItem(m_hwndListView, &lvi);
  787. ASSERT(fRet);
  788. pFileInfo = (CUiSendFileInfo *) lvi.lParam;
  789. if (pFileInfo == m_pCurrSendFileInfo)
  790. {
  791. ClearSendInfo(FALSE);
  792. }
  793. delete pFileInfo;
  794. }
  795. fRet = ListView_DeleteAllItems(m_hwndListView);
  796. ASSERT(fRet);
  797. }
  798. void CAppletWindow::OnSendAll(void)
  799. {
  800. if ((NULL == m_pCurrSendFileInfo)&&(NULL != m_pEngine))
  801. {
  802. CUiSendFileInfo *pFileInfo = ChooseFirstUnSentFile();
  803. SendNow(pFileInfo);
  804. }
  805. }
  806. void CAppletWindow::OnSendOne(void)
  807. {
  808. if ((NULL == m_pCurrSendFileInfo)&&(NULL != m_pEngine))
  809. {
  810. CUiSendFileInfo *pFileInfo = ChooseSelectedFile();
  811. if (!pFileInfo)
  812. {
  813. pFileInfo = ChooseFirstUnSentFile();
  814. }
  815. SendNow(pFileInfo);
  816. }
  817. }
  818. //
  819. // SendNow
  820. //
  821. BOOL CAppletWindow::SendNow(CUiSendFileInfo *pFileInfo)
  822. {
  823. BOOL fRet;
  824. if (NULL != pFileInfo)
  825. {
  826. // send this file now...
  827. m_pCurrSendFileInfo = pFileInfo;
  828. m_nCurrSendEventHandle = ::GetNewEventHandle();
  829. pFileInfo->SetFileHandle(::GetNewFileHandle());
  830. // duplicate full file name
  831. ULONG cbSize = ::lstrlen(pFileInfo->GetFullName()) + 1;
  832. DBG_SAVE_FILE_LINE
  833. LPTSTR pszFullName = new TCHAR[cbSize];
  834. if (NULL != pszFullName)
  835. {
  836. ::CopyMemory(pszFullName, pFileInfo->GetFullName(), cbSize);
  837. DBG_SAVE_FILE_LINE
  838. if (S_OK == m_pEngine->SafePostMessage(
  839. new CreateSessionMsg(MBFT_PRIVATE_SEND_TYPE,
  840. m_nCurrSendEventHandle)))
  841. {
  842. int iSelect;
  843. MEMBER_ID nMemberID;
  844. iSelect = m_pToolbar->GetSelectedItem((LPARAM*)&nMemberID);
  845. if (0 == iSelect)
  846. { // Send to All
  847. DBG_SAVE_FILE_LINE
  848. if (S_OK == m_pEngine->SafePostMessage(
  849. new SubmitFileSendMsg(0, 0, pszFullName,
  850. pFileInfo->GetFileHandle(),
  851. m_nCurrSendEventHandle,
  852. FALSE)))
  853. {
  854. return TRUE;
  855. }
  856. else
  857. {
  858. ERROR_OUT(("CAppletWindow::SendNow: cannot create SubmitFileSendMsg"));
  859. }
  860. }
  861. else
  862. { // Send to one
  863. T120UserID uidRecv = GET_PEER_ID_FROM_MEMBER_ID(nMemberID);
  864. DBG_SAVE_FILE_LINE
  865. if (S_OK == m_pEngine->SafePostMessage(
  866. new SubmitFileSendMsg(uidRecv, 0, pszFullName,
  867. pFileInfo->GetFileHandle(),
  868. m_nCurrSendEventHandle,
  869. FALSE)))
  870. {
  871. return TRUE;
  872. }
  873. else
  874. {
  875. ERROR_OUT(("CAppletWindow::SendNow: cannot create SubmitFileSendMsg to 1"));
  876. }
  877. }
  878. }
  879. else
  880. {
  881. ERROR_OUT(("CAppletWindow::SendNow: cannot create CreateSessionMsg"));
  882. }
  883. delete [] pszFullName;
  884. }
  885. ClearSendInfo(TRUE);
  886. }
  887. return FALSE;
  888. }
  889. CUiSendFileInfo *CAppletWindow::ChooseFirstUnSentFile(void)
  890. {
  891. CUiSendFileInfo *pFileInfo = NULL;
  892. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  893. if (cItems > 0)
  894. {
  895. // examine each item one by one
  896. LVITEM lvi;
  897. ::ZeroMemory(&lvi, sizeof(lvi));
  898. lvi.mask = LVIF_PARAM;
  899. for (ULONG i = 0; i < cItems; i++, pFileInfo = NULL)
  900. {
  901. lvi.iItem = i;
  902. BOOL fRet = ListView_GetItem(m_hwndListView, &lvi);
  903. ASSERT(fRet);
  904. pFileInfo = (CUiSendFileInfo *) lvi.lParam;
  905. // if file handle is not zero, then it has been sent
  906. if (! pFileInfo->GetFileHandle())
  907. {
  908. break;
  909. }
  910. }
  911. }
  912. return pFileInfo;
  913. }
  914. CUiSendFileInfo *CAppletWindow::ChooseSelectedFile(void)
  915. {
  916. CUiSendFileInfo *pFileInfo = NULL;
  917. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  918. LVITEM lvi;
  919. ::ZeroMemory(&lvi, sizeof(lvi));
  920. lvi.mask = LVIF_PARAM | LVIF_STATE;
  921. lvi.stateMask = LVIS_SELECTED;
  922. ULONG i = 0;
  923. while (i < cItems)
  924. {
  925. lvi.iItem = i;
  926. BOOL fRet = ListView_GetItem(m_hwndListView, &lvi);
  927. if (fRet && lvi.state & LVIS_SELECTED)
  928. {
  929. pFileInfo = (CUiSendFileInfo *) lvi.lParam;
  930. pFileInfo->SetErrorCode(iMBFT_OK);
  931. break;
  932. }
  933. else
  934. {
  935. i++;
  936. pFileInfo = NULL;
  937. }
  938. }
  939. return pFileInfo;
  940. }
  941. //
  942. // OnMenuSelect
  943. //
  944. void CAppletWindow::OnMenuSelect(UINT uiItemID, UINT uiFlags, HMENU hSysMenu)
  945. {
  946. UINT firstMenuId;
  947. UINT statusId;
  948. //
  949. // Work out the help ID for the menu item. We have to store this now
  950. // because when the user presses F1 from a menu item, we can't tell
  951. // which item it was.
  952. //
  953. if ((uiFlags & MF_POPUP) && (uiFlags & MF_SYSMENU))
  954. {
  955. // System menu selected
  956. statusId = (m_pCurrSendFileInfo)?IDS_STBAR_SENDING_XYZ:IDS_STBAR_NOT_TRANSFERING;
  957. }
  958. else if (uiFlags & MF_POPUP)
  959. {
  960. // get popup menu handle and first item
  961. HMENU hPopup = ::GetSubMenu( hSysMenu, uiItemID );
  962. firstMenuId = ::GetMenuItemID( hPopup, 0 );
  963. switch(firstMenuId)
  964. {
  965. case IDM_ADD_FILES:
  966. statusId = IDS_MENU_FILE;
  967. break;
  968. case IDM_HELP:
  969. statusId = IDS_MENU_HELP;
  970. break;
  971. default:
  972. statusId = (m_pCurrSendFileInfo)?IDS_STBAR_SENDING_XYZ:IDS_STBAR_NOT_TRANSFERING;
  973. }
  974. }
  975. else
  976. {
  977. // A normal menu item has been selected
  978. statusId = uiItemID;
  979. }
  980. // Set the new help text
  981. TCHAR szStatus[256];
  982. if (::LoadString(g_hDllInst, statusId, szStatus, 256))
  983. {
  984. ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_TRANSFER_FILE, (LPARAM)szStatus);
  985. }
  986. }
  987. //
  988. // OnStopSending
  989. //
  990. void CAppletWindow::OnStopSending(void)
  991. {
  992. m_fSendALL = FALSE;
  993. if (m_nCurrSendEventHandle)
  994. {
  995. DBG_SAVE_FILE_LINE
  996. HRESULT hr = m_pEngine->SafePostMessage(
  997. new FileTransferControlMsg(
  998. m_nCurrSendEventHandle,
  999. m_pCurrSendFileInfo->GetFileHandle(),
  1000. NULL,
  1001. NULL,
  1002. FileTransferControlMsg::EnumAbortFile));
  1003. ASSERT(hr == S_OK);
  1004. }
  1005. }
  1006. //
  1007. // OnOpenRecvFolder
  1008. //
  1009. void CAppletWindow::OnOpenRecvFolder(void)
  1010. {
  1011. TCHAR szRecvFolder[MAX_PATH];
  1012. while (1)
  1013. {
  1014. if (S_OK == ::GetRecvFolder(NULL, szRecvFolder))
  1015. {
  1016. ::ShellExecute(NULL, NULL, szRecvFolder, NULL, NULL, SW_SHOWNORMAL);
  1017. break;
  1018. }
  1019. else if (m_UIMode != FTUIMODE_NOUI)
  1020. {
  1021. ::MyLoadString(IDS_RECVDLG_DIRNOEXIST, s_szScratchText, szRecvFolder);
  1022. if (IDYES == ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_YESNO))
  1023. {
  1024. OnChangeFolder();
  1025. }
  1026. else
  1027. {
  1028. break;
  1029. }
  1030. }
  1031. }
  1032. }
  1033. //
  1034. // OnChageFolder
  1035. //
  1036. void OnChangeFolder(void)
  1037. {
  1038. BOOL rc;
  1039. TCHAR szPath[MAX_PATH];
  1040. ::GetRecvFolder(NULL, szPath);
  1041. if (::lstrlen(szPath) > MAX_FILE_NAME_LENGTH)
  1042. {
  1043. LPTSTR psz = szPath;
  1044. int i = MAX_FILE_NAME_LENGTH - 1;
  1045. while (i)
  1046. {
  1047. psz = CharNext(psz);
  1048. i--;
  1049. }
  1050. ::lstrcpy(psz, TEXT("..."));
  1051. }
  1052. ::MyLoadString(IDS_BROWSETITLE, s_szScratchText, szPath);
  1053. if (FBrowseForFolder(szPath, CCHMAX(szPath), s_szScratchText))
  1054. {
  1055. ::GetRecvFolder(szPath, szPath);
  1056. }
  1057. }
  1058. //
  1059. // OnExit
  1060. //
  1061. void CAppletWindow::OnExit(BOOL fNoQuery)
  1062. {
  1063. if ((g_pFileXferApplet->InConf() || g_pFileXferApplet->HasSDK())
  1064. && ! g_fShutdownByT120)
  1065. {
  1066. // There 2.x node inside the conference
  1067. // hide the window
  1068. ::ShowWindow(m_hwndMainUI, SW_HIDE);
  1069. m_UIMode = g_fNoUI ? FTUIMODE_NOUI : FTUIMODE_UIHIDDEN;
  1070. }
  1071. else
  1072. if (fNoQuery || QueryShutdown())
  1073. {
  1074. #if defined(TEST_PLUGABLE) && defined(_DEBUG)
  1075. ::OnPluggableEnd();
  1076. #endif
  1077. MBFTEngine *pEngine = m_pEngine;
  1078. ::T120_AppletStatus(APPLET_ID_FT, APPLET_CLOSING);
  1079. if (NULL != m_pEngine)
  1080. {
  1081. GCCAppPermissionToEnrollInd Ind;
  1082. ::ZeroMemory(&Ind, sizeof(Ind));
  1083. Ind.nConfID = m_pEngine->GetConfID();
  1084. Ind.fPermissionGranted = FALSE;
  1085. m_pEngine->OnPermitToEnrollIndication(&Ind);
  1086. UnregisterEngine();
  1087. }
  1088. OnRemoveAllFiles();
  1089. ::SetWindowLongPtr(m_hwndMainUI, GWLP_USERDATA, 0);
  1090. SaveWindowPosition();
  1091. HWND hwnd = m_hwndMainUI;
  1092. m_hwndMainUI = NULL;
  1093. ::DestroyWindow(hwnd);
  1094. if (NULL != g_pFileXferApplet)
  1095. {
  1096. g_pFileXferApplet->UnregisterWindow(this);
  1097. g_pFileXferApplet->UnregisterEngine(pEngine);
  1098. }
  1099. Release();
  1100. }
  1101. }
  1102. //
  1103. // OnHelp
  1104. //
  1105. void CAppletWindow::OnHelp(void)
  1106. {
  1107. DebugEntry(CAppletWindow::OnHelp);
  1108. ShowNmHelp(s_cszHtmlHelpFile);
  1109. DebugExitVOID(CAppletWindow::OnHelp);
  1110. }
  1111. //
  1112. // OnAbout
  1113. //
  1114. INT_PTR AboutDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1115. {
  1116. BOOL fHandled = FALSE;
  1117. switch (uMsg)
  1118. {
  1119. case WM_INITDIALOG:
  1120. {
  1121. TCHAR szFormat[256];
  1122. TCHAR szVersion[512];
  1123. ::GetDlgItemText(hdlg, IDC_ABOUT_VERSION, szFormat, count_of(szFormat));
  1124. ::wsprintf(szVersion, szFormat, VER_PRODUCTRELEASE_STR,
  1125. VER_PRODUCTVERSION_STR);
  1126. ::SetDlgItemText(hdlg, IDC_ABOUT_VERSION, szVersion);
  1127. fHandled = TRUE;
  1128. }
  1129. break;
  1130. case WM_COMMAND:
  1131. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1132. {
  1133. case IDOK:
  1134. case IDCANCEL:
  1135. case IDCLOSE:
  1136. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1137. {
  1138. case BN_CLICKED:
  1139. ::EndDialog(hdlg, IDCANCEL);
  1140. break;
  1141. }
  1142. break;
  1143. }
  1144. fHandled = TRUE;
  1145. break;
  1146. }
  1147. return(fHandled);
  1148. }
  1149. void CAppletWindow::OnAbout(void)
  1150. {
  1151. ::DialogBoxParam(g_hDllInst, MAKEINTRESOURCE(IDD_ABOUTBOX), m_hwndMainUI,
  1152. AboutDlgProc, 0);
  1153. }
  1154. BOOL FBrowseForFolder(LPTSTR pszFolder, UINT cchMax, LPCTSTR pszTitle)
  1155. {
  1156. LPITEMIDLIST pidlRoot;
  1157. SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DRIVES, &pidlRoot);
  1158. BROWSEINFO bi;
  1159. ClearStruct(&bi);
  1160. bi.hwndOwner = NULL;
  1161. bi.lpszTitle = pszTitle;
  1162. bi.ulFlags = BIF_RETURNONLYFSDIRS;
  1163. bi.pidlRoot = pidlRoot;
  1164. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  1165. BOOL fRet = (pidl != NULL);
  1166. if (fRet)
  1167. {
  1168. ASSERT(cchMax >= MAX_PATH);
  1169. SHGetPathFromIDList(pidl, pszFolder);
  1170. ASSERT(lstrlen(pszFolder) < (int) cchMax);
  1171. }
  1172. // Get the shell's allocator to free PIDLs
  1173. LPMALLOC lpMalloc;
  1174. if (!SHGetMalloc(&lpMalloc) && (NULL != lpMalloc))
  1175. {
  1176. if (NULL != pidlRoot)
  1177. {
  1178. lpMalloc->Free(pidlRoot);
  1179. }
  1180. if (pidl)
  1181. {
  1182. lpMalloc->Free(pidl);
  1183. }
  1184. lpMalloc->Release();
  1185. }
  1186. return fRet;
  1187. }
  1188. /////////////////////////////////////////////////////////////////
  1189. //
  1190. // WM_NOTIFY
  1191. //
  1192. LRESULT OnNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1193. {
  1194. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1195. if (NULL != pWindow)
  1196. {
  1197. switch (wParam)
  1198. {
  1199. case IDC_LIST_VIEW:
  1200. pWindow->OnNotifyListView(lParam);
  1201. break;
  1202. default:
  1203. if (TTN_NEEDTEXT == ((NMHDR *) lParam)->code)
  1204. {
  1205. // display the tool tip text
  1206. TOOLTIPTEXT *pToolTipText = (TOOLTIPTEXT *) lParam;
  1207. ULONG_PTR nID;
  1208. // get id and hwnd
  1209. if (pToolTipText->uFlags & TTF_IDISHWND)
  1210. {
  1211. // idFrom is actually the HWND of the tool
  1212. nID = ::GetDlgCtrlID((HWND) pToolTipText->hdr.idFrom);
  1213. }
  1214. else
  1215. {
  1216. nID = pToolTipText->hdr.idFrom;
  1217. }
  1218. // give it to em
  1219. pToolTipText->lpszText = MAKEINTRESOURCE(nID);
  1220. pToolTipText->hinst = g_hDllInst;
  1221. }
  1222. break;
  1223. }
  1224. }
  1225. return 0;
  1226. }
  1227. int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  1228. {
  1229. CUiSendFileInfo *pFileInfo1 = (CUiSendFileInfo *) lParam1;
  1230. CUiSendFileInfo *pFileInfo2 = (CUiSendFileInfo *) lParam2;
  1231. int iResult;
  1232. iResult = 0; // equal, at default
  1233. switch (lParamSort)
  1234. {
  1235. case (IDS_LV_FILE_NAME - IDS_LV_FILE_NAME):
  1236. iResult = ::lstrcmpi(pFileInfo1->GetName(), pFileInfo2->GetName());
  1237. break;
  1238. case (IDS_LV_FILE_SIZE - IDS_LV_FILE_NAME):
  1239. if (pFileInfo1->GetSize() > pFileInfo2->GetSize())
  1240. {
  1241. iResult = 1;
  1242. }
  1243. else
  1244. if (pFileInfo1->GetSize() < pFileInfo2->GetSize())
  1245. {
  1246. iResult = -1;
  1247. }
  1248. break;
  1249. case (IDS_LV_FILE_STATUS - IDS_LV_FILE_NAME):
  1250. case (IDS_LV_FILE_MODIFIED - IDS_LV_FILE_NAME):
  1251. // do nothing at all, for now...
  1252. break;
  1253. }
  1254. return iResult;
  1255. }
  1256. void CAppletWindow::OnNotifyListView(LPARAM lParam)
  1257. {
  1258. LV_DISPINFO *pDispInfo = (LV_DISPINFO *) lParam;
  1259. NM_LISTVIEW *pLVN = (NM_LISTVIEW *) lParam;
  1260. FILETIME ftFileTime;
  1261. SYSTEMTIME stSystemTime;
  1262. CUiSendFileInfo *pFileInfo;
  1263. int iSize;
  1264. TCHAR szBuffer[MAX_PATH];
  1265. switch (pLVN->hdr.code)
  1266. {
  1267. case LVN_GETDISPINFO:
  1268. pFileInfo = (CUiSendFileInfo *) pDispInfo->item.lParam;
  1269. ASSERT(NULL != pFileInfo);
  1270. switch (pDispInfo->item.iSubItem)
  1271. {
  1272. case (IDS_LV_FILE_NAME - IDS_LV_FILE_NAME):
  1273. pDispInfo->item.pszText = pFileInfo->GetName();
  1274. break;
  1275. case (IDS_LV_FILE_SIZE - IDS_LV_FILE_NAME):
  1276. ::wsprintf(szBuffer, TEXT("%u"), pFileInfo->GetSize());
  1277. iSize = GetNumberFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE,
  1278. szBuffer, NULL, s_szScratchText, MAX_PATH);
  1279. s_szScratchText[iSize - 4] = '\0'; // remove the trailing ".00"
  1280. pDispInfo->item.pszText = s_szScratchText;
  1281. break;
  1282. case (IDS_LV_FILE_STATUS - IDS_LV_FILE_NAME):
  1283. {
  1284. ULONG cbTotalSend = pFileInfo->GetTotalSend();
  1285. ULONG cbFileSize = pFileInfo->GetSize();
  1286. s_szScratchText[0] = TEXT('\0');
  1287. switch (pFileInfo->GetErrorCode())
  1288. {
  1289. case iMBFT_OK:
  1290. case iMBFT_MULT_RECEIVER_ABORTED:
  1291. if (!pFileInfo->GetFileHandle())
  1292. break; // handle == NULL, if cbTotalSend == 0, zero length file to be sent.
  1293. if (cbTotalSend >= cbFileSize)
  1294. {
  1295. ::MyLoadString(IDS_LV_FILE_SENT);
  1296. }
  1297. else
  1298. if (cbTotalSend)
  1299. {
  1300. if (m_pEngine)
  1301. {
  1302. ::MyLoadString(IDS_LV_FILE_SENDING);
  1303. }
  1304. else
  1305. {
  1306. ::MyLoadString(IDS_LV_FILE_CANCELED);
  1307. }
  1308. }
  1309. break;
  1310. case iMBFT_SENDER_ABORTED:
  1311. case iMBFT_RECEIVER_ABORTED:
  1312. case iMBFT_NO_MORE_FILES:
  1313. ::MyLoadString(IDS_LV_FILE_CANCELED);
  1314. break;
  1315. default:
  1316. ::MyLoadString(IDS_LV_FILE_FAILED);
  1317. break;
  1318. }
  1319. pDispInfo->item.pszText = s_szScratchText;
  1320. }
  1321. break;
  1322. case (IDS_LV_FILE_MODIFIED - IDS_LV_FILE_NAME):
  1323. ftFileTime = pFileInfo->GetLastWrite();
  1324. FileTimeToSystemTime(&ftFileTime, &stSystemTime);
  1325. iSize = GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &stSystemTime,
  1326. "MM'/'dd'/'yyyy", s_szScratchText, MAX_PATH);
  1327. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &stSystemTime,
  1328. " hh':'mm tt", &s_szScratchText[iSize - 1], MAX_PATH-iSize-1);
  1329. pDispInfo->item.pszText = s_szScratchText;
  1330. break;
  1331. }
  1332. break;
  1333. case LVN_COLUMNCLICK:
  1334. {
  1335. BOOL fRet = ListView_SortItems(pLVN->hdr.hwndFrom, ListViewCompareProc, (LPARAM) pLVN->iSubItem);
  1336. ASSERT(fRet);
  1337. }
  1338. break;
  1339. }
  1340. }
  1341. /////////////////////////////////////////////////////////////////
  1342. //
  1343. // WM_DROPFILES
  1344. //
  1345. LRESULT OnDropFiles(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1346. {
  1347. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1348. ASSERT(NULL != pWindow);
  1349. if (g_fSendAllowed)
  1350. {
  1351. return pWindow->OnDropFiles((HANDLE) wParam);
  1352. }
  1353. else
  1354. {
  1355. ::MyLoadString(IDS_MSGBOX_POL_PREVENT);
  1356. ::MessageBox(pWindow->GetHwnd(), s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP);
  1357. return 1;
  1358. }
  1359. }
  1360. LRESULT CAppletWindow::OnDropFiles(HANDLE hDrop)
  1361. {
  1362. if (NULL != m_pEngine && m_pEngine->GetPeerCount() > 1)
  1363. {
  1364. HRESULT hr;
  1365. // get the number of dropped files
  1366. ULONG cFiles = ::DragQueryFile((HDROP) hDrop, 0xFFFFFFFF, NULL, 0);
  1367. // set up the common portion of list view item
  1368. LVITEM lvi;
  1369. ::ZeroMemory(&lvi, sizeof(lvi));
  1370. // lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  1371. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  1372. // iterate on these files
  1373. for (ULONG i = 0; i < cFiles; i++)
  1374. {
  1375. BOOL fRet;
  1376. TCHAR szFile[MAX_PATH];
  1377. if (::DragQueryFile((HDROP) hDrop, i, szFile, count_of(szFile)))
  1378. {
  1379. DBG_SAVE_FILE_LINE
  1380. CUiSendFileInfo *pFileInfo = new CUiSendFileInfo(this, NULL, szFile, &fRet);
  1381. if (NULL != pFileInfo && fRet)
  1382. {
  1383. // put it to the list view
  1384. lvi.iItem = ListView_GetItemCount(m_hwndListView);
  1385. lvi.iSubItem = 0;
  1386. // we are responsible for storing the text to display
  1387. lvi.pszText = LPSTR_TEXTCALLBACK;
  1388. lvi.cchTextMax = MAX_PATH;
  1389. lvi.lParam = (LPARAM) pFileInfo;
  1390. int iRet = ListView_InsertItem(m_hwndListView, &lvi);
  1391. ASSERT(-1 != iRet);
  1392. // UpdateListView(pFileInfo);
  1393. }
  1394. else
  1395. {
  1396. // BUGBUG: we should pop up some error message box here!
  1397. ::MyLoadString(IDS_INVALID_FILENAME, s_szScratchText, szFile);
  1398. ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP);
  1399. delete pFileInfo;
  1400. }
  1401. }
  1402. }
  1403. ::DragFinish((HDROP) hDrop);
  1404. SetForegroundWindow(m_hwndMainUI);
  1405. UpdateUI();
  1406. return 0;
  1407. }
  1408. ::MyLoadString(IDS_MSGBOX_NO_CONF);
  1409. ::SetForegroundWindow(m_hwndMainUI);
  1410. ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP);
  1411. return 1;
  1412. }
  1413. /////////////////////////////////////////////////////////////////
  1414. //
  1415. // WM_CONTEXTMENU
  1416. //
  1417. LRESULT OnContextMenu(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1418. {
  1419. LRESULT rc = 0;
  1420. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1421. ASSERT(NULL != pWindow);
  1422. if ((WPARAM) pWindow->GetHwnd() == wParam)
  1423. {
  1424. // BUGBUG use TrackPopupMenu to show context sensitive menu
  1425. pWindow->OnContextMenuForMainUI(lParam);
  1426. }
  1427. else
  1428. if ((WPARAM) pWindow->GetListView() == wParam)
  1429. {
  1430. // BUGBUG use TrackPopupMenu to show context sensitive menu
  1431. pWindow->OnContextMenuForListView(lParam);
  1432. }
  1433. else
  1434. {
  1435. rc = 1;
  1436. }
  1437. return rc;
  1438. }
  1439. enum
  1440. {
  1441. MENU_IDX_ADD_FILES,
  1442. MENU_IDX_REMOVE_FILES,
  1443. MENU_IDX_BREAK_1,
  1444. MENU_IDX_SEND_ALL,
  1445. MENU_IDX_SEND_ONE,
  1446. MENU_IDX_STOP_SENDING,
  1447. MENU_IDX_BREAK_2,
  1448. MENU_IDX_OPEN_RECV_FOLDER,
  1449. };
  1450. static UI_MENU_INFO s_aMenuInfo[] =
  1451. {
  1452. { IDS_MENU_ADD_FILES, IDM_ADD_FILES, MF_ENABLED | MF_STRING },
  1453. { IDS_MENU_REMOVE_FILES, IDM_REMOVE_FILES, MF_ENABLED | MF_STRING },
  1454. { 0, 0, MF_SEPARATOR}, // menu break
  1455. { IDS_MENU_SEND_ALL, IDM_SEND_ALL, MF_ENABLED | MF_STRING },
  1456. { IDS_MENU_SEND_ONE, IDM_SEND_ONE, MF_ENABLED | MF_STRING },
  1457. { IDS_MENU_STOP_SENDING, IDM_STOP_SENDING, MF_ENABLED | MF_STRING },
  1458. { 0, 0, MF_SEPARATOR}, // menu break
  1459. { IDS_MENU_OPEN_RECV_FOLDER, IDM_OPEN_RECV_FOLDER, MF_ENABLED | MF_STRING },
  1460. { IDS_MENU_CHANGE_FOLDER, IDM_CHANGE_FOLDER, MF_ENABLED | MF_STRING },
  1461. { 0, 0, MF_SEPARATOR }, // menu break
  1462. { IDS_MENU_EXIT, IDM_EXIT, MF_ENABLED | MF_STRING },
  1463. };
  1464. void CAppletWindow::SetContextMenuStates(void)
  1465. {
  1466. if (g_fSendAllowed)
  1467. {
  1468. BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1);
  1469. s_aMenuInfo[MENU_IDX_ADD_FILES].nFlags = fMoreThanOne ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING);
  1470. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  1471. s_aMenuInfo[MENU_IDX_REMOVE_FILES].nFlags = cItems ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING);
  1472. s_aMenuInfo[MENU_IDX_SEND_ALL].nFlags = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING);
  1473. s_aMenuInfo[MENU_IDX_SEND_ONE].nFlags = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(FALSE)) ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING);
  1474. s_aMenuInfo[MENU_IDX_STOP_SENDING].nFlags = m_nCurrSendEventHandle ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING);
  1475. }
  1476. else
  1477. {
  1478. s_aMenuInfo[MENU_IDX_ADD_FILES].nFlags =(MF_GRAYED | MF_STRING);
  1479. s_aMenuInfo[MENU_IDX_REMOVE_FILES].nFlags =(MF_GRAYED | MF_STRING);
  1480. s_aMenuInfo[MENU_IDX_SEND_ALL].nFlags = (MF_GRAYED | MF_STRING);
  1481. s_aMenuInfo[MENU_IDX_SEND_ONE].nFlags = (MF_GRAYED | MF_STRING);
  1482. s_aMenuInfo[MENU_IDX_STOP_SENDING].nFlags = (MF_GRAYED | MF_STRING);
  1483. }
  1484. }
  1485. void CAppletWindow::OnContextMenuForMainUI(LPARAM lParam)
  1486. {
  1487. SetContextMenuStates();
  1488. CreateMenu(lParam, count_of(s_aMenuInfo), &s_aMenuInfo[0]);
  1489. }
  1490. void CAppletWindow::OnContextMenuForListView(LPARAM lParam)
  1491. {
  1492. SetContextMenuStates();
  1493. CreateMenu(lParam, 6, &s_aMenuInfo[0]);
  1494. }
  1495. void CAppletWindow::CreateMenu(LPARAM lParam, ULONG cItems, UI_MENU_INFO aMenuInfo[])
  1496. {
  1497. HMENU hMenu = ::CreatePopupMenu();
  1498. if (NULL != hMenu)
  1499. {
  1500. for (ULONG i = 0; i < cItems; i++)
  1501. {
  1502. if (aMenuInfo[i].idCommand)
  1503. {
  1504. if (::MyLoadString(aMenuInfo[i].idString))
  1505. {
  1506. ::AppendMenu(hMenu, aMenuInfo[i].nFlags, aMenuInfo[i].idCommand, s_szScratchText);
  1507. }
  1508. }
  1509. else
  1510. {
  1511. ::AppendMenu(hMenu, aMenuInfo[i].nFlags, 0, 0);
  1512. }
  1513. }
  1514. ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON,
  1515. GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
  1516. 0, // reserved, must be zero
  1517. m_hwndMainUI,
  1518. NULL); // ignore
  1519. }
  1520. }
  1521. /////////////////////////////////////////////////////////////////
  1522. //
  1523. // WM_SIZE
  1524. //
  1525. LRESULT OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1526. {
  1527. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1528. ASSERT(NULL != pWindow);
  1529. pWindow->OnSizeToolBar();
  1530. pWindow->OnSizeStatusBar();
  1531. pWindow->OnSizeListView();
  1532. return 0;
  1533. }
  1534. void CAppletWindow::OnSizeToolBar(void)
  1535. {
  1536. RECT rcWindow;
  1537. SIZE szToolBar;
  1538. ::GetClientRect(m_hwndMainUI, &rcWindow);
  1539. m_pToolbar->GetDesiredSize(&szToolBar);
  1540. ULONG cx = rcWindow.right - rcWindow.left;
  1541. ULONG cy = szToolBar.cy;;
  1542. ULONG x = 0;
  1543. ULONG y = 0;
  1544. ::MoveWindow(m_pToolbar->GetWindow(), x, y, cx, cy, TRUE);
  1545. }
  1546. void CAppletWindow::OnSizeStatusBar(void)
  1547. {
  1548. RECT rcWindow, rcStatusBar;
  1549. ::GetClientRect(m_hwndMainUI, &rcWindow);
  1550. ::GetWindowRect(m_hwndStatusBar, &rcStatusBar);
  1551. ULONG cx = rcWindow.right - rcWindow.left;
  1552. ULONG cy = rcStatusBar.bottom - rcStatusBar.top;
  1553. ULONG x = 0;
  1554. ULONG y = rcWindow.bottom - cy;
  1555. ::MoveWindow(m_hwndStatusBar, x, y, cx, cy, TRUE);
  1556. ::MoveWindow(m_hwndProgressBar, x + cx/2, y, cx/2 - 40, cy, TRUE);
  1557. int aWidths[NUM_STATUS_BAR_PARTS];
  1558. aWidths[0] = cx / 2; // conference state
  1559. aWidths[1] = cx - 40; // transfer name
  1560. aWidths[2] = -1; // transfer percentage
  1561. ASSERT(3 == NUM_STATUS_BAR_PARTS);
  1562. ::SendMessage(m_hwndStatusBar, SB_SETPARTS, NUM_STATUS_BAR_PARTS, (LPARAM) &aWidths[0]);
  1563. }
  1564. void CAppletWindow::OnSizeListView(void)
  1565. {
  1566. // get the size and position of the main window
  1567. RECT rcWindow, rcToolBar, rcStatusBar;
  1568. SIZE szToolBar;
  1569. ::GetClientRect(m_hwndMainUI, &rcWindow);
  1570. m_pToolbar->GetDesiredSize(&szToolBar);
  1571. ::GetWindowRect(m_hwndStatusBar, &rcStatusBar);
  1572. ULONG x = 0;
  1573. ULONG y = szToolBar.cy - 1;
  1574. ULONG cx = rcWindow.right - rcWindow.left;
  1575. ULONG cy = rcWindow.bottom - rcWindow.top - y - (rcStatusBar.bottom - rcStatusBar.top) + 1;
  1576. ::MoveWindow(m_hwndListView, x, y, cx, cy, TRUE);
  1577. }
  1578. /////////////////////////////////////////////////////////////////
  1579. //
  1580. // WM_HELP
  1581. //
  1582. LRESULT OnHelp(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1583. {
  1584. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1585. ASSERT(NULL != pWindow);
  1586. pWindow->OnHelp();
  1587. return 0;
  1588. }
  1589. /////////////////////////////////////////////////////////////////
  1590. //
  1591. // WM_CLOSE
  1592. //
  1593. LRESULT OnClose(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1594. {
  1595. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1596. ASSERT(NULL != pWindow);
  1597. if (NULL != pWindow)
  1598. {
  1599. pWindow->OnExit();
  1600. }
  1601. return 0;
  1602. }
  1603. /////////////////////////////////////////////////////////////////
  1604. //
  1605. // WM_INITMENUPOPUP
  1606. //
  1607. /*
  1608. LRESULT OnInitMenuPopup(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1609. {
  1610. if (0 != HIWORD(lParam)) // System menu flag
  1611. {
  1612. HMENU hMenu = (HMENU) wParam; // handle of pop-up menu
  1613. ::EnableMenuItem(hMenu, SC_MAXIMIZE, MF_GRAYED);
  1614. ::EnableMenuItem(hMenu, SC_SIZE, MF_GRAYED);
  1615. return 0;
  1616. }
  1617. return 1;
  1618. }
  1619. */
  1620. /////////////////////////////////////////////////////////////////
  1621. //
  1622. // WM_MENUSELECT
  1623. //
  1624. LRESULT OnMenuSelect(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1625. {
  1626. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1627. ASSERT(NULL != pWindow);
  1628. if (NULL != pWindow)
  1629. {
  1630. pWindow->OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam),
  1631. GET_WM_MENUSELECT_FLAGS(wParam, lParam),
  1632. GET_WM_MENUSELECT_HMENU(wParam, lParam));
  1633. }
  1634. return 0;
  1635. }
  1636. /////////////////////////////////////////////////////////////////
  1637. //
  1638. // WM_INITMENUPOPUP
  1639. //
  1640. LRESULT OnGetMinMaxInfo(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1641. {
  1642. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1643. if (NULL != pWindow)
  1644. {
  1645. pWindow->OnGetMinMaxInfo((LPMINMAXINFO) lParam);
  1646. return 0;
  1647. }
  1648. return 1;
  1649. }
  1650. void CAppletWindow::OnGetMinMaxInfo(LPMINMAXINFO pMMI)
  1651. {
  1652. static BOOL s_fEnterBefore = FALSE;
  1653. static SIZE s_csFrame;
  1654. static SIZE s_csSeparator;
  1655. static SIZE s_csScrollBars;
  1656. static SIZE s_csToolBar;
  1657. static SIZE s_csStatusBar;
  1658. static SIZE s_csSum;
  1659. if (! s_fEnterBefore)
  1660. {
  1661. s_fEnterBefore = TRUE;
  1662. s_csFrame.cx = ::GetSystemMetrics(SM_CXSIZEFRAME);
  1663. s_csFrame.cy = ::GetSystemMetrics(SM_CYSIZEFRAME);
  1664. s_csSeparator.cx = ::GetSystemMetrics(SM_CXEDGE);
  1665. s_csSeparator.cy = ::GetSystemMetrics(SM_CYEDGE);
  1666. s_csScrollBars.cx = ::GetSystemMetrics(SM_CXVSCROLL);
  1667. s_csScrollBars.cy = ::GetSystemMetrics(SM_CYHSCROLL);
  1668. m_pToolbar->GetDesiredSize(&s_csToolBar);
  1669. RECT rcStatusBar;
  1670. ::GetWindowRect(m_hwndStatusBar, &rcStatusBar);
  1671. s_csStatusBar.cx = rcStatusBar.right - rcStatusBar.left;
  1672. s_csStatusBar.cy = rcStatusBar.bottom - rcStatusBar.top;
  1673. s_csSum.cx = (s_csFrame.cx << 1);
  1674. s_csSum.cy = (s_csFrame.cy << 1) + (s_csSeparator.cy << 3) +
  1675. s_csToolBar.cy + (rcStatusBar.bottom - rcStatusBar.top) +
  1676. ::GetSystemMetrics( SM_CYCAPTION ) + ::GetSystemMetrics( SM_CYMENU );
  1677. }
  1678. RECT rcListViewItem;
  1679. SIZE csListView;
  1680. csListView.cx = 0;
  1681. for (ULONG i = 0; i < NUM_LIST_VIEW_COLUMNS; i++)
  1682. {
  1683. csListView.cx += ListView_GetColumnWidth(m_hwndListView, i);
  1684. }
  1685. if (ListView_GetItemRect(m_hwndListView, 0, &rcListViewItem, LVIR_BOUNDS))
  1686. {
  1687. csListView.cy = 20 + 3 * (rcListViewItem.bottom - rcListViewItem.top);
  1688. }
  1689. else
  1690. {
  1691. csListView.cy = 20 + 30;
  1692. }
  1693. // Set the minimum width and height of the window
  1694. pMMI->ptMinTrackSize.x = s_csSum.cx + max(s_csToolBar.cx, csListView.cx);
  1695. pMMI->ptMinTrackSize.y = s_csSum.cy + csListView.cy;
  1696. //
  1697. // Retrieves the size of the work area on the primary display monitor. The work
  1698. // area is the portion of the screen not obscured by the system taskbar or by
  1699. // application desktop toolbars
  1700. //
  1701. RECT rcWorkArea;
  1702. ::SystemParametersInfo( SPI_GETWORKAREA, 0, (&rcWorkArea), NULL );
  1703. SIZE csMaxSize;
  1704. csMaxSize.cx = rcWorkArea.right - rcWorkArea.left;
  1705. csMaxSize.cy = rcWorkArea.bottom - rcWorkArea.top;
  1706. pMMI->ptMaxPosition.x = 0;
  1707. pMMI->ptMaxPosition.y = 0;
  1708. pMMI->ptMaxSize.x = csMaxSize.cx;
  1709. pMMI->ptMaxSize.y = csMaxSize.cy;
  1710. pMMI->ptMaxTrackSize.x = csMaxSize.cx;
  1711. pMMI->ptMaxTrackSize.y = csMaxSize.cy;
  1712. }
  1713. /////////////////////////////////////////////////////////////////
  1714. //
  1715. // WM_QUERYENDSESSION
  1716. //
  1717. LRESULT OnQueryEndSession(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1718. {
  1719. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1720. ASSERT(NULL != pWindow);
  1721. if (NULL != pWindow)
  1722. {
  1723. return pWindow->QueryShutdown(); // TRUE: ok to send session; FALSE, no.
  1724. }
  1725. return TRUE; // ok to end session
  1726. }
  1727. /////////////////////////////////////////////////////////////////
  1728. //
  1729. // WM_ENDSESSION
  1730. //
  1731. LRESULT OnEndSession(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1732. {
  1733. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1734. if (wParam && NULL != pWindow)
  1735. {
  1736. pWindow->OnExit(TRUE);
  1737. }
  1738. return 0;
  1739. }
  1740. /////////////////////////////////////////////////////////////////
  1741. //
  1742. // WM_DRAWITEM
  1743. //
  1744. LRESULT OnDrawItem(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1745. {
  1746. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1747. if (wParam && NULL != pWindow)
  1748. {
  1749. pWindow->DrawItem((DRAWITEMSTRUCT *)lParam);
  1750. }
  1751. return 0;
  1752. }
  1753. /////////////////////////////////////////////////////////////////
  1754. //
  1755. // WM_SEND_NEXT
  1756. //
  1757. LRESULT OnSendNext(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1758. {
  1759. CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1760. if (NULL != pWindow)
  1761. {
  1762. pWindow->OnSendAll();
  1763. pWindow->UpdateUI();
  1764. }
  1765. return 0;
  1766. }
  1767. /////////////////////////////////////////////////////////////////
  1768. //
  1769. // Main windows procedure
  1770. //
  1771. LRESULT CALLBACK FtMainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1772. {
  1773. LRESULT rc;
  1774. switch (uMsg)
  1775. {
  1776. case WM_CREATE:
  1777. rc = ::OnCreate(hwnd, wParam, lParam);
  1778. break;
  1779. case WM_COMMAND:
  1780. rc = ::OnCommand(hwnd, wParam, lParam);
  1781. break;
  1782. case WM_NOTIFY:
  1783. rc = ::OnNotify(hwnd, wParam, lParam);
  1784. break;
  1785. case WM_DROPFILES:
  1786. rc = ::OnDropFiles(hwnd, wParam, lParam);
  1787. break;
  1788. case WM_CONTEXTMENU:
  1789. rc = ::OnContextMenu(hwnd, wParam, lParam);
  1790. break;
  1791. case WM_SIZE:
  1792. rc = ::OnSize(hwnd, wParam, lParam);
  1793. break;
  1794. case WM_HELP:
  1795. rc = ::OnHelp(hwnd, wParam, lParam);
  1796. break;
  1797. case WM_DRAWITEM:
  1798. rc = ::OnDrawItem(hwnd, wParam, lParam);
  1799. break;
  1800. case WM_CLOSE:
  1801. rc = ::OnClose(hwnd, wParam, lParam);
  1802. break;
  1803. case WM_INITMENUPOPUP:
  1804. // rc = ::OnInitMenuPopup(hwnd, wParam, lParam);
  1805. break;
  1806. case WM_MENUSELECT:
  1807. rc = ::OnMenuSelect(hwnd, wParam, lParam);
  1808. break;
  1809. case WM_GETMINMAXINFO:
  1810. rc = ::OnGetMinMaxInfo(hwnd, wParam, lParam);
  1811. break;
  1812. case WM_QUERYENDSESSION:
  1813. rc = OnQueryEndSession(hwnd, wParam, lParam);
  1814. break;
  1815. case WM_ENDSESSION:
  1816. rc = ::OnEndSession(hwnd, wParam, lParam);
  1817. break;
  1818. case WM_SEND_NEXT:
  1819. rc = ::OnSendNext(hwnd, wParam, lParam);
  1820. break;
  1821. #if defined(TEST_PLUGABLE) && defined(_DEBUG)
  1822. case WM_PLUGABLE_SOCKET:
  1823. rc = ::OnPluggableSocket(hwnd, wParam, lParam);
  1824. break;
  1825. #endif
  1826. default:
  1827. rc = ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  1828. break;
  1829. }
  1830. return rc;
  1831. }
  1832. /////////////////////////////////////////////////////////////////
  1833. //
  1834. // OnEngineNotify
  1835. //
  1836. void CAppletWindow::OnEngineNotify(MBFTMsg *pMsg)
  1837. {
  1838. BOOL fHeartBeat = FALSE;
  1839. switch (pMsg->GetMsgType())
  1840. {
  1841. case EnumFileOfferNotifyMsg:
  1842. if (m_UIMode != FTUIMODE_NOUI)
  1843. {
  1844. HandleFileOfferNotify((FileOfferNotifyMsg *) pMsg);
  1845. }
  1846. break;
  1847. case EnumFileTransmitMsg:
  1848. if (m_UIMode != FTUIMODE_NOUI)
  1849. {
  1850. HandleProgressNotify((FileTransmitMsg *) pMsg);
  1851. }
  1852. fHeartBeat = TRUE;
  1853. break;
  1854. case EnumFileErrorMsg:
  1855. if (m_UIMode != FTUIMODE_NOUI)
  1856. {
  1857. HandleErrorNotify((FileErrorMsg *) pMsg);
  1858. }
  1859. break;
  1860. case EnumPeerMsg:
  1861. HandlePeerNotification((PeerMsg *) pMsg);
  1862. break;
  1863. case EnumInitUnInitNotifyMsg:
  1864. HandleInitUninitNotification((InitUnInitNotifyMsg *) pMsg);
  1865. break;
  1866. case EnumFileEventEndNotifyMsg:
  1867. if (m_UIMode != FTUIMODE_NOUI)
  1868. {
  1869. HandleFileEventEndNotification((FileEventEndNotifyMsg *) pMsg);
  1870. }
  1871. break;
  1872. default:
  1873. ASSERT(0);
  1874. break;
  1875. } // switch
  1876. }
  1877. void CAppletWindow::HandleFileOfferNotify(FileOfferNotifyMsg *pMsg)
  1878. {
  1879. HRESULT hr = S_OK;
  1880. if (g_fRecvAllowed)
  1881. {
  1882. DBG_SAVE_FILE_LINE
  1883. CUiRecvFileInfo *pRecvFileInfo = new CUiRecvFileInfo(pMsg, &hr);
  1884. if (NULL != pRecvFileInfo && S_OK == hr)
  1885. {
  1886. if (NULL != m_pEngine)
  1887. {
  1888. DBG_SAVE_FILE_LINE
  1889. CRecvDlg *pDlg = new CRecvDlg(this,
  1890. m_pEngine->GetConfID(),
  1891. pMsg->m_NodeID,
  1892. pMsg->m_EventHandle,
  1893. pRecvFileInfo,
  1894. &hr);
  1895. if (NULL != pDlg && S_OK == hr)
  1896. {
  1897. DBG_SAVE_FILE_LINE
  1898. if (S_OK == m_pEngine->SafePostMessage(
  1899. new FileTransferControlMsg(
  1900. pMsg->m_EventHandle,
  1901. pMsg->m_hFile,
  1902. pRecvFileInfo->GetRecvFolder(),
  1903. pMsg->m_szFileName,
  1904. FileTransferControlMsg::EnumAcceptFile)))
  1905. {
  1906. return;
  1907. }
  1908. else
  1909. {
  1910. ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot confirm file offer"));
  1911. }
  1912. }
  1913. else
  1914. {
  1915. ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot allocate CRecvDlg, hr=0x%x", hr));
  1916. }
  1917. delete pDlg;
  1918. }
  1919. else
  1920. {
  1921. ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: no file transfer engine"));
  1922. }
  1923. }
  1924. else
  1925. {
  1926. ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot allocate CUiRecvFileInfo, hr=0x%x", hr));
  1927. }
  1928. delete pRecvFileInfo;
  1929. }
  1930. else
  1931. {
  1932. DBG_SAVE_FILE_LINE
  1933. if (S_OK != m_pEngine->SafePostMessage(
  1934. new FileTransferControlMsg(
  1935. pMsg->m_EventHandle,
  1936. pMsg->m_hFile,
  1937. NULL,
  1938. pMsg->m_szFileName,
  1939. FileTransferControlMsg::EnumRejectFile)))
  1940. {
  1941. ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot confirm file offer"));
  1942. }
  1943. }
  1944. }
  1945. void CAppletWindow::HandleProgressNotify(FileTransmitMsg *pMsg)
  1946. {
  1947. CRecvDlg *pDlg = NULL;
  1948. MBFT_NOTIFICATION wMBFTCode = (MBFT_NOTIFICATION) pMsg->m_TransmitStatus;
  1949. switch (wMBFTCode)
  1950. {
  1951. case iMBFT_FILE_SEND_BEGIN:
  1952. // fall through... because the file start PDU can have data.
  1953. case iMBFT_FILE_SEND_PROGRESS:
  1954. if (NULL != m_pCurrSendFileInfo)
  1955. {
  1956. ASSERT(m_nCurrSendEventHandle == pMsg->m_EventHandle);
  1957. ASSERT(m_pCurrSendFileInfo->GetFileHandle() == pMsg->m_hFile);
  1958. ASSERT(m_pCurrSendFileInfo->GetSize() == pMsg->m_FileSize);
  1959. m_pCurrSendFileInfo->SetTotalSend(pMsg->m_BytesTransmitted);
  1960. UpdateListView(m_pCurrSendFileInfo);
  1961. UpdateStatusBar();
  1962. }
  1963. break;
  1964. case iMBFT_FILE_SEND_END:
  1965. if (NULL != m_pCurrSendFileInfo)
  1966. {
  1967. UpdateListView(m_pCurrSendFileInfo);
  1968. UpdateStatusBar();
  1969. }
  1970. break;
  1971. case iMBFT_FILE_RECEIVE_BEGIN:
  1972. // fall through... because the file start PDU can have data.
  1973. case iMBFT_FILE_RECEIVE_PROGRESS:
  1974. pDlg = FindDlgByHandles(pMsg->m_EventHandle, pMsg->m_hFile);
  1975. if (NULL != pDlg)
  1976. {
  1977. pDlg->OnProgressUpdate(pMsg);
  1978. }
  1979. break;
  1980. case iMBFT_FILE_RECEIVE_END:
  1981. // doing nothing...
  1982. break;
  1983. default:
  1984. ASSERT(0);
  1985. break;
  1986. }
  1987. }
  1988. void CAppletWindow::HandleErrorNotify(FileErrorMsg *pMsg)
  1989. {
  1990. MBFTFILEHANDLE nFileHandle = pMsg->m_hFile;
  1991. if(LOWORD(nFileHandle) == LOWORD(_iMBFT_PROSHARE_ALL_FILES))
  1992. {
  1993. nFileHandle = _iMBFT_PROSHARE_ALL_FILES;
  1994. }
  1995. if (m_nCurrSendEventHandle == pMsg->m_EventHandle &&
  1996. m_pCurrSendFileInfo->GetFileHandle() == nFileHandle)
  1997. {
  1998. m_pCurrSendFileInfo->SetErrorCode((MBFT_ERROR_CODE) pMsg->m_ErrorCode);
  1999. UINT idString;
  2000. switch ((MBFT_ERROR_CODE) pMsg->m_ErrorCode)
  2001. {
  2002. case iMBFT_OK:
  2003. idString = 0;
  2004. break;
  2005. case iMBFT_SENDER_ABORTED:
  2006. case iMBFT_RECEIVER_ABORTED:
  2007. case iMBFT_NO_MORE_FILES:
  2008. idString = IDS_MSGBOX2_CANCELED;
  2009. break;
  2010. case iMBFT_MULT_RECEIVER_ABORTED:
  2011. idString = IDS_MSGBOX2_MULT_CANCEL;
  2012. break;
  2013. // case iMBFT_RECEIVER_REJECTED:
  2014. default:
  2015. idString = IDS_MSGBOX2_SEND_FAILED;
  2016. break;
  2017. }
  2018. if (idString)
  2019. {
  2020. if (! m_pCurrSendFileInfo->HasShownUI())
  2021. {
  2022. if (::MyLoadString(idString, s_szScratchText, m_pCurrSendFileInfo->GetName()))
  2023. {
  2024. m_pCurrSendFileInfo->SetShowUI();
  2025. ::MsgBox2(this, s_szScratchText);
  2026. }
  2027. else
  2028. {
  2029. ASSERT(0);
  2030. }
  2031. }
  2032. }
  2033. UpdateListView(m_pCurrSendFileInfo);
  2034. UpdateStatusBar();
  2035. ClearSendInfo(TRUE);
  2036. if (! idString)
  2037. {
  2038. // send the next one now
  2039. if (m_fSendALL)
  2040. {
  2041. ::PostMessage(m_hwndMainUI, WM_SEND_NEXT, 0, 0);
  2042. }
  2043. }
  2044. }
  2045. else
  2046. {
  2047. CRecvDlg *pDlg = FindDlgByHandles(pMsg->m_EventHandle, nFileHandle);
  2048. if (NULL != pDlg)
  2049. {
  2050. switch ((MBFT_ERROR_CODE) pMsg->m_ErrorCode)
  2051. {
  2052. case iMBFT_RECEIVER_ABORTED:
  2053. case iMBFT_MULT_RECEIVER_ABORTED:
  2054. pDlg->OnCanceled();
  2055. break;
  2056. default:
  2057. pDlg->OnRejectedFile();
  2058. break;
  2059. }
  2060. }
  2061. else
  2062. {
  2063. switch((MBFT_ERROR_CODE) pMsg->m_ErrorCode)
  2064. {
  2065. case iMBFT_INVALID_PATH:
  2066. ::MyLoadString(IDS_MSGBOX2_INVALID_DIRECTORY,
  2067. s_szScratchText, pMsg->m_stFileInfo.szFileName);
  2068. break;
  2069. case iMBFT_DIRECTORY_FULL_ERROR:
  2070. ::MyLoadString(IDS_MSGBOX2_DIRECTORY_FULL,
  2071. s_szScratchText, pMsg->m_stFileInfo.lFileSize,
  2072. pMsg->m_stFileInfo.szFileName);
  2073. break;
  2074. case iMBFT_FILE_ACCESS_DENIED:
  2075. ::MyLoadString(IDS_MSGBOX2_FILE_CREATE_FAILED,
  2076. s_szScratchText, pMsg->m_stFileInfo.szFileName);
  2077. break;
  2078. default:
  2079. return;
  2080. }
  2081. ::MsgBox2(this, s_szScratchText);
  2082. }
  2083. }
  2084. }
  2085. void CAppletWindow::HandlePeerNotification(PeerMsg *pMsg)
  2086. {
  2087. m_pToolbar->HandlePeerNotification(m_pEngine->GetConfID(),
  2088. m_pEngine->GetNodeID(), pMsg);
  2089. }
  2090. void CAppletWindow::HandleInitUninitNotification(InitUnInitNotifyMsg *pMsg)
  2091. {
  2092. if (pMsg->m_iNotifyMessage == EnumInvoluntaryUnInit)
  2093. {
  2094. UnregisterEngine();
  2095. }
  2096. }
  2097. void CAppletWindow::HandleFileEventEndNotification(FileEventEndNotifyMsg *pMsg)
  2098. {
  2099. if (m_nCurrSendEventHandle == pMsg->m_EventHandle)
  2100. {
  2101. ClearSendInfo(TRUE);
  2102. // send the next one now
  2103. if (m_fSendALL)
  2104. {
  2105. ::PostMessage(m_hwndMainUI, WM_SEND_NEXT, 0, 0);
  2106. }
  2107. }
  2108. }
  2109. /////////////////////////////////////////////////////////////////
  2110. //
  2111. // Main UI methods
  2112. //
  2113. void CAppletWindow::BringToFront(void)
  2114. {
  2115. if (NULL != m_hwndMainUI)
  2116. {
  2117. int nCmdShow = SW_SHOW;
  2118. WINDOWPLACEMENT wp;
  2119. ::ZeroMemory(&wp, sizeof(wp));
  2120. wp.length = sizeof(wp);
  2121. if (::GetWindowPlacement(m_hwndMainUI, &wp))
  2122. {
  2123. if (SW_MINIMIZE == wp.showCmd || SW_SHOWMINIMIZED == wp.showCmd)
  2124. {
  2125. // The window is minimized - restore it:
  2126. nCmdShow = SW_RESTORE;
  2127. }
  2128. }
  2129. // show the window now
  2130. ::ShowWindow(m_hwndMainUI, nCmdShow);
  2131. m_UIMode = FTUIMODE_SHOWUI;
  2132. // bring it to the foreground
  2133. ::SetForegroundWindow(m_hwndMainUI);
  2134. }
  2135. }
  2136. void CAppletWindow::ClearSendInfo(BOOL fUpdateUI)
  2137. {
  2138. m_pCurrSendFileInfo = NULL;
  2139. m_nCurrSendEventHandle = NULL;
  2140. if (fUpdateUI)
  2141. {
  2142. UpdateUI();
  2143. }
  2144. }
  2145. void CAppletWindow::ClearRecvInfo(void)
  2146. {
  2147. CRecvDlg *pDlg;
  2148. while (NULL != (pDlg = m_RecvDlgList.Get()))
  2149. {
  2150. ::EndDialog(pDlg->GetHwnd(), IDCLOSE);
  2151. pDlg->Release();
  2152. }
  2153. }
  2154. BOOL CAppletWindow::HasUnSentFiles(BOOL fUnSentOnly)
  2155. {
  2156. BOOL fRc = FALSE;
  2157. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  2158. CUiSendFileInfo *pFileInfo;
  2159. LVITEM lvi;
  2160. if (!fUnSentOnly && cItems) {
  2161. return TRUE;
  2162. }
  2163. ::ZeroMemory(&lvi, sizeof(lvi));
  2164. lvi.mask = LVIF_PARAM; // examine each item one by one
  2165. for (ULONG i = 0; i < cItems; i++, pFileInfo = NULL)
  2166. {
  2167. lvi.iItem = i;
  2168. BOOL fRet = ListView_GetItem(m_hwndListView, &lvi);
  2169. ASSERT(fRet);
  2170. pFileInfo = (CUiSendFileInfo *) lvi.lParam;
  2171. if (!pFileInfo->GetFileHandle()) // if file handle is not zero, then it has been sent or cancelled
  2172. {
  2173. fRc = TRUE;
  2174. break;
  2175. }
  2176. }
  2177. return fRc;
  2178. }
  2179. void CAppletWindow::UpdateUI(void)
  2180. {
  2181. UpdateTitle();
  2182. UpdateMenu();
  2183. UpdateToolBar();
  2184. UpdateStatusBar();
  2185. }
  2186. void CAppletWindow::UpdateTitle(void)
  2187. {
  2188. UINT captionID;
  2189. if ((! m_pEngine) || (m_pEngine->GetPeerCount() <= 1))
  2190. {
  2191. captionID = IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION;
  2192. }
  2193. else
  2194. {
  2195. captionID = IDS_MSFT_IN_CALL_WINDOW_CAPTION;
  2196. }
  2197. ::LoadString(g_hDllInst, captionID, s_szMSFT, sizeof(s_szMSFT));
  2198. SetWindowText(m_hwndMainUI, s_szMSFT);
  2199. }
  2200. void CAppletWindow::UpdateMenu(void)
  2201. {
  2202. HMENU hMenu = ::GetMenu(m_hwndMainUI);
  2203. if (NULL != hMenu)
  2204. {
  2205. if (g_fSendAllowed)
  2206. {
  2207. BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1);
  2208. ::EnableMenuItem(hMenu, IDM_ADD_FILES, fMoreThanOne ? MF_ENABLED : MF_GRAYED);
  2209. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  2210. ::EnableMenuItem(hMenu, IDM_REMOVE_FILES, cItems ? MF_ENABLED : MF_GRAYED);
  2211. ::EnableMenuItem(hMenu, IDM_SEND_ALL, (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? MF_ENABLED : MF_GRAYED);
  2212. ::EnableMenuItem(hMenu, IDM_SEND_ONE, (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(FALSE)) ? MF_ENABLED : MF_GRAYED);
  2213. ::EnableMenuItem(hMenu, IDM_STOP_SENDING, m_nCurrSendEventHandle ? MF_ENABLED : MF_GRAYED);
  2214. }
  2215. else
  2216. {
  2217. ::EnableMenuItem(hMenu, IDM_ADD_FILES, MF_GRAYED);
  2218. ::EnableMenuItem(hMenu, IDM_REMOVE_FILES, MF_GRAYED);
  2219. ::EnableMenuItem(hMenu, IDM_SEND_ALL, MF_GRAYED);
  2220. ::EnableMenuItem(hMenu, IDM_SEND_ONE, MF_GRAYED);
  2221. ::EnableMenuItem(hMenu, IDM_STOP_SENDING, MF_GRAYED);
  2222. }
  2223. }
  2224. }
  2225. void CAppletWindow::UpdateToolBar(void)
  2226. {
  2227. int iFlags[count_of(buttons)];
  2228. ::ZeroMemory(iFlags, sizeof(iFlags));
  2229. iFlags[2] = iFlags[5] = iFlags[6] = 1; // separators
  2230. iFlags[7] = 1; // open recv folders
  2231. if (g_fSendAllowed)
  2232. {
  2233. BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1);
  2234. ULONG cItems = ListView_GetItemCount(m_hwndListView);
  2235. iFlags[0] = fMoreThanOne ? TRUE : FALSE; // Add files
  2236. iFlags[1] = cItems ? TRUE : FALSE; // Delete files
  2237. iFlags[3] = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? TRUE : FALSE; // Send file(s)
  2238. iFlags[4] = m_nCurrSendEventHandle ? TRUE : FALSE; // Stop sending
  2239. m_pToolbar->UpdateButton(iFlags);
  2240. }
  2241. else
  2242. {
  2243. m_pToolbar->UpdateButton(iFlags);
  2244. }
  2245. }
  2246. void CAppletWindow::UpdateStatusBar(void)
  2247. {
  2248. int idString, iPos = 0;
  2249. HICON hIcon;
  2250. RECT rc;
  2251. // set the text in part 0
  2252. s_szScratchText[0] = TEXT('\0');
  2253. if ((NULL != m_pEngine) && (NULL != m_pCurrSendFileInfo))
  2254. {
  2255. idString = IDS_STBAR_SENDING_XYZ;
  2256. ::MyLoadString(idString, s_szScratchText, m_pCurrSendFileInfo->GetName());
  2257. }
  2258. else if (NULL == m_pEngine)
  2259. {
  2260. ::MyLoadString(IDS_STBAR_NOT_IN_CALL);
  2261. }
  2262. else
  2263. {
  2264. ::MyLoadString(IDS_STBAR_NOT_TRANSFERING);
  2265. }
  2266. ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_TRANSFER_FILE, (LPARAM) s_szScratchText);
  2267. // set the progres bar in part 1
  2268. if ((NULL != m_pCurrSendFileInfo)&&m_pCurrSendFileInfo->GetSize())
  2269. {
  2270. iPos = 100 * m_pCurrSendFileInfo->GetTotalSend() / m_pCurrSendFileInfo->GetSize();
  2271. }
  2272. ::SendMessage(m_hwndStatusBar, SB_GETRECT, SBP_PROGRESS, (LPARAM)&rc);
  2273. ::MoveWindow(m_hwndProgressBar,
  2274. rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  2275. FALSE);
  2276. ::SendMessage(m_hwndProgressBar, PBM_SETPOS, iPos, 0);
  2277. // set the icon in part 2
  2278. hIcon = (NULL != m_pEngine) ? m_hIconInCall : m_hIconNotInCall;
  2279. ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_SBICON | SBT_OWNERDRAW, (LPARAM)hIcon);
  2280. }
  2281. void CAppletWindow::UpdateListView(CUiSendFileInfo *pFileInfo)
  2282. {
  2283. LVFINDINFO lvfi;
  2284. ::ZeroMemory(&lvfi, sizeof(lvfi));
  2285. lvfi.flags = LVFI_PARAM;
  2286. lvfi.lParam = (LPARAM) pFileInfo;
  2287. int iItem = ListView_FindItem(m_hwndListView, -1, &lvfi);
  2288. if (-1 != iItem)
  2289. {
  2290. for (ULONG i = 0; i < NUM_LIST_VIEW_COLUMNS; i++)
  2291. {
  2292. ListView_SetItemText(m_hwndListView, iItem, i, LPSTR_TEXTCALLBACK);
  2293. }
  2294. }
  2295. }
  2296. ////////////////////////////////////////////////////////////////////
  2297. //
  2298. // Save window position for File Transfer
  2299. //
  2300. void CAppletWindow::SaveWindowPosition(void)
  2301. {
  2302. RECT rcWnd;
  2303. RegEntry reWnd( FILEXFER_KEY, HKEY_CURRENT_USER);
  2304. // If we are not maximized or minimized
  2305. if (!::IsZoomed(m_hwndMainUI) && !::IsIconic(m_hwndMainUI))
  2306. {
  2307. ::GetWindowRect(m_hwndMainUI, &rcWnd);
  2308. reWnd.SetValue (REGVAL_WINDOW_XPOS, rcWnd.left);
  2309. reWnd.SetValue (REGVAL_WINDOW_YPOS, rcWnd.top);
  2310. reWnd.SetValue (REGVAL_WINDOW_WIDTH, rcWnd.right - rcWnd.left);
  2311. reWnd.SetValue (REGVAL_WINDOW_HEIGHT, rcWnd.bottom - rcWnd.top);
  2312. }
  2313. }
  2314. void CAppletWindow::FocusNextRecvDlg(void)
  2315. {
  2316. if (!m_RecvDlgList.IsEmpty())
  2317. {
  2318. m_RecvDlgList.Reset();
  2319. CRecvDlg *pRecvDlg = m_RecvDlgList.Iterate();
  2320. if (pRecvDlg)
  2321. {
  2322. SetFocus(pRecvDlg->GetHwnd());
  2323. }
  2324. }
  2325. }
  2326. void CAppletWindow::FocusNextErrorDlg(void)
  2327. {
  2328. if (!m_ErrorDlgList.IsEmpty())
  2329. {
  2330. m_ErrorDlgList.Reset();
  2331. HWND hwndErrorDlg = m_ErrorDlgList.Iterate();
  2332. if (hwndErrorDlg)
  2333. {
  2334. ::SetFocus(hwndErrorDlg);
  2335. }
  2336. }
  2337. }
  2338. /////////////////////////////////////////////////////////////////
  2339. //
  2340. // Utilities
  2341. //
  2342. LPTSTR PathNameToFileName(LPTSTR pszPathName)
  2343. {
  2344. LPTSTR psz = pszPathName;
  2345. while (*psz != '\0')
  2346. {
  2347. BOOL fDirChar = (*psz == TEXT('\\'));
  2348. psz = ::CharNext(psz);
  2349. if (fDirChar)
  2350. {
  2351. pszPathName = psz;
  2352. }
  2353. }
  2354. return pszPathName;
  2355. }
  2356. int MyLoadString(UINT idStr)
  2357. {
  2358. s_szScratchText[0] = TEXT('\0');
  2359. int iRet = ::LoadString(g_hDllInst, idStr, s_szScratchText, MAX_PATH);
  2360. ASSERT(iRet);
  2361. return iRet;
  2362. }
  2363. int MyLoadString(UINT idStr, LPTSTR pszDstStr)
  2364. {
  2365. *pszDstStr = TEXT('\0');
  2366. int iRet = ::LoadString(g_hDllInst, idStr, pszDstStr, MAX_PATH);
  2367. ASSERT(iRet);
  2368. return iRet;
  2369. }
  2370. int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement)
  2371. {
  2372. int cch;
  2373. TCHAR szText[MAX_PATH];
  2374. cch = ::LoadString(g_hDllInst, idStr, szText, count_of(szText));
  2375. if (cch)
  2376. {
  2377. ::wsprintf(pszDstStr, szText, pszElement);
  2378. }
  2379. else
  2380. {
  2381. ASSERT(0);
  2382. *pszDstStr = TEXT('\0');
  2383. }
  2384. return cch;
  2385. }
  2386. int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, LPTSTR pszElement2)
  2387. {
  2388. int cch;
  2389. TCHAR szText[MAX_PATH];
  2390. cch = ::LoadString(g_hDllInst, idStr, szText, count_of(szText));
  2391. if (cch)
  2392. {
  2393. ::wsprintf(pszDstStr, szText, pszElement1, pszElement2);
  2394. }
  2395. else
  2396. {
  2397. ASSERT(0);
  2398. *pszDstStr = TEXT('\0');
  2399. }
  2400. return cch;
  2401. }
  2402. void LoadDefaultStrings(void)
  2403. {
  2404. // load file transfer name
  2405. s_szMSFT[0] = TEXT('\0');
  2406. ::LoadString(g_hDllInst, IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION,
  2407. s_szMSFT, count_of(s_szMSFT));
  2408. }
  2409. /////////////////////////////////////////////////////////////////
  2410. //
  2411. // CUiSendFileInfo
  2412. //
  2413. CUiSendFileInfo::CUiSendFileInfo(CAppletWindow *pWindow, TCHAR szDir[], TCHAR szFile[], BOOL *pfRet)
  2414. :
  2415. m_nFileHandle(0),
  2416. m_cbTotalSend(0),
  2417. m_eSendErrorCode(iMBFT_OK),
  2418. m_fAlreadyShowUI(FALSE),
  2419. m_pszFullName(NULL)
  2420. {
  2421. *pfRet = FALSE; // failure as default
  2422. HANDLE hFile;
  2423. // build a full name
  2424. hFile = GetOpenFile(pWindow, szDir, szFile, TRUE); // try to resolve
  2425. if (INVALID_HANDLE_VALUE == hFile)
  2426. {
  2427. hFile = GetOpenFile(pWindow, szDir, szFile, FALSE);
  2428. }
  2429. if (INVALID_HANDLE_VALUE != hFile)
  2430. {
  2431. // get the file info
  2432. ::ZeroMemory(&m_FileInfo, sizeof(m_FileInfo));
  2433. BOOL rc = ::GetFileInformationByHandle(hFile, &m_FileInfo);
  2434. ::CloseHandle(hFile);
  2435. if (rc)
  2436. {
  2437. ASSERT(0 == m_FileInfo.nFileSizeHigh);
  2438. // make sure the file size is smaller than what the policy says
  2439. if ((! g_cbMaxSendFileSize) || GetSize() <= g_cbMaxSendFileSize * 1024)
  2440. {
  2441. *pfRet = TRUE;
  2442. }
  2443. else if (pWindow->GetUIMode() != FTUIMODE_NOUI)
  2444. {
  2445. ::MyLoadString(IDS_MSGBOX_SEND_BIG_FILE, s_szScratchText, (LPTSTR) g_cbMaxSendFileSize, m_pszFileName);
  2446. ::MessageBox(pWindow->GetHwnd(), s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP);
  2447. }
  2448. }
  2449. }
  2450. }
  2451. CUiSendFileInfo::~CUiSendFileInfo(void)
  2452. {
  2453. delete m_pszFullName;
  2454. }
  2455. HANDLE CUiSendFileInfo::GetOpenFile(CAppletWindow *pWindow, TCHAR szDir[], TCHAR szFile[], BOOL fResolve)
  2456. {
  2457. // build a full name
  2458. ULONG cch;
  2459. TCHAR szName[MAX_PATH*2];
  2460. HANDLE hFile = INVALID_HANDLE_VALUE;
  2461. if ((NULL != szDir)&&(!_StrChr(szFile, '\\')))
  2462. {
  2463. cch = ::lstrlen(szDir);
  2464. ::wsprintf(szName, (TEXT('\\') == szDir[cch-1]) ? TEXT("%s%s") : TEXT("%s\\%s"), szDir, szFile);
  2465. }
  2466. else
  2467. {
  2468. // file name is the full name
  2469. ::lstrcpy(szName, szFile);
  2470. }
  2471. // resolve shortcut if necessary
  2472. cch = ::lstrlen(szName) + 1;
  2473. if (fResolve&&(cch >= 4))
  2474. {
  2475. if (! ::lstrcmpi(&szName[cch-5], TEXT(".lnk")))
  2476. {
  2477. pWindow->ResolveShortcut(szName, szName);
  2478. cch = ::lstrlen(szName) + 1;
  2479. }
  2480. }
  2481. if (m_pszFullName)
  2482. {
  2483. delete [] m_pszFullName;
  2484. }
  2485. // construct the full name
  2486. DBG_SAVE_FILE_LINE
  2487. m_pszFullName = new TCHAR[cch];
  2488. if (NULL != m_pszFullName)
  2489. {
  2490. ::CopyMemory(m_pszFullName, szName, cch * sizeof(TCHAR));
  2491. m_pszFileName = ::PathNameToFileName(m_pszFullName);
  2492. // open the file
  2493. hFile = ::CreateFile(m_pszFullName, GENERIC_READ,
  2494. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2495. NULL, OPEN_EXISTING,
  2496. FILE_ATTRIBUTE_NORMAL, NULL);
  2497. }
  2498. return hFile;
  2499. }
  2500. /////////////////////////////////////////////////////////////////
  2501. //
  2502. // CUiRecvFileInfo
  2503. //
  2504. CUiRecvFileInfo::CUiRecvFileInfo(FileOfferNotifyMsg *pMsg, HRESULT *pHr)
  2505. :
  2506. m_nFileHandle(pMsg->m_hFile),
  2507. m_FileDateTime(pMsg->m_FileDateTime),
  2508. m_cbFileSize(pMsg->m_FileSize),
  2509. m_cbTotalRecvSize(0),
  2510. m_pszFullName(NULL),
  2511. m_pszRecvFolder(NULL)
  2512. {
  2513. *pHr = E_FAIL; // failure, at default
  2514. ULONG cchTotal = ::lstrlen(pMsg->m_szFileName);
  2515. // construct the full name
  2516. DBG_SAVE_FILE_LINE
  2517. m_pszFullName = new TCHAR[cchTotal+2];
  2518. if (NULL != m_pszFullName)
  2519. {
  2520. // construct full name and file name
  2521. ::wsprintf(m_pszFullName, TEXT("%s"), pMsg->m_szFileName);
  2522. m_pszFileName = PathNameToFileName(m_pszFullName);
  2523. ULONG cchFile = ::lstrlen(m_pszFileName);
  2524. DBG_SAVE_FILE_LINE
  2525. m_pszRecvFolder = new TCHAR[cchTotal - cchFile + 2];
  2526. if (NULL != m_pszRecvFolder)
  2527. {
  2528. ::CopyMemory(m_pszRecvFolder, m_pszFullName, cchTotal - cchFile);
  2529. m_pszRecvFolder[cchTotal - cchFile - 1] = TEXT('\0');
  2530. *pHr = S_OK;
  2531. }
  2532. }
  2533. }
  2534. CUiRecvFileInfo::~CUiRecvFileInfo(void)
  2535. {
  2536. delete m_pszFullName;
  2537. delete m_pszRecvFolder;
  2538. }
  2539. /////////////////////////////////////////////////////////////////
  2540. //
  2541. // Receive Dialog
  2542. //
  2543. CRecvDlg::CRecvDlg
  2544. (
  2545. CAppletWindow *pWindow,
  2546. T120ConfID nConfID,
  2547. T120NodeID nidSender,
  2548. MBFTEVENTHANDLE nEventHandle,
  2549. CUiRecvFileInfo *pFileInfo,
  2550. HRESULT *pHr
  2551. )
  2552. :
  2553. CRefCount(MAKE_STAMP_ID('F','T','R','D')),
  2554. m_pWindow(pWindow),
  2555. m_nConfID(nConfID),
  2556. m_nidSender(nidSender),
  2557. m_nEventHandle(nEventHandle),
  2558. m_pRecvFileInfo(pFileInfo),
  2559. m_fRecvComplete(FALSE),
  2560. m_fShownRecvCompleteUI(FALSE),
  2561. m_idResult(0),
  2562. m_dwEstTimeLeft(0),
  2563. m_dwPreviousTime(0),
  2564. m_dwPreviousTransferred(0),
  2565. m_dwBytesPerSec(0),
  2566. m_dwStartTime(::GetTickCount())
  2567. {
  2568. *pHr = E_FAIL; // failure, at default
  2569. m_hwndRecvDlg = ::CreateDialogParam(g_hDllInst, MAKEINTRESOURCE(IDD_RECVDLG),
  2570. pWindow->GetHwnd(), RecvDlgProc, (LPARAM) this);
  2571. ASSERT(NULL != m_hwndRecvDlg);
  2572. if (NULL != m_hwndRecvDlg)
  2573. {
  2574. ::ShowWindow(m_hwndRecvDlg, SW_SHOWNORMAL);
  2575. m_pWindow->RegisterRecvDlg(this);
  2576. *pHr = S_OK;
  2577. ::SetForegroundWindow(m_hwndRecvDlg);
  2578. }
  2579. }
  2580. CRecvDlg::~CRecvDlg(void)
  2581. {
  2582. delete m_pRecvFileInfo;
  2583. m_pWindow->UnregisterRecvDlg(this);
  2584. if (NULL != m_hwndRecvDlg)
  2585. {
  2586. HWND hwnd = m_hwndRecvDlg;
  2587. m_hwndRecvDlg = NULL;
  2588. ::EndDialog(hwnd, IDCLOSE);
  2589. }
  2590. }
  2591. /////////////////////////////////////////////////////////////////
  2592. //
  2593. // RecvDlg_OnInitDialog
  2594. //
  2595. void RecvDlg_OnInitDialog(HWND hdlg, WPARAM wParam, LPARAM lParam)
  2596. {
  2597. CRecvDlg *pDlg = (CRecvDlg *) ::GetWindowLongPtr(hdlg, DWLP_USER);
  2598. ASSERT(NULL != pDlg);
  2599. CUiRecvFileInfo *pFileInfo = (CUiRecvFileInfo *) pDlg->GetRecvFileInfo();
  2600. ASSERT(NULL != pFileInfo);
  2601. // move the window to proper location
  2602. ULONG nCaptionHeight = ::GetSystemMetrics(SM_CYCAPTION);
  2603. ULONG nShift = nCaptionHeight * (s_cRecvDlg++ % 8);
  2604. RECT rcDlg;
  2605. ::GetWindowRect(hdlg, &rcDlg);
  2606. ::MoveWindow(hdlg, rcDlg.left + nShift, rcDlg.top + nShift,
  2607. rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top, FALSE);
  2608. // Set font (for international)
  2609. HFONT hfont = (HFONT) ::GetStockObject(DEFAULT_GUI_FONT);
  2610. ASSERT(NULL != hfont);
  2611. ::SendDlgItemMessage(hdlg, IDE_RECVDLG_RECFILE, WM_SETFONT, (WPARAM) hfont, 0);
  2612. ::SendDlgItemMessage(hdlg, IDE_RECVDLG_RECDIR, WM_SETFONT, (WPARAM) hfont, 0);
  2613. ::SendDlgItemMessage(hdlg, IDE_RECVDLG_SENDER, WM_SETFONT, (WPARAM) hfont, 0);
  2614. // cache names
  2615. LPTSTR pszFileName = pFileInfo->GetName();
  2616. LPTSTR pszFullName = pFileInfo->GetFullName();
  2617. // title
  2618. TCHAR szText[MAX_PATH*2];
  2619. if (::MyLoadString(IDS_RECVDLG_TITLE, szText, pszFileName))
  2620. {
  2621. ::SetWindowText(hdlg, szText);
  2622. }
  2623. // filename
  2624. ::lstrcpyn(szText, pszFileName, MAX_FILE_NAME_LENGTH);
  2625. if (::lstrlen(pszFileName) > MAX_FILE_NAME_LENGTH)
  2626. {
  2627. LPTSTR psz = szText;
  2628. int i = MAX_FILE_NAME_LENGTH - 1;
  2629. while (i)
  2630. {
  2631. psz = CharNext(psz);
  2632. i--;
  2633. }
  2634. ::lstrcpy(psz, TEXT("..."));
  2635. }
  2636. ::SetDlgItemText(hdlg, IDE_RECVDLG_RECFILE, szText);
  2637. // directory Name
  2638. LPTSTR psz = szText;
  2639. ::lstrcpyn(szText, pszFullName, (int)(pszFileName - pszFullName));
  2640. HDC hdc = ::GetDC(hdlg);
  2641. if (NULL != hdc)
  2642. {
  2643. SIZE size;
  2644. if (::GetTextExtentPoint32(hdc, szText, ::lstrlen(szText), &size))
  2645. {
  2646. RECT rc;
  2647. ::GetWindowRect(::GetDlgItem(hdlg, IDE_RECVDLG_RECDIR), &rc);
  2648. if (size.cx > (rc.right - rc.left))
  2649. {
  2650. // Just display the folder name
  2651. psz = (LPTSTR) ::GetFileNameFromPath(szText);
  2652. }
  2653. }
  2654. }
  2655. ::ReleaseDC(hdlg, hdc);
  2656. ::SetDlgItemText(hdlg, IDE_RECVDLG_RECDIR, psz);
  2657. // sender Name
  2658. if (::T120_GetNodeName(pDlg->GetConfID(), pDlg->GetSenderID(), szText, count_of(szText)))
  2659. {
  2660. ::SetDlgItemText(hdlg, IDE_RECVDLG_SENDER, szText);
  2661. }
  2662. // update "Received xxx bytes of yyy"
  2663. if (::MyLoadString(IDS_RECVDLG_RECBYTES, szText, pFileInfo->GetTotalRecvSize(), pFileInfo->GetSize()))
  2664. {
  2665. ::SetDlgItemText(hdlg, IDE_RECVDLG_RECBYTES, szText);
  2666. }
  2667. // progress bar
  2668. ::SendMessage(GetDlgItem(hdlg, IDC_RECVDLG_PROGRESS), PBM_SETPOS, pDlg->GetPercent(), 0);
  2669. // start animation
  2670. Animate_Open(GetDlgItem(hdlg, IDC_RECVDLG_ANIMATE), MAKEINTRESOURCE(IDA_RECVDLG_ANIMATION));
  2671. // do the animation work
  2672. if (! pDlg->IsRecvComplete())
  2673. {
  2674. Animate_Play(GetDlgItem(hdlg, IDC_RECVDLG_ANIMATE), 0, -1, -1);
  2675. if (::LoadString(g_hDllInst, IDS_RECVDLG_START, szText, count_of(szText)))
  2676. {
  2677. ::SetDlgItemText(hdlg, IDE_RECVDLG_TIME, szText);
  2678. }
  2679. }
  2680. // show the window now
  2681. ::ShowWindow(hdlg, SW_SHOWNORMAL);
  2682. // UpdateProgress();
  2683. pDlg->OnProgressUpdate();
  2684. }
  2685. /////////////////////////////////////////////////////////////////
  2686. //
  2687. // RecvDlg_OnCommand
  2688. //
  2689. void RecvDlg_OnCommand(HWND hdlg, WPARAM wParam, LPARAM lParam)
  2690. {
  2691. CRecvDlg *pDlg = (CRecvDlg *) ::GetWindowLongPtr(hdlg, DWLP_USER);
  2692. ASSERT(NULL != pDlg);
  2693. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2694. {
  2695. case IDM_RECVDLG_DELETE:
  2696. pDlg->OnDelete();
  2697. break;
  2698. case IDM_RECVDLG_OPEN:
  2699. pDlg->OnOpen();
  2700. break;
  2701. case IDM_RECVDLG_ACCEPT:
  2702. case IDOK:
  2703. case IDCANCEL:
  2704. case IDCLOSE:
  2705. pDlg->OnAccept();
  2706. break;
  2707. default:
  2708. return;
  2709. }
  2710. // dismiss the dialog
  2711. ::EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam));
  2712. pDlg->Release();
  2713. }
  2714. void CRecvDlg::OnOpen(void)
  2715. {
  2716. // create short version of the path name
  2717. TCHAR szDir[MAX_PATH];
  2718. ::GetShortPathName(m_pRecvFileInfo->GetRecvFolder(), szDir, count_of(szDir));
  2719. // create short version of the full name
  2720. TCHAR szFile[MAX_PATH];
  2721. szFile[0] = TEXT('\0');
  2722. ::wsprintf(szFile, TEXT("%s\\%s"), szDir, m_pRecvFileInfo->GetName());
  2723. TRACE_OUT(("FT: Opening [%s] in [%]", m_pRecvFileInfo->GetName(), szDir));
  2724. HINSTANCE hInst = ::ShellExecute(m_pWindow->GetHwnd(),
  2725. NULL,
  2726. szFile,
  2727. NULL,
  2728. szDir,
  2729. SW_SHOWDEFAULT);
  2730. if (32 >= (DWORD_PTR) hInst)
  2731. {
  2732. WARNING_OUT(("Unable to open [%s] - showing file", szFile));
  2733. ::ShellExecute(m_pWindow->GetHwnd(),
  2734. NULL,
  2735. szDir,
  2736. m_pRecvFileInfo->GetFullName(),
  2737. NULL,
  2738. SW_SHOWDEFAULT);
  2739. }
  2740. }
  2741. void CRecvDlg::OnDelete(void)
  2742. {
  2743. StopAnimation();
  2744. // check if transfer has completed
  2745. if (! m_fRecvComplete)
  2746. {
  2747. DBG_SAVE_FILE_LINE
  2748. m_pWindow->GetEngine()->SafePostMessage(
  2749. new FileTransferControlMsg(
  2750. m_nEventHandle,
  2751. m_pRecvFileInfo->GetFileHandle(),
  2752. NULL,
  2753. NULL,
  2754. FileTransferControlMsg::EnumAbortFile));
  2755. }
  2756. else
  2757. {
  2758. ::DeleteFile(m_pRecvFileInfo->GetFullName());
  2759. }
  2760. }
  2761. void CRecvDlg::OnAccept(void)
  2762. {
  2763. StopAnimation();
  2764. }
  2765. /////////////////////////////////////////////////////////////////
  2766. //
  2767. // RecvDlg_OnInitMenuPopup
  2768. //
  2769. void RecvDlg_OnInitMenuPopup(HWND hdlg, WPARAM wParam, LPARAM lParam)
  2770. {
  2771. if (0 != HIWORD(lParam)) // System menu flag
  2772. {
  2773. HMENU hMenu = (HMENU) wParam; // handle of pop-up menu
  2774. ::EnableMenuItem(hMenu, SC_MAXIMIZE, MF_GRAYED);
  2775. ::EnableMenuItem(hMenu, SC_SIZE, MF_GRAYED);
  2776. }
  2777. }
  2778. /////////////////////////////////////////////////////////////////
  2779. //
  2780. // RecvDlgProc
  2781. //
  2782. INT_PTR CALLBACK RecvDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2783. {
  2784. BOOL fRet = TRUE; // processed
  2785. switch (uMsg)
  2786. {
  2787. case WM_INITDIALOG:
  2788. ASSERT(NULL != lParam);
  2789. ::SetWindowLongPtr(hdlg, DWLP_USER, lParam);
  2790. RecvDlg_OnInitDialog(hdlg, wParam, lParam);
  2791. break;
  2792. case WM_COMMAND:
  2793. RecvDlg_OnCommand(hdlg, wParam, lParam);
  2794. break;
  2795. case WM_INITMENUPOPUP:
  2796. RecvDlg_OnInitMenuPopup(hdlg, wParam, lParam);
  2797. fRet = FALSE;
  2798. break;
  2799. // This means user wants to delete the file.
  2800. case WM_CLOSE:
  2801. RecvDlg_OnCommand(hdlg, IDCLOSE, lParam);
  2802. break;;
  2803. default:
  2804. fRet = FALSE; // not processed
  2805. break;
  2806. }
  2807. return fRet;
  2808. }
  2809. /////////////////////////////////////////////////////////////////
  2810. //
  2811. // RecvDlg Animation
  2812. //
  2813. void CRecvDlg::StopAnimation(void)
  2814. {
  2815. HWND hwnd = ::GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_ANIMATE);
  2816. if (NULL != hwnd)
  2817. {
  2818. Animate_Stop(hwnd);
  2819. Animate_Close(hwnd);
  2820. }
  2821. }
  2822. /////////////////////////////////////////////////////////////////
  2823. //
  2824. // RecvDlg Progress
  2825. //
  2826. ULONG CRecvDlg::GetPercent(void)
  2827. {
  2828. ULONG cbFileSize = m_pRecvFileInfo->GetSize();
  2829. ULONG cbTotalRecvSize = m_pRecvFileInfo->GetTotalRecvSize();
  2830. if (! cbFileSize || (cbTotalRecvSize >= cbFileSize))
  2831. {
  2832. return 100;
  2833. }
  2834. // FUTURE: Consider using EnlargedUnsignedMultiply
  2835. if (cbFileSize < 0x01000000)
  2836. {
  2837. return (cbTotalRecvSize * 100) / cbFileSize;
  2838. }
  2839. return cbTotalRecvSize / (cbFileSize / 100);
  2840. }
  2841. void CRecvDlg::OnProgressUpdate(FileTransmitMsg *pMsg)
  2842. {
  2843. if (NULL != pMsg)
  2844. {
  2845. ASSERT(iMBFT_FILE_RECEIVE_PROGRESS == (MBFT_NOTIFICATION) pMsg->m_TransmitStatus ||
  2846. iMBFT_FILE_RECEIVE_BEGIN == (MBFT_NOTIFICATION) pMsg->m_TransmitStatus);
  2847. ASSERT(m_nEventHandle == pMsg->m_EventHandle);
  2848. ASSERT(m_pRecvFileInfo->GetFileHandle() == pMsg->m_hFile);
  2849. ASSERT(m_pRecvFileInfo->GetSize() == pMsg->m_FileSize);
  2850. m_pRecvFileInfo->SetTotalRecvSize(pMsg->m_BytesTransmitted);
  2851. if (pMsg->m_BytesTransmitted >= pMsg->m_FileSize)
  2852. {
  2853. m_fRecvComplete = TRUE;
  2854. m_idResult = IDS_RECVDLG_COMPLETE;
  2855. }
  2856. }
  2857. if (m_fRecvComplete && ! m_fShownRecvCompleteUI)
  2858. {
  2859. m_fRecvComplete = TRUE;
  2860. TCHAR szText[MAX_PATH];
  2861. if (::LoadString(g_hDllInst, IDS_RECVDLG_CLOSE, szText, count_of(szText)))
  2862. {
  2863. ::SetDlgItemText(m_hwndRecvDlg, IDM_RECVDLG_ACCEPT, szText);
  2864. }
  2865. if (IDS_RECVDLG_COMPLETE == m_idResult)
  2866. {
  2867. ::EnableWindow(::GetDlgItem(m_hwndRecvDlg, IDM_RECVDLG_OPEN), TRUE);
  2868. }
  2869. else
  2870. {
  2871. ::EnableWindow(::GetDlgItem(m_hwndRecvDlg, IDM_RECVDLG_DELETE), FALSE);
  2872. }
  2873. // Reset animation
  2874. HWND hwnd = ::GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_ANIMATE);
  2875. Animate_Stop(hwnd);
  2876. Animate_Close(hwnd);
  2877. Animate_Open(hwnd, MAKEINTRESOURCE(IDA_RECVDLG_DONE));
  2878. Animate_Seek(hwnd, ((IDS_RECVDLG_COMPLETE == m_idResult) ? 0 : 1));
  2879. m_fShownRecvCompleteUI = TRUE;
  2880. }
  2881. ULONG cbTotalRecvSize = m_pRecvFileInfo->GetTotalRecvSize();
  2882. ULONG cbFileSize = m_pRecvFileInfo->GetSize();
  2883. DWORD dwNow = ::GetTickCount();
  2884. DWORD dwBytesPerSec;
  2885. DWORD dwBytesRead;
  2886. TCHAR szOut[MAX_PATH];
  2887. if (m_dwPreviousTransferred != cbTotalRecvSize)
  2888. {
  2889. TCHAR szFmt[MAX_PATH];
  2890. // Update "Received xxx bytes of yyy"
  2891. if (::LoadString(g_hDllInst, IDS_RECVDLG_RECBYTES, szFmt, count_of(szFmt)))
  2892. {
  2893. ::wsprintf(szOut, szFmt, cbTotalRecvSize, cbFileSize);
  2894. ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_RECBYTES, szOut);
  2895. }
  2896. // Update Progress Bar
  2897. if (cbTotalRecvSize)
  2898. {
  2899. ::SendMessage(GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_PROGRESS), PBM_SETPOS, GetPercent(), 0);
  2900. }
  2901. }
  2902. // check if no time estimate is required
  2903. if (m_fRecvComplete)
  2904. {
  2905. if (::LoadString(g_hDllInst, m_idResult, szOut, count_of(szOut)))
  2906. {
  2907. ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_TIME, szOut);
  2908. }
  2909. return;
  2910. }
  2911. // first time we're in here for this file?
  2912. if (! m_dwPreviousTime || ! cbTotalRecvSize)
  2913. {
  2914. // no data, yet
  2915. m_dwPreviousTime = dwNow - 1000;
  2916. ASSERT(! m_dwPreviousTransferred);
  2917. ASSERT(! m_dwBytesPerSec);
  2918. return;
  2919. }
  2920. // Has enough time elapsed to update the display?
  2921. // We do this about every 5 seconds (note the adjustment for first time)
  2922. if ((dwNow - m_dwPreviousTime) < 5000)
  2923. return;
  2924. dwBytesRead = cbTotalRecvSize - m_dwPreviousTransferred;
  2925. // We take 10 times the number of bytes and divide by the number of
  2926. // tenths of a second to minimize both overflow and roundoff
  2927. dwBytesPerSec = dwBytesRead * 10 / ((dwNow - m_dwPreviousTime) / 100);
  2928. if (! dwBytesPerSec)
  2929. {
  2930. // very low transmission rate! Ignore the information?
  2931. return;
  2932. }
  2933. if (m_dwBytesPerSec)
  2934. {
  2935. // Take the average of the current transfer rate and the
  2936. // previously computed one, just to try to smooth out
  2937. // some random fluctuations
  2938. dwBytesPerSec = (dwBytesPerSec + m_dwBytesPerSec) / 2;
  2939. }
  2940. m_dwBytesPerSec = dwBytesPerSec;
  2941. // Calculate time remaining (round up by adding 1)
  2942. m_dwEstTimeLeft = ((cbFileSize - cbTotalRecvSize) / m_dwBytesPerSec) + 1;
  2943. // Reset time and # of bytes read
  2944. m_dwPreviousTime = dwNow;
  2945. m_dwPreviousTransferred = cbTotalRecvSize;
  2946. if (m_dwEstTimeLeft < 3)
  2947. {
  2948. // szOut[0] = _T('\0'); // don't bother updating when almost done
  2949. return;
  2950. }
  2951. if (m_dwEstTimeLeft > 99)
  2952. {
  2953. // dwTime is about 2 mintes
  2954. ::MyLoadString(IDS_RECVDLG_MINUTES, szOut, ((m_dwEstTimeLeft / 60) + 1));
  2955. }
  2956. else
  2957. {
  2958. // Round up to 5 seconds so it doesn't look so random
  2959. ::MyLoadString(IDS_RECVDLG_SECONDS, szOut, (((m_dwEstTimeLeft + 4) / 5) * 5) );
  2960. }
  2961. ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_TIME, szOut);
  2962. }
  2963. void CRecvDlg::OnCanceled(void)
  2964. {
  2965. m_idResult = IDS_RECVDLG_CANCEL;
  2966. m_fRecvComplete = TRUE;
  2967. OnProgressUpdate();
  2968. }
  2969. void CRecvDlg::OnRejectedFile(void)
  2970. {
  2971. m_idResult = IDS_RECVDLG_SENDER_CANCEL;
  2972. m_fRecvComplete = TRUE;
  2973. OnProgressUpdate();
  2974. }
  2975. //////////////////////////////////////////////////////////////////////
  2976. //
  2977. // Shortcut/Link Management
  2978. //
  2979. void CAppletWindow::ResolveShortcut(LPTSTR pszSrcFile, LPTSTR pszDstFile)
  2980. {
  2981. ASSERT(NULL != pszSrcFile && '\0' != *pszSrcFile);
  2982. ASSERT(NULL != pszDstFile);
  2983. IShellLink *psl;
  2984. HRESULT hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  2985. IID_IShellLink, (LPVOID *) &psl);
  2986. if (SUCCEEDED(hr))
  2987. {
  2988. IPersistFile *ppf;
  2989. hr = psl->QueryInterface(IID_IPersistFile, (LPVOID *) &ppf);
  2990. if (SUCCEEDED(hr))
  2991. {
  2992. WCHAR wsz[MAX_PATH]; /* Buffer for unicode string */
  2993. #ifdef _UNICODE
  2994. ::lstrcpyn(wsz, pszSrcFile, MAX_PATH);
  2995. #else
  2996. ::MultiByteToWideChar(CP_ACP, 0, pszSrcFile, -1, wsz, MAX_PATH);
  2997. #endif
  2998. hr = ppf->Load(wsz, STGM_READ);
  2999. if (SUCCEEDED(hr))
  3000. {
  3001. /* Resolve the link, this may post UI to find the link */
  3002. hr = psl->Resolve(m_hwndMainUI, SLR_ANY_MATCH);
  3003. if (SUCCEEDED(hr))
  3004. {
  3005. psl->GetPath(pszDstFile, MAX_PATH, NULL, 0);
  3006. }
  3007. TRACE_OUT(("CAppletWindow::ResolveShortcut: File resolved to [%s]", pszDstFile));
  3008. }
  3009. ppf->Release();
  3010. }
  3011. psl->Release();
  3012. }
  3013. }
  3014. /////////////////////////////////////////////////////////////////
  3015. //
  3016. // Non-blocking Message Box
  3017. //
  3018. INT_PTR MsgBox2DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3019. {
  3020. BOOL fHandled = FALSE;
  3021. CAppletWindow *pWindow;
  3022. switch (uMsg)
  3023. {
  3024. case WM_INITDIALOG:
  3025. {
  3026. // get the text to display
  3027. LPTSTR pszText = (LPTSTR) lParam;
  3028. ASSERT(NULL != pszText && TEXT('\0') != *pszText);
  3029. // estimate how big the read-only edit control should be
  3030. HDC hdc = ::GetDC(hdlg);
  3031. if (NULL != hdc)
  3032. {
  3033. SIZE csEdit;
  3034. if (::GetTextExtentPoint32(hdc, pszText, ::lstrlen(pszText), &csEdit))
  3035. {
  3036. const ULONG c_nMarginX = 0;
  3037. const ULONG c_nMarginY = 10;
  3038. ULONG nCaptionHeight = ::GetSystemMetrics(SM_CYCAPTION);
  3039. ULONG nShift = nCaptionHeight * (s_cMsgBox2Dlg++ % 8);
  3040. // move the edit control
  3041. HWND hwndEdit = ::GetDlgItem(hdlg, IDE_MSGBOX2_TEXT);
  3042. POINT ptEdit;
  3043. ptEdit.x = c_nMarginX;
  3044. ptEdit.y = c_nMarginY + (c_nMarginY >> 1);
  3045. csEdit.cx += c_nMarginX << 1;
  3046. csEdit.cy += c_nMarginY << 1;
  3047. ::MoveWindow(hwndEdit, ptEdit.x, ptEdit.y, csEdit.cx, csEdit.cy, FALSE);
  3048. // move the ok button
  3049. HWND hwndOK = ::GetDlgItem(hdlg, IDOK);
  3050. RECT rcOK;
  3051. ::GetWindowRect(hwndOK, &rcOK);
  3052. SIZE csOK;
  3053. csOK.cx = rcOK.right - rcOK.left;
  3054. csOK.cy = rcOK.bottom - rcOK.top;
  3055. POINT ptOK;
  3056. ptOK.x = ptEdit.x + (csEdit.cx >> 1) - (csOK.cx >> 1);
  3057. ptOK.y = ptEdit.y + csEdit.cy + (c_nMarginY >> 1);
  3058. ::MoveWindow(hwndOK, ptOK.x, ptOK.y, csOK.cx, csOK.cy, FALSE);
  3059. // adjust all the windows
  3060. RECT rcDlg, rcClient;
  3061. ::GetWindowRect(hdlg, &rcDlg);
  3062. POINT ptDlg;
  3063. ptDlg.x = rcDlg.left + nShift;
  3064. ptDlg.y = rcDlg.top + nShift;
  3065. ::GetClientRect(hdlg, &rcClient);
  3066. SIZE csDlg;
  3067. csDlg.cx = (rcDlg.right - rcDlg.left) - (rcClient.right - rcClient.left);
  3068. csDlg.cy = (rcDlg.bottom - rcDlg.top) - (rcClient.bottom - rcClient.top);
  3069. csDlg.cx += ptEdit.x + csEdit.cx + c_nMarginX;
  3070. csDlg.cy += ptOK.y + csOK.cy + c_nMarginY;
  3071. ::MoveWindow(hdlg, ptDlg.x, ptDlg.y, csDlg.cx, csDlg.cy, FALSE);
  3072. }
  3073. ::ReleaseDC(hdlg, hdc);
  3074. }
  3075. ::SetDlgItemText(hdlg, IDE_MSGBOX2_TEXT, pszText);
  3076. delete [] pszText; // free the display text
  3077. fHandled = TRUE;
  3078. }
  3079. break;
  3080. case WM_COMMAND:
  3081. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3082. {
  3083. case IDOK:
  3084. case IDCANCEL:
  3085. case IDCLOSE:
  3086. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  3087. {
  3088. case BN_CLICKED:
  3089. pWindow = (CAppletWindow*)::GetWindowLongPtr(hdlg, DWLP_USER);
  3090. ASSERT (pWindow);
  3091. if (pWindow)
  3092. {
  3093. pWindow->RemoveErrorDlg(hdlg);
  3094. pWindow->FocusNextErrorDlg();
  3095. }
  3096. ::EndDialog(hdlg, IDOK);
  3097. break;
  3098. }
  3099. break;
  3100. }
  3101. fHandled = TRUE;
  3102. break;
  3103. }
  3104. return(fHandled);
  3105. }
  3106. BOOL MsgBox2(CAppletWindow *pWindow, LPTSTR pszText)
  3107. {
  3108. BOOL fRet = FALSE;
  3109. ULONG cch = ::lstrlen(pszText) + 1;
  3110. DBG_SAVE_FILE_LINE
  3111. LPTSTR pszNew = new TCHAR[cch];
  3112. if (NULL != pszNew)
  3113. {
  3114. ::CopyMemory(pszNew, pszText, cch);
  3115. HWND hwndDlg = ::CreateDialogParam(g_hDllInst, MAKEINTRESOURCE(IDD_MSGBOX2),
  3116. pWindow->GetHwnd(), MsgBox2DlgProc, (LPARAM) pszNew);
  3117. ASSERT(NULL != hwndDlg);
  3118. if (NULL != hwndDlg)
  3119. {
  3120. ::ShowWindow(hwndDlg, SW_SHOWNORMAL);
  3121. fRet = TRUE;
  3122. ::SetForegroundWindow(hwndDlg);
  3123. ::SetWindowLongPtr(hwndDlg, DWLP_USER, (LPARAM)pWindow);
  3124. pWindow->AddErrorDlg(hwndDlg);
  3125. }
  3126. }
  3127. else
  3128. {
  3129. ERROR_OUT(("FT::MsgBox2: cannot duplicate string [%s]", pszText));
  3130. }
  3131. return fRet;
  3132. }
  3133. /////////////////////////////////////////////////////////////////
  3134. //
  3135. // Receive Folder Management
  3136. //
  3137. HRESULT GetRecvFolder(LPTSTR pszInFldr, LPTSTR pszOutFldr)
  3138. {
  3139. LPTSTR psz;
  3140. TCHAR szPath[MAX_PATH];
  3141. RegEntry reFileXfer(FILEXFER_KEY, HKEY_CURRENT_USER);
  3142. if (NULL == pszInFldr)
  3143. {
  3144. // NULL directory specified - get info from registry or use default
  3145. psz = reFileXfer.GetString(REGVAL_FILEXFER_PATH);
  3146. if (NULL != psz && TEXT('\0') != *psz)
  3147. {
  3148. ::lstrcpyn(szPath, psz, count_of(szPath));
  3149. }
  3150. else
  3151. {
  3152. TCHAR szInstallDir[MAX_PATH];
  3153. ::GetInstallDirectory(szInstallDir);
  3154. ::MyLoadString(IDS_RECDIR_DEFAULT, szPath, szInstallDir);
  3155. }
  3156. pszInFldr = szPath;
  3157. }
  3158. ::lstrcpyn(pszOutFldr, pszInFldr, MAX_PATH);
  3159. // Remove trailing backslash, if any
  3160. for (psz = pszOutFldr; *psz; psz = CharNext(psz))
  3161. {
  3162. if ('\\' == *psz && '\0' == *CharNext(psz))
  3163. {
  3164. *psz = '\0';
  3165. break;
  3166. }
  3167. }
  3168. HRESULT hr;
  3169. if (!FEnsureDirExists(pszOutFldr))
  3170. {
  3171. WARNING_OUT(("ChangeRecDir: FT directory is invalid [%s]", pszOutFldr));
  3172. hr = E_FAIL;
  3173. }
  3174. else
  3175. {
  3176. // update the registry
  3177. reFileXfer.SetValue(REGVAL_FILEXFER_PATH, pszOutFldr);
  3178. hr = S_OK;
  3179. }
  3180. return hr;
  3181. }
  3182. void EnsureTrailingSlash(LPTSTR psz)
  3183. {
  3184. LPTSTR psz2;
  3185. // Make sure the directory name has a trailing '\'
  3186. while (TEXT('\0') != *psz)
  3187. {
  3188. psz2 = ::CharNext(psz);
  3189. if (TEXT('\\') == *psz && TEXT('\0') == *psz2)
  3190. {
  3191. // The path already ends with a backslash
  3192. return;
  3193. }
  3194. psz = psz2;
  3195. }
  3196. // Append a trailing backslash
  3197. *psz = TEXT('\\');
  3198. psz = ::CharNext(psz);
  3199. *psz = TEXT('\0');
  3200. }
  3201.