【问题标题】:How can I tell how my DLL was loaded?如何知道我的 DLL 是如何加载的?
【发布时间】:2011-09-06 19:51:17
【问题描述】:

我的 DLL 如何检测它是隐式加载还是显式加载?

MyTestDll.dll 示例

library MyTestDll;

uses SimpleShareMem, Windows, Dialogs;

procedure DetectMethodDllLoad: bool;
begin
  // ?????
  // need to detect loading method - implicit or explicit
end;

procedure MyTest; stdcall;
begin
  if DetectMethodDllLoad then
    ShowMessage('Working Program1 (implicit dll load)')
  else
    ShowMessage('Working Program2 (explicit dll load)');
end;

exports MyTest;

begin
end.

Program1.exe(隐式加载 dll)

procedure MyTest; stdcall; external 'MyTestDll.dll' Name 'MyTest';

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

Program2.exe(显式加载 dll)

type
  TMyTest = procedure; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyTest: TMyTest;
  H: HModule;
begin
  H := LoadLibrary('MyTestDll.dll');
  if H = 0 then
    exit;
  @MyTest := GetProcAddress(H, 'MyTest');
  if Assigned(MyTest) then
    MyTest;
  FreeLibrary(H);
end;

如何实现DetectMethodDllLoad

【问题讨论】:

  • 你的问题不清楚。你能改写一下吗?
  • DLL 使用动态链接而不是静态链接。也许您希望绘制的区别在于隐式链接和显式链接。没关系,这里没有问题,我投票结束。
  • 好吧,现在我将添加一个示例
  • 在您更新问题之前获得了接近票数。我现在明白你了。
  • @David - 问题不在于链接,而在于加载。我认为 dll 术语的动态/静态加载没有任何问题。

标签: windows delphi dll


【解决方案1】:

如果您可以创建 DllMain 过程,DLL_PROCESS_ATTACH 调用的 lpReserved 参数将告诉您负载是静态的还是动态的。

http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx

你当然可以在 C 中做到这一点。我不知道在 Delphi 中是否可能。

【讨论】:

  • 是的,这是必要的。但是如何在 Delphi 上制作呢? ;)
  • 将处理程序分配给 DLL 的 initialization 部分中的 SysInit.DllProcEx 回调。然而,问题是DllProc/Ex 回调没有被调用DLL_PROCESS_ATTACH,因为它们当时还没有被分配。不过,您可以尝试处理第一个 DLL_THREAD_ATTACHevent。
  • 但是@Remy,线程附加调用没有定义lpReserved 参数。这只是为进程附加设置的。
  • SysInit.DllProc/Ex 回调是 Delphi 公开访问 DllMain() 参数的唯一方式,但 DLL_PROCESS_ATTACH 在回调可以在用户代码中分配之前被触发,并且 Delphi 不缓存 @ 987654331@ 任何地方的价值,所以你在德尔福运气不好。切换到 C++ :-)
  • 可以在 C++ 项目中使用 Delphi .pas 文件,但不能在 Delphi 项目中使用 C++ .c/.cpp 文件。你必须创建一个 C++ 项目来解决这个问题,因为你不能像在 C++ 中那样用你自己的代码替换 Delphi 的默认 DllMain() 处理程序。
【解决方案2】:

这是一个非常好的教程,包含静态和动态两种方法:

Static vs. Dynamic Dynamic Link Library Loading - A Comparison

【讨论】:

  • 正确的术语是当导入包含在加载模块导入表中时的隐式链接和使用 LoadLibrary/GetProcAddress 时的显式链接。使用$LINK 可以获得静态链接。如果你真的愿意,你可以称之为静态链接,但这不是官方术语。
  • 如果您想了解有关此主题的更多信息,请参阅此处:msdn.microsoft.com/en-us/library/253b8k2c(VS.80).aspx
  • 好的。谢谢你的术语和你的链接。顺便说一句,这在doc中是这样写的。
  • 还有延迟加载不写任何LoadLibrary代码。
  • 请参阅DllMain Entry Point 文档中的“DLL_PROCESS_ATTACH”,其中 MS 对 DLL 使用 “动态加载”“静态加载” 术语。
【解决方案3】:

谢谢哈里·约翰斯顿!!! :)

library MyTestDll;  

uses SimpleShareMem, Windows, Dialogs;  

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 DetectMethodDllLoad: bool;  
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;

procedure MyTest; stdcall;  
begin  
...
end;  

exports MyTest;  

begin  
  if DetectMethodDllLoad then  
    ShowMessage('Working Program1 (implicit dll load)')  
  else  
    ShowMessage('Working Program2 (explicit dll load)');  
end.  

附: System.TDLLProcEx 在 Delphi XE 中不起作用

library MyTestDll; 

....

procedure MyDLLProcEx(Reason:integer;x:pointer);
begin
if x=nil then showmessage('dyn') else showmessage('stat');
end;

begin
DLLProcEx:=@MyDLLProcEx;
end;

x = nil 总是:(

【讨论】:

  • -1 有几个原因:首先,没有解释这段代码的作用(或者为什么 Harry Johnston 与它有任何关系)。其次,我碰巧理解该代码在做什么,并且我不能赞同在未记录的调用堆栈结构中进行探索,至少不是没有理由说明为什么我们应该期望它在任何特定版本的 Delphi 中都有效。第三,您自己承认,用于演示正确答案的代码不起作用。这个答案会伤害或误导以后来这里寻求答案的人。
  • @Gu: DllProcEx 不会为DLL_PROCESS_ATTACH 自动调用,您必须在分配DllProcEx 后手动调用它。 Delphi 不公开对DLL_PROCESS_ATTACH 事件的保留值的访问。
  • @Rob,大概可以信任 Delphi 使用标准的 Windows 调用堆栈,至少是暂时的?我不明白为什么首先在 DllMain 函数中调用 DetectMethodDllLoad,有人可以澄清一下吗?由于您可以在 DllMain 中执行的操作受到限制,您在使用运行时库函数时需要非常小心。
  • @Rob,我认为顾的意思是第二段代码不起作用,而不是第一段不起作用。
  • @Harry、System.pasSysInit.pas 做了一些有趣的事情。它们不一定遵守通常的调用约定。检测函数是从 DLL 的入口点调用的,因为这是唯一可以使用 lpReserved 参数的地方。您不能从任何导出的函数中调用它,因为入口点参数将不再位于堆栈上。其他 RTL 功能都很好;这是您需要避免的 DLL 函数。 DetectMethodDllLoad 没有打电话。也许我应该说接受而不是正确;我知道第二个代码就是顾指的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
相关资源
最近更新 更多