php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69642 Windows 10 reported as Windows 8 in phpinfo()
Submitted: 2015-05-15 20:25 UTC Modified: 2015-06-08 15:50 UTC
From: wenz@php.net Assigned: ab (profile)
Status: Closed Package: PHP options/info functions
PHP Version: master-Git-2015-05-15 (Git) OS: Windows 10
Private report: No CVE-ID: None
 [2015-05-15 20:25 UTC] wenz@php.net
Description:
------------
The phpinfo() output on Windows 8.1 and Windows Server 2012 R2 reports the OS as Windows 8 and Windows Server 2012.

This is due to the deprecation of GetVersionEx (which we are using) on these platforms - http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074%28v=vs.85%29.aspx

Once we compile the Windows builds with the Visual Studio 2013 compiler and the Windows 8.1 (or higher) SDK, _NT_TARGET_VERSION=$(_NT_TARGET_VERSION_LATEST) seems to help. Alternatively, we could use a manifest file, see https://msdn.microsoft.com/en-us/library/windows/desktop/dn481241%28v=vs.85%29.aspx. This would require a change to the build scripts, though. Until we actually do this, we need a different approach. 

VerifyVersionInfo (http://msdn.microsoft.com/en-us/library/windows/desktop/ms725491%28v=vs.85%29.aspx) looked like the best solution when I tackled a related but for Windows 8.1 (#67407). However despite Microsoft originally introducing that function to have an alternative to GetVersionEx, it looks like this function is deprecated already, see the note at http://blogs.msdn.com/b/chuckw/archive/2014/10/03/windows-10-technical-preview.aspx. The first technology preview of Windows 10 reported itself as version 6.4, since the second technology preview Windows 10 identifies itself as 10.0, yet VerifyVersionInfo reports 6.2 here. Thus, even the isWindows10OrGreater() function from the Windows 10 SDK (which uses VerifyVersionInf) does not identify Windows 10 correctly if there is no manifest! Incredible ... 

Microsoft provides a tiny hint at https://msdn.microsoft.com/en-us/library/windows/desktop/ms724429%28v=vs.85%29.aspx though: "To obtain the full version number for the operating system, call the GetFileVersionInfo function on one of the system DLLs, such as Kernel32.dll, then call VerQueryValue to obtain the \\StringFileInfo\\<lang><codepage>\\ProductVersion subblock of the file version information." I have tried to implement this to the best of my knowledge, but for some reason I cannot use the GetFileVersionInfoSize() function from version.dll. I hope someone with more C experience than I have could look at the attached diff. I hope that only a little bit is missing ... I have changed to code so that once the GetFileVersionInfo approach works, it is used for both Windows 8.1 and Windows 10, making the VerifyVersionInfo call obsolete.

Note: at some point, we should tackle this at a greater scale. I have also thought about using WMI, but this seems to be overkill. Maybe using a Manifest would be the most feasible option eventually.

I am aware that the final version of Windows 10 has not been released yet. However I guess that PHP 7 will be released close to the release of Windows 10, and it would not look good if our shiny new version could not detect the new OS version number, so I would like to get that resolved rather sooner than later. 

Please let me know if I can be of any assistance with testing etc.!



Test script:
---------------
<?php
  phpinfo(INFO_GENERAL);


Expected result:
----------------
Output contains "Windows 10" on a Windows 10 machine.


Actual result:
--------------
Output contains "Windows 8" (and not 10) on a Windows 10 machine.


Patches

detect-windows-10-not-working-yet (last revision 2015-05-15 20:25 UTC) by wenz)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-05-15 20:25 UTC] wenz@php.net
-Assigned To: +Assigned To: ab
 [2015-05-16 19:57 UTC] ab@php.net
Yeah, I was checking this stuff 1-2 months ago, and the versions delivered was valid win8 only on win10. So i thought as it's just a preview, it might get better later. So thanks for the patch. Would this work also on downlevel (mainly win7 and win8)? Need to test that before, otherwise we could mix the old and new method.

Could you please rewrite the patch so it does early returns instead of those nested ifs? That would improve the code readability a lot. And, how about backporting to PHP5? Whereby i can take it over once it's in master.

Thanks.
 [2015-05-16 22:10 UTC] wenz@php.net
Since Technical Preview 2 of Windows 10, the version number is (supposedly - with Microsoft you never know ;-) ) consistently 10.0. 

