关于SHParseDisplayName 爆炸的问题

不知道是mingw自带的api搞错了还是什么

他是这样写的

HRESULT WINAPI SHParseDisplayName(LPCWSTR,IBindCtx*,LPITEMIDLIST,SFGAOF,SFGAOF*);

第三个参数是LPITEMIDLIST,但是这样写会爆炸

微软的是这样写的

SHSTDAPI SHParseDisplayName( PCWSTR pszName, IBindCtx *pbc, PIDLIST_ABSOLUTE *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut );

也就是说第三个参数应该是LPITEMIDLIST*

于是我就加了个&但是编译器报错了

没办法,最后只好硬着头皮(LPITEMIDLIST)&lpItemList,你猜怎么着……

#include <windows.h> #include <shlobj.h> #include <tchar.h> #include <commctrl.h> #include <strsafe.h> #include <Shlwapi.h> #include <knownfolders.h> #include <ShObjIdl.h> #pragma comment(lib, "Shlwapi.lib") #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "Shell32.lib") // 禁用某些警告 #define _CRT_NONSTDC_NO_DEPRECATE #pragma warning(disable:4996) // 确保使用正确版本的公共控件 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // 避免宏重定义 #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0601 #endif #ifndef WINVER #define WINVER 0x0601 #endif // 全局状态管理结构 typedef struct { HTREEITEM hItem; BOOL isExpanded; LPITEMIDLIST pidl; BOOL isLibrary; BOOL isSystemFolder; } TreeNodeState; #define MAX_TREE_NODES 1024 TreeNodeState g_treeStates[MAX_TREE_NODES]; int g_nodeCount = 0; // 控件ID定义 #define ID_TREEVIEW 101 #define ID_EDIT_PATH 102 #define ID_BUTTON_COPY 103 // 函数声明 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HTREEITEM ExpandTreeViewItem(HWND hTreeView, HTREEITEM hItem); HRESULT PopulateChildFolders(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlParent, BOOL isLibraryParent); HTREEITEM AddFolderToTreeView(HWND hTreeView, HTREEITEM hParent, LPWSTR pszName, LPITEMIDLIST pidl, BOOL isLibrary, BOOL isSystemFolder); void CleanupTreeStates(); void DebugPrint(LPCTSTR format, ...); void UpdatePathDisplay(HWND hEdit, LPITEMIDLIST pidl, BOOL isLibrary); void CopyPathToClipboard(HWND hWnd, LPCTSTR path); BOOL IsLibraryFolder(LPITEMIDLIST pidl); BOOL IsSystemFolder(LPITEMIDLIST pidl); BOOL ShouldSkipFolder(LPCTSTR pszName, BOOL isLibraryContext); HRESULT HandleLibraryFolder(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlLibrary); HRESULT SafeGetDisplayName(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPWSTR pszName, DWORD cchName); HRESULT EnumerateFolderContents(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlFolder, BOOL isLibraryContext); HRESULT AddKnownLibraryFolders(HWND hTreeView, HTREEITEM hParent); HRESULT EnumerateLibraryContents(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlLibrary); // 主窗口类名 #define CLASS_NAME _T("TreeViewDesktopBrowser") // 函数实现 void DebugPrint(LPCTSTR format, ...) { TCHAR buffer[1024]; va_list args; va_start(args, format); StringCchVPrintf(buffer, _countof(buffer), format, args); va_end(args); OutputDebugString(buffer); } void CleanupTreeStates() { DebugPrint(L"清理状态\n"); for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].pidl) { CoTaskMemFree(g_treeStates[i].pidl); g_treeStates[i].pidl = NULL; } } g_nodeCount = 0; } HTREEITEM AddFolderToTreeView(HWND hTreeView, HTREEITEM hParent, LPWSTR pszName, LPITEMIDLIST pidl, BOOL isLibrary, BOOL isSystemFolder) { if (!hTreeView || !pszName || !pidl) return NULL; TVINSERTSTRUCT tvInsert = { 0 }; tvInsert.hParent = hParent; tvInsert.hInsertAfter = TVI_LAST; tvInsert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN; tvInsert.item.pszText = pszName; tvInsert.item.lParam = (LPARAM)pidl; tvInsert.item.cChildren = 1; HTREEITEM hItem = TreeView_InsertItem(hTreeView, &tvInsert); if (hItem) { if (g_nodeCount < MAX_TREE_NODES) { g_treeStates[g_nodeCount].hItem = hItem; g_treeStates[g_nodeCount].isExpanded = FALSE; g_treeStates[g_nodeCount].pidl = pidl; g_treeStates[g_nodeCount].isLibrary = isLibrary; g_treeStates[g_nodeCount].isSystemFolder = isSystemFolder; g_nodeCount++; } } else { DebugPrint(L"添加文件夹失败: %s\n", pszName); CoTaskMemFree(pidl); } return hItem; } HTREEITEM ExpandTreeViewItem(HWND hTreeView, HTREEITEM hItem) { if (!hTreeView || !hItem) return NULL; TVITEM tvItem = { 0 }; tvItem.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; tvItem.hItem = hItem; tvItem.stateMask = TVIS_EXPANDED; if (!TreeView_GetItem(hTreeView, &tvItem)) { return NULL; } LPITEMIDLIST pidlParent = (LPITEMIDLIST)tvItem.lParam; if (!pidlParent) return NULL; BOOL isCurrentlyExpanded = (tvItem.state & TVIS_EXPANDED) != 0; if (!isCurrentlyExpanded) { BOOL isLibraryParent = FALSE; for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].hItem == hItem) { isLibraryParent = g_treeStates[i].isLibrary; break; } } HTREEITEM hFirstChild = TreeView_GetChild(hTreeView, hItem); if (!hFirstChild) { HRESULT hr = PopulateChildFolders(hTreeView, hItem, pidlParent, isLibraryParent); if (FAILED(hr)) { DebugPrint(L"展开失败: 0x%08X\n", hr); return NULL; } } TreeView_Expand(hTreeView, hItem, TVE_EXPAND); for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].hItem == hItem) { g_treeStates[i].isExpanded = TRUE; break; } } } else { TreeView_Expand(hTreeView, hItem, TVE_COLLAPSE); for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].hItem == hItem) { g_treeStates[i].isExpanded = FALSE; break; } } } return hItem; } HRESULT PopulateChildFolders(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlParent, BOOL isLibraryParent) { DebugPrint(L"填充子文件夹,父节点是库: %d\n", isLibraryParent); if (IsLibraryFolder(pidlParent)) { return HandleLibraryFolder(hTreeView, hParent, pidlParent); } return EnumerateFolderContents(hTreeView, hParent, pidlParent, isLibraryParent); } HRESULT SafeGetDisplayName(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPWSTR pszName, DWORD cchName) { if (!pFolder || !pidl || !pszName || cchName == 0) { return E_INVALIDARG; } STRRET strRet; HRESULT hr = pFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strRet); if (SUCCEEDED(hr)) { hr = StrRetToBuf(&strRet, pidl, pszName, cchName); if (strRet.uType == STRRET_WSTR && strRet.pOleStr) { CoTaskMemFree(strRet.pOleStr); } } return hr; } BOOL IsLibraryFolder(LPITEMIDLIST pidl) { if (!pidl) return FALSE; LPITEMIDLIST pidlLibraries = NULL; if (SUCCEEDED(SHGetKnownFolderIDList(FOLDERID_Libraries, 0, NULL, &pidlLibraries))) { BOOL isEqual = ILIsEqual(pidl, pidlLibraries); CoTaskMemFree(pidlLibraries); if (isEqual) return TRUE; } IShellFolder* pDesktop = NULL; if (SUCCEEDED(SHGetDesktopFolder(&pDesktop))) { WCHAR szName[MAX_PATH]; if (SUCCEEDED(SafeGetDisplayName(pDesktop, pidl, szName, _countof(szName)))) { if (_wcsicmp(szName, L"库") == 0 || _wcsicmp(szName, L"Libraries") == 0 || wcsstr(szName, L"库") != NULL) { // 包含"库"字样的也可能是库 pDesktop->Release(); return TRUE; } } pDesktop->Release(); } return FALSE; } BOOL IsSystemFolder(LPITEMIDLIST pidl) { if (!pidl) return FALSE; // 通过路径判断系统文件夹 WCHAR szPath[MAX_PATH]; if (SHGetPathFromIDList(pidl, szPath)) { // 常见的系统文件夹路径模式 if (wcsstr(szPath, L"\\Windows\\") != NULL || wcsstr(szPath, L"\\Program Files\\") != NULL || wcsstr(szPath, L"\\ProgramData\\") != NULL || (wcsstr(szPath, L"\\Users\\") != NULL && wcsstr(szPath, L"\\AppData\\") != NULL)) { return TRUE; } } return FALSE; } void CopyPathToClipboard(HWND hWnd, LPCTSTR path) { if (OpenClipboard(hWnd)) { EmptyClipboard(); SIZE_T cbSize = (_tcslen(path) + 1) * sizeof(TCHAR); HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cbSize); if (hGlobal) { LPTSTR pszData = (LPTSTR)GlobalLock(hGlobal); if (pszData) { _tcscpy_s(pszData, _tcslen(path) + 1, path); GlobalUnlock(hGlobal); #ifdef UNICODE SetClipboardData(CF_UNICODETEXT, hGlobal); #else SetClipboardData(CF_TEXT, hGlobal); #endif } else { GlobalFree(hGlobal); } } CloseClipboard(); MessageBox(hWnd, _T("路径已复制到剪贴板"), _T("成功"), MB_ICONINFORMATION); } else { MessageBox(hWnd, _T("无法打开剪贴板"), _T("错误"), MB_ICONERROR); } } HRESULT HandleLibraryFolder(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlLibrary) { DebugPrint(L"处理库文件夹\n"); return EnumerateLibraryContents(hTreeView, hParent, pidlLibrary); } // 修复的 AddKnownLibraryFolders 函数,避免在已知库中重复添加 HRESULT AddKnownLibraryFolders(HWND hTreeView, HTREEITEM hParent) { DebugPrint(L"添加已知库文件夹\n"); // 检查父节点是否是已知库文件夹本身,如果是则跳过添加 TVITEM tvParent = { 0 }; tvParent.mask = TVIF_HANDLE | TVIF_TEXT; tvParent.hItem = hParent; WCHAR szParentName[MAX_PATH] = L""; tvParent.pszText = szParentName; tvParent.cchTextMax = _countof(szParentName); if (TreeView_GetItem(hTreeView, &tvParent)) { // 检查父节点名称是否是已知库文件夹 static const LPCWSTR knownLibraryNames[] = { L"文档", L"图片", L"音乐", L"视频", L"Documents", L"Pictures", L"Music", L"Videos", NULL }; BOOL isParentKnownLibrary = FALSE; for (int i = 0; knownLibraryNames[i] != NULL; i++) { if (wcscmp(szParentName, knownLibraryNames[i]) == 0) { isParentKnownLibrary = TRUE; break; } } if (isParentKnownLibrary) { DebugPrint(L"父节点是已知库文件夹 %s,跳过添加已知库文件夹\n", szParentName); return S_FALSE; // 跳过添加 } } struct { KNOWNFOLDERID folderId; LPCWSTR name; } libraries[] = { { FOLDERID_Documents, L"文档" }, { FOLDERID_Pictures, L"图片" }, { FOLDERID_Music, L"音乐" }, { FOLDERID_Videos, L"视频" }, }; int addedCount = 0; for (int i = 0; i < ARRAYSIZE(libraries); i++) { LPITEMIDLIST pidl = NULL; HRESULT hr = SHGetKnownFolderIDList(libraries[i].folderId, 0, NULL, &pidl); if (SUCCEEDED(hr) && pidl) { UINT pidlSize = ILGetSize(pidl); if (pidlSize > 0) { LPITEMIDLIST pidlPersistent = (LPITEMIDLIST)CoTaskMemAlloc(pidlSize); if (pidlPersistent) { memcpy(pidlPersistent, pidl, pidlSize); BOOL isLibrary = IsLibraryFolder(pidlPersistent); BOOL isSystem = IsSystemFolder(pidlPersistent); HTREEITEM hNewItem = AddFolderToTreeView(hTreeView, hParent, (LPWSTR)libraries[i].name, pidlPersistent, isLibrary, isSystem); if (hNewItem) { addedCount++; DebugPrint(L"添加已知库文件夹: %s\n", libraries[i].name); } else { CoTaskMemFree(pidlPersistent); } } } CoTaskMemFree(pidl); } } DebugPrint(L"成功添加 %d 个已知库文件夹\n", addedCount); return addedCount > 0 ? S_OK : E_FAIL; } BOOL ShouldSkipFolder(LPCTSTR pszName, BOOL isLibraryContext) { if (!pszName) return FALSE; if (pszName[0] == L'\0' || wcscmp(pszName, L".") == 0 || wcscmp(pszName, L"..") == 0) { return TRUE; } static const LPCWSTR skipFolders[] = { L"Application Data", L"Cookies", L"Local Settings", L"NetHood", L"PrintHood", L"Recent", L"SendTo", L"Templates", L"$Recycle.Bin", L"System32", L"SysWOW64", NULL }; for (int i = 0; skipFolders[i] != NULL; i++) { if (_wcsicmp(pszName, skipFolders[i]) == 0) { return TRUE; } } return FALSE; } HRESULT EnumerateFolderContents(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlFolder, BOOL isLibraryContext) { DebugPrint(L"枚举文件夹内容\n"); IShellFolder* pFolder = NULL; HRESULT hr = SHBindToObject(NULL, pidlFolder, NULL, IID_IShellFolder, (void**)&pFolder); if (FAILED(hr)) { DebugPrint(L"绑定文件夹失败: 0x%08X\n", hr); return hr; } IEnumIDList* pEnum = NULL; hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS, &pEnum); if (FAILED(hr) || !pEnum) { DebugPrint(L"枚举失败: 0x%08X\n", hr); pFolder->Release(); return FAILED(hr) ? hr : E_FAIL; } int itemCount = 0; LPITEMIDLIST pidlChild = NULL; ULONG cFetched = 0; while (SUCCEEDED(pEnum->Next(1, &pidlChild, &cFetched)) && cFetched > 0) { WCHAR szName[MAX_PATH] = L""; hr = SafeGetDisplayName(pFolder, pidlChild, szName, _countof(szName)); if (SUCCEEDED(hr)) { if (ShouldSkipFolder(szName, isLibraryContext)) { CoTaskMemFree(pidlChild); continue; } LPITEMIDLIST pidlCombined = ILCombine(pidlFolder, pidlChild); if (pidlCombined) { BOOL isChildLibrary = IsLibraryFolder(pidlCombined); BOOL isSystemFolder = IsSystemFolder(pidlCombined); UINT pidlSize = ILGetSize(pidlCombined); if (pidlSize > 0) { LPITEMIDLIST pidlPersistent = (LPITEMIDLIST)CoTaskMemAlloc(pidlSize); if (pidlPersistent) { memcpy(pidlPersistent, pidlCombined, pidlSize); HTREEITEM hNewItem = AddFolderToTreeView(hTreeView, hParent, szName, pidlPersistent, isChildLibrary, isSystemFolder); if (hNewItem) { itemCount++; DebugPrint(L"添加文件夹: %s (库: %d, 系统: %d)\n", szName, isChildLibrary, isSystemFolder); } else { CoTaskMemFree(pidlPersistent); } } } CoTaskMemFree(pidlCombined); } } CoTaskMemFree(pidlChild); } pEnum->Release(); pFolder->Release(); DebugPrint(L"枚举完成,添加 %d 个项目\n", itemCount); return S_OK; } // 修复的 EnumerateLibraryContents 函数 - 现在会正确枚举库内容,避免重复添加已知库 HRESULT EnumerateLibraryContents(HWND hTreeView, HTREEITEM hParent, LPITEMIDLIST pidlLibrary) { DebugPrint(L"枚举库内容 - 开始\n"); int totalAdded = 0; // 1. 首先添加已知的库文件夹 HRESULT hr = AddKnownLibraryFolders(hTreeView, hParent); if (SUCCEEDED(hr)) { DebugPrint(L"已知库文件夹添加完成\n"); totalAdded += 4; // 文档、图片、音乐、视频四个已知库 } // 2. 然后枚举库中的其他文件夹(不包括已知的库文件夹) IShellFolder* pFolder = NULL; hr = SHBindToObject(NULL, pidlLibrary, NULL, IID_IShellFolder, (void**)&pFolder); if (FAILED(hr)) { DebugPrint(L"绑定库文件夹失败: 0x%08X\n", hr); return hr; } IEnumIDList* pEnum = NULL; hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS, &pEnum); if (FAILED(hr) || !pEnum) { DebugPrint(L"枚举库内容失败: 0x%08X\n", hr); pFolder->Release(); return FAILED(hr) ? hr : E_FAIL; } int enumeratedCount = 0; LPITEMIDLIST pidlChild = NULL; ULONG cFetched = 0; // 定义已知库文件夹的名称列表(多种语言) static const LPCWSTR knownLibraryNames[] = { L"文档", L"图片", L"音乐", L"视频", L"Documents", L"Pictures", L"Music", L"Videos", NULL }; while (SUCCEEDED(pEnum->Next(1, &pidlChild, &cFetched)) && cFetched > 0) { WCHAR szName[MAX_PATH] = L""; hr = SafeGetDisplayName(pFolder, pidlChild, szName, _countof(szName)); if (SUCCEEDED(hr)) { // 检查是否为已知库文件夹 BOOL isKnownLibrary = FALSE; for (int i = 0; knownLibraryNames[i] != NULL; i++) { if (wcscmp(szName, knownLibraryNames[i]) == 0) { isKnownLibrary = TRUE; break; } } // 跳过已知的库文件夹(已经通过AddKnownLibraryFolders添加) if (isKnownLibrary) { DebugPrint(L"跳过已知库文件夹: %s\n", szName); CoTaskMemFree(pidlChild); continue; } if (ShouldSkipFolder(szName, TRUE)) { CoTaskMemFree(pidlChild); continue; } LPITEMIDLIST pidlCombined = ILCombine(pidlLibrary, pidlChild); if (pidlCombined) { BOOL isChildLibrary = IsLibraryFolder(pidlCombined); BOOL isSystemFolder = IsSystemFolder(pidlCombined); UINT pidlSize = ILGetSize(pidlCombined); if (pidlSize > 0) { LPITEMIDLIST pidlPersistent = (LPITEMIDLIST)CoTaskMemAlloc(pidlSize); if (pidlPersistent) { memcpy(pidlPersistent, pidlCombined, pidlSize); HTREEITEM hNewItem = AddFolderToTreeView(hTreeView, hParent, szName, pidlPersistent, isChildLibrary, isSystemFolder); if (hNewItem) { enumeratedCount++; totalAdded++; DebugPrint(L"添加库中项目: %s (库: %d, 系统: %d)\n", szName, isChildLibrary, isSystemFolder); } else { CoTaskMemFree(pidlPersistent); } } } CoTaskMemFree(pidlCombined); } } CoTaskMemFree(pidlChild); } pEnum->Release(); pFolder->Release(); DebugPrint(L"库枚举完成,总共添加 %d 个项目(已知: %d, 枚举: %d)\n", totalAdded, totalAdded - enumeratedCount, enumeratedCount); return S_OK; } void UpdatePathDisplay(HWND hEdit, LPITEMIDLIST pidl, BOOL isLibrary) { if (!hEdit || !pidl) return; WCHAR szDisplay[MAX_PATH * 2] = L""; if (isLibrary) { IShellFolder* pDesktop = NULL; if (SUCCEEDED(SHGetDesktopFolder(&pDesktop))) { WCHAR szDisplayName[MAX_PATH]; if (SUCCEEDED(SafeGetDisplayName(pDesktop, pidl, szDisplayName, _countof(szDisplayName)))) { WCHAR szPath[MAX_PATH]; if (SHGetPathFromIDList(pidl, szPath)) { StringCchPrintf(szDisplay, _countof(szDisplay), L"库: %s\n路径: %s", szDisplayName, szPath); } else { StringCchPrintf(szDisplay, _countof(szDisplay), L"库: %s", szDisplayName); } } pDesktop->Release(); } } else { WCHAR szPath[MAX_PATH]; if (SHGetPathFromIDList(pidl, szPath)) { StringCchCopy(szDisplay, _countof(szDisplay), szPath); } else { IShellFolder* pDesktop = NULL; if (SUCCEEDED(SHGetDesktopFolder(&pDesktop))) { WCHAR szDisplayName[MAX_PATH]; if (SUCCEEDED(SafeGetDisplayName(pDesktop, pidl, szDisplayName, _countof(szDisplayName)))) { StringCchPrintf(szDisplay, _countof(szDisplay), L"虚拟文件夹: %s", szDisplayName); } pDesktop->Release(); } } } SetWindowText(hEdit, szDisplay); } // WndProc 和 WinMain 函数保持不变 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hTreeView = NULL; static HWND hEditPath = NULL; static HWND hButtonCopy = NULL; static HTREEITEM hDesktopItem = NULL; switch (message) { case WM_CREATE: { // 创建控件 CreateWindow(L"STATIC", L"所选路径:", WS_CHILD | WS_VISIBLE | SS_LEFT, 10, 10, 100, 20, hWnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hEditPath = CreateWindow(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY, 120, 10, 600, 25, hWnd, (HMENU)ID_EDIT_PATH, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hButtonCopy = CreateWindow(L"BUTTON", L"复制路径", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 730, 10, 100, 25, hWnd, (HMENU)ID_BUTTON_COPY, ((LPCREATESTRUCT)lParam)->hInstance, NULL); hTreeView = CreateWindow(WC_TREEVIEW, L"", WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_TRACKSELECT, 10, 50, 860, 580, hWnd, (HMENU)ID_TREEVIEW, ((LPCREATESTRUCT)lParam)->hInstance, NULL); if (!hTreeView) { MessageBox(hWnd, L"TreeView 创建失败!", L"错误", MB_ICONERROR); return -1; } HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); if (hFont) { SendMessage(hEditPath, WM_SETFONT, (WPARAM)hFont, TRUE); SendMessage(hButtonCopy, WM_SETFONT, (WPARAM)hFont, TRUE); SendMessage(hTreeView, WM_SETFONT, (WPARAM)hFont, TRUE); } // 初始化桌面根节点 IShellFolder* pDesktopFolder = NULL; HRESULT hr = SHGetDesktopFolder(&pDesktopFolder); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlDesktop = NULL; hr = SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidlDesktop); if (SUCCEEDED(hr)) { WCHAR szName[MAX_PATH]; hr = SafeGetDisplayName(pDesktopFolder, pidlDesktop, szName, _countof(szName)); if (SUCCEEDED(hr)) { UINT pidlSize = ILGetSize(pidlDesktop); if (pidlSize > 0) { LPITEMIDLIST pidlPersistent = (LPITEMIDLIST)CoTaskMemAlloc(pidlSize); if (pidlPersistent) { memcpy(pidlPersistent, pidlDesktop, pidlSize); TVINSERTSTRUCT tvInsert = { 0 }; tvInsert.hParent = TVI_ROOT; tvInsert.hInsertAfter = TVI_LAST; tvInsert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN; tvInsert.item.pszText = szName; tvInsert.item.lParam = (LPARAM)pidlPersistent; tvInsert.item.cChildren = 1; hDesktopItem = TreeView_InsertItem(hTreeView, &tvInsert); if (hDesktopItem) { DebugPrint(L"添加桌面节点: %s\n", szName); TreeView_Expand(hTreeView, hDesktopItem, TVE_EXPAND); TreeView_SelectItem(hTreeView, hDesktopItem); UpdatePathDisplay(hEditPath, pidlDesktop, FALSE); } else { CoTaskMemFree(pidlPersistent); } } } } CoTaskMemFree(pidlDesktop); } pDesktopFolder->Release(); } break; } case WM_COMMAND: { int wmId = LOWORD(wParam); if (wmId == ID_BUTTON_COPY) { WCHAR szPath[MAX_PATH * 2]; GetWindowText(hEditPath, szPath, _countof(szPath)); if (wcslen(szPath) > 0) { CopyPathToClipboard(hWnd, szPath); } } break; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; if (pnmh->idFrom == ID_TREEVIEW) { switch (pnmh->code) { case TVN_SELCHANGED: { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; TVITEM tvItem = { 0 }; tvItem.mask = TVIF_HANDLE | TVIF_PARAM; tvItem.hItem = pnmtv->itemNew.hItem; if (TreeView_GetItem(hTreeView, &tvItem)) { LPITEMIDLIST pidl = (LPITEMIDLIST)tvItem.lParam; if (pidl) { BOOL isLibrary = FALSE; for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].hItem == pnmtv->itemNew.hItem) { isLibrary = g_treeStates[i].isLibrary; break; } } UpdatePathDisplay(hEditPath, pidl, isLibrary); } } break; } case TVN_ITEMEXPANDING: { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; if (pnmtv->action == TVE_EXPAND) { TVITEM tvItem = { 0 }; tvItem.mask = TVIF_HANDLE | TVIF_PARAM; tvItem.hItem = pnmtv->itemNew.hItem; if (TreeView_GetItem(hTreeView, &tvItem)) { LPITEMIDLIST pidl = (LPITEMIDLIST)tvItem.lParam; if (pidl) { BOOL isLibraryParent = FALSE; for (int i = 0; i < g_nodeCount; i++) { if (g_treeStates[i].hItem == pnmtv->itemNew.hItem) { isLibraryParent = g_treeStates[i].isLibrary; break; } } HTREEITEM hFirstChild = TreeView_GetChild(hTreeView, pnmtv->itemNew.hItem); if (!hFirstChild) { HRESULT hr = PopulateChildFolders(hTreeView, pnmtv->itemNew.hItem, pidl, isLibraryParent); if (FAILED(hr)) { DebugPrint(L"填充子文件夹失败: 0x%08X\n", hr); } } } } } break; } } } break; } case WM_SIZE: { if (hTreeView && hEditPath && hButtonCopy) { RECT rcClient; GetClientRect(hWnd, &rcClient); MoveWindow(hEditPath, 120, 10, rcClient.right - 240, 25, TRUE); MoveWindow(hButtonCopy, rcClient.right - 110, 10, 100, 25, TRUE); MoveWindow(hTreeView, 10, 50, rcClient.right - 20, rcClient.bottom - 60, TRUE); } break; } case WM_DESTROY: CleanupTreeStates(); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { MessageBox(NULL, _T("COM初始化失败!"), _T("错误"), MB_ICONERROR); return 1; } INITCOMMONCONTROLSEX icex; ZeroMemory(&icex, sizeof(icex)); icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_TREEVIEW_CLASSES | ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES; if (!InitCommonControlsEx(&icex)) { InitCommonControls(); } WNDCLASSEX wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszClassName = CLASS_NAME; if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("窗口注册失败!"), _T("错误"), MB_ICONERROR); CoUninitialize(); return 1; } HWND hWnd = CreateWindow( CLASS_NAME, _T("桌面浏览器 - 完整库支持版"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 700, NULL, NULL, hInstance, NULL); if (!hWnd) { MessageBox(NULL, _T("窗口创建失败!"), _T("错误"), MB_ICONERROR); CoUninitialize(); return 1; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } CleanupTreeStates(); CoUninitialize(); return (int)msg.wParam; }
最新发布
09-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值