BUG: SystemStats::getOperatingSystemName() on Windows 10

No, they don’t output the same. First, for the JUCE file class, the name needs to be an absolute path. This is not necessary in this case. Second, the version numbers returned are different. My function returns

10.0.15063.296

With File::getVersion () it returns

6.2.15063.296

No idea why this is, but for that alone I prefer to continue to use my old, years old function.

Also, there are no permission problems. I’ve used this function for years and every support file we’ve been sent has this correct information in it.

OK - can you do me a favour and sanity-check this cleaned up version:

struct WindowsVersion
{
    WindowsVersion()
    {
        auto name = _T("kernel32.dll");
        DWORD handle = 0;

        if (auto size = GetFileVersionInfoSize (filename, &handle))
        {
            HeapBlock<char> data (size);

            if (GetFileVersionInfo (filename, handle, size, data))
            {
                VS_FIXEDFILEINFO* info = nullptr;

                if (VerQueryValue (data, (LPCTSTR) _T("\\"), (void**) &info, &size))
                {
                    if (size > 0 && info != nullptr && info->dwSignature == 0xfeef04bd)
                    {
                        major  = HIWORD (info->dwFileVersionMS);
                        minor  = LOWORD (info->dwFileVersionMS);
                        point1 = HIWORD (info->dwFileVersionLS);
                        point2 = LOWORD (info->dwFileVersionLS);
                    }
                }
            }
        }
    }

    WORD major = 0, minor = 0, point1 = 0, point2 = 0;
};

Looks like name should have been filename but anyways, VerQueryValue's fourth parameter is of type PUINT and not DWORD*.

Try this - works fine for me:

struct WindowsVersion
{
    WindowsVersion()
    {
        auto filename = _T ("kernel32.dll");
        DWORD handle = 0;

        if (auto size = GetFileVersionInfoSize (filename, &handle))
        {
            HeapBlock<char> data (size);

            if (GetFileVersionInfo (filename, handle, size, data) != FALSE)
            {
                VS_FIXEDFILEINFO* info = nullptr;
                UINT length = 0;

                if (VerQueryValue (data, (LPCTSTR) _T ("\\"), (void**) &info, &length) != FALSE)
                {
                    if (length > 0 && info != nullptr && info->dwSignature == 0xfeef04bd)
                    {
                        major = HIWORD (info->dwFileVersionMS);
                        minor = LOWORD (info->dwFileVersionMS);
                        point1 = HIWORD (info->dwFileVersionLS);
                        point2 = LOWORD (info->dwFileVersionLS);
                    }
                }
            }
        }
    }

    WORD major = 0, minor = 0, point1 = 0, point2 = 0;
};

It’s OK - I actually already implemented this on develop (slightly differently)

Oh my… This keep rearing its head. This function still returns incorrectly when called from an AAX plugin! Any ideas?

Guessing ProTools must deliberately load a different version of kernel32.dll, or something

FWIW I’m using this now which appears to work:

#include <lmerr.h>
#include <lm.h>

#pragma comment(lib, "netapi32.lib")

static bool GetWindowsVersion(DWORD& major, DWORD& minor)
{
    LPBYTE pinfoRawData;
    if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData))
    {
        WKSTA_INFO_100 * pworkstationInfo = (WKSTA_INFO_100 *)pinfoRawData;
        major = pworkstationInfo->wki100_ver_major;
        minor = pworkstationInfo->wki100_ver_minor;
        ::NetApiBufferFree(pinfoRawData);
        return true;
    }
    return false;
}

static bool isWindows10OrGreater()
{
    DWORD major, minor;

    if (GetWindowsVersion(major, minor))
        return major >= 10;

    return false;
}

Anyone see any issue with that on Windows 7+ ?

Here’s a different approach I’ve used on Windows 10 to find out the build number:

auto getWindowsVersionInfo = []
{
    RTL_OSVERSIONINFOW versionInfo = { 0 };

    if (auto* mod = ::GetModuleHandleW (L"ntdll.dll"))
    {
        using RtlGetVersion = LONG (WINAPI*)(PRTL_OSVERSIONINFOW);

        if (auto* rtlGetVersion = (RtlGetVersion) ::GetProcAddress (mod, "RtlGetVersion"))
        {
            versionInfo.dwOSVersionInfoSize = sizeof (versionInfo);
            constexpr LONG STATUS_SUCCESS = 0;

            if (rtlGetVersion (&versionInfo) != STATUS_SUCCESS)
                versionInfo = { 0 };
        }
    }

    return versionInfo;
};

auto versionInfo = getWindowsVersionInfo();
DBG (versionInfo.dwMajorVersion);   // 10
DBG (versionInfo.dwMinorVersion);   // 0
DBG (versionInfo.dwBuildNumber);    // 17763

but like Martin I’ve not yet investigated if this will work on Windows 7.

2 Likes

Thanks Tom

Actually, my thinking in terms of not using GetModuleHandleW() or JUCE’s own DLL loading stuff (etc) is that my plugin will just fail to load if the dll is missing. Which in some ways is preferable to silently returning the wrong result in my case

Do you mean if the ntdll.dll is missing?

Well my example was using netapi32, but I get your point!