// FileControlExample.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "FileControlExample.h" #include "FileControl.h" #include <Commctrl.h> #include <Shlobj.h> // 文件夹选择 #include <Uxtheme.h> // 扩展样式相关API #pragma comment(lib,"UxTheme.lib") #include <shlwapi.h> // 路径相关API #pragma comment(lib,"shlwapi.lib") typedef struct _TREE_ITEM { HTREEITEM hTreeItem; WCHAR szFilePath[MAX_PATH]; }TREE_ITEM,*PTREE_ITEM; typedef struct _LIST_ITEM { int nItemIndex; WCHAR szFilePath[MAX_PATH]; }LIST_ITEM,*PLIST_ITEM; #define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 list<TREE_ITEM> g_lstTreeInfo; list<LIST_ITEM> g_lstListInfo; //HTREEITEM g_hParent; //TreeView_GetSelection // 此代码模块中包含的函数的前向声明: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HTREEITEM AddItemToTree(HWND hTree, LPWSTR lpItemName, HTREEITEM hParent, BOOL bFolder); BOOL AddItemToList(HWND hWnd,FILE_INFO stcInfo, DWORD dwIndex); VOID UpdataControl(HWND hWnd, LPWSTR lpPath, HTREEITEM hParent); VOID DeleteTreeItemListNode(HTREEITEM hItem); BOOL SelectFolder(HWND hWnd, LPWSTR lpszFolder); VOID InitList(HWND hWnd); VOID Tree_LButtonDown(HWND hWnd); VOID List_RButtonDown(HWND hWnd); int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { DialogBox(hInstance,LPTSTR(IDD_DIALOG),0,(DLGPROC)WndProc); return 0; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_INITDIALOG:{ InitList(hWnd); break;} case WM_NOTIFY: { // 1. 判断是否为左键单击消息,并且消息消息来自树控件 if ( NM_CLICK==((LPNMHDR)lParam)->code && IDC_TREE==((LPNMHDR)lParam)->idFrom ) { Tree_LButtonDown(hWnd); } // 2. 判断是否为右键单击消息,并且消息消息来自列表框控件 else if ( NM_RCLICK==((LPNMHDR)lParam)->code && IDC_LIST==((LPNMHDR)lParam)->idFrom ) { List_RButtonDown(hWnd); } break; } case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case BTN_SELETE: WCHAR szPath[MAX_PATH]; SelectFolder(hWnd, szPath); UpdataControl(hWnd, szPath, NULL); break; case ID__32771: { UINT nSeleteItem = ListView_GetSelectionMark(GetDlgItem(hWnd,IDC_LIST)); for (list<LIST_ITEM>::iterator i=g_lstListInfo.begin(); i!=g_lstListInfo.end(); i++) { if ( i->nItemIndex != nSeleteItem ) continue; CFileControl obj; obj.SetFileIsHidden(i->szFilePath); break; } break; } case ID__32772: { UINT nSeleteItem = ListView_GetSelectionMark(GetDlgItem(hWnd,IDC_LIST)); for (list<LIST_ITEM>::iterator i=g_lstListInfo.begin(); i!=g_lstListInfo.end(); i++) { if ( i->nItemIndex != nSeleteItem ) continue; CFileControl obj; obj.SetFileIsOnlyRead(i->szFilePath); break; } break; } case IDCANCEL: PostQuitMessage(0); default: return FALSE; } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_CLOSE: // 重点 PostQuitMessage(0); default: return FALSE; } return TRUE; } HTREEITEM AddItemToTree(HWND hTree, LPWSTR lpItemName, HTREEITEM hParent, BOOL bFolder) { TVITEM tvi = {0}; // 树节点项属性信息 TVINSERTSTRUCT tvins = {0}; // 树形控件的节点信息 tvi.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM; tvi.pszText = lpItemName; tvi.cchTextMax = wcslen(lpItemName)+sizeof(TCHAR); if ( bFolder ) { tvi.iImage = 1; tvi.iSelectedImage = 2; tvi.cChildren = I_CHILDRENCALLBACK; } else { tvi.iImage = 3; tvi.iSelectedImage = 3; tvi.cChildren = 0; } tvins.item = tvi; // 插入点的属性信息 tvins.hInsertAfter = TVI_SORT; // 插入位置 if ( NULL == hParent ) // 父节点的句柄 tvins.hParent = TVI_ROOT; else tvins.hParent = hParent; return TreeView_InsertItem(hTree,&tvins); } VOID UpdataControl(HWND hWnd, LPWSTR lpPath, HTREEITEM hParent) { HWND hTreeWnd = GetDlgItem(hWnd,IDC_TREE); // 1. 清空Tree的子节点 if ( hParent ) { // 1.1 获取其子节点,如果有的话则循环删除其子节点,否则跳过此步骤 HTREEITEM hNext_A = TreeView_GetNextItem(hTreeWnd,hParent,TVGN_CHILD); if ( hNext_A ) { // 1.1.1 获取其子节点的下一个节点 HTREEITEM hNext_B = TreeView_GetNextItem(hTreeWnd,hNext_A,TVGN_NEXT); // 1.1.2 删除第一个子节点 TreeView_DeleteItem(hTreeWnd,hNext_A); DeleteTreeItemListNode(hNext_A); // 1.1.3 将第二个节点hNext_B的句柄值赋值给第一个节点hNext_A hNext_A = hNext_B; // 1.1.4 如此往复删除剩余节点 while ( hNext_B = TreeView_GetNextItem(hTreeWnd,hNext_A,TVGN_NEXT) ) { TreeView_DeleteItem(hTreeWnd,hNext_A); DeleteTreeItemListNode(hNext_A); hNext_A = hNext_B; } // 1.1.5 删除最后一个节点 if ( hNext_A ) { TreeView_DeleteItem(hTreeWnd,hNext_A); DeleteTreeItemListNode(hNext_A); } } } // 2. 获取此目录下的所有文件列表,并清除列表框中的所有内容 CFileControl objFile; list<FILE_INFO> lstFileInfo; objFile.GetFileList(lpPath,lstFileInfo); ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_LIST)); // 清空列表框 g_lstListInfo.clear(); // 情况列表框信息链表 // 3. 将目录添加到Tree控件中 DWORD dwIndex = 0; for (list<FILE_INFO>::iterator i=lstFileInfo.begin(); i!=lstFileInfo.end(); i++) { TREE_ITEM strTreeItem = {0}; if ( i->bIsFolder ) { // 3.1 将目录添加到Tree控件中,并将此节点信息加入链表 strTreeItem.hTreeItem = AddItemToTree(hTreeWnd, i->szFilePath, hParent, TRUE); StringCbPrintf(strTreeItem.szFilePath, MAX_PATH, L"%s\%s", lpPath, i->szFilePath); g_lstTreeInfo.push_back(strTreeItem); continue; } // 3.2 将文件添加到List控件中并将此节点信息加入链表 AddItemToList(hWnd,*i,dwIndex); LIST_ITEM stcListItem = {0}; stcListItem.nItemIndex = dwIndex; StringCbCopy(stcListItem.szFilePath,MAX_PATH,i->szFilePath); g_lstListInfo.push_back(stcListItem); dwIndex++; } lstFileInfo.clear(); } VOID DeleteTreeItemListNode(HTREEITEM hItem) { for ( list<TREE_ITEM>::iterator i = g_lstTreeInfo.begin(); i != g_lstTreeInfo.end(); i++) { if ( i->hTreeItem != hItem ) continue; g_lstTreeInfo.erase(i); break; } } BOOL AddItemToList(HWND hWnd,FILE_INFO stcInfo, DWORD dwIndex) { HWND hListWnd = GetDlgItem(hWnd,IDC_LIST); LVITEM lvItem = {0}; lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvItem.state = 0; // 子项的状态 lvItem.stateMask = 0; // 状态有效的屏蔽位 lvItem.iImage = 0; // 与列表框关联的指定图像的索引值 lvItem.iSubItem = 0; // 子项的索引值(可以视为列号) WCHAR szInfo[64] = {0}; lvItem.iItem = dwIndex; lvItem.pszText = PathFindFileName(stcInfo.szFilePath); lvItem.cchTextMax = wcslen(lvItem.pszText)+sizeof(TCHAR); ListView_InsertItem(hListWnd, &lvItem); wsprintf(szInfo,L"%I64d KB",stcInfo.qwFileSize/1024); ListView_SetItemText(hListWnd, lvItem.iItem, 1, szInfo); wsprintf(szInfo,L"%4d年%.2d月%#02d日,%.2d:%.2d:%.2d", stcInfo.stcCreatTime.wYear, stcInfo.stcCreatTime.wMonth, stcInfo.stcCreatTime.wDay, stcInfo.stcCreatTime.wHour, stcInfo.stcCreatTime.wMinute, stcInfo.stcCreatTime.wSecond); ListView_SetItemText(hListWnd, lvItem.iItem, 2, szInfo); wsprintf(szInfo,L"%4d年%.2d月%#02d日,%.2d:%.2d:%.2d", stcInfo.stcLastWriteTime.wYear, stcInfo.stcLastWriteTime.wMonth, stcInfo.stcLastWriteTime.wDay, stcInfo.stcLastWriteTime.wHour, stcInfo.stcLastWriteTime.wMinute, stcInfo.stcLastWriteTime.wSecond); ListView_SetItemText(hListWnd, lvItem.iItem, 3, szInfo); wsprintf(szInfo,L"%4d年%.2d月%#02d日,%.2d:%.2d:%.2d", stcInfo.stcLastAccessTime.wYear, stcInfo.stcLastAccessTime.wMonth, stcInfo.stcLastAccessTime.wDay, stcInfo.stcLastAccessTime.wHour, stcInfo.stcLastAccessTime.wMinute, stcInfo.stcLastAccessTime.wSecond); ListView_SetItemText(hListWnd, lvItem.iItem, 4, szInfo); return TRUE; } BOOL SelectFolder(HWND hWnd, LPWSTR lpszFolder) { BROWSEINFO bi = {0}; ITEMIDLIST *pidl; TCHAR szPath[MAX_PATH]; bi.hwndOwner = hWnd; bi.pszDisplayName = szPath; bi.lpszTitle = TEXT("Please select a folder"); bi.ulFlags = BIF_RETURNONLYFSDIRS; if( pidl=SHBrowseForFolder(&bi) ) { SHGetPathFromIDList( pidl, lpszFolder ); return TRUE; } return FALSE; } VOID InitList(HWND hWnd) { // 1. 设置列表框样式为“可整行选择”、“有网格” ListView_SetExtendedListViewStyle( GetDlgItem(hWnd,IDC_LIST), LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_AUTOCHECKSELECT ); // 2. 初始化列表框内容 LVCOLUMN lvc = {0}; lvc.mask = LVCF_WIDTH|LVCF_TEXT; // 列表框样式 lvc.iImage = 1; // 与列表框关联的指定图像的索引值 lvc.fmt = LVCFMT_LEFT; // 列的对齐方式 lvc.pszText = L"文件名"; lvc.cx = 128; lvc.iSubItem = 0; ListView_InsertColumn(GetDlgItem(hWnd,IDC_LIST), lvc.iSubItem, &lvc); lvc.pszText = L"文件大小"; lvc.cx = 88; lvc.iSubItem = 1; ListView_InsertColumn(GetDlgItem(hWnd,IDC_LIST), lvc.iSubItem, &lvc); lvc.pszText = L"创建时间"; lvc.cx = 88; lvc.iSubItem = 2; ListView_InsertColumn(GetDlgItem(hWnd,IDC_LIST), lvc.iSubItem, &lvc); lvc.pszText = L"修改时间"; lvc.cx = 88; lvc.iSubItem = 3; ListView_InsertColumn(GetDlgItem(hWnd,IDC_LIST), lvc.iSubItem, &lvc); lvc.pszText = L"访问时间"; lvc.cx = 88; lvc.iSubItem = 4; ListView_InsertColumn(GetDlgItem(hWnd,IDC_LIST), lvc.iSubItem, &lvc); } VOID Tree_LButtonDown(HWND hWnd) { // 1. 初始化必要的信息 POINT stcPoint = {0}; // 发生此消息时的鼠标坐标 HWND hTreeWnd = GetDlgItem(hWnd,IDC_TREE); // 树形控件HEND GetCursorPos(&stcPoint); // 2. 将鼠标位置转换为相对坐标 HTREEITEM hTreeItem; TVHITTESTINFO thti; ScreenToClient(hTreeWnd,&stcPoint); thti.pt = stcPoint; thti.flags = LVHT_EX_GROUP_BACKGROUND; // 3. 如果选中的列表框中的某一项,则更新树控件内容 if ( hTreeItem = TreeView_HitTest(hTreeWnd,&thti) ) { for ( list<TREE_ITEM>::iterator i = g_lstTreeInfo.begin(); i != g_lstTreeInfo.end(); i++) { if ( i->hTreeItem != hTreeItem ) continue; UpdataControl(hWnd,i->szFilePath,hTreeItem); break; } } } VOID List_RButtonDown(HWND hWnd) { POINT stcPoint = {0}; // 发生此消息时的鼠标坐标 HWND hListWnd = GetDlgItem(hWnd,IDC_LIST); // 列表框的HWND // 1. 将鼠标位置转换为相对坐标,然后测试是否选中的列表框中的某一项 int nListItemIndex; LVHITTESTINFO thti; GetCursorPos(&stcPoint); // 2. 判断是否点击了列表项的头结点 ScreenToClient(hListWnd,&stcPoint); thti.pt = stcPoint; thti.flags = LVHT_EX_GROUP_HEADER; nListItemIndex = ListView_HitTestEx(hListWnd,&thti); if ( -1 != nListItemIndex ) { // 2.1 加载菜单资源 HMENU hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MENU1)); HMENU hPopup = GetSubMenu(hMenu, 0); if ( !hMenu || !hPopup ) return; // 2.2 将相对坐标转换为原鼠标位置 ClientToScreen(hListWnd,&stcPoint); // 2.3 弹出菜单 TrackPopupMenuEx(hPopup, TPM_LEFTALIGN|TPM_RIGHTBUTTON, stcPoint.x, stcPoint.y, hWnd, NULL); // 2.4 释放相关资源 DestroyMenu(hMenu); } }