【问题标题】:delphi - call external WinAPI functiondelphi - 调用外部 WinAPI 函数
【发布时间】:2016-04-02 21:35:06
【问题描述】:

我正在尝试调用 IsNativeVhdBoot 函数,但收到错误消息 The parameter is incorrect.

function IsNativeVhdBoot(var NativeVhdBoot:PBOOL):BOOL; external Kernel32 name 'IsNativeVhdBoot';

function _IsNativeVhdBoot:Boolean;
var
  pB:PBOOL;
begin
  Result := False;
  if IsNativeVhdBoot(pB) then
    Result := pB^
  else RaiseLastOSError;
end;

我也试过这样称呼它

function __IsNativeVhdBoot: Boolean;
type
  TIsNativeVhdBoot = function(
    var NativeVhdBoot: pBOOL
  ): BOOL; stdcall;
var
  bNativeVhdBoot: pBOOL;
  NativeVhdBoot : TIsNativeVhdBoot;
begin
  Result := False;
  NativeVhdBoot := GetProcAddress(GetModuleHandle(kernel32), 'IsNativeVhdBoot');
  if (@NativeVhdBoot <> nil) then
  begin
    if not NativeVhdBoot(bNativeVhdBoot) then
      RaiseLastOSError;
    Result := bNativeVhdBoot^;
  end
  else
    RaiseLastOSError;
end;

我的问题是

  1. 我在调用上述函数时做错了什么。
  2. 调用 delphi中的extranl WinAPI调用它function Foo():BOOL; external Kernel32 name 'Foo';type TFoo = function(): BOOL; stdcall;有什么区别

因为我通常像第一种方法一样进行调用,但是当我收到上述错误消息时,我搜索了如何调用外部函数并找到了另一种方法。

更新

在 C++ 中测试了相同的函数,我得到了同样的错误,我的代码如下

#include "stdafx.h"
#include "Windows.h"

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL Result = false;
    SetLastError(0);
    if (IsNativeVhdBoot(&Result)) {
        if (Result) {
            printf_s("Running inside VHD\n");
        }
        else
            printf_s("Running inside physical disk drive\n");
    }
    else
        printf("IsNativeVhdBoot failed with error %d.\n", GetLastError());
    return 0;
}

【问题讨论】:

  • 该函数的文档似乎略有偏差。据我所知,至少在 Windows 10 上跟踪它,该函数返回结果。也就是说,FALSE 结果意味着这不是 VHD 启动,而不是调用失败。
  • @500-InternalServerError: 这也是我看到的结果。无论参数如何传递给函数,它似乎总是返回 false 并且 GetLastError 总是说它是一个无效的参数,所以看起来输入被忽略并且函数实际上返回是否它是 VHD 启动。跨度>

标签: c++ delphi winapi windows-10


【解决方案1】:

在您的第一次尝试中,您的调用约定不匹配,您链接的文档将其声明为“stdcall”。然而,从 cmets 到问题和这个答案,这似乎不是你得到“参数不正确”错误的原因。该调用似乎在所有情况下都设置了此错误。

在这两种尝试中,您的参数都有一个额外的间接级别。文档指出 API 需要一个 BOOL 变量的地址。参数的解释实际上与文档中的声明不一致,该声明建议指向指向 BOOL 的指针。但是,“winbase.h”中的实际声明与文档中的声明不同,并且符合措辞:

WINBASEAPI
BOOL
WINAPI
IsNativeVhdBoot (
    _Out_ PBOOL NativeVhdBoot
    );

所以参数是“var BOOL”或“PBOOL”,而不是“var PBOOL”。如果您使用“PBOOL”,则必须传递现有 BOOL 变量的地址,而不是像第一个 sn-p 中那样不指向任何地方的指针。

此时应该注意,这实际上并不重要,因为 API 似乎没有设置 'out' 参数。这可能有些意料之中,因为文档令人困惑,因为它声明结果将被设置为参数,并将作为函数结果返回。这是不寻常的......

请注意,函数的返回值并不表示函数失败或成功 - 根据文档。这本身是不一致的,因为文档还建议调用GetLastError,通常GetLastError 仅在函数失败时调用,在这里我们无法在调用它之前知道它是否失败。无论如何,这意味着您必须删除在错误返回时引发异常的语句。


对于第二个问题,您的第一个声明静态加载库,第二个 sn-p 动态加载库。有关详细信息,请参阅documentation。如上所述,您还有一个额外的区别,即第一个具有寄存器调用约定,但这种区别并不意味着存在。

【讨论】:

  • 感谢您的解释,我已将函数更改为function IsNativeVhdBoot(var NativeVhdBoot:BOOL):BOOL; stdcall; external kernel32; LastOSError 仍然返回The parameter is incorrect.
  • 奇怪的是,文档没有明确我们何时应该调用 GetLastError,因为返回错误并不意味着函数失败。
  • @Repeat - 如果您在函数调用之前将最后一个错误设置为 0,是否会出现这种情况?
  • @setact 是的,我尝试在调用它之前将最后一个错误设置为 0,但总是返回相同的错误。
  • 文档说BOOL WINAPI IsNativeVhdBoot ( _Out_ PBOOL *NativeVhdBoot ); 所以它是一个指向PBOOL 的指针。我会检查头文件,文档可能是错误的。
猜你喜欢
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 2018-04-22
相关资源
最近更新 更多