Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.04;
Скачать: [xml.tar.bz2];




Вниз

Как узнать какая программа загрузила мою DLL? 


VBill   (2002-03-19 16:55) [0]

Как узнать какая программа загрузила мою DLL?
Надо получить о ней хоть какую нибудь информацию - HANDLE or имя файла or и т.д.



Виктор Щербаков   (2002-03-19 17:00) [1]

Смотри Tool Help Functions.



VBill   (2002-03-19 17:06) [2]

Это которые CreateToolhelp32Snapshot и т.д?? Тогда
1. WinNT 4.0 Unsupported
2. Какая именно функция??

Мне надо в момент загрузки DLL (не обязательно при загрузке, но имхо в другое время не получится точно) узнать какая прога ее загружает.



Виктор Щербаков   (2002-03-19 17:12) [3]

Тогда смотри в хэлпе DllProc.
Но лучше почитать у Рихтера про DllMain.



Dimka Maslov   (2002-03-19 17:21) [4]

Обычно hInstance основного модуля в процессе равен $00400000 (если его Image Base не переопределён программистом, создавшим его). Этим и можно воспользоваться для определении пути к программе, загрузившей динамическую библиотеку.

function GetApplicationName: string;
var
Buffer: array [0..MAX_PATH-1] of
begin
GetModuleFileName($00400000, @Buf[0], SizeOf(Buffer));
Result:=PChar(@Buf[0]);
end;



VBill   (2002-03-19 17:30) [5]

Виктор Щербаков
До задания вопроса изучил DllProc и ничего интересного там не нашел - HMODULE DLLки и причина вызова функции (насколько я помню).

Dimka Maslov
Попробую.
>Обычно hInstance ...
А если нет ?)



Виктор Щербаков   (2002-03-19 17:34) [6]


> причина вызова функции (насколько я помню).

Чего ж еще нужно? Если причина вызова DllMain- проецирование dll в адресное пространство процесса, то исследуй наздоровье загрузивший dll процесс например так: Dimka Maslov © (19.03.02 17:21)



paul_shmakov   (2002-03-20 01:42) [7]

2 Dimka Maslov:
насчет обычного $400000 - не правда, для получения этого числа нужно использовать GetModuleHandle(nil)



Digitman   (2002-03-20 09:38) [8]

Points to a procedure invoked by a DLL entry point.

Unit

System

Category

miscellaneous routines

var DLLProc: Pointer;

Description

DLLProc is used to specify a procedure that is invoked every time a DLL"s entry point is called. A procedure assigned to DLLProc must take one parameter of type Integer. For example,

procedure LibraryProc(Reason: Integer);

When the procedure is invoked, this single parameter contains a value between 0 and 3 as defined by the following group of constants in the Windows unit.

const

DLL_PROCESS_DETACH = 0;
DLL_PROCESS_ATTACH = 1;
DLL_THREAD_ATTACH = 2;
DLL_THREAD_DETACH = 3;

For further details on the meaning of these constants, refer to the description of the DllEntryPoint function in the Win32 API online help.

Note: DLL_PROCESS_ATTACH is passed to the procedure only if the DLL’s initialization code calls the procedure and specifies DLL_PROCESS_ATTACH as a parameter.

---------------------------------------------------------------
Резюме :
в теле DllProc (см.хэлп, как ее "перехватить") с параметром DLL_PROCESS_ATTACH или DLL_THREAD_ATTACH достаточно вызвать MainThreadId или GetCurrentThreadId, чтобы, получив Id процесса/потока, использовать этот Id для получения инф-ции о процессе/потоке, "подключившемся" к твоей DLL.



Dimka Maslov   (2002-03-20 15:22) [9]

Всё о-о-о-чень просто. Для того, чтобы узнать имя процесса, загрузившего библиотеку, достаточно воспользоваться стандартной функцией ParamStr(0). Это даст правильный результат даже если бибиотека используется из MSVC++!



Digitman   (2002-03-20 16:25) [10]

>Dimka Maslov
Я не проверял, но ! Если библ-ку динамически востребовал additional thread некоего процесса ?



Fellomena   (2002-03-20 16:31) [11]

А почему просто в DLL entry point не поставить:
begin
MessageBox(0, PChar(Application.ExeName), "Hi", 0);
end.

Или эта инфа должны в программе получаться ?
Если да, то что-то типа:

HModule:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
lpme.dwSize:=sizeof(MODULEENTRY32);
Module32First(HModule, lpme);
//работа с полученной структурой
While Module32Next(HModule, lpme) do
begin
//работа с полученной структурой
end;



VBill   (2002-03-20 16:50) [12]

Fellomena
Никаких Application не будет. Будет только Windows.pas :)
CreateToolhelp32Snapshot см.выше - WINNT Unsupported :(

ALL
Вспомнил, что можно запустить несколько копий программы - поэтому путь к ней не нужен (хотя, чтото я не догадался про paramstr )
Попробую GetCurrentProcessID
PS Можете по русски объяснить, что за псевдо handle в
HANDLE GetCurrentProcess(VOID);
?? В чем это заключается??



Fellomena   (2002-03-20 16:53) [13]

2 VBill:
Application в данном случае не класс VCL а объект системы.
Так что откуда ты его вызывать будешь - не имеет значения.
Если твою dll загрузит в своё АП Explorer, то выдастся полный путь к запускающему файлу, т.е. /../explorer.exe



Digitman   (2002-03-20 17:00) [14]

>Fellomena
1. Не забывай, что DLLEntryPoint может быть вызвана и в доп.потоке, а , значит, ф-ции GDI нельзя вызывать без синхронизации с осн.потоком.

2. Библиотечный экземпляр переменной пипа TApplication в момент исполнения тела процедуры с адресом равным DLLEntryPoint (точнее DLLProc, поскольку Делфи не дает доступа непосредственно к DLLEntryPoint, а вызывает DLLProc в контексте инициализации библ-ки после инициализации всех составляющих ее модулей) ВСЕГДА будет равен NIL.



Fellomena   (2002-03-20 17:06) [15]

2 Digitman:
1. Можно в DLLEntryPoint анализировать что послужило причиной вызова и соответствующим образом реагировать на это.
2. Что ты хочешь сказать своим вторым пунктом ответа ? Попробуй сделай элементарный глобальный хук со строчкой, предложенной мною ранее, в begin .. end. секции dll из которой будет устанавливаться хук - увидишь, что будет, когда любое приложение отобразит эту dll в своё АП (при срабатывании хука естественно) !



Digitman   (2002-03-20 17:18) [16]

>Fellomena
1. Не спорю. Именно об этом и сказал в Digitman © (20.03.02 09:38). Но ты же приведенным тобой примером советуешь автору вызывать некие ф-ции GDI, не учитывая потенциальный вариант вызова DllEntryPoint в доп.потоке, а сие не есть правильно.

2. Опять же - ссылаясь на твой пример :
MessageBox(0, PChar(Application.ExeName), "Hi", 0);

Ведь эта строчка обратится, выполняемая в контексте переопределенной процедуры DllProc, обратится не к переменной Application хост-процесса, а к переменной Application экземпляра библ-ки, который = nil в этот момент ! И коих (экземпляров сегмента данных библ-ки) будет столько, сколько процессов/потоков пытаются "загрузить" библ-ку (отобразить, как ты говоришь, АП ее сегментов на собственное АП).

Именно это и хотел сказать я) И хуки-то здесь ни при чем вовсе) Ежу, к.г., понятно, что АП библ-ки отображается на АП хост-процесса)



Fellomena   (2002-03-20 17:27) [17]

2 Digitman:

1. Согласна.

2. Почему же тогда при отображении неким процессом dll Application - это Application, как ты говоришь, хост-процесса, а в переопределённой - экземпляра библиотеки ?
Поясни на примере plz.
И ты согласен, что
begin
MessageBox(0, PChar(Application.ExeName), "Hi", 0);
end.
При "присоединении" dll процессом будет выводиться имя исполняемого модуля из которого этот процесс был загружен ?



VBill   (2002-03-20 17:29) [18]

Имелось ввиду, что в uses будет только Windows.pas ну и по мелочам, но не Forms, содержащий этот (T)Application.

PS.Почитал последние сообщения - мозги пухнут :) Пошел перерабатывать



Dimka Maslov   (2002-03-20 17:34) [19]

>Digitman
Я проверил, если даже библиотека динамически цепляется в дополнительном потоке ParamStr(0) всё равно вернёт имя exe файла, вот её код:

function ParamStr(Index: Integer): string;
var
P: PChar;
Buffer: array[0..260] of Char;
begin
if Index = 0 then
SetString(Result, Buffer, GetModuleFileName(0, Buffer, SizeOf(Buffer)))
else
begin
P := GetCommandLine;
while True do
begin
P := GetParamStr(P, Result);
if (Index = 0) or (Result = "") then Break;
Dec(Index);
end;
end;
end;


