From ec2e8d298d469128b53053a007b0b3b1c51af2ec Mon Sep 17 00:00:00 2001
From: Gilles Khouzam <gillesk@microsoft.com>
Date: Thu, 10 Sep 2015 13:53:00 -0700
Subject: [PATCH] [CMake 0015674]: Windows: Correctly determine Windows version
 for CMAKE_HOST_SYSTEM_VERSION

Fixing version support on Windows 8 and above.
Adding support for manifest files on Windows.
Adding a manifest to enable proper version querying on Windows for CMake
executables.
Adding support for new versions of Windows in
GetOperatingSystemNameAndVersion.
Fixing potential buffer overrun calling GetVersionEx and mixing a Wide
call with an ASCII datastructure.
---
 Source/CMakeLists.txt                      | 13 ++++--
 Source/QtDialog/CMakeLists.txt             |  2 +-
 Source/cmGeneratorTarget.cxx               | 14 +++++++
 Source/cmGeneratorTarget.h                 |  2 +
 Source/cmGlobalGenerator.cxx               | 60 ++++++----------------------
 Source/cmVisualStudio10TargetGenerator.cxx | 33 +++++++++++++++
 Source/cmVisualStudio10TargetGenerator.h   |  1 +
 Source/cmake.version.manifest              | 18 +++++++++
 Source/kwsys/SystemTools.cxx               | 64 +++++++++++++++++++++++-------
 9 files changed, 140 insertions(+), 67 deletions(-)
 create mode 100644 Source/cmake.version.manifest

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 16b9ea1..f909bdd 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -502,6 +502,11 @@ if (WIN32)
       cmGhsMultiGpj.cxx
       cmGhsMultiGpj.h
       )
+
+    # Add a manifest file to executables on Windows to allow for GetVersion
+    # to work properly on Windows 8 and above
+    set(MANIFEST_FILE cmake.version.manifest)
+
   endif()
 endif ()
 
@@ -531,7 +536,7 @@ set(SRCS ${SRCS}
 
 if(WIN32 AND NOT CYGWIN)
   set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
-  add_executable(cmcldeps cmcldeps.cxx)
+  add_executable(cmcldeps cmcldeps.cxx ${MANIFEST_FILE})
   target_link_libraries(cmcldeps CMakeLib)
   install(TARGETS cmcldeps DESTINATION bin)
 endif()
@@ -720,15 +725,15 @@ if(APPLE)
 endif()
 
 # Build CMake executable
-add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h)
+add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
 target_link_libraries(cmake CMakeLib)
 
 # Build CTest executable
-add_executable(ctest ctest.cxx)
+add_executable(ctest ctest.cxx ${MANIFEST_FILE})
 target_link_libraries(ctest CTestLib)
 
 # Build CPack executable
-add_executable(cpack CPack/cpack.cxx)
+add_executable(cpack CPack/cpack.cxx ${MANIFEST_FILE})
 target_link_libraries(cpack CPackLib)
 
 # Curses GUI
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index ad6a7fb..5fb4431 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -155,7 +155,7 @@ endif()
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
-add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS})
+add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS} ${MANIFEST_FILE})
 target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${CMake_QT_LIBRARIES})
 if(Qt_BIN_DIR)
   set_property(TARGET cmake-gui PROPERTY Qt_BIN_DIR ${Qt_BIN_DIR})
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 09387b7..fb5805b 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -75,6 +75,7 @@ struct IDLSourcesTag {};
 struct ResxTag {};
 struct ModuleDefinitionFileTag {};
 struct AppManifestTag{};
+struct ManifestsTag{};
 struct CertificatesTag{};
 struct XamlTag{};
 
@@ -216,6 +217,10 @@ struct TagVisitor
       {
       DoAccept<IsSameTag<Tag, AppManifestTag>::Result>::Do(this->Data, sf);
       }
