c++ - delphi - 调用外部WinAPI函数

标签 c++ delphi winapi windows-10

我正在尝试调用IsNativeVhdBoot函数,但我收到错误消息参数不正确。

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. 调用时 extranl WinAPI在delphi中调用它有什么区别 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;
}

最佳答案

在您的第一次尝试中,您的调用约定不匹配,您链接的文档将其声明为“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 。如上所述,您还有一个额外的区别,即第一个具有寄存器调用约定,但这种区别并不意味着如此。

关于c++ - delphi - 调用外部WinAPI函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36378993/

相关文章:

c++ - 没有临时实例的成员指针的偏移量

c++ - 在一个线程中创建对象并使用 std::atomic 访问另一个线程

delphi - 如何使用TStreamWriter和TStreamReader读写PDF文件?

android - 适用于手机和平板电脑的应用程序

c# - 在禁用滚动条的RichTextBox中获取滚动条 'position'

c++ - 关闭调用后,如何在 UDP recvfrom() 调用中获取返回值 0?

c++ - RPN 计算器 C++ 问题

delphi - 用DELPHI获取网页内容

c++ - 给定基色计算渐变填充的开始和结束颜色

.net - 如何设置amcap的默认色彩空间为YUY2?