А. Легалов - Применение Windows API
- Название:Применение Windows API
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:2002
- Город:Красноярск
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Легалов - Применение Windows API краткое содержание
Применение Windows API - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
}
bool IsOK() const {
return SUCCEEDED(_hresult);
}
private:
HRESULT _hresult;
};
Этот путь оболочки станет корнем, из которого окно просмотра начнет его взаимодействие с пользователем.
С точки зрения клиентского кода, окно просмотра — путь, выбранный пользователем. Именно поэтому он наследуется от SShellPtr.
Между прочим, ITEMIDLIST — официальное имя для этого обобщенного пути. Это — список, и я не назвал его SHITEMID'ом. Впредь я буду воздерживаться от любых дальнейших комментариев или шуток относительно соглашений, связанных с именами, используемыми в оболочке.
class FolderBrowser: public SShellPtr {
public:
FolderBrowser(HWND hwndOwner, SShellPtr& 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& root, UINT browseForWhat, char const *title) {
_displayName [0] = '\0';
_fullPath [0] = '\0';
_browseInfo.hwndOwner = hwndOwner;
_browseInfo.pidlRoot = root;
_browseInfo.pszDisplayName = _displayName;
_browseInfo.lpszTitle = title;
_browseInfo.ulFlags = browseForWhat;
_browseInfo.lpfn = 0;
_browseInfo.lParam = 0;
_browseInfo.iImage = 0;
// Let the user do the browsing
_p = SHBrowseForFolder(&_browseInfo);
if (_p != 0) SHGetPathFromIDList(_p, _fullPath);
}
Вот так! Разве это не просто?
Далее: Вам, наверное, будет приятно услышать то, что я думаю об OLE?
Дефекты OLE
Перевод А. И. Легалова
Англоязычный оригинал находится на сервере компании Reliable Software
Вы могли слышать или читать критические мнения относительно OLE.Программисты обычно жалуются на сложность системы подсчета ссылок и недостатосную поддержку наследования. Microsoft обожествляет этот счетчик, говоря, что нет никакого другого способа, и что этот способ является для вас наилучшим [2]. Интерфейсы, как сказано, должно быть ссылочно подсчитаны (refcounted), и имеется мудрый, рубильник обеспечивающий соединение (агрегацию) частей (нежно называемый ухудшением (aggravation) OLE программистами), который обеспечивает те же самые функциональные возможности, что и наследование. Может быть они правы, и проблема взаимодействия с объектами, загружаемыми во время выполнения настолько сложна, что просто не имеется более лучшего способа? С другой стороны, возможно, что OLE имеет фатальный дефект, который только обостряется во всех других местах.
Фатальный дефект проекта OLE — требование того, чтобы была возможность добраться от любого интерфейса до любого другого интерфейса.
Технически это интерфейсное прыгание сделано за счет того, что каждый интерфейс наследует от матери всех интерфейсов IUnknown. IUnknown имеет фатальный метод QueryInterface, который, как предполагается, возвращает любой интерфейс, обеспечиваемый текущим объектом. Это единственное предположение препятствует наличию любой возможности простой реализации наследования. Позвольте мне объясняют почему.
Предположим, что Вы имеете объект FooObj с интерфейсом IFoo. Эта ситуация легко моделируется в C++ при наличии абстрактного класса (все методы — чистые виртуальные) IFoo и конкретного класс FooObj, который наследуется из IFoo и реализует все его методы.
Теперь Вам вдруг захотелось расширить этот объект, добавляя поддержку для другого интерфейса IBar. В C++ это тривиально, Вы только определяете класс FooBarObj, который наследует от FooObj и IBar. Этот новый класс поддерживает интерфейс IFoo вместе с его реализацией через наследование из FooObj. Он также поддерживает интерфейс IBar и обеспечивает реализацию методов IBar.
Любой, кто знает C++, может сделать это с закрытыми глазами. Так, почему же Вы не можете сделать то же самое в OLE? Здесь проявляется Изъян. Вы должны быть способны получить интерфейс IBar из интерфейса IFoo, используя его QueryInterface. Но, подождите минуту, объект FooObj, который обеспечивает реализацию всех методов IFoo, включая QueryInterface, не имеет никаких сведений относительно IBar! Невозможно было даже представить наличие IBar. Так, как же в этой ситуации обеспечить доступ к IBar?
Хороший вопрос. Я не собираюсь входить в кровавые подробности агрегационной рубки, которая, как предполагается, решает эту проблему. Накладываемые ограничения и пороки начального проекта, действительно, изобретательно, рубят. Так имеется ли лучший проект? Читайте дальше…
Можете ли Вы отметить случай, когда были вынуждены проводить различия между объектом, который реализует интерфейсы и интерфейсами непосредственно? Это два полностью различных понятия. Вы не можете объяснить что-нибудь в OLE без того, чтобы не говорить об объектах, иногда называемых компонентами. Интерфейсы важны, но объекты еще более важны. Когда Вы можете получить один интерфейс от другого? Когда они совместно используют один и тот же основной объект. Вы можете изменять состояние объекта, используя один интерфейс и затем исследовать это состояние через другой интерфейс. Очевидно, что это тот же самый объект! В моем примере я описал два интерфейса, IFoo и IBar, и два объекта (или класса объектов), FooObject и FooBarObject.
Фактически, любой, кто реализует интерфейсы (используя C++, C, или Basic) имеет дело с объектами. Однако, эта очень важная абстракция полностью отсутствует с точки зрения клиента OLE. Все, что клиент видит – это интерфейсы. Основной объект подобен призраку.
Но это не призрак. Он физически представлен в адресном пространстве вашей программы, или непосредственно, или как заглушка пересылки. Так, почему скрывают это? Действительно, разве OLE не было бы более простым с явным понятием объекта? Давайте посмотрим, как это работало бы.
Клиент этого «интеллектуального OLE» вызвал бы CoCreateInstance или ClassFactory::CreateInstance, чтобы получить указатель на объект (а не на интерфейс!). Используя этот указатель, клиент вызвал бы QueryInterface, чтобы получить интерфейс. Если бы клиент хотел получить другой интерфейс, он или она сделали бы другое обращение QueryInterface через объект, а не через интерфейс. Вы не могли бы получать интерфейс из другого интерфейса. Только объект обладал бы способностью распределять интерфейсы. Bye, bye IUnknown!
Позвольте мне показать Вам некоторый гипотетический код в этом новом «интеллектуальное OLE».
CoObject* obj CoCreateInstance(CLSID_FooBarObject);
IFoo* foo = obj->QueryInterface(IID_FOO);
foo->FooMethod();
IBar* bar = obj->QueryInterface(IID_BAR);
bar->BarMethod();
delete obj;
Я преднамеренно опустил всю проверку ошибок и подсчет ссылок. Фактически, я не написал бы код, подобный этому, в серьезном приложении, я использовал бы интеллектуальные указатели и исключения. Но обратете внимание на одну вещь, в «интеллектуальном OLE» наследование столь же просто как и в C++. Здесь не имеется никакого способа перейти от интерфейса к интерфейсу и нет никакого IUnknown. Расширение FooObject, добавлением IBar требует не больше работы чем создание FooBarObject, наследующего от FooObject и IBar, реализующего методы IBar и переписывание метода QueryInterface CoObject. Я полагаю, что все «интеллектуальное OLE» объекты наследуют от абстрактного класса CoObject и переопределяют его метод QueryInterface (это очень отличается от наличия всех интерфейсов, наследующих от IUnknown!).
Читать дальшеИнтервал:
Закладка: