BUG: SystemStats::getOperatingSystemName() on Windows 10


#1

It will return Windows 8.0 but my OS is Windows 10…


#2

It’s not a bug, if an application hasn’t implemented certain things then is will return windows 8 even on windows 10, if you’re developing a plugin you are at the mercy of the host in this situation.

If you want something more accurate doing the following will normally work pretty well (could be improved)

String getOSName()
{
   #if JUCE_WINDOWS
    const String processStr = "C:\\Windows\\system32\\cmd.exe /c ver";
    const String name = getProcessStdOutput(processStr);

    if (name.isNotEmpty())
        return name;
   #elif JUCE_MAC
    String name = getProcessStdOutput("sw_vers -productName");
    if (name.isNotEmpty())
    {
        String version = getProcessStdOutput("sw_vers -productVersion");
        if (version.isNotEmpty())
        {
            String build = getProcessStdOutput("sw_vers -buildVersion");

            if (build.isNotEmpty())
                return name + " " + version + " (" + build + ")";
        }
    }
   #endif

    return SystemStats::getOperatingSystemName();
}

#3

If you don’t specify in your app manifest that your app supports Windows 8.1 and 10 then the Windows version number verification methods will just report Windows 8. Here is the msdn page on what you need to add to the manifest.


#4

Thanks, Anthony_Nicholls, ed95.

I still dont understand why the method doesn’t match its name…May be it should add more comments?


#5

Well it’s a bug alright. I mean if you are using this method to find out which system your users are working on this does not give you the right result. So maybe the method should be renamed or at least explained that it is unreliable.

The method says:
/** Returns the name of the type of operating system we’re running on.

        @returns a string describing the OS type.
        @see getOperatingSystemType
    */
    static String getOperatingSystemName();

And that’s just not what it does.


#6

Maybe it’s better to just make sure features like this are unavailable on platforms where the result is going to be unreliable.
The same is for example true for File::getVolumeSerialNumber(), on OSX this will always return 0.
Of course you could check for the 0, but why offer the feature if it doesn’t actually work?


#7

No, it isn’t!

Like Ed said, this is a deliberate behaviour that Microsoft added - they WANT the application to get a fake version unless you specifically mark your app as being compatible with Windows 10.

Our function does its job correctly as far as reporting the information that the OS gives it. If you set up your manifest correctly, then it’ll do what you want.


#8

Another option is to warn the user with a jassert like you do in TypeFace::scanFolderForFonts for example.

void Typeface::scanFolderForFonts (const File&)
{
    jassertfalse; // not implemented on this platform
}

#9

So either JUCE is not meant to be compatible with Windows 10, or that’s a bug in the projucer.

You can add that manifest yourself, as Ed pointed out, but those changes will be overwritten every time you save your projucer project.


#10

Projucer needs an option for the exporter to define an additional Manifest file:


#11

Hmm. Yes, it looks pretty messy to tell VS that you want Windows 10 compatibility… Do they really expect everyone to write a custom manifest for that, or is there a setting hidden in there somewhere that’ll set the flag?


#12

In my special case ( a plugin installer ), i need this manifest to prevent Windows 10 to give a warning after starting the application after it was downloaded.

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
    <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
    <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
    <!--The ID below indicates application support for Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
    <!--The ID below indicates application support for Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
    <!--The ID below indicates application support for Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
  </application>
</compatibility>
</assembly>

By the way it would be cool, if you also add a setting for requiring admin rights.
This is important for custom plugin installers

Currently i use this linker flag, but i think it could be also integrated in the manifest

/MANIFESTUAC:level='requireAdministrator'


#13

Even once you fix this for applications it doesn’t fix the issue for plugins as you’re at the mercy of the Host which may or may not have added Windows 10 support.


#14

anyway, i need this option for a custom manifest, currently this settings will be overriden after resaving it with projucer


#15

I’ve just added the ability to specify a custom manifest file in the Projucer - see the develop branch #c254578.


#16

Just testing this, seems like VS2012 exporters will not open anymore? I get a lot off asserts, but no official warning from Projucer? Shouldn’t at least the exporter be automatically converted to a supported VS version?


#17

Good point. The Projucer should at least warn you when you open a project with exporters earlier than 2013. We’ll fix this.


#18

There is a simple way to get the correct version-number, regardless of hosting situation etc.

You simply get the version-information from the kernel32.dll

I’ve implemented that for Nexus2 a while ago and it works perfectly. When Windows 10 came out, we didn’t have to change a thing for the version-detection.

If there is any interest, I can post the code here for inclusion in JUCE.


#19

I know it’s not pretty and pretty old-school (was written some time ago), but it works:

static void getVersionFromFile (char *out, const char *filename)
{
	strcpy(out, "unknown");

	DWORD  verHandle = NULL;
	UINT   size = 0;
	LPBYTE lpBuffer = NULL;
	DWORD  verSize = GetFileVersionInfoSize(filename, &verHandle);

	if (verSize != NULL)
	{
		LPSTR verData = (LPSTR)malloc(verSize);
		if (verData)
		{
			if (GetFileVersionInfo(filename, verHandle, verSize, verData))
			{
				if (VerQueryValue(verData, "\\", (VOID FAR* FAR*)&lpBuffer, &size))
				{
					if (size)
					{
						VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
						if (verInfo->dwSignature == 0xfeef04bd)
						{
							if (!verInfo->dwFileVersionLS)
							{
								sprintf(out, "%d.%d",
									(verInfo->dwFileVersionMS >> 16) & 0xffff,
									verInfo->dwFileVersionMS & 0xffff
								);
							}
							else if (!(verInfo->dwFileVersionLS & 0xffff))
							{
								sprintf(out, "%d.%d.%d",
									(verInfo->dwFileVersionMS >> 16) & 0xffff,
									verInfo->dwFileVersionMS & 0xffff,
									(verInfo->dwFileVersionLS >> 16) & 0xffff
								);
							}
							else
							{
								sprintf(out, "%d.%d.%d.%d",
									(verInfo->dwFileVersionMS >> 16) & 0xffff,
									verInfo->dwFileVersionMS & 0xffff,
									(verInfo->dwFileVersionLS >> 16) & 0xffff,
									verInfo->dwFileVersionLS & 0xffff
								);
							}
						}
					}
				}
			}
			free(verData);
		}
	}
}

On my computer this returns 10.0.15063.296 for the Windows version (creators update is installed).


#20

We already have a function File::getVersion() which should do the same thing as all that code. Does that work?

But I can’t help thinking there could be permissions issues in accessing the windows system folder under some user accounts…?