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

В данной статье я хотел бы рассмотреть два вопроса – во первых, рассмотреть пример использования точки входа библиотеки (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. В принципе наименования файлов могут быть такими как нравится вам, в коде я буду придерживаться указанной схемы. В прикрепленном файле вы найдете исходные коды проекта.
Для получения версии файла используется функция, получающая в качестве параметра путь к файлу библиотеки и ссылку на строку, куда нужно записать результат. Код функции:
[code]
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;
}
}

[/code]
Обратите внимание на точку входа:
[code]
//Глобальная переменная для имени библиотеки
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;
}

[/code]

И собственно код из модуля loadforms
[code]
//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 = "???? ver." + versioninfo;
fmMain->ShowModal();
delete fmMain;
return NULL;
}

#pragma package(smart_init)

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

[/code]
На сегодня все.
При перепечатке ссылка на ресурс обязательна.
Обсуждение статьи на форуме

Розкажи друзям

Share to Facebook
Share to Google Buzz
Share to Google Plus
Share to LiveJournal
Share to MyWorld
Share to Odnoklassniki
Share to Yandex
Ви можете залишити комментар, чи зробити посилання зі свого сайту.

Залиште коментар

Programmed by Varkon Ltd