Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.11.14;
Скачать: CL | DM;

Вниз

Доступ к 3-му параметру DllEntryPoint()   Найти похожие ветки 

 
Digitman ©   (2002-09-12 08:21) [0]

BOOL WINAPI DllEntryPoint(

HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
);


lpvReserved

Specifies further aspects of DLL initialization and cleanup.
If fdwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllEntryPoint has been called by using FreeLibrary and non-NULL if DllEntryPoint has been called during process termination.

Оч простой вопрос :

Каким образом, не меняя контекст system.pas и sysinit.pas, получить доступ по чтению к параметру lpvReserved в момент, когда код инициализации/деинициализации DLL (генерируемой средствами Делфи) получает управление ?

Интересны простые и изящные идеи, обеспечивающие надежное решение задачи для указанных ОС и версий Делфи.


 
Ученик ©   (2002-09-12 08:55) [1]

Есть подозрение, что DllProc нужно присвоить адрес процедуры

procedure MyDLLProcEx(Reason: Integer; Reserved: Integer);
begin

end;

В Delphi 6 переменная называется
{ DllProcEx passes the Reserved param provided by WinNT on DLL load & exit }
DllProcEx: TDLLProcEx absolute DllProc;

Для Delphi 5 переменной нет, но возможно будет работать для DllProc, к сожалению проверить не могу.


 
Digitman ©   (2002-09-12 09:19) [2]

>Ученик

Не будет это работать в D5.

@@noTLSproc:

{ Call any DllProc }

MOV EDX,[ESP+4]
TEST EDX,EDX
JE @@noDllProc
MOV EAX,[EBP+12]
CALL EDX

А как это реализовано в D6 ?
Приведи, пожалуйста, полный код _StartLib, у меня нет под руеой Д6


 
Ученик ©   (2002-09-12 09:24) [3]

procedure _InitLib;
asm
{ -> EAX Inittable }
{ [EBP+8] Hinst }
{ [EBP+12] Reason }
{ [EBP+16] Resvd }

MOV EDX,offset Module
CMP dword ptr [EBP+12],DLL_PROCESS_ATTACH
JNE @@notInit

PUSH EAX
PUSH EDX
MOV ModuleIsLib,1
MOV ECX,[EBP+8]
MOV HInstance,ECX
MOV [EDX].TLibModule.Instance,ECX
MOV [EDX].TLibModule.CodeInstance,0
MOV [EDX].TLibModule.DataInstance,0
CALL InitializeModule
POP EDX
POP EAX

@@notInit:
PUSH DllProc
MOV ECX,offset TlsProc
CALL _StartLib
end;

procedure _StartLib;
asm
{ -> EAX InitTable }
{ EDX Module }
{ ECX InitTLS }
{ [ESP+4] DllProc }
{ [EBP+8] HInst }
{ [EBP+12] Reason }

{ Push some desperately needed registers }

PUSH ECX
PUSH ESI
PUSH EDI

{ Save the current init context into the stackframe of our caller }

MOV ESI,offset InitContext
LEA EDI,[EBP- (type TExcFrame) - (type TInitContext)]
MOV ECX,(type TInitContext)/4
REP MOVSD

{ Setup the current InitContext }

POP InitContext.DLLSaveEDI
POP InitContext.DLLSaveESI
MOV InitContext.DLLSaveEBP,EBP
MOV InitContext.DLLSaveEBX,EBX
MOV InitContext.InitTable,EAX
MOV InitContext.Module,EDX
LEA ECX,[EBP- (type TExcFrame) - (type TInitContext)]
MOV InitContext.OuterContext,ECX
XOR ECX,ECX
CMP dword ptr [EBP+12],0
JNE @@notShutDown
MOV ECX,[EAX].PackageInfoTable.UnitCount
@@notShutDown:
MOV InitContext.InitCount,ECX

MOV EAX, offset RaiseException
MOV RaiseExceptionProc, EAX
MOV EAX, offset RTLUnwind
MOV RTLUnwindProc, EAX

CALL SetExceptionHandler

MOV EAX,[EBP+12]
INC EAX
MOV InitContext.DLLInitState,AL
DEC EAX

{ Init any needed TLS }

POP ECX
MOV EDX,[ECX]
MOV InitContext.ExitProcessTLS,EDX
JE @@skipTLSproc
CMP AL,3 // DLL_THREAD_DETACH
JGE @@skipTLSproc // call ExitThreadTLS proc after DLLProc
CALL dword ptr [ECX+EAX*4]
@@skipTLSproc:

{ Call any DllProc }

PUSH ECX
MOV ECX,[ESP+8]
TEST ECX,ECX
JE @@noDllProc
MOV EAX,[EBP+12]
MOV EDX,[EBP+16]
CALL ECX
@@noDllProc:

