Страница 1 из 1

TStrings - ShellListView - ShellTreeView.

Добавлено: 26 апр 2006, 15:59
lexusrus
Здравствуйте, уважаемые программеры! Такой вопрос. Пользователь с помощью стандартных диалогов выбирает файлы и папки, которые со всем содержимым добавляются в TStrings. А задача заключается в том, чтобы в каком-нибудь визуальном компоненте отобразить структуру TStrings, т.е. в корневом каталоге будут все файлы и папки, которые были добавлены непосредственно, при щелчке на папке, показывается ее содержимое. У меня есть только вариант, когда все выбранные объекты копируются в отдельную папку на диске, а потом эта папка отображается в ShellTreeView. Но хочется все сделать виртуально.

Добавлено: 27 апр 2006, 16:16
Romeo
Предлагаю использовать обычный TreeView. Иконки для элементов можно получать через SHGetFileInfo. Контекстное меню тоже можно выдрать из системы, но это уже немного потруднее. Могу кинуть готовый код как это делается, если понадобится.

Добавлено: 02 май 2006, 07:08
lexusrus
Да, если можно, то кинь.

Добавлено: 03 май 2006, 11:52
Romeo

Код: Выделить всё

#include <shlobj.h>
#include <atlbase.h>

...

void ShowContextMenu(HWND hWnd, LPCTSTR pszPath, int x, int y)
{
   USES_CONVERSION;

   // Строим полное имя файла/каталога
   TCHAR tchFullPath[MAX_PATH];
   GetFullPathName(pszPath, sizeof(tchFullPath)/sizeof(TCHAR), tchFullPath, NULL);

   // Получаем интерфейс IShellFolder рабочего стола
   IShellFolder *pDesktopFolder;
   SHGetDesktopFolder(&pDesktopFolder);

   // Преобразуем заданный путь в LPITEMIDLIST
   LPITEMIDLIST pidl;
   pDesktopFolder->ParseDisplayName(hWnd, NULL, T2OLE(tchFullPath), NULL, &pidl, NULL);

   // Ищем последний идентификатор в полученном списке pidl
   LPITEMIDLIST pLastId = pidl;
   USHORT temp;
   while(1)
   {
       int offset = pLastId->mkid.cb;
       temp = *(USHORT*)((BYTE*)pLastId + offset);

       if(temp == 0)
           break;

       pLastId = (LPITEMIDLIST)((BYTE*)pLastId + offset);
   }
   
   // Получаем интерфейс IShellFolder родительского объекта для заданного файла/каталога
   // Примечание: родительский каталог идентифицируется списком pidl за вычетом последнего
   //             элемента, поэтому мы временно зануляем pLastId->mkid.cb, отрезая его от списка
   temp = pLastId->mkid.cb;
   pLastId->mkid.cb = 0;
   IShellFolder *pFolder;
   pDesktopFolder->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder);

   // Получаем интерфейс IContextMenu для заданного файла/каталога
   // Примечание: относительно родительского объекта заданный файл/каталог идентифицируется
   //             единственным элементом pLastId
   pLastId->mkid.cb = temp;
   IContextMenu *pContextMenu;
   pFolder->GetUIObjectOf(
      hWnd, 1, (LPCITEMIDLIST *)&pLastId, IID_IContextMenu, NULL, (void**)&pContextMenu);

   // Создаём меню
   HMENU hPopupMenu = CreatePopupMenu();

   // Заполняем меню
   pContextMenu->QueryContextMenu(hPopupMenu, 0, 1, 0x7FFF, 0);

   // Отображаем меню
   UINT nCmd = TrackPopupMenu(hPopupMenu,
      TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, x, y, 0, hWnd, 0);

   // Выполняем команду (если она была выбрана)
   if(nCmd)
   {
      CMINVOKECOMMANDINFO ici;
      ZeroMemory(&ici, sizeof(CMINVOKECOMMANDINFO));
      ici.cbSize = sizeof(CMINVOKECOMMANDINFO);

      ici.hwnd = hWnd;
      ici.lpVerb = MAKEINTRESOURCE(nCmd-1);
      ici.nShow = SW_SHOWNORMAL;

      pContextMenu->InvokeCommand(&ici);
   }

   // Получаем интерфейс IMalloc
   IMalloc *pMalloc;
   SHGetMalloc(&pMalloc);

   // Освобождаем память, выделенную для pidl
   pMalloc->Free(pidl);

   // Освобождаем все полученные интерфейсы
   pDesktopFolder->Release();
   pFolder->Release();
   pContextMenu->Release();
   pMalloc->Release();

   return;
}
Код взят с RSDN'а:
http://www.rsdn.ru/article/qna/winshell/filemenu.xml

Там также есть очень краткие коментарии, хотя, думаю, и так всё понятно.