: ```// FileExplorer.cpp #include <windows.h> #include <commctrl.h> #include <shlwapi.h> #include <tchar.h> #include <shellapi.h> #pragma comment(lib, "Comctl32.lib") #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "Shlwapi.lib") #define IDC_TREEVIEW 1001 // Глобальные переменные HINSTANCE hInst; HWND hTreeView; // Объявления функций LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HTREEITEM AddItemToTree(HWND, LPCTSTR, HTREEITEM, BOOL hasChildren); void PopulateTreeView(HWND); void AddDriveNodes(HWND); void AddDummyNode(HTREEITEM hParent); void ExpandItem(HTREEITEM hItem); int WINAPI _tWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR    lpCmdLine, _In_ int       nCmdShow) { MSG msg; WNDCLASS wc = { 0 }; HWND hwnd; hInst = hInstance; // Регистрируем класс окна wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.hInstance = hInstance; wc.lpszClassName = _T("FileExplorerClass"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClass(&wc); // Создаем главное окно hwnd = CreateWindow( wc.lpszClassName, _T("Проводник файловой системы"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 600, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Цикл обработки сообщений while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } void InitTreeViewImageLists(HWND hwndTV) { SHFILEINFO shfi = { 0 }; HIMAGELIST himl; // Получаем системный список изображений для небольших иконок himl = (HIMAGELIST)SHGetFileInfo( _T("C:\\"), 0, &shfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON); if (himl) { // Связываем полученный список изображений с контролом дерева TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL); } else { // Обработка ошибки: SHGetFileInfo не удалось MessageBox(hwndTV, _T("Не удалось получить системный список изображений."), _T("Ошибка"), MB_ICONERROR); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: { // Инициализируем общие контролы INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_TREEVIEW_CLASSES; InitCommonControlsEx(&icex); RECT rcClient; GetClientRect(hwnd, &rcClient); // Создаем контрол дерева hTreeView = CreateWindowEx(0, WC_TREEVIEW, _T("Tree View"), WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, 0, 0, rcClient.right, rcClient.bottom, hwnd, (HMENU)IDC_TREEVIEW, hInst, NULL); InitTreeViewImageLists(hTreeView); // Заполняем дерево PopulateTreeView(hTreeView); } break; case WM_SIZE: { // Изменяем размер контрола дерева при изменении размера окна RECT rcClient; GetClientRect(hwnd, &rcClient); SetWindowPos(hTreeView, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER); } break; case WM_NOTIFY: { LPNMHDR lpnmh = (LPNMHDR)lParam; if (lpnmh->hwndFrom == hTreeView) { if (lpnmh->code == TVN_ITEMEXPANDING) { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; HTREEITEM hItem = pnmtv->itemNew.hItem; ExpandItem(hItem); } } } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } void PopulateTreeView(HWND hTreeView) { // Добавляем корневые узлы для всех логических дисков AddDriveNodes(hTreeView); } void AddDriveNodes(HWND hTreeView) { TCHAR szDrives[MAX_PATH] = { 0 }; DWORD dwResult = GetLogicalDriveStrings(MAX_PATH - 1, szDrives); if (dwResult > 0 && dwResult <= MAX_PATH) { TCHAR* szSingleDrive = szDrives; while (*szSingleDrive) { // Получаем тип диска UINT driveType = GetDriveType(szSingleDrive); // Определяем, является ли диск доступным if (driveType == DRIVE_FIXED || driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM) { // Добавляем диск в дерево HTREEITEM hRoot = AddItemToTree(hTreeView, szSingleDrive, TVI_ROOT, TRUE); // Добавляем фиктивный узел, чтобы отобразить кнопку раскрытия AddDummyNode(hRoot); } // Переходим к следующему диску szSingleDrive += _tcslen(szSingleDrive) + 1; } } else { // Обработка ошибки MessageBox(hTreeView, _T("Не удалось получить список логических дисков."), _T("Ошибка"), MB_ICONERROR); } } HTREEITEM AddItemToTree(HWND hwndTV, LPCTSTR lpszItem, HTREEITEM hParent, BOOL hasChildren) { TVITEM tvi = { 0 }; TVINSERTSTRUCT tvins = { 0 }; SHFILEINFO shfi = { 0 }; // Получаем информацию о файле для получения иконки и отображаемого имени if (SHGetFileInfo( lpszItem, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(SHFILEINFO), SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_TYPENAME)) { tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM; tvi.pszText = shfi.szDisplayName; tvi.cchTextMax = (int)_tcslen(shfi.szDisplayName); tvi.iImage = shfi.iIcon; tvi.iSelectedImage = shfi.iIcon; tvi.cChildren = hasChildren ? 1 : 0; tvi.lParam = (LPARAM)_tcsdup(lpszItem); // Дублируем строку пути } else { tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM; tvi.pszText = (LPTSTR)lpszItem; tvi.cchTextMax = (int)_tcslen(lpszItem); tvi.cChildren = hasChildren ? 1 : 0; tvi.lParam = (LPARAM)_tcsdup(lpszItem); } tvins.item = tvi; tvins.hInsertAfter = TVI_LAST; tvins.hParent = hParent; HTREEITEM hNewItem = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)&tvins); // Если у элемента есть дети, добавляем фиктивный узел if (hasChildren) { AddDummyNode(hNewItem); } return hNewItem; } void AddDummyNode(HTREEITEM hParent) { TVITEM tvi = { 0 }; TVINSERTSTRUCT tvins = { 0 }; tvi.mask = TVIF_TEXT; tvi.cchTextMax = 0; // Исправленная строка: tvi.pszText = (LPTSTR)_T(""); // Пустой текст для фиктивного узла tvins.item = tvi; tvins.hInsertAfter = TVI_LAST; tvins.hParent = hParent; // Вставляем фиктивный дочерний узел TreeView_InsertItem(hTreeView, &tvins); } void ExpandItem(HTREEITEM hItem) { TVITEM tvi = { 0 }; tvi.hItem = hItem; tvi.mask = TVIF_PARAM | TVIF_CHILDREN; TreeView_GetItem(hTreeView, &tvi); // Проверяем, есть ли у узла фиктивный ребенок HTREEITEM hChild = TreeView_GetChild(hTreeView, hItem); if (hChild) { // Удаляем фиктивный дочерний узел TreeView_DeleteItem(hTreeView, hChild); // Добавляем реальные дочерние элементы LPTSTR szPath = (LPTSTR)tvi.lParam; WIN32_FIND_DATA ffd; HANDLE hFind = INVALID_HANDLE_VALUE; TCHAR szDir[MAX_PATH]; TCHAR szFullPath[MAX_PATH]; // Подготавливаем строку для функций поиска файлов _stprintf_s(szDir, MAX_PATH, _T("%s*"), szPath); // Находим первый файл в директории hFind = FindFirstFile(szDir, &ffd); if (INVALID_HANDLE_VALUE == hFind) return; do { // Пропускаем скрытые и системные файлы if (_tcscmp(ffd.cFileName, _T(".")) != 0 && _tcscmp(ffd.cFileName, _T("..")) != 0 && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { // Строим полный путь _stprintf_s(szFullPath, MAX_PATH, _T("%s%s%s"), szPath, ffd.cFileName, (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _T("\\") : _T("")); BOOL hasChild = FALSE; if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // Проверяем, есть ли поддиректории TCHAR szSubDir[MAX_PATH]; _stprintf_s(szSubDir, MAX_PATH, _T("%s*"), szFullPath); WIN32_FIND_DATA ffdSub; HANDLE hFindSub = FindFirstFile(szSubDir, &ffdSub); if (hFindSub != INVALID_HANDLE_VALUE) { do { if ((ffdSub.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(ffdSub.cFileName, _T(".")) != 0 && _tcscmp(ffdSub.cFileName, _T("..")) != 0) { hasChild = TRUE; break; } } while (FindNextFile(hFindSub, &ffdSub) != 0); FindClose(hFindSub); } } // Добавляем элемент в дерево HTREEITEM hNewItem = AddItemToTree(hTreeView, szFullPath, hItem, hasChild); if (hasChild) { // Добавляем фиктивный узел к новому элементу AddDummyNode(hNewItem); } } } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); // Обновляем информацию о количестве детей у узла tvi.cChildren = TreeView_GetChild(hTreeView, hItem) ? 1 : 0; TreeView_SetItem(hTreeView, &tvi); } }```