POP ECX
MOV EAX, [EBP+12]
CMP AL,3 // DLL_THREAD_DETACH
JL @@afterDLLproc // don"t free TLS on process shutdown
CALL dword ptr [ECX+EAX*4]

@@afterDLLProc:

{ Set IsLibrary if there was no exe yet }

CMP MainInstance,0
JNE @@haveExe
MOV IsLibrary,1
FNSTCW Default8087CW // save host exe"s FPU preferences

@@haveExe:

MOV EAX,[EBP+12]
DEC EAX
JNE _Halt0
CALL InitUnits
RET 4
end;


 
Игорь Шевченко ©   (2002-09-12 10:20) [4]

IMHO, анализируя код, похоже, что переданные параметры передаются в DLLProc без изменения, как в D5, так и в D6


 
Digitman ©   (2002-09-12 11:11) [5]

>Игорь Шевченко

да вот не получается, Игорь, как ты имеешь честь скромно предполагать)

Вот смотри - явно же видна разница :

D5:

@@noTLSproc:

{ Call any DllProc }

MOV EDX,[ESP+4]
TEST EDX,EDX
JE @@noDllProc
MOV EAX,[EBP+12] //Reason - как положено : 1-м параметром в EAX
CALL EDX // 2-й параметр д.б. в EDX, а этот РОН использован для иной цели - как CALL-диспетчер

D6:
{ Call any DllProc }

PUSH ECX
MOV ECX,[ESP+8]
TEST ECX,ECX
JE @@noDllProc
MOV EAX,[EBP+12] //Reason - 1-м параметром в EAX
MOV EDX,[EBP+16] //Reserved - 2-м параметром в EDX
CALL ECX //порядок ! оба параметра доступны в теле DLLProc


 
Игорь Шевченко ©   (2002-09-12 11:14) [6]

Digitman © (12.09.02 11:11)

Извиняюсь, не углядел, что вызываемая по DLLProc процедура имеет fastcall calling convention.

Спасибо за науку :-)

С уважением,


 
Ученик ©   (2002-09-12 11:17) [7]

>Digitman ©
Из стэка уже достали ?


 
Digitman ©   (2002-09-12 11:31) [8]

быть бы уверенным, что и в полсед.версиях смещение будет равно +16 - нет проблем, конечно, достать из стека ...


 
Ученик ©   (2002-09-12 11:43) [9]

В последних версиях $IFDEF VERXXX и DllProcEx


 
Digitman ©   (2002-09-12 14:08) [10]

Господа, будьте любезны, проверьте этот код у себя :


type
PDllEntryPointFrame = ^TDllEntryPointFrame;
TDllEntryPointFrame = packed record
hModule: THandle; // DLL module handle
dwReason: DWord; // reason for calling DLLEntryPoint function of DLL
bStatic: LongBool; // TRUE if DLL is loading/unloading satically, FALSE - dinamically
end;

function IsStaticDLLCall: Boolean;
asm
mov edx, [hInstance]
mov eax, ebp
@@nextframe:
cmp [eax + $08].TDllEntryPointFrame.hModule, edx
je @@found
mov eax, [eax]
jmp @@nextframe
@@found:
mov eax, [eax + $08].TDllEntryPointFrame.bStatic
end;


результат вызова ф-ции контекстом исполняемого внутри DLL кода показывает, как было осуществлено обращение к DLL из хост-процесса для загрузки/выгрузки - статически или динамически

код вроде бы устойчиво работает (в D5) и в dpr дельфийской библиотеки и в разделах initialization/finalization любого из ее модулей

хотелось бы проверить это в Д6/Д7


 
Ученик ©   (2002-09-12 14:25) [11]

Delphi 7, Windows 2000, не работает (AV), статическая загрузка DLL


 
Ученик ©   (2002-09-12 14:29) [12]

Сорри, не туда вставил, все работает


 
Ученик ©   (2002-09-12 14:48) [13]

Шутка

procedure Test(I1, I2, I3, I4 : Integer);
begin
if IsStaticDLLCall then
MessageBox(0, "Static", "Info", MB_OK)
else
MessageBox(0, "Dynamic", "Info", MB_OK)
end;

begin
Test(HInstance, HInstance, HInstance, HInstance)
end.


 
Digitman ©   (2002-09-12 15:14) [14]

>Ученик

А в разделах init/final - тоже работает ? Или не пробовал ?


 
Ученик ©   (2002-09-12 15:22) [15]

>Digitman © (12.09.02 15:14)
При динамической работает в секциях init/final
При статической похоже final не вызывается


 
Digitman ©   (2002-09-12 15:29) [16]

>Ученик
>>При статической похоже final не вызывается

быть того не может)

ну да ладно, это уже не столь важно..
главное, что стековые манипуляции (в интересующем меня плане) оказываются идентичными в модулях system и sysinit начиная с D5 и вплоть до D7.

