I'm faced with the need to use a new Windows runtime function where it's available, and fall back to an older one where the new one doesn't exist.
The code path is performance-critical. I need to call GetSystemTimePreciseAsFileTime if the platform (Windows 8 / Windows Server 2012) offers it, and fall back to GetSystemTimeAsFileTime if the newer version doesn't exist.
I'm aware that I can use LoadLibrary and GetProcAddress to load GetSystemTimePreciseAsFileTime and if that fails, fall back to GetSystemTimeAsFileTime. I'm concerned about the performance impact of calling something as performance-criticial as this though another layer of indirection though.
Is there any built-in mechanism to lazy load a symbol, not a whole DLL? So I can test the Windows version at startup and call a function that uses GetSystemTimePreciseAsFileTime on Win8, otherwise call the one that uses GetSystemTimeAsFileTime, without causing the whole executable to fail with a link error on older Windows versions?
Or should I just stop worrying and use GetProcAddress?
As the various comments to the question say, the cost of GetProcAddress() is minimal. The cost of calling a function via a function pointer is also near-zero.
But let's say we're working hyper-critically. We observe that the two functions that you want to call have the signatures
VOID WINAPI GetSystemTimePreciseAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
That is, they have nearly the same signatures; the only difference is that weird return type of VOID... which MSDN says is just a macro that expands to void, so they're exactly the same.
What does this mean? This means you can use a single function pointer variable, initialized once at the start of your program like so:
// global scope
VOID (*WINAPI myGetSystemTime)(LPFILETIME);
// in your initalization code
FARPROC fp;
myGetSystemTime = GetSystemTimeAsFileTime;
if (/* LoadLibraryW(L"kernel32.dll") worked */) {
fp = GetProcAddress(/* library handle */, "GetSystemTimePreciseAsFileTime");
if (fp != NULL)
myGetSystemTime = (VOID (*WINAPI)(LPFILETIME)) fp;
}
// and don't worry about errors from LoadLibraryW() or GetProcAddress() since we want to use the fallback; you may log a warning if you so choose
and then all you need to do is call (*myGetSystemTime)(&time) when you need to selectively call the function. No conditional branches or constantly polling DLLs, and there should be no measurable performance impact.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With