+    else if (ext == "manifest")
+      {
+      DoAccept<IsSameTag<Tag, ManifestsTag>::Result>::Do(this->Data, sf);
+      }
     else if (ext == "pfx")
       {
       DoAccept<IsSameTag<Tag, CertificatesTag>::Result>::Do(this->Data, sf);
@@ -626,6 +631,15 @@ cmGeneratorTarget
 //----------------------------------------------------------------------------
 void
 cmGeneratorTarget
+::GetManifests(std::vector<cmSourceFile const*>& data,
+               const std::string& config) const
+{
+  IMPLEMENT_VISIT(Manifests);
+}
+
+//----------------------------------------------------------------------------
+void
+cmGeneratorTarget
 ::GetCertificates(std::vector<cmSourceFile const*>& data,
                   const std::string& config) const
 {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 06d9a1f..916f281 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -71,6 +71,8 @@ public:
                               const std::string& config) const;
   void GetAppManifest(std::vector<cmSourceFile const*>&,
                       const std::string& config) const;
+  void GetManifests(std::vector<cmSourceFile const*>&,
+                    const std::string& config) const;
   void GetCertificates(std::vector<cmSourceFile const*>&,
                        const std::string& config) const;
   void GetXamlSources(std::vector<cmSourceFile const*>&,
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 49f3b29..e300cb9 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -10,24 +10,10 @@
   See the License for more information.
 ============================================================================*/
 #if defined(_WIN32) && !defined(__CYGWIN__)
-#include "windows.h" // this must be first to define GetCurrentDirectory
-#if defined(_MSC_VER) && _MSC_VER >= 1800
-# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-#endif
-typedef struct {
-  ULONG  dwOSVersionInfoSize;
-  ULONG  dwMajorVersion;
-  ULONG  dwMinorVersion;
-  ULONG  dwBuildNumber;
-  ULONG  dwPlatformId;
-  WCHAR  szCSDVersion[128];
-  USHORT wServicePackMajor;
-  USHORT wServicePackMinor;
-  USHORT wSuiteMask;
-  UCHAR  wProductType;
-  UCHAR  wReserved;
-} CMRTL_OSVERSIONINFOEXW;
-
+# include "windows.h" // this must be first to define GetCurrentDirectory
+# if defined(_MSC_VER) && _MSC_VER >= 1800
+#  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
+# endif
 #endif
 
 #include "cmGlobalGenerator.h"
@@ -446,45 +432,25 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
   if (!mf->GetDefinition("CMAKE_SYSTEM"))
     {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-    CMRTL_OSVERSIONINFOEXW osviex;
+    OSVERSIONINFOEX osviex;
     ZeroMemory(&osviex, sizeof(osviex));
     osviex.dwOSVersionInfoSize = sizeof(osviex);
 
-    typedef LONG (FAR WINAPI *cmRtlGetVersion)(CMRTL_OSVERSIONINFOEXW*);
-    cmRtlGetVersion rtlGetVersion = reinterpret_cast<cmRtlGetVersion>(
-      GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion"));
-    if (rtlGetVersion && rtlGetVersion(&osviex) == 0)
-      {
-      std::ostringstream windowsVersionString;
-      windowsVersionString << osviex.dwMajorVersion << "."
-                           << osviex.dwMinorVersion << "."
-                           << osviex.dwBuildNumber;
-      windowsVersionString.str();
-      mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
-                        windowsVersionString.str().c_str());
-      }
-    else
-      {
-      // RtlGetVersion failed, so use the deprecated GetVersionEx function.
-      /* Windows version number data.  */
-      OSVERSIONINFO osvi;
-      ZeroMemory(&osvi, sizeof(osvi));
-      osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 # pragma warning (push)
 # pragma warning (disable:4996)
 #endif
-      GetVersionEx (&osvi);
+    GetVersionEx((OSVERSIONINFO*)&osviex);
 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 # pragma warning (pop)
 #endif
-      std::ostringstream windowsVersionString;
-      windowsVersionString << osvi.dwMajorVersion << "."
-                           << osvi.dwMinorVersion;
-      windowsVersionString.str();
-      mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
-                        windowsVersionString.str().c_str());
-      }
+    std::ostringstream windowsVersionString;
+    windowsVersionString << osviex.dwMajorVersion << "."
+                         << osviex.dwMinorVersion << "."
+                         << osviex.dwBuildNumber;
+    windowsVersionString.str();
+    mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
+                      windowsVersionString.str().c_str());
 #endif
     // Read the DetermineSystem file
     std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 4c380f7..4c39238 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2203,6 +2203,37 @@ cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config)
     }
 }
 
