Операционная система windows 32 основывается на оболочке, которая использует виртуальные папки, такие, как 'my computer' (Мой компьютер), 'desktop' (Рабочий Стол) и 'recycle bin' (Корзина). Некоторые из них являются частью физической файловой системы. Другими словами, они имеют соответствующий реальный каталог в файловой системе. Это относится, например, к системным папкам 'desktop' и 'recycle bin'. Данные каталоги могут быть использованы как InitialDir в TOpenDialog, но сначала вы должны получить их физическое месторасположение, которое может различаться на других компьютерах. Чтобы узнать их реальное месторасположение на локальном диске, вы должны воспользоваться некоторыми специальными вызовами API (смотри пример ниже). Другие папки, типа 'my computer' и 'printers' не являются частью файловой системы, они чисто виртуальные. Обращаю ваше внимание на то, что такие папки можно использовать в TOpenDialog, но никак не в InitialDir.
Виртуальные папки (я немного упрощаю) имеют тип SHITEMID (идентификатор элемента). Получить к ним доступ можно используя pointers to item identifiers list (PIDL, указатель на элемент списка идентификаторов). Для того, чтобы получить PIDL специальной папки, вы должны использовать функцию SHGetSpecialFolder. Физическое месторасположение соответствующей директории можно получить, передавая PIDL в качестве входного параметра функции GetPathFromIDList. Если папка является частью файловой системы, функция возвращает путь к ней в виде строки (которая впоследствии может использоваться как InitialDir). Но если вы хотите использовать OpenDialog только с виртуальными папками (например, с 'my computer'), то в принципе вы должны использовать PIDL как InitialDir, но это работать не будет. Я думаю дело в том, что TOpenDialog использует PIDLs только для просмотра, а для InitialDir требуются только реальные (физические) каталоги.
Вот пример, показывающий как получить путь к 'recent documents' (последние документы) и использовать его в качестве InitialDir:
procedure TForm1.Button1Click(Sender: TObject); var PIDL: Pointer; Path: LPSTR; const CSIDL_RECENT = $0008; begin Path := StrAlloc(MAX_PATH); SHGetSpecialFolderLocation(Handle, CSIDL_RECENT, @PIDL); if SHGetPathFromIDList(PIDL, Path) then // возвращает False если папка не является частью файловой системы beginOpenDialog1.InitialDir := Path;OpenDialog1.Execute;end;StrDispose(Path); end; |
Я думаю вам необходимо создать класс-оболочку для этих вызовов API. Они располагаются в shell32.dll. Наилучший совет, который я могу дать при изучении этого вопроса - копнуть поглубже файл ShlObj.h. Я также не программирую в C, но почерпнул оттуда немало ценной информации.
Вот некоторые константы, которые вам могут понадобиться:
CSIDL_DESKTOP = $0000;CSIDL_PROGRAMS = $0002;CSIDL_CONTROLS = $0003;CSIDL_PRINTERS = $0004;CSIDL_PERSONAL = $0005;CSIDL_STARTUP = $0007;CSIDL_RECENT = $0008;CSIDL_SENDTO = $0009;CSIDL_BITBUCKET = $000a;CSIDL_STARTMENU = $000b;CSIDL_DESKTOPDIRECTORY = $0010;CSIDL_DRIVES = $0011; // Мой компьютерCSIDL_NETWORK = $0012;CSIDL_NETHOOD = $0013;CSIDL_FONTS = $0014;CSIDL_TEMPLATES = $0015; |
[000280]