Читать «Применение Windows API» онлайн - страница 32

А. И. Легалов

char path [MAX_PATH];

path [0] = '\0';

Desktop desktop;

ShPath browseRoot(desktop, unicodePath);

if (browseRoot.IsOK()) {

 FolderBrowser browser(hwnd, browseRoot, BIF_RETURNONLYFSDIRS, "Select folder of your choice");

 if (folder.IsOK()) {

  strcpy (path, browser.GetPath());

 }

}

Давайте, запустим объект desktop. Он использует интерфейс по имени IShellFolder. Обратите внимание, как мы приходим к Первому Правилу Захвата. Мы распределяем ресурсы в конструкторе, вызывая функцию API SHGetDesktopFolder. Интеллектуальный указатель интерфейса будет заботиться об управлении ресурсами (подсчет ссылок).

class Desktop: public SIfacePtr<IShellFolder> {

public:

 Desktop() {

  if (SHGetDesktopFolder(&_p) != NOERROR) throw "SHGetDesktopFolder failed";

 }

};

Как только мы получили рабочий стол, мы должны создать специальный вид пути, который используется PMDFS. Класс ShPath инкапсулирует этот «путь». Он создан из правильного Unicode пути (используйте mbstowcs, чтобы преобразовать путь ASCII в Unicode: int mbstowcs(wchar_t *wchar, const char *mbchar, size_t count)). Результат преобразования — обобщенный путь относительно рабочего стола. Обратите внимание, что память для нового пути распределена оболочкой – мы инкапсулируем это в SShellPtr, чтобы быть уверенными в правильном освобождении.

class ShPath: public SShellPtr<ITEMIDLIST> {

public:

 ShPath (SIfacePtr<IShellFolder>& folder, wchar_t* path) {

  ULONG lenParsed = 0;

  _hresult = folder->ParseDisplayName(0, 0, path, &lenParsed, &_p, 0);

 }

 bool IsOK() const {

  return SUCCEEDED(_hresult);

 }

private:

 HRESULT _hresult;

};

Этот путь оболочки станет корнем, из которого окно просмотра начнет его взаимодействие с пользователем.

С точки зрения клиентского кода, окно просмотра — путь, выбранный пользователем. Именно поэтому он наследуется от SShellPtr<ITEMIDLIST>.

Между прочим, ITEMIDLIST — официальное имя для этого обобщенного пути. Это — список, и я не назвал его SHITEMID'ом. Впредь я буду воздерживаться от любых дальнейших комментариев или шуток относительно соглашений, связанных с именами, используемыми в оболочке.

class FolderBrowser: public SShellPtr<ITEMIDLIST> {

public:

 FolderBrowser(HWND hwndOwner, SShellPtr<ITEMIDLIST>& root, UINT browseForWhat, char const *title);

 char const* GetDisplayName() { return _displayName; }

 char const* GetPath() { return _fullPath; }

 bool IsOK()const { return _p != 0; };

private:

 char _displayName[MAX_PATH];

 char _fullPath[MAX_PATH];

 BROWSEINFO _browseInfo;

};

FolderBrowser::FolderBrowser(HWND hwndOwner, SShellPtr<ITEMIDLIST>& root, UINT browseForWhat, char const *title) {