1

I'm writing a game. When it starts up, I want to call the Windows 10 GetCurrentPackageFullName() function to see if my app is running as a Universal Windows Program or not.

However, GetCurrentPackageFullName() does not exist in Windows 7 and earlier, so when people run my game on their systems, they get this error:

image

Is there a way to avoid this error by first checking if the function even exists in kernel32.dll and if not then simply not call it? I've tried the following but it doesn't seem to work:

try {
  //do we even have this function?
  typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
  PGNSI pGNSI;
  SYSTEM_INFO si;

  ZeroMemory(&si, sizeof(SYSTEM_INFO));

  pGNSI = (PGNSI) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetCurrentPackageFullName");

  //ok this exists, now let's use it
  if(pGNSI != NULL) {
    //then I call the function here
  }
} catch (int e) {
  //do nothing, just don't crash
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Actually it seems I can't even check at runtime, because from looking at the logs this error is appearing before the code even runs. Am I linking kernel.lib or kernel.dll incorrectly perhaps? – Ben Johnson Jan 26 '17 at 00:14
  • Note, you don't need `ZeroMemory` if you use struct zero-initialization syntax `SYSTEM_INFO si = {0};`. Also you should prefer `nullptr` over the `NULL` macro. – Dai Jan 26 '17 at 00:14
  • [A simple alternative would be to simple check the OS, if you're running on windows 10 instead...](http://stackoverflow.com/questions/32193855/c-check-if-windows-10) then you call the function according. – Prix Jan 26 '17 at 00:14
  • 1
    You probably want to use LoadLibrary instead of GetModuleHandle –  Jan 26 '17 at 00:14
  • 1
    Also, does any of your code actually throw a C++ exception? Win32 doesn't raise C++ exceptions, so your `try/catch` is useless in this case. Win32's exceptions are "SEH" exceptions and require the non-standard `__try`/`__except` keywords: http://stackoverflow.com/questions/7049502/c-try-and-try-catch-finally – Dai Jan 26 '17 at 00:16
  • @NeilButterworth there is no reason to use `LoadLibrary()` instead of `GetModuleHandle()` for `kernel32.dll`, as it exists in every running process. – Remy Lebeau Jan 26 '17 at 04:31
  • 3
    @Prix checking the OS version is not a solution, since the error message means the code is static linking to the function, so the error occurs before any code is run. Checking the OS version would only work if the function is delay-loaded, but `kernel32.dll` cannot be delay-loaded. – Remy Lebeau Jan 26 '17 at 04:33
  • _//then I call the function here_. OK, but __how__ do you call the function?? – Jabberwocky Jan 26 '17 at 16:27

1 Answers1

4

Using GetProcAddress() and not calling the function if NULL is the correct solution.

I think there are two problems:

  1. You should call LoadLibrary() instead of GetModuleHandle().

  2. Where you have the comment //then I call the function here, I suspect that you are still calling the GetCurrentPackageFullName() function statically. You need to call the function via the pGNSI pointer instead so you won't have the function statically linked into the program.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Dan Korn
  • 1,274
  • 9
  • 14
  • The error message box in the OP's screenshot looks like the one raised by Windows' module loader, during the dynamic-linking-before-`main` stage, so removing the call to `GetCurrentPackageFullName` will stop the loader from looking for it and so stop the error messages. – Dai Jan 26 '17 at 00:19
  • I think this is the right answer. I'm just going to test it now. But your suspicion was correct, I was not using the function pointer and so it was linking explicitly. I'll vote up in a sec! – Ben Johnson Jan 26 '17 at 00:43
  • 1
    for `kernel32.dll` we can use `GetModuleHandle` because `kernel32.dll` already loaded and always present. however in case another DLLs (not `kernel32` or `ntdll` ) really need call `LoadLibrary` – RbMm Jan 26 '17 at 02:34