- •Методические указания для выполнения лабораторной работы №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 в зависимости от их типа»
- •Как установить
- •Подробности реализации
- •Задания для лабораторных работ
- •Содержание отчета
DragLeave()
DragLeave() вызывается, если пользователь утаскивает объект прочь от нашего целевого файла, не сбрасывая его. Этот метод не используется для меню Send To, но он вызывается, если у вас открыто окно проводника на каталоге Send To и вы перетаскиваете файлы в этот каталог. У нас нет никакой очистки, которую нужно было бы сделать (деструктор CString сам позаботиться об этом), поэтому все, что нам нужно сделать - это вернуть S_OK:
|
HRESULT CSendToShlExt::DragLeave() { return S_OK; } |
Drop()
Если пользователь выберет наш пункт из меню Send To, проводник вызывает метод Drop(), прототип которого:
|
HRESULT IDropTarget::Drop ( IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ); |
Первые три параметра такие же, как у DragEnter(). Drop() должен вернуть результат всей операции через параметр pdwEffect. Наша реализация Drop() создает диалог и передает ему список имен файлов. Диалог делает все работу, и, когда происходит возврат из DoModal(), мы устанавливаем результат сбрасывания:
|
HRESULT CSendToShlExt::Drop ( IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // init MFC
CSendToCloneDlg dlg ( &m_lsDroppedFiles );
dlg.DoModal();
*pdwEffect = DROPEFFECT_COPY; return S_OK; } |
Диалог выглядит так:
Это достаточно прямолинейный MFC диалог, и вы можете найти исходники в файле SendToCloneDlg.cpp. Я делал копирование и перемещение используя класс CShellFileOp из моей статьи "CShellFileOp - Wrapper for SHFileOperation."
Подождите! А как мы сообщим проводнику о нашем обработчике сбрасывания? И как нам получить пункт в меню Send To? Я объясню, как это делается, в следующем разделе.
Регистрация расширения
Регистрация обработчика сбрасывания немного отличается от регистрации других типов расширений, т.к. требует создания новой ассоциации под ключом HKEY_CLASSES_ROOT. AppWizard генерирует RGS сценарий, показанный ниже. Часть, которую вы должны добавить или изменить выделена.
|
HKCR { .SendToClone = s 'CLSID\{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}' SendToClone.SendToShlExt.1 = s 'SendToShlExt Class' { CLSID = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}' } SendToClone.SendToShlExt = s 'SendToShlExt Class' { CLSID = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}' CurVer = s 'SendToClone.SendToShlExt.1' } NoRemove CLSID { ForceRemove {B7F3240E-0E29-11D4-8D3B-80CD3621FB09} = s 'Send To Any Folder Clone' { ProgID = s 'SendToClone.SendToShlExt.1' VersionIndependentProgID = s 'SendToClone.SendToShlExt' ForceRemove 'Programmable' InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } 'TypeLib' = s '{B7F32400-0E29-11D4-8D3B-80CD3621FB09}' val NeverShowExt = s '' DefaultIcon = s '%MODULE%,0' shellex { DropHandler = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}' } } } } |
Первая строка как раз и выполняет ассоциацию. Она создает новое расширение, .SendToClone, которое и будет использоваться нашей целью для сбрасывания. Заметим, что у значения по умолчанию ключа .SendToClone есть приставка "CLSID\". Это говорит проводнику, что данные, которые описывает ассоциация находятся в ключе под HKCR\CLSID, рядом с более стандартными ассоциациями, данные которых сохранены в ключе прямо под HKEY_CLASSES_ROOT (например, ключ .txt указывает на ключ txtfile), но это только кажется стандартным - сохранение ассоциации обработчика сбрасывания под своим CLSID ключом, чтобы держать все данные в одном месте.
Строка "Send To Any Folder Clone" - это описание типа файла, которая появляется в проводнике, если вы просматриваете каталог Send To. Значение NeverShowExt создано, чтобы сообщить проводнику, что не нужно показывать расширение ".SendToClone". DefaultIcon - ключ, указывающий размещение иконки, ассоциированной с файлами .SendToClone. Наконец, у нас есть знакомый ключ shellex с подключом DropHandler. Т.к. здесь может быть только один обработчик для данного типа файлов, GUID обработчика сохранен прямо в ключе DropHandler, вместо подключа под DropHandler.
Оставшаяся деталь - создать файл в каталоге Send To, чтобы там появился наш пункт в меню. Мы можем сделать это в DllRegisterServer() и удалить файл в DllUnregisterServer(). Вот код, создающий файл:
|
LPITEMIDLIST pidl; TCHAR szSendtoPath [MAX_PATH]; HANDLE hFile; LPMALLOC pMalloc;
if ( SUCCEEDED( SHGetSpecialFolderLocation ( NULL, CSIDL_SENDTO, &pidl ))) { if ( SHGetPathFromIDList ( pidl, szSendtoPath )) { PathAppend ( szSendtoPath, _T("Some other folder.SendToClone") );
hFile = CreateFile ( szSendtoPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
CloseHandle ( hFile ); }
if ( SUCCEEDED( SHGetMalloc ( &pMalloc ))) { pMalloc->Free ( pidl ); pMalloc->Release(); } } |
Вот как выглядит новое меню Send To с нашим пунктом меню:
DllUnregisterServer() содержит простой код, который удаляет файл. Код, показанный выше, работает на всех версиях Windows (ну хорошо, на версиях 4 и выше). Если вы знаете, что ваш код будет запущен только в оболочке версии 4.71 и выше, вы можете использовать SHGetSpecialFolderPath() вместо SHGetSpecialFolderLocation().
