问题
I'm trying to dynamically load an exe file from my program and run SomeProcedure from that dynamicaly loaded exe. Here's what I'm doing in loaded exe - library.exe
interface
procedure SomeProcedure; stdcall;
implementation
procedure SomeProcedure;
begin
ShowMessage('Ala has a cat');
end;
And here's my exe that load's library.exe and try to run SomeProcedure from it.
type
THandle = Integer;
TProc = procedure();
var
AHandle: THandle;
Proc: TProc;
procedure TForm1.Button1Click(Sender: TObject);
begin
AHandle := LoadLibrary('library.exe');
if AHandle <> 0 then begin
@Proc := GetProcAddress(AHandle, 'SomeProcedure');
if @Proc <> nil then
try
Proc;
finally
FreeLibrary(AHandle);
end;
end;
end;
end;
Unfortunately it's not working - AHandle has an address but GetProcAddress always returns nil. What am I doing wrong?
回答1:
To the very best of my knowledge, what you are attempting is not possible. You cannot use LoadLibrary to load a .exe file, and then call its exported functions. You can only have one .exe file loaded into a process. You'll need to move the functionality into a library, or a COM server, or some other solution.
As Sertac points out, the documentation does cover this:
LoadLibrary can also be used to load other executable modules. For example, the function can specify an .exe file to get a handle that can be used in FindResource or LoadResource. However, do not use LoadLibrary to run an .exe file. Instead, use the CreateProcess function.
You can use GetProcAddress with the module handle of an executable. But you have to obtain the module handle by calling GetModuleHandle(0), for example.
回答2:
As David already pointed out it is nearly impossible. Well not impossible I would say. Just for the sake of understanding you could teoretically call CreateProcess and then hook its call and the calls that follow. One of the calls is also ZwCreateSection. I played with things like that a long time ago and it is theoretically possible to do it. CreateProcess creates an empty process context that then gets filled with other Zw/Nt kernell calls. Knowing the calls you could supply the content.
But that was theory and even that is hacking into the OS. As David pointed out it is impossible to do it in a sane and documented way. What you can do hovewer is extract the exe as a resource to a temporary file and the execute it. You can then wait for it to end and after that delete the file. That is the only way to do it. To do it all in RAM is a no go.
EDIT:
Here is an article on a technique that can be used. But its an ugly hack :)
回答3:
"now I have an AV in call to Proc" - you forget to define "stdcall" in definition of TProc.
Just created small sample demonstrating loading/executing of exported function from another EXE.
Application 1:
program Exe4Export;
uses
Vcl.Forms,
Unit3 in 'Unit3.pas' {Form3},
ExportTypes in 'ExportTypes.pas';
{$R *.res}
function Test:integer; stdcall; export;
begin
result := 7;
end;
exports
Test;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm3, Form3);
Application.Run;
end.
Application 2:
type
TExtProc = function: integer; stdcall;
procedure TForm3.FormCreate(Sender: TObject);
var
h: HMODULE;
p: TExtProc;
begin
h := LoadLibrary('Exe4Export.exe');
p := GetProcAddress(h, 'Test');
if assigned(p) then
caption := IntToStr(p);
FreeLibrary(h);
end;
So app2 loads app1 into own address space (yes, it is possible for DLL), then get address of function and call it in same way like for DLL.
来源:https://stackoverflow.com/questions/18218593/dynamically-loading-exe-file