delphi - 调用外部WinAPI函数

时间:2016-04-02 21:35:07

标签: 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;

我也试过这样称呼

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中夸大WinAPI,将其称为function Foo():BOOL; external Kernel32 name 'Foo';type TFoo = function(): BOOL; stdcall;
  3. 之间的区别是什么?

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

    更新

    在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;
    }
    

1 个答案:

答案 0 :(得分:5)

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

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

WINBASEAPI
BOOL
WINAPI
IsNativeVhdBoot (
    _Out_ PBOOL NativeVhdBoot
    );

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

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

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


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