- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Создание текста для тултипа
После вызова Load() проводник вызывает QueryInterface() для получения другого интерфейса, IQueryInfo. Это приятный, простой интерфейс из двух методов, из которых в действительности используется только один. Снова откройте TxtInfoShlExt.h и добавьте выделенные строки:
|
class ATL_NO_VTABLE CTxtInfoShlExt : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CTxtInfoShlExt, &CLSID_TxtInfoShlExt>, public IDispatchImpl<ITxtInfoShlExt, &IID_ITxtInfoShlExt, &LIBID_TXTINFOLib>, public IPersistFile, public IQueryInfo { BEGIN_COM_MAP(CTxtInfoShlExt) COM_INTERFACE_ENTRY(ITxtInfoShlExt) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IPersistFile) COM_INTERFACE_ENTRY(IQueryInfo) END_COM_MAP() |
Затем добавьте прототипы для методов IQueryInfo:
|
// IQueryInfo STDMETHOD(GetInfoFlags)(DWORD*) { return E_NOTIMPL; } STDMETHOD(GetInfoTip)(DWORD, LPWSTR*); |
Метод GetInfoFlags() в данный момент не используется, поэтому мы возвращаем E_NOTIMPL. Метод GetInfoTip() передаст проводнику текст для отображения в тултипе. Начало несколько скучное:
|
HRESULT CTxtInfoShlExt::GetInfoTip ( DWORD dwFlags, LPWSTR* ppwszTip ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // init MFC
LPMALLOC pMalloc; CStdioFile file; DWORD dwFileSize; CString sFirstLine; BOOL bReadLine; CString sTooltip;
USES_CONVERSION; |
Сначала мы вызываем AFX_MANAGE_STATE для инициализации MFC. Это нужно сделать в первую очередь, еще до объявления переменых, т.к. конструкторы будут вызывать MFC-функции.
dwFlags в данный момент не используется. ppwszTip - указатель на LPWSTR (указатель на строку UNICODE), который изначально будет указывать на буфер, который мы должны распределить. В первую очередь мы попытаемся открыть файл для чтения. Имя файла мы знаем, так как сохранили его в Load().
|
if ( !file.Open ( m_sFilename , CFile::modeRead | CFile::shareDenyWrite )) return E_FAIL; |
Теперь нам необходим указатель на интерфейс IMalloc, чтобы распределить буфер в разделяемой памяти оболочки. Этот указатель мы можем получить вызвав функцию SHGetMalloc():
|
if ( FAILED( SHGetMalloc ( &pMalloc ))) return E_FAIL; |
Более подробно о IMalloc я расскажу позже. Дальше нам надо получить размер файла и первую строку:
|
// Get the size of the file. dwFileSize = file.GetLength();
// Read in the first line from the file. bReadLine = file.ReadString ( sFirstLine ); |
Если к файлу был получен доступ, и он не пустой, bReadLine примет значение TRUE. На следующем шаге мы создаем первую часть строки описания, которая отобразит размер файла:
|
sTooltip.Format ( _T("File size: %lu"), dwFileSize ); |
Теперь, если мы смогли прочитать первую строку файла, добавляем ее к строке описания:
|
if ( bReadLine ) { sTooltip += _T("\n"); sTooltip += sFirstLine; } |
После того, как мы создадим строку описания, нужно поместить ее в буфер. Для этого используем IMalloc. Указатель, возвращаемый SHGetMalloc() - это копия интерфейса оболочки IMalloc. Вся память, которую мы выделяем с помощью этого интерфейса, находится в пространстве процесса оболочки, поэтому проводник имеет к ней доступ. Более того, оболочка может сама ее освободить. Так что мы размещаем буфер и забываем об этом. Оболочка сама освободит память сразу после окончания ее использования.
Мы должны помнить, что строка, которую мы передаем оболочке должна быть в UNICODE. Вот почему в выражении Alloc() (см. код ниже) есть умножение на sizeof(wchar_t). При выделении памяти просто для lstrlen(sToolTip) будет выделена только половина требуемого количества памяти.
|
*ppwszTip = (LPWSTR) pMalloc->Alloc ( (1 + lstrlen(sTooltip)) * sizeof(wchar_t) );
if ( NULL == *ppwszTip ) { pMalloc->Release(); return E_OUTOFMEMORY; }
// Use the Unicode string copy function to put the tooltip text in the buffer. wcscpy ( *ppwszTip, T2COLE((LPCTSTR) sTooltip) ); |
И, наконец, нужно освободить интерфейс IMalloc, полученный ранее.
|
pMalloc->Release(); return S_OK; } |
Вот и все! Проводник берет строку в *ppwszTip и отображает ее в тултипе.