As I wrote the issue with the patch is that it does not work - I somehow cannot use the functions from version.dll (that's why I have all the if statements). So this needs to be fixed first before we rearrange the code. I do hope it's a small thing, but except from PHP patches my C coding ended 15 years ago, so I was hoping someone could take a look. 

If the "get functionality from version.dll" stuff eventually works, it should cover Windows 8.1, Windows Server 2012 R2, Windows 10 and also the upcoming Windows Server 2016. Windows 8 and 7 are already covered by the old API, I did not change that part of the code.

Sorry I am not of more help, but there is anything I can do, please let me know!
 [2015-05-20 19:42 UTC] ab@php.net
-Status: Assigned +Status: Feedback
 [2015-05-20 19:42 UTC] ab@php.net
I was a bit rambling around on this matter and tripped over this blog http://blogs.msdn.com/b/chuckw/archive/2013/09/10/manifest-madness.aspx . Theoretically, we could try to create manifests. The current makefile is already prepared for that, it there's a file with a suffix .manifest, it'll be taken automatically. Say, having x64\Release_TS\php7ts.dll, a file x64\Release_TS\php7ts.dll.manifest would be picked up automatically if exists. I've tried this  but it was still delivering 6.2 under win8.1. Notsure, maybe you'll have more luck :) But we should check this carefully, not that it'd need some digital signatures or alike, that were bad.

Another resource - to the possibility of reading file versions. A worky example can be found here https://support.microsoft.com/en-us/kb/167597/ . With that, I saw outputs like 10,0,10074,0 on kernel32.dll and user32.dll under win10, and like 6,3,9600,17415 under win8.1. Though this way isn't recommended officially, maybe we could take it as a very last fallback solution, if nothing else works. At least you could check whether you see the same as described.

The function IsWindows10OrGreater() didn't want even to link for me, quite strange.

But anyway you're right, we'd better to fix this as early as possible. Possibly also for PHP5.

Thanks.
 [2015-05-27 12:30 UTC] ab@php.net
@wenz, ping, were you able to verify the snippets to read file versions?

Thanks.
 [2015-05-27 12:47 UTC] wenz@php.net
Sorry for the late reply. I did try the manifest approach, but did not get any change in behavior. Maybe there is a way to embed the manifest in the executable, but I did not succeed in doing so. 
The file version approach sounds good. I am trying a similar approach in my (non-functional) patch, but the link you posted looks very promising. Will probably try that tomorrow.
 [2015-05-27 18:30 UTC] wenz@php.net
took a closer look at it. Actually my non-working patch uses a very similar approach. I fail at using the GetFileVersionInfoSize and GetFileVersionInfo functions from version.dll - getting NULL back (see the patch). Is there something obvious I am missing?
 [2015-05-27 18:41 UTC] ab@php.net
Please check this https://gist.github.com/weltling/bc99faed4f09d615b7a7 . This works with vc9 to vc14. But I'm completely not sure we should use it, it adds one more dll dependency. Heh ... i'd still prefer to dig further for manifests.

Thanks.
 [2015-05-27 19:01 UTC] wenz@php.net
yeah, standalone it works, but (as far as I understand it) the GetVersionInfoSize and GetVersionInfo functions are only available if I pull them out of version.dll using GetProcAddress(), and that's what somehow doesn't work in my patch. Or I am missing something trivial, which might very well be possible with my rusty C.
 [2015-05-27 20:14 UTC] ab@php.net
Thanks for checking anyway. I'm going to continue investigating on the manifest stuff, if that didn't worked - will probably go your way integrating the file version reading.

Thanks.
 [2015-05-27 23:18 UTC] ab@php.net
Pah, I've managed a simple snippet now to work with manifest. Look:

================= getversionex.c =================
#include <windows.h>
#include <stdio.h>

void main()
{
    OSVERSIONINFO osvi;
    BOOL bIsWindowsXPorLater;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    GetVersionEx(&osvi);

    bIsWindowsXPorLater = 
       ( (osvi.dwMajorVersion > 5) ||
       ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));

	printf("major=%d minor=%d\n", osvi.dwMajorVersion, osvi.dwMinorVersion);

}
================= getversionex.c =================

==================== my.manifest ========================
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True/PM</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
       <application> 
           <!-- Windows Vista -->
           <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> 
           <!-- Windows 7 -->
           <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
           <!-- Windows 8 -->
           <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
           <!-- Windows 8.1 -->
           <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
           <!-- Windows 10 -->
           <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
       </application> 
   </compatibility>
</assembly>
==================== my.manifest ========================

Then the following commands:

cl getversionex.c
mt -manifest my.manifest -outputresource:getversionex.exe;1

And, we already have a mechanism in the makefile to run the latter command. So what i do think now - we should dig into this, probably use the default manifest if an extension/sapi doesn't supply one. I also haven't checked how it behaves when say it's a dll which is loaded in the exe without embedded manifest, should be checked yet.

But if it works, we should use GetVersionEx - it's available in all the Windows versions including win10. If it's disappeared somewhen - well, then it needs to be changed. It should be also better from the performance side. If GetVersionEx did disappear somewhen, so maybe also dont use a CRT which doesn't fully support the version helper stuff.

What do you think?

Thanks.
 [2015-05-28 23:36 UTC] ab@php.net
@wenz, ahoi :)

I came further with this subject. In short - for win10 a manifest is required. You can write it big. It's not like the previous change on win 8.1 where without manifest it would deliver 6.2 but one could trick it with an additional check. win10 would  always deliver 6.2 without manifest. even for the version helper API.

The changes are landed in master now. Please take a look at https://github.com/php/php-src/compare/0a173501c86a426f3387c3d7229420b721743dfc...7ab99ed4b0a4eeded1c684631a8a65bd9cd85bcd .

