有效地为不同的Windows版本使用不同的API

时间:2014-09-17 13:46:45

标签: c windows winapi dll

我面临着在可用的情况下使用新的Windows运行时功能的需要,并且回归到新的运行时功能不存在的情况。

代码路径对性能至关重要。如果平台(Windows 8 / Windows Server 2012)提供它,我需要调用GetSystemTimePreciseAsFileTime,如果新版本不存在,我需要回GetSystemTimeAsFileTime

我知道我可以使用LoadLibraryGetProcAddress来加载GetSystemTimePreciseAsFileTime,如果失败,请回到GetSystemTimeAsFileTime。我关注的是通过另一层间接性来调用某些东西作为性能的关键性能影响。

是否有任何内置机制来延迟加载符号,而不是整个DLL?所以我可以在启动时测试Windows版本并调用在Win8上使用GetSystemTimePreciseAsFileTime的函数,否则调用使用GetSystemTimeAsFileTime的函数,而不会导致整个可执行文件失败并在旧版Windows上出现链接错误?

或者我应该停止担心并使用GetProcAddress

2 个答案:

答案 0 :(得分:9)

正如对问题的各种评论所说,GetProcAddress()的成本很低。通过函数指针调用函数的成本也接近于零。

但是,让我们说我们正在超级批判地工作。我们观察到您要调用的两个函数具有签名

VOID WINAPI GetSystemTimePreciseAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);

也就是说,它们的签名几乎相同;唯一的区别是奇怪的返回类型VOID ... which MSDN says is just a macro that expands to void,所以它们完全一样。

这是什么意思?这意味着您可以使用单个函数指针变量,在程序开始时初始化一次,如下所示:

// 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

然后当您需要有选择地调用该函数时,您需要做的就是调用(*myGetSystemTime)(&time)。没有条件分支或不断轮询DLL,并且应该没有可衡量的性能影响。

答案 1 :(得分:4)

我认为andlabs的回答可能是正确的;通过指针调用函数的性能损失不太可能很大。另一方面,它确实需要额外的RAM往返(或者导致指针占用缓存中可能更好用的一行)所以它不是绝对一定。

如果分析表明您确实遇到了问题,请考虑将性能关键代码放入DLL中。有两个版本的DLL,每个版本一个。安装应用程序后,请放置适当的版本。