// File: ftui.h #include "mbftpch.h" #include #include #include "ftui.h" #include "version.h" #include #include static ULONG s_cMsgBox2Dlg = 0; // for alignment static ULONG s_cRecvDlg = 0; // for alignment static ULONG s_sort = -1; ULONG _GetPercent(ULONG cbTotalRecvSize , ULONG cbFileSize); TCHAR s_szMSFT[64]; static TCHAR s_szScratchText[MAX_PATH*2]; static const TCHAR s_cszHtmlHelpFile[] = TEXT("conf.chm"); #define MAX_FILE_NAME_LENGTH 30 LRESULT CALLBACK FtMainWndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK RecvDlgProc(HWND, UINT, WPARAM, LPARAM); LPTSTR PathNameToFileName(LPTSTR pszPathName); HRESULT GetRecvFolder(LPTSTR pszInFldr, LPTSTR pszOutFldr); BOOL MsgBox2(CAppletWindow *pWindow, LPTSTR pszText); void ShiftFocus(HWND hwndTop, BOOL bForward); void EnsureTrailingSlash(LPTSTR); int MyLoadString(UINT idStr); int MyLoadString(UINT idStr, LPTSTR pszDstStr); int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement); int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, LPTSTR pszElement2); __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement) { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement); } __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement1, UINT_PTR nElement2) { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement1, (LPTSTR) nElement2); } int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, UINT_PTR nElement2) { return MyLoadString(idStr, pszDstStr, pszElement1, (LPTSTR) nElement2); } __inline int MyLoadString(UINT idStr, LPTSTR pszDstStr, UINT_PTR nElement1, LPTSTR pszElement2) { return MyLoadString(idStr, pszDstStr, (LPTSTR) nElement1, pszElement2); } #define count_of(array) (sizeof(array) / sizeof(array[0])) void OnChangeFolder(void); BOOL FBrowseForFolder(LPTSTR pszFolder, UINT cchMax, LPCTSTR pszTitle); extern BOOL g_fShutdownByT120; void OPT_GetFTWndPosition(RECT *pRect) { int iLeft, iTop, iRight, iBottom; RegEntry reWnd( FILEXFER_KEY, HKEY_CURRENT_USER); iLeft = reWnd.GetNumber(REGVAL_WINDOW_XPOS, 0); iTop = reWnd.GetNumber(REGVAL_WINDOW_YPOS, 0); iRight = reWnd.GetNumber(REGVAL_WINDOW_WIDTH, 0) + iLeft; iBottom = reWnd.GetNumber(REGVAL_WINDOW_HEIGHT, 0) + iTop; // If it was empty, use the new rect if (!(iBottom || iTop || iLeft || iRight)) { return; } // Make sure that the window rectangle is (at least partially) on // screen, and not too large. First get the screen size int screenWidth = ::GetSystemMetrics(SM_CXSCREEN); int screenHeight = ::GetSystemMetrics(SM_CYSCREEN); // Check the window size if ((iRight - iLeft) > screenWidth) { iRight = iLeft + screenWidth; } if ((iBottom - iTop) > screenHeight) { iTop = screenHeight; } // Check the window position if (iLeft >= screenWidth) { // Off screen to the right - keep the width the same iLeft = screenWidth - (iRight - iLeft); iRight = screenWidth; } if (iRight < 0) { // Off screen to the left - keep the width the same iRight = iRight - iLeft; iLeft = 0; } if (iTop >= screenHeight) { // Off screen to the bottom - keep the height the same iTop = screenHeight - (iBottom - iTop); iBottom = screenHeight; } if (iBottom < 0) { // Off screen to the top - keep the height the same iBottom = (iBottom - iTop); iTop = 0; } pRect->left = iLeft; pRect->top = iTop; pRect->right = iRight - iLeft; pRect->bottom = iBottom - iTop; } CAppletWindow::CAppletWindow(BOOL fNoUI, HRESULT *pHr) : CRefCount(MAKE_STAMP_ID('F','T','U','I')), m_hwndMainUI(NULL), m_pToolbar(NULL), m_hwndListView(NULL), m_hwndStatusBar(NULL), m_pEngine(NULL), m_fInFileOpenDialog(FALSE), m_pCurrSendFileInfo(NULL), m_nCurrSendEventHandle(0), m_hIconInCall(NULL), m_hIconNotInCall(NULL) { m_UIMode = fNoUI ? FTUIMODE_NOUI : FTUIMODE_UIHIDDEN; ::GetCurrentDirectory(MAX_PATH, m_szDefaultDir); *pHr = E_FAIL; // failure, at default // create window class name ::wsprintf(&m_szFtMainWndClassName[0], TEXT("FTMainWnd%0X_%0X"), ::GetCurrentProcessId(), ::GetTickCount()); ASSERT(::lstrlenA(&m_szFtMainWndClassName[0]) < sizeof(m_szFtMainWndClassName)); // register window class first WNDCLASS wc; ::ZeroMemory(&wc, sizeof(wc)); //wc.style = 0; wc.lpfnWndProc = FtMainWndProc; // wc.cbClsExtra = 0; // wc.cbWndExtra = 0; wc.hInstance = g_hDllInst; wc.hIcon = ::LoadIcon(g_hDllInst, MAKEINTRESOURCE(IDI_FILE_TRANSFER)); // wc.hbrBackground = NULL; // wc.hCursor = NULL; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_FT); wc.lpszClassName = m_szFtMainWndClassName; if (::RegisterClass(&wc)) { ::MyLoadString(IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION); m_hwndMainUI = ::CreateWindow( m_szFtMainWndClassName, s_szScratchText, WS_OVERLAPPEDWINDOW | WS_TABSTOP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, // no parent window NULL, // use class' menu g_hDllInst, (LPVOID) this); // this window is for this object if (NULL != m_hwndMainUI) { // success *pHr = S_OK; } } m_hAccel = ::LoadAccelerators(g_hDllInst, MAKEINTRESOURCE(RECVDLGACCELTABLE)); m_hLVAccel = ::LoadAccelerators(g_hDllInst, MAKEINTRESOURCE(LISTVIEWACCELTABLE)); } CAppletWindow::~CAppletWindow(void) { ASSERT(NULL == m_hwndMainUI); ::UnregisterClass(m_szFtMainWndClassName, g_hDllInst); ClearSendInfo(FALSE); ClearRecvInfo(); if (m_hIconInCall) ::DestroyIcon(m_hIconInCall); if (m_hIconNotInCall) ::DestroyIcon(m_hIconNotInCall); ASSERT(NULL == m_pEngine); } BOOL CAppletWindow::FilterMessage(MSG *pMsg) { CRecvDlg *pRecvDlg; HWND hwndError; HWND hwndForeground = ::GetForegroundWindow(); m_RecvDlgList.Reset(); while (NULL != (pRecvDlg = m_RecvDlgList.Iterate())) { if (::IsDialogMessage(pRecvDlg->GetHwnd(), pMsg)) { return TRUE; } } if (hwndForeground == m_hwndMainUI) { BOOL fRet = ::TranslateAccelerator(m_hwndMainUI, m_hLVAccel, pMsg); return fRet; } m_ErrorDlgList.Reset(); while (NULL != (hwndError = m_ErrorDlgList.Iterate())) { if (::IsDialogMessage(hwndError, pMsg)) { return TRUE; } } return FALSE; } BOOL CAppletWindow::QueryShutdown(BOOL fShutdown) { if (m_UIMode != FTUIMODE_NOUI) { int id = 0; if (m_nCurrSendEventHandle) { id = (fShutdown)?IDS_QUERY_SEND_SHUTDOWN:IDS_QUERY_SEND_HANGUP; } else if (IsReceiving()) { id = (fShutdown)?IDS_QUERY_RECVING_SHUTDOWN:IDS_QUERY_RECVING_HANGUP; } if (id) { // could be in any thread TCHAR szText[MAX_PATH]; if (::MyLoadString(id, szText)) { if (IDNO == ::MessageBox(NULL, szText, s_szMSFT, MB_TASKMODAL | MB_YESNO | MB_ICONQUESTION)) { return FALSE; } } } } if (m_nCurrSendEventHandle) { OnStopSending(); } if (IsReceiving()) { CRecvDlg *pRecvDlg = NULL; m_RecvDlgList.Reset(); while (NULL != (pRecvDlg = m_RecvDlgList.Iterate())) { DBG_SAVE_FILE_LINE GetEngine()->SafePostMessage( new FileTransferControlMsg( pRecvDlg->GetEventHandle(), pRecvDlg->GetFileHandle(), NULL, NULL, FileTransferControlMsg::EnumAbortFile)); } } return TRUE; } void CAppletWindow::RegisterEngine(MBFTEngine *pEngine) { ASSERT(NULL == m_pEngine); pEngine->AddRef(); m_pEngine = pEngine; UpdateUI(); } void CAppletWindow::UnregisterEngine(void) { if (NULL != m_pEngine) { m_pEngine->Release(); m_pEngine = NULL; ClearSendInfo(TRUE); ClearRecvInfo(); } if (UIHidden()) { // exit ::PostMessage(m_hwndMainUI, WM_CLOSE, 0, 0); } else { UpdateUI(); // don't quit } } void CAppletWindow::RegisterRecvDlg(CRecvDlg *pDlg) { m_RecvDlgList.Prepend(pDlg); } void CAppletWindow::UnregisterRecvDlg(CRecvDlg *pDlg) { m_RecvDlgList.Remove(pDlg); FocusNextRecvDlg(); } BOOL CAppletWindow::IsReceiving(void) { BOOL fRet = FALSE; CRecvDlg *pDlg; CUiRecvFileInfo *pRecvFile; m_RecvDlgList.Reset(); while (NULL != (pDlg = m_RecvDlgList.Iterate())) { pRecvFile = pDlg->GetRecvFileInfo(); if (pRecvFile && (pRecvFile->GetTotalRecvSize() < pRecvFile->GetSize())) { fRet = TRUE; break; } } return fRet; } CRecvDlg * CAppletWindow::FindDlgByHandles(MBFTEVENTHANDLE nEventHandle, MBFTFILEHANDLE nFileHandle) { CRecvDlg *pDlg; m_RecvDlgList.Reset(); while (NULL != (pDlg = m_RecvDlgList.Iterate())) { if (nEventHandle == pDlg->GetEventHandle() && nFileHandle == pDlg->GetFileHandle()) { break; } } return pDlg; } ///////////////////////////////////////////////////////////////// // // WM_CREATE // LRESULT OnCreate(HWND hwnd, WPARAM wParam, LPARAM lParam) { CREATESTRUCT *p = (CREATESTRUCT *) lParam; CAppletWindow *pWindow = (CAppletWindow *) p->lpCreateParams; ASSERT(NULL != pWindow); ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) p->lpCreateParams); pWindow->SetHwnd(hwnd); ::InitCommonControls(); pWindow->CreateToolBar(); pWindow->CreateStatusBar(); pWindow->CreateListView(); ::DragAcceptFiles(hwnd, g_fSendAllowed); // resize the window MINMAXINFO mmi; ::ZeroMemory(&mmi, sizeof(mmi)); pWindow->OnGetMinMaxInfo(&mmi); RECT rcUI; ::GetWindowRect(pWindow->GetHwnd(), &rcUI); rcUI.right = mmi.ptMinTrackSize.x; rcUI.bottom = mmi.ptMinTrackSize.y + 30; OPT_GetFTWndPosition(&rcUI); ::MoveWindow(pWindow->GetHwnd(), rcUI.left, rcUI.top, rcUI.right, rcUI.bottom, TRUE); pWindow->UpdateUI(); #if defined(TEST_PLUGABLE) && defined(_DEBUG) ::OnPluggableBegin(hwnd); #endif return 0; } enum { TB_IDX_ADD_FILES = 0, TB_IDX_REMOVE_FILES, TB_IDX_BREAK_1, TB_IDX_IDM_SEND_ALL, TB_IDX_IDM_SEND_ONE, TB_IDX_IDM_STOP_SENDING, TB_IDX_BREAK_2, TB_IDX_IDM_OPEN_RECV_FOLDER, TB_IDX_IDM_CHANGE_FOLDER, TB_IDX_BREAK_3, TB_IDX_IDM_HELP, }; static Buttons buttons [] = { {IDB_ADDFILES, CBitmapButton::Disabled+1, 1, IDM_ADD_FILES, (LPCSTR)IDS_MENU_ADD_FILES,}, {IDB_REMOVEFILES, CBitmapButton::Disabled+1, 1, IDM_REMOVE_FILES, (LPCSTR)IDS_MENU_REMOVE_FILES,}, {0, 0, 0, 0, 0,}, {IDB_SENDFILE, CBitmapButton::Disabled+1, 1, IDM_SEND_ALL, (LPCSTR)IDS_MENU_SEND_ALL,}, {IDB_STOPSEND, CBitmapButton::Disabled+1, 1, IDM_STOP_SENDING, (LPCSTR)IDS_MENU_STOP_SENDING,}, {0, 0, 0, 0, 0,}, {IDB_FOLDER, CBitmapButton::Disabled+1, 1, IDM_OPEN_RECV_FOLDER, (LPCSTR)IDS_MENU_OPEN_RECV_FOLDER,}, {0, 0, 0, 0, 0}, }; BOOL CAppletWindow::CreateToolBar(void) { DBG_SAVE_FILE_LINE m_pToolbar = new CComboToolbar(); if (m_pToolbar) { m_pToolbar->Create(m_hwndMainUI, &buttons[0], count_of(buttons), this); m_pToolbar->Release(); return TRUE; } return FALSE; } BOOL CAppletWindow::CreateStatusBar(void) { m_hwndStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, // status bar class TEXT(""), // no default text WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, 0, 0, 0, 0, m_hwndMainUI, (HMENU) IDC_STATUS_BAR, g_hDllInst, NULL); ASSERT(NULL != m_hwndStatusBar); if (NULL != m_hwndStatusBar) { // Load Call Icons m_hIconInCall = (HICON) ::LoadImage(g_hDllInst, MAKEINTRESOURCE(IDI_INCALL), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); m_hIconNotInCall = (HICON) ::LoadImage(g_hDllInst, MAKEINTRESOURCE(IDI_NOT_INCALL), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); if (CreateProgressBar()) { return TRUE; } } return FALSE; } BOOL CAppletWindow::CreateProgressBar(void) { RECT rcl; GetClientRect(m_hwndStatusBar, &rcl); m_hwndProgressBar = ::CreateWindowEx(0, PROGRESS_CLASS, TEXT(""), WS_CHILD | WS_VISIBLE | PBS_SMOOTH, rcl.right/2 + 2, 2, rcl.right - rcl.right/2 - 40, rcl.bottom - 8, m_hwndStatusBar, (HMENU)IDC_PROGRESS_BAR, g_hDllInst, NULL); if (m_hwndProgressBar) { ::SendMessage(m_hwndProgressBar, PBM_SETRANGE, 0L, MAKELONG(0, 100)); return TRUE; } return FALSE; } BOOL CAppletWindow::CreateListView(void) { // get the size and position of the main window RECT rcWindow, rcToolBar, rcStatusBar; SIZE szToolBar; ::GetClientRect(m_hwndMainUI, &rcWindow); m_pToolbar->GetDesiredSize(&szToolBar); ::GetWindowRect(m_hwndStatusBar, &rcStatusBar); ULONG x = 0; ULONG y = szToolBar.cy - 1; ULONG cx = rcWindow.right - rcWindow.left; ULONG cy = rcWindow.bottom - rcWindow.top - y - (rcStatusBar.bottom - rcStatusBar.top) + 1; // create the list view window m_hwndListView = ::CreateWindowEx(WS_EX_CLIENTEDGE, // sunken look WC_LISTVIEW , // list view class TEXT(""), // no default text WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT |WS_TABSTOP | LVS_AUTOARRANGE | WS_CLIPCHILDREN | LVS_SHOWSELALWAYS, x, y, cx, cy, m_hwndMainUI, (HMENU) IDC_LIST_VIEW, g_hDllInst, NULL); ASSERT(NULL != m_hwndListView); if (NULL != m_hwndListView) { // set extended list view styles DWORD dwExtStyle = ListView_GetExtendedListViewStyle(m_hwndListView); dwExtStyle |= (LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT); ListView_SetExtendedListViewStyle(m_hwndListView, dwExtStyle); // enable window only if we can send files ::EnableWindow(m_hwndListView, g_fSendAllowed); // set up the columns ULONG i; LVCOLUMN lvc; LVITEM lvi; TCHAR szText[64]; int iColumnSize[NUM_LIST_VIEW_COLUMNS] = {150, 80, 70, 130}; // listview column size // initialize the common part of the columns lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; // left-aligned column lvc.pszText = szText; // initialize columns one by one for (i = 0; i < NUM_LIST_VIEW_COLUMNS; i++) { lvc.iSubItem = i; ::LoadString(g_hDllInst, IDS_LV_FILE_NAME + i, szText, count_of(szText)); lvc.cx = iColumnSize[i]; int iRet = ListView_InsertColumn(m_hwndListView, lvc.iSubItem, &lvc); ASSERT(-1 != iRet); } return TRUE; } return FALSE; } BOOL CAppletWindow::DrawItem(LPDRAWITEMSTRUCT pdis) { ASSERT(pdis); if (NULL != (pdis->itemData)) { int nWidth = pdis->rcItem.right - pdis->rcItem.left; int nHeight = pdis->rcItem.bottom - pdis->rcItem.top; int nLeft = pdis->rcItem.left; int nTop = pdis->rcItem.top; int xSmIcon = ::GetSystemMetrics(SM_CXSMICON); int ySmIcon = ::GetSystemMetrics(SM_CYSMICON); if (nWidth > xSmIcon) { nLeft += (nWidth - xSmIcon) / 2 - 5; nWidth = xSmIcon; } if (nHeight > ySmIcon) { nTop += (nHeight - ySmIcon) / 2; nHeight = ySmIcon; } ::DrawIconEx( pdis->hDC, nLeft, nTop, (HICON) (pdis->itemData), nWidth, nHeight, 0, NULL, DI_NORMAL); } return TRUE; } void CAppletWindow::OnCommand(WORD wId, HWND hwndCtl, WORD codeNotify) { switch (wId) { case IDM_ADD_FILES: OnAddFiles(); UpdateUI(); break; case IDM_REMOVE_FILES: OnRemoveFiles(); UpdateUI(); break; case IDM_SEND_ALL: s_cMsgBox2Dlg = 0; SetSendMode(TRUE); OnSendAll(); UpdateUI(); break; case IDM_SEND_ONE: s_cMsgBox2Dlg = 0; SetSendMode(FALSE); OnSendOne(); UpdateUI(); break; case IDM_STOP_SENDING: OnStopSending(); UpdateUI(); break; case IDM_OPEN_RECV_FOLDER: OnOpenRecvFolder(); break; case IDM_CHANGE_FOLDER: OnChangeFolder(); break; case IDM_EXIT: OnExit(); break; case IDM_HELP: OnHelp(); break; case ID_NAV_TAB: ShiftFocus(m_hwndMainUI, TRUE); if(GetFocus() == m_hwndListView) { SetListViewFocus(); } break; case ID_NAV_SHIFT_TAB: ShiftFocus(m_hwndMainUI, FALSE); if(GetFocus() == m_hwndListView) { SetListViewFocus(); } break; case IDM_ABOUT: OnAbout(); break; default: WARNING_OUT(("FT::OnCommand: unknown command ID=%u", (UINT) wId)); break; } return; } ///////////////////////////////////////////////////////////////// // // WM_COMMAND // LRESULT OnCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (NULL != pWindow) { WORD wNotifyCode = GET_WM_COMMAND_CMD(wParam, lParam); // notification code WORD wID = GET_WM_COMMAND_ID(wParam, lParam); // item, control, or accelerator identifier HWND hwndCtl = (HWND) lParam; // handle of control pWindow->OnCommand(wID, hwndCtl, wNotifyCode); return 0; } else { WARNING_OUT((" CAppletWindow::OnCommand--Received unhandled window message.\n")); } return (DefWindowProc(hwnd, WM_COMMAND, wParam, lParam)); } // // OnAddFiles // UINT_PTR APIENTRY SendFileDlgHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (WM_INITDIALOG == uMsg) { hdlg = ::GetParent(hdlg); // Real dialog is this window's parent if (::MyLoadString(IDS_FILEDLG_SEND)) { ::SetDlgItemText(hdlg, IDOK, s_szScratchText); } } return 0; } void CAppletWindow::OnAddFiles(void) { TCHAR szTitle[MAX_PATH]; TCHAR szFilter[MAX_PATH]; TCHAR szDirSav[MAX_PATH]; TCHAR szSendDir[MAX_PATH]; // Load dialog title and filter strings if (::MyLoadString(IDS_FILEDLG_TITLE, szTitle) && ::MyLoadString(IDS_FILEDLG_FILTER, szFilter)) { // replace '|' to '\0' LPTSTR pszFltr = szFilter; while (TEXT('\0') != *pszFltr) { if (TEXT('|') == *pszFltr) { *pszFltr = TEXT('\0'); pszFltr++; // cannot use CharNext } else { pszFltr = ::CharNext(pszFltr); } } // only allow one "Select a file to send" dialog if (! m_fInFileOpenDialog) { m_fInFileOpenDialog = TRUE; // Allocate a really large buffer to hold the file list ULONG cbBufSize = 8192; DBG_SAVE_FILE_LINE LPTSTR pszBuffer = new TCHAR[cbBufSize]; if (NULL != pszBuffer) { *pszBuffer = TEXT('\0'); // start with null string OPENFILENAME ofn; ::ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hwndMainUI; ofn.hInstance = g_hDllInst; ofn.lpstrFilter = &szFilter[0]; ofn.nFilterIndex = 1L; // FUTURE: remember filter preference ofn.lpstrFile = pszBuffer; ofn.nMaxFile = cbBufSize - 1; // Number of TCHAR in pszFiles (not including NULL) ofn.lpstrTitle = &szTitle[0]; ofn.lpstrInitialDir = m_szDefaultDir; ofn.lpfnHook = SendFileDlgHookProc; ofn.Flags = OFN_ALLOWMULTISELECT | OFN_ENABLEHOOK | // OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER; // remember current directory ::ZeroMemory(szSendDir, sizeof(szSendDir)); ::GetCurrentDirectory(count_of(szDirSav), szDirSav); ::lstrcpyn(szSendDir, szDirSav, count_of(szSendDir)); if (::GetOpenFileName(&ofn)) { // if there is only a single file, the first string is the full path. // if there are more than one file, the first string is the directory path // and followed by a list of file names. terminated by double null // remember the working directory for next time ULONG cchDirPath; LPTSTR pszFileName; ULONG cchFile = ::lstrlen(ofn.lpstrFile); if (TEXT('\0') == ofn.lpstrFile[cchFile] && TEXT('\0') == ofn.lpstrFile[cchFile+1]) { // // only a single file // pszFileName = ::PathNameToFileName(ofn.lpstrFile); cchDirPath = (ULONG)(pszFileName - ofn.lpstrFile); if (cchDirPath) { cchDirPath--; // back to '\\' } ASSERT(TEXT('\\') == ofn.lpstrFile[cchDirPath]); ofn.lpstrFile[cchDirPath] = TEXT('\0'); } else { // // multiple files // cchDirPath = ::lstrlen(ofn.lpstrFile); pszFileName = ofn.lpstrFile + cchDirPath + 1; } ::lstrcpy(m_szDefaultDir, ofn.lpstrFile); EnsureTrailingSlash(m_szDefaultDir); ::ZeroMemory(szSendDir, sizeof(szSendDir)); ::CopyMemory(szSendDir, ofn.lpstrFile, cchDirPath * sizeof(TCHAR)); EnsureTrailingSlash(szSendDir); // set up the common portion of list view item LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); // lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; // iterate the file name while ('\0' != *pszFileName) { BOOL fRet; DBG_SAVE_FILE_LINE CUiSendFileInfo *pFileInfo = new CUiSendFileInfo(this, szSendDir, pszFileName, &fRet); if (NULL != pFileInfo && fRet) { // put it to the list view lvi.iItem = ListView_GetItemCount(m_hwndListView); lvi.iSubItem = 0; // we are responsible for storing the text to display lvi.pszText = LPSTR_TEXTCALLBACK; lvi.cchTextMax = MAX_PATH; lvi.lParam = (LPARAM) pFileInfo; int iRet = ListView_InsertItem(m_hwndListView, &lvi); ASSERT(-1 != iRet); // UpdateListView(pFileInfo); } else { delete pFileInfo; } // get to the next file name pszFileName += ::lstrlen(pszFileName) + 1; } // while } else { // err code for cancel is zero, which is ok. ASSERT(! ::CommDlgExtendedError()); } // restore old working directory ::SetCurrentDirectory(szDirSav); } delete [] pszBuffer; m_fInFileOpenDialog = FALSE; } else { // bring the active dialog to the front BringToFront(); } } // if LoadString } // // OnRemoveFiles // void CAppletWindow::OnRemoveFiles(void) { UINT nState; ULONG cItems = ListView_GetItemCount(m_hwndListView); LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_STATE; lvi.stateMask = LVIS_SELECTED; ULONG i = 0; while (i < cItems) { lvi.iItem = i; BOOL fRet = ListView_GetItem(m_hwndListView, &lvi); if (fRet && lvi.state & LVIS_SELECTED) { CUiSendFileInfo *pFileInfo = (CUiSendFileInfo *) lvi.lParam; if (pFileInfo == m_pCurrSendFileInfo) { OnStopSending(); ClearSendInfo(FALSE); } delete pFileInfo; fRet = ListView_DeleteItem(m_hwndListView, i); ASSERT(fRet); cItems--; ASSERT((ULONG) ListView_GetItemCount(m_hwndListView) == cItems); } else { i++; } } if (cItems > 0) // set focus to first remaining item { SetListViewFocus(); } } void CAppletWindow::OnRemoveAllFiles(void) { BOOL fRet; CUiSendFileInfo *pFileInfo; ULONG cItems = ListView_GetItemCount(m_hwndListView); LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM; for (ULONG i = 0; i < cItems; i++) { lvi.iItem = i; fRet = ListView_GetItem(m_hwndListView, &lvi); ASSERT(fRet); pFileInfo = (CUiSendFileInfo *) lvi.lParam; if (pFileInfo == m_pCurrSendFileInfo) { ClearSendInfo(FALSE); } delete pFileInfo; } fRet = ListView_DeleteAllItems(m_hwndListView); ASSERT(fRet); } void CAppletWindow::OnSendAll(void) { if ((NULL == m_pCurrSendFileInfo)&&(NULL != m_pEngine)) { CUiSendFileInfo *pFileInfo = ChooseFirstUnSentFile(); SendNow(pFileInfo); } } void CAppletWindow::OnSendOne(void) { if ((NULL == m_pCurrSendFileInfo)&&(NULL != m_pEngine)) { CUiSendFileInfo *pFileInfo = ChooseSelectedFile(); if (!pFileInfo) { pFileInfo = ChooseFirstUnSentFile(); } SendNow(pFileInfo); } } // // SendNow // BOOL CAppletWindow::SendNow(CUiSendFileInfo *pFileInfo) { BOOL fRet; if (NULL != pFileInfo) { // send this file now... m_pCurrSendFileInfo = pFileInfo; m_nCurrSendEventHandle = ::GetNewEventHandle(); pFileInfo->SetFileHandle(::GetNewFileHandle()); // duplicate full file name ULONG cbSize = ::lstrlen(pFileInfo->GetFullName()) + 1; DBG_SAVE_FILE_LINE LPTSTR pszFullName = new TCHAR[cbSize]; if (NULL != pszFullName) { ::CopyMemory(pszFullName, pFileInfo->GetFullName(), cbSize); DBG_SAVE_FILE_LINE if (S_OK == m_pEngine->SafePostMessage( new CreateSessionMsg(MBFT_PRIVATE_SEND_TYPE, m_nCurrSendEventHandle))) { int iSelect; MEMBER_ID nMemberID; iSelect = m_pToolbar->GetSelectedItem((LPARAM*)&nMemberID); if (0 == iSelect) { // Send to All DBG_SAVE_FILE_LINE if (S_OK == m_pEngine->SafePostMessage( new SubmitFileSendMsg(0, 0, pszFullName, pFileInfo->GetFileHandle(), m_nCurrSendEventHandle, FALSE))) { return TRUE; } else { ERROR_OUT(("CAppletWindow::SendNow: cannot create SubmitFileSendMsg")); } } else { // Send to one T120UserID uidRecv = GET_PEER_ID_FROM_MEMBER_ID(nMemberID); DBG_SAVE_FILE_LINE if (S_OK == m_pEngine->SafePostMessage( new SubmitFileSendMsg(uidRecv, 0, pszFullName, pFileInfo->GetFileHandle(), m_nCurrSendEventHandle, FALSE))) { return TRUE; } else { ERROR_OUT(("CAppletWindow::SendNow: cannot create SubmitFileSendMsg to 1")); } } } else { ERROR_OUT(("CAppletWindow::SendNow: cannot create CreateSessionMsg")); } delete [] pszFullName; } ClearSendInfo(TRUE); } return FALSE; } CUiSendFileInfo *CAppletWindow::ChooseFirstUnSentFile(void) { CUiSendFileInfo *pFileInfo = NULL; ULONG cItems = ListView_GetItemCount(m_hwndListView); if (cItems > 0) { // examine each item one by one LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM; for (ULONG i = 0; i < cItems; i++, pFileInfo = NULL) { lvi.iItem = i; BOOL fRet = ListView_GetItem(m_hwndListView, &lvi); ASSERT(fRet); pFileInfo = (CUiSendFileInfo *) lvi.lParam; // if file handle is not zero, then it has been sent if (! pFileInfo->GetFileHandle()) { break; } } } return pFileInfo; } CUiSendFileInfo *CAppletWindow::ChooseSelectedFile(void) { CUiSendFileInfo *pFileInfo = NULL; ULONG cItems = ListView_GetItemCount(m_hwndListView); LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_STATE; lvi.stateMask = LVIS_SELECTED; ULONG i = 0; while (i < cItems) { lvi.iItem = i; BOOL fRet = ListView_GetItem(m_hwndListView, &lvi); if (fRet && lvi.state & LVIS_SELECTED) { pFileInfo = (CUiSendFileInfo *) lvi.lParam; pFileInfo->SetErrorCode(iMBFT_OK); break; } else { i++; pFileInfo = NULL; } } return pFileInfo; } // // OnMenuSelect // void CAppletWindow::OnMenuSelect(UINT uiItemID, UINT uiFlags, HMENU hSysMenu) { UINT firstMenuId; UINT statusId; // // Work out the help ID for the menu item. We have to store this now // because when the user presses F1 from a menu item, we can't tell // which item it was. // if ((uiFlags & MF_POPUP) && (uiFlags & MF_SYSMENU)) { // System menu selected statusId = (m_pCurrSendFileInfo)?IDS_STBAR_SENDING_XYZ:IDS_STBAR_NOT_TRANSFERING; } else if (uiFlags & MF_POPUP) { // get popup menu handle and first item HMENU hPopup = ::GetSubMenu( hSysMenu, uiItemID ); firstMenuId = ::GetMenuItemID( hPopup, 0 ); switch(firstMenuId) { case IDM_ADD_FILES: statusId = IDS_MENU_FILE; break; case IDM_HELP: statusId = IDS_MENU_HELP; break; default: statusId = (m_pCurrSendFileInfo)?IDS_STBAR_SENDING_XYZ:IDS_STBAR_NOT_TRANSFERING; } } else { // A normal menu item has been selected statusId = uiItemID; } // Set the new help text TCHAR szStatus[256]; if (::LoadString(g_hDllInst, statusId, szStatus, 256)) { ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_TRANSFER_FILE, (LPARAM)szStatus); } } // // OnStopSending // void CAppletWindow::OnStopSending(void) { m_fSendALL = FALSE; if (m_nCurrSendEventHandle) { DBG_SAVE_FILE_LINE HRESULT hr = m_pEngine->SafePostMessage( new FileTransferControlMsg( m_nCurrSendEventHandle, m_pCurrSendFileInfo->GetFileHandle(), NULL, NULL, FileTransferControlMsg::EnumAbortFile)); ASSERT(hr == S_OK); } } // // OnOpenRecvFolder // void CAppletWindow::OnOpenRecvFolder(void) { TCHAR szRecvFolder[MAX_PATH]; while (1) { if (S_OK == ::GetRecvFolder(NULL, szRecvFolder)) { ::ShellExecute(NULL, NULL, szRecvFolder, NULL, NULL, SW_SHOWNORMAL); break; } else if (m_UIMode != FTUIMODE_NOUI) { ::MyLoadString(IDS_RECVDLG_DIRNOEXIST, s_szScratchText, szRecvFolder); if (IDYES == ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_YESNO)) { OnChangeFolder(); } else { break; } } } } // // OnChageFolder // void OnChangeFolder(void) { BOOL rc; TCHAR szPath[MAX_PATH]; ::GetRecvFolder(NULL, szPath); if (::lstrlen(szPath) > MAX_FILE_NAME_LENGTH) { LPTSTR psz = szPath; int i = MAX_FILE_NAME_LENGTH - 1; while (i) { psz = CharNext(psz); i--; } ::lstrcpy(psz, TEXT("...")); } ::MyLoadString(IDS_BROWSETITLE, s_szScratchText, szPath); if (FBrowseForFolder(szPath, CCHMAX(szPath), s_szScratchText)) { ::GetRecvFolder(szPath, szPath); } } // // OnExit // void CAppletWindow::OnExit(BOOL fNoQuery) { if ((g_pFileXferApplet->InConf() || g_pFileXferApplet->HasSDK()) && ! g_fShutdownByT120) { // There 2.x node inside the conference // hide the window ::ShowWindow(m_hwndMainUI, SW_HIDE); m_UIMode = g_fNoUI ? FTUIMODE_NOUI : FTUIMODE_UIHIDDEN; } else if (fNoQuery || QueryShutdown()) { #if defined(TEST_PLUGABLE) && defined(_DEBUG) ::OnPluggableEnd(); #endif MBFTEngine *pEngine = m_pEngine; ::T120_AppletStatus(APPLET_ID_FT, APPLET_CLOSING); if (NULL != m_pEngine) { GCCAppPermissionToEnrollInd Ind; ::ZeroMemory(&Ind, sizeof(Ind)); Ind.nConfID = m_pEngine->GetConfID(); Ind.fPermissionGranted = FALSE; m_pEngine->OnPermitToEnrollIndication(&Ind); UnregisterEngine(); } OnRemoveAllFiles(); ::SetWindowLongPtr(m_hwndMainUI, GWLP_USERDATA, 0); SaveWindowPosition(); HWND hwnd = m_hwndMainUI; m_hwndMainUI = NULL; ::DestroyWindow(hwnd); if (NULL != g_pFileXferApplet) { g_pFileXferApplet->UnregisterWindow(this); g_pFileXferApplet->UnregisterEngine(pEngine); } Release(); } } // // OnHelp // void CAppletWindow::OnHelp(void) { DebugEntry(CAppletWindow::OnHelp); ShowNmHelp(s_cszHtmlHelpFile); DebugExitVOID(CAppletWindow::OnHelp); } // // OnAbout // INT_PTR AboutDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL fHandled = FALSE; switch (uMsg) { case WM_INITDIALOG: { TCHAR szFormat[256]; TCHAR szVersion[512]; ::GetDlgItemText(hdlg, IDC_ABOUT_VERSION, szFormat, count_of(szFormat)); ::wsprintf(szVersion, szFormat, VER_PRODUCTRELEASE_STR, VER_PRODUCTVERSION_STR); ::SetDlgItemText(hdlg, IDC_ABOUT_VERSION, szVersion); fHandled = TRUE; } break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: case IDCANCEL: case IDCLOSE: switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case BN_CLICKED: ::EndDialog(hdlg, IDCANCEL); break; } break; } fHandled = TRUE; break; } return(fHandled); } void CAppletWindow::OnAbout(void) { ::DialogBoxParam(g_hDllInst, MAKEINTRESOURCE(IDD_ABOUTBOX), m_hwndMainUI, AboutDlgProc, 0); } BOOL FBrowseForFolder(LPTSTR pszFolder, UINT cchMax, LPCTSTR pszTitle) { LPITEMIDLIST pidlRoot; if(FAILED(SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DRIVES, &pidlRoot))) { return FALSE; } BROWSEINFO bi; ClearStruct(&bi); bi.hwndOwner = NULL; bi.lpszTitle = pszTitle; bi.ulFlags = BIF_RETURNONLYFSDIRS; bi.pidlRoot = pidlRoot; LPITEMIDLIST pidl = SHBrowseForFolder(&bi); BOOL fRet = (pidl != NULL); if (fRet) { ASSERT(cchMax >= MAX_PATH); SHGetPathFromIDList(pidl, pszFolder); ASSERT(lstrlen(pszFolder) < (int) cchMax); } // Get the shell's allocator to free PIDLs LPMALLOC lpMalloc; if (FAILED(SHGetMalloc(&lpMalloc)) && (NULL != lpMalloc)) { if (NULL != pidlRoot) { lpMalloc->Free(pidlRoot); } if (pidl) { lpMalloc->Free(pidl); } lpMalloc->Release(); } return fRet; } ///////////////////////////////////////////////////////////////// // // WM_NOTIFY // LRESULT OnNotify(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (NULL != pWindow) { switch (wParam) { case IDC_LIST_VIEW: pWindow->OnNotifyListView(lParam); break; default: if (TTN_NEEDTEXT == ((NMHDR *) lParam)->code) { // display the tool tip text TOOLTIPTEXT *pToolTipText = (TOOLTIPTEXT *) lParam; ULONG_PTR nID; // get id and hwnd if (pToolTipText->uFlags & TTF_IDISHWND) { // idFrom is actually the HWND of the tool nID = ::GetDlgCtrlID((HWND) pToolTipText->hdr.idFrom); } else { nID = pToolTipText->hdr.idFrom; } // give it to em pToolTipText->lpszText = MAKEINTRESOURCE(nID); pToolTipText->hinst = g_hDllInst; } break; } } return 0; } int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { CUiSendFileInfo *pFileInfo1 = (CUiSendFileInfo *) lParam1; CUiSendFileInfo *pFileInfo2 = (CUiSendFileInfo *) lParam2; int iResult; iResult = 0; // equal, at default switch (lParamSort) { case (IDS_LV_FILE_NAME - IDS_LV_FILE_NAME): iResult = lstrcmpi(pFileInfo1->GetName(), pFileInfo2->GetName()); break; case (IDS_LV_FILE_SIZE - IDS_LV_FILE_NAME): if (pFileInfo1->GetSize() > pFileInfo2->GetSize()) { iResult = 1; } else if (pFileInfo1->GetSize() < pFileInfo2->GetSize()) { iResult = -1; } break; case (IDS_LV_FILE_STATUS - IDS_LV_FILE_NAME): if ((pFileInfo1->GetTotalSend() == pFileInfo1->GetSize()) >( pFileInfo2->GetTotalSend() == pFileInfo2->GetSize())) { iResult = 1; } else if ((pFileInfo1->GetTotalSend() == pFileInfo1->GetSize()) < (pFileInfo2->GetTotalSend() == pFileInfo2->GetSize())) { iResult = -1; } break; case (IDS_LV_FILE_MODIFIED - IDS_LV_FILE_NAME): FILETIME fTime1 = pFileInfo1->GetLastWrite(); FILETIME fTime2 = pFileInfo2->GetLastWrite(); iResult = CompareFileTime(&fTime1,&fTime2); break; } return iResult*s_sort; } void CAppletWindow::OnNotifyListView(LPARAM lParam) { LV_DISPINFO *pDispInfo = (LV_DISPINFO *) lParam; NM_LISTVIEW *pLVN = (NM_LISTVIEW *) lParam; FILETIME ftFileTime; SYSTEMTIME stSystemTime; CUiSendFileInfo *pFileInfo; int iSize; TCHAR szBuffer[MAX_PATH]; switch (pLVN->hdr.code) { case LVN_GETDISPINFO: pFileInfo = (CUiSendFileInfo *) pDispInfo->item.lParam; ASSERT(NULL != pFileInfo); switch (pDispInfo->item.iSubItem) { case (IDS_LV_FILE_NAME - IDS_LV_FILE_NAME): pDispInfo->item.pszText = pFileInfo->GetName(); break; case (IDS_LV_FILE_SIZE - IDS_LV_FILE_NAME): ::wsprintf(szBuffer, TEXT("%u"), pFileInfo->GetSize()); iSize = GetNumberFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE, szBuffer, NULL, s_szScratchText, MAX_PATH); s_szScratchText[iSize - 4] = '\0'; // remove the trailing ".00" pDispInfo->item.pszText = s_szScratchText; break; case (IDS_LV_FILE_STATUS - IDS_LV_FILE_NAME): { ULONG cbTotalSend = pFileInfo->GetTotalSend(); ULONG cbFileSize = pFileInfo->GetSize(); s_szScratchText[0] = TEXT('\0'); switch (pFileInfo->GetErrorCode()) { case iMBFT_OK: case iMBFT_MULT_RECEIVER_ABORTED: if (!pFileInfo->GetFileHandle()) break; // handle == NULL, if cbTotalSend == 0, zero length file to be sent. if (cbTotalSend >= cbFileSize) { ::MyLoadString(IDS_LV_FILE_SENT); } else if (cbTotalSend) { if (m_pEngine) { ::MyLoadString(IDS_LV_FILE_SENDING); } else { ::MyLoadString(IDS_LV_FILE_CANCELED); } } break; case iMBFT_SENDER_ABORTED: case iMBFT_RECEIVER_ABORTED: case iMBFT_NO_MORE_FILES: ::MyLoadString(IDS_LV_FILE_CANCELED); break; default: ::MyLoadString(IDS_LV_FILE_FAILED); break; } pDispInfo->item.pszText = s_szScratchText; } break; case (IDS_LV_FILE_MODIFIED - IDS_LV_FILE_NAME): ftFileTime = pFileInfo->GetLastWrite(); FileTimeToSystemTime(&ftFileTime, &stSystemTime); iSize = GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &stSystemTime, "MM'/'dd'/'yyyy", s_szScratchText, MAX_PATH); GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &stSystemTime, " hh':'mm tt", &s_szScratchText[iSize - 1], MAX_PATH-iSize-1); pDispInfo->item.pszText = s_szScratchText; break; } break; case LVN_COLUMNCLICK: { s_sort = s_sort *(-1); BOOL fRet = ListView_SortItems(pLVN->hdr.hwndFrom, ListViewCompareProc, (LPARAM) pLVN->iSubItem); ASSERT(fRet); } break; } } ///////////////////////////////////////////////////////////////// // // WM_DROPFILES // LRESULT OnDropFiles(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); if (g_fSendAllowed) { return pWindow->OnDropFiles((HANDLE) wParam); } else { ::MyLoadString(IDS_MSGBOX_POL_PREVENT); ::MessageBox(pWindow->GetHwnd(), s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP); return 1; } } LRESULT CAppletWindow::OnDropFiles(HANDLE hDrop) { if (NULL != m_pEngine && m_pEngine->GetPeerCount() > 1) { HRESULT hr; // get the number of dropped files ULONG cFiles = ::DragQueryFile((HDROP) hDrop, 0xFFFFFFFF, NULL, 0); // set up the common portion of list view item LVITEM lvi; ::ZeroMemory(&lvi, sizeof(lvi)); // lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; // iterate on these files for (ULONG i = 0; i < cFiles; i++) { BOOL fRet; TCHAR szFile[MAX_PATH]; if (::DragQueryFile((HDROP) hDrop, i, szFile, count_of(szFile))) { DBG_SAVE_FILE_LINE CUiSendFileInfo *pFileInfo = new CUiSendFileInfo(this, NULL, szFile, &fRet); if (NULL != pFileInfo && fRet) { // put it to the list view lvi.iItem = ListView_GetItemCount(m_hwndListView); lvi.iSubItem = 0; // we are responsible for storing the text to display lvi.pszText = LPSTR_TEXTCALLBACK; lvi.cchTextMax = MAX_PATH; lvi.lParam = (LPARAM) pFileInfo; int iRet = ListView_InsertItem(m_hwndListView, &lvi); ASSERT(-1 != iRet); // UpdateListView(pFileInfo); } else { // BUGBUG: we should pop up some error message box here! ::MyLoadString(IDS_INVALID_FILENAME, s_szScratchText, szFile); ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP); delete pFileInfo; } } } ::DragFinish((HDROP) hDrop); SetForegroundWindow(m_hwndMainUI); UpdateUI(); return 0; } ::MyLoadString(IDS_MSGBOX_NO_CONF); ::SetForegroundWindow(m_hwndMainUI); ::MessageBox(m_hwndMainUI, s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP); return 1; } ///////////////////////////////////////////////////////////////// // // WM_CONTEXTMENU // LRESULT OnContextMenu(HWND hwnd, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); if ((WPARAM) pWindow->GetHwnd() == wParam) { // BUGBUG use TrackPopupMenu to show context sensitive menu pWindow->OnContextMenuForMainUI(lParam); } else if ((WPARAM) pWindow->GetListView() == wParam) { // BUGBUG use TrackPopupMenu to show context sensitive menu pWindow->OnContextMenuForListView(lParam); } else { rc = 1; } return rc; } enum { MENU_IDX_ADD_FILES, MENU_IDX_REMOVE_FILES, MENU_IDX_BREAK_1, MENU_IDX_SEND_ALL, MENU_IDX_SEND_ONE, MENU_IDX_STOP_SENDING, MENU_IDX_BREAK_2, MENU_IDX_OPEN_RECV_FOLDER, }; static UI_MENU_INFO s_aMenuInfo[] = { { IDS_MENU_ADD_FILES, IDM_ADD_FILES, MF_ENABLED | MF_STRING }, { IDS_MENU_REMOVE_FILES, IDM_REMOVE_FILES, MF_ENABLED | MF_STRING }, { 0, 0, MF_SEPARATOR}, // menu break { IDS_MENU_SEND_ALL, IDM_SEND_ALL, MF_ENABLED | MF_STRING }, { IDS_MENU_SEND_ONE, IDM_SEND_ONE, MF_ENABLED | MF_STRING }, { IDS_MENU_STOP_SENDING, IDM_STOP_SENDING, MF_ENABLED | MF_STRING }, { 0, 0, MF_SEPARATOR}, // menu break { IDS_MENU_OPEN_RECV_FOLDER, IDM_OPEN_RECV_FOLDER, MF_ENABLED | MF_STRING }, { IDS_MENU_CHANGE_FOLDER, IDM_CHANGE_FOLDER, MF_ENABLED | MF_STRING }, { 0, 0, MF_SEPARATOR }, // menu break { IDS_MENU_EXIT, IDM_EXIT, MF_ENABLED | MF_STRING }, }; void CAppletWindow::SetContextMenuStates(void) { if (g_fSendAllowed) { BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1); s_aMenuInfo[MENU_IDX_ADD_FILES].nFlags = fMoreThanOne ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING); ULONG cItems = ListView_GetItemCount(m_hwndListView); s_aMenuInfo[MENU_IDX_REMOVE_FILES].nFlags = cItems ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_SEND_ALL].nFlags = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_SEND_ONE].nFlags = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(FALSE)) ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_STOP_SENDING].nFlags = m_nCurrSendEventHandle ? (MF_ENABLED | MF_STRING) : (MF_GRAYED | MF_STRING); } else { s_aMenuInfo[MENU_IDX_ADD_FILES].nFlags =(MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_REMOVE_FILES].nFlags =(MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_SEND_ALL].nFlags = (MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_SEND_ONE].nFlags = (MF_GRAYED | MF_STRING); s_aMenuInfo[MENU_IDX_STOP_SENDING].nFlags = (MF_GRAYED | MF_STRING); } } void CAppletWindow::OnContextMenuForMainUI(LPARAM lParam) { SetContextMenuStates(); CreateMenu(lParam, count_of(s_aMenuInfo), &s_aMenuInfo[0]); } void CAppletWindow::OnContextMenuForListView(LPARAM lParam) { SetContextMenuStates(); CreateMenu(lParam, 6, &s_aMenuInfo[0]); } void CAppletWindow::CreateMenu(LPARAM lParam, ULONG cItems, UI_MENU_INFO aMenuInfo[]) { HMENU hMenu = ::CreatePopupMenu(); if (NULL != hMenu) { for (ULONG i = 0; i < cItems; i++) { if (aMenuInfo[i].idCommand) { if (::MyLoadString(aMenuInfo[i].idString)) { ::AppendMenu(hMenu, aMenuInfo[i].nFlags, aMenuInfo[i].idCommand, s_szScratchText); } } else { ::AppendMenu(hMenu, aMenuInfo[i].nFlags, 0, 0); } } ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, // reserved, must be zero m_hwndMainUI, NULL); // ignore } } ///////////////////////////////////////////////////////////////// // // WM_SIZE // LRESULT OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); pWindow->OnSizeToolBar(); pWindow->OnSizeStatusBar(); pWindow->OnSizeListView(); return 0; } void CAppletWindow::OnSizeToolBar(void) { RECT rcWindow; SIZE szToolBar; ::GetClientRect(m_hwndMainUI, &rcWindow); m_pToolbar->GetDesiredSize(&szToolBar); ULONG cx = rcWindow.right - rcWindow.left; ULONG cy = szToolBar.cy;; ULONG x = 0; ULONG y = 0; ::MoveWindow(m_pToolbar->GetWindow(), x, y, cx, cy, TRUE); } void CAppletWindow::OnSizeStatusBar(void) { RECT rcWindow, rcStatusBar; ::GetClientRect(m_hwndMainUI, &rcWindow); ::GetWindowRect(m_hwndStatusBar, &rcStatusBar); ULONG cx = rcWindow.right - rcWindow.left; ULONG cy = rcStatusBar.bottom - rcStatusBar.top; ULONG x = 0; ULONG y = rcWindow.bottom - cy; ::MoveWindow(m_hwndStatusBar, x, y, cx, cy, TRUE); ::MoveWindow(m_hwndProgressBar, x + cx/2, y, cx/2 - 40, cy, TRUE); int aWidths[NUM_STATUS_BAR_PARTS]; aWidths[0] = cx / 2; // conference state aWidths[1] = cx - 40; // transfer name aWidths[2] = -1; // transfer percentage ASSERT(3 == NUM_STATUS_BAR_PARTS); ::SendMessage(m_hwndStatusBar, SB_SETPARTS, NUM_STATUS_BAR_PARTS, (LPARAM) &aWidths[0]); } void CAppletWindow::OnSizeListView(void) { // get the size and position of the main window RECT rcWindow, rcToolBar, rcStatusBar; SIZE szToolBar; ::GetClientRect(m_hwndMainUI, &rcWindow); m_pToolbar->GetDesiredSize(&szToolBar); ::GetWindowRect(m_hwndStatusBar, &rcStatusBar); ULONG x = 0; ULONG y = szToolBar.cy - 1; ULONG cx = rcWindow.right - rcWindow.left; ULONG cy = rcWindow.bottom - rcWindow.top - y - (rcStatusBar.bottom - rcStatusBar.top) + 1; ::MoveWindow(m_hwndListView, x, y, cx, cy, TRUE); } ///////////////////////////////////////////////////////////////// // // WM_HELP // LRESULT OnHelp(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); pWindow->OnHelp(); return 0; } ///////////////////////////////////////////////////////////////// // // WM_CLOSE // LRESULT OnClose(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); if (NULL != pWindow) { pWindow->OnExit(); } return 0; } ///////////////////////////////////////////////////////////////// // // WM_INITMENUPOPUP // /* LRESULT OnInitMenuPopup(HWND hwnd, WPARAM wParam, LPARAM lParam) { if (0 != HIWORD(lParam)) // System menu flag { HMENU hMenu = (HMENU) wParam; // handle of pop-up menu ::EnableMenuItem(hMenu, SC_MAXIMIZE, MF_GRAYED); ::EnableMenuItem(hMenu, SC_SIZE, MF_GRAYED); return 0; } return 1; } */ ///////////////////////////////////////////////////////////////// // // WM_MENUSELECT // LRESULT OnMenuSelect(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); if (NULL != pWindow) { pWindow->OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam), GET_WM_MENUSELECT_FLAGS(wParam, lParam), GET_WM_MENUSELECT_HMENU(wParam, lParam)); } return 0; } ///////////////////////////////////////////////////////////////// // // WM_INITMENUPOPUP // LRESULT OnGetMinMaxInfo(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (NULL != pWindow) { pWindow->OnGetMinMaxInfo((LPMINMAXINFO) lParam); return 0; } return 1; } void CAppletWindow::OnGetMinMaxInfo(LPMINMAXINFO pMMI) { static BOOL s_fEnterBefore = FALSE; static SIZE s_csFrame; static SIZE s_csSeparator; static SIZE s_csScrollBars; static SIZE s_csToolBar; static SIZE s_csStatusBar; static SIZE s_csSum; if (! s_fEnterBefore) { s_fEnterBefore = TRUE; s_csFrame.cx = ::GetSystemMetrics(SM_CXSIZEFRAME); s_csFrame.cy = ::GetSystemMetrics(SM_CYSIZEFRAME); s_csSeparator.cx = ::GetSystemMetrics(SM_CXEDGE); s_csSeparator.cy = ::GetSystemMetrics(SM_CYEDGE); s_csScrollBars.cx = ::GetSystemMetrics(SM_CXVSCROLL); s_csScrollBars.cy = ::GetSystemMetrics(SM_CYHSCROLL); m_pToolbar->GetDesiredSize(&s_csToolBar); RECT rcStatusBar; ::GetWindowRect(m_hwndStatusBar, &rcStatusBar); s_csStatusBar.cx = rcStatusBar.right - rcStatusBar.left; s_csStatusBar.cy = rcStatusBar.bottom - rcStatusBar.top; s_csSum.cx = (s_csFrame.cx << 1); s_csSum.cy = (s_csFrame.cy << 1) + (s_csSeparator.cy << 3) + s_csToolBar.cy + (rcStatusBar.bottom - rcStatusBar.top) + ::GetSystemMetrics( SM_CYCAPTION ) + ::GetSystemMetrics( SM_CYMENU ); } RECT rcListViewItem; SIZE csListView; csListView.cx = 0; for (ULONG i = 0; i < NUM_LIST_VIEW_COLUMNS; i++) { csListView.cx += ListView_GetColumnWidth(m_hwndListView, i); } if (ListView_GetItemRect(m_hwndListView, 0, &rcListViewItem, LVIR_BOUNDS)) { csListView.cy = 20 + 3 * (rcListViewItem.bottom - rcListViewItem.top); } else { csListView.cy = 20 + 30; } // Set the minimum width and height of the window pMMI->ptMinTrackSize.x = s_csSum.cx + max(s_csToolBar.cx, csListView.cx); pMMI->ptMinTrackSize.y = s_csSum.cy + csListView.cy; // // Retrieves the size of the work area on the primary display monitor. The work // area is the portion of the screen not obscured by the system taskbar or by // application desktop toolbars // RECT rcWorkArea; ::SystemParametersInfo( SPI_GETWORKAREA, 0, (&rcWorkArea), NULL ); SIZE csMaxSize; csMaxSize.cx = rcWorkArea.right - rcWorkArea.left; csMaxSize.cy = rcWorkArea.bottom - rcWorkArea.top; pMMI->ptMaxPosition.x = 0; pMMI->ptMaxPosition.y = 0; pMMI->ptMaxSize.x = csMaxSize.cx; pMMI->ptMaxSize.y = csMaxSize.cy; pMMI->ptMaxTrackSize.x = csMaxSize.cx; pMMI->ptMaxTrackSize.y = csMaxSize.cy; } ///////////////////////////////////////////////////////////////// // // WM_QUERYENDSESSION // LRESULT OnQueryEndSession(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); ASSERT(NULL != pWindow); if (NULL != pWindow) { return pWindow->QueryShutdown(); // TRUE: ok to send session; FALSE, no. } return TRUE; // ok to end session } ///////////////////////////////////////////////////////////////// // // WM_ENDSESSION // LRESULT OnEndSession(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (wParam && NULL != pWindow) { pWindow->OnExit(TRUE); } return 0; } ///////////////////////////////////////////////////////////////// // // WM_DRAWITEM // LRESULT OnDrawItem(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (wParam && NULL != pWindow) { pWindow->DrawItem((DRAWITEMSTRUCT *)lParam); } return 0; } ///////////////////////////////////////////////////////////////// // // WM_SEND_NEXT // LRESULT OnSendNext(HWND hwnd, WPARAM wParam, LPARAM lParam) { CAppletWindow *pWindow = (CAppletWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (NULL != pWindow) { pWindow->OnSendAll(); pWindow->UpdateUI(); } return 0; } ///////////////////////////////////////////////////////////////// // // Main windows procedure // LRESULT CALLBACK FtMainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; switch (uMsg) { case WM_CREATE: rc = ::OnCreate(hwnd, wParam, lParam); break; case WM_COMMAND: rc = ::OnCommand(hwnd, wParam, lParam); break; case WM_NOTIFY: rc = ::OnNotify(hwnd, wParam, lParam); break; case WM_DROPFILES: rc = ::OnDropFiles(hwnd, wParam, lParam); break; case WM_CONTEXTMENU: rc = ::OnContextMenu(hwnd, wParam, lParam); break; case WM_SIZE: rc = ::OnSize(hwnd, wParam, lParam); break; case WM_HELP: rc = ::OnHelp(hwnd, wParam, lParam); break; case WM_DRAWITEM: rc = ::OnDrawItem(hwnd, wParam, lParam); break; case WM_CLOSE: rc = ::OnClose(hwnd, wParam, lParam); break; case WM_INITMENUPOPUP: // rc = ::OnInitMenuPopup(hwnd, wParam, lParam); break; case WM_MENUSELECT: rc = ::OnMenuSelect(hwnd, wParam, lParam); break; case WM_GETMINMAXINFO: rc = ::OnGetMinMaxInfo(hwnd, wParam, lParam); break; case WM_QUERYENDSESSION: rc = OnQueryEndSession(hwnd, wParam, lParam); break; case WM_ENDSESSION: rc = ::OnEndSession(hwnd, wParam, lParam); break; case WM_SEND_NEXT: rc = ::OnSendNext(hwnd, wParam, lParam); break; #if defined(TEST_PLUGABLE) && defined(_DEBUG) case WM_PLUGABLE_SOCKET: rc = ::OnPluggableSocket(hwnd, wParam, lParam); break; #endif default: rc = ::DefWindowProc(hwnd, uMsg, wParam, lParam); break; } return rc; } ///////////////////////////////////////////////////////////////// // // OnEngineNotify // void CAppletWindow::OnEngineNotify(MBFTMsg *pMsg) { BOOL fHeartBeat = FALSE; switch (pMsg->GetMsgType()) { case EnumFileOfferNotifyMsg: if (m_UIMode != FTUIMODE_NOUI) { HandleFileOfferNotify((FileOfferNotifyMsg *) pMsg); } break; case EnumFileTransmitMsg: if (m_UIMode != FTUIMODE_NOUI) { HandleProgressNotify((FileTransmitMsg *) pMsg); } fHeartBeat = TRUE; break; case EnumFileErrorMsg: if (m_UIMode != FTUIMODE_NOUI) { HandleErrorNotify((FileErrorMsg *) pMsg); } break; case EnumPeerMsg: HandlePeerNotification((PeerMsg *) pMsg); break; case EnumInitUnInitNotifyMsg: HandleInitUninitNotification((InitUnInitNotifyMsg *) pMsg); break; case EnumFileEventEndNotifyMsg: if (m_UIMode != FTUIMODE_NOUI) { HandleFileEventEndNotification((FileEventEndNotifyMsg *) pMsg); } break; default: ASSERT(0); break; } // switch } void CAppletWindow::HandleFileOfferNotify(FileOfferNotifyMsg *pMsg) { HRESULT hr = S_OK; if (g_fRecvAllowed) { DBG_SAVE_FILE_LINE CUiRecvFileInfo *pRecvFileInfo = new CUiRecvFileInfo(pMsg, &hr); if (NULL != pRecvFileInfo && S_OK == hr) { if (NULL != m_pEngine) { DBG_SAVE_FILE_LINE CRecvDlg *pDlg = new CRecvDlg(this, m_pEngine->GetConfID(), pMsg->m_NodeID, pMsg->m_EventHandle, pRecvFileInfo, &hr); if (NULL != pDlg && S_OK == hr) { DBG_SAVE_FILE_LINE if (S_OK == m_pEngine->SafePostMessage( new FileTransferControlMsg( pMsg->m_EventHandle, pMsg->m_hFile, pRecvFileInfo->GetRecvFolder(), pMsg->m_szFileName, FileTransferControlMsg::EnumAcceptFile))) { return; } else { ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot confirm file offer")); } } else { ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot allocate CRecvDlg, hr=0x%x", hr)); } delete pDlg; } else { ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: no file transfer engine")); } } else { ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot allocate CUiRecvFileInfo, hr=0x%x", hr)); } delete pRecvFileInfo; } else { DBG_SAVE_FILE_LINE if (S_OK != m_pEngine->SafePostMessage( new FileTransferControlMsg( pMsg->m_EventHandle, pMsg->m_hFile, NULL, pMsg->m_szFileName, FileTransferControlMsg::EnumRejectFile))) { ERROR_OUT(("CAppletWindow::HandleFileOfferNotify: cannot confirm file offer")); } } } void CAppletWindow::HandleProgressNotify(FileTransmitMsg *pMsg) { CRecvDlg *pDlg = NULL; MBFT_NOTIFICATION wMBFTCode = (MBFT_NOTIFICATION) pMsg->m_TransmitStatus; ULONG totalSent = 0; ULONG fileSize = 0; ULONG percentSent = 0; switch (wMBFTCode) { case iMBFT_FILE_SEND_BEGIN: // fall through... because the file start PDU can have data. case iMBFT_FILE_SEND_PROGRESS: if (NULL != m_pCurrSendFileInfo) { ASSERT(m_nCurrSendEventHandle == pMsg->m_EventHandle); ASSERT(m_pCurrSendFileInfo->GetFileHandle() == pMsg->m_hFile); ASSERT(m_pCurrSendFileInfo->GetSize() == pMsg->m_FileSize); fileSize = m_pCurrSendFileInfo->GetSize(); totalSent = m_pCurrSendFileInfo->GetTotalSend(); m_pCurrSendFileInfo->SetTotalSend(pMsg->m_BytesTransmitted); percentSent = _GetPercent(totalSent, fileSize)*10; if(m_pCurrSendFileInfo->GetPercentSent()!= percentSent || fileSize == totalSent) { UpdateListView(m_pCurrSendFileInfo); UpdateStatusBar(); m_pCurrSendFileInfo->SetPercentSent(percentSent); } } break; break; case iMBFT_FILE_SEND_END: if (NULL != m_pCurrSendFileInfo) { UpdateListView(m_pCurrSendFileInfo); UpdateStatusBar(); } break; case iMBFT_FILE_RECEIVE_BEGIN: // fall through... because the file start PDU can have data. case iMBFT_FILE_RECEIVE_PROGRESS: pDlg = FindDlgByHandles(pMsg->m_EventHandle, pMsg->m_hFile); if (NULL != pDlg) { pDlg->OnProgressUpdate(pMsg); } break; case iMBFT_FILE_RECEIVE_END: // doing nothing... break; default: ASSERT(0); break; } } void CAppletWindow::HandleErrorNotify(FileErrorMsg *pMsg) { MBFTFILEHANDLE nFileHandle = pMsg->m_hFile; if(LOWORD(nFileHandle) == LOWORD(_iMBFT_PROSHARE_ALL_FILES)) { nFileHandle = _iMBFT_PROSHARE_ALL_FILES; } if (m_nCurrSendEventHandle == pMsg->m_EventHandle && m_pCurrSendFileInfo->GetFileHandle() == nFileHandle) { m_pCurrSendFileInfo->SetErrorCode((MBFT_ERROR_CODE) pMsg->m_ErrorCode); UINT idString; switch ((MBFT_ERROR_CODE) pMsg->m_ErrorCode) { case iMBFT_OK: idString = 0; break; case iMBFT_SENDER_ABORTED: case iMBFT_RECEIVER_ABORTED: case iMBFT_NO_MORE_FILES: idString = IDS_MSGBOX2_CANCELED; break; case iMBFT_MULT_RECEIVER_ABORTED: idString = IDS_MSGBOX2_MULT_CANCEL; break; // case iMBFT_RECEIVER_REJECTED: default: idString = IDS_MSGBOX2_SEND_FAILED; break; } if (idString) { if (! m_pCurrSendFileInfo->HasShownUI()) { if (::MyLoadString(idString, s_szScratchText, m_pCurrSendFileInfo->GetName())) { m_pCurrSendFileInfo->SetShowUI(); ::MsgBox2(this, s_szScratchText); } else { ASSERT(0); } } } UpdateListView(m_pCurrSendFileInfo); UpdateStatusBar(); ClearSendInfo(TRUE); if (! idString) { // send the next one now if (m_fSendALL) { ::PostMessage(m_hwndMainUI, WM_SEND_NEXT, 0, 0); } } } else { CRecvDlg *pDlg = FindDlgByHandles(pMsg->m_EventHandle, nFileHandle); if (NULL != pDlg) { switch ((MBFT_ERROR_CODE) pMsg->m_ErrorCode) { case iMBFT_RECEIVER_ABORTED: case iMBFT_MULT_RECEIVER_ABORTED: pDlg->OnCanceled(); break; default: pDlg->OnRejectedFile(); break; } } else { switch((MBFT_ERROR_CODE) pMsg->m_ErrorCode) { case iMBFT_INVALID_PATH: ::MyLoadString(IDS_MSGBOX2_INVALID_DIRECTORY, s_szScratchText, pMsg->m_stFileInfo.szFileName); break; case iMBFT_DIRECTORY_FULL_ERROR: ::MyLoadString(IDS_MSGBOX2_DIRECTORY_FULL, s_szScratchText, pMsg->m_stFileInfo.lFileSize, pMsg->m_stFileInfo.szFileName); break; case iMBFT_FILE_ACCESS_DENIED: ::MyLoadString(IDS_MSGBOX2_FILE_CREATE_FAILED, s_szScratchText, pMsg->m_stFileInfo.szFileName); break; default: return; } ::MsgBox2(this, s_szScratchText); } } } void CAppletWindow::HandlePeerNotification(PeerMsg *pMsg) { m_pToolbar->HandlePeerNotification(m_pEngine->GetConfID(), m_pEngine->GetNodeID(), pMsg); } void CAppletWindow::HandleInitUninitNotification(InitUnInitNotifyMsg *pMsg) { if (pMsg->m_iNotifyMessage == EnumInvoluntaryUnInit) { UnregisterEngine(); } } void CAppletWindow::HandleFileEventEndNotification(FileEventEndNotifyMsg *pMsg) { if (m_nCurrSendEventHandle == pMsg->m_EventHandle) { ClearSendInfo(TRUE); // send the next one now if (m_fSendALL) { ::PostMessage(m_hwndMainUI, WM_SEND_NEXT, 0, 0); } } } ///////////////////////////////////////////////////////////////// // // Main UI methods // void CAppletWindow::BringToFront(void) { if (NULL != m_hwndMainUI) { int nCmdShow = SW_SHOW; WINDOWPLACEMENT wp; ::ZeroMemory(&wp, sizeof(wp)); wp.length = sizeof(wp); if (::GetWindowPlacement(m_hwndMainUI, &wp)) { if (SW_MINIMIZE == wp.showCmd || SW_SHOWMINIMIZED == wp.showCmd) { // The window is minimized - restore it: nCmdShow = SW_RESTORE; } } // show the window now ::ShowWindow(m_hwndMainUI, nCmdShow); m_UIMode = FTUIMODE_SHOWUI; // bring it to the foreground ::SetForegroundWindow(m_hwndMainUI); } } void CAppletWindow::ClearSendInfo(BOOL fUpdateUI) { m_pCurrSendFileInfo = NULL; m_nCurrSendEventHandle = NULL; if (fUpdateUI) { UpdateUI(); } } void CAppletWindow::ClearRecvInfo(void) { CRecvDlg *pDlg; while (NULL != (pDlg = m_RecvDlgList.Get())) { ::EndDialog(pDlg->GetHwnd(), IDCLOSE); pDlg->Release(); } } BOOL CAppletWindow::HasUnSentFiles(BOOL fUnSentOnly) { BOOL fRc = FALSE; ULONG cItems = ListView_GetItemCount(m_hwndListView); CUiSendFileInfo *pFileInfo; LVITEM lvi; if (!fUnSentOnly && cItems) { return TRUE; } ::ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM; // examine each item one by one for (ULONG i = 0; i < cItems; i++, pFileInfo = NULL) { lvi.iItem = i; BOOL fRet = ListView_GetItem(m_hwndListView, &lvi); ASSERT(fRet); pFileInfo = (CUiSendFileInfo *) lvi.lParam; if (!pFileInfo->GetFileHandle()) // if file handle is not zero, then it has been sent or cancelled { fRc = TRUE; break; } } return fRc; } void CAppletWindow::UpdateUI(void) { UpdateTitle(); UpdateMenu(); UpdateToolBar(); UpdateStatusBar(); } void CAppletWindow::UpdateTitle(void) { UINT captionID; if ((! m_pEngine) || (m_pEngine->GetPeerCount() <= 1)) { captionID = IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION; } else { captionID = IDS_MSFT_IN_CALL_WINDOW_CAPTION; } ::LoadString(g_hDllInst, captionID, s_szMSFT, sizeof(s_szMSFT)); SetWindowText(m_hwndMainUI, s_szMSFT); } void CAppletWindow::UpdateMenu(void) { HMENU hMenu = ::GetMenu(m_hwndMainUI); if (NULL != hMenu) { if (g_fSendAllowed) { BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1); ::EnableMenuItem(hMenu, IDM_ADD_FILES, fMoreThanOne ? MF_ENABLED : MF_GRAYED); ULONG cItems = ListView_GetItemCount(m_hwndListView); ::EnableMenuItem(hMenu, IDM_REMOVE_FILES, cItems ? MF_ENABLED : MF_GRAYED); ::EnableMenuItem(hMenu, IDM_SEND_ALL, (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? MF_ENABLED : MF_GRAYED); ::EnableMenuItem(hMenu, IDM_SEND_ONE, (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(FALSE)) ? MF_ENABLED : MF_GRAYED); ::EnableMenuItem(hMenu, IDM_STOP_SENDING, m_nCurrSendEventHandle ? MF_ENABLED : MF_GRAYED); } else { ::EnableMenuItem(hMenu, IDM_ADD_FILES, MF_GRAYED); ::EnableMenuItem(hMenu, IDM_REMOVE_FILES, MF_GRAYED); ::EnableMenuItem(hMenu, IDM_SEND_ALL, MF_GRAYED); ::EnableMenuItem(hMenu, IDM_SEND_ONE, MF_GRAYED); ::EnableMenuItem(hMenu, IDM_STOP_SENDING, MF_GRAYED); } } } void CAppletWindow::UpdateToolBar(void) { int iFlags[count_of(buttons)]; ::ZeroMemory(iFlags, sizeof(iFlags)); iFlags[2] = iFlags[5] = iFlags[6] = 1; // separators iFlags[7] = 1; // open recv folders if (g_fSendAllowed) { BOOL fMoreThanOne = (NULL != m_pEngine) && (m_pEngine->GetPeerCount() > 1); ULONG cItems = ListView_GetItemCount(m_hwndListView); iFlags[0] = fMoreThanOne ? TRUE : FALSE; // Add files iFlags[1] = cItems ? TRUE : FALSE; // Delete files iFlags[3] = (fMoreThanOne && ! m_nCurrSendEventHandle && HasUnSentFiles(TRUE)) ? TRUE : FALSE; // Send file(s) iFlags[4] = m_nCurrSendEventHandle ? TRUE : FALSE; // Stop sending m_pToolbar->UpdateButton(iFlags); } else { m_pToolbar->UpdateButton(iFlags); } } void CAppletWindow::UpdateStatusBar(void) { int idString, iPos = 0; HICON hIcon; RECT rc; // set the text in part 0 s_szScratchText[0] = TEXT('\0'); if ((NULL != m_pEngine) && (NULL != m_pCurrSendFileInfo)) { idString = IDS_STBAR_SENDING_XYZ; ::MyLoadString(idString, s_szScratchText, m_pCurrSendFileInfo->GetName()); } else if (NULL == m_pEngine) { ::MyLoadString(IDS_STBAR_NOT_IN_CALL); } else { ::MyLoadString(IDS_STBAR_NOT_TRANSFERING); } ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_TRANSFER_FILE, (LPARAM) s_szScratchText); // set the progres bar in part 1 if ((NULL != m_pCurrSendFileInfo)&&m_pCurrSendFileInfo->GetSize()) { iPos = (int)_GetPercent(m_pCurrSendFileInfo->GetTotalSend(), m_pCurrSendFileInfo->GetSize()); } ::SendMessage(m_hwndStatusBar, SB_GETRECT, SBP_PROGRESS, (LPARAM)&rc); ::MoveWindow(m_hwndProgressBar, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); ::SendMessage(m_hwndProgressBar, PBM_SETPOS, iPos, 0); // set the icon in part 2 hIcon = (NULL != m_pEngine) ? m_hIconInCall : m_hIconNotInCall; ::SendMessage(m_hwndStatusBar, SB_SETTEXT, SBP_SBICON | SBT_OWNERDRAW, (LPARAM)hIcon); } void CAppletWindow::UpdateListView(CUiSendFileInfo *pFileInfo) { LVFINDINFO lvfi; ::ZeroMemory(&lvfi, sizeof(lvfi)); lvfi.flags = LVFI_PARAM; lvfi.lParam = (LPARAM) pFileInfo; int iItem = ListView_FindItem(m_hwndListView, -1, &lvfi); if (-1 != iItem) { for (ULONG i = 0; i < NUM_LIST_VIEW_COLUMNS; i++) { ListView_SetItemText(m_hwndListView, iItem, i, LPSTR_TEXTCALLBACK); } } } //////////////////////////////////////////////////////////////////// // // Save window position for File Transfer // void CAppletWindow::SaveWindowPosition(void) { RECT rcWnd; RegEntry reWnd( FILEXFER_KEY, HKEY_CURRENT_USER); // If we are not maximized or minimized if (!::IsZoomed(m_hwndMainUI) && !::IsIconic(m_hwndMainUI)) { ::GetWindowRect(m_hwndMainUI, &rcWnd); reWnd.SetValue (REGVAL_WINDOW_XPOS, rcWnd.left); reWnd.SetValue (REGVAL_WINDOW_YPOS, rcWnd.top); reWnd.SetValue (REGVAL_WINDOW_WIDTH, rcWnd.right - rcWnd.left); reWnd.SetValue (REGVAL_WINDOW_HEIGHT, rcWnd.bottom - rcWnd.top); } } void CAppletWindow::FocusNextRecvDlg(void) { if (!m_RecvDlgList.IsEmpty()) { m_RecvDlgList.Reset(); CRecvDlg *pRecvDlg = m_RecvDlgList.Iterate(); if (pRecvDlg) { SetFocus(pRecvDlg->GetHwnd()); } } } void CAppletWindow::FocusNextErrorDlg(void) { if (!m_ErrorDlgList.IsEmpty()) { m_ErrorDlgList.Reset(); HWND hwndErrorDlg = m_ErrorDlgList.Iterate(); if (hwndErrorDlg) { ::SetFocus(hwndErrorDlg); } } } ///////////////////////////////////////////////////////////////// // // Utilities // LPTSTR PathNameToFileName(LPTSTR pszPathName) { LPTSTR psz = pszPathName; while (*psz != '\0') { BOOL fDirChar = (*psz == TEXT('\\')); psz = ::CharNext(psz); if (fDirChar) { pszPathName = psz; } } return pszPathName; } int MyLoadString(UINT idStr) { s_szScratchText[0] = TEXT('\0'); int iRet = ::LoadString(g_hDllInst, idStr, s_szScratchText, MAX_PATH); ASSERT(iRet); return iRet; } int MyLoadString(UINT idStr, LPTSTR pszDstStr) { *pszDstStr = TEXT('\0'); int iRet = ::LoadString(g_hDllInst, idStr, pszDstStr, MAX_PATH); ASSERT(iRet); return iRet; } int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement) { int cch; TCHAR szText[MAX_PATH]; cch = ::LoadString(g_hDllInst, idStr, szText, count_of(szText)); if (cch) { ::wsprintf(pszDstStr, szText, pszElement); } else { ASSERT(0); *pszDstStr = TEXT('\0'); } return cch; } int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement1, LPTSTR pszElement2) { int cch; TCHAR szText[MAX_PATH]; cch = ::LoadString(g_hDllInst, idStr, szText, count_of(szText)); if (cch) { ::wsprintf(pszDstStr, szText, pszElement1, pszElement2); } else { ASSERT(0); *pszDstStr = TEXT('\0'); } return cch; } void LoadDefaultStrings(void) { // load file transfer name s_szMSFT[0] = TEXT('\0'); ::LoadString(g_hDllInst, IDS_MSFT_NOT_IN_CALL_WINDOW_CAPTION, s_szMSFT, count_of(s_szMSFT)); } ///////////////////////////////////////////////////////////////// // // CUiSendFileInfo // CUiSendFileInfo::CUiSendFileInfo(CAppletWindow *pWindow, TCHAR szDir[], TCHAR szFile[], BOOL *pfRet) : m_nFileHandle(0), m_cbTotalSend(0), m_eSendErrorCode(iMBFT_OK), m_percentSent(-1), m_fAlreadyShowUI(FALSE), m_pszFullName(NULL) { *pfRet = FALSE; // failure as default HANDLE hFile; // build a full name hFile = GetOpenFile(pWindow, szDir, szFile, TRUE); // try to resolve if (INVALID_HANDLE_VALUE == hFile) { hFile = GetOpenFile(pWindow, szDir, szFile, FALSE); } if (INVALID_HANDLE_VALUE != hFile) { // get the file info ::ZeroMemory(&m_FileInfo, sizeof(m_FileInfo)); BOOL rc = ::GetFileInformationByHandle(hFile, &m_FileInfo); ::CloseHandle(hFile); if (rc) { ASSERT(0 == m_FileInfo.nFileSizeHigh); // make sure the file size is smaller than what the policy says if ((! g_cbMaxSendFileSize) || GetSize() <= g_cbMaxSendFileSize * 1024) { *pfRet = TRUE; } else if (pWindow->GetUIMode() != FTUIMODE_NOUI) { ::MyLoadString(IDS_MSGBOX_SEND_BIG_FILE, s_szScratchText, (LPTSTR) g_cbMaxSendFileSize, m_pszFileName); ::MessageBox(pWindow->GetHwnd(), s_szScratchText, s_szMSFT, MB_OK | MB_ICONSTOP); } } } } CUiSendFileInfo::~CUiSendFileInfo(void) { delete m_pszFullName; } HANDLE CUiSendFileInfo::GetOpenFile(CAppletWindow *pWindow, TCHAR szDir[], TCHAR szFile[], BOOL fResolve) { // build a full name ULONG cch; TCHAR szName[MAX_PATH*2]; HANDLE hFile = INVALID_HANDLE_VALUE; if ((NULL != szDir)&&(!_StrChr(szFile, '\\'))) { cch = ::lstrlen(szDir); ::wsprintf(szName, (TEXT('\\') == szDir[cch-1]) ? TEXT("%s%s") : TEXT("%s\\%s"), szDir, szFile); } else { // file name is the full name ::lstrcpy(szName, szFile); } // resolve shortcut if necessary cch = ::lstrlen(szName) + 1; if (fResolve&&(cch >= 4)) { if (! lstrcmpi(&szName[cch-5], TEXT(".lnk"))) { pWindow->ResolveShortcut(szName, szName); cch = ::lstrlen(szName) + 1; } } if (m_pszFullName) { delete [] m_pszFullName; } // construct the full name DBG_SAVE_FILE_LINE m_pszFullName = new TCHAR[cch]; if (NULL != m_pszFullName) { ::CopyMemory(m_pszFullName, szName, cch * sizeof(TCHAR)); m_pszFileName = ::PathNameToFileName(m_pszFullName); // open the file hFile = ::CreateFile(m_pszFullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } return hFile; } ///////////////////////////////////////////////////////////////// // // CUiRecvFileInfo // CUiRecvFileInfo::CUiRecvFileInfo(FileOfferNotifyMsg *pMsg, HRESULT *pHr) : m_nFileHandle(pMsg->m_hFile), m_FileDateTime(pMsg->m_FileDateTime), m_cbFileSize(pMsg->m_FileSize), m_cbTotalRecvSize(0), m_pszFullName(NULL), m_pszRecvFolder(NULL) { *pHr = E_FAIL; // failure, at default ULONG cchTotal = ::lstrlen(pMsg->m_szFileName); // construct the full name DBG_SAVE_FILE_LINE m_pszFullName = new TCHAR[cchTotal+2]; if (NULL != m_pszFullName) { // construct full name and file name strcpy(m_pszFullName, pMsg->m_szFileName); m_pszFileName = PathNameToFileName(m_pszFullName); ULONG cchFile = ::lstrlen(m_pszFileName); DBG_SAVE_FILE_LINE m_pszRecvFolder = new TCHAR[cchTotal - cchFile + 2]; if (NULL != m_pszRecvFolder) { ::CopyMemory(m_pszRecvFolder, m_pszFullName, cchTotal - cchFile); m_pszRecvFolder[cchTotal - cchFile - 1] = TEXT('\0'); *pHr = S_OK; } } } CUiRecvFileInfo::~CUiRecvFileInfo(void) { delete m_pszFullName; delete m_pszRecvFolder; } ///////////////////////////////////////////////////////////////// // // Receive Dialog // CRecvDlg::CRecvDlg ( CAppletWindow *pWindow, T120ConfID nConfID, T120NodeID nidSender, MBFTEVENTHANDLE nEventHandle, CUiRecvFileInfo *pFileInfo, HRESULT *pHr ) : CRefCount(MAKE_STAMP_ID('F','T','R','D')), m_pWindow(pWindow), m_nConfID(nConfID), m_nidSender(nidSender), m_nEventHandle(nEventHandle), m_pRecvFileInfo(pFileInfo), m_fRecvComplete(FALSE), m_fShownRecvCompleteUI(FALSE), m_idResult(0), m_dwEstTimeLeft(0), m_dwPreviousTime(0), m_dwPreviousTransferred(0), m_dwBytesPerSec(0), m_dwStartTime(::GetTickCount()) { *pHr = E_FAIL; // failure, at default m_hwndRecvDlg = ::CreateDialogParam(g_hDllInst, MAKEINTRESOURCE(IDD_RECVDLG), pWindow->GetHwnd(), RecvDlgProc, (LPARAM) this); ASSERT(NULL != m_hwndRecvDlg); if (NULL != m_hwndRecvDlg) { ::ShowWindow(m_hwndRecvDlg, SW_SHOWNORMAL); m_pWindow->RegisterRecvDlg(this); *pHr = S_OK; ::SetForegroundWindow(m_hwndRecvDlg); } } CRecvDlg::~CRecvDlg(void) { delete m_pRecvFileInfo; m_pWindow->UnregisterRecvDlg(this); if (NULL != m_hwndRecvDlg) { HWND hwnd = m_hwndRecvDlg; m_hwndRecvDlg = NULL; ::EndDialog(hwnd, IDCLOSE); } } ///////////////////////////////////////////////////////////////// // // RecvDlg_OnInitDialog // void RecvDlg_OnInitDialog(HWND hdlg, WPARAM wParam, LPARAM lParam) { CRecvDlg *pDlg = (CRecvDlg *) ::GetWindowLongPtr(hdlg, DWLP_USER); ASSERT(NULL != pDlg); CUiRecvFileInfo *pFileInfo = (CUiRecvFileInfo *) pDlg->GetRecvFileInfo(); ASSERT(NULL != pFileInfo); // move the window to proper location ULONG nCaptionHeight = ::GetSystemMetrics(SM_CYCAPTION); ULONG nShift = nCaptionHeight * (s_cRecvDlg++ % 8); RECT rcDlg; ::GetWindowRect(hdlg, &rcDlg); ::MoveWindow(hdlg, rcDlg.left + nShift, rcDlg.top + nShift, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top, FALSE); // Set font (for international) HFONT hfont = (HFONT) ::GetStockObject(DEFAULT_GUI_FONT); ASSERT(NULL != hfont); ::SendDlgItemMessage(hdlg, IDE_RECVDLG_RECFILE, WM_SETFONT, (WPARAM) hfont, 0); ::SendDlgItemMessage(hdlg, IDE_RECVDLG_RECDIR, WM_SETFONT, (WPARAM) hfont, 0); ::SendDlgItemMessage(hdlg, IDE_RECVDLG_SENDER, WM_SETFONT, (WPARAM) hfont, 0); // cache names LPTSTR pszFileName = pFileInfo->GetName(); LPTSTR pszFullName = pFileInfo->GetFullName(); // title TCHAR szText[MAX_PATH*2]; if (::MyLoadString(IDS_RECVDLG_TITLE, szText, pszFileName)) { ::SetWindowText(hdlg, szText); } // filename ::lstrcpyn(szText, pszFileName, MAX_FILE_NAME_LENGTH); if (::lstrlen(pszFileName) > MAX_FILE_NAME_LENGTH) { LPTSTR psz = szText; int i = MAX_FILE_NAME_LENGTH - 1; while (i) { psz = CharNext(psz); i--; } ::lstrcpy(psz, TEXT("...")); } ::SetDlgItemText(hdlg, IDE_RECVDLG_RECFILE, szText); // directory Name LPTSTR psz = szText; ::lstrcpyn(szText, pszFullName, (int)(pszFileName - pszFullName)); HDC hdc = ::GetDC(hdlg); if (NULL != hdc) { SIZE size; if (::GetTextExtentPoint32(hdc, szText, ::lstrlen(szText), &size)) { RECT rc; ::GetWindowRect(::GetDlgItem(hdlg, IDE_RECVDLG_RECDIR), &rc); if (size.cx > (rc.right - rc.left)) { // Just display the folder name psz = (LPTSTR) ::GetFileNameFromPath(szText); } } } ::ReleaseDC(hdlg, hdc); ::SetDlgItemText(hdlg, IDE_RECVDLG_RECDIR, psz); // sender Name if (::T120_GetNodeName(pDlg->GetConfID(), pDlg->GetSenderID(), szText, count_of(szText))) { ::SetDlgItemText(hdlg, IDE_RECVDLG_SENDER, szText); } // update "Received xxx bytes of yyy" if (::MyLoadString(IDS_RECVDLG_RECBYTES, szText, pFileInfo->GetTotalRecvSize(), pFileInfo->GetSize())) { ::SetDlgItemText(hdlg, IDE_RECVDLG_RECBYTES, szText); } // progress bar ::SendMessage(GetDlgItem(hdlg, IDC_RECVDLG_PROGRESS), PBM_SETPOS, pDlg->GetPercent(), 0); // start animation Animate_Open(GetDlgItem(hdlg, IDC_RECVDLG_ANIMATE), MAKEINTRESOURCE(IDA_RECVDLG_ANIMATION)); // do the animation work if (! pDlg->IsRecvComplete()) { Animate_Play(GetDlgItem(hdlg, IDC_RECVDLG_ANIMATE), 0, -1, -1); if (::LoadString(g_hDllInst, IDS_RECVDLG_START, szText, count_of(szText))) { ::SetDlgItemText(hdlg, IDE_RECVDLG_TIME, szText); } } // show the window now ::ShowWindow(hdlg, SW_SHOWNORMAL); // UpdateProgress(); pDlg->OnProgressUpdate(); } ///////////////////////////////////////////////////////////////// // // RecvDlg_OnCommand // void RecvDlg_OnCommand(HWND hdlg, WPARAM wParam, LPARAM lParam) { CRecvDlg *pDlg = (CRecvDlg *) ::GetWindowLongPtr(hdlg, DWLP_USER); ASSERT(NULL != pDlg); switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_RECVDLG_DELETE: pDlg->OnDelete(); break; case IDM_RECVDLG_OPEN: pDlg->OnOpen(); break; case IDM_RECVDLG_ACCEPT: case IDOK: case IDCANCEL: case IDCLOSE: pDlg->OnAccept(); break; default: return; } // dismiss the dialog ::EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam)); pDlg->Release(); } void CRecvDlg::OnOpen(void) { // create short version of the path name TCHAR szDir[MAX_PATH]; ::GetShortPathName(m_pRecvFileInfo->GetRecvFolder(), szDir, count_of(szDir)); // create short version of the full name TCHAR szFile[MAX_PATH]; szFile[0] = TEXT('\0'); ::wsprintf(szFile, TEXT("%s\\%s"), szDir, m_pRecvFileInfo->GetName()); TRACE_OUT(("FT: Opening [%s] in [%]", m_pRecvFileInfo->GetName(), szDir)); HINSTANCE hInst = ::ShellExecute(m_pWindow->GetHwnd(), NULL, szFile, NULL, szDir, SW_SHOWDEFAULT); if (32 >= (DWORD_PTR) hInst) { WARNING_OUT(("Unable to open [%s] - showing file", szFile)); ::ShellExecute(m_pWindow->GetHwnd(), NULL, szDir, m_pRecvFileInfo->GetFullName(), NULL, SW_SHOWDEFAULT); } } void CRecvDlg::OnDelete(void) { StopAnimation(); // check if transfer has completed if (! m_fRecvComplete) { DBG_SAVE_FILE_LINE m_pWindow->GetEngine()->SafePostMessage( new FileTransferControlMsg( m_nEventHandle, m_pRecvFileInfo->GetFileHandle(), NULL, NULL, FileTransferControlMsg::EnumAbortFile)); } else { ::DeleteFile(m_pRecvFileInfo->GetFullName()); } } void CRecvDlg::OnAccept(void) { StopAnimation(); } ///////////////////////////////////////////////////////////////// // // RecvDlg_OnInitMenuPopup // void RecvDlg_OnInitMenuPopup(HWND hdlg, WPARAM wParam, LPARAM lParam) { if (0 != HIWORD(lParam)) // System menu flag { HMENU hMenu = (HMENU) wParam; // handle of pop-up menu ::EnableMenuItem(hMenu, SC_MAXIMIZE, MF_GRAYED); ::EnableMenuItem(hMenu, SC_SIZE, MF_GRAYED); } } ///////////////////////////////////////////////////////////////// // // RecvDlgProc // INT_PTR CALLBACK RecvDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL fRet = TRUE; // processed switch (uMsg) { case WM_INITDIALOG: ASSERT(NULL != lParam); ::SetWindowLongPtr(hdlg, DWLP_USER, lParam); RecvDlg_OnInitDialog(hdlg, wParam, lParam); break; case WM_COMMAND: RecvDlg_OnCommand(hdlg, wParam, lParam); break; case WM_INITMENUPOPUP: RecvDlg_OnInitMenuPopup(hdlg, wParam, lParam); fRet = FALSE; break; // This means user wants to delete the file. case WM_CLOSE: RecvDlg_OnCommand(hdlg, IDCLOSE, lParam); break;; default: fRet = FALSE; // not processed break; } return fRet; } ///////////////////////////////////////////////////////////////// // // RecvDlg Animation // void CRecvDlg::StopAnimation(void) { HWND hwnd = ::GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_ANIMATE); if (NULL != hwnd) { Animate_Stop(hwnd); Animate_Close(hwnd); } } ULONG _GetPercent(ULONG cbTotalRecvSize , ULONG cbFileSize) { if (! cbFileSize || (cbTotalRecvSize >= cbFileSize)) { return 100; } // FUTURE: Consider using EnlargedUnsignedMultiply if (cbFileSize < 0x01000000) { return (cbTotalRecvSize * 100) / cbFileSize; } return cbTotalRecvSize / (cbFileSize / 100); } ///////////////////////////////////////////////////////////////// // // RecvDlg Progress // ULONG CRecvDlg::GetPercent(void) { return _GetPercent(m_pRecvFileInfo->GetTotalRecvSize(), m_pRecvFileInfo->GetSize()); } void CRecvDlg::OnProgressUpdate(FileTransmitMsg *pMsg) { if (NULL != pMsg) { ASSERT(iMBFT_FILE_RECEIVE_PROGRESS == (MBFT_NOTIFICATION) pMsg->m_TransmitStatus || iMBFT_FILE_RECEIVE_BEGIN == (MBFT_NOTIFICATION) pMsg->m_TransmitStatus); ASSERT(m_nEventHandle == pMsg->m_EventHandle); ASSERT(m_pRecvFileInfo->GetFileHandle() == pMsg->m_hFile); ASSERT(m_pRecvFileInfo->GetSize() == pMsg->m_FileSize); m_pRecvFileInfo->SetTotalRecvSize(pMsg->m_BytesTransmitted); if (pMsg->m_BytesTransmitted >= pMsg->m_FileSize) { m_fRecvComplete = TRUE; m_idResult = IDS_RECVDLG_COMPLETE; } } if (m_fRecvComplete && ! m_fShownRecvCompleteUI) { m_fRecvComplete = TRUE; TCHAR szText[MAX_PATH]; if (::LoadString(g_hDllInst, IDS_RECVDLG_CLOSE, szText, count_of(szText))) { ::SetDlgItemText(m_hwndRecvDlg, IDM_RECVDLG_ACCEPT, szText); } if (IDS_RECVDLG_COMPLETE == m_idResult) { ::EnableWindow(::GetDlgItem(m_hwndRecvDlg, IDM_RECVDLG_OPEN), TRUE); } else { ::EnableWindow(::GetDlgItem(m_hwndRecvDlg, IDM_RECVDLG_DELETE), FALSE); } // Reset animation HWND hwnd = ::GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_ANIMATE); Animate_Stop(hwnd); Animate_Close(hwnd); Animate_Open(hwnd, MAKEINTRESOURCE(IDA_RECVDLG_DONE)); Animate_Seek(hwnd, ((IDS_RECVDLG_COMPLETE == m_idResult) ? 0 : 1)); m_fShownRecvCompleteUI = TRUE; } ULONG cbTotalRecvSize = m_pRecvFileInfo->GetTotalRecvSize(); ULONG cbFileSize = m_pRecvFileInfo->GetSize(); DWORD dwNow = ::GetTickCount(); DWORD dwBytesPerSec; DWORD dwBytesRead; TCHAR szOut[MAX_PATH]; if (m_dwPreviousTransferred != cbTotalRecvSize) { TCHAR szFmt[MAX_PATH]; // Update "Received xxx bytes of yyy" if (::LoadString(g_hDllInst, IDS_RECVDLG_RECBYTES, szFmt, count_of(szFmt))) { ::wsprintf(szOut, szFmt, cbTotalRecvSize, cbFileSize); ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_RECBYTES, szOut); } // Update Progress Bar if (cbTotalRecvSize) { ::SendMessage(GetDlgItem(m_hwndRecvDlg, IDC_RECVDLG_PROGRESS), PBM_SETPOS, GetPercent(), 0); } } // check if no time estimate is required if (m_fRecvComplete) { if (::LoadString(g_hDllInst, m_idResult, szOut, count_of(szOut))) { ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_TIME, szOut); } return; } // first time we're in here for this file? if (! m_dwPreviousTime || ! cbTotalRecvSize) { // no data, yet m_dwPreviousTime = dwNow - 1000; ASSERT(! m_dwPreviousTransferred); ASSERT(! m_dwBytesPerSec); return; } // Has enough time elapsed to update the display? // We do this about every 5 seconds (note the adjustment for first time) if ((dwNow - m_dwPreviousTime) < 5000) return; dwBytesRead = cbTotalRecvSize - m_dwPreviousTransferred; // We take 10 times the number of bytes and divide by the number of // tenths of a second to minimize both overflow and roundoff dwBytesPerSec = dwBytesRead * 10 / ((dwNow - m_dwPreviousTime) / 100); if (! dwBytesPerSec) { // very low transmission rate! Ignore the information? return; } if (m_dwBytesPerSec) { // Take the average of the current transfer rate and the // previously computed one, just to try to smooth out // some random fluctuations dwBytesPerSec = (dwBytesPerSec + m_dwBytesPerSec) / 2; } m_dwBytesPerSec = dwBytesPerSec; // Calculate time remaining (round up by adding 1) m_dwEstTimeLeft = ((cbFileSize - cbTotalRecvSize) / m_dwBytesPerSec) + 1; // Reset time and # of bytes read m_dwPreviousTime = dwNow; m_dwPreviousTransferred = cbTotalRecvSize; if (m_dwEstTimeLeft < 3) { // szOut[0] = _T('\0'); // don't bother updating when almost done return; } if (m_dwEstTimeLeft > 99) { // dwTime is about 2 mintes ::MyLoadString(IDS_RECVDLG_MINUTES, szOut, ((m_dwEstTimeLeft / 60) + 1)); } else { // Round up to 5 seconds so it doesn't look so random ::MyLoadString(IDS_RECVDLG_SECONDS, szOut, (((m_dwEstTimeLeft + 4) / 5) * 5) ); } ::SetDlgItemText(m_hwndRecvDlg, IDE_RECVDLG_TIME, szOut); } void CRecvDlg::OnCanceled(void) { m_idResult = IDS_RECVDLG_CANCEL; m_fRecvComplete = TRUE; OnProgressUpdate(); } void CRecvDlg::OnRejectedFile(void) { m_idResult = IDS_RECVDLG_SENDER_CANCEL; m_fRecvComplete = TRUE; OnProgressUpdate(); } ////////////////////////////////////////////////////////////////////// // // Shortcut/Link Management // void CAppletWindow::ResolveShortcut(LPTSTR pszSrcFile, LPTSTR pszDstFile) { ASSERT(NULL != pszSrcFile && '\0' != *pszSrcFile); ASSERT(NULL != pszDstFile); IShellLink *psl; HRESULT hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *) &psl); if (SUCCEEDED(hr)) { IPersistFile *ppf; hr = psl->QueryInterface(IID_IPersistFile, (LPVOID *) &ppf); if (SUCCEEDED(hr)) { WCHAR wsz[MAX_PATH]; /* Buffer for unicode string */ #ifdef _UNICODE ::lstrcpyn(wsz, pszSrcFile, MAX_PATH); #else ::MultiByteToWideChar(CP_ACP, 0, pszSrcFile, -1, wsz, MAX_PATH); #endif hr = ppf->Load(wsz, STGM_READ); if (SUCCEEDED(hr)) { /* Resolve the link, this may post UI to find the link */ hr = psl->Resolve(m_hwndMainUI, SLR_ANY_MATCH); if (SUCCEEDED(hr)) { psl->GetPath(pszDstFile, MAX_PATH, NULL, 0); } TRACE_OUT(("CAppletWindow::ResolveShortcut: File resolved to [%s]", pszDstFile)); } ppf->Release(); } psl->Release(); } } ///////////////////////////////////////////////////////////////// // // Non-blocking Message Box // INT_PTR MsgBox2DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL fHandled = FALSE; CAppletWindow *pWindow; switch (uMsg) { case WM_INITDIALOG: { // get the text to display LPTSTR pszText = (LPTSTR) lParam; ASSERT(NULL != pszText && TEXT('\0') != *pszText); // estimate how big the read-only edit control should be HDC hdc = ::GetDC(hdlg); if (NULL != hdc) { SIZE csEdit; if (::GetTextExtentPoint32(hdc, pszText, ::lstrlen(pszText), &csEdit)) { const ULONG c_nMarginX = 0; const ULONG c_nMarginY = 10; ULONG nCaptionHeight = ::GetSystemMetrics(SM_CYCAPTION); ULONG nShift = nCaptionHeight * (s_cMsgBox2Dlg++ % 8); // move the edit control HWND hwndEdit = ::GetDlgItem(hdlg, IDE_MSGBOX2_TEXT); POINT ptEdit; ptEdit.x = c_nMarginX; ptEdit.y = c_nMarginY + (c_nMarginY >> 1); csEdit.cx += c_nMarginX << 1; csEdit.cy += c_nMarginY << 1; ::MoveWindow(hwndEdit, ptEdit.x, ptEdit.y, csEdit.cx, csEdit.cy, FALSE); // move the ok button HWND hwndOK = ::GetDlgItem(hdlg, IDOK); RECT rcOK; ::GetWindowRect(hwndOK, &rcOK); SIZE csOK; csOK.cx = rcOK.right - rcOK.left; csOK.cy = rcOK.bottom - rcOK.top; POINT ptOK; ptOK.x = ptEdit.x + (csEdit.cx >> 1) - (csOK.cx >> 1); ptOK.y = ptEdit.y + csEdit.cy + (c_nMarginY >> 1); ::MoveWindow(hwndOK, ptOK.x, ptOK.y, csOK.cx, csOK.cy, FALSE); // adjust all the windows RECT rcDlg, rcClient; ::GetWindowRect(hdlg, &rcDlg); POINT ptDlg; ptDlg.x = rcDlg.left + nShift; ptDlg.y = rcDlg.top + nShift; ::GetClientRect(hdlg, &rcClient); SIZE csDlg; csDlg.cx = (rcDlg.right - rcDlg.left) - (rcClient.right - rcClient.left); csDlg.cy = (rcDlg.bottom - rcDlg.top) - (rcClient.bottom - rcClient.top); csDlg.cx += ptEdit.x + csEdit.cx + c_nMarginX; csDlg.cy += ptOK.y + csOK.cy + c_nMarginY; ::MoveWindow(hdlg, ptDlg.x, ptDlg.y, csDlg.cx, csDlg.cy, FALSE); } ::ReleaseDC(hdlg, hdc); } ::SetDlgItemText(hdlg, IDE_MSGBOX2_TEXT, pszText); delete [] pszText; // free the display text fHandled = TRUE; } break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: case IDCANCEL: case IDCLOSE: switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case BN_CLICKED: pWindow = (CAppletWindow*)::GetWindowLongPtr(hdlg, DWLP_USER); ASSERT (pWindow); if (pWindow) { pWindow->RemoveErrorDlg(hdlg); pWindow->FocusNextErrorDlg(); } ::EndDialog(hdlg, IDOK); break; } break; } fHandled = TRUE; break; } return(fHandled); } BOOL MsgBox2(CAppletWindow *pWindow, LPTSTR pszText) { BOOL fRet = FALSE; ULONG cch = ::lstrlen(pszText) + 1; DBG_SAVE_FILE_LINE LPTSTR pszNew = new TCHAR[cch]; if (NULL != pszNew) { ::CopyMemory(pszNew, pszText, cch); HWND hwndDlg = ::CreateDialogParam(g_hDllInst, MAKEINTRESOURCE(IDD_MSGBOX2), pWindow->GetHwnd(), MsgBox2DlgProc, (LPARAM) pszNew); ASSERT(NULL != hwndDlg); if (NULL != hwndDlg) { ::ShowWindow(hwndDlg, SW_SHOWNORMAL); fRet = TRUE; ::SetForegroundWindow(hwndDlg); ::SetWindowLongPtr(hwndDlg, DWLP_USER, (LPARAM)pWindow); pWindow->AddErrorDlg(hwndDlg); } } else { ERROR_OUT(("FT::MsgBox2: cannot duplicate string [%s]", pszText)); } return fRet; } ///////////////////////////////////////////////////////////////// // // Receive Folder Management // HRESULT GetRecvFolder(LPTSTR pszInFldr, LPTSTR pszOutFldr) { LPTSTR psz; TCHAR szPath[MAX_PATH]; RegEntry reFileXfer(FILEXFER_KEY, HKEY_CURRENT_USER); if (NULL == pszInFldr) { // NULL directory specified - get info from registry or use default psz = reFileXfer.GetString(REGVAL_FILEXFER_PATH); if (NULL != psz && TEXT('\0') != *psz) { ::lstrcpyn(szPath, psz, count_of(szPath)); } else { TCHAR szInstallDir[MAX_PATH]; ::GetInstallDirectory(szInstallDir); ::MyLoadString(IDS_RECDIR_DEFAULT, szPath, szInstallDir); } pszInFldr = szPath; } ::lstrcpyn(pszOutFldr, pszInFldr, MAX_PATH); // Remove trailing backslash, if any for (psz = pszOutFldr; *psz; psz = CharNext(psz)) { if ('\\' == *psz && '\0' == *CharNext(psz)) { *psz = '\0'; break; } } HRESULT hr; if (!FEnsureDirExists(pszOutFldr)) { WARNING_OUT(("ChangeRecDir: FT directory is invalid [%s]", pszOutFldr)); hr = E_FAIL; } else { // update the registry reFileXfer.SetValue(REGVAL_FILEXFER_PATH, pszOutFldr); hr = S_OK; } return hr; } void EnsureTrailingSlash(LPTSTR psz) { LPTSTR psz2; // Make sure the directory name has a trailing '\' while (TEXT('\0') != *psz) { psz2 = ::CharNext(psz); if (TEXT('\\') == *psz && TEXT('\0') == *psz2) { // The path already ends with a backslash return; } psz = psz2; } // Append a trailing backslash *psz = TEXT('\\'); psz = ::CharNext(psz); *psz = TEXT('\0'); }