Search code examples
visual-studio-2008winapivisual-c++mfc

Does windows preload ComCtrl32.dll in an app?


I've come across a situation where I know a code

I've created an MFC app in Visual Studio 2008 that generates a Tray Icon and some notifications. I've read I can use a different NOTIFYICONDATA structure for Windows Vista than for Windows XP by setting the cbSize property of the structure to initialize it. I've also read that I can use LoadIconMetric in Windows Vista to load my icon for the notification, whereas in Windows XP, that function is not available to me and I must use LoadIcon.

In my application, I've set the following:

#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

I'm compiling and linking against the Windows 7 SDK on a Windows 7 x64 machine in Visual Studio 2008. My test for WindowsVista or greater looks like this (straight out of 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);
}

Now here's the interesting part. I use IsWinVistaOrLater to determine if I should use LoadIconMetric or 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
}

On XP this crashes with "Ordinal 380 not found in ComCtrl32.dll". If I comment out the call to LoadIconMetric, things are happy (even with all those target vers set to Vista). Does Windows try to import all the function calls regardless of runtime code path?


Solution

  • Instead of LoadLibrary and GetProcAddress suggested by Chris, you can write a Vista-only delay-load-linked DLL which contains all Vista-only code while your main project still targets XP. Then you don't need to load Vista-only code unless the execution pass the Vista version check and call functions exported from the Vista code DLL.