简体   繁体   English

delphi-调用外部WinAPI函数

[英]delphi - call external WinAPI function

I'm trying to call IsNativeVhdBoot function but i get error message The parameter is incorrect. 我正在尝试调用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;

I have also tried to call it this way 我也尝试过这样称呼它

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;

My questions is 我的问题是

  1. What I'm doing wrong to call the above function. 我在调用上述函数时做错了。
  2. When Calling an extranl WinAPI in delphi what is the difference between calling it function Foo():BOOL; external Kernel32 name 'Foo'; 在delphi中调用Extranl WinAPI时,调用它的function Foo():BOOL; external Kernel32 name 'Foo';什么区别function Foo():BOOL; external Kernel32 name 'Foo'; function Foo():BOOL; external Kernel32 name 'Foo'; and type TFoo = function(): BOOL; stdcall; type TFoo = function(): BOOL; stdcall; type TFoo = function(): BOOL; stdcall;

Because i usually do the calls like the first method but when i get the above error message i searched how to call external function and i found the other method. 因为我通常像第一种方法那样进行调用,但是当我收到上述错误消息时,我搜索了如何调用外部函数,然后找到了另一种方法。

Update 更新

Tested the same function in C++ and i got the same error, my code was as the following 在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;
}

In your first try, you have a calling convention mismatch, documentation you linked states it to be 'stdcall'. 在您的第一次尝试中,您遇到了调用约定不匹配的情况,所链接的文档将其称为“ stdcall”。 It would seem, however, from the comments to the question and this answer that this is not the reason you get the "parameter is incorrect" error. 但是,从注释到问题以及此答案似乎似乎不是您收到“参数不正确”错误的原因。 The call seems to set this error in all conditions. 该呼叫似乎在所有情况下都设置了此错误。

In both of the tries, you have an extra indirection level with your parameter. 在这两次尝试中,您的参数都有一个额外的间接级别。 The documentation states that the API is expecting an address of a BOOL variable. 该文档指出该API需要BOOL变量的地址。 Explanation of the parameter is actually inconsistent with the declaration in the documentation which suggests a pointer to a pointer to a BOOL. 参数的说明实际上与文档中的声明不一致,该说明建议使用指向BOOL的指针的指针。 However the actual declaration in 'winbase.h' is different than the one in the documentation and is in accordance with the wording: 但是,“ winbase.h”中的实际声明与文档中的声明不同,并且符合以下措辞:

WINBASEAPI
BOOL
WINAPI
IsNativeVhdBoot (
    _Out_ PBOOL NativeVhdBoot
    );

So the parameter is a 'var BOOL' or a 'PBOOL', not a 'var PBOOL'. 因此,该参数是“ var BOOL”或“ PBOOL”,而不是“ var PBOOL”。 Should you use 'PBOOL', you have to pass an existing BOOL variable's address, not a pointer that doesn't point to anywhere as in your first snippet. 如果您使用“ PBOOL”,则必须传递现有的BOOL变量的地址,而不是传递第一个代码片段中未指向任何地方的指针。

At this point one should note that, it actually doesn't matter, as the API does not seem to be setting the 'out' parameter. 在这一点上,应该注意的是,实际上并不重要,因为API似乎没有设置'out'参数。 This maybe somewhat expected as the documentation is confusing in that it states that the result will both be set to the parameter, and will be returned as the function result. 这可能有些预料,因为文档令人困惑,因为它声明结果将被设置为参数,并将作为函数结果返回。 Which is unusual... 这不寻常...

Notice that the return value of the function does not indicate that the function failed or succeeded - according to the documentation. 请注意,根据文档,该函数的返回值并不表示该函数失败或成功。 This is inconsistent in itself as the documentation also suggests to call GetLastError , normally GetLastError is only called when a function fails and here we have no means to know if it failed or not before calling it. 这本身就是矛盾的文件还表明调用GetLastError ,通常GetLastError时,函数失败时才调用,在这里我们也没办法知道它是否调用它之前失败与否。 In any case, the implication is that you have to remove the statement that raises an exception at a false return. 无论如何,这意味着您必须删除在错误返回时引发异常的语句。


For the second question, your first declaration statically loads the library, the second snippet dynamically loads the library. 对于第二个问题,您的第一个声明静态地加载了库,第二个代码段动态地加载了库。 For more information, refer to documentation . 有关更多信息,请参阅文档 As mentioned above, you have an additional difference in that the first one has register calling convention, but that difference is not meant to be. 如上所述,您还有一个额外的区别,那就是第一个具有寄存器调用约定,但这并不是必须的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM