Reputation: 41
In a Delphi DLL need to establish the caller -- which may be a simple ".exe" or a DBMS runtime module -- which means it must obtain the command which is running in the process.
I know that CmdLine won't work, and probably ParamStr(0), and cannot use "main window" based techniques as caller will sometimes not have a window. I suspect that GetModuleHandle is the starting point, but need assistance to get from there to command being executed.
Upvotes: 4
Views: 1426
Reputation: 612954
In fact ParamStr(0)
will work fine. It is, on Windows, implemented with a call to the API function GetModuleFileName
, passing a value of 0
as the module handle. This retrieves the file name associated with the main executable module. This works just the same no matter that the call is made from a DLL or the main executable.
We don't really need to dig into the implementation if we would trust the Delphi documentation. Admittedly this can sometimes be a risky business! The documentation for ParamStr
says:
ParamStr(0) returns the path and file name of the executing program (for example,
C:\TEST\MYPROG.EXE
).
If you need to know the arguments that were passed to the executable process, you can use ParamStr
passing indices greater than zero. Or you could call GetCommandLine
and parse the command line yourself.
Do beware that GetCommandLine
will not always give the same executable file name as GetModuleFileName
. The documentation says:
The name of the executable in the command line that the operating system provides to a process is not necessarily identical to that in the command line that the calling process gives to the CreateProcess function. The operating system may prepend a fully qualified path to an executable name that is provided without a fully qualified path.
All this feels a little dirty though. It might be cleaner to export an initialization function from the DLL and require callers to pass whatever information you need.
Upvotes: 1
Reputation: 256711
I created a test dll:
library Project2;
uses
System.SysUtils, System.Classes, Vcl.Forms, Vcl.Dialogs, Winapi.Windows;
{$R *.res}
procedure DoStuff; stdcall;
begin
ShowMessage(
'ParamStr(0): '+ParamStr(0)+#13#10+
'GetCommandLine: : '+GetCommandLine);
end;
exports
DoStuff;
begin
end.
And then call it from a test application:
procedure TForm1.Button1Click(Sender: TObject);
var
module: HMODULE;
doStuff: procedure; stdcall;
begin
module := LoadLibrary('D:\Temp\Win32\Debug\Project2.dll');
if module = 0 then
RaiseLastOSError;
try
doStuff := GetProcAddress(module, 'DoStuff');
if @doStuff = nil then
raise Exception.Create('Could not find export "DoStuff"');
DoStuff;
finally
FreeLibrary(module);
end;
end;
And it sees the command line, using both:
ParamStr(0)
GetCommandLine
GetCommandLine
obviously shows the entire command line, while ParamStr(0)
is (by definition) just the process executable path.
Upvotes: 4