+void cmVisualStudio10TargetGenerator::WriteManifestOptions(
+  std::string const& config)
+{
+  if(this->Target->GetType() == cmTarget::EXECUTABLE ||
+     this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
+     this->Target->GetType() == cmTarget::MODULE_LIBRARY)
+    {
+    bool wroteTag = false;
+    std::vector<cmSourceFile const*> manifests;
+    this->GeneratorTarget->GetManifests(manifests, "");
+    for(std::vector<cmSourceFile const*>::const_iterator si =
+        manifests.begin(); si != manifests.end(); ++si)
+      {
+      std::string manifest = this->ConvertPath((*si)->GetFullPath(), false);
+      this->ConvertToWindowsSlash(manifest);
+      if(!wroteTag)
+        {
+        wroteTag = true;
+        this->WriteString("<Manifest>\n", 2);
+        this->WriteString("<AdditionalManifestFiles>", 3);
+        }
+      (*this->BuildFileStream) << manifest << ";";
+      }
+    if(wroteTag)
+      {
+      (*this->BuildFileStream) << "</AdditionalManifestFiles>\n";
+      this->WriteString("</Manifest>\n", 2);
+      }
+    }
+}
+
 
 //----------------------------------------------------------------------------
 void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
@@ -2740,6 +2771,8 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
     this->WriteLinkOptions(*i);
     //    output lib flags       <Lib></Lib>
     this->WriteLibOptions(*i);
+    //    output manifest flags  <Manifest></Manifest>
+    this->WriteManifestOptions(*i);
     if(this->NsightTegra &&
        this->Target->GetType() == cmTarget::EXECUTABLE &&
        this->Target->GetPropertyAsBool("ANDROID_GUI"))
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 451f8b2..5fadb60 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -111,6 +111,7 @@ private:
   void AddLibraries(cmComputeLinkInformation& cli,
                     std::vector<std::string>& libVec);
   void WriteLibOptions(std::string const& config);
+  void WriteManifestOptions(std::string const& config);
   void WriteEvents(std::string const& configName);
   void WriteEvent(const char* name,
                   std::vector<cmCustomCommand> const& commands,
diff --git a/Source/cmake.version.manifest b/Source/cmake.version.manifest
new file mode 100644
index 0000000..e7010c9
--- /dev/null
+++ b/Source/cmake.version.manifest
@@ -0,0 +1,18 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+          manifestVersion="1.0"
+		  xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+   <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>
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 97a1df8..6d6f6a0 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -4879,9 +4879,6 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
   OSVERSIONINFOEXA osvi;
   BOOL bOsVersionInfoEx;
 
-  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
-  // If that fails, try using the OSVERSIONINFO structure.
-
   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXA));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
 
@@ -4893,14 +4890,10 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
 #  pragma warning (disable:4996)
 # endif
 #endif
-  bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *)&osvi);
+  bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA *)&osvi);
   if (!bOsVersionInfoEx)
     {
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-    if (!GetVersionEx((OSVERSIONINFO *)&osvi))
-      {
-      return 0;
-      }
+    return 0;
     }
 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 # pragma warning (pop)
@@ -4913,10 +4906,56 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
     case VER_PLATFORM_WIN32_NT:
 
       // Test for the specific product family.
+      if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0)
+      {
+        if (osvi.wProductType == VER_NT_WORKSTATION)
+        {
+          res += "Microsoft Windows 10";
+        }
+        else
+        {
+          res += "Microsoft Windows Server 2016 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3)
+      {
+        if (osvi.wProductType == VER_NT_WORKSTATION)
+        {
+          res += "Microsoft Windows 8.1";
+        }
+        else
+        {
+          res += "Microsoft Windows Server 2012 R2 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2)
+      {
+        if (osvi.wProductType == VER_NT_WORKSTATION)
+        {
+          res += "Microsoft Windows 8";
+        }
+        else
+        {
+          res += "Microsoft Windows Server 2012 family";
+        }
+      }
+
+      if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
+      {
+        if (osvi.wProductType == VER_NT_WORKSTATION)
+        {
+          res += "Microsoft Windows 7";
+        }
+        else
+        {
+          res += "Microsoft Windows Server 2008 R2 family";
+        }
+      }
 
       if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
         {
-#if (_MSC_VER >= 1300)
         if (osvi.wProductType == VER_NT_WORKSTATION)
           {
           res += "Microsoft Windows Vista";
@@ -4925,9 +4964,6 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
           {
           res += "Microsoft Windows Server 2008 family";
           }
-#else
-        res += "Microsoft Windows Vista or Windows Server 2008";
-#endif
         }
 
       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
@@ -4956,7 +4992,6 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
         {
         // Test for the workstation type.
 
-#if (_MSC_VER >= 1300)
         if (osvi.wProductType == VER_NT_WORKSTATION)
           {
           if (osvi.dwMajorVersion == 4)
@@ -5028,7 +5063,6 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
               }
             }
           }
-#endif // Visual Studio 7 and up
         }
 
       // Test for specific product on Windows NT 4.0 SP5 and earlier
-- 
2.5.1.windows.1

