问题
I'm trying to call IsNativeVhdBoot function but i get error message 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
- What I'm doing wrong to call the above function.
- When Calling an
extranl WinAPI in delphi what is the difference between calling it
function Foo():BOOL; external Kernel32 name 'Foo';
andtype 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
#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:
In your first try, you have a calling convention mismatch, documentation you linked states it to be '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. Explanation of the parameter is actually inconsistent with the declaration in the documentation which suggests a pointer to a pointer to a BOOL. However the actual declaration in 'winbase.h' is different than the one in the documentation and is in accordance with the wording:
WINBASEAPI
BOOL
WINAPI
IsNativeVhdBoot (
_Out_ PBOOL NativeVhdBoot
);
So the parameter is a 'var BOOL' or a 'PBOOL', not a '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.
At this point one should note that, it actually doesn't matter, as the API does not seem to be setting the 'out' parameter. 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. 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.
来源:https://stackoverflow.com/questions/36378993/delphi-call-external-winapi-function