2

I'd like to build an application that invokes CancelIoEx on Windows Vista and newer (where it is supported) and does something else on Windows XP (where it is not).

  1. What happens if I compile the application under Windows 7 but run it under Windows XP? What will happen at runtime? Will I get some sort of load error?

  2. How do I get my application to pick one code path or another (avoiding load errors) depending on what operating system is being used at runtime? Please provide sample code.

UPDATE: Please note that the DLL exists on Windows XP but the function does not.

Gili
  • 86,244
  • 97
  • 390
  • 689
  • possible duplicate of [Delay Loading DLLs](http://stackoverflow.com/questions/1388388/delay-loading-dlls) – Greg Hewgill Jan 26 '12 at 18:27
  • @GregHewgill, delay loading isn't appropriate in this case (dynamic loading is). Aside from that, I believe this isn't an exact duplicate because #1 isn't covered, nor is it clear how to detect which OS is running in #2. – Gili Jan 26 '12 at 18:33
  • 1
    The way to detect the OS is *not* to detect the specific OS, but simply try to load the DLL. You want feature detection, not version detection. The feature is explained in the documentation here: http://msdn.microsoft.com/en-us/library/151kt790.aspx – Greg Hewgill Jan 26 '12 at 18:36
  • @GregHewgill, if you take a look at the documentation for CancelIoEx() you will note the DLL in question is Kernel32.dll. The DLL is not missing. The function is. As such, I don't believe delay-loading applies. – Gili Jan 26 '12 at 18:38
  • 1
    Sorry, I must have misread your question. I've provided an answer that should work by way of apology. :) – Greg Hewgill Jan 26 '12 at 18:43
  • 1
    possible duplicate of [Checking for existance of Windows API Functions](http://stackoverflow.com/questions/1129340/checking-for-existance-of-windows-api-functions), [How to call a kernel32.dll function GetTickCount() using LoadLibrary(..) in C++](http://stackoverflow.com/questions/6557028/how-to-call-a-kernel32-dll-function-gettickcount-using-loadlibrary-in-c) – Cody Gray - on strike Jan 26 '12 at 18:51
  • Not blaming you for asking a duplicate question, of course. If you didn't know about `LoadLibrary` or `GetProcAddress`, you'd have a hard time finding them. I just like to keep all answers in one place. Call it an obsession. :-) – Cody Gray - on strike Jan 26 '12 at 19:01

2 Answers2

2

Yes, an application that references a non-existent DLL export will fail to load.

Adding code to take different paths based on the OS version won't help much, because you'll still have the reference to the non-existent function.

Instead, you need to resolve the reference at run-time.

One option is Delay Load Import (with the /DELAYLOAD linker flag), but I don't think this is supported for the core system DLLs (like kernel32).

The other is to use LoadLibrary and GetProcAddress. The code is something like this, though in reality you'd do the lookup once when your app starts, not each time you call the function.

// Declare type of pointer to CancelIoEx function
typedef BOOL (WINAPI *CancelIoExType)(HANDLE hFile, LPOVERLAPPED lpOverlapped);

// Load module; won't fail because it's already imported
HMODULE hKernel32 = LoadLibrary(L"kernel32.dll");
// Look up function address
CancelIoExType pCancelIoEx = (CancelIoExType)GetProcAddress(hKernel32, "CancelIoEx");
// Do something with it
if (pCancelIoEx)
{
    // Function exists so call it
    pCancelIoEx(hMyFile, pMyOverlapped);
}
else
{
    // Function doesn't exist
}
arx
  • 16,686
  • 2
  • 44
  • 61
1

In order to resolve a symbol at runtime, you need to use LoadLibrary and GetProcAddress:

HMODULE kernel32 = LoadLibrary("kernel32.dll");
BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED) = GetProcAddress(kernel32, "CancelIoEx");

In the case that CancelIoEx is not available, you will get NULL back from GetProcAddress. Once you have the pointer (you only need to do the above once), you can call it normally with:

pCancelIoEx(h, &lp);
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285