то есть при Index = 0 она работает так написал paul_shmakov, при Index <> 0 она берёт информацию из GetCommandLine, а уж эта функция во всех потоках даёт одинаковый результат, где бы её не вызывали.



Dimka Maslov   (2002-03-20 17:36) [20]

>Fellomena

function TApplication.GetExeName: string;
begin
Result := ParamStr(0);
end;


т.е Application.ExeName === ParamStr(0) и не зависит от того в каком модуле находится объект Application



Alx2   (2002-03-20 17:37) [21]

Если подцеплен в Uses Forms,
то всегда в Controls выполняется
procedure InitControls;
var
AtomText: array[0..31] of Char;
begin
WindowAtom := GlobalAddAtom(StrFmt(AtomText, "Delphi%.8X",
[GetCurrentProcessID]));
ControlAtom := GlobalAddAtom(
StrFmt(AtomText, "ControlOfs%.8X%.8X", [HInstance, GetCurrentThreadID]));
CanvasList := TThreadList.Create;
InitIMM32;
Mouse := TMouse.Create;
Screen := TScreen.Create(nil);
Application := TApplication.Create(nil);
InitCtl3D;
Application.ShowHint := True;
RegisterIntegerConsts(TypeInfo(TCursor), IdentToCursor, CursorToIdent);
end;

Application<>Nil



Виктор Щербаков   (2002-03-20 17:46) [22]

А код инициализации модулей выполняется настоящей DllMain до передачи управления в блок begin end. Поэтому пример Fellomena (20.03.02 16:31) будет работать правильно.



Digitman   (2002-03-20 18:10) [23]

>Dimka Maslov
Не буду возражать. Судя по коду - дествительно так.

>Alx2
Не буду сейчас влезать в дебри, просто заострю вснимание на следующем :

модуль Forms


finalization
if Application <> nil then ...;


при каких нештатных условиях м.б. выполнено условие Application <> nil, если экз-р TApplication создается автоматически и безусловно в InitControls() ?


>Fellomena
Я не о том, что будет выводиться, а что не будет ...
Я о том, что объектная переменная типа TApplication своя для каждого экз-ра сегмента данных, к которому обращается единственный сег-т кода, включающий код модуля Forms.
Т.е., два разных хост-процесса "грузят" одну и ту же библ-ку. И в хост-процессе и в библ-ке используется Forms. В рез-те будет существовать минимум 4 сег-та данных, фрагментами которого оперирует исп.код модуля Forms, а в каждом сегменте будет инициализирована или не инициализирована собственная ссылка на собственный экз-р объекта TApplication



Fellomena   (2002-03-20 18:15) [24]

2 Digitman © (20.03.02 18:10):
это, как ты сказал, и ежу понятно :)



Rooman   (2002-03-20 19:10) [25]

что-то подозрительно как-то...

если подключить forms понятно, что появится Application и будет заполнен соответствующими данными. Т.е. application.exename должен указывать на какой-то путь. Это ясно. Доверие - нулевое, т.к. чтобы поверить в то, что этот путь равен именно пути головного процесса, надо просмотреть исходный код как минимум конструктора Application.
Будьте добры посмотреть и доказать, или опровергнуть это утверждение.

Вот с paramstr(0) более убедительно. Но опять же, приведите мне фрагменты исходников и докажите/опровергните!



Rooman   (2002-03-20 19:15) [26]

function ParamStr(Index: Integer): string;
var
P: PChar;
Buffer: array[0..260] of Char;
begin
if Index = 0 then
SetString(Result, Buffer, GetModuleFileName(0, Buffer, SizeOf(Buffer)))
else
begin
P := GetCommandLine;
while True do
begin
P := GetParamStr(P, Result);
if (Index = 0) or (Result = "") then Break;
Dec(Index);
end;
end;
end;



Rooman   (2002-03-20 19:18) [27]

function GetModuleFileName(Module: Integer; Filename: PChar; Size: Integer): Integer; stdcall;
external kernel name "GetModuleFileNameA";



Rooman   (2002-03-20 19:18) [28]

The GetModuleFileName function retrieves the full path and filename for the executable file containing the specified module.

Windows 95: The GetModuleFilename function will return long filenames when an application"s version number is greater than or equal to 4.00 and the long filename is available. Otherwise, it returns only 8.3 format filenames.

