Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11631
Последний выпуск: 19.06.2015

Использование DllEntryPoint

Автор: Константин Малахов
4 апреля 2009 года

В данной статье я хотел бы рассмотреть два вопроса - во первых, рассмотреть пример использования точки входа библиотеки (DllEntryPoint), во вторых - продемонстрировать один из способов, как определить версию файла библиотеки из ее самой. Собственно определение версии - это задача достаточно частная - на самом деле используя подобную технологию можно например маппить в память образ длл, модифицировать и... ну впрочем ограничимся получением версии.

И так начнем с точки входа (Dll Entry Point). Хочу обратить внимание, что я рассматриваю сейчас только случай когда загрузка библиотеки происходит динамически, если вам нужна статическия линковка - поэкспериментируйте самостоятельно.

Точка входа (DllEntryPoint) очень удобный иструмент для настройки загрузки и выгрузки вашей библиотеки. Функция точки входа вызывается при каждой загрузке и выгрузке библиотеки и получает три параметра - дескриптор библиотеки (HINSTANCE), флаг причины вызова(DWORD fwdreason) и детализация вызова (LPVOID lpvReserved). Хочу отметить, что если вы не используете VC-стиль для dll, то наименование и типы могут немного отличаться.

Как это использовать? Дескриптор библиотеки может быть использован при вызове различных функций - например той же функции получения версии файла.

Флаг загрузки может принимать следующие значения:

  • DLL_PROCESS_ATTACH - При присоединении к адресному пространству текущего процесса, в результате его запуска или вызова функции LoadLibrary
  • DLL_THREAD_ATTACH - Данный процесс создает новый поток
  • DLL_PROCESS_DETACH - Завершение процесса либо вызов FreeLibrary
  • DLL_THREAD_DETACH - Завершение потока

Параметр lpvReserved позволяет определить каким образом загружена библиотека - статически или динамически. Если параметр имеет значение отличное от NULL - библиотека загружена статически, если же NULL - то динамически (с использованием LoadLibrary/FreeLibrary).

Как это использовать? В качестве примера я приведу код, который позволяет получить номер версии библиотеки и вывести его в заголовке модального окна. Для этого вы должны создать новый проект типа DllWizard, Source Type - C++, Use VCL, VC++Style Dll. В проект добавьте юнит (File/New/Unit), сохраните его под названием loadforms.cpp. Так же добавьте форму, дайте ей название fmMain, файл сохраните как main.cpp. Из файла с DllEntryPoin можете прочесть и удалить обширный комментарий и сохранить файл как maindll.cpp, а сам проект - так как нравится вам - например versiontest. В принципе наименования файлов могут быть такими как нравится вам, в коде я буду придерживаться указанной схемы. В прикрепленном файле вы найдете исходные коды проекта.

Для получения версии файла используется функция, получающая в качестве параметра путь к файлу библиотеки и ссылку на строку, куда нужно записать результат. Код функции:

void FileVersion(char* file,String &version){

VS_FIXEDFILEINFO pvsf;
DWORD dwHandle;
DWORD cchver;
BOOL bret;
cchver = GetFileVersionInfoSize( file, &dwHandle );
if( cchver != 0 )
{
    char* pver = new char[ cchver ];
    bret = GetFileVersionInfo( file, dwHandle, cchver, pver );
    if( bret )
    {
        UINT uLen;
        void *pbuf;
        bret = VerQueryValue( pver, "\\", &pbuf, &uLen );
        if( bret )
        {
            memcpy( &pvsf, pbuf, sizeof( VS_FIXEDFILEINFO ) );
            char* fileVersion = new char[ cchver ];

            sprintf( fileVersion,
                      "%01.1d.%01.1d.%01.1d.%01.1d",
                      HIWORD( pvsf.dwFileVersionMS ),
                      LOWORD( pvsf.dwFileVersionMS ),
                      HIWORD( pvsf.dwFileVersionLS ),
                      LOWORD( pvsf.dwFileVersionLS ) );
           version = (String)fileVersion;
            delete [] fileVersion;
        }
    }
   delete[] pver;
}
}

Обратите внимание на точку входа:

//Глобальная переменная для имени библиотеки
char *VersionInfo = new char[512];
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
{
 switch(fwdreason){
case DLL_PROCESS_ATTACH:
  {
   //Библиотека загружена через LoadLibrary?
   if(lpvReserved == NULL){
    //Получаем имя модуля
    GetModuleFileName(hinstDLL,VersionInfo,512);

   }
  break;
  }

case DLL_PROCESS_DETACH:
 {
  if(lpvReserved == NULL)
//Если вызывана FreeLibrary - очищаем память и выходим
   delete[] VersionInfo;
 }
}

        return 1;
}

И собственно код из модуля loadforms

//loadforms.h

#ifndef loadformsH
#define loadformsH
//---------------------------------------------------------------------------
#include 

//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) HWND ShowDllForm();

#endif

//loadforms.cpp
#pragma hdrstop

#include "loadforms.h"
#include "main.h"
#include 


extern char *VersionInfo;

void FileVersion(char* file,String &version);
typedef DWORD(__import *pGetFileVersionInfoSize)(LPCTSTR lptstrFilename,LPDWORD lpdwHandle);
typedef DWORD(__import *pGetFileVersionInfo)(LPCTSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData);
typedef DWORD(__import *pVerQueryValue)(LPCVOID pBlock,LPCTSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen);

pGetFileVersionInfoSize fGetFileVersionInfoSize;
pGetFileVersionInfo  fGetFileVersionInfo;
pVerQueryValue fVerQueryValue;

void FileVersion(char* file,String &version){

VS_FIXEDFILEINFO pvsf;
DWORD dwHandle;
DWORD cchver;
BOOL bret;
cchver = GetFileVersionInfoSize( file, &dwHandle );
if( cchver != 0 )
{
    char* pver = new char[ cchver ];
    bret = GetFileVersionInfo( file, dwHandle, cchver, pver );
    if( bret )
    {
        UINT uLen;
        void *pbuf;
        bret = VerQueryValue( pver, "\\", &pbuf, &uLen );
        if( bret )
        {
            memcpy( &pvsf, pbuf, sizeof( VS_FIXEDFILEINFO ) );
            char* fileVersion = new char[ cchver ];

            sprintf( fileVersion,
                      "%01.1d.%01.1d.%01.1d.%01.1d",
                      HIWORD( pvsf.dwFileVersionMS ),
                      LOWORD( pvsf.dwFileVersionMS ),
                      HIWORD( pvsf.dwFileVersionLS ),
                      LOWORD( pvsf.dwFileVersionLS ) );
           version = (String)fileVersion;
            delete [] fileVersion;
        }
    }
   delete[] pver;
}
}


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

HWND ShowDllForm()
{
 fmMain = new TfmMain(Application);
 String versioninfo;
 FileVersion(VersionInfo,versioninfo);
 fmMain->Caption = "Aaii ver." + versioninfo;
 fmMain->ShowModal();
 delete fmMain;
 return NULL;
}


#pragma package(smart_init)

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

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог