- •Методические указания для выполнения лабораторной работы №2.6 по курсу «Операционные системы и системное программирование»
- •Цель работы
- •Теоретические сведения
- •Пример 1 «Добавление пунктов в контекстное меню для отдельных расширений файлов»
- •Использование AppWizard.
- •Интерфейс инициализации
- •Интерфейс взаимодействия с контекстным меню
- •Модификация контекстного меню
- •Отображение подсказки в строке состояния
- •Выполнение выбора пользователя
- •Регистрация расширения оболочки
- •Отладка расширения оболочки
- •Результат
- •Пример 2 «Добавление пунктов в контекстное меню для всех файлов не зависимо от расширения»
- •Дополнительные функции расширения, добавляющего пункты к контекстному меню оболочки.
- •Использование AppWizard
- •Интерфейс инициализации
- •Добавление пунктов к меню
- •Подсказка в строке состояния и "действие"
- •Выполнение выбора пользователя
- •Регистрация расширения
- •Результат
- •Другие способы регистрации расширения
- •Пример 3 «Использование разделяемой с оболочкой памяти»
- •Расширение QueryInfo
- •Использование AppWizard
- •Интерфейс инициализации
- •Создание текста для тултипа
- •Регистрация расширения оболочки
- •Пример 4 «Обработчик перетаскивания контекстного меню»
- •Обработчик перетаскивания
- •Интерфейс инициализации
- •Модификация контекстного меню
- •Создание связи
- •Обеспечение подсказки в строке состояния
- •Создание связи
- •Регистрация расширения
- •Пример 5 «Добавления новых страниц в набор свойств файлов»
- •Обработчик набора свойств
- •Использование AppWizard
- •Интерфейс инициализации
- •Добавление страниц свойств
- •Неприятная ситуация с периодом жизни объектов
- •Функции обратного вызова страницы свойств
- •Обработчики сообщений страницы свойств
- •Регистрация расширения
- •Пример 6 «Обработчик сбрасывания в меню Send To»
- •Обработчик сбрасывания
- •Использование AppWizard
- •Интерфейс инициализации
- •Участвуем в операции drag and drop
- •DragEnter()
- •DragLeave()
- •Регистрация расширения
- •Пример 7 «Owner-drawn меню в расширениях контекстных меню и по созданию расширения контекстного меню, которое отзывается на правый щелчок на фоне окна каталога» Расширение 1 - Пункты меню owner-drawn.
- •Использование AppWizard
- •Интерфейс инициализации.
- •Взаимодействие с контекстным меню
- •Модифицирование контекстного меню.
- •Отображение всплывающей подсказки в строке состояния.
- •Выполнение выбора пользователя.
- •Рисование пункта меню.
- •Обработка wm_measureitem
- •Обработка wm_drawitem
- •Регистрация расширения оболочки
- •Расширение 2 - Обработка щелчка правой кнопкой мыши на фоне окна каталога.
- •Отличия в iShellExtInit::Initialize()
- •Отличия в регистрации.
- •Пример 8 «Добавление колонки в окно детального просмотра Проводника» Детальный просмотр в Windows 2000
- •Использование AppWizard
- •Интерфейс расширения
- •Инициализация
- •Перечисление новых столбцов
- •Отображение данных в столбцах
- •Небольшое отступление - обработка тэгов id3
- •Как это все выглядит?
- •Регистрация расширения оболочки
- •Еще одна полезная штучка - InfoTips
- •Пример 9 «Настройка иконок, отображаемых для файлов заданного типа» Файловые иконки в Проводнике
- •Использование AppWizard
- •Интерфейс расширения
- •Интерфейс инициализации
- •Интерфейс iExtractIcon
- •Извлечение методом 1
- •Извлечение методом 2
- •Регистрация расширения
- •Пример 10 «Расширение оболочки для изменения иконок у dll в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Добавление страниц свойств
Если Initialize() возвращает S_OK, проводник запрашивает новый интерфейс - IShellPropSheetExt. IShellPropSheetExt совсем прост, с единственным методом, требующим реализации. Чтобы добавить IShellPropSheetExt к нашему классу, откройте FileTimeShlExt.h и добавьте выделенные строки:
|
class ATL_NO_VTABLE CFileTimeShlExt : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CFileTimeShlExt, &CLSID_FileTimeShlExt>, public IDispatchImpl<IFileTimeShlExt, &IID_IFileTimeShlExt, &LIBID_FILETIMELib>, public IShellExtInit,
public IShellPropSheetExt { BEGIN_COM_MAP(CFileTimeShlExt) COM_INTERFACE_ENTRY(IFileTimeShlExt) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IShellExtInit) COM_INTERFACE_ENTRY(IShellPropSheetExt) END_COM_MAP()
public: // IShellPropSheetExt STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE, LPARAM); STDMETHOD(ReplacePage)(UINT, LPFNADDPROPSHEETPAGE, LPARAM) { return E_NOTIMPL; } |
AddPages() - метод, который мы реализуем. Расширения используют ReplacePage() только для того, чтобы заменять вкладки в элементах панели управления. Поэтому нет необходимости здесь его реализовывать. Проводник вызывает нашу функцию AddPages(), чтобы мы могли добавить страницы к набору свойств, установленному проводником.
Параметры функции AddPages() - указатель на функцию и LPARAM используются только оболочкой. lpfnAddPageProc указывает на функцию оболочки, которую мы вызываем, чтобы добавить вкладки. LPARAM - загадочная величина, но она важна только для оболочки. Мы ничего с ней не делаем, просто передаем ее обратно в функцию lpfnAddPageProc.
|
HRESULT CFileTimeShlExt::AddPages ( LPFNADDPROPSHEETPAGE lpfnAddPageProc, LPARAM lParam ) { PROPSHEETPAGE psp; HPROPSHEETPAGE hPage; TCHAR szPageTitle [MAX_PATH]; string_list::const_iterator it, itEnd;
for ( it = m_lsFiles.begin(), itEnd = m_lsFiles.end(); it != itEnd; it++ ) { // 'it' - указатель на следующее имя файла. Создаем копию строки, // которой будет владеть страница LPCTSTR szFile = _tcsdup ( it->c_str() ); |
В первую очередь мы должны создать копию имени файла. Причину я объясню ниже.
Следующий шаг - создать строку, наименование для нашей закладки. Строка будет именем файла без расширения. К тому же, строка будет обрезана, если содержит более 24 символов. Это произвольный предел. 24 мне просто приглянулось. Должен же быть какой-то предел, чтобы имя файла не вышло за пределы закладки.
|
// Удаляем путь и расширение из имени файла - это будет заголовок страницы. // Укорачиваем имя до 24 символов. lstrcpy ( szPageTitle, it->c_str() ); PathStripPath ( szPageTitle ); PathRemoveExtension ( szPageTitle ); szPageTitle[24] = '\0'; |
Т.к. мы используем непосредственно SDK, для создания страницы свойств придется испачкать ручки структурой PROPSHEETPAGE. Вот установки для параметров структуры:
|
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_DEFAULT | PSP_USEICONID | PSP_USECALLBACK; psp.hInstance = _Module.GetModuleInstance(); psp.pszTemplate = MAKEINTRESOURCE(IDD_FILETIME_PROPPAGE); psp.pszIcon = MAKEINTRESOURCE(IDI_ICON); psp.pszTitle = szPageTitle; psp.pfnDlgProc = PropPageDlgProc; psp.lParam = (LPARAM) szFile; psp.pfnCallback = PropPageCallbackProc; psp.pcRefParent = (UINT*) &_Module.m_nLockCnt; |
Теперь несколько деталей, на которые нужно обратить внимание, чтобы расширение работало корректно:
pszIcon устанавливает ID ресурса иконки 16x16, которая будет отображаться на закладке. Наличие иконки не обязательно, конечно, но я добавил, чтобы наша закладка выделялась.
pfnDlgProc содержит адрес оконной процедуры нашей вкладки.
lParam получает значение переменной szFile - копии имени файла, с которым связана наша вкладка.
pfnCallback - адрес функции обратного вызова, которая вызывается, когда закладка создается и когда уничтожается. Роль этой функции я объясню позже.
pcRefParent - адрес переменной-члена, унаследованной от CComModule. Эта переменная является счетчиком ссылок на DLL. Оболочка увеличивает этот счетчик, когда набор свойств отображен, чтобы держать DLL в памяти, пока набор открыт. Счетчик уменьшится после того, как набор свойств будет уничтожен.
Установив параметры этой структуры, мы обращаемся к API, для создания страницы свойств.
|
hPage = CreatePropertySheetPage ( &psp ); |
Если все отлично, мы вызываем callback функцию оболочки, которая добавляет вновь созданную страницу к набору свойств. Функция возвращает BOOL индикатор успеха или неудачи. Если это неудача, мы уничтожаем страницу.
|
if ( NULL != hPage ) { // Вызываем callback функцию оболочки, чтобы добавить страницу к набору свойств if ( !lpfnAddPageProc ( hPage, lParam )) { DestroyPropertySheetPage ( hPage ); } } } // end for return S_OK; } |
