#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;
}
最新发布