- •Методические указания для выполнения лабораторной работы №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 - это InvokeCommand(). Это метод вызывается, когда пользователь щелкнет на пункте меню, который мы добавили. Прототип для InvokeCommand():
|
HRESULT IContextMenu::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo ); |
Структура CMINVOKECOMMANDINFO содержит целую тонну информации. Но для наших целях важно позаботиться только о lpVerb и hwnd. lpVerb имеет двойное назначение - это может быть имя "действия" (см.выше), или индекс, сообщающий нам, какой из пунктов нашего меню был отмечен щелчком. hwnd - дескриптор окна проводника, в котором пользователь вызвал наше расширение.
Поскольку у нас только один пункт меню, мы осуществим проверку lpVerb. Если это 0, мы будем знать, что это наш пункт меню был отмечен. Самая простая вещь, которую я смог придумать - это высвечивать сообщение о том, что делает этот код. Сообщение показывает имя отмеченного файла и это докажет нам, что все действительно работает.
|
HRESULT CSimpleShlExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo ) { // If lpVerb really points to a string, ignore this function call and bail out. if ( 0 != HIWORD( pCmdInfo->lpVerb )) return E_INVALIDARG;
// Get the command index - the only valid one is 0. switch ( LOWORD( pCmdInfo->lpVerb )) { case 0: { TCHAR szMsg [MAX_PATH + 32];
wsprintf ( szMsg, _T("The selected file was:\n\n%s"), m_szFile );
MessageBox ( pCmdInfo->hwnd, szMsg, _T("SimpleShlExt"), MB_ICONINFORMATION );
return S_OK; } break;
default: return E_INVALIDARG; break; } } |
Регистрация расширения оболочки
Итак, мы осуществили все интерфейсы, но как сделать, чтобы проводник мог использовать наше расширение? ATL автоматически генерирует код, который регистрирует нашу DLL как COM сервер, но это всего лишь позволит другим приложениям использовать нашу DLL. Для того чтобы сообщить проводнику, что наше расширение существует, мы должны зарегистрировать его в секции, которая содержит информацию о TXT-файлах:
|
HKEY_CLASSES_ROOT\txtfile |
Под этим ключом укажем ключ ShellEx , содержащий список расширений оболочки, вызываемых для TXT-файлов. Под ключом ShellEx ключ ContextMenuHandlers содержит список расширений контекстного меню. Каждое расширение создает свой субключ под ключом ContextMenuHandlers и устанавливает значение этого ключа по своему GUID. Например, для нашего простого расширения, создадим ключ:
|
HKEY_CLASSES_ROOT\txtfile\ShellEx\ContextMenuHandlers\SimpleShlExt |
и установим его default значение согласно нашему GUID:"{5E2121EE-0300-11D4-8D3B-444553540000}".
Однако вы не должны писать любой код, чтобы это сделать. Посмотрите список файлов и найдите файл SimpleShlExt.rgs. Это текстовый файл предназначен для ATL и указывает, какие ключи регистрации добавлять, когда сервер регистрируется, и какие удалять, когда сервер разрегистрируется.
Вот как выглядят данные для регистрации:
|
HKCR { NoRemove txtfile { NoRemove ShellEx { NoRemove ContextMenuHandlers { ForceRemove SimpleShlExt = s '{5E2121EE-0300-11D4-8D3B-444553540000}' } } } } |
Каждая строка является именем ключа реестра. HKCR - сокращение для HKEY_CLASSES_ROOT. Ключевое слово NoRemove означает, что ключ не должен быть удален, когда сервер разрегистрируется. Последняя строка немного более сложная. Ключевое слово ForceRemove означает, что если ключ существует, он будет удален прежде, чем новый ключ записан. Рассмотрим остальную часть строки. Символ s означает, что подстрока, указанная после него будет сохранена, как значение по умолчанию для ключа SimpleShlExt.
Рассмотрим подробнее этот момент. Ключ, под которым мы зарегистрировали наше расширение - это HKCR\txtfile. Однако имя "txtfile" не является постоянным или предрешенным. Если вы посмотрите в HKCR\.txt, где было сохранено имя, то убедитесь, что это значение этого ключа по умолчанию. Это имеет два побочных эффекта:
Мы не можем надежно использовать RGS скрипт, т.к. "txtfile" может не быть корректным именем ключа.
Может быть установлен другой текстовый редактор, который будет ассоциировать TXT файлы с собой. Если он изменит значение по умолчанию ключа HKCR\.txt, все существующие расширения прекратят свою работу.
Мне это кажется проектным недостатком. Я думаю, Microsoft думает также, т.к. недавно созданы расширения, подобные QueryInfo, зарегистрированные непосредственно под ключом .txt.
ОК. Конец статьи. Последняя деталь о регистрации. В Windows NT/2000 мы также должны внести наше расширение в список "одобренных" расширений. Если мы этого не сделаем, наше расширение не будет доступно пользователю, который не имеет прав администратора. Этот список находится в
|
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved |
В этом ключе мы создаем string переменную, чье имя - это наш GUID. Содержание строки может быть любым. Код, выполняющий это действие, входит в наши функции DllRegisterServer() и DllUnregisterServer() .
