- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Интерфейс взаимодействия с контекстным меню
Как только проводник инициализировал наше расширение, он вызовет методы IContextMenu, позволяющие добавить пункты в меню, обеспечивающие подсказку в строке состояния и выполняющие выбор пользователя.
Добавление IContextMenu к нашему расширению подобно добавлению IShellExtInit. Откроем SimpleShlExt.h и добавим выделенные строки:
|
class ATL_NO_VTABLE CSimpleShlExt : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CSimpleShlExt, &CLSID_SimpleShlExt>, public IDispatchImpl<ISimpleShlExt, &IID_ISimpleShlExt, &LIBID_SIMPLEEXTLib>, public IShellExtInit, public IContextMenu { BEGIN_COM_MAP(CSimpleShlExt) COM_INTERFACE_ENTRY(ISimpleShlExt) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IShellExtInit) COM_INTERFACE_ENTRY(IContextMenu) END_COM_MAP() |
А затем добавим прототипы методов IContextMenu:
|
public: // IContextMenu STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT); STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO); STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT); |
Модификация контекстного меню
IContextMenu имеет 3 метода. Первый из них, QueryContextMenu(), позволяет модифицировать меню. Вот его прототип:
|
HRESULT IContextMenu::QueryContextMenu ( HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags ); |
hmenu это дескриптор контекстного меню. uMenuIndex - позиция, с которой мы должны начать добавлять свои пункты. uidFirstCmd и uidLastCmd - интервал идентификаторов команд, которые мы можем использовать для наших пунктов меню. uFlags указывает, почему проводник вызывает QueryContextMenu(), но об этом позже.
Описания возвращаемого значения различны в различных источниках. В книге Dino Esposito говорится, что это число пунктов меню, добавленных QueryContextMenu(). Библиотека MSDN, поступающая с VC6, говорит, что это ID последнего пункта меню, который мы добавим, плюс 1. Поздние on-line документы MSDN говорят:
"Установите значение кода (возвращаемого через HRESULT) равным значению самого большего идентификатора команды, плюс 1. Например, idCmdFirst установлен в 5 и вы добавляете к меню 3 пункта с ID = 5, 7 и 8. Возвращаемое значение должно быть MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1)."
Я следовал объяснениям Dino в коде, написанном мною. Его метод получения возвращаемого значения эквивалентен методу on-line MSDN до тех пор, пока вы считаете количество пунктов вашего меню с помощью uidFirstCmd и прибавляете 1 для каждого добавленного пункта. Наше простое расширение будет иметь только один пункт, поэтому функция QueryContextMenu() совсем проста:
|
HRESULT CSimpleShlExt::QueryContextMenu ( HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags ) { // If the flags include CMF_DEFAULTONLY then we shouldn't do anything. if ( uFlags & CMF_DEFAULTONLY ) { return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 ); }
InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T("SimpleShlExt Test Item") );
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 1 ); } |
Первое, что мы делаем - это проверяем uFlags. Вы можете найти полный список флагов в MSDN, но для контекстного меню важно только одно значение - CMF_DEFAULTONLY. Этот флаг сообщает расширениям, что добавляются только пункты меню по-умолчанию. Расширение ничего не должно добавлять, если этот флаг присутствует. Вот почему мы немедленно возвращаем 0, если выставлен это флаг. Если этого флага нет, мы модифицируем меню (используя hmenu), и возвращаем 1, чтобы сообщить оболочке, что мы добавили 1 пункт меню.
