- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Выполнение выбора пользователя
Когда пользователь щелкает на одном из пунктов меню, проводник вызывает метод InvokeCommand(). Он в первую очередь проверяет старшее слово в значении lpVerb. Если оно не нулевое, то это имя "действия", которое можно извлечь. Поскольку мы уже знаем, что "действия" работают некорректно (по крайней мере в Windows 98), не будем обращать на них внимание. Рассмотрим младшее слово. Если оно 0 или 1, можно быть уверенным, что выбран один из наших пунктов меню.
|
HRESULT CDllRegShlExt::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo ) { // If lpVerb really points to a string, ignore this function call and bail out. if ( 0 != HIWORD( pInfo->lpVerb )) return E_INVALIDARG;
// Check that lpVerb is one of our commands (0 or 1) switch ( LOWORD( pInfo->lpVerb )) { case 0: case 1: { CProgressDlg dlg ( &m_lsFiles, pInfo );
dlg.DoModal(); return S_OK; } break;
default: return E_INVALIDARG; break; } } |
Если младшее слово lpVerb принимает значение 0 или 1, мы создаем диалог (производный от класса ATL CDialogImpl) для отображения процесса регистрации/разрегистрации и передаем ему список имен файлов.
Вся реальная работа производится в классе CProgressDlg. Функция этого класса OnInitDialog() инициализирует элемент управления "список" (list control) и затем вызывает CProgressDlg::DoWork(). Эта функция просматривает список, который был построен в CDllRegShlExt::Initialize() и вызывает соответствующую функцию в каждом файле. Основной код приведен ниже, но он не является полным, поскольку я не привел код проверки ошибок и части по заполнению списка. Этого вполне достаточно, чтобы продемонстрировать, как просматривается список имен файлов и показать действия с каждым файлом.
|
void CProgressDlg::DoWork() { HRESULT (STDAPICALLTYPE* pfn)(); string_list::const_iterator it, itEnd; HINSTANCE hinst; LPCSTR pszFnName; HRESULT hr; WORD wCmd;
wCmd = LOWORD ( m_pCmdInfo->lpVerb );
// We only support 2 commands, so check the value passed in lpVerb. if ( wCmd > 1 ) return;
// Determine which function we'll be calling. Note that these strings are // not enclosed in the _T macro, since GetProcAddress() only takes an // ANSI string for the function name. pszFnName = wCmd ? "DllUnregisterServer" : "DllRegisterServer";
for ( it = m_pFileList->begin(), itEnd = m_pFileList->end(); it != itEnd; it++ ) { // Try to load the next file. hinst = LoadLibrary ( it->c_str() );
if ( NULL == hinst ) continue;
// Get the address of the register/unregister function. (FARPROC&) pfn = GetProcAddress ( hinst, pszFnName );
// If it wasn't found, go on to the next file. if ( NULL == pfn ) continue;
// Call the function! hr = pfn(); |
Нужно дать некоторые объяснения относительно цикла "for", поскольку, если вы не в курсе, коллекция классов STL несколько "странновата". m_pFileList - указатель списка m_lsFiles в классе CDllRegShlExt. (Этот указатель был передан конструктору класса CProgressDlg). Коллекция списков STL имеет тип, называемый const_iterator, сущность которого аналогична типу POSITION в MFC. А переменная типа const_iterator действует как указатель на const объект в списке, поэтому этот итератор может применяться с "->" для получения доступа к этому объекту. Он также может быть увеличен с помощью оператора "++" для продвижения вперед по списку.
Итак, в выражении инициализации цикла "for" вызывается list::begin() для получения итератора, "указывающего" на первую строку списка и, затем, вызывается list::end() для получения итератора, который "указывает" на "конец" списка, то есть на следующую позицию после последней строки. (Я поместил термины в кавычки, чтобы подчеркнуть, что понятия указывания, начала и конца списка очень абстрактны для типа const_iterator и могут быть материализованы через методы const_iterator [типа begin()] или операторы [типа "++"]. Итераторы начала и конца обозначены it и itEnd соответственно. Цикл продолжается, пока it не станет равным itEnd, то есть пока it не достигнет "конца" списка. Итератор it, проходя через цикл, каждый раз увеличивается, и таким образом, в одном витке цикла обрабатывается одна строка списка.
Выражение it->c_str() использует оператор "" для итератора. Поскольку it выполняет функцию указателя на строку (помните, m_pFileList является списком строк STL), то it->c_str() вызывает функцию c_str() для строки, на которую в данный момент указывает it. c_str() возвращает указатель на C-style строку символов, в данном случае эквивалент LPCTSTR.
Остальное в DoWork() - это освобождение ресурсов и обработка ошибок.
(Я только сейчас осознал, как странно звучит разговор о переменной, названной "it" (это). Sorry.) :-)
