- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Неприятная ситуация с периодом жизни объектов
Настало время выполнить мое обещание - объяснить, зачем нужен дубликат строки, содержащей имя файла. Дубликат необходим, потому что после возврата из AddPages() оболочка освобождает свой интерфейс IShellPropSheetExt, который, в свою очередь, разрушает объект CFileTimeShlExt. Это означает, что оконная процедура страницы свойств не сможет получить доступ к элементу m_lsFiles класса CFileTimeShlExt.
Моим решением было сделать копию каждого имени файла и передать указатель на эту копию во вкладку. Вкладка, обладая памятью, отвечает за ее освобождение. Если есть более чем один выделенный файл, каждая вкладка получает копию имени файла с ней связанного. Память освобождается функцией PropPageCallbackProc , приведенной ниже. Эта строка в AddPages():
|
psp.lParam = (LPARAM) szFile; |
очень важна. Она сохраняет указатель в структуре PROPSHEETPAGE и делает его доступным в оконной процедуре страницы свойств.
Функции обратного вызова страницы свойств
Теперь обратимся к странице свойств. Вот как она выглядит:
Держите в уме эту картинку, пока читаете объяснения о том, как она работает.
Заметьте, что здесь нет контрола для отображения и корректировки времени последнего доступа к файлу. FAT сохраняет только дату последнего доступа. Другие файловые системы сохраняют также время последнего доступа, но я не реализовывал логику по проверке типа файловой системы. При изменении даты последнего доступа время всегда будет сохраняться как 12 часов ночи, если файловая система поддерживает поле времени последнего доступа.
Страница имеет две функции обратного вызова и два обработчика сообщений. Их прототипы идут вначале файла FileTimeShlExt.cpp:
|
BOOL CALLBACK PropPageDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); UINT CALLBACK PropPageCallbackProc ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp ); BOOL OnInitDialog ( HWND hwnd, LPARAM lParam ); BOOL OnApply ( HWND hwnd, PSHNOTIFY* phdr ); |
Оконная процедура приятно проста. Она обрабатывает три сообщения: WM_INITDIALOG, PSN_APPLY и DTN_DATETIMECHANGE. Вот часть WM_INITDIALOG:
|
BOOL CALLBACK PropPageDlgProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { BOOL bRet = FALSE;
switch ( uMsg ) { case WM_INITDIALOG: bRet = OnInitDialog ( hwnd, lParam ); break; |
OnInitDialog() я объясню позже. Дальше идет PSN_APPLY, которое посылается, если пользователь щелкнет OK или Apply.
|
case WM_NOTIFY: { NMHDR* phdr = (NMHDR*) lParam;
switch ( phdr->code ) { case PSN_APPLY: bRet = OnApply ( hwnd, (PSHNOTIFY*) phdr ); break; |
И, в конце, DTN_DATETIMECHANGE. Это самое простое, мы просто делаем доступной кнопку Apply посылкой сообщения набору свойств (который является родительским окном для нашей страницы).
|
case DTN_DATETIMECHANGE: // Если пользователь изменил содержимое DTP, разрешаем кнопку Apply SendMessage ( GetParent(hwnd), PSM_CHANGED, (WPARAM) hwnd, 0 ); break; } } break; }
return bRet; } |
Пока все хорошо. Другая callback функция вызывается, когда вкладка создается или уничтожается. Нас интересует последний случай, так как именно тогда мы можем освободить дубликат строки, который был создан раньше, в AddPages(). Параметр ppsp указывает на структуру PROPSHEETPAGE, которую мы использовали для создания вкладки. Ее элемент lParam все еще указывает на дубликат строки, который должен быть освобожден.
|
UINT CALLBACK PropPageCallbackProc ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp ) { if ( PSPCB_RELEASE == uMsg ) { free ( (void*) ppsp->lParam ); }
return 1; } |
Функция всегда возвращает 1, потому что, если функция вызывается в период создания страницы, то возвращая 0 она может прервать дальнейший процесс создания. Возвращение 1 позволяет завершить процесс создания вкладки нормально. Возвращаемое значение игнорируется, если функция вызвана, когда закладка уничтожается.
