- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Обработка wm_measureitem
Когда оболочка посылает нашему расширению сообщение WM_MEASUREITEM для запроса размеров нашего пункта меню, мы начинаем с проверки, затребованы ли размеры нашего собственного пункта меню. Если тест пройден, мы получаем размеры битмапа, затем вычисляем размер всего пункта меню.
Сначала размер битмапа:
|
STDMETHODIMP CBmpCtxMenuExt::OnMeasureItem ( MEASUREITEMSTRUCT* pmis, LRESULT* pResult ) { BITMAP bm; LONG lThumbWidth; LONG lThumbHeight;
// Check that we're getting called for our own menu item. if ( m_uOurItemID != pmis->itemID ) return S_OK;
m_bmp.GetBitmap ( &bm );
m_lBmpWidth = bm.bmWidth; m_lBmpHeight = bm.bmHeight; |
Далее, мы вычисляем размер эскиза, и, исходя из этого, размер всего пункта меню. Если картинка меньше, чем максимальный размер эскиза (который в демонстрационном проекте 64х64), то она будет нарисована как есть. Иначе, картинка будет нарисована размером 64х64. Это может исказить ее вид, но опять же, создание приятного вида эскиза оставлено для упражнений.
|
// Calculate the bitmap thumbnail size. lThumbWidth = (m_lBmpWidth <= m_lMaxThumbnailSize) ? m_lBmpWidth : m_lMaxThumbnailSize;
lThumbHeight = (m_lBmpHeight <= m_lMaxThumbnailSize) ? m_lBmpHeight : m_lMaxThumbnailSize;
// Calculate the size of the menu item, which is the size of the thumbnail + // the border and padding (which provides some space at the edges of the item). m_lItemWidth = lThumbWidth + m_lTotalBorderSpace; m_lItemHeight = lThumbHeight + m_lTotalBorderSpace; |
Теперь, когда у нас есть размер пункта меню, мы сохраняем размеры обратно в MENUITEMSTRUCT, которую мы получили с сообщением. Проводник зарезервирует достаточно места в меню для нашего пункта.
|
// Store the size of the item in the MEASUREITEMSTRUCT. pmis->itemWidth = m_lItemWidth; pmis->itemHeight = m_lItemHeight;
*pResult = TRUE; // we handled the message
return S_OK; } |
Обработка wm_drawitem
Когда мы получаем сообщение WM_DRAWITEM, проводник требует, чтобы мы действительно вывели наш пункт меню. Мы начинаем с вычисления прямоугольника, в котором мы нарисуем объемную границу вокруг эскиза. Это не обязательно тот же прямоугольник, которые занимает пункт меню, потому что меню может оказаться шире, чем размер, который мы установили в обработчике WM_MEASUREITEM.
|
STDMETHODIMP CBmpCtxMenuExt::OnDrawItem ( DRAWITEMSTRUCT* pdis, LRESULT* pResult ) { CDC dcBmpSrc; CDC* pdcMenu = CDC::FromHandle ( pdis->hDC ); CRect rcItem ( pdis->rcItem ); // RECT of our menu item CRect rcDraw; // RECT in which we'll be drawing
// Check that we're getting called for our own menu item. if ( m_uOurItemID != pdis->itemID ) return S_OK;
// rcDraw will first be set to the RECT that we set in WM_MEASUREITEM. // It will get deflated as we go along. rcDraw.left = (rcItem.right + rcItem.left - m_lItemWidth) / 2; rcDraw.top = (rcItem.top + rcItem.bottom - m_lItemHeight) / 2; rcDraw.right = rcDraw.left + m_lItemWidth; rcDraw.bottom = rcDraw.top + m_lItemHeight;
// Shrink rcDraw to account for the padding space around // the thumbnail.
rcDraw.DeflateRect ( m_lMenuItemSpacing, m_lMenuItemSpacing ); |
Первый шаг рисования - окрашивание фона пункта меню. Элемент itemState структуры DRAWITEMSTRUCT показывает, отмечен наш пункт меню, или нет. Это определяет, какой цвет мы используем для фона.
|
// Fill in the background of the menu item. if ( pdis->itemState & ODS_SELECTED ) pdcMenu->FillSolidRect ( rcItem, GetSysColor ( COLOR_HIGHLIGHT )); else pdcMenu->FillSolidRect ( rcItem, GetSysColor ( COLOR_3DFACE )); |
Далее, мы рисуем вдавленую границу, чтобы эскиз выглядел в меню утопленным.
|
// Draw the sunken 3D border. for ( int i = 1; i <= m_l3DBorderWidth; i++ ) { pdcMenu->Draw3dRect ( rcDraw, GetSysColor ( COLOR_3DDKSHADOW ), GetSysColor ( COLOR_3DHILIGHT ));
rcDraw.DeflateRect ( 1, 1 ); } |
Последний шаг - нарисовать сам эскиз. Я выбрал простой путь и просто сделал вызов StretchBlt(). Результат не всегда красивый, но моей целью было сохранить простоту кода.
|
// Create a new DC and select the original bitmap into it. dcBmpSrc.CreateCompatibleDC ( &dc ); dcBmpSrc.SelectObject ( &m_bmp );
// Blit the bitmap to the menu DC. pdcMenu->StretchBlt ( rcDraw.left, rcDraw.top, rcDraw.Width(), rcDraw.Height(), &dcBmpSrc, 0, 0, m_lBmpWidth, m_lBmpHeight, SRCCOPY );
*pResult = TRUE; // we handled the message
return S_OK; } |
Замечу, что в реальном расширении было бы хорошей идеей использовать для рисования свободный от мерцания класс, чтобы пункт меню не мерцал, когда вы перемещаете над ним мышь.
Вот несколько экранных кадров меню! Сначала - это меню в невыбраном и в выбранном состоянии.
А здесь - меню в оболочке версии 4.00. Заметьте, как в выбранном состоянии инвертируются все цвета, делая его безобразным.
