我遇到过一种我知道代码的情况
我在Visual Studio 2008中创建了一个MFC应用程序,它可以生成一个托盘图标和一些通知。我已经阅读过,通过设置结构的NOTIFYICONDATA
属性来初始化它,我可以为Windows Vista使用不同的cbSize
结构而不是Windows XP。我还读过,我可以在Windows Vista中使用LoadIconMetric
加载我的通知图标,而在Windows XP中,我无法使用该功能,我必须使用LoadIcon
。
在我的应用程序中,我设置了以下内容:
#ifndef WINVER
#define WINVER 0x0600 // Vista
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // Vista
#end#if
#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0600 // Vista
#endif
#ifndef _WIN32_IE
#define _WIN32_IE 0x0700
#endif
我正在Visual Studio 2008中的Windows 7 x64计算机上编译和链接Windows 7 SDK。我对Windows Vista或更高版本的测试看起来像这样(直接来自MSDN):
static BOOL IsWinVistaOrLater()
{
// Initialize the OSVERSIONINFOEX structure.
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 1;
// Initialize the condition mask.
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
// Perform the test.
return VerifyVersionInfo(&osvi,
VER_MAJORVERSION | VER_MINORVERSION,
dwlConditionMask);
}
现在这是有趣的部分。我使用IsWinVistaOrLater来确定是否应该使用LoadIconMetric或LoadIcon:
if (IsWinVistaOrLater())
{
tnd_Happy.dwInfoFlags = NIIF_LARGE_ICON | tnd_Happy.dwInfoFlags;
LoadIconMetric(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON_HAPPY), LIM_SMALL, &(tnd_Happy.hIcon));
} else {
tnd_Happy.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE (IDI_ICON_HAPPY)); // ICON RESOURCE ID
}
在XP上崩溃,“在ComCtrl32.dll中找不到Ordinal 380”。如果我注释掉LoadIconMetric
的电话,那么事情就会很开心(即使将所有目标版本设置为Vista)。无论运行时代码路径如何,Windows都会尝试导入所有函数调用吗?
答案 0 :(得分:10)
只是为了帮助可能遇到非常类似问题的其他人。即使在使用Visual Studio C ++ 2010 Express WinApi模板应用程序的Windows 7下,我也无法使用LoadIconMetric。将Comctl32.lib添加到dependecies并包括CommCtrl.h之后,它继续说“在ComCtrl32.dll中找不到Ordinal 380”。我不太清楚我错过了什么,因为我完全不熟悉这些组件的切换版本。经过一段时间后,我发现了这一点,这里是这种情况的宝贵来源:
我通过在包含CommCtrl.h之前添加此行来解决了这个问题(请注意,我的应用程序仅针对Windows Vista及更高版本):
// Need CommCtrl v6 for LoadIconMetric()
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
它源自Microsoft示例项目:
答案 1 :(得分:7)
如果您为Vista设置了头文件,那么它将允许您构建无法在早期版本的Windows上加载的应用程序。这就是为什么正确设置该文件非常重要的原因。
解决您的问题:
应该可以在comctl32.dll上使用/DELAYLOAD开关。没有/ DELAYLOAD Windows将尝试预先导入所有功能(无论代码路径如何)
将目标版本头文件重置为0x0501(XP)。如果您尝试使用任何高级功能,Windows现在会自动发出警告。使用LoadLibrary(“comctl32.dll”)和&&amp ;;访问新功能。 GetProcAddress的( “LoadIconMetric”)。这种方法的缺点是你可以通过GetProcAddress进行新的调用,但结构(如果它们已经改变)将是旧的结构。
最后,很多comctl32.dll功能都是一个技巧:除非您具有特定Enabled Visual Styles,否则您的comctl32.dll版本应该始终是版本5版本。 (如果在VS2005或VS2008中创建了MFC项目,则应该已自动完成)。这意味着可以将WINVER设置为Vista,但随后ComCtl32调用开始失败,因为版本5 ComCtl32无法理解新的更大的结构。
答案 2 :(得分:3)
而不是Chris建议的LoadLibrary
和GetProcAddress
,您可以编写一个仅限Vista的延迟加载链接DLL,其中包含所有仅限Vista的代码,而您的主项目仍然以XP为目标。然后您不需要加载仅Vista代码,除非执行通过Vista版本检查并调用从Vista代码DLL导出的函数。