Delphi的LoadLibrary返回0(LastErrorcde=3221225616),这是什么意思?

4

我需要在我们的主应用程序中使用第三方dll。当我静态链接到提供的DLL时,它可以正常工作,并且我可以使用DLL的导出函数。但是,我们不希望我们的主应用程序在启动时依赖于此DLL,因此我尝试在需要时动态加载DLL:

DLLHandle := LoadLibrary('3rdparty.dll');
ret := GetLastError();
if DLLHandle = 0 then
begin
  err := SysErrorMessage(ret);
  Writeln(err);
end //...

但是它不起作用:LoadLibrary函数返回0,LastErrorcode为3221225616。因为我不知道我做错了什么,我尝试了同样的代码(在同一台电脑上)用c编写,它可以工作:但是为什么delphi不能工作呢?我在同一个dll上调用了同样的LoadLibrary函数!
当我使用ProcMon监视时,我看到第三方dll被加载,并且第三方dll的依赖dll也被加载了。因此,Windows肯定能找到DLL。但是在加载过程中某个地方失败了: 当我尝试使用DONT_RESOLVE_DLL_REFERENCES或LOAD_LIBRARY_AS_DATAFILE的LoadLibraryEX加载DLL时,它也可以工作(但我当然无法调用所需的函数...)
我没有更多的想法:希望你们能帮助我进一步...谢谢!
5个回答

11

这个有效吗?

var
  SavedCW: word;

...

SavedCW := Get8087CW;
Set8087CW(SavedCW or $7);
DLLHandle := LoadLibrary('3rdparty.dll');
Set8087CW(SavedCW);
if DLLHandle = 0 then
begin
  ret := GetLastError();  
  err := SysErrorMessage(ret);
  Writeln(err);
end //...

有些讨论:

错误代码3221225616似乎是无效浮点操作的结果,根据谷歌的搜索结果。这似乎非常专业;实际上,加载库与浮点运算有什么关系呢?浮点控制字(CW)是一个位字段,其中的位指定处理浮点错误的处理器应该如何处理;实际上,通过将这些位之一更改为1(顺便说一句,这是默认状态),通常可以处理意外的浮点错误。例如,请参见我的这个问题,在这个问题中,我得到了一个完全意想不到的除以零错误,这可以通过将控制字的“除以零”位设置为1来处理。


我现在将$4(二进制100)更改为$7(二进制111)。这有帮助吗?(我怀疑最低有效位是有问题的;如果是这种情况,那么做$1(二进制001)可能就足够了。) - Andreas Rejbrand
阅读我的链接和Danny的链接,那应该会帮助你理解。 - Craig Stuntz
4
Kristof表示:浮点控制字位可以控制(除其他功能外)FPU如何处理各种浮点错误-零除、溢出、下溢等。FPU可以忽略错误或触发硬件异常。大多数C/C++ RTLs禁用FP异常。Delphi应用程序设置控制字以启用某些FP异常。您可以随意禁用FP异常,但请仔细考虑忽略错误的后果,这些错误实质上指示您的应用程序中存在不良数据。 - dthorpe
1
背景信息:我之前写过一篇类似的博客文章,分析了8087控制字标志位的情况:http://wiert.wordpress.com/2009/05/06/delphi-michael-justin-had-strange-floating-point-results-when-his-8087-fpu-control-word-got-hosed/ - Jeroen Wiert Pluimers
3
应用程序加载时,DLL很快就会在进程中被加载,很可能在Delphi运行时库将8087控制字设置为最佳值之前。DLL可能期望8087控制字是操作系统的默认值。 - Jeroen Wiert Pluimers
显示剩余3条评论

7

6

3221225616 = STATUS_FLOAT_INVALID_OPERATION。我猜测您的Delphi和C应用程序中FPU CW可能不同,导致您的DLL初始化对此非常敏感。


1

我认为你应该向3rdparty.dll的开发人员报告他们DLL中的一个错误。


-1

我知道这是一个旧的帖子,但我刚遇到了同样的问题,它涉及一个用VB编写的DLL。

这个解决方案适用于x86和x64。

var  ret:cardinal;
     em:TArithmeticExceptionMask;
begin
  result:= 1;
  If Lib <> 0 Then exit;     // already loaded
  em:=GetExceptionmask;
  SetExceptionmask(em+[exInvalidOp,exZeroDivide,exOverflow, exUnderflow]);
  Lib := LoadLibrary(DLLname);
  SetExceptionmask(em);
  ret := GetLastError;
  if ret<>0 then
    raise exception.create(SysErrorMessage(ret));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接