Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП - методички / OS&SP_Lab_2.6(shell).doc
Скачиваний:
95
Добавлен:
18.05.2015
Размер:
1.12 Mб
Скачать

Отладка расширения оболочки

В конечном счете вы напишете расширение, которое может быть далеко не простым, и вам придется его отлаживать. Откройте установки вашего проекта и на закладке 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().

Вот пошаговое содержание функции:

  1. Изменить текущий каталог на каталог, открытый в окне проводника.

  2. Перечислить все выбранные файлы.

  3. Каждый файл попытаться загрузить с LoadLibrary().

  4. Если LoadLibrary() завершилась успешно, убедиться, что файл экспортирует функции DllRegisterServer() и DllUnregisterServer().

  5. Если обе функции обнаружены, добавить имя файла к списку файлов 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;

Соседние файлы в папке ОСиСП - методички