- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Инициализация
У интерфейса IColumnProvider три метода. Первый из них - Initialize(), имеющий следующий прототип:
|
HRESULT IColumnProvider::Initialize ( LPCSHCOLUMNINIT psci ); |
Оболочка передает нам структуру SHCOLUMNINIT, которая в этот момент содержит всего одно поле - полный путь к папке, которая отображается в проводнике. Нам не нужна эта информация, поэтому наше расширение просто возвращает S_OK.
Перечисление новых столбцов
Когда Проводник видит, что наш обработчик зарегистрирован, он вызывает расширение, чтобы получить информацию о каждом столбце, который поддерживает наше расширение. Это делается через метод GetColumnInfo(). Вот его прототип:
|
HRESULT IColumnProvider::GetColumnInfo ( DWORD dwIndex, SHCOLUMNINFO* psci ); |
dwIndex - это начинающийся с 0 счетчик, который показывает, каким столбцом интересуется Проводник. Другой параметр - это указатель на структуру SHCOLUMNINFO, которую наше расширение заполняет параметрами столбца.
Первый член структуры SHCOLUMNINFO - другая структура - SHCOLUMNID. SHCOLUMNID - это пара GUID/DWORD, в которой GUID это "format ID", а DWORD - "property ID". Эта пара чисел однозначно идентифицирует любой столбец в системе. Расширение может повторно использовать уже имеющийся столбец (например, Автор), в этом случае format ID и property ID принимают предопределенные значения. Расширение, которое добавляет новые столбцы, может использовать свой собственный GUID для format ID (т.к. CLSID гарантированно уникален) и простой счетчик для property ID.
Наше расширение будет использовать оба метода. Мы будем повторно использовать столбцы Author (Автор), Title (Название), и Comments (Комментарии), и добавим еще три: MP3 Album (Альбом), MP3 Year (Год), и MP3 Genre (Жанр).
Вот начало нашего метода GetColumnInfo():
|
STDMETHODIMP CMP3ColExt::GetColumnInfo ( DWORD dwIndex, SHCOLUMNINFO* psci ) { // У нас 6 столбцов, поэтому, если dwIndex = 6 или больше, возвращаем S_FALSE // чтобы показать, что все столбцы перечислены. if ( dwIndex > 5 ) return S_FALSE; |
Если dwIndex больше или равен 6, мы возвращаем S_FALSE, чтобы остановить перечисление, в противном случае мы заполняем структуру SHCOLUMNINFO. Для dwIndex от 0 до 2 мы возвращаем данные одного из наших новых столбцов. Для значений от 3 до 5 мы возвращаем данные одного из повторно используемых встроенных столбцов. Вот как мы задаем наш первый столбец, который показывает название альбома из соответствующего поля тэга ID3:
|
switch ( dwIndex ) { case 0: // MP3 Album - дополнительный столбец { psci->scid.fmtid = *_Module.pguidVer; // Удобно использовать этот GUID psci->scid.pid = 0; // Можно сделать любой ID, но самое простое - использовать номер столбца psci->vt = VT_LPSTR; // Возвращаем данные в виде строки psci->fmt = LVCFMT_LEFT; // Текст выровнен по левой границе psci->csFlags = SHCOLSTATE_TYPE_STR; // Данные сортируются как строки psci->cChars = 32; // Начальная ширина колонки в символах
lstrcpynW ( psci->wszTitle, L"MP3 Album", MAX_COLUMN_NAME_LEN ); lstrcpynW ( psci->wszDescription, L"Album name of an MP3", MAX_COLUMN_DESC_LEN ); } break; |
Мы используем GUID модуля нашего расширения как format ID, и номер столбца как property ID. Член структуры SHCOLUMNINIT vt индицирует, какой тип данных мы возвратим Проводнику. Значение VT_LPSTR указывает, что это будет строка в C-стиле. fmt может быть одной из LVCFMT_* констант, и указывает на тип выравнивания текста столбца. В данном случае текст будет выровнен по левой границе.
csFlags содержит несколько флажков для столбца. Однако, не все флажки, кажется, поддерживаются оболочкой. Ниже приведены существующие флажки и объяснение их эффектов:
SHCOLSTATE_TYPE_STR, SHCOLSTATE_TYPE_INT, and SHCOLSTATE_TYPE_DATE Указывает, в какой тип данных должны преобразовываться данные столбца, когда Проводник сортирует столбец. Есть три возможности - в строку, в целое, в дату.
SHCOLSTATE_ONBYDEFAULT Документация говорит, что включение этого флага заставит столбец появляться по умолчанию в окне просмотра папки, пока пользователь не удалит этот столбец. Но я не смог этого добиться.
SHCOLSTATE_SLOW Согласно документации, включение этого флага указывает, что для накопления данных столбца требуется некоторое время, и Проводник создаст один или более фоновых потоков, для того чтобы в это время можно было продолжать работу с интерфейсом Проводника. В моих тестах я не видел никакого эффекта от установки этого флага. Проводник всегда использовал только один поток, чтобы собрать данные для столбцов расширения.
SHCOLSTATE_SECONDARYUI Документация сообщает, что установка этого флага предотвращает появление названия этого столбца в контекстном меню заголовка. Это означает, что если вы не установите этот флаг, название столбца появится в контекстном меню. Однако названия дополнительных столбцов никогда не появляются в контекстном меню, так что сейчас этот флаг не имеет никакого эффекта.
SHCOLSTATE_HIDDEN Установка этого флага предотвращает появление названия столбца в диалоге настройки столбцов. Так как сейчас нет никакой другой возможности выбрать скрытый таким образом столбец, этот флаг делает столбец бесполезным.
cChars содержит заданную по умолчанию ширину для столбца в символах. Установите его равным максимуму из длины наименования столбца и самой длинной строки, которая может появится в столбце. Вы должны также добавить 2 или 3 к этому числу, чтобы гарантировать, к что ширина столбца достаточна, чтобы отобразить весь текст. (Если Вы не сделаете этого небольшого дополнения, заданная по умолчанию ширина столбца может быть недостаточно широка, и текст получится сокращенным.)
Заключительные два члена - строки в Unicode, которые содержат название столбца (текст, который показывается в заголовке) и описание столбца. В настоящее время описание не используется оболочкой, и пользователь никогда не видит его.
Столбцы #1 и #2 довольно похожи, однако столбец #1 иллюстрирует момент относительно типа данных и метода сортировки. Этот столбец показывает год. Вот код, который его определяет:
|
case 1: // MP3 year - дополнительный столбец { psci->scid.fmtid = *_Module.pguidVer; // Удобно использовать этот GUID psci->scid.pid = 1; // Можно сделать любой ID, но самое простое - использовать номер столбца psci->vt = VT_LPSTR; // Возвращаем данные в виде строки psci->fmt = LVCFMT_RIGHT; // Текст выровнен по правой границе psci->csFlags = SHCOLSTATE_TYPE_INT; // Данные сортируются как числа psci->cChars = 6; // Начальная ширина колонки в символах
lstrcpynW ( psci->wszTitle, L"MP3 Year", MAX_COLUMN_NAME_LEN ); lstrcpynW ( psci->wszDescription, L"Year of an MP3", MAX_COLUMN_DESC_LEN ); } break; |
Заметьте, что vt = VT_LPSTR, т.е. мы передаем Проводнику строку, но csFlags = SHCOLSTATE_TYPE_INT, а это означает, что когда данные сортируются, это должно происходить в цифровой форме. Поскольку есть такая возможность, возвратить номер вместо строки, а тэг ID3 хранит год как строку, такое определение столбца избавляет нас от неприятностей, связанных с преобразованием года в цифровую форму.
Когда dwIndex имеет значение от 3 до 5, мы возвращаем информацию о встроенных столбцах повторного использования. Столбец 3 показывает поле Artist тэга ID3 в столбце Author:
|
case 3: // MP3 artist - повторное использование встроенного столбца Author { psci->scid.fmtid = FMTID_SummaryInformation; // Предопределенный FMTID psci->scid.pid = 4; // Предопределенный - Author psci->vt = VT_LPSTR; // Возвращаем данные в виде строки psci->fmt = LVCFMT_LEFT; // Текст выровнен по левой границе psci->csFlags = SHCOLSTATE_TYPE_STR; // Данные сортируются как строки psci->cChars = 32; // Начальная ширина колонки в символах } break; |
FMTID_SummaryInformation - предопределенный символ, а ID поля Author (4) приведено в MSDN. См. страницу "The Summary Information Property Set". При повторном использовании столбца мы не возвращаем заголовок или описание, так как оболочка сама позаботится об этом.
Наконец, после блока оператора switch мы возвращаем S_OK, чтобы показать, что мы заполнили структуру SHCOLUMNINFO.
