![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Исполняемый модуль, dllinfo.dll
Исходные тексты (VC7)
А будет вот что – в зависимости от типа 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; } |
Спасибо Erusov D. Sergeevich за справедливое замечание по первому варианту DLLINFO – загружать dll два раза было совершенно не обязательно.
… то они нарисованы Виталием Брусенцевым (Виталий, привет! :-) ). Cможете нарисовать значки более точно и красиво отражающие понятия COM, .NET и Win32 dll – не забудьте поделиться со всеми.
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |