// FileManagerDlg.cpp : implementation file // #include "stdafx.h" #include "2015Remote.h" #include "FileManagerDlg.h" #include "FileTransferModeDlg.h" #include "InputDlg.h" #include "ZstdArchive.h" #include "2015RemoteDlg.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, ID_SEPARATOR }; #define MAX_SEND_BUFFER 65535 #define MAX_RECV_BUFFER 65535 typedef struct { LVITEM* plvi; CString sCol2; } lvItem, *plvItem; ///////////////////////////////////////////////////////////////////////////// // CFileManagerDlg dialog float GetScreenScalingFactor() { HDC hdc = GetDC(NULL); // 获取屏幕设备上下文 int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); // 获取水平 DPI ReleaseDC(NULL, hdc); // 缩放比例 = DPI / 标准 DPI(96) return dpiX / 96.0f; } CFileManagerDlg::CFileManagerDlg(CWnd* pParent, Server* pIOCPServer, ClientContext *pContext) : DialogBase(CFileManagerDlg::IDD, pParent, pIOCPServer, pContext, IDI_ICON_FATHER) { m_fScalingFactor = GetScreenScalingFactor(); //{{AFX_DATA_INIT(CFileManagerDlg) //}}AFX_DATA_INIT m_bIsClosed = false; m_ProgressCtrl = NULL; // 保存远程驱动器列表 memset(m_bRemoteDriveList, 0, sizeof(m_bRemoteDriveList)); PBYTE pSrc = m_ContextObject->m_DeCompressionBuffer.GetBuffer(1); int length = m_ContextObject->m_DeCompressionBuffer.GetBufferLen() - 1; if (length > 0) memcpy(m_bRemoteDriveList, pSrc, length); m_nTransferMode = TRANSFER_MODE_NORMAL; m_nOperatingFileLength = 0; m_nCounter = 0; m_bIsStop = false; m_hRecvFile = INVALID_HANDLE_VALUE; m_bSearching = false; m_bSearchStopped = false; m_nSearchResultCount = 0; m_dwSearchStartTime = 0; m_bLocalSearching = false; m_bLocalSearchStopped = false; m_nLocalSearchResultCount = 0; m_dwLocalSearchStartTime = 0; m_hLocalSearchThread = NULL; } void CFileManagerDlg::DoDataExchange(CDataExchange* pDX) { __super::DoDataExchange(pDX); //{{AFX_DATA_MAP(CFileManagerDlg) DDX_Control(pDX, IDC_REMOTE_PATH, m_Remote_Directory_ComboBox); DDX_Control(pDX, IDC_LOCAL_PATH, m_Local_Directory_ComboBox); DDX_Control(pDX, IDC_LIST_REMOTE, m_list_remote); DDX_Control(pDX, IDC_LIST_LOCAL, m_list_local); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CFileManagerDlg, CDialog) //{{AFX_MSG_MAP(CFileManagerDlg) ON_WM_QUERYDRAGICON() ON_WM_SIZE() ON_NOTIFY(NM_DBLCLK, IDC_LIST_LOCAL, OnDblclkListLocal) ON_NOTIFY(LVN_BEGINDRAG, IDC_LIST_LOCAL, OnBegindragListLocal) ON_NOTIFY(LVN_BEGINDRAG, IDC_LIST_REMOTE, OnBegindragListRemote) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_TIMER() ON_WM_CLOSE() ON_NOTIFY(NM_DBLCLK, IDC_LIST_REMOTE, OnDblclkListRemote) ON_COMMAND(IDT_LOCAL_PREV, OnLocalPrev) ON_COMMAND(IDT_REMOTE_PREV, OnRemotePrev) ON_COMMAND(IDT_LOCAL_VIEW, OnLocalView) ON_COMMAND(IDM_LOCAL_LIST, OnLocalList) ON_COMMAND(IDM_LOCAL_REPORT, OnLocalReport) ON_COMMAND(IDM_LOCAL_BIGICON, OnLocalBigicon) ON_COMMAND(IDM_LOCAL_SMALLICON, OnLocalSmallicon) ON_COMMAND(IDM_REMOTE_BIGICON, OnRemoteBigicon) ON_COMMAND(IDM_REMOTE_LIST, OnRemoteList) ON_COMMAND(IDM_REMOTE_REPORT, OnRemoteReport) ON_COMMAND(IDM_REMOTE_SMALLICON, OnRemoteSmallicon) ON_COMMAND(IDT_REMOTE_VIEW, OnRemoteView) ON_UPDATE_COMMAND_UI(IDT_LOCAL_STOP, OnUpdateLocalStop) ON_UPDATE_COMMAND_UI(IDT_REMOTE_STOP, OnUpdateRemoteStop) ON_UPDATE_COMMAND_UI(IDT_LOCAL_PREV, OnUpdateLocalPrev) ON_UPDATE_COMMAND_UI(IDT_REMOTE_PREV, OnUpdateRemotePrev) ON_UPDATE_COMMAND_UI(IDT_LOCAL_COPY, OnUpdateLocalCopy) ON_UPDATE_COMMAND_UI(IDT_REMOTE_COPY, OnUpdateRemoteCopy) ON_UPDATE_COMMAND_UI(IDT_REMOTE_DELETE, OnUpdateRemoteDelete) ON_UPDATE_COMMAND_UI(IDT_REMOTE_NEWFOLDER, OnUpdateRemoteNewfolder) ON_UPDATE_COMMAND_UI(IDT_LOCAL_DELETE, OnUpdateLocalDelete) ON_UPDATE_COMMAND_UI(IDT_LOCAL_NEWFOLDER, OnUpdateLocalNewfolder) ON_UPDATE_COMMAND_UI(IDT_LOCAL_SEARCH, OnUpdateLocalSearch) ON_UPDATE_COMMAND_UI(IDT_REMOTE_SEARCH, OnUpdateRemoteSearch) ON_COMMAND(IDT_REMOTE_COPY, OnRemoteCopy) ON_COMMAND(IDT_LOCAL_COPY, OnLocalCopy) ON_COMMAND(IDT_LOCAL_DELETE, OnLocalDelete) ON_COMMAND(IDT_REMOTE_DELETE, OnRemoteDelete) ON_COMMAND(IDT_REMOTE_STOP, OnRemoteStop) ON_COMMAND(IDT_LOCAL_STOP, OnLocalStop) ON_COMMAND(IDT_LOCAL_NEWFOLDER, OnLocalNewfolder) ON_COMMAND(IDT_REMOTE_NEWFOLDER, OnRemoteNewfolder) ON_COMMAND(IDT_LOCAL_DESKTOP, OnLocalDesktop) ON_COMMAND(IDT_LOCAL_DOWNLOADS, OnLocalDownloads) ON_COMMAND(IDT_LOCAL_HOME, OnLocalHome) ON_COMMAND(IDT_LOCAL_SEARCH, OnLocalSearch) ON_COMMAND(IDT_REMOTE_DESKTOP, OnRemoteDesktop) ON_COMMAND(IDT_REMOTE_DOWNLOADS, OnRemoteDownloads) ON_COMMAND(IDT_REMOTE_HOME, OnRemoteHome) ON_COMMAND(IDT_REMOTE_SEARCH, OnRemoteSearch) ON_COMMAND(IDM_TRANSFER, OnTransfer) ON_COMMAND(IDM_RENAME, OnRename) ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST_LOCAL, OnEndlabeleditListLocal) ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST_REMOTE, OnEndlabeleditListRemote) ON_COMMAND(IDM_DELETE, OnDelete) ON_COMMAND(IDM_NEWFOLDER, OnNewfolder) ON_COMMAND(IDM_REFRESH, OnRefresh) ON_COMMAND(IDM_LOCAL_OPEN, OnLocalOpen) ON_COMMAND(IDM_REMOTE_OPEN_SHOW, OnRemoteOpenShow) ON_COMMAND(IDM_REMOTE_OPEN_HIDE, OnRemoteOpenHide) ON_NOTIFY(NM_RCLICK, IDC_LIST_LOCAL, OnRclickListLocal) ON_NOTIFY(NM_RCLICK, IDC_LIST_REMOTE, OnRclickListRemote) ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) ON_MESSAGE(WM_LOCAL_SEARCH_DONE, OnLocalSearchDone) ON_MESSAGE(WM_LOCAL_SEARCH_PROGRESS, OnLocalSearchProgress) //}}AFX_MSG_MAP ON_COMMAND(ID_FILEMANGER_COMPRESS, &CFileManagerDlg::OnFilemangerCompress) ON_COMMAND(ID_FILEMANGER_UNCOMPRESS, &CFileManagerDlg::OnFilemangerUncompress) ON_COMMAND(IDM_TRANSFER_S, &CFileManagerDlg::OnTransferV2ToRemote) ON_COMMAND(IDM_TRANSFER_R, &CFileManagerDlg::OnTransferV2ToLocal) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFileManagerDlg message handlers int GetIconIndex_(LPCTSTR lpFileName, DWORD dwFileAttributes) { SHFILEINFO sfi = {}; if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) dwFileAttributes = FILE_ATTRIBUTE_NORMAL; else dwFileAttributes |= FILE_ATTRIBUTE_NORMAL; SHGetFileInfo ( lpFileName, dwFileAttributes, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES ); return sfi.iIcon; } int GetIconIndex(LPCTSTR lpFileName, DWORD dwFileAttributes) { VLDGlobalDisable(); // 代码中排除: Windows.Storage.dll 内部缓存,不是代码泄漏,是误报。 int index = GetIconIndex_(lpFileName, dwFileAttributes); VLDGlobalEnable(); return index; } BOOL CFileManagerDlg::OnInitDialog() { __super::OnInitDialog(); // 多语言翻译 - Static控件 SetDlgItemText(IDC_STATIC_LOCAL, _TR("本地")); SetDlgItemText(IDC_STATIC_REMOTE, _TR("远程")); // TODO: Add extra initialization here // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon RECT rect; GetClientRect(&rect); /*为真彩工具条添加的代码*/ // 一定要定义工具栏ID,不然RepositionBars会重置工具栏的位置 // ID 定义在AFX_IDW_CONTROLBAR_FIRST AFX_IDW_CONTROLBAR_LAST // 本地工具条 CBRS_TOP 会在工具条上产生一条线 if (!m_wndToolBar_Local.Create(this, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_ANY | CBRS_TOOLTIPS | CBRS_FLYBY, ID_LOCAL_TOOLBAR) ||!m_wndToolBar_Local.LoadToolBar(IDR_TOOLBAR1)) { TRACE0("Failed to create toolbar "); return -1; //Failed to create } m_wndToolBar_Local.ModifyStyle(0, TBSTYLE_FLAT); //Fix for WinXP m_wndToolBar_Local.LoadTrueColorToolBar ( 24, //加载真彩工具条 IDB_TOOLBAR_ENABLE, IDB_TOOLBAR_ENABLE, IDB_TOOLBAR_DISABLE ); // 添加下拉按钮 m_wndToolBar_Local.AddDropDownButton(this, IDT_LOCAL_VIEW, IDR_LOCAL_VIEW); if (!m_wndToolBar_Remote.Create(this, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_ANY | CBRS_TOOLTIPS | CBRS_FLYBY, ID_REMOTE_TOOLBAR) ||!m_wndToolBar_Remote.LoadToolBar(IDR_TOOLBAR2)) { TRACE0("Failed to create toolbar "); return -1; //Failed to create } m_wndToolBar_Remote.ModifyStyle(0, TBSTYLE_FLAT); //Fix for WinXP m_wndToolBar_Remote.LoadTrueColorToolBar ( 24, //加载真彩工具条 IDB_TOOLBAR_ENABLE, IDB_TOOLBAR_ENABLE, IDB_TOOLBAR_DISABLE ); // 添加下拉按钮 m_wndToolBar_Remote.AddDropDownButton(this, IDT_REMOTE_VIEW, IDR_REMOTE_VIEW); //显示工具栏 UpdateWindowsPos(); // 设置标题 CString str; str.FormatL("%s - 文件管理",m_IPAddress); SetWindowText(str); // 为列表视图设置ImageList m_list_local.SetImageList(&(THIS_APP->m_pImageList_Large), LVSIL_NORMAL); m_list_local.SetImageList(&(THIS_APP->m_pImageList_Small), LVSIL_SMALL); // 创建带进度条的状态栏 if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } m_wndStatusBar.SetPaneInfo(0, m_wndStatusBar.GetItemID(0), SBPS_STRETCH, NULL); m_wndStatusBar.SetPaneInfo(1, m_wndStatusBar.GetItemID(1), SBPS_NORMAL, 120); m_wndStatusBar.SetPaneInfo(2, m_wndStatusBar.GetItemID(2), SBPS_NORMAL, 50); RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); //显示状态栏 m_wndStatusBar.GetItemRect(1, &rect); m_ProgressCtrl = new CProgressCtrl; m_ProgressCtrl->Create(PBS_SMOOTH | WS_VISIBLE, rect, &m_wndStatusBar, 1); m_ProgressCtrl->SetRange(0, 100); //设置进度条范围 m_ProgressCtrl->SetPos(20); //设置进度条当前位置 m_list_local.ModifyStyle(FALSE, LVS_REPORT); m_list_remote.ModifyStyle(FALSE, LVS_REPORT); FixedLocalDriveList(); FixedRemoteDriveList(); ///////////////////////////////////////////// //// Set up initial variables m_bDragging = false; m_nDragIndex = -1; m_nDropIndex = -1; CoInitialize(NULL); SHAutoComplete(GetDlgItem(IDC_LOCAL_PATH)->GetWindow(GW_CHILD)->m_hWnd, SHACF_FILESYSTEM); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CFileManagerDlg::OnSize(UINT nType, int cx, int cy) { __super::OnSize(nType, cx, cy); // TODO: Add your message handler code here // 状态栏还没有创建 if (m_wndStatusBar.m_hWnd == NULL) return; // 定位状态栏 RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); //显示工具栏 RECT rect; m_wndStatusBar.GetItemRect(1, &rect); m_ProgressCtrl->MoveWindow(&rect); UpdateWindowsPos(); } void CFileManagerDlg::UpdateWindowsPos() { RECT rect; GetClientRect(&rect); int cx = rect.right - rect.left; int cy = rect.bottom - rect.top; GetDlgItem(IDC_LIST_LOCAL)->MoveWindow(0, 36, cx, (cy - 100) / 2); GetDlgItem(IDC_LIST_REMOTE)->MoveWindow(0, (cy / 2) + 28, cx, (cy - 100) / 2); GetDlgItem(IDC_STATIC_LOCAL)->MoveWindow(10, 10, 25 * m_fScalingFactor, 20); GetDlgItem(IDC_STATIC_REMOTE)->MoveWindow(10, cy / 2, 25 * m_fScalingFactor, 20); GetDlgItem(IDC_LOCAL_PATH)->MoveWindow(56, 5, 210, 12); GetDlgItem(IDC_REMOTE_PATH)->MoveWindow(56, (cy / 2) - 4, 210, 12); //显示工具栏 m_wndToolBar_Local.MoveWindow(268, 0, (rect.right - 268), 48); m_wndToolBar_Remote.MoveWindow(268, (rect.bottom / 2 - 10), (rect.right - 268), 48); } void CFileManagerDlg::FixedLocalDriveList() { // 停止正在进行的本地搜索 if (m_bLocalSearching) { m_bLocalSearching = false; m_bLocalSearchStopped = true; } char DriveString[256]; char *pDrive = NULL; m_list_local.DeleteAllItems(); while(m_list_local.DeleteColumn(0) != 0); m_list_local.InsertColumnL(0, "名称", LVCFMT_LEFT, 200); m_list_local.InsertColumnL(1, "类型", LVCFMT_LEFT, 100); m_list_local.InsertColumnL(2, "总大小", LVCFMT_LEFT, 100); m_list_local.InsertColumnL(3, "可用空间", LVCFMT_LEFT, 115); GetLogicalDriveStrings(sizeof(DriveString), DriveString); pDrive = DriveString; char FileSystem[MAX_PATH]; unsigned __int64 HDAmount = 0; unsigned __int64 HDFreeSpace = 0; unsigned long AmntMB = 0; // 总大小 unsigned long FreeMB = 0; // 剩余空间 for (int i = 0; *pDrive != '\0'; i++, pDrive += lstrlen(pDrive) + 1) { // 得到磁盘相关信息 memset(FileSystem, 0, sizeof(FileSystem)); // 得到文件系统信息及大小 GetVolumeInformation(pDrive, NULL, 0, NULL, NULL, NULL, FileSystem, MAX_PATH); int nFileSystemLen = lstrlen(FileSystem) + 1; if (GetDiskFreeSpaceEx(pDrive, (PULARGE_INTEGER)&HDFreeSpace, (PULARGE_INTEGER)&HDAmount, NULL)) { AmntMB = HDAmount / 1024 / 1024; FreeMB = HDFreeSpace / 1024 / 1024; } else { AmntMB = 0; FreeMB = 0; } int nItem = m_list_local.InsertItem(i, pDrive, GetIconIndex(pDrive, GetFileAttributes(pDrive))); m_list_local.SetItemData(nItem, 1); if (lstrlen(FileSystem) == 0) { SHFILEINFO sfi = {}; SHGetFileInfo(pDrive, FILE_ATTRIBUTE_NORMAL, &sfi,sizeof(SHFILEINFO), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); m_list_local.SetItemText(nItem, 1, sfi.szTypeName); } else { m_list_local.SetItemText(nItem, 1, FileSystem); } CString str; str.FormatL("%10.1f GB", (float)AmntMB / 1024); m_list_local.SetItemText(nItem, 2, str); str.FormatL("%10.1f GB", (float)FreeMB / 1024); m_list_local.SetItemText(nItem, 3, str); } // 重置本地当前路径 m_Local_Path = ""; m_Local_Directory_ComboBox.ResetContent(); ShowMessage(_TRF("本地:装载目录 %s 完成"), m_Local_Path); } void CFileManagerDlg::OnDblclkListLocal(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here if (m_list_local.GetSelectedCount() == 0 || m_list_local.GetItemData(m_list_local.GetSelectionMark()) != 1) return; FixedLocalFileList(); *pResult = 0; } void CFileManagerDlg::FixedLocalFileList(CString directory) { // 导航时停止正在进行的本地搜索 if (m_bLocalSearching) { m_bLocalSearching = false; m_bLocalSearchStopped = true; } if (directory.GetLength() == 0) { int nItem = m_list_local.GetSelectionMark(); // 如果有选中的,是目录 if (nItem != -1) { if (m_list_local.GetItemData(nItem) == 1) { directory = m_list_local.GetItemText(nItem, 0); } } // 从组合框里得到路径 else { m_Local_Directory_ComboBox.GetWindowText(m_Local_Path); } } // 得到父目录 if (directory == "..") { m_Local_Path = GetParentDirectory(m_Local_Path); } // 刷新当前用 else if (directory != ".") { m_Local_Path += directory; if(m_Local_Path.Right(1) != "\\") m_Local_Path += "\\"; } // 是驱动器的根目录,返回磁盘列表 if (m_Local_Path.GetLength() == 0) { FixedLocalDriveList(); return; } m_Local_Directory_ComboBox.InsertStringL(0, m_Local_Path); m_Local_Directory_ComboBox.SetCurSel(0); // 重建标题 m_list_local.DeleteAllItems(); while(m_list_local.DeleteColumn(0) != 0); m_list_local.InsertColumnL(0, "名称", LVCFMT_LEFT, 200); m_list_local.InsertColumnL(1, "大小", LVCFMT_LEFT, 100); m_list_local.InsertColumnL(2, "类型", LVCFMT_LEFT, 100); m_list_local.InsertColumnL(3, "修改日期", LVCFMT_LEFT, 115); int nItemIndex = 0; m_list_local.SetItemData ( m_list_local.InsertItem(nItemIndex++, "..", GetIconIndex(NULL, FILE_ATTRIBUTE_DIRECTORY)), 1 ); // i 为 0 时列目录,i 为 1时列文件 for (int i = 0; i < 2; ++i) { CFileFind file; BOOL bContinue; bContinue = file.FindFile(m_Local_Path + "*.*"); while (bContinue) { bContinue = file.FindNextFile(); if (file.IsDots()) continue; bool bIsInsert = !file.IsDirectory() == i; if (!bIsInsert) continue; int nItem = m_list_local.InsertItem(nItemIndex++, file.GetFileName(), GetIconIndex(file.GetFileName(), GetFileAttributes(file.GetFilePath()))); m_list_local.SetItemData(nItem, file.IsDirectory()); SHFILEINFO sfi = {}; SHGetFileInfo(file.GetFileName(), FILE_ATTRIBUTE_NORMAL, &sfi,sizeof(SHFILEINFO), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); m_list_local.SetItemText(nItem, 2, sfi.szTypeName); CString str; str.FormatL("%10d KB", file.GetLength() / 1024 + (file.GetLength() % 1024 ? 1 : 0)); m_list_local.SetItemText(nItem, 1, str); CTime time; file.GetLastWriteTime(time); m_list_local.SetItemText(nItem, 3, time.FormatL("%Y-%m-%d %H:%M")); } } ShowMessage(_TRF("本地:装载目录 %s 完成"), m_Local_Path); } void CFileManagerDlg::DropItemOnList(CListCtrl* pDragList, CListCtrl* pDropList) { //This routine performs the actual drop of the item dragged. //It simply grabs the info from the Drag list (pDragList) // and puts that info into the list dropped on (pDropList). //Send: pDragList = pointer to CListCtrl we dragged from, // pDropList = pointer to CListCtrl we are dropping on. //Return: nothing. ////Variables // Unhilight the drop target if(pDragList == pDropList) { //we are return return; } //EO if(pDragList... pDropList->SetItemState(m_nDropIndex, 0, LVIS_DROPHILITED); if ((CWnd *)pDropList == &m_list_local) { OnRemoteCopy(); } else if ((CWnd *)pDropList == &m_list_remote) { OnLocalCopy(); } else { // 见鬼了 return; } // 重置 m_nDropIndex = -1; } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CFileManagerDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CFileManagerDlg::OnBegindragListLocal(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here //// Save the index of the item being dragged in m_nDragIndex //// This will be used later for retrieving the info dragged m_nDragIndex = pNMListView->iItem; if (!m_list_local.GetItemText(m_nDragIndex, 0).Compare("..")) return; //We will call delete later (in LButtonUp) to clean this up if(m_list_local.GetSelectedCount() > 1) //more than 1 item in list is selected m_hCursor = THIS_APP->LoadCursor(IDC_CURSOR_MDRAG); else m_hCursor = THIS_APP->LoadCursor(IDC_CURSOR_DRAG); ASSERT(m_hCursor); //make sure it was created //// Change the cursor to the drag image //// (still must perform DragMove() in OnMouseMove() to show it moving) //// Set dragging flag and others m_bDragging = TRUE; //we are in a drag and drop operation m_nDropIndex = -1; //we don't have a drop index yet m_pDragList = &m_list_local; //make note of which list we are dragging from m_pDropWnd = &m_list_local; //at present the drag list is the drop list //// Capture all mouse messages SetCapture(); *pResult = 0; } void CFileManagerDlg::OnBegindragListRemote(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here //// Save the index of the item being dragged in m_nDragIndex //// This will be used later for retrieving the info dragged m_nDragIndex = pNMListView->iItem; if (!m_list_local.GetItemText(m_nDragIndex, 0).Compare("..")) return; //We will call delete later (in LButtonUp) to clean this up if(m_list_remote.GetSelectedCount() > 1) //more than 1 item in list is selected m_hCursor = THIS_APP->LoadCursor(IDC_CURSOR_MDRAG); else m_hCursor = THIS_APP->LoadCursor(IDC_CURSOR_DRAG); ASSERT(m_hCursor); //make sure it was created //// Change the cursor to the drag image //// (still must perform DragMove() in OnMouseMove() to show it moving) //// Set dragging flag and others m_bDragging = TRUE; //we are in a drag and drop operation m_nDropIndex = -1; //we don't have a drop index yet m_pDragList = &m_list_remote; //make note of which list we are dragging from m_pDropWnd = &m_list_remote; //at present the drag list is the drop list //// Capture all mouse messages SetCapture (); *pResult = 0; } void CFileManagerDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //While the mouse is moving, this routine is called. //This routine will redraw the drag image at the present // mouse location to display the dragging. //Also, while over a CListCtrl, this routine will highlight // the item we are hovering over. //// If we are in a drag/drop procedure (m_bDragging is true) if (m_bDragging) { //SetClassLong(m_list_local.m_hWnd, GCL_HCURSOR, (LONG)THIS_APP->LoadCursor(IDC_DRAG)); //// Move the drag image CPoint pt(point); //get our current mouse coordinates ClientToScreen(&pt); //convert to screen coordinates //// Get the CWnd pointer of the window that is under the mouse cursor CWnd* pDropWnd = WindowFromPoint (pt); ASSERT(pDropWnd); //make sure we have a window //// If we drag outside current window we need to adjust the highlights displayed if (pDropWnd != m_pDropWnd) { if (m_nDropIndex != -1) { //If we drag over the CListCtrl header, turn off the hover highlight TRACE("m_nDropIndex is -1\n"); CListCtrl* pList = (CListCtrl*)m_pDropWnd; VERIFY (pList->SetItemState (m_nDropIndex, 0, LVIS_DROPHILITED)); // redraw item VERIFY (pList->RedrawItems (m_nDropIndex, m_nDropIndex)); pList->UpdateWindow (); m_nDropIndex = -1; } } // Save current window pointer as the CListCtrl we are dropping onto m_pDropWnd = pDropWnd; // Convert from screen coordinates to drop target client coordinates pDropWnd->ScreenToClient(&pt); //If we are hovering over a CListCtrl we need to adjust the highlights if(pDropWnd->IsKindOf(RUNTIME_CLASS (CListCtrl))) { //Note that we can drop here SetCursor(m_hCursor); if (m_pDropWnd->m_hWnd == m_pDragList->m_hWnd) return; UINT uFlags; CListCtrl* pList = (CListCtrl*)pDropWnd; // Turn off hilight for previous drop target pList->SetItemState (m_nDropIndex, 0, LVIS_DROPHILITED); // Redraw previous item pList->RedrawItems (m_nDropIndex, m_nDropIndex); // Get the item that is below cursor m_nDropIndex = ((CListCtrl*)pDropWnd)->HitTest(pt, &uFlags); if (m_nDropIndex != -1) { // Highlight it pList->SetItemState(m_nDropIndex, LVIS_DROPHILITED, LVIS_DROPHILITED); // Redraw item pList->RedrawItems(m_nDropIndex, m_nDropIndex); pList->UpdateWindow(); } } else { //If we are not hovering over a CListCtrl, change the cursor // to note that we cannot drop here SetCursor(LoadCursor(NULL, IDC_NO)); } } __super::OnMouseMove(nFlags, point); } void CFileManagerDlg::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //This routine is the end of the drag/drop operation. //When the button is released, we are to drop the item. //There are a few things we need to do to clean up and // finalize the drop: // 1) Release the mouse capture // 2) Set m_bDragging to false to signify we are not dragging // 3) Actually drop the item (we call a separate function to do that) //If we are in a drag and drop operation (otherwise we don't do anything) if (m_bDragging) { // Release mouse capture, so that other controls can get control/messages ReleaseCapture(); // Note that we are NOT in a drag operation m_bDragging = FALSE; CPoint pt (point); //Get current mouse coordinates ClientToScreen (&pt); //Convert to screen coordinates // Get the CWnd pointer of the window that is under the mouse cursor CWnd* pDropWnd = WindowFromPoint (pt); ASSERT (pDropWnd); //make sure we have a window pointer // If window is CListCtrl, we perform the drop if (pDropWnd->IsKindOf (RUNTIME_CLASS (CListCtrl))) { m_pDropList = (CListCtrl*)pDropWnd; //Set pointer to the list we are dropping on DropItemOnList(m_pDragList, m_pDropList); //Call routine to perform the actual drop } } __super::OnLButtonUp(nFlags, point); } BOOL CFileManagerDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_ESCAPE) return true; if (pMsg->wParam == VK_RETURN) { if ( pMsg->hwnd == m_list_local.m_hWnd || pMsg->hwnd == ((CEdit*)m_Local_Directory_ComboBox.GetWindow(GW_CHILD))->m_hWnd ) { FixedLocalFileList(); } else if ( pMsg->hwnd == m_list_remote.m_hWnd || pMsg->hwnd == ((CEdit*)m_Remote_Directory_ComboBox.GetWindow(GW_CHILD))->m_hWnd ) { GetRemoteFileList(); } return TRUE; } } // 单击除了窗口标题栏以外的区域使窗口移动 if (pMsg->message == WM_LBUTTONDOWN && pMsg->hwnd == m_hWnd) { pMsg->message = WM_NCLBUTTONDOWN; pMsg->wParam = HTCAPTION; } /* UINT CFileManagerDlg::OnNcHitTest (Cpoint point ) { UINT nHitTest =Cdialog: : OnNcHitTest (point ) return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest } 上述技术有两点不利之处, 其一是在窗口的客户区域双击时,窗口将极大; 其二, 它不适合包含几个视窗的主框窗口。 */ if(m_wndToolBar_Local.IsWindowVisible()) { CWnd* pWndParent = m_wndToolBar_Local.GetParent(); m_wndToolBar_Local.OnUpdateCmdUI((CFrameWnd*)this, TRUE); } if(m_wndToolBar_Remote.IsWindowVisible()) { CWnd* pWndParent = m_wndToolBar_Remote.GetParent(); m_wndToolBar_Remote.OnUpdateCmdUI((CFrameWnd*)this, TRUE); } return __super::PreTranslateMessage(pMsg); } void CFileManagerDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default m_ProgressCtrl->StepIt(); __super::OnTimer(nIDEvent); } void CFileManagerDlg::FixedRemoteDriveList() { // 加载系统统图标列表 设置驱动器图标列表 HIMAGELIST hImageListLarge = NULL; HIMAGELIST hImageListSmall = NULL; Shell_GetImageLists(&hImageListLarge, &hImageListSmall); ListView_SetImageList(m_list_remote.m_hWnd, hImageListLarge, LVSIL_NORMAL); ListView_SetImageList(m_list_remote.m_hWnd, hImageListSmall, LVSIL_SMALL); m_list_remote.DeleteAllItems(); // 重建Column while(m_list_remote.DeleteColumn(0) != 0); m_list_remote.InsertColumnL(0, "名称", LVCFMT_LEFT, 200); m_list_remote.InsertColumnL(1, "类型", LVCFMT_LEFT, 100); m_list_remote.InsertColumnL(2, "总大小", LVCFMT_LEFT, 100); m_list_remote.InsertColumnL(3, "可用空间", LVCFMT_LEFT, 115); char *pDrive = NULL; pDrive = (char *)m_bRemoteDriveList; unsigned long AmntMB = 0; // 总大小 unsigned long FreeMB = 0; // 剩余空间 //char VolName[MAX_PATH]; //char FileSystem[MAX_PATH]; /* 6 DRIVE_FLOPPY 7 DRIVE_REMOVABLE 8 DRIVE_FIXED 9 DRIVE_REMOTE 10 DRIVE_REMOTE_DISCONNECT 11 DRIVE_CDROM */ int nIconIndex = -1; for (int i = 0; pDrive[i] != '\0';) { if (pDrive[i] == 'A' || pDrive[i] == 'B') { nIconIndex = 6; } else { switch (pDrive[i + 1]) { case DRIVE_REMOVABLE: nIconIndex = 7; break; case DRIVE_FIXED: nIconIndex = 8; break; case DRIVE_REMOTE: nIconIndex = 9; break; case DRIVE_CDROM: nIconIndex = 11; break; default: nIconIndex = 8; break; } } CString str; str.FormatL("%c:\\", pDrive[i]); int nItem = m_list_remote.InsertItem(i, str, nIconIndex); m_list_remote.SetItemData(nItem, 1); memcpy(&AmntMB, pDrive + i + 2, 4); memcpy(&FreeMB, pDrive + i + 6, 4); str.FormatL("%10.1f GB", (float)AmntMB / 1024); m_list_remote.SetItemText(nItem, 2, str); str.FormatL("%10.1f GB", (float)FreeMB / 1024); m_list_remote.SetItemText(nItem, 3, str); i += 10; char *lpFileSystemName = NULL; char *lpTypeName = NULL; lpTypeName = pDrive + i; i += lstrlen(pDrive + i) + 1; lpFileSystemName = pDrive + i; // 磁盘类型, 为空就显示磁盘名称 if (lstrlen(lpFileSystemName) == 0) { m_list_remote.SetItemText(nItem, 1, lpTypeName); } else { m_list_remote.SetItemText(nItem, 1, lpFileSystemName); } i += lstrlen(pDrive + i) + 1; } // 重置远程当前路径 m_Remote_Path = ""; m_Remote_Directory_ComboBox.ResetContent(); ShowMessage(_TRF("远程:装载目录 %s 完成"), m_Remote_Path); } void CFileManagerDlg::OnClose() { CancelIO(); // 等待数据处理完毕 if (IsProcessing()) { ShowWindow(SW_HIDE); return; } CoUninitialize(); DialogBase::OnClose(); } CString CFileManagerDlg::GetParentDirectory(CString strPath) { CString strCurPath = strPath; int Index = strCurPath.ReverseFind('\\'); if (Index == -1) { return strCurPath; } CString str = strCurPath.Left(Index); Index = str.ReverseFind('\\'); if (Index == -1) { strCurPath = ""; return strCurPath; } strCurPath = str.Left(Index); if(strCurPath.Right(1) != "\\") strCurPath += "\\"; return strCurPath; } void CFileManagerDlg::OnReceiveComplete() { switch (m_ContextObject->m_DeCompressionBuffer.GetBuffer(0)[0]) { case TOKEN_FILE_LIST: // 文件列表 try { FixedRemoteFileList ( m_ContextObject->m_DeCompressionBuffer.GetBuffer(0), m_ContextObject->m_DeCompressionBuffer.GetBufferLen() - 1 ); } catch (CMemoryException* e) { char err[256]; e->GetErrorMessage(err, sizeof(err)); Mprintf("[ERROR] CMemoryException: %s\n", err); } catch (CFileException* e) { char err[256]; e->GetErrorMessage(err, sizeof(err)); Mprintf("[ERROR] CFileException: %s\n", err); } catch (CException* e) { char err[256]; e->GetErrorMessage(err, sizeof(err)); Mprintf("[ERROR] CException: %s\n", err); } catch (...) { Mprintf("[ERROR] Other exception\n"); } break; case TOKEN_FILE_SIZE: // 传输文件时的第一个数据包,文件大小,及文件名 CreateLocalRecvFile(); break; case TOKEN_FILE_DATA: // 文件内容 WriteLocalRecvFile(); break; case TOKEN_TRANSFER_FINISH: // 传输完成 EndLocalRecvFile(); break; case TOKEN_CREATEFOLDER_FINISH: GetRemoteFileList("."); break; case TOKEN_DELETE_FINISH: EndRemoteDeleteFile(); break; case TOKEN_GET_TRANSFER_MODE: SendTransferMode(); break; case TOKEN_DATA_CONTINUE: SendFileData(); break; case TOKEN_RENAME_FINISH: // 刷新远程文件列表 GetRemoteFileList("."); break; case TOKEN_SEARCH_FILE_LIST: // 搜索结果列表 if (m_bSearchStopped) break; // 已停止,丢弃在途数据 try { FixedRemoteSearchFileList ( m_ContextObject->m_DeCompressionBuffer.GetBuffer(0), m_ContextObject->m_DeCompressionBuffer.GetBufferLen() - 1 ); } catch (...) { Mprintf("[ERROR] Search list exception\n"); } break; case TOKEN_SEARCH_FILE_FINISH: // 搜索完成 if (m_bSearchStopped) { m_bSearchStopped = false; // 收到结束标记,重置停止标志 break; } m_bSearching = false; m_list_remote.EnableWindow(TRUE); { DWORD dwElapsed = (GetTickCount() - m_dwSearchStartTime) / 1000; ShowMessage(_TRF("搜索 \"%s\" 在 %s 完成,共 %d 个结果 (耗时 %d秒)"), m_strSearchName, m_strSearchPath, m_nSearchResultCount, dwElapsed); } break; default: SendException(); break; } } void CFileManagerDlg::GetRemoteFileList(CString directory) { // 导航到目录时停止正在进行的远程搜索 if (m_bSearching) { BYTE bStop = COMMAND_FILES_SEARCH_STOP; m_ContextObject->Send2Client(&bStop, 1); m_bSearching = false; m_bSearchStopped = true; // 丢弃在途搜索数据 } if (directory.GetLength() == 0) { int nItem = m_list_remote.GetSelectionMark(); // 如果有选中的,是目录 if (nItem != -1) { if (m_list_remote.GetItemData(nItem) == 1) { directory = m_list_remote.GetItemText(nItem, 0); } } // 从组合框里得到路径 else { m_Remote_Directory_ComboBox.GetWindowText(m_Remote_Path); } } // 得到父目录 if (directory == "..") { m_Remote_Path = GetParentDirectory(m_Remote_Path); } else if (directory != ".") { m_Remote_Path += directory; if(m_Remote_Path.Right(1) != "\\") m_Remote_Path += "\\"; } // 是驱动器的根目录,返回磁盘列表 if (m_Remote_Path.GetLength() == 0) { FixedRemoteDriveList(); return; } // 发送数据前清空缓冲区 int PacketSize = m_Remote_Path.GetLength() + 2; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, PacketSize); bPacket[0] = COMMAND_LIST_FILES; memcpy(bPacket + 1, m_Remote_Path.GetBuffer(0), PacketSize - 1); m_ContextObject->Send2Client(bPacket, PacketSize); LocalFree(bPacket); m_Remote_Directory_ComboBox.InsertStringL(0, m_Remote_Path); m_Remote_Directory_ComboBox.SetCurSel(0); // 得到返回数据前禁窗口 m_list_remote.EnableWindow(FALSE); m_ProgressCtrl->SetPos(0); } void CFileManagerDlg::OnDblclkListRemote(NMHDR* pNMHDR, LRESULT* pResult) { if (m_list_remote.GetSelectedCount() == 0 || m_list_remote.GetItemData(m_list_remote.GetSelectionMark()) != 1) return; // TODO: Add your control notification handler code here GetRemoteFileList(); *pResult = 0; } void CFileManagerDlg::FixedRemoteFileList(BYTE *pbBuffer, DWORD dwBufferLen) { // 重新设置ImageList SHFILEINFO sfi = {}; HIMAGELIST hImageListLarge = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi,sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON); HIMAGELIST hImageListSmall = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi,sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON); ListView_SetImageList(m_list_remote.m_hWnd, hImageListLarge, LVSIL_NORMAL); ListView_SetImageList(m_list_remote.m_hWnd, hImageListSmall, LVSIL_SMALL); // 重建标题 m_list_remote.DeleteAllItems(); while(m_list_remote.DeleteColumn(0) != 0); m_list_remote.InsertColumnL(0, "名称", LVCFMT_LEFT, 200); m_list_remote.InsertColumnL(1, "大小", LVCFMT_LEFT, 100); m_list_remote.InsertColumnL(2, "类型", LVCFMT_LEFT, 100); m_list_remote.InsertColumnL(3, "修改日期", LVCFMT_LEFT, 115); int nItemIndex = 0; m_list_remote.SetItemData ( m_list_remote.InsertItem(nItemIndex++, "..", GetIconIndex(NULL, FILE_ATTRIBUTE_DIRECTORY)), 1 ); /* ListView 消除闪烁 更新数据前用SetRedraw(FALSE) 更新后调用SetRedraw(TRUE) */ m_list_remote.SetRedraw(FALSE); if (dwBufferLen != 0) { // for (int i = 0; i < 2; ++i) { // 跳过Token,共5字节 char *pList = (char *)(pbBuffer + 1); for(char *pBase = pList; pList - pBase < dwBufferLen - 1;) { char *pszFileName = NULL; DWORD dwFileSizeHigh = 0; // 文件高字节大小 DWORD dwFileSizeLow = 0; // 文件低字节大小 int nItem = 0; bool bIsInsert = false; FILETIME ftm_strReceiveLocalFileTime; int nType = *pList ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; // i 为 0 时,列目录,i为1时列文件 bIsInsert = !(nType == FILE_ATTRIBUTE_DIRECTORY) == i; pszFileName = ++pList; if (bIsInsert) { nItem = m_list_remote.InsertItem(nItemIndex++, pszFileName, GetIconIndex(pszFileName, nType)); m_list_remote.SetItemData(nItem, nType == FILE_ATTRIBUTE_DIRECTORY); SHFILEINFO sfi = {}; SHGetFileInfo(pszFileName, FILE_ATTRIBUTE_NORMAL | nType, &sfi,sizeof(SHFILEINFO), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); m_list_remote.SetItemText(nItem, 2, sfi.szTypeName); } // 得到文件大小 pList += lstrlen(pszFileName) + 1; if (bIsInsert) { memcpy(&dwFileSizeHigh, pList, 4); memcpy(&dwFileSizeLow, pList + 4, 4); CString strSize; strSize.FormatL("%10d KB", (dwFileSizeHigh * (MAXDWORD+long long(1))) / 1024 + dwFileSizeLow / 1024 + (dwFileSizeLow % 1024 ? 1 : 0)); m_list_remote.SetItemText(nItem, 1, strSize); memcpy(&ftm_strReceiveLocalFileTime, pList + 8, sizeof(FILETIME)); CTime time(ftm_strReceiveLocalFileTime); m_list_remote.SetItemText(nItem, 3, time.FormatL("%Y-%m-%d %H:%M")); } pList += 16; } } } m_list_remote.SetRedraw(TRUE); // 恢复窗口 m_list_remote.EnableWindow(TRUE); ShowMessage(_TRF("远程:装载目录 %s 完成"), m_Remote_Path); } void CFileManagerDlg::FixedRemoteSearchFileList(BYTE *pbBuffer, DWORD dwBufferLen) { // 第一批结果到达时,初始化搜索列表 if (!m_bSearching) { m_bSearching = true; m_nSearchResultCount = 0; m_IconCache.clear(); // 预缓存文件夹图标 m_IconCache["*folder*"] = GetIconIndex(NULL, FILE_ATTRIBUTE_DIRECTORY); // 重新设置ImageList SHFILEINFO sfi = {}; HIMAGELIST hImageListLarge = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON); HIMAGELIST hImageListSmall = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON); ListView_SetImageList(m_list_remote.m_hWnd, hImageListLarge, LVSIL_NORMAL); ListView_SetImageList(m_list_remote.m_hWnd, hImageListSmall, LVSIL_SMALL); // 重建标题 (搜索模式: 名称、大小、修改日期、路径) m_list_remote.DeleteAllItems(); while (m_list_remote.DeleteColumn(0) != 0); m_list_remote.InsertColumnL(0, "名称", LVCFMT_LEFT, 180); m_list_remote.InsertColumnL(1, "大小", LVCFMT_LEFT, 90); m_list_remote.InsertColumnL(2, "修改日期", LVCFMT_LEFT, 115); m_list_remote.InsertColumnL(3, "路径", LVCFMT_LEFT, 220); } m_list_remote.SetRedraw(FALSE); if (dwBufferLen != 0) { char *pList = (char *)(pbBuffer + 1); for (char *pBase = pList; pList - pBase < (int)(dwBufferLen - 1);) { int nType = *pList ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; char *pszFullPath = ++pList; // 从完整路径中提取文件名 CString csFullPath(pszFullPath); int nPos = csFullPath.ReverseFind('\\'); CString csFileName = (nPos >= 0) ? csFullPath.Right(csFullPath.GetLength() - nPos - 1) : csFullPath; CString csDir = (nPos >= 0) ? csFullPath.Left(nPos) : ""; // 按扩展名缓存图标,避免重复调用SHGetFileInfo int nIcon; if (nType == FILE_ATTRIBUTE_DIRECTORY) { nIcon = m_IconCache["*folder*"]; } else { CString csExt; int nDot = csFileName.ReverseFind('.'); csExt = (nDot >= 0) ? csFileName.Mid(nDot) : "*noext*"; csExt.MakeLower(); auto it = m_IconCache.find((LPCSTR)csExt); if (it != m_IconCache.end()) { nIcon = it->second; } else { nIcon = GetIconIndex((LPCSTR)csExt, nType); m_IconCache[(LPCSTR)csExt] = nIcon; } } int nItem = m_list_remote.InsertItem(m_nSearchResultCount, csFileName, nIcon); m_list_remote.SetItemData(nItem, nType == FILE_ATTRIBUTE_DIRECTORY); pList += lstrlen(pszFullPath) + 1; // 文件大小 DWORD dwFileSizeHigh = 0, dwFileSizeLow = 0; memcpy(&dwFileSizeHigh, pList, 4); memcpy(&dwFileSizeLow, pList + 4, 4); CString strSize; strSize.FormatL("%10d KB", (dwFileSizeHigh * (MAXDWORD + long long(1))) / 1024 + dwFileSizeLow / 1024 + (dwFileSizeLow % 1024 ? 1 : 0)); m_list_remote.SetItemText(nItem, 1, strSize); // 修改日期 FILETIME ftLastWrite; memcpy(&ftLastWrite, pList + 8, sizeof(FILETIME)); CTime time(ftLastWrite); m_list_remote.SetItemText(nItem, 2, time.FormatL("%Y-%m-%d %H:%M")); // 路径 m_list_remote.SetItemText(nItem, 3, csDir); pList += 16; m_nSearchResultCount++; } } m_list_remote.SetRedraw(TRUE); DWORD dwElapsed = (GetTickCount() - m_dwSearchStartTime) / 1000; ShowMessage(_TRF("搜索 \"%s\" 在 %s ... 已找到 %d 个 (%d秒)"), m_strSearchName, m_strSearchPath, m_nSearchResultCount, dwElapsed); } void CFileManagerDlg::ShowMessage(const char *lpFmt, ...) { char *buff = new char[1024]; va_list arglist; va_start( arglist, lpFmt ); memset(buff, 0, 1024); vsprintf(buff, lpFmt, arglist); // fix: 多线程操作控件引发崩溃的问题 // m_wndStatusBar.SetPaneText(0, buff); // msg 第1个参数为缓存大小,第2个参数为缓存指针 SendMessage(WM_MY_MESSAGE, 1024, (LPARAM)buff); va_end( arglist ); } void CFileManagerDlg::OnLocalPrev() { // TODO: Add your command handler code here FixedLocalFileList(".."); } void CFileManagerDlg::OnRemotePrev() { // TODO: Add your command handler code here GetRemoteFileList(".."); } void CFileManagerDlg::OnLocalDesktop() { char path[MAX_PATH]; if (SHGetSpecialFolderPathA(m_hWnd, path, CSIDL_DESKTOPDIRECTORY, FALSE)) { m_Local_Path = path; if (m_Local_Path.Right(1) != "\\") m_Local_Path += "\\"; FixedLocalFileList("."); } } void CFileManagerDlg::OnLocalDownloads() { char path[MAX_PATH]; if (SHGetSpecialFolderPathA(m_hWnd, path, CSIDL_PROFILE, FALSE)) { m_Local_Path.Format("%s\\Downloads\\", path); FixedLocalFileList("."); } } void CFileManagerDlg::OnLocalHome() { char path[MAX_PATH]; if (SHGetSpecialFolderPathA(m_hWnd, path, CSIDL_PROFILE, FALSE)) { m_Local_Path = path; if (m_Local_Path.Right(1) != "\\") m_Local_Path += "\\"; FixedLocalFileList("."); } } // 通配符匹配 (支持 * 和 ?, 大小写不敏感) bool CFileManagerDlg::WildcardMatch(LPCTSTR pattern, LPCTSTR str) { while (*pattern) { if (*pattern == '*') { pattern++; if (!*pattern) return true; while (*str) { if (WildcardMatch(pattern, str)) return true; str++; } return false; } else if (*pattern == '?') { if (!*str) return false; pattern++; str++; } else { if (tolower((unsigned char)*pattern) != tolower((unsigned char)*str)) return false; pattern++; str++; } } return *str == '\0'; } #define LOCAL_SEARCH_MAX_DEPTH 32 #define LOCAL_SEARCH_MAX_RESULTS 10000 struct LocalSearchContext { CFileManagerDlg *pDlg; CString searchPath; CString searchName; }; static bool LocalShouldSkipDirectory(DWORD dwAttributes) { if ((dwAttributes & FILE_ATTRIBUTE_HIDDEN) && (dwAttributes & FILE_ATTRIBUTE_SYSTEM)) return true; if (dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT) return true; return false; } DWORD WINAPI CFileManagerDlg::LocalSearchThreadProc(LPVOID lpParam) { LocalSearchContext *pCtx = (LocalSearchContext *)lpParam; pCtx->pDlg->LocalSearchWorker(); delete pCtx; return 0; } void CFileManagerDlg::LocalSearchWorker() { char szPattern[MAX_PATH]; if (m_strLocalSearchName.Find('*') < 0 && m_strLocalSearchName.Find('?') < 0) wsprintf(szPattern, "*%s*", (LPCSTR)m_strLocalSearchName); else lstrcpy(szPattern, (LPCSTR)m_strLocalSearchName); struct SearchDir { CString path; int depth; }; std::vector dirStack; dirStack.push_back({m_strLocalSearchPath, 0}); auto *pResults = new std::vector(); DWORD dwLastProgressTime = GetTickCount(); int nLastProgressCount = 0; while (!dirStack.empty() && m_bLocalSearching && (int)pResults->size() < LOCAL_SEARCH_MAX_RESULTS) { SearchDir cur = dirStack.back(); dirStack.pop_back(); if (cur.depth > LOCAL_SEARCH_MAX_DEPTH) continue; WIN32_FIND_DATA fd; HANDLE hFind = FindFirstFile(cur.path + "*.*", &fd); if (hFind == INVALID_HANDLE_VALUE) continue; std::vector subdirs; do { if (!m_bLocalSearching) break; if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0) continue; BOOL bIsDir = fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; if (WildcardMatch(szPattern, fd.cFileName) && (int)pResults->size() < LOCAL_SEARCH_MAX_RESULTS) { LocalSearchItem item; item.fileName = fd.cFileName; item.dir = cur.path; item.bIsDir = bIsDir; int nDot = item.fileName.ReverseFind('.'); item.ext = bIsDir ? "*folder*" : ((nDot >= 0) ? item.fileName.Mid(nDot) : "*noext*"); item.ext.MakeLower(); item.sizeHigh = fd.nFileSizeHigh; item.sizeLow = fd.nFileSizeLow; item.ftWrite = fd.ftLastWriteTime; pResults->push_back(item); } if (bIsDir && !LocalShouldSkipDirectory(fd.dwFileAttributes)) subdirs.push_back({cur.path + fd.cFileName + "\\", cur.depth + 1}); } while (FindNextFile(hFind, &fd)); FindClose(hFind); for (int i = (int)subdirs.size() - 1; i >= 0; i--) dirStack.push_back(subdirs[i]); // 数量增加500+或距上次更新超过2秒,则更新进度 int nCount = (int)pResults->size(); DWORD dwNow = GetTickCount(); if (nCount - nLastProgressCount >= 500 || (nCount > nLastProgressCount && dwNow - dwLastProgressTime >= 2000)) { ::PostMessage(m_hWnd, WM_LOCAL_SEARCH_PROGRESS, (WPARAM)nCount, 0); nLastProgressCount = nCount; dwLastProgressTime = dwNow; } } // 搜索完成,将所有结果一次性发送给UI线程 // wParam: 1=正常完成, 0=被停止 BOOL bCompleted = dirStack.empty() || (int)pResults->size() >= LOCAL_SEARCH_MAX_RESULTS; ::SendMessage(m_hWnd, WM_LOCAL_SEARCH_DONE, bCompleted, (LPARAM)pResults); } LRESULT CFileManagerDlg::OnLocalSearchProgress(WPARAM wParam, LPARAM lParam) { if (!m_bLocalSearching || m_bLocalSearchStopped) return 0; DWORD dwElapsed = (GetTickCount() - m_dwLocalSearchStartTime) / 1000; ShowMessage(_TRF("搜索 \"%s\" 在 %s ... 已找到 %d 个 (%d秒)"), m_strLocalSearchName, m_strLocalSearchPath, (int)wParam, dwElapsed); return 0; } LRESULT CFileManagerDlg::OnLocalSearchDone(WPARAM wParam, LPARAM lParam) { auto *pResults = (std::vector *)lParam; // 搜索被停止或已导航离开,丢弃结果 if (m_bLocalSearchStopped) { delete pResults; return 0; } // 插入所有结果 m_list_local.SetRedraw(FALSE); for (size_t i = 0; i < pResults->size(); i++) { const LocalSearchItem &item = (*pResults)[i]; int nType = item.bIsDir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; int nIcon; auto it = m_LocalIconCache.find((LPCSTR)item.ext); if (it != m_LocalIconCache.end()) { nIcon = it->second; } else { nIcon = GetIconIndex((LPCSTR)item.ext, nType); m_LocalIconCache[(LPCSTR)item.ext] = nIcon; } int nItem = m_list_local.InsertItem(m_nLocalSearchResultCount, item.fileName, nIcon); m_list_local.SetItemData(nItem, item.bIsDir ? 1 : 0); CString strSize; __int64 fileSize = ((__int64)item.sizeHigh << 32) | item.sizeLow; strSize.Format("%10d KB", (int)(fileSize / 1024 + (fileSize % 1024 ? 1 : 0))); m_list_local.SetItemText(nItem, 1, strSize); CTime time(item.ftWrite); m_list_local.SetItemText(nItem, 2, time.Format("%Y-%m-%d %H:%M")); CString dir = item.dir; if (dir.GetLength() > 3 && dir.Right(1) == "\\") dir = dir.Left(dir.GetLength() - 1); m_list_local.SetItemText(nItem, 3, dir); m_nLocalSearchResultCount++; } m_list_local.SetRedraw(TRUE); DWORD dwElapsed = (GetTickCount() - m_dwLocalSearchStartTime) / 1000; if (wParam) // 正常完成 ShowMessage(_TRF("搜索 \"%s\" 在 %s 完成,共 %d 个结果 (耗时 %d秒)"), m_strLocalSearchName, m_strLocalSearchPath, m_nLocalSearchResultCount, dwElapsed); else // 被停止 ShowMessage(_TRF("搜索 \"%s\" 在 %s 已停止,共 %d 个结果 (耗时 %d秒)"), m_strLocalSearchName, m_strLocalSearchPath, m_nLocalSearchResultCount, dwElapsed); m_bLocalSearching = false; m_list_local.EnableWindow(TRUE); delete pResults; return 0; } void CFileManagerDlg::OnLocalSearch() { CInputDlg dlg(this); dlg.Init(_TR("搜索文件"), _TR("请输入搜索关键词")); if (dlg.DoModal() == IDOK && !dlg.m_str.IsEmpty()) { if (m_Local_Path.GetLength() == 0) return; // 停止远程搜索 if (m_bSearching) { m_bSearchStopped = true; m_bSearching = false; m_list_remote.EnableWindow(TRUE); BYTE bStop = COMMAND_FILES_SEARCH_STOP; m_ContextObject->Send2Client(&bStop, 1); } // 停止上一次本地搜索 if (m_bLocalSearching) { m_bLocalSearching = false; m_bLocalSearchStopped = true; } // 等待旧线程结束 (同时处理消息避免SendMessage死锁) if (m_hLocalSearchThread) { while (MsgWaitForMultipleObjects(1, &m_hLocalSearchThread, FALSE, 5000, QS_ALLINPUT) == WAIT_OBJECT_0 + 1) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } CloseHandle(m_hLocalSearchThread); m_hLocalSearchThread = NULL; } // 重置状态 m_bLocalSearching = true; m_bLocalSearchStopped = false; m_nLocalSearchResultCount = 0; m_dwLocalSearchStartTime = GetTickCount(); m_strLocalSearchPath = m_Local_Path; m_strLocalSearchName = dlg.m_str; m_LocalIconCache.clear(); m_LocalIconCache["*folder*"] = GetIconIndex(NULL, FILE_ATTRIBUTE_DIRECTORY); // 初始化列表列 (搜索模式: 名称、大小、修改日期、路径) SHFILEINFO sfi = {}; HIMAGELIST hImageListLarge = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON); HIMAGELIST hImageListSmall = (HIMAGELIST)SHGetFileInfo(NULL, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON); ListView_SetImageList(m_list_local.m_hWnd, hImageListLarge, LVSIL_NORMAL); ListView_SetImageList(m_list_local.m_hWnd, hImageListSmall, LVSIL_SMALL); m_list_local.DeleteAllItems(); while (m_list_local.DeleteColumn(0) != 0); m_list_local.InsertColumnL(0, "名称", LVCFMT_LEFT, 180); m_list_local.InsertColumnL(1, "大小", LVCFMT_LEFT, 90); m_list_local.InsertColumnL(2, "修改日期", LVCFMT_LEFT, 115); m_list_local.InsertColumnL(3, "路径", LVCFMT_LEFT, 220); m_list_local.EnableWindow(FALSE); ShowMessage(_TRF("正在搜索 \"%s\" 在 %s ..."), m_strLocalSearchName, m_strLocalSearchPath); // 启动搜索线程 LocalSearchContext *pCtx = new LocalSearchContext; pCtx->pDlg = this; m_hLocalSearchThread = CreateThread(NULL, 0, LocalSearchThreadProc, (LPVOID)pCtx, 0, NULL); } } void CFileManagerDlg::OnRemoteDesktop() { m_Remote_Path = "%USERPROFILE%\\Desktop\\"; GetRemoteFileList("."); } void CFileManagerDlg::OnRemoteDownloads() { m_Remote_Path = "%USERPROFILE%\\Downloads\\"; GetRemoteFileList("."); } void CFileManagerDlg::OnRemoteHome() { m_Remote_Path = "%USERPROFILE%\\"; GetRemoteFileList("."); } void CFileManagerDlg::OnRemoteSearch() { // 停止本地搜索 if (m_bLocalSearching) { m_bLocalSearching = false; m_bLocalSearchStopped = true; m_list_local.EnableWindow(TRUE); } // 如果正在远程搜索,先停止 if (m_bSearching) { BYTE bStop = COMMAND_FILES_SEARCH_STOP; m_ContextObject->Send2Client(&bStop, 1); m_bSearching = false; } CInputDlg dlg(this); dlg.Init(_TR("搜索文件"), _TR("请输入搜索关键词")); if (dlg.DoModal() == IDOK && !dlg.m_str.IsEmpty()) { if (m_Remote_Path.GetLength() == 0) return; // 重置搜索状态 (m_bSearching 将在第一个 TOKEN_SEARCH_FILE_LIST 到达时设为 true) m_bSearching = false; m_bSearchStopped = false; m_nSearchResultCount = 0; m_dwSearchStartTime = GetTickCount(); // 构建搜索数据包: [COMMAND_SEARCH_FILE][SearchPath\0][SearchFileName\0] CString searchPath = m_Remote_Path; CString searchName = dlg.m_str; m_strSearchPath = searchPath; m_strSearchName = searchName; int nPathLen = searchPath.GetLength() + 1; int nNameLen = searchName.GetLength() + 1; int nPacketSize = 1 + nPathLen + nNameLen; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, nPacketSize); bPacket[0] = COMMAND_SEARCH_FILE; memcpy(bPacket + 1, searchPath.GetBuffer(0), nPathLen); memcpy(bPacket + 1 + nPathLen, searchName.GetBuffer(0), nNameLen); m_ContextObject->Send2Client(bPacket, nPacketSize); LocalFree(bPacket); m_list_remote.EnableWindow(FALSE); ShowMessage(_TRF("正在搜索 %s ..."), searchName); } } void CFileManagerDlg::OnLocalView() { // TODO: Add your command handler code here m_list_local.ModifyStyle(LVS_TYPEMASK, LVS_ICON); } // 在工具栏上显示ToolTip BOOL CFileManagerDlg::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) { ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW); //让上一层的边框窗口优先处理该消息 if (GetRoutingFrame() != NULL) return FALSE; //分ANSI and UNICODE两个处理版本 TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; TCHAR szFullText[256]; CString strTipText; UINT_PTR nID = pNMHDR->idFrom; //如果idFrom是一个子窗口,则得到其ID。 if ( pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) || pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND) ) { //idFrom是工具条的句柄 nID = ::GetDlgCtrlID((HWND)nID); } if (nID != 0) { //若是0,为一分隔栏,不是按钮 //得到nID对应的字符串 AfxLoadString(nID, szFullText); //从上面得到的字符串中取出Tooltip使用的文本 AfxExtractSubString(strTipText, szFullText, 1, '\n'); } //复制分离出的文本 #ifndef _UNICODE if (pNMHDR->code == TTN_NEEDTEXTA) lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText)); else _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText)); #else if (pNMHDR->code == TTN_NEEDTEXTA) _wcstombsz(pTTTA->szText, strTipText, sizeof(pTTTA->szText)); else lstrcpyn(pTTTW->szText, strTipText, sizeof(pTTTW->szText)); #endif *pResult = 0; //显示Tooltip窗口 ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE); return TRUE; //消息处理完毕 } //////////////////////////////////以下为工具栏响应处理////////////////////////////////////////// void CFileManagerDlg::OnLocalList() { // TODO: Add your command handler code here m_list_local.ModifyStyle(LVS_TYPEMASK, LVS_LIST); } void CFileManagerDlg::OnLocalReport() { // TODO: Add your command handler code here m_list_local.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); } void CFileManagerDlg::OnLocalBigicon() { // TODO: Add your command handler code here m_list_local.ModifyStyle(LVS_TYPEMASK, LVS_ICON); } void CFileManagerDlg::OnLocalSmallicon() { // TODO: Add your command handler code here m_list_local.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON); } void CFileManagerDlg::OnRemoteList() { // TODO: Add your command handler code here m_list_remote.ModifyStyle(LVS_TYPEMASK, LVS_LIST); } void CFileManagerDlg::OnRemoteReport() { // TODO: Add your command handler code here m_list_remote.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); } void CFileManagerDlg::OnRemoteBigicon() { // TODO: Add your command handler code here m_list_remote.ModifyStyle(LVS_TYPEMASK, LVS_ICON); } void CFileManagerDlg::OnRemoteSmallicon() { // TODO: Add your command handler code here m_list_remote.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON); } void CFileManagerDlg::OnRemoteView() { // TODO: Add your command handler code here m_list_remote.ModifyStyle(LVS_TYPEMASK, LVS_ICON); } // 为根目录时禁用向上按钮 void CFileManagerDlg::OnUpdateLocalPrev(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(m_Local_Path.GetLength() && m_list_local.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateLocalDelete(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here // 不是根目录,并且选择项目大于0 pCmdUI->Enable(m_Local_Path.GetLength() && m_list_local.GetSelectedCount() && m_list_local.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateLocalNewfolder(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(m_Local_Path.GetLength() && m_list_local.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateLocalSearch(CCmdUI* pCmdUI) { // 有本地路径、列表可用、且没有搜索正在进行 pCmdUI->Enable(m_Local_Path.GetLength() && m_list_local.IsWindowEnabled() && !m_bLocalSearching && !m_bSearching); } void CFileManagerDlg::OnUpdateRemoteSearch(CCmdUI* pCmdUI) { // 有远程路径、列表可用、且没有搜索正在进行 pCmdUI->Enable(m_Remote_Path.GetLength() && m_list_remote.IsWindowEnabled() && !m_bSearching && !m_bLocalSearching); } void CFileManagerDlg::OnUpdateLocalCopy(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable ( m_list_local.IsWindowEnabled() && (m_Remote_Path.GetLength() || m_list_remote.GetSelectedCount()) // 远程路径为空,或者有选择 && m_list_local.GetSelectedCount()// 本地路径为空,或者有选择 ); } void CFileManagerDlg::OnUpdateLocalStop(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable((!m_list_local.IsWindowEnabled() && m_bIsUpload) || m_bLocalSearching); } void CFileManagerDlg::OnUpdateRemotePrev(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(m_Remote_Path.GetLength() && m_list_remote.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateRemoteCopy(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here // 不是根目录,并且选择项目大于0 pCmdUI->Enable ( m_list_remote.IsWindowEnabled() && (m_Local_Path.GetLength() || m_list_local.GetSelectedCount()) // 本地路径为空,或者有选择 && m_list_remote.GetSelectedCount() // 远程路径为空,或者有选择 ); } void CFileManagerDlg::OnUpdateRemoteDelete(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here // 不是根目录,并且选择项目大于0 pCmdUI->Enable(m_Remote_Path.GetLength() && m_list_remote.GetSelectedCount() && m_list_remote.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateRemoteNewfolder(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(m_Remote_Path.GetLength() && m_list_remote.IsWindowEnabled()); } void CFileManagerDlg::OnUpdateRemoteStop(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable((!m_list_remote.IsWindowEnabled() && !m_bIsUpload) || m_bSearching); } bool CFileManagerDlg::FixedUploadDirectory(LPCTSTR lpPathName) { char lpszFilter[MAX_PATH]; char *lpszSlash = NULL; memset(lpszFilter, 0, sizeof(lpszFilter)); if (lpPathName[lstrlen(lpPathName) - 1] != '\\') lpszSlash = "\\"; else lpszSlash = ""; wsprintf(lpszFilter, "%s%s*.*", lpPathName, lpszSlash); WIN32_FIND_DATA wfd; HANDLE hFind = FindFirstFile(lpszFilter, &wfd); if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败 return FALSE; do { if (wfd.cFileName[0] == '.') continue; // 过滤这两个目录 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { char strDirectory[MAX_PATH]; wsprintf(strDirectory, "%s%s%s", lpPathName, lpszSlash, wfd.cFileName); FixedUploadDirectory(strDirectory); // 如果找到的是目录,则进入此目录进行递归 } else { CString file; file.FormatL("%s%s%s", lpPathName, lpszSlash, wfd.cFileName); //Mprintf("send file %s\n",strFile); m_Remote_Upload_Job.AddTail(file); // 对文件进行操作 } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); // 关闭查找句柄 return true; } void CFileManagerDlg::EnableControl(BOOL bEnable) { m_list_local.EnableWindow(bEnable); m_list_remote.EnableWindow(bEnable); m_Local_Directory_ComboBox.EnableWindow(bEnable); m_Remote_Directory_ComboBox.EnableWindow(bEnable); } void CFileManagerDlg::OnLocalCopy() { m_bIsUpload = true; // TODO: Add your command handler code here // TODO: Add your command handler code here // 如果Drag的,找到Drop到了哪个文件夹 if (m_nDropIndex != -1 && m_pDropList->GetItemData(m_nDropIndex)) m_hCopyDestFolder = m_pDropList->GetItemText(m_nDropIndex, 0); // 重置上传任务列表 m_Remote_Upload_Job.RemoveAll(); POSITION pos = m_list_local.GetFirstSelectedItemPosition(); //iterator for the CListCtrl while(pos) { //so long as we have a valid POSITION, we keep iterating int nItem = m_list_local.GetNextSelectedItem(pos); CString file = m_Local_Path + m_list_local.GetItemText(nItem, 0); // 如果是目录 if (m_list_local.GetItemData(nItem)) { file += '\\'; FixedUploadDirectory(file.GetBuffer(0)); } else { // 添加到上传任务列表中去 m_Remote_Upload_Job.AddTail(file); } } //EO while(pos) -- at this point we have deleted the moving items and stored them in memory if (m_Remote_Upload_Job.IsEmpty()) { MessageBoxAPI_L(m_hWnd, "文件夹为空", "警告", MB_OK|MB_ICONWARNING); return; } EnableControl(FALSE); SendUploadJob(); } void CFileManagerDlg::OnLocalCompress() { std::vector paths; POSITION pos = m_list_local.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_local.GetNextSelectedItem(pos); CString file = m_Local_Path + m_list_local.GetItemText(nItem, 0); // 如果是目录 if (m_list_local.GetItemData(nItem)) { file += '\\'; } paths.push_back(file.GetBuffer(0)); } std::string target = m_Local_Path.GetString() + ToPekingDateTime(0) + ".zsta"; zsta::Error err = zsta::CZstdArchive::Compress(paths, target); if (err != zsta::Error::Success) { MessageBoxAPI_L(m_hWnd, _TR("压缩失败: ") + CString(zsta::CZstdArchive::GetErrorString(err)), "错误", MB_OK | MB_ICONERROR); } else { FixedLocalFileList("."); } } bool HasZstaExtension(const std::string& path) { if (path.size() < 5) return false; std::string ext = path.substr(path.size() - 5); // 转小写比较 for (char& c : ext) c = tolower(c); return ext == ".zsta"; } std::string GetExtractDir(const std::string& archivePath) { if (archivePath.size() >= 5) { std::string ext = archivePath.substr(archivePath.size() - 5); for (char& c : ext) c = tolower(c); if (ext == ".zsta") { return archivePath.substr(0, archivePath.size() - 5); } } return archivePath + "_extract"; } void CFileManagerDlg::OnLocalUnCompress() { BOOL needRefresh = FALSE; POSITION pos = m_list_local.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_local.GetNextSelectedItem(pos); CString file = m_Local_Path + m_list_local.GetItemText(nItem, 0); // 如果是目录 if (m_list_local.GetItemData(nItem)) { continue; } else if (HasZstaExtension(file.GetString())) { std::string path(file.GetBuffer(0)); std::string destDir = GetExtractDir(path); zsta::Error err = zsta::CZstdArchive::Extract(path, destDir); if (err != zsta::Error::Success) { MessageBoxAPI_L(m_hWnd, _TR("解压失败: ") + CString(zsta::CZstdArchive::GetErrorString(err)), "错误", MB_OK | MB_ICONERROR); } else { needRefresh = TRUE; } } } if (needRefresh) { FixedLocalFileList("."); } } //////////////// 文件传输操作 //////////////// // 只管发出了下载的文件 // 一个一个发,接收到下载完成时,下载第二个文件 ... void CFileManagerDlg::OnRemoteCopy() { m_bIsUpload = false; // 禁用文件管理窗口 EnableControl(TRUE); // TODO: Add your command handler code here // 如果Drag的,找到Drop到了哪个文件夹 if (m_nDropIndex != -1 && m_pDropList->GetItemData(m_nDropIndex)) m_hCopyDestFolder = m_pDropList->GetItemText(m_nDropIndex, 0); // 重置下载任务列表 m_Remote_Download_Job.RemoveAll(); POSITION pos = m_list_remote.GetFirstSelectedItemPosition(); //iterator for the CListCtrl while(pos) { //so long as we have a valid POSITION, we keep iterating int nItem = m_list_remote.GetNextSelectedItem(pos); CString file = m_Remote_Path + m_list_remote.GetItemText(nItem, 0); // 如果是目录 if (m_list_remote.GetItemData(nItem)) file += '\\'; // 添加到下载任务列表中去 m_Remote_Download_Job.AddTail(file); } //EO while(pos) -- at this point we have deleted the moving items and stored them in memory // 发送第一个下载任务 SendDownloadJob(); } std::vector BuildMultiStringPath(const std::vector& paths); void CFileManagerDlg::OnRemoteCompress() { std::vector paths; std::string target = m_Remote_Path.GetString() + ToPekingDateTime(0) + ".zsta"; paths.push_back(target); POSITION pos = m_list_remote.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_remote.GetNextSelectedItem(pos); CString file = m_Remote_Path + m_list_remote.GetItemText(nItem, 0); // 如果是目录 if (m_list_remote.GetItemData(nItem)) { file += '\\'; } paths.push_back(file.GetBuffer(0)); } if (paths.size() <= 1) { MessageBoxAPI_L(m_hWnd, "请先选择要压缩的文件或文件夹!", "提示", MB_OK | MB_ICONWARNING); return; } auto pathsMultiString = BuildMultiStringPath(paths); BYTE* bPacket = (BYTE*)LocalAlloc(LPTR, pathsMultiString.size() + 1); if (bPacket) { memcpy(bPacket + 1, pathsMultiString.data(), pathsMultiString.size()); bPacket[0] = CMD_COMPRESS_FILES; m_ContextObject->Send2Client(bPacket, (DWORD)(pathsMultiString.size() + 1)); LocalFree(bPacket); } } void CFileManagerDlg::OnRemoteUnCompress() { std::vector paths; POSITION pos = m_list_remote.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_remote.GetNextSelectedItem(pos); CString file = m_Remote_Path + m_list_remote.GetItemText(nItem, 0); // 如果是目录 if (m_list_remote.GetItemData(nItem)) { continue; } else if (HasZstaExtension(file.GetString())) { paths.push_back(file.GetBuffer(0)); } } if (paths.empty()) { MessageBoxAPI_L(m_hWnd, "请先选择要解压的.zsta文件!", "提示", MB_OK | MB_ICONWARNING); return; } auto pathsMultiString = BuildMultiStringPath(paths); BYTE* bPacket = (BYTE*)LocalAlloc(LPTR, pathsMultiString.size() + 1); if (bPacket) { memcpy(bPacket + 1, pathsMultiString.data(), pathsMultiString.size()); bPacket[0] = CMD_UNCOMPRESS_FILES; m_ContextObject->Send2Client(bPacket, (DWORD)(pathsMultiString.size() + 1)); LocalFree(bPacket); } } // 发出一个下载任务 BOOL CFileManagerDlg::SendDownloadJob() { if (m_Remote_Download_Job.IsEmpty()) return FALSE; // 发出第一个下载任务命令 CString file = m_Remote_Download_Job.GetHead(); int nPacketSize = file.GetLength() + 2; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, nPacketSize); bPacket[0] = COMMAND_DOWN_FILES; // 文件偏移,续传时用 memcpy(bPacket + 1, file.GetBuffer(0), file.GetLength() + 1); m_ContextObject->Send2Client(bPacket, nPacketSize); LocalFree(bPacket); // 从下载任务列表中删除自己 m_Remote_Download_Job.RemoveHead(); return TRUE; } // 发出一个上传任务 BOOL CFileManagerDlg::SendUploadJob() { if (m_Remote_Upload_Job.IsEmpty()) return FALSE; CString strDestDirectory = m_Remote_Path; // 如果远程也有选择,当做目标文件夹 int nItem = m_list_remote.GetSelectionMark(); // 是文件夹 if (nItem != -1 && m_list_remote.GetItemData(nItem) == 1) { strDestDirectory += m_list_remote.GetItemText(nItem, 0) + "\\"; } if (!m_hCopyDestFolder.IsEmpty()) { strDestDirectory += m_hCopyDestFolder + "\\"; } // 发出第一个下载任务命令 m_strOperatingFile = m_Remote_Upload_Job.GetHead(); DWORD dwSizeHigh; DWORD dwSizeLow; // 1 字节token, 8字节大小, 文件名称, '\0' HANDLE hFile; CString fileRemote = m_strOperatingFile; // 远程文件 // 得到要保存到的远程的文件路径 fileRemote.Replace(m_Local_Path, strDestDirectory); m_strUploadRemoteFile = fileRemote; hFile = CreateFile(m_strOperatingFile.GetBuffer(0), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) return FALSE; dwSizeLow = GetFileSize (hFile, &dwSizeHigh); m_nOperatingFileLength = (dwSizeHigh * (MAXDWORD+long long(1))) + dwSizeLow; SAFE_CLOSE_HANDLE(hFile); // 构造数据包,发送文件长度 int nPacketSize = fileRemote.GetLength() + 10; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, nPacketSize); memset(bPacket, 0, nPacketSize); bPacket[0] = COMMAND_FILE_SIZE; memcpy(bPacket + 1, &dwSizeHigh, sizeof(DWORD)); memcpy(bPacket + 5, &dwSizeLow, sizeof(DWORD)); memcpy(bPacket + 9, fileRemote.GetBuffer(0), fileRemote.GetLength() + 1); m_ContextObject->Send2Client(bPacket, nPacketSize); LocalFree(bPacket); // 从下载任务列表中删除自己 m_Remote_Upload_Job.RemoveHead(); return TRUE; } // 发出一个删除任务 BOOL CFileManagerDlg::SendDeleteJob() { if (m_Remote_Delete_Job.IsEmpty()) return FALSE; // 发出第一个下载任务命令 CString file = m_Remote_Delete_Job.GetHead(); int nPacketSize = file.GetLength() + 2; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, nPacketSize); if (file.GetAt(file.GetLength() - 1) == '\\') { ShowMessage(_TRF("远程:删除目录 %s\\*.* 完成"), file); bPacket[0] = COMMAND_DELETE_DIRECTORY; } else { ShowMessage(_TRF("远程:删除文件 %s 完成"), file); bPacket[0] = COMMAND_DELETE_FILE; } // 文件偏移,续传时用 memcpy(bPacket + 1, file.GetBuffer(0), nPacketSize - 1); m_ContextObject->Send2Client(bPacket, nPacketSize); LocalFree(bPacket); // 从下载任务列表中删除自己 m_Remote_Delete_Job.RemoveHead(); return TRUE; } // 将远程文件路径转换为本地保存路径 // strFilePath: 远程文件的完整路径 (客户端返回的,保持原始形式含环境变量) // strRemotePath: 远程目录路径 (可能含环境变量如 %USERPROFILE%\Desktop\) // strLocalPath: 本地目标目录路径 // 返回: 本地文件保存路径 static CString RemotePathToLocal(const CString& strFilePath, const CString& strRemotePath, const CString& strLocalPath) { CString strResult = strFilePath; strResult.Replace(strRemotePath, strLocalPath); return strResult; } void CFileManagerDlg::CreateLocalRecvFile() { // 重置计数器 m_nCounter = 0; CString strDestDirectory = m_Local_Path; // 如果本地也有选择,当做目标文件夹 int nItem = m_list_local.GetSelectionMark(); // 是文件夹 if (nItem != -1 && m_list_local.GetItemData(nItem) == 1) { strDestDirectory += m_list_local.GetItemText(nItem, 0) + "\\"; } if (!m_hCopyDestFolder.IsEmpty()) { strDestDirectory += m_hCopyDestFolder + "\\"; } FILESIZE *pFileSize = (FILESIZE *)(m_ContextObject->m_DeCompressionBuffer.GetBuffer(1)); DWORD dwSizeHigh = pFileSize->dwSizeHigh; DWORD dwSizeLow = pFileSize->dwSizeLow; m_nOperatingFileLength = (dwSizeHigh * (MAXDWORD+long long(1))) + dwSizeLow; // 当前正操作的文件名 m_strOperatingFile = m_ContextObject->m_DeCompressionBuffer.GetBuffer(9); // 得到要保存到的本地的文件路径 m_strReceiveLocalFile = RemotePathToLocal(m_strOperatingFile, m_Remote_Path, strDestDirectory); // 创建多层目录 MakeSureDirectoryPathExists(m_strReceiveLocalFile.GetBuffer(0)); WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(m_strReceiveLocalFile.GetBuffer(0), &FindFileData); if (hFind != INVALID_HANDLE_VALUE && m_nTransferMode != TRANSFER_MODE_OVERWRITE_ALL && m_nTransferMode != TRANSFER_MODE_ADDITION_ALL && m_nTransferMode != TRANSFER_MODE_JUMP_ALL ) { CFileTransferModeDlg dlg(this); dlg.m_strFileName = m_strReceiveLocalFile; switch (dlg.DoModal()) { case IDC_OVERWRITE: m_nTransferMode = TRANSFER_MODE_OVERWRITE; break; case IDC_OVERWRITE_ALL: m_nTransferMode = TRANSFER_MODE_OVERWRITE_ALL; break; case IDC_ADDITION: m_nTransferMode = TRANSFER_MODE_ADDITION; break; case IDC_ADDITION_ALL: m_nTransferMode = TRANSFER_MODE_ADDITION_ALL; break; case IDC_JUMP: m_nTransferMode = TRANSFER_MODE_JUMP; break; case IDC_JUMP_ALL: m_nTransferMode = TRANSFER_MODE_JUMP_ALL; break; case IDC_CANCEL: m_nTransferMode = TRANSFER_MODE_CANCEL; break; } } if (m_nTransferMode == TRANSFER_MODE_CANCEL) { // 取消传送 m_bIsStop = true; SendStop(); return; } int nTransferMode; switch (m_nTransferMode) { case TRANSFER_MODE_OVERWRITE_ALL: nTransferMode = TRANSFER_MODE_OVERWRITE; break; case TRANSFER_MODE_ADDITION_ALL: nTransferMode = TRANSFER_MODE_ADDITION; break; case TRANSFER_MODE_JUMP_ALL: nTransferMode = TRANSFER_MODE_JUMP; break; default: nTransferMode = m_nTransferMode; } // 1字节Token,四字节偏移高四位,四字节偏移低四位 BYTE bToken[9]; DWORD dwCreationDisposition = CREATE_ALWAYS; // 文件打开方式 memset(bToken, 0, sizeof(bToken)); bToken[0] = COMMAND_CONTINUE; // 文件已经存在 if (hFind != INVALID_HANDLE_VALUE) { // 提示点什么 // 如果是续传 if (nTransferMode == TRANSFER_MODE_ADDITION) { memcpy(bToken + 1, &FindFileData.nFileSizeHigh, 4); memcpy(bToken + 5, &FindFileData.nFileSizeLow, 4); // 接收的长度递增 m_nCounter += FindFileData.nFileSizeHigh * (MAXDWORD+long long(1)); m_nCounter += FindFileData.nFileSizeLow; dwCreationDisposition = OPEN_EXISTING; } // 覆盖 else if (nTransferMode == TRANSFER_MODE_OVERWRITE) { // 偏移置0 memset(bToken + 1, 0, 8); // 重新创建 dwCreationDisposition = CREATE_ALWAYS; } // 跳过,指针移到-1 else if (nTransferMode == TRANSFER_MODE_JUMP) { m_ProgressCtrl->SetPos(100); DWORD dwOffset = -1; memcpy(bToken + 5, &dwOffset, 4); dwCreationDisposition = OPEN_EXISTING; } } else { // 偏移置0 memset(bToken + 1, 0, 8); // 重新创建 dwCreationDisposition = CREATE_ALWAYS; } FindClose(hFind); // 关闭之前的句柄(如果有) if (m_hRecvFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hRecvFile); m_hRecvFile = INVALID_HANDLE_VALUE; } // 打开文件并保持句柄,直到传输完成 m_hRecvFile = CreateFile ( m_strReceiveLocalFile.GetBuffer(0), GENERIC_WRITE, FILE_SHARE_READ, // 只允许读共享,防止其他程序写入 NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0 ); // 需要错误处理 if (m_hRecvFile == INVALID_HANDLE_VALUE) { m_nOperatingFileLength = 0; m_nCounter = 0; MessageBoxAPI_L(m_hWnd, m_strReceiveLocalFile + _TR(" 文件创建失败"), "警告", MB_OK|MB_ICONWARNING); return; } ShowProgress(); if (m_bIsStop) SendStop(); else { // 发送继续传输文件的token,包含文件续传的偏移 m_ContextObject->Send2Client(bToken, sizeof(bToken)); } } // 写入文件内容 void CFileManagerDlg::WriteLocalRecvFile() { // 检查文件句柄是否有效 if (m_hRecvFile == INVALID_HANDLE_VALUE) { CString msg; msg.FormatL("%s 文件句柄无效", m_strReceiveLocalFile); ::MessageBox(m_hWnd, msg, _TR("警告"), MB_OK|MB_ICONWARNING); m_bIsStop = true; SendStop(); return; } BYTE *pData; DWORD dwBytesToWrite; DWORD dwBytesWrite; int nHeadLength = 9; // 1 + 4 + 4 数据包头部大小,为固定的9 FILESIZE *pFileSize; // 得到数据的偏移 pData = m_ContextObject->m_DeCompressionBuffer.GetBuffer(nHeadLength); pFileSize = (FILESIZE *)m_ContextObject->m_DeCompressionBuffer.GetBuffer(1); // 得到数据在文件中的偏移, 赋值给计数器 m_nCounter = MAKEINT64(pFileSize->dwSizeLow, pFileSize->dwSizeHigh); LONG dwOffsetHigh = pFileSize->dwSizeHigh; LONG dwOffsetLow = pFileSize->dwSizeLow; dwBytesToWrite = m_ContextObject->m_DeCompressionBuffer.GetBufferLen() - nHeadLength; SetFilePointer(m_hRecvFile, dwOffsetLow, &dwOffsetHigh, FILE_BEGIN); int nRet = 0, i = 0; for (; i < MAX_WRITE_RETRY; ++i) { // 写入文件 nRet = WriteFile ( m_hRecvFile, pData, dwBytesToWrite, &dwBytesWrite, NULL ); if (nRet > 0) { break; } } if (i == MAX_WRITE_RETRY && nRet <= 0) { DWORD dwErr = GetLastError(); CString msg; msg.FormatL("%s 文件写入失败 (错误码: %d)", m_strReceiveLocalFile, dwErr); ::MessageBox(m_hWnd, msg, _TR("警告"), MB_OK|MB_ICONWARNING); m_bIsStop = true; } // 注意:不在这里关闭句柄,等传输完成后在 EndLocalRecvFile 中关闭 // 为了比较,计数器递增 m_nCounter += dwBytesWrite; ShowProgress(); if (m_bIsStop) SendStop(); else { BYTE bToken[9]; bToken[0] = COMMAND_CONTINUE; // Fix: use 64-bit arithmetic to handle files > 4GB __int64 newOffset = MAKEINT64(dwOffsetLow, dwOffsetHigh) + dwBytesWrite; dwOffsetHigh = (DWORD)(newOffset >> 32); dwOffsetLow = (DWORD)(newOffset & 0xFFFFFFFF); memcpy(bToken + 1, &dwOffsetHigh, sizeof(dwOffsetHigh)); memcpy(bToken + 5, &dwOffsetLow, sizeof(dwOffsetLow)); m_ContextObject->Send2Client(bToken, sizeof(bToken)); } } void CFileManagerDlg::EndLocalRecvFile() { // 关闭文件句柄 if (m_hRecvFile != INVALID_HANDLE_VALUE) { CloseHandle(m_hRecvFile); m_hRecvFile = INVALID_HANDLE_VALUE; } m_nCounter = 0; m_strOperatingFile = ""; m_nOperatingFileLength = 0; if (m_Remote_Download_Job.IsEmpty() || m_bIsStop) { m_Remote_Download_Job.RemoveAll(); m_bIsStop = false; // 重置传输方式 m_nTransferMode = TRANSFER_MODE_NORMAL; EnableControl(TRUE); FixedLocalFileList("."); ShowMessage(_TRF("本地:装载目录 %s\\*.* 完成"), m_Local_Path); } else { // 我靠,不sleep下会出错,服了可能以前的数据还没send出去 Sleep(5); SendDownloadJob(); } return; } void CFileManagerDlg::EndLocalUploadFile() { m_nCounter = 0; m_strOperatingFile = ""; m_nOperatingFileLength = 0; if (m_Remote_Upload_Job.IsEmpty() || m_bIsStop) { m_Remote_Upload_Job.RemoveAll(); m_bIsStop = false; EnableControl(TRUE); GetRemoteFileList("."); ShowMessage(_TRF("远程:装载目录 %s\\*.* 完成"), m_Remote_Path); } else { // 我靠,不sleep下会出错,服了可能以前的数据还没send出去 Sleep(5); SendUploadJob(); } return; } void CFileManagerDlg::EndRemoteDeleteFile() { if (m_Remote_Delete_Job.IsEmpty() || m_bIsStop) { m_bIsStop = false; EnableControl(TRUE); GetRemoteFileList("."); ShowMessage(_TRF("远程:装载目录 %s\\*.* 完成"), m_Remote_Path); } else { // 我靠,不sleep下会出错,服了可能以前的数据还没send出去 Sleep(5); SendDeleteJob(); } return; } void CFileManagerDlg::SendException() { BYTE bBuff = COMMAND_EXCEPTION; m_ContextObject->Send2Client(&bBuff, 1); } void CFileManagerDlg::SendContinue() { BYTE bBuff = COMMAND_CONTINUE; m_ContextObject->Send2Client(&bBuff, 1); } void CFileManagerDlg::SendStop() { BYTE bBuff = COMMAND_STOP; m_ContextObject->Send2Client(&bBuff, 1); } void CFileManagerDlg::ShowProgress() { CString strDirection; if (m_bIsUpload) strDirection = _L(_T("传送文件")); else strDirection = _L(_T("接收文件")); char *lpDirection = (char*)(LPCSTR)strDirection; // 防止除零导致未定义行为 if (m_nOperatingFileLength <= 0) { return; } if (m_nCounter < 0 || m_nCounter > m_nOperatingFileLength) { m_nCounter = m_nOperatingFileLength; } int progress = (int)((double)m_nCounter / m_nOperatingFileLength * 100); ShowMessage("%s %s %dKB (%d%%)", lpDirection, m_strOperatingFile, (int)(m_nCounter / 1024), progress); m_ProgressCtrl->SetPos(progress); if (m_nCounter == m_nOperatingFileLength) { m_nCounter = m_nOperatingFileLength = 0; // 关闭文件句柄 } } void CFileManagerDlg::OnLocalDelete() { m_bIsUpload = true; CString str; if (m_list_local.GetSelectedCount() > 1) str.FormatL("确定要将这 %d 项删除吗?", m_list_local.GetSelectedCount()); else { CString file = m_list_local.GetItemText(m_list_local.GetSelectionMark(), 0); if (m_list_local.GetItemData(m_list_local.GetSelectionMark()) == 1) str.FormatL("确实要删除文件夹“%s”并将所有内容删除吗?", file); else str.FormatL("确实要把“%s”删除吗?", file); } if (MessageBoxAPI_L(m_hWnd, str, "确认删除", MB_YESNO|MB_ICONQUESTION) == IDNO) return; EnableControl(FALSE); POSITION pos = m_list_local.GetFirstSelectedItemPosition(); //iterator for the CListCtrl while(pos) { //so long as we have a valid POSITION, we keep iterating int nItem = m_list_local.GetNextSelectedItem(pos); CString file = m_Local_Path + m_list_local.GetItemText(nItem, 0); // 如果是目录 if (m_list_local.GetItemData(nItem)) { file += '\\'; DeleteDirectory(file); } else { DeleteFile(file); } } //EO while(pos) -- at this point we have deleted the moving items and stored them in memory // 禁用文件管理窗口 EnableControl(TRUE); FixedLocalFileList("."); } void CFileManagerDlg::OnRemoteDelete() { m_bIsUpload = false; // TODO: Add your command handler code here CString str; if (m_list_remote.GetSelectedCount() > 1) str.FormatL("确定要将这 %d 项删除吗?", m_list_remote.GetSelectedCount()); else { CString file = m_list_remote.GetItemText(m_list_remote.GetSelectionMark(), 0); if (m_list_remote.GetItemData(m_list_remote.GetSelectionMark()) == 1) str.FormatL("确实要删除文件夹“%s”并将所有内容删除吗?", file); else str.FormatL("确实要把“%s”删除吗?", file); } if (MessageBoxAPI_L(m_hWnd, str, "确认删除", MB_YESNO|MB_ICONQUESTION) == IDNO) return; m_Remote_Delete_Job.RemoveAll(); POSITION pos = m_list_remote.GetFirstSelectedItemPosition(); //iterator for the CListCtrl while(pos) { //so long as we have a valid POSITION, we keep iterating int nItem = m_list_remote.GetNextSelectedItem(pos); CString file = m_Remote_Path + m_list_remote.GetItemText(nItem, 0); // 如果是目录 if (m_list_remote.GetItemData(nItem)) file += '\\'; m_Remote_Delete_Job.AddTail(file); } //EO while(pos) -- at this point we have deleted the moving items and stored them in memory EnableControl(FALSE); // 发送第一个下载任务 SendDeleteJob(); } void CFileManagerDlg::OnRemoteStop() { // TODO: Add your command handler code here m_bIsStop = true; // 标记搜索已停止,忽略后续到达的搜索数据 if (m_bSearching) { m_bSearchStopped = true; m_bSearching = false; m_list_remote.EnableWindow(TRUE); DWORD dwElapsed = (GetTickCount() - m_dwSearchStartTime) / 1000; ShowMessage(_TRF("搜索已停止,共 %d 个结果 (耗时 %d秒)"), m_nSearchResultCount, dwElapsed); } // 同时发送搜索停止命令到客户端 BYTE bBuff = COMMAND_FILES_SEARCH_STOP; m_ContextObject->Send2Client(&bBuff, 1); } void CFileManagerDlg::OnLocalStop() { m_bIsStop = true; if (m_bLocalSearching) { m_bLocalSearching = false; // 通知搜索线程停止,由OnLocalSearchDone显示结果 } } void CFileManagerDlg::PostNcDestroy() { // TODO: Add your specialized code here and/or call the base class __super::PostNcDestroy(); } void CFileManagerDlg::SendTransferMode() { CFileTransferModeDlg dlg(this); dlg.m_strFileName = m_strUploadRemoteFile; switch (dlg.DoModal()) { case IDC_OVERWRITE: m_nTransferMode = TRANSFER_MODE_OVERWRITE; break; case IDC_OVERWRITE_ALL: m_nTransferMode = TRANSFER_MODE_OVERWRITE_ALL; break; case IDC_ADDITION: m_nTransferMode = TRANSFER_MODE_ADDITION; break; case IDC_ADDITION_ALL: m_nTransferMode = TRANSFER_MODE_ADDITION_ALL; break; case IDC_JUMP: m_nTransferMode = TRANSFER_MODE_JUMP; break; case IDC_JUMP_ALL: m_nTransferMode = TRANSFER_MODE_JUMP_ALL; break; case IDC_CANCEL: m_nTransferMode = TRANSFER_MODE_CANCEL; break; } if (m_nTransferMode == TRANSFER_MODE_CANCEL) { m_bIsStop = true; EndLocalUploadFile(); return; } BYTE bToken[5]; bToken[0] = COMMAND_SET_TRANSFER_MODE; memcpy(bToken + 1, &m_nTransferMode, sizeof(m_nTransferMode)); m_ContextObject->Send2Client((unsigned char *)&bToken, sizeof(bToken)); } void CFileManagerDlg::SendFileData() { FILESIZE *pFileSize = (FILESIZE *)(m_ContextObject->m_DeCompressionBuffer.GetBuffer(1)); LONG dwOffsetHigh = pFileSize->dwSizeHigh ; LONG dwOffsetLow = pFileSize->dwSizeLow; m_nCounter = MAKEINT64(pFileSize->dwSizeLow, pFileSize->dwSizeHigh); ShowProgress(); if (m_nCounter == m_nOperatingFileLength || pFileSize->dwSizeLow == -1 || m_bIsStop) { EndLocalUploadFile(); return; } HANDLE hFile; hFile = CreateFile(m_strOperatingFile.GetBuffer(0), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { return; } SetFilePointer(hFile, dwOffsetLow, &dwOffsetHigh, FILE_BEGIN); int nHeadLength = 9; // 1 + 4 + 4 数据包头部大小,为固定的9 DWORD nNumberOfBytesToRead = MAX_SEND_BUFFER - nHeadLength; DWORD nNumberOfBytesRead = 0; BYTE *lpBuffer = (BYTE *)LocalAlloc(LPTR, MAX_SEND_BUFFER); // Token, 大小,偏移,数据 lpBuffer[0] = COMMAND_FILE_DATA; memcpy(lpBuffer + 1, &dwOffsetHigh, sizeof(dwOffsetHigh)); memcpy(lpBuffer + 5, &dwOffsetLow, sizeof(dwOffsetLow)); // 返回值 bool bRet = true; ReadFile(hFile, lpBuffer + nHeadLength, nNumberOfBytesToRead, &nNumberOfBytesRead, NULL); SAFE_CLOSE_HANDLE(hFile); if (nNumberOfBytesRead > 0) { int nPacketSize = nNumberOfBytesRead + nHeadLength; m_ContextObject->Send2Client(lpBuffer, nPacketSize); } LocalFree(lpBuffer); } bool CFileManagerDlg::DeleteDirectory(LPCTSTR lpszDirectory) { WIN32_FIND_DATA wfd; char lpszFilter[MAX_PATH]; wsprintf(lpszFilter, "%s\\*.*", lpszDirectory); HANDLE hFind = FindFirstFile(lpszFilter, &wfd); if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败 return FALSE; do { if (wfd.cFileName[0] != '.') { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { char strDirectory[MAX_PATH]; wsprintf(strDirectory, "%s\\%s", lpszDirectory, wfd.cFileName); DeleteDirectory(strDirectory); } else { char strFile[MAX_PATH]; wsprintf(strFile, "%s\\%s", lpszDirectory, wfd.cFileName); DeleteFile(strFile); } } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); // 关闭查找句柄 if(!RemoveDirectory(lpszDirectory)) { return FALSE; } return true; } void CFileManagerDlg::OnLocalNewfolder() { if (m_Local_Path == "") return; // TODO: Add your command handler code here CInputDialog dlg(this); dlg.Init(_TR("新建目录"), _TR("请输入目录名称:")); if (dlg.DoModal() == IDOK && dlg.m_str.GetLength()) { // 创建多层目录 MakeSureDirectoryPathExists(m_Local_Path + dlg.m_str + "\\"); FixedLocalFileList("."); } } void CFileManagerDlg::OnRemoteNewfolder() { if (m_Remote_Path == "") return; // TODO: Add your command handler code here // TODO: Add your command handler code here CInputDialog dlg(this); dlg.Init(_TR("新建目录"), _TR("请输入目录名称:")); if (dlg.DoModal() == IDOK && dlg.m_str.GetLength()) { CString file = m_Remote_Path + dlg.m_str + "\\"; UINT nPacketSize = file.GetLength() + 2; // 创建多层目录 LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, file.GetLength() + 2); lpBuffer[0] = COMMAND_CREATE_FOLDER; memcpy(lpBuffer + 1, file.GetBuffer(0), nPacketSize - 1); m_ContextObject->Send2Client(lpBuffer, nPacketSize); LocalFree(lpBuffer); } } void CFileManagerDlg::OnTransfer() { // TODO: Add your command handler code here POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { OnLocalCopy(); } else { OnRemoteCopy(); } } void CFileManagerDlg::OnFilemangerCompress() { POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { OnLocalCompress(); } else { OnRemoteCompress(); } } void CFileManagerDlg::OnFilemangerUncompress() { POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { OnLocalUnCompress(); } else { OnRemoteUnCompress(); } } void CFileManagerDlg::OnRename() { // TODO: Add your command handler code here POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { m_list_local.EditLabel(m_list_local.GetSelectionMark()); } else { m_list_remote.EditLabel(m_list_remote.GetSelectionMark()); } } void CFileManagerDlg::OnEndlabeleditListLocal(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; // TODO: Add your control notification handler code here CString str, strExistingFileName, strNewFileName; m_list_local.GetEditControl()->GetWindowText(str); strExistingFileName = m_Local_Path + m_list_local.GetItemText(pDispInfo->item.iItem, 0); strNewFileName = m_Local_Path + str; *pResult = ::MoveFile(strExistingFileName.GetBuffer(0), strNewFileName.GetBuffer(0)); } void CFileManagerDlg::OnEndlabeleditListRemote(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; // TODO: Add your control notification handler code here CString str, strExistingFileName, strNewFileName; m_list_remote.GetEditControl()->GetWindowText(str); strExistingFileName = m_Remote_Path + m_list_remote.GetItemText(pDispInfo->item.iItem, 0); strNewFileName = m_Remote_Path + str; if (strExistingFileName != strNewFileName) { UINT nPacketSize = strExistingFileName.GetLength() + strNewFileName.GetLength() + 3; LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, nPacketSize); lpBuffer[0] = COMMAND_RENAME_FILE; memcpy(lpBuffer + 1, strExistingFileName.GetBuffer(0), strExistingFileName.GetLength() + 1); memcpy(lpBuffer + 2 + strExistingFileName.GetLength(), strNewFileName.GetBuffer(0), strNewFileName.GetLength() + 1); m_ContextObject->Send2Client(lpBuffer, nPacketSize); LocalFree(lpBuffer); } *pResult = 1; } void CFileManagerDlg::OnDelete() { // TODO: Add your command handler code here POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { OnLocalDelete(); } else { OnRemoteDelete(); } } void CFileManagerDlg::OnNewfolder() { // TODO: Add your command handler code here POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { OnLocalNewfolder(); } else { OnRemoteNewfolder(); } } void CFileManagerDlg::OnRefresh() { // TODO: Add your command handler code here POINT pt; GetCursorPos(&pt); if (GetFocus()->m_hWnd == m_list_local.m_hWnd) { FixedLocalFileList("."); } else { GetRemoteFileList("."); } } void CFileManagerDlg::OnLocalOpen() { // TODO: Add your command handler code here CString str; str = m_Local_Path + m_list_local.GetItemText(m_list_local.GetSelectionMark(), 0); ShellExecute(NULL, "open", str, NULL, NULL, SW_SHOW); } void CFileManagerDlg::OnRemoteOpenShow() { // TODO: Add your command handler code here CString str; str = m_Remote_Path + m_list_remote.GetItemText(m_list_remote.GetSelectionMark(), 0); int nPacketLength = str.GetLength() + 2; LPBYTE lpPacket = (LPBYTE)LocalAlloc(LPTR, nPacketLength); lpPacket[0] = COMMAND_OPEN_FILE_SHOW; memcpy(lpPacket + 1, str.GetBuffer(0), nPacketLength - 1); m_ContextObject->Send2Client(lpPacket, nPacketLength); LocalFree(lpPacket); } void CFileManagerDlg::OnRemoteOpenHide() { // TODO: Add your command handler code here CString str; str = m_Remote_Path + m_list_remote.GetItemText(m_list_remote.GetSelectionMark(), 0); int nPacketLength = str.GetLength() + 2; LPBYTE lpPacket = (LPBYTE)LocalAlloc(LPTR, nPacketLength); lpPacket[0] = COMMAND_OPEN_FILE_HIDE; memcpy(lpPacket + 1, str.GetBuffer(0), nPacketLength - 1); m_ContextObject->Send2Client(lpPacket, nPacketLength); LocalFree(lpPacket); } void CFileManagerDlg::OnRclickListLocal(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here CListCtrl *pListCtrl = &m_list_local; CMenu popup; popup.LoadMenu(IDR_FILEMANAGER); TranslateMenu(&popup); CMenu* pM = popup.GetSubMenu(0); CPoint p; GetCursorPos(&p); pM->DeleteMenu(6, MF_BYPOSITION); if (pListCtrl->GetSelectedCount() == 0) { int count = pM->GetMenuItemCount(); for (int i = 0; i < count; ++i) { pM->EnableMenuItem(i, MF_BYPOSITION | MF_GRAYED); } } if (pListCtrl->GetSelectedCount() <= 1) { pM->EnableMenuItem(IDM_NEWFOLDER, MF_BYCOMMAND | MF_ENABLED); } if (pListCtrl->GetSelectedCount() == 1) { // 是文件夹 if (pListCtrl->GetItemData(pListCtrl->GetSelectionMark()) == 1) pM->EnableMenuItem(IDM_LOCAL_OPEN, MF_BYCOMMAND | MF_GRAYED); else pM->EnableMenuItem(IDM_LOCAL_OPEN, MF_BYCOMMAND | MF_ENABLED); } else pM->EnableMenuItem(IDM_LOCAL_OPEN, MF_BYCOMMAND | MF_GRAYED); // V2传输: 本地列表只能上传到远程,不能从远程下载 // 需要选中文件且远程目录已打开(不是驱动器列表) if (pListCtrl->GetSelectedCount() > 0 && !m_Remote_Path.IsEmpty()) { pM->EnableMenuItem(IDM_TRANSFER_S, MF_BYCOMMAND | MF_ENABLED); } else { pM->EnableMenuItem(IDM_TRANSFER_S, MF_BYCOMMAND | MF_GRAYED); } pM->EnableMenuItem(IDM_TRANSFER_R, MF_BYCOMMAND | MF_GRAYED); // 本地列表不能从远程下载 pM->EnableMenuItem(IDM_REFRESH, MF_BYCOMMAND | MF_ENABLED); pM->TrackPopupMenu(TPM_LEFTALIGN, p.x, p.y, this); *pResult = 0; } void CFileManagerDlg::OnRclickListRemote(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here int nRemoteOpenMenuIndex = 7; // 由于添加了2个V2菜单项,位置需要调整 CListCtrl *pListCtrl = &m_list_remote; CMenu popup; popup.LoadMenu(IDR_FILEMANAGER); TranslateMenu(&popup); CMenu* pM = popup.GetSubMenu(0); CPoint p; GetCursorPos(&p); pM->DeleteMenu(IDM_LOCAL_OPEN, MF_BYCOMMAND); if (pListCtrl->GetSelectedCount() == 0) { int count = pM->GetMenuItemCount(); for (int i = 0; i < count; ++i) { pM->EnableMenuItem(i, MF_BYPOSITION | MF_GRAYED); } } if (pListCtrl->GetSelectedCount() <= 1) { pM->EnableMenuItem(IDM_NEWFOLDER, MF_BYCOMMAND | MF_ENABLED); } if (pListCtrl->GetSelectedCount() == 1) { // 是文件夹 if (pListCtrl->GetItemData(pListCtrl->GetSelectionMark()) == 1) pM->EnableMenuItem(nRemoteOpenMenuIndex, MF_BYPOSITION| MF_GRAYED); else pM->EnableMenuItem(nRemoteOpenMenuIndex, MF_BYPOSITION | MF_ENABLED); } else pM->EnableMenuItem(nRemoteOpenMenuIndex, MF_BYPOSITION | MF_GRAYED); // V2传输: 远程列表只能从远程下载,不能上传到远程 // 需要选中文件且本地目录已打开(不是驱动器列表) if (pListCtrl->GetSelectedCount() > 0 && !m_Local_Path.IsEmpty()) { pM->EnableMenuItem(IDM_TRANSFER_R, MF_BYCOMMAND | MF_ENABLED); } else { pM->EnableMenuItem(IDM_TRANSFER_R, MF_BYCOMMAND | MF_GRAYED); } pM->EnableMenuItem(IDM_TRANSFER_S, MF_BYCOMMAND | MF_GRAYED); // 远程列表不能上传到远程 pM->EnableMenuItem(IDM_REFRESH, MF_BYCOMMAND | MF_ENABLED); pM->TrackPopupMenu(TPM_LEFTALIGN, p.x, p.y, this); *pResult = 0; } bool CFileManagerDlg::MakeSureDirectoryPathExists(LPCTSTR pszDirPath) { LPTSTR p, pszDirCopy; DWORD dwAttributes; // Make a copy of the string for editing. __try { pszDirCopy = (LPTSTR)malloc(sizeof(TCHAR) * (lstrlen(pszDirPath) + 1)); if(pszDirCopy == NULL) return FALSE; lstrcpy(pszDirCopy, pszDirPath); p = pszDirCopy; // If the second character in the path is "\", then this is a UNC // path, and we should skip forward until we reach the 2nd \ in the path. if((*p == TEXT('\\')) && (*(p+1) == TEXT('\\'))) { p++; // Skip over the first \ in the name. p++; // Skip over the second \ in the name. // Skip until we hit the first "\" (\\Server\). while(*p && *p != TEXT('\\')) { p = CharNext(p); } // Advance over it. if(*p) { p++; } // Skip until we hit the second "\" (\\Server\Share\). while(*p && *p != TEXT('\\')) { p = CharNext(p); } // Advance over it also. if(*p) { p++; } } else if(*(p+1) == TEXT(':')) { // Not a UNC. See if it's : p++; p++; // If it exists, skip over the root specifier if(*p && (*p == TEXT('\\'))) { p++; } } while(*p) { if(*p == TEXT('\\')) { *p = TEXT('\0'); dwAttributes = GetFileAttributes(pszDirCopy); // Nothing exists with this name. Try to make the directory name and error if unable to. if(dwAttributes == 0xffffffff) { if(!CreateDirectory(pszDirCopy, NULL)) { if(GetLastError() != ERROR_ALREADY_EXISTS) { free(pszDirCopy); return FALSE; } } } else { if((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { // Something exists with this name, but it's not a directory... Error free(pszDirCopy); return FALSE; } } *p = TEXT('\\'); } p = CharNext(p); } } __except(EXCEPTION_EXECUTE_HANDLER) { // SetLastError(GetExceptionCode()); free(pszDirCopy); return FALSE; } free(pszDirCopy); return TRUE; } // V2传输: 本地文件上传到远程 void CFileManagerDlg::OnTransferV2ToRemote() { // 收集本地选中的文件列表 std::vector files; POSITION pos = m_list_local.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_local.GetNextSelectedItem(pos); CString itemText = m_list_local.GetItemText(nItem, 0); // 跳过".." if (itemText == "..") continue; CString file = m_Local_Path + itemText; // 如果是目录,递归收集文件 if (m_list_local.GetItemData(nItem)) { file += '\\'; CollectFilesRecursive(file.GetString(), files); } else { files.push_back(file.GetString()); } } if (files.empty()) { MessageBoxAPI_L(m_hWnd, "没有选中任何文件", "提示", MB_OK | MB_ICONINFORMATION); return; } // 通知客户端目标目录(使用远程当前目录) // 由 SendFilesToClientV2 内部的 COMMAND_C2C_PREPARE 处理 // 调用V2传输 - 需要通过IP找到主连接(m_ContextObject是子连接) if (g_2015RemoteDlg && m_ContextObject) { // 通过子连接的IP地址找到主连接 std::string peerIP = m_ContextObject->GetPeerName(); context* mainCtx = g_2015RemoteDlg->FindHostByIP(peerIP); if (mainCtx) { // 使用远程当前目录作为目标目录 std::string remoteDir = m_Remote_Path.GetString(); g_2015RemoteDlg->SendFilesToClientV2(mainCtx, files, remoteDir); ShowMessage(_TRF("V2传输已启动,共 %d 个文件 -> %s"), (int)files.size(), remoteDir.c_str()); } else { ShowMessage(_TRF("找不到主连接: %s"), peerIP.c_str()); } } } // V2传输: 远程文件下载到本地 void CFileManagerDlg::OnTransferV2ToLocal() { // 收集远程选中的文件列表 std::vector remotePaths; POSITION pos = m_list_remote.GetFirstSelectedItemPosition(); while (pos) { int nItem = m_list_remote.GetNextSelectedItem(pos); CString itemText = m_list_remote.GetItemText(nItem, 0); // 跳过".." if (itemText == "..") continue; CString file = m_Remote_Path + itemText; // 如果是目录,添加结尾的反斜杠 if (m_list_remote.GetItemData(nItem)) { file += '\\'; } remotePaths.push_back(file.GetString()); } if (remotePaths.empty()) { MessageBoxAPI_L(m_hWnd, "没有选中任何文件", "提示", MB_OK | MB_ICONINFORMATION); return; } // 构建命令包: [cmd:1][targetDir\0][file1\0][file2\0]...[fileN\0][\0] std::vector packet; packet.push_back(CMD_DOWN_FILES_V2); // 目标目录(本地当前目录) std::string targetDir = m_Local_Path.GetString(); packet.insert(packet.end(), targetDir.begin(), targetDir.end()); packet.push_back('\0'); // 文件列表 for (const auto& path : remotePaths) { packet.insert(packet.end(), path.begin(), path.end()); packet.push_back('\0'); } packet.push_back('\0'); // 双null结束 // 发送命令 m_ContextObject->Send2Client((BYTE*)packet.data(), (DWORD)packet.size()); ShowMessage(_TRF("V2下载请求已发送,共 %d 个项目"), (int)remotePaths.size()); } // 递归收集目录中的所有文件(包括目录本身) void CFileManagerDlg::CollectFilesRecursive(const std::string& dirPath, std::vector& files) { // 先添加目录本身(去掉末尾的反斜杠) std::string dirEntry = dirPath; if (!dirEntry.empty() && (dirEntry.back() == '\\' || dirEntry.back() == '/')) { dirEntry.pop_back(); } files.push_back(dirEntry); WIN32_FIND_DATAA wfd; std::string searchPath = dirPath + "*.*"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &wfd); if (hFind == INVALID_HANDLE_VALUE) return; do { if (wfd.cFileName[0] != '.') { std::string fullPath = dirPath + wfd.cFileName; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { CollectFilesRecursive(fullPath + "\\", files); } else { files.push_back(fullPath); } } } while (FindNextFileA(hFind, &wfd)); FindClose(hFind); }