- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
Отладка расширения оболочки
В конечном счете вы напишете расширение, которое может быть далеко не простым, и вам придется его отлаживать. Откройте установки вашего проекта и на закладке Debug укажите полный путь к проводнику в окне "Remote executable path and file name", например "C:\windows\explorer.exe". Если вы используете Windows 2000 и установили DesktopProcess как указывалось выше, нажмите F5, откроется окно проводника и вы сможете начать отладку. Пока вы будете делать свою работу, вы не будете испытывать проблем с пересозданием DLL, т.к. когда вы закроете это окно, ваше расширение будет выгружено.
В Windows 9x вы должны отключить оболочку перед запуском отладчика. Щелкните Start и затем ShutDown. Держите нажатыми Ctrl+Alt+Shift и щелкните Cancel. Это отключит проводник и вы увидите, что панель задач исчезла. Вы можете вернуться в VC и нажать F5, чтобы начать отладку.
Для остановки сеанса отладки нажмите Shift+F5, чтобы закрыть проводник. Когда отладка будет завершена, вы можете запустить проводник с коммандной строки и нормально загрузить оболочку.
Результат
Так выглядит контекстное меню после добавления нашего пункта:
Наш пункт здесь!
Так выглядит строка статуса с выведенной подсказкой:
А так выглядит сообщение, показывающее имя файла, который был отмечен:
Пример 2 «Добавление пунктов в контекстное меню для всех файлов не зависимо от расширения»
В этом примере будет показано как оперировать несколькими файлами в одной операции. Пример расширения - утилита, которая может регистрировать и разрегистрировать серверы COM. Кроме того она также демонстрирует применение диалогового класса ATL CDialogImpl. Будет дано объяснение некоторых специальных регистрационных ключей, которые вы можете использовать для загрузки расширения для любых файлов, а не только для файлов заранее выбранного типа.
Дополнительные функции расширения, добавляющего пункты к контекстному меню оболочки.
Это расширение позволяет регистрировать и разрегистрировать серверы СOM в файлах EXE, DLL и OCX. В отличии от расширения, реализованного в первой части, это расширение будет оперировать всеми файлами, выделенными, когда произошел щелчок правой кнопкой мыши.
Использование AppWizard
Запустите AppWizard и создайте новый ATL COM проект. Назовем его DllReg. Сохраните все начальные установки и щелкните Finish. Чтобы добавить COM объект к DLL перейдите в дерево просмотра классов - ClassView, щелкните правой кнопкой мыши на пункте DllReg classes и укажите New ATL Object
В мастере ATL Object на первой панели уже выбран Simple Object, поэтому просто щелкните Next. Во второй панели в поле редактирования Short Name введите CDllRegShlExt и щелкните OK. (Остальные поля редактирования заполняются автоматически.) Мы своими действиями создали класс CDllRegShlExt, в котором содержится базовый код для выполнения COM объекта. Добавим свой код к этому классу.
Интерфейс инициализации
В реализации IShellExtInit::Initialize() будет несколько отличий. Это обусловлено двумя причинами. Во-первых, мы перечислим все выбранные файлы. Во-вторых, мы протестируем их на предмет экспорта функций регистрации и разрегистрации. Мы будем рассматривать только те файлы, которые экспортируют обе функции - DllRegisterServer() и DllUnregisterServer(). Остальные файлы будут проигнорированы.
Поскольку нам придется использовать элемент управления list view, классы строк и списков из STL, необходимо добавить в файл stdafx.h следующие строки:
|
#include <commctrl.h> #include <string> #include <list> #include <atlwin.h> typedef std::list<std::basic_string<TCHAR> > string_list; |
Наш класс CDllRegShlExt также нуждается в нескольких переменных-членах:
|
protected: HBITMAP m_hRegBmp; HBITMAP m_hUnregBmp; string_list m_lsFiles; TCHAR m_szDir [MAX_PATH]; |
Конструктор класса CDllRegShlExt загружает из ресурсов две картинки для использования в контекстном меню:
|
CDLLRegShlExt::CDLLRegShlExt() { m_hRegBmp = LoadBitmap ( _Module.GetModuleInstance(), MAKEINTRESOURCE(IDB_REGISTERBMP) );
m_hUnregBmp = LoadBitmap ( _Module.GetModuleInstance(), MAKEINTRESOURCE(IDB_UNREGISTERBMP) ); } |
Внимательно просмотрите часть I. Она содержит инструкцию, как добавить IShellExtInit к списку интерфейсов, реализуемых CDllRegShlExt. Как только вы это сделаете, вы будете готовы к написанию функции Initialize().
Вот пошаговое содержание функции:
Изменить текущий каталог на каталог, открытый в окне проводника.
Перечислить все выбранные файлы.
Каждый файл попытаться загрузить с LoadLibrary().
Если LoadLibrary() завершилась успешно, убедиться, что файл экспортирует функции DllRegisterServer() и DllUnregisterServer().
Если обе функции обнаружены, добавить имя файла к списку файлов m_lsFiles, пригодных к работе.
|
HRESULT CDllRegShlExt::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID ) { TCHAR szFile [MAX_PATH]; TCHAR szFolder [MAX_PATH]; TCHAR szCurrDir [MAX_PATH]; TCHAR* pszLastBackslash; UINT uNumFiles; HDROP hdrop; FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stg = { TYMED_HGLOBAL }; HINSTANCE hinst; bool bChangedDir = false; HRESULT (STDAPICALLTYPE* pfn)(); |
Масса рутинных локальных переменных! Сначала нужно получить HDROP из pDataObj. Это делается также, как для расширения в первой части.
|
// Read the list of folders from the data object. They're stored in HDROP // format, so just get the HDROP handle and then use the drag 'n' drop APIs // on it. if ( FAILED( pDO->GetData ( &etc, &stg ))) return E_INVALIDARG;
// Get an HDROP handle. hdrop = (HDROP) GlobalLock ( stg.hGlobal );
if ( NULL == hdrop ) { ReleaseStgMedium ( &stg ); return E_INVALIDARG; }
// Determine how many files are involved in this operation. uNumFiles = DragQueryFile ( hdrop, 0xFFFFFFFF, NULL, 0 ); |
Затем следует цикл for для извлечения следующего имени файла (с помощью DragQueryFile()) и попытка загрузить его с LoadLibrary().
|
for ( UINT uFile = 0; uFile < uNumFiles; uFile++ ) { // Get the next filename. if ( 0 == DragQueryFile ( hdrop, uFile, szFile, MAX_PATH )) continue;
// Try & load the DLL. hinst = LoadLibrary ( szFile );
if ( NULL == hinst ) continue; |
Далее проверяем, экспортируются ли две необходимые функции:
|
// Get the address of DllRegisterServer(); (FARPROC&) pfn = GetProcAddress ( hinst, "DllRegisterServer" );
// If it wasn't found, skip the file. if ( NULL == pfn ) { FreeLibrary ( hinst ); continue; }
// Get the address of DllUnregisterServer(); (FARPROC&) pfn = GetProcAddress ( hinst, "DllUnregisterServer" );
// If it was found, we can operate on the file, so add it to // our list of files (m_lsFiles). if ( NULL != pfn ) { m_lsFiles.push_back ( szFile ); }
FreeLibrary ( hinst ); } // end for |
И последний шаг в вышеуказанном блоке шагов - добавить имя файла в m_lsFiles, который является списком из семейства STL-списков, содержащих строки. Этот список будет использован позже, когда мы будем регистрировать и разрегистрировать файлы.
Что еще необходимо сделать в функции Initialize(), так это освободить ресурсы и возвратить проводнику правильное значение.
|
// Release resources. GlobalUnlock ( stg.hGlobal ); ReleaseStgMedium ( &stg );
// If we found any files we can work with, return S_OK. Otherwise, // return E_INVALIDARG so we don't get called again for this right-click // operation.
return ( m_lsFiles.size() > 0 ) ? S_OK : E_INVALIDARG; |