Благодарю за помощь и содействие !


 
Ученик ©   (2002-09-12 15:56) [17]

>Digitman © (12.09.02 15:29)

initialization
if IsLibrary then begin
if IsStaticDLLCall then
MessageBox(0, "I Static", "Info", MB_OK)
else
MessageBox(0, "I Dynamic", "Info", MB_OK)
end
finalization
if IsLibrary then begin
if IsStaticDLLCall then
MessageBox(0, "F Static", "Info", MB_OK)
else
MessageBox(0, "F Dynamic", "Info", MB_OK)
end
end


FreeLibrary(LoadLibrary("DllTest.dll"));

Два сообщения

function ExportString : PChar; stdcall; external "DllTest.dll";

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(ExportString)
end

Одно сообщение на загрузке,

Может конечно вызывается, но окно не показывается, интересно почему.


 
Ученик ©   (2002-09-12 16:10) [18]

>Ученик © (12.09.02 15:56)
Диагноз верен, сообщения в файл выводятся, с MessageBox непонятки


 
Digitman ©   (2002-09-12 16:57) [19]

>Ученик

ShowMessage() в модуле Dialogs требует как миниму наличия невыгруженного и не деинициализированного еще модуля USER32.DLL в АП хост-процесса. И вполне возможно, что при стат. деинициализации/выгрузке системой модулей, загруженных ранее статически, модуль USER32.DLL деинициализируется системой несколько раньше обращения к нему со стороны кода в Dialogs, поэтому окно не выводится, а потенциальнеые ошибки обращения к USER32 мягко "гасятся" системой : на кой черт, спрашивается, ей чего-то сообщать юзеру, если процесс завершен и приложение все равно выгружается вместе со всеми "потрохами" ?
Хотя ... предположение (о порядке деинициализации/выгрузке взаимозависимых модулей) проверить, конечно, следовало бы ...


 
Ученик ©   (2002-09-12 17:08) [20]

>Digitman © (12.09.02 16:57)
Здесь Windows.MessageBox, но скорее всего действительно вывод гасится, хотя почему бы не сообщать об Exception-ах, которые происходят при выгрузке


 
Digitman ©   (2002-09-12 17:27) [21]

> Ученик

Если не лень, оттрассируй пошагово неработающий MessageBox() в данной ситуации - мне тоже интересно...


 
Игорь Шевченко ©   (2002-09-12 17:27) [22]

Digitman © (12.09.02 16:57)
Ученик © (12.09.02 17:08)

Есть список InitializationOrderList в PEB^.LoaderData - там можно посмотреть, кто в какой последовательности инициализировался. Выгрузка происходит в обратном порядке (IMHO).

Но я сомневаюсь, что user32 деинициализируется раньше, чем клиентская DLL.

С уважением,


 
Digitman ©   (2002-09-12 17:41) [23]

>Игорь Шевченко

Я тоже сомневаюсь. Но, тем не менее, факт остается фактом и , значит, причина в чем-то другом. Без трассировки это сложно сказать


 
Ученик ©   (2002-09-12 18:39) [24]

Попробовал MessageBox(0, "F Static", "Info", MB_OK + MB_SERVICE_NOTIFICATION); сообщение в этом случае показывается


 
Digitman ©   (2002-09-12 18:58) [25]

Отсюда - вывод : предположение неверно.

значит, что-то в Dialogs ...


 
Ученик ©   (2002-09-12 19:09) [26]

>Digitman © (12.09.02 18:58)
Здесь нет Dialogs, ShowMessage, и так далее :-), сообщения выводятся средствами Windows API,
только если указан MB_SERVICE_NOTIFICATION, оно показывается по другому, почему не показывается в первом случае так и не понятно.


 
paul_shmakov ©   (2002-09-13 14:46) [27]

лучше OutputDebugString для таких вещей использовать


 
msts   (2002-09-13 16:34) [28]

У меня сообщение показывается
только без обработки ввода - прорисовывается и сразу закрывается
видимо процесс выгрузки независим от GUI и пока он незавершен
то сообщение видимо а как только достигнул определенной стадии
(например библиотека какая то выгружается) исчезает
заметно когда много BPL-ек используется (в данном случае штук 30)



Страницы: 1 вся ветка

Текущий архив: 2002.11.14;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.019 c
4-46195
Граф
2002-10-05 07:40
2002.11.14
Добавление пункта в контекстное меню Windows Explorer при инсталл


14-46097
AL2002
2002-10-24 15:30
2002.11.14
Я тут узнал.


1-45863
mikl2002
2002-11-05 15:05
2002.11.14
Путь и Dll


1-45901
Shaman2002
2002-11-05 18:41
2002.11.14
Как нарисовать дугу?


1-45980
First_May
2002-11-04 14:56
2002.11.14
MDI проект...