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

Регистрация расширения

Хэндлер иконок регистрируется под ключом типа файлов, для которого он предназначен, в нашем случае это HKCR\txtfile. Как и для других расширений используется ключ ShellEx под txtfile. Затем следует ключ IconHandler. Значение умолчанию для этого ключа - GUID расширения. Заметьте, что может быть только один хэндлер иконок для каждого типа файлов. Мы также должны изменить значение ключа DefaultIcon на "%1", чтобы наш обработчик был задействован.

Вот RGS сценарий регистрации расширения:

HKCR

{

NoRemove txtfile

{

NoRemove DefaultIcon = s '%%1'

NoRemove ShellEx

{

ForceRemove IconHandler = s '{DF4F5AE4-E795-4C12-BC26-7726C27F71AE}'

}

}

}

Отметим, что для того, чтобы определить строку "%1", мы должны писать в RGS файле "%%1", т.к. % это спецсимвол, используемый для указания заменяемых параметров (например "%MODULE%").

Тот факт, что мы перезаписываем существующее значение DefaultIcon имеет большое значение. Как нам правильно деинсталировать свое расширение, если мы уничтожили старое значение DefaultIcon? Выход в том, что мы сохраняем значение DefaultIcon в DllRegisterServer() и восстанавливаем его в DllUnregisterServer(). Мы должны сделать это в процессе деинсталляции и оставить иконки текстовых файлов такими, какими они были до нашего вмешательства.

Посмотрите код функций регистрации/разрегистрации чтобы увидеть как они работают. Отметим, что мы делали сохранение перед вызовом ATL для выполнения RGS скрипта, поскольку если мы сделаем по другому, значение DefaultIcon будет перезаписано прежде, чем мы получить возможность сохранить его.

Пример 10 «Расширение оболочки для изменения иконок у dll в зависимости от их типа»

будет вот что – в зависимости от типа dll (COM, .NET, “обычная” dll) в окне проводника для неё будет показываться своя иконка:

Крупные значки

Мелкие значки

Ага, не знали что mfc42.dll – COM сервер :-)

Как установить

Скопируйте dllinfo.dll на локальный диск и зарегистрируйте командой

Regsvr32 dllinfo.dll

После этого нужно или перерегистрироваться в windows, или каким-либо другим способом заставить Проводник перестроить кэш иконок.

Подробности реализации

О написании расширения, устанавливающего иконку для файла в зависимости от его содержимого можно прочитать в Руководстве по написанию расширения для настройки иконок, отображаемых для файлов заданного типа от Michael Dunn, здесь же имеет смысл остановиться на способе определения типа dll:

// получаем тип dll

DLLTYPE Cdlltester::GetDllType()

{

WORD ImageType = 0;

DLLTYPE result = ITISNOTDLL;

HRESULT ( STDAPICALLTYPE * pfn ) ();

// загружаем, но DllMain не вызываем, ни к чему

HINSTANCE hi = ::LoadLibraryEx ( m_szFilename, NULL,

DONT_RESOLVE_DLL_REFERENCES );

if ( hi )

{

// пробуем на COM

( FARPROC& ) pfn = ::GetProcAddress ( hi, "DllGetClassObject" );

if ( pfn ) // это COM dll !

result = COMDLL;

else

{

// DLL, но не COM

// может .NET ?

ImageType = ::GetExecutableImageType( hi );

if ( ! EIT_IS_DLL( ImageType ) )

result = ITISNOTDLL;

else

{

if ( EIT_IS_DOTNET( ImageType ) )

result = NETDLL;

else

// если, неCOM, неNET, значит просто dll

result = WIN32DLL;

}

}

::Sleep( 0 );

::FreeLibrary ( hi );

}

return result;

}

Как видно из текста программы, для проверки на COM просто проверяется наличие экспортируемой функции DllGetClassObject. Исполняемые файлы .NET - это обычные файлы формата PE (Portable Executable). Для получения адреса той области, где располагается специфичная для .NET информация, необходимо обратиться к элементу IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR массива IMAGE_DATA_DIRECTORY, расположенному в конце заголовка PE-файла (структуры IMAGE_NT_HEADERS).

В статье Matt Pietrek “An In-Depth Look into the Win32 Portable Executable File Format” есть упоминание о том, что в более новых версиях системных заголовочных файлов IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR переименован в IMAGE_DIRECTORY_ENTRY_COMHEADER, однако в ноябрьском 2001 года Platform SDK нового названия еще нет.

Каждый элемент массива IMAGE_DATA_DIRECTORY содержит информацию о расположении данных, определяемых этим элементом.

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

typedef struct _IMAGE_DATA_DIRECTORY

{

DWORD VirtualAddress; //относительный виртуальный адрес данных

DWORD Size; //размер данных

}

Таким образом, для определения принадлежности файла к .NET достаточно проверить поле Size элемента IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR массива DataDirectory. Если в файле есть .NET информация, размер данных, Size будет отличным от нуля.

#define EIT_IS_DLL(t) ((-1!=(t))&&((t) & 0x1))

#define EIT_IS_DOTNET(t) ((-1!=(t))&&((t) & 0x2))

//-------------------------------------------------------------------

// Функция для проверки типа уже загруженного исполняемого файла

//

// Параметры:

//

// hinst - HINSTANCE загруженного модуля

//

// Возвращаемое значение:

//

// Если младший бит возвр.значения установлен, то файл является

// динамической библиотекой (dll), иначе это exe-файл. Для

// проверки можно использовать макрос EIT_IS_DLL();

//

// Второй бит возвр.значения установлен, то файл является

// файлом .NET. Для проверки можно использовать макрос

// EIT_IS_DOTNET();

//

// В случае неудачи возвращается -1.

//-------------------------------------------------------------------

WORD GetExecutableImageType( HINSTANCE hinst )

{

PBYTE pFileBase;

PIMAGE_DOS_HEADER pDosHeader;

PIMAGE_NT_HEADERS pNtHeader;

WORD result = 0;

if ( !hinst )

return -1;

pFileBase = ( PBYTE ) hinst;

// Убеждаемся в корректности

pDosHeader = ( PIMAGE_DOS_HEADER ) pFileBase;

if ( IMAGE_DOS_SIGNATURE == pDosHeader->e_magic )

{

pNtHeader = ( PIMAGE_NT_HEADERS ) ( pFileBase + pDosHeader->e_lfanew );

if ( ( !IsBadReadPtr( pNtHeader, sizeof( pNtHeader->Signature ) ) ) &&

( IMAGE_NT_SIGNATURE == pNtHeader->Signature ) &&

( pNtHeader->FileHeader.Characteristics &

IMAGE_FILE_EXECUTABLE_IMAGE ) )

{

// Делаем необходимые проверки

if ( pNtHeader->FileHeader.

Characteristics & IMAGE_FILE_DLL )

result |= 0x1;

if ( pNtHeader->OptionalHeader.

DataDirectory[ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ].Size )

result |= 0x2;

}

}

return result;

}

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