2

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

  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'; and 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

#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;
}
RepeatUntil
  • 2,272
  • 4
  • 32
  • 57
  • 2
    The documentation for that function appears to be slightly off. As far as I can tell from tracing into it on Windows 10 at least, the function returns the result. That is, a FALSE result means that this wasn't a VHD boot - not that the call failed. – 500 - Internal Server Error Apr 03 '16 at 01:50
  • @500-InternalServerError: That's the results I seem to be seeing as well. No matter how the parameter is passed to the function, it seems to always return false and GetLastError always says it's an invalid parameter, so it appears that the input is ignored and that the function actually returns whether or not it's a VHD boot. – Ken White Apr 03 '16 at 03:26

1 Answers1

5

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.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • thanks for the explained, i have changed the function to `function IsNativeVhdBoot(var NativeVhdBoot:BOOL):BOOL; stdcall; external kernel32;` The `LastOSError` still return `The parameter is incorrect.` – RepeatUntil Apr 03 '16 at 09:19
  • Strange thing is that the documentation does not clear when should we call GetLastError since a false return does not mean the function failed. – Sertac Akyuz Apr 03 '16 at 09:29
  • @Repeat - Is that the case if you set the last error to 0 before the function call? – Sertac Akyuz Apr 03 '16 at 09:37
  • @setact yes, I have tried to set the last error to 0 before call it but always return the same error. – RepeatUntil Apr 03 '16 at 09:45
  • Docs say `BOOL WINAPI IsNativeVhdBoot ( _Out_ PBOOL *NativeVhdBoot );` so it's a pointer to `PBOOL`. I'd check the header files, docs could be wrong. – David Heffernan Apr 03 '16 at 12:03
  • @David - The wording is though, "pointer to a variable that receives a boolean". Normally I'd consider the declaration in the documentation definitive, but it doesn't make much sense here to expect a pointer to a pointer to a BOOL. Anyway neither seems to do job here according to comments. I wouldn't be surprised if the function does not actually expect any parameters at all. – Sertac Akyuz Apr 03 '16 at 13:38
  • Sertac @david-heffernan Tested the same function in c++ but the error is the same the snippet added in the question part. – RepeatUntil Apr 03 '16 at 18:53
  • I think the docs are wrong. I think that the result is returned in the return value. Have you tried on a machine where you expect true to be the result? – David Heffernan Apr 03 '16 at 18:56
  • @Repeat - Thanks for informing. Your result confirms this answer has several issues. 1- Wrong calling convention is not the cause of the specific error. 2- Have to address that the docs explicitly state that the return is the result of the query and you have to remove the exception at a false return. 3- It is unclear what to do with the parameter. At this point I actually find the first comment to the question more helpful. – Sertac Akyuz Apr 03 '16 at 19:05
  • @DavidHeffernan just now i test it the same error is returned. – RepeatUntil Apr 03 '16 at 19:10
  • SertacAkyuz i accepted your answer because you have answer my second question thanks for that – RepeatUntil Apr 03 '16 at 19:13
  • @Repeat what value is returned on machine booted from a vhd container? That is, the function return value. – David Heffernan Apr 03 '16 at 19:16
  • @DavidHeffernan The return value is always false even in VHD boot. – RepeatUntil Apr 03 '16 at 19:18
  • @David - the declaration in winbase.h is `WINAPI IsNativeVhdBoot ( _Out_ PBOOL NativeVhdBoot );` – Sertac Akyuz Apr 03 '16 at 19:53
  • @Repeat - I modified the answer to have it reflect the facts, rather than claims. However it is still ugly if you ask me. I'll not hesitate to remove it as it is not quite helpful at all, should a better one appear. Or on any other condition... – Sertac Akyuz Apr 03 '16 at 20:42
  • @SertacAkyuz Everything is cleared and explained in your answer thanks a lot. – RepeatUntil Apr 03 '16 at 22:40
  • Whether a PBOOL, var BOOL, var PBOOL or a PPBOOL are passed does not matter. All are passed as pointers. The function does not know the difference, so it can hardly be complaining about it. The GetLastError must be wrong. In other words, the declaration of the parameter and what gets passed does not explain the error. – Rudy Velthuis Apr 04 '16 at 00:02