One note to this - manifests, even if embedded into some dll, it won't have any effect when the exe which loads them doesn't have manifest. This is really hard linked to the fact that "manifest is required for win10". It is not for win 8.1 because of the workaround we have. However now when the manifest is embedded, I get the orderly 6.3 on win 8.1, so how it should be. But with Apache builds which don't have it, it will be 6.2. So any exe which wants to read the version is required to have a proper manifest.

It would be great if you could test the current master branch. I've added yet basic conditions to recognize win10, so that should be shown as well. To test it with Apache, it's simple. Just run the mt command I mentioned in the previous post targeting your httpd.exe . Please use vc14 for your builds. If the test went clean, we will need to backport this into PHP5.

Besides that - the GetVersionEx is still available with win10. Despite deprecated, I don't see any reason to go for the version helpers. GetVersion, as it's still available, will serve for years. After that, only the holy "shoot me dead" can say what happens to that version API. You know what i mean :)
 
Thanks.
 [2015-05-30 20:09 UTC] ab@php.net
@wenz maybe you have time, you could at least test the bins in http://windows.php.net/downloads/snaps/ostc/69642/manifest_test.zip (just run test.bat and post here).

Thanks.
 [2015-05-30 21:19 UTC] wenz@php.net
gone all weekend ... will do so early next week!
 [2015-05-31 19:52 UTC] ab@php.net
Now it's ported into the PHP5 tree. Please start with it, maybe right with 5.5, when you come to it. I've added basic code to recognize win10 and server 2016, as well as to properly recognize the win 8.1 servrer 2012. 

Now you can also check with further product types. But please don't remove the workaround for 8.1, it's still important fe if mod_php is loaded under httpd.exe which has no proper manifest.

Thanks.
 [2015-06-03 09:57 UTC] wenz@php.net
I have now tested both the manifest test binaries you sent and manually built CLI versions for the 5.5, 5.6, and master branches on these systems (fresh OS installations in all cases):

- Windows 7 -> 6.1
- Windows 8 -> 6.2
- Windows 8.1 -> 6.3
- Windows Server 2012 R2 -> 6.3
- Windows 10 (Tech Preview 2, including the new update from the weekend) -> 10.0
- Windows Server 2016 (TP 2) -> 10.0

The only situation where the code failed was when I tried your binaries on 2012 R2 (application can not be used on your system) - I was using the 32bit edition though, so that may be the reason. The manually compiled versions did work as expected.

I am also +1 for keeping my clumpsy 8.1 workaround in, for the reasons you stated. 

The only thing I did notice was that a SKU was reported incorrectly, but I need to doublecheck with MSDN whether that is really true or if I am too confused by the many different names and versions. I'll create another bug report and patch once I come to that.

Thank you so much for getting this fixed! I still don't understand why my attempts to add a manifest all failed ... :-( I'll do some more tests with Apache installations (the way I understand it, httpd.exe needs a manifest there), and if that's the case I'lltry to talk to the XAMPP people to maybe add this to their distribution, since I guess they are reponsible for a great chunk of WAMP-Installations.
 [2015-06-05 16:14 UTC] ab@php.net
-Status: Feedback +Status: Closed
 [2015-06-05 16:14 UTC] ab@php.net
@wenz, thanks for such the extensive testing. Yeah, the bins produced by me was 64-bit, they couldn't run on x86. This bug seems to be fixed so far.

For PHP 5.5 it was the last chance as it's in security mode very soon. If you think you can catch up with finer recognition of the product types, that could be good. Otherwise, it's already something usable given win10 is even not released yet. Once you've some more info and time, so yep, you can do it in another ticket using some better info.

Thanks.
 [2015-06-08 15:01 UTC] wenz@php.net
I have now had a deeper look at it. There are two reasons for the incorrect SKU detection that happens under certain circumstances:

1) Microsoft changed the behavior of the GetProductInfo API (AARGH!) which returns "Business" on the Professional versions of Windows 7, 8, and 8.1.
2) Some SKUs are missing from our list in winver.h. A specific instance is probably the one reported in Bug #55319

I have written a patch for 1) since quite a number of users is affected and it would be nice to get this into the final 5.5 update, if possible. I'll do some testing on Vista (where the API still has its old behavior) tonight and then provide the patches or PRs tomorrow. I have also started working on #2, adding almost 70 additional SKUs to winver.h, but will need to update info.c and update the appropriate SKU names there (and then will need to test this in some of the SKUs). This will take some time, so that's why I am doing 1) first. Will reference the bug reports here once I am done.
 [2015-06-08 15:50 UTC] ab@php.net
Ok, this sounds like a plan. The 5.5 branch will be allowed to accept your patch till June 20th. Otherwise just ping again with PRs and I'll merge them.

From the other hand, seeing all the "product lists", I was asking myself whether it really needs to be of that detail grade. As for me, just telling user "it's win 7, 8, 8.1, etc." (or the same for server) were enough and wouldn't require us to put so much energy into such thing. 

Thanks.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC