IsWindows10OrGreater function from <VersionHelpers.h> usage problem in asm x86 code

141 Views Asked by At

Have a task to call IsWindows10OrGreater function in asm x86 code. At first, I tried to include it from kernel32 lib, but than I found out that this library doesn't contain IsWindows10OrGreater function, instead it can be found in VersionHelpers.h file. So, I decided to create cpp file, include Windows.h and VersionHelpers.h file in there, and then extern IsWindows10OrGreater function in my asm file. But I got such error: LNK2001 unresolved external symbol _IsWindows10OrGreater.

IsWindows10OrGreater.cpp:

#include <Windows.h>
#include <VersionHelpers.h>

main.asm:

.686
.model flat, STDCALL
option casemap :none

extern IsWindows10OrGreater : proc

.data
wMajorVersion dw 10
wMinorVersion dw 0
wServicePackMajor dw 0

.code
Start:
    push wServicePackMajor
    push wMinorVersion
    push wMajorVersion
    call IsWindows10OrGreater
end Start

Tried to write in that cpp file a function that calls IsWindows10OrGreater function and returns it's result, but got more new errors. Still can't fix it, maybe there is another correct approach to use IsWindows10OrGreater function in asm x86 code?

1

There are 1 best solutions below

0
winapiadmin On

Problem


This is the definition of IsWindows10OrGreater()

VERSIONHELPERAPI
IsWindows10OrGreater();

which is expanded to

inline bool
IsWindows10OrGreater();

About inline


Because it's inline,

The inline keyword tells the compiler to substitute the code within the function definition for every instance of a function call.

Using inline functions can make your program faster because they eliminate the overhead associated with function calls. The compiler can optimize functions expanded inline in ways that aren't available to normal functions.

Inline code substitution occurs at the compiler's discretion. For example, the compiler won't inline a function if its address is taken or if it's too large to inline.

A function defined in the body of a class declaration is implicitly an inline function.

The inline and __inline specifiers instruct the compiler to insert a copy of the function body into each place the function is called.

The difference between the inline functions and macros

Inline functions are similar to macros, because the function code is expanded at the point of the call at compile time. However, inline functions are parsed by the compiler, and macros are expanded by the preprocessor. As a result, there are several important differences:

  • Inline functions follow all the protocols of type safety enforced on normal functions.

  • Inline functions are specified using the same syntax as any other function except that they include the inline keyword in the function declaration.

  • Expressions passed as arguments to inline functions are evaluated once. In some cases, expressions passed as arguments to macros can be evaluated more than once.

The following example shows a macro that converts lowercase letters to uppercase:

// inline_functions_macro.c
#include <stdio.h>
#include <conio.h>

#define toupper(a) ((a) >= 'a' && ((a) <= 'z') ? ((a)-('a'-'A')):(a))

int main() {
   char ch;
   printf_s("Enter a character: ");
   ch = toupper( getc(stdin) );
   printf_s( "%c", ch );
}
//  Sample Input:  xyz
// Sample Output:  Z

The intent of the expression toupper(getc(stdin)) is that a character should be read from the console device (stdin) and, if necessary, converted to uppercase.

Because of the implementation of the macro, getc is executed once to determine whether the character is greater than or equal to "a," and once to determine whether it's less than or equal to "z." If it is in that range, getc is executed again to convert the character to uppercase. It means the program waits for two or three characters when, ideally, it should wait for only one.

Inline functions remedy the problem previously described:

// inline_functions_inline.cpp
#include <stdio.h>
#include <conio.h>

inline char toupper( char a ) {
   return ((a >= 'a' && a <= 'z') ? a-('a'-'A') : a );
}

int main() {
   printf_s("Enter a character: ");
   char ch = toupper( getc(stdin) );
   printf_s( "%c", ch );
}

Output:

Sample Input: a
Sample Output: A

When to use inline functions

Inline functions are best used for small functions such as accessing private data members. The main purpose of these one- or two-line "accessor" functions is to return state information about objects. Short functions are sensitive to the overhead of function calls. Longer functions spend proportionately less time in the calling and returning sequence and benefit less from inlining.

Note


The inline keyword tells the compiler that inline expansion is preferred. However, the compiler can create a separate instance of the function (instantiate) and create standard calling linkages instead of inserting the code inline. Two cases where this behavior can happen are:

  • Recursive functions.

  • Functions that are referred to through a pointer elsewhere in the translation unit.

  • If you use inline function is assembly, notice assembly can't having inline functions, except you having only one-line processing (for example, HIWORD, LOBYTE, etc.) then you can expand to a wrapper and then call it.

Simple solution


From another linked question:

So there is no symbol in any library named IsWindows10OrGreater, which explains why the linker isn't finding it. You should be able to recreate the logic from those functions and call VerifyVersionInfoW directly, which is exported (from Kernel32.lib).