delphi - 调用外部WinAPI函数

Rep*_*til 2 c++ delphi winapi windows-10

我正在尝试调用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;
Run Code Online (Sandbox Code Playgroud)

我也试过这样称呼它

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;
Run Code Online (Sandbox Code Playgroud)

我的问题是

  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;
}
Run Code Online (Sandbox Code Playgroud)

Ser*_*yuz 5

在您的第一次尝试中,您有一个调用约定不匹配,您链接的文档声明它是'stdcall'.但是,从问题和答案的评论看来,这并不是你得到"参数不正确"错误的原因.该调用似乎在所有条件下都设置了此错误.

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

WINBASEAPI
BOOL
WINAPI
IsNativeVhdBoot (
    _Out_ PBOOL NativeVhdBoot
    );
Run Code Online (Sandbox Code Playgroud)

所以参数是'var BOOL'或'PBOOL',而不是'var PBOOL'.如果你使用'PBOOL',你必须传递一个现有的BOOL变量的地址,而不是指向你的第一个片段中没有指向任何地方的指针.

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

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


对于第二个问题,您的第一个声明静态加载库,第二个片段动态加载库.有关更多信息,请参阅文档.如上所述,您还有一个额外的区别,即第一个具有寄存器调用约定,但这种差异并不意味着.