DWORD GetModuleFileName(

HMODULE hModule, // handle to module to find filename for
LPTSTR lpFilename, // pointer to buffer for module path
DWORD nSize // size of buffer, in characters
);


Parameters

hModule

Identifies the module whose executable filename is being requested. If this parameter is NULL, GetModuleFileName returns the path for the file used to create the calling process.

lpFilename

Points to a buffer that is filled in with the path and filename of the given module.

nSize

Specifies the length, in characters, of the lpFilename buffer. If the length of the path and filename exceeds this limit, the string is truncated.



Return Values

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.
If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a module is loaded in two processes, its module filename in one process may differ in case from its module filename in the other process.

See Also

GetModuleHandle, LoadLibrary



Alx2   (2002-03-21 08:27) [29]

>Rooman (20.03.02 19:15)
>Но опять же, приведите мне фрагменты исходников
>и докажите/опровергните

Типа, экзамен? :) Если нет возможности самостоятельно посмотреть модуль forms, лови:


constructor TApplication.Create(AOwner: TComponent);
var
P: PChar;
ModuleName: array[0..255] of Char;
begin
inherited Create(AOwner);
FBiDiMode := bdLeftToRight;
FTopMostList := TList.Create;
FWindowHooks := TList.Create;
FHintControl := nil;
FHintWindow := nil;
FHintColor := DefHintColor;
FHintPause := DefHintPause;
FHintShortCuts := True;
FHintShortPause := DefHintShortPause;
FHintHidePause := DefHintHidePause;
FShowHint := False;
FActive := True;
FIcon := TIcon.Create;
FIcon.Handle := LoadIcon(MainInstance, "MAINICON");
FIcon.OnChange := IconChanged;
GetModuleFileName(MainInstance, ModuleName, SizeOf(ModuleName));
OemToAnsi(ModuleName, ModuleName);
P := AnsiStrRScan(ModuleName, "\");
if P <> nil then StrCopy(ModuleName, P + 1);
P := AnsiStrScan(ModuleName, ".");
if P <> nil then P^ := #0;
AnsiLower(ModuleName + 1);
FTitle := ModuleName;
if not IsLibrary then CreateHandle; - Специально на случай DLL
UpdateFormatSettings := True;
UpdateMetricSettings := True;
FShowMainForm := True;
FAllowTesting := True;
FTestLib := 0;
end;


-----------
Т.е. application.exename должен указывать на какой-то путь. Это ясно. Доверие - нулевое, т.к. чтобы поверить в то, что этот путь равен именно пути головного процесса, надо просмотреть исходный код как минимум конструктора Application.
--------------

Не совсем конструктор, вернее, совсем не конструктор (об этом уже было в предыдущих сообщениях)


function TApplication.GetExeName: string;
begin
Result := ParamStr(0);
end;


Остальные твои цитаты ничего нового не дают. Как бы сказал Digitman, и ежу понятно :))

Еще о старте DLL в модуле system:

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

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 @@noTLSproc
CALL dword ptr [ECX+EAX*4]
@@noTLSproc:

{ Call any DllProc }

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

{ 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 //Вот тут и родится Application при использовании модуля Forms :)
RET 4
end;





> Digitman
>если экз-р TApplication создается автоматически
>и безусловно в InitControls() ?
А что, это не так?

>при каких нештатных условиях
>м.б. выполнено условие Application <> nil,

Digitman, по-моему это просто правило хорошего тона. А нештатная ситуация может быть и такой: программа могла заранее похоронить этот Application. Правда, не знаю с какой целью, но это уже другие проблемы :)



paul_shmakov   (2002-03-24 21:41) [30]


var
FileName: array[0..MAX_PATH] of Char;
begin
if GetModuleFileName(GetModuleHandle(nil), FileName, MAX_PATH) <> 0 then
begin
// ok. FileName содержит имя файла процесса, в который загружена dll.
// и зачем TApplication?
end;




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.04;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.81 MB
Время: 0.025 c
1-9567            VBill                 2002-03-19 16:55  2002.04.04  
Как узнать какая программа загрузила мою DLL?


1-9578            michael_B             2002-03-24 22:18  2002.04.04  
Подскажите компоненту для создания плавающего меню под стиль OfficeXP


1-9526            Лана Розанова         2002-03-23 18:30  2002.04.04  
ListBox


4-9675            Basaev                2002-02-03 17:39  2002.04.04  
Как из своей програмы можно запустить другую программу


1-9537            Vacheslav             2002-03-23 19:23  2002.04.04  
Как в чужую программу добавить свой пункт меню?