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

А. И. Легалов

template <class T> class

SShellPtr {

public:

 ~SShellPtr() {

  Free();

  _malloc->Release();

 }

 T* weak operator->() { return _p; }

 T const* operator->() const { return _p; }

 operator T const* () const { return _p; }

 T const& GetAccess () const { return *_p; }

protected:

 SShellPtr() : _p(0) {

  // Obtain malloc here, rather than

  // in the destructor.

  // Destructor must be fail-proof.

  // Revisit: Would static IMalloc * _shellMalloc work?

  if (SHGetMalloc(&_malloc) == E_FAIL) throw Exception "Couldn't obtain Shell Malloc";

 }

 void Free() {

  if (_p != 0) _malloc->Free(_p);

 _p = 0;

 }

 T * _p;

 IMalloc* _malloc;

private:

 SShellPtr(SShellPtr const& p) {}

 void operator=(SShellPtr const & p) {}

};

Обратите внимание на использование ранее показанного приема: класс SShellPtr непосредственно не пригоден для использования. Вы должны наследовать от него подкласс и реализовать в нем соответствующий конструктор.

Обратите также внимание, что я не уверен, может ли _shellMalloc быть статическим элементом SShellPtr. Проблема состоит в том, что статические элементы инициализируются перед WinMain. Из-за этого вся COM система может оказаться неустойчивой. С другой стороны, документация говорит, что Вы можете безопасно вызывать из другой API функции CoGetMalloc перед обращением к CoInitialize. Это не говорит о том, может ли SHGetMalloc, который делает почти то же самое, также вызываться в любое время в вашей программе. Подобно многим других случаям, когда система ужасно разработана или задокументирована, только эксперимент может ответить на такие вопросы. Добро пожаловать к нам с такими ответами.

Между прочим, если Вы нуждаетесь в интеллектуальном указателе, который использует специфическое распределение памяти для COM, то получите его, вызывая CoGetMalloc. Вы можете без опаски сделать этот _malloc статическим элементом и инициализировать его только один раз в вашей программе (ниже SComMalloc::GetMalloc тоже статический):

IMalloc* SComMalloc::_malloc = SComMalloc::GetMalloc();

IMalloc* SComMalloc::GetMalloc() {

 IMalloc* malloc = 0;

 if (CoGetMalloc(1, &malloc) == S_OK) return malloc;

 else return 0;

}

Это – все, что надо знать, чтобы начать использовать оболочку Windows и ее COM интерфейсы. Ниже приводится пример. Оболочка Windows имеет понятие Рабочего стола, являющегося корнем «файловой» системы. Вы обращали внимание, как Windows приложения допускают пользователя, просматривают файловую систему, начинающуюся на рабочем столе? Этим способом Вы можете, например, создавать файлы непосредственно на вашем рабочем столе, двигаться между дисководами, просматривать сетевой дисковод, и т.д. Это, в действительности, Распределенная Файловая система (PMDFS — poor man's Distributed File System) ограниченного человека (?). Как ваше приложение может получить доступ к PMDFS? Просто. В качестве примера напишем код, который позволит пользователю, выбирать папку, просматривая PMDFS. Все, что мы должны сделать — это овладеть рабочим столом, позиционироваться относительно его, запустить встроенное окно просмотра и сформировать путь, который выбрал пользователь.