- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Извлечение методом 1
Первый вызываемый метод IExtractIcon - GetIconLocation(). Эта функция просматривает файл (чье имя было сохранено в IPersistFile::Load()) и возвращает пару имя файла/индекс, как это обсуждалось выше. Вот прототип GetIconLocation():
|
HRESULT IExtractIcon::GetIconLocation ( UINT uFlags, LPTSTR szIconFile, UINT cchMax, int* piIndex, UINT* pwFlags ); |
Параметры:
uFlags Некоторые флаги, которые могут изменить поведение расширения. GIL_ASYNC передается, чтобы запросить, не займет ли процесс извлечения много времени. Если так, расширение может запросить извлечение в фоновом потоке, чтобы не задерживать интерфейс Проводника. Другие флаги, GIL_FORSHELL и GIL_OPENICON, кажется имеют значение только для расширений пространства имен. Нам не стоит беспокоиться насчет флагов, поскольку наш код не требует больших затрат времени на выполнение.
szIconFile, cchMax szIconFile - буфер, предоставленный оболочкой, в который помещается имя файла, содержащего иконку для использования проводником. cchMax - размер буфера в символах.
piIndex Указатель на int, в котором мы сохраним индекс иконки в файле (чье имя мы внесли в szIconFile)
pwFlags Указатель на UINT, в котором мы можем передать флаги, изменяющие поведение Проводника. Эти флаги описаны ниже.
GetIconLocation() заполняет параметры szIconFile и piIndex и возвращает S_OK. Можно также вернуть S_FALSE, если мы все-же решим, что не хотим обеспечивать указанную иконку. В этом случае Проводник установит иконку "неизвестный файл":
В параметре pwFlags Проводнику могут быть переданы следующие флаги:
GIL_DONTCACHE Сообщает Проводнику, что не надо проверять кэш иконок. В результате всегда будет вызываться IExtractIcon::Extract(). Я расскажу об этом флаге подробнее позже, когда буду описывать извлечение методом 2.
GIL_NOTFILENAME Согласно MSDN, этот флаг требует от Проводника проигнорировать пару szIconFile/piIndex, возвращаемую GetIconLocation(). Очевидно, таким образом расширения должны заставить Проводник всегда вызывать IExtractIcon::Extract(), однако этот флаг никак не влияет на то, что происходит после возврата из GetIconLocation().
GIL_SIMULATEDOC Этот флаг заставляет Проводник взять исконку, переданную расширением, вставить ее внутрь иконки в виде чистого листочка и использовать то что получилось как иконку для файла. Я продемонстрирую работу этого флага позже.
В методе 1 GetIconLocation() получает размер файла и основываясь на нем возвращает индекс от 0 до 3 включительно. У этого метода есть один недостаток - нам нужно отслеживать ID ресурсов и быть уверенным, что они в правильном порядке. Наше расширение имеет только 4 иконки, так что эта бухгалтерия не сложна, но если иконок будет больше, или вы будете удалять и добавлять иконки в вашем проекте, вы должны будете внимательно следить за идентификаторами ваших ресурсов.
Вот реализация нашей функции GetIconLocation(). Сначала мы открываем файл и получаем его размер. Если при этом произойдет ошибка, мы вернем S_FALSE и Проводник будет использовать иконку по умолчанию.
|
STDMETHODIMP CTxtIconShlExt::GetIconLocation ( UINT uFlags, LPTSTR szIconFile, UINT cchMax, int* piIndex, UINT* pwFlags ) { DWORD dwFileSizeLo, dwFileSizeHi; DWORDLONG ldwSize; HANDLE hFile;
hFile = CreateFile ( m_szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( INVALID_HANDLE_VALUE == hFile ) return S_FALSE; // Сообщаем оболочке, что нужно использовать иконку по умолчанию
dwFileSizeLo = GetFileSize ( hFile, &dwFileSizeHi );
CloseHandle ( hFile );
if ( (DWORD) -1 == dwFileSizeLo && GetLastError() != NO_ERROR ) return S_FALSE; // Сообщаем оболочке, что нужно использовать иконку по умолчанию
ldwSize = ((DWORDLONG) dwFileSizeHi)<<32 | dwFileSizeLo; |
Далее мы получаем путь к нашей DLL, поскольку иконки находятся в ней и копируем его в буффер szIconFile.
|
TCHAR szModulePath[MAX_PATH];
GetModuleFileName ( _Module.GetModuleInstance(), szModulePath, MAX_PATH ); lstrcpyn ( szIconFile, szModulePath, cchMax ); |
На следующем шаге мы проверяем размер файла и записываем в piIndex индекс иконки, соответствующей этому размеру.
|
if ( 0 == ldwSize ) *piIndex = 0; else if ( ldwSize < 4096 ) *piIndex = 1; else if ( ldwSize < 8192 ) *piIndex = 2; else *piIndex = 3; |
В конце мы устанавливаем pwFlags в 0, чтобы получить от Проводника поведение по умолчанию. Это означает, что он проверит кэш иконок, чтобы определить, есть ли иконка szIconFile/piIndex в кэше, и, если да, то IExtractIcon::Extract() вызываться не будет. Мы возвращаем S_OK чтобы показать, что GetIconLocation() завершилась успешно.
|
*pwFlags = 0; return S_OK; } |
Поскольку мы сообщили Проводнику, где найти иконку, наша реализация Extract() возвращает S_FALSE, чтобы он самостоятельно извлек иконку. Параметры Extract() я буду обсуждать в следующем разделе.
|
STDMETHODIMP CTxtIconShlExt::Extract ( LPCTSTR pszFile, UINT nIconIndex, HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize ) { return S_FALSE; // Сообщаем оболочке что извлечение ей нужно сделать самостоятельно } |
И вот как выглядят наши иконки в действии:
Если изменить GetIconLocation() так чтобы pwFlags был установлен в GIL_SIMULATEDOC, иконки будут выглядеть так:
Заметьте, что в режиме больших иконок использована маленькая версия нашей иконки (16х16). При просмотре в режиме мелких значков Проводник дополнительно уменьшает нашу маленькую иконку, что выглядит не очень красиво.
