From 867de7fc670ffd67c9cb8dcffae42f87de7023ed Mon Sep 17 00:00:00 2001
From: David Cole <david.cole@kitware.com>
Date: Fri, 16 Nov 2007 07:01:58 -0500
Subject: [PATCH] ENH: Add ability to call Visual Studio macros from CMake. Add
 a CMake Visual Studio macro to reload a solution file automatically if CMake
 makes changes to .sln files or .vcproj files. Add code to call the macro
 automatically for any running Visual Studio instances with the .sln file open
 at the end of the Visual Studio Generate call. Only call the macro if some
 .sln or .vcproj file changed during Generate. Also, add handling for
 REG_EXPAND_SZ type to SystemTools::ReadRegistryValue - returned string has
 environment variable references expanded.

---
 Source/CMakeLists.txt                     |   5 +
 Source/cmCallVisualStudioMacro.cxx        | 464 ++++++++++++++++++++++
 Source/cmCallVisualStudioMacro.h          |  49 +++
 Source/cmGeneratedFileStream.cxx          |  14 +-
 Source/cmGeneratedFileStream.h            |   4 +-
 Source/cmGlobalGenerator.cxx              |  18 +
 Source/cmGlobalGenerator.h                |   8 +
 Source/cmGlobalVisualStudio7Generator.cxx |  17 +-
 Source/cmGlobalVisualStudio8Generator.cxx |  28 ++
 Source/cmGlobalVisualStudio8Generator.h   |   8 +
 Source/cmGlobalVisualStudio9Generator.cxx |  27 ++
 Source/cmGlobalVisualStudio9Generator.h   |   7 +
 Source/cmGlobalVisualStudioGenerator.cxx  | 355 +++++++++++++++++
 Source/cmGlobalVisualStudioGenerator.h    |  20 +
 Source/cmLocalVisualStudio7Generator.cxx  |   4 +
 Source/cmake.cxx                          |  29 ++
 Source/kwsys/SystemTools.cxx              |  22 +-
 Templates/CMakeVSMacros1.vsmacros         | Bin 0 -> 88064 bytes
 18 files changed, 1064 insertions(+), 15 deletions(-)
 create mode 100644 Source/cmCallVisualStudioMacro.cxx
 create mode 100644 Source/cmCallVisualStudioMacro.h
 create mode 100644 Templates/CMakeVSMacros1.vsmacros

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 86c4579883..d4ec11aca0 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -208,6 +208,11 @@ ENDIF(APPLE)
 
 
 IF (WIN32)
+  SET(SRCS ${SRCS}
+    cmCallVisualStudioMacro.cxx
+    cmCallVisualStudioMacro.h
+    )
+
   IF(NOT UNIX)
     SET(SRCS ${SRCS}
       cmGlobalBorlandMakefileGenerator.cxx
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
new file mode 100644
index 0000000000..635e264a0e
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -0,0 +1,464 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#include "cmCallVisualStudioMacro.h"
+#include "cmSystemTools.h"
+
+
+#if defined(_MSC_VER)
+#define HAVE_COMDEF_H
+#endif
+
+
+#if defined(HAVE_COMDEF_H)
+
+
+#include <comdef.h>
+
+
+//----------------------------------------------------------------------------
+///! Use ReportHRESULT to make a cmSystemTools::Error after calling
+///! a COM method that may have failed.
+#define ReportHRESULT(hr, context) \
+  if (FAILED(hr)) \
+    { \
+    std::ostringstream oss; \
+    oss.flags(std::ios::hex); \
+    oss << context << " failed HRESULT, hr = 0x" << hr << std::endl; \
+    oss.flags(std::ios::dec); \
+    oss << __FILE__ << "(" << __LINE__ << ")"; \
+    cmSystemTools::Error(oss.str().c_str()); \
+    }
+
+
+//----------------------------------------------------------------------------
+///! Using the given instance of Visual Studio, call the named macro
+HRESULT InstanceCallMacro(
+  IDispatch* vsIDE,
+  const std::string& macro,
+  const std::string& args)
+{
+  HRESULT hr = E_POINTER;
+
+  _bstr_t macroName(macro.c_str());
+  _bstr_t macroArgs(args.c_str());
+
+  if (0 != vsIDE)
+    {
+    DISPID dispid = (DISPID) -1;
+    OLECHAR *name = L"ExecuteCommand";
+
+    hr = vsIDE->GetIDsOfNames(IID_NULL, &name, 1,
+           LOCALE_USER_DEFAULT, &dispid);
+    ReportHRESULT(hr, "GetIDsOfNames(ExecuteCommand)");
+
+    if (SUCCEEDED(hr))
+      {
+      VARIANTARG vargs[2];
+      DISPPARAMS params;
+      VARIANT result;
+      EXCEPINFO excep;
+      UINT arg = (UINT) -1;
+
+      // No VariantInit or VariantClear calls are necessary for
+      // these two vargs. They are both local _bstr_t variables
+      // that remain in scope for the duration of the Invoke call.
+      //
+      V_VT(&vargs[1]) = VT_BSTR;
+      V_BSTR(&vargs[1]) = macroName;
+      V_VT(&vargs[0]) = VT_BSTR;
+      V_BSTR(&vargs[0]) = macroArgs;
+
+      params.rgvarg = &vargs[0];
+      params.rgdispidNamedArgs = 0;
+      params.cArgs = sizeof(vargs)/sizeof(vargs[0]);
+      params.cNamedArgs = 0;
+
+      VariantInit(&result);
+
+      memset(&excep, 0, sizeof(excep));
+
+      hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+        DISPATCH_METHOD, &params, &result, &excep, &arg);
+      ReportHRESULT(hr, "Invoke(ExecuteCommand)");
+
+      VariantClear(&result);
+      }
+    }
+
+  return hr;
+}
+
+
+//----------------------------------------------------------------------------
+///! Get the Solution object from the IDE object
+HRESULT GetSolutionObject(
+  IDispatch* vsIDE,
+  IDispatchPtr& vsSolution)
+{
+  HRESULT hr = E_POINTER;
+
+  if (0 != vsIDE)
+    {
+    DISPID dispid = (DISPID) -1;
+    OLECHAR *name = L"Solution";
+
+    hr = vsIDE->GetIDsOfNames(IID_NULL, &name, 1,
+           LOCALE_USER_DEFAULT, &dispid);
+    ReportHRESULT(hr, "GetIDsOfNames(Solution)");
+
+    if (SUCCEEDED(hr))
+      {
+      DISPPARAMS params;
+      VARIANT result;
+      EXCEPINFO excep;
+      UINT arg = (UINT) -1;
+
+      params.rgvarg = 0;
+      params.rgdispidNamedArgs = 0;
+      params.cArgs = 0;
+      params.cNamedArgs = 0;
+
+      VariantInit(&result);
+
+      memset(&excep, 0, sizeof(excep));
+
+      hr = vsIDE->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+        DISPATCH_PROPERTYGET, &params, &result, &excep, &arg);
+      ReportHRESULT(hr, "Invoke(Solution)");
+
+      if (SUCCEEDED(hr))
+        {
+        vsSolution = V_DISPATCH(&result);
+        }
+
+      VariantClear(&result);
+      }
+    }
+
+  return hr;
+}
+
+
+//----------------------------------------------------------------------------
+///! Get the FullName property from the Solution object
+HRESULT GetSolutionFullName(
+  IDispatch* vsSolution,
+  std::string& fullName)
+{
+  HRESULT hr = E_POINTER;
+
+  if (0 != vsSolution)
+    {
+    DISPID dispid = (DISPID) -1;
+    OLECHAR *name = L"FullName";
+
+    hr = vsSolution->GetIDsOfNames(IID_NULL, &name, 1,
+           LOCALE_USER_DEFAULT, &dispid);
+    ReportHRESULT(hr, "GetIDsOfNames(FullName)");
+
+    if (SUCCEEDED(hr))
+      {
+      DISPPARAMS params;
+      VARIANT result;
+      EXCEPINFO excep;
+      UINT arg = (UINT) -1;
+
+      params.rgvarg = 0;
+      params.rgdispidNamedArgs = 0;
+      params.cArgs = 0;
+      params.cNamedArgs = 0;
+
+      VariantInit(&result);
+
+      memset(&excep, 0, sizeof(excep));
+
+      hr = vsSolution->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
+        DISPATCH_PROPERTYGET, &params, &result, &excep, &arg);
+      ReportHRESULT(hr, "Invoke(FullName)");
+
+      if (SUCCEEDED(hr))
+        {
+        fullName = (std::string) (_bstr_t) V_BSTR(&result);
+        }
+
+      VariantClear(&result);
+      }
+    }
+
+  return hr;
+}
+
+
+//----------------------------------------------------------------------------
+///! Get the FullName property from the Solution object, given the IDE object
+HRESULT GetIDESolutionFullName(
+  IDispatch* vsIDE,
+  std::string& fullName)
+{
+  IDispatchPtr vsSolution;
+  HRESULT hr = GetSolutionObject(vsIDE, vsSolution);
+  ReportHRESULT(hr, "GetSolutionObject");
+
+  if (SUCCEEDED(hr))
+    {
+    GetSolutionFullName(vsSolution, fullName);
+    ReportHRESULT(hr, "GetSolutionFullName");
+    }
+
+  return hr;
+}
+
+
+//----------------------------------------------------------------------------
+///! Get all running objects from the Windows running object table.
+///! Save them in a map by their display names.
+HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
+{
+  // mrot == Map of the Running Object Table
+
+  IRunningObjectTablePtr runningObjectTable;
+  IEnumMonikerPtr monikerEnumerator;
+  IMonikerPtr moniker;
+  ULONG numFetched = 0;
+
+  HRESULT hr = GetRunningObjectTable(0, &runningObjectTable);
+  ReportHRESULT(hr, "GetRunningObjectTable");
+
+  if(SUCCEEDED(hr))
+    {
+    hr = runningObjectTable->EnumRunning(&monikerEnumerator);
+    ReportHRESULT(hr, "EnumRunning");
+    }
+
+  if(SUCCEEDED(hr))
+    {
+    hr = monikerEnumerator->Reset();
+    ReportHRESULT(hr, "Reset");
+    }
+
+  if(SUCCEEDED(hr))
+    {
+    while (S_OK == monikerEnumerator->Next(1, &moniker, &numFetched))
+      {
+      std::string runningObjectName;
+      IUnknownPtr runningObjectVal;
+      IBindCtxPtr ctx;
+
+      hr = CreateBindCtx(0, &ctx);
+      ReportHRESULT(hr, "CreateBindCtx");
+
+      if(SUCCEEDED(hr))
+        {
+        LPOLESTR displayName = 0;
+        hr = moniker->GetDisplayName(ctx, 0, &displayName);
+        ReportHRESULT(hr, "GetDisplayName");
+        if (displayName)
+          {
+          runningObjectName = (std::string) (_bstr_t) displayName;
+          CoTaskMemFree(displayName);
+          }
+
+        hr = runningObjectTable->GetObject(moniker, &runningObjectVal);
+        ReportHRESULT(hr, "GetObject");
+        if(SUCCEEDED(hr))
+          {
+          mrot.insert(std::make_pair(runningObjectName, runningObjectVal));
+          }
+        }
+
+      numFetched = 0;
+      moniker = 0;
+      }
+    }
+
+  return hr;
+}
+
+
+//----------------------------------------------------------------------------
+///! Do the two file names refer to the same Visual Studio solution? Or are
+///! we perhaps looking for any and all solutions?
+bool FilesSameSolution(
+  const std::string& slnFile,
+  const std::string& slnName)
+{
+  if (slnFile == "ALL" || slnName == "ALL")
+    {
+    return true;
+    }
+
+  // Otherwise, make lowercase local copies, convert to Unix slashes, and
+  // see if the resulting strings are the same:
+  std::string s1 = cmSystemTools::LowerCase(slnFile);
+  std::string s2 = cmSystemTools::LowerCase(slnName);
+  cmSystemTools::ConvertToUnixSlashes(s1);
+  cmSystemTools::ConvertToUnixSlashes(s2);
+
+  return s1 == s2;
+}
+
+
+//----------------------------------------------------------------------------
+///! Find instances of Visual Studio with the given solution file
+///! open. Pass "ALL" for slnFile to gather all running instances
+///! of Visual Studio.
+HRESULT FindVisualStudioInstances(
+  const std::string& slnFile,
+  std::vector<IDispatchPtr>& instances)
+{
+  std::map<std::string, IUnknownPtr> mrot;
+
+  HRESULT hr = GetRunningInstances(mrot);
+  ReportHRESULT(hr, "GetRunningInstances");
+
+  if(SUCCEEDED(hr))
+    {
+    std::map<std::string, IUnknownPtr>::iterator it;
+    for(it = mrot.begin(); it != mrot.end(); ++it)
+      {
+      if (cmSystemTools::StringStartsWith(it->first.c_str(),
+        "!VisualStudio.DTE."))
+        {
+        IDispatchPtr disp(it->second);
+        if (disp != (IDispatch*) 0)
+          {
+          std::string slnName;
+          hr = GetIDESolutionFullName(disp, slnName);
+          ReportHRESULT(hr, "GetIDESolutionFullName");
+
+          if (FilesSameSolution(slnFile, slnName))
+            {
+            instances.push_back(disp);
+
+            //std::cout << "Found Visual Studio instance." << std::endl;
+            //std::cout << "  ROT entry name: " << it->first << std::endl;
+            //std::cout << "  ROT entry object: " << (IUnknown*) it->second << std::endl;
+            //std::cout << "  slnFile: " << slnFile << std::endl;
+            //std::cout << "  slnName: " << slnName << std::endl;
+            }
+          }
+        }
+      }
+    }
+
+  return hr;
+}
+
+
+#endif  //defined(HAVE_COMDEF_H)
+
+
+//----------------------------------------------------------------------------
+int cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
+  const std::string& slnFile)
+{
+  int count = 0;
+
+#if defined(HAVE_COMDEF_H)
+  HRESULT hr = CoInitialize(0);
+  ReportHRESULT(hr, "CoInitialize");
+
+  if(SUCCEEDED(hr))
+    {
+    std::vector<IDispatchPtr> instances;
+    hr = FindVisualStudioInstances(slnFile, instances);
+    ReportHRESULT(hr, "FindVisualStudioInstances");
+
+    if(SUCCEEDED(hr))
+      {
+      count = instances.size();
+      }
+
+    // Force release all COM pointers before CoUninitialize:
+    instances.clear();
+
+    CoUninitialize();
+    }
+#endif
+
+  return count;
+}
+
+
+//----------------------------------------------------------------------------
+///! Get all running objects from the Windows running object table.
+///! Save them in a map by their display names.
+int cmCallVisualStudioMacro::CallMacro(
+  const std::string& slnFile,
+  const std::string& macro,
+  const std::string& args)
+{
+  int err = 1; // no comdef.h
+
+#if defined(HAVE_COMDEF_H)
+  err = 2; // error initializing
+
+  HRESULT hr = CoInitialize(0);
+  ReportHRESULT(hr, "CoInitialize");
+
+  if(SUCCEEDED(hr))
+    {
+    std::vector<IDispatchPtr> instances;
+    hr = FindVisualStudioInstances(slnFile, instances);
+    ReportHRESULT(hr, "FindVisualStudioInstances");
+
+    if(SUCCEEDED(hr))
+      {
+      err = 0; // no error
+
+      std::vector<IDispatchPtr>::iterator it;
+      for(it = instances.begin(); it != instances.end(); ++it)
+        {
+        hr = InstanceCallMacro(*it, macro, args);
+        ReportHRESULT(hr, "InstanceCallMacro");
+
+        if (FAILED(hr))
+          {
+          err = 3; // error attempting to call the macro
+          }
+        }
+
+      if(0 == instances.size())
+        {
+        // no instances to call
+
+        //cmSystemTools::Message(
+        //  "cmCallVisualStudioMacro::CallMacro no instances found to call",
+        //  "Warning");
+        }
+      }
+
+    // Force release all COM pointers before CoUninitialize:
+    instances.clear();
+
+    CoUninitialize();
+    }
+#else
+  cmSystemTools::Error("cmCallVisualStudioMacro::CallMacro is not "
+    "supported on this platform");
+#endif
+
+  if (err)
+    {
+    std::ostringstream oss;
+    oss << "cmCallVisualStudioMacro::CallMacro failed, err = " << err;
+    cmSystemTools::Error(oss.str().c_str());
+    }
+
+  return err;
+}
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
new file mode 100644
index 0000000000..ea3cc104d6
--- /dev/null
+++ b/Source/cmCallVisualStudioMacro.h
@@ -0,0 +1,49 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmCallVisualStudioMacro_h
+#define cmCallVisualStudioMacro_h
+
+#include "cmStandardIncludes.h"
+
+/** \class cmCallVisualStudioMacro
+ * \brief Control class for communicating with CMake's Visual Studio macros
+ *
+ * Find running instances of Visual Studio by full path solution name.
+ * Call a Visual Studio IDE macro in any of those instances.
+ */
+class cmCallVisualStudioMacro
+{
+public:
+  ///! Call the named macro in instances of Visual Studio with the
+  ///! given solution file open. Pass "ALL" for slnFile to call the
+  ///! macro in each Visual Studio instance.
+  static int CallMacro(const std::string& slnFile,
+                       const std::string& macro,
+                       const std::string& args);
+
+  ///! Count the number of running instances of Visual Studio with the
+  ///! given solution file open. Pass "ALL" for slnFile to count all
+  ///! running Visual Studio instances.
+  static int GetNumberOfRunningVisualStudioInstances(
+    const std::string& slnFile);
+
+protected:
+
+private:
+};
+
+#endif
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 660d9d5ef7..1bd8669d26 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -90,7 +90,7 @@ cmGeneratedFileStream::Open(const char* name, bool quiet, bool binaryFlag)
 }
 
 //----------------------------------------------------------------------------
-cmGeneratedFileStream&
+bool
 cmGeneratedFileStream::Close()
 {
   // Save whether the temporary output file is valid before closing.
@@ -100,9 +100,7 @@ cmGeneratedFileStream::Close()
   this->Stream::close();
 
   // Remove the temporary file (possibly by renaming to the real file).
-  this->cmGeneratedFileStreamBase::Close();
-
-  return *this;
+  return this->cmGeneratedFileStreamBase::Close();
 }
 
 //----------------------------------------------------------------------------
@@ -170,8 +168,10 @@ void cmGeneratedFileStreamBase::Open(const char* name)
 }
 
 //----------------------------------------------------------------------------
-void cmGeneratedFileStreamBase::Close()
+bool cmGeneratedFileStreamBase::Close()
 {
+  bool replaced = false;
+
   std::string resname = this->Name;
   if ( this->Compress && this->CompressExtraExtension )
     {
@@ -200,12 +200,16 @@ void cmGeneratedFileStreamBase::Close()
       {
       this->RenameFile(this->TempName.c_str(), resname.c_str());
       }
+
+    replaced = true;
     }
 
   // Else, the destination was not replaced.
   //
   // Always delete the temporary file. We never want it to stay around.
   cmSystemTools::RemoveFile(this->TempName.c_str());
+
+  return replaced;
 }
 
 //----------------------------------------------------------------------------
diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h
index 9d718e1813..2dfeaf3571 100644
--- a/Source/cmGeneratedFileStream.h
+++ b/Source/cmGeneratedFileStream.h
@@ -44,7 +44,7 @@ protected:
   // after the real stream is closed and Okay is set to whether the
   // real stream was still valid for writing when it was closed.
   void Open(const char* name);
-  void Close();
+  bool Close();
 
   // Internal file replacement implementation.
   int RenameFile(const char* oldname, const char* newname);
@@ -123,7 +123,7 @@ public:
    * destionation file if the stream is still valid when this method
    * is called.
    */
-  cmGeneratedFileStream& Close();
+  bool Close();
 
   /**
    * Set whether copy-if-different is done.
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 5299a1c905..7acd92bc28 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -737,6 +737,10 @@ void cmGlobalGenerator::Configure()
 
 void cmGlobalGenerator::Generate()
 {
+  // Some generators track files replaced during the Generate.
+  // Start with an empty vector:
+  this->FilesReplacedDuringGenerate.clear();
+
   // For each existing cmLocalGenerator
   unsigned int i;
 
@@ -1785,3 +1789,17 @@ const char* cmGlobalGenerator::GetExtraGeneratorName() const
 {
   return this->ExtraGenerator==0 ? 0 : this->ExtraGenerator->GetName();
 }
+
+void cmGlobalGenerator::FileReplacedDuringGenerate(const std::string& filename)
+{
+  this->FilesReplacedDuringGenerate.push_back(filename);
+}
+
+void cmGlobalGenerator::GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames)
+{
+  filenames.clear();
+  std::copy(
+    this->FilesReplacedDuringGenerate.begin(),
+    this->FilesReplacedDuringGenerate.end(),
+    std::back_inserter(filenames));
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 160c728d04..8e1bf12e10 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -230,6 +230,11 @@ public:
 
   const std::map<cmStdString, std::vector<cmLocalGenerator*> >& GetProjectMap()
                                                const {return this->ProjectMap;}
+
+  // track files replaced during a Generate
+  void FileReplacedDuringGenerate(const std::string& filename);
+  void GetFilesReplacedDuringGenerate(std::vector<std::string>& filenames);
+
 protected:
   void SetLanguageEnabledFlag(const char* l, cmMakefile* mf);
   void SetLanguageEnabledMaps(const char* l, cmMakefile* mf);
@@ -287,6 +292,9 @@ private:
   std::map<cmStdString, std::vector<cmTarget *> > TargetDependencies;
 
   cmExternalMakefileProjectGenerator* ExtraGenerator;
+
+  // track files replaced during a Generate
+  std::vector<std::string> FilesReplacedDuringGenerate;
 };
 
 #endif
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 513677941a..3556d79397 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -16,8 +16,8 @@
 =========================================================================*/
 #include "windows.h" // this must be first to define GetCurrentDirectory
 #include "cmGlobalVisualStudio7Generator.h"
-#include "cmLocalVisualStudio7Generator.h"
 #include "cmGeneratedFileStream.h"
+#include "cmLocalVisualStudio7Generator.h"
 #include "cmMakefile.h"
 #include "cmake.h"
 
@@ -202,7 +202,7 @@ void cmGlobalVisualStudio7Generator::GenerateConfigurations(cmMakefile* mf)
     configs += ";";
     configs += this->Configurations[i];
     }
-  
+
   mf->AddCacheDefinition(
     "CMAKE_CONFIGURATION_TYPES",
     configs.c_str(),
@@ -219,6 +219,13 @@ void cmGlobalVisualStudio7Generator::Generate()
 
   // Now write out the DSW
   this->OutputSLNFile();
+
+  // If any solution or project files changed during the generation,
+  // tell Visual Studio to reload them...
+  if(!cmSystemTools::GetErrorOccuredFlag())
+    {
+    this->CallVisualStudioReloadMacro();
+    }
 }
 
 void cmGlobalVisualStudio7Generator
@@ -241,11 +248,15 @@ void cmGlobalVisualStudio7Generator
     return;
     }
   this->WriteSLNFile(fout, root, generators);
+  if (fout.Close())
+    {
+    this->FileReplacedDuringGenerate(fname);
+    }
 }
 
 // output the SLN file
 void cmGlobalVisualStudio7Generator::OutputSLNFile()
-{ 
+{
   std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
   for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
     {
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 5013a6824e..3ea9f75c0e 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -71,6 +71,34 @@ void cmGlobalVisualStudio8Generator::Configure()
   this->CreateGUID(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
 }
 
+//----------------------------------------------------------------------------
+std::string cmGlobalVisualStudio8Generator::GetUserMacrosDirectory()
+{
+  std::string base;
+  std::string path;
+
+  // base begins with the VisualStudioProjectsLocation reg value...
+  if (cmSystemTools::ReadRegistryValue(
+    "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\8.0;VisualStudioProjectsLocation",
+    base))
+    {
+    cmSystemTools::ConvertToUnixSlashes(base);
+
+    // 7.0 macros folder:
+    //path = base + "/VSMacros";
+
+    // 7.1 macros folder:
+    //path = base + "/VSMacros71";
+
+    // 8.0 macros folder:
+    path = base + "/VSMacros80";
+    }
+
+  // path is (correctly) still empty if we did not read the base value from
+  // the Registry value
+  return path;
+}
+
 //----------------------------------------------------------------------------
 void cmGlobalVisualStudio8Generator::Generate()
 {
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 38963e3589..b7250a13eb 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -49,6 +49,14 @@ public:
    */
   virtual void Configure();
   virtual void Generate();
+
+  /**
+   * Where does this version of Visual Studio look for macros for the
+   * current user? Returns the empty string if this version of Visual
+   * Studio does not implement support for VB macros.
+   */
+  virtual std::string GetUserMacrosDirectory();
+
 protected:
 
   // Utility target fix is not needed for VS8.
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
index c0d31e6dae..06d959b608 100644
--- a/Source/cmGlobalVisualStudio9Generator.cxx
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -53,9 +53,36 @@ void cmGlobalVisualStudio9Generator
   entry.Full = "";
 }
 
+//----------------------------------------------------------------------------
 void cmGlobalVisualStudio9Generator
 ::EnableLanguage(std::vector<std::string>const &  lang, 
                  cmMakefile *mf, bool optional)
 {
   cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
 }
+
+//----------------------------------------------------------------------------
+std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory()
+{
+  std::string base;
+  std::string path;
+
+  // base begins with the VisualStudioProjectsLocation reg value...
+  if (cmSystemTools::ReadRegistryValue(
+    "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\9.0;VisualStudioProjectsLocation",
+    base))
+    {
+    cmSystemTools::ConvertToUnixSlashes(base);
+
+    // 9.0 macros folder:
+    path = base + "/VSMacros80";
+      // *NOT* a typo; right now in Visual Studio 2008 beta the macros
+      // folder is VSMacros80... They may change it to 90 before final
+      // release of 2008 or they may not... we'll have to keep our eyes
+      // on it
+    }
+
+  // path is (correctly) still empty if we did not read the base value from
+  // the Registry value
+  return path;
+}
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
index 565d7624b4..03c422a6f4 100644
--- a/Source/cmGlobalVisualStudio9Generator.h
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -51,5 +51,12 @@ public:
   virtual void EnableLanguage(std::vector<std::string>const& languages, 
                               cmMakefile *, bool optional);
   virtual void WriteSLNHeader(std::ostream& fout);
+
+  /**
+   * Where does this version of Visual Studio look for macros for the
+   * current user? Returns the empty string if this version of Visual
+   * Studio does not implement support for VB macros.
+   */
+  virtual std::string GetUserMacrosDirectory();
 };
 #endif
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 658516c3e7..9e6817e538 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -16,6 +16,7 @@
 =========================================================================*/
 #include "cmGlobalVisualStudioGenerator.h"
 
+#include "cmCallVisualStudioMacro.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmTarget.h"
@@ -57,10 +58,99 @@ void cmGlobalVisualStudioGenerator::Generate()
   // Fix utility dependencies to avoid linking to libraries.
   this->FixUtilityDepends();
 
+  // Configure CMake Visual Studio macros, for this user on this version
+  // of Visual Studio.
+  this->ConfigureCMakeVisualStudioMacros();
+
   // Run all the local generators.
   this->cmGlobalGenerator::Generate();
 }
 
+//----------------------------------------------------------------------------
+void RegisterVisualStudioMacros(const std::string& macrosFile);
+
+//----------------------------------------------------------------------------
+#define CMAKE_VSMACROS_FILENAME \
+  "CMakeVSMacros1.vsmacros"
+
+#define CMAKE_VSMACROS_RELOAD_MACRONAME \
+  "Macros.CMakeVSMacros1.Macros.ReloadProjects"
+
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudioGenerator::ConfigureCMakeVisualStudioMacros()
+{
+  cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+  std::string dir = this->GetUserMacrosDirectory();
+
+  if (mf != 0 && dir != "")
+    {
+    std::string src = mf->GetRequiredDefinition("CMAKE_ROOT");
+    src += "/Templates/" CMAKE_VSMACROS_FILENAME;
+
+    std::string dst = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
+
+    // Only copy if dst does not already exist. Write this file initially,
+    // but never overwrite local mods.
+    if (!cmSystemTools::FileExists(dst.c_str()))
+      {
+      if (!cmSystemTools::CopyFileAlways(src.c_str(), dst.c_str()))
+        {
+        std::ostringstream oss;
+        oss << "Could not copy from: " << src << std::endl;
+        oss << "                 to: " << dst << std::endl;
+        cmSystemTools::Message(oss.str().c_str(), "Warning");
+        }
+      }
+
+    RegisterVisualStudioMacros(dst);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmGlobalVisualStudioGenerator::CallVisualStudioReloadMacro()
+{
+  // If any solution or project files changed during the generation,
+  // tell Visual Studio to reload them...
+  cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+  std::string dir = this->GetUserMacrosDirectory();
+
+  if (mf != 0 && dir != "")
+    {
+    std::vector<std::string> filenames;
+    this->GetFilesReplacedDuringGenerate(filenames);
+    if (filenames.size() > 0)
+      {
+      // Convert vector to semi-colon delimited string of filenames:
+      std::string projects;
+      std::vector<std::string>::iterator it = filenames.begin();
+      if (it != filenames.end())
+        {
+        projects = *it;
+        ++it;
+        }
+      for (; it != filenames.end(); ++it)
+        {
+        projects += ";";
+        projects += *it;
+        }
+
+      std::string topLevelSlnName = mf->GetStartOutputDirectory();
+      topLevelSlnName += "/";
+      topLevelSlnName += mf->GetProjectName();
+      topLevelSlnName += ".sln";
+
+      cmCallVisualStudioMacro::CallMacro(topLevelSlnName,
+        CMAKE_VSMACROS_RELOAD_MACRONAME, projects);
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+std::string cmGlobalVisualStudioGenerator::GetUserMacrosDirectory()
+{
+  return "";
+}
+
 //----------------------------------------------------------------------------
 void cmGlobalVisualStudioGenerator::FixUtilityDepends()
 {
@@ -224,3 +314,268 @@ cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
   // No special case.  Just use the original dependency name.
   return name;
 }
+
+//----------------------------------------------------------------------------
+#include <windows.h>
+
+//----------------------------------------------------------------------------
+bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
+  std::string& nextAvailableSubKeyName)
+{
+  bool macrosRegistered = false;
+
+  std::string s1;
+  std::string s2;
+
+  // Make lowercase local copies, convert to Unix slashes, and
+  // see if the resulting strings are the same:
+  s1 = cmSystemTools::LowerCase(macrosFile);
+  cmSystemTools::ConvertToUnixSlashes(s1);
+
+  std::string keyname;
+  HKEY hkey = NULL;
+  LONG result = ERROR_SUCCESS;
+  DWORD index = 0;
+
+  keyname = "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros\\OtherProjects7";
+  hkey = NULL;
+  result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(), 0, KEY_READ, &hkey);
+  if (ERROR_SUCCESS == result)
+    {
+    // Iterate the subkeys and look for the values of interest in each subkey:
+    CHAR subkeyname[256];
+    DWORD cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
+    CHAR keyclass[256];
+    DWORD cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
+    FILETIME lastWriteTime;
+    lastWriteTime.dwHighDateTime = 0;
+    lastWriteTime.dwLowDateTime = 0;
+
+    while (ERROR_SUCCESS == RegEnumKeyEx(hkey, index, subkeyname, &cch_subkeyname,
+      0, keyclass, &cch_keyclass, &lastWriteTime))
+      {
+      // Open the subkey and query the values of interest:
+      HKEY hsubkey = NULL;
+      result = RegOpenKeyEx(hkey, subkeyname, 0, KEY_READ, &hsubkey);
+      if (ERROR_SUCCESS == result)
+        {
+        DWORD valueType = REG_SZ;
+        CHAR data1[256];
+        DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
+        RegQueryValueEx(hsubkey, "Path", 0, &valueType, (LPBYTE) &data1[0], &cch_data1);
+
+        DWORD data2 = 0;
+        DWORD cch_data2 = sizeof(data2);
+        RegQueryValueEx(hsubkey, "Security", 0, &valueType, (LPBYTE) &data2, &cch_data2);
+
+        DWORD data3 = 0;
+        DWORD cch_data3 = sizeof(data3);
+        RegQueryValueEx(hsubkey, "StorageFormat", 0, &valueType, (LPBYTE) &data3, &cch_data3);
+
+        s2 = cmSystemTools::LowerCase(data1);
+        cmSystemTools::ConvertToUnixSlashes(s2);
+        if (s2 == s1)
+          {
+          macrosRegistered = true;
+          }
+
+        std::string fullname(data1);
+        std::string filename;
+        std::string filepath;
+        std::string filepathname;
+        std::string filepathpath;
+        if (cmSystemTools::FileExists(fullname.c_str()))
+          {
+          filename = cmSystemTools::GetFilenameName(fullname);
+          filepath = cmSystemTools::GetFilenamePath(fullname);
+          filepathname = cmSystemTools::GetFilenameName(filepath);
+          filepathpath = cmSystemTools::GetFilenamePath(filepath);
+          }
+
+        //std::cout << keyname << "\\" << subkeyname << ":" << std::endl;
+        //std::cout << "  Path: " << data1 << std::endl;
+        //std::cout << "  Security: " << data2 << std::endl;
+        //std::cout << "  StorageFormat: " << data3 << std::endl;
+        //std::cout << "  filename: " << filename << std::endl;
+        //std::cout << "  filepath: " << filepath << std::endl;
+        //std::cout << "  filepathname: " << filepathname << std::endl;
+        //std::cout << "  filepathpath: " << filepathpath << std::endl;
+        //std::cout << std::endl;
+
+        RegCloseKey(hsubkey);
+        }
+      else
+        {
+        std::cout << "error opening subkey: " << subkeyname << std::endl;
+        std::cout << std::endl;
+        }
+
+      ++index;
+      cch_subkeyname = sizeof(subkeyname)/sizeof(subkeyname[0]);
+      cch_keyclass = sizeof(keyclass)/sizeof(keyclass[0]);
+      lastWriteTime.dwHighDateTime = 0;
+      lastWriteTime.dwLowDateTime = 0;
+      }
+
+    RegCloseKey(hkey);
+    }
+  else
+    {
+    std::cout << "error opening key: " << keyname << std::endl;
+    std::cout << std::endl;
+    }
+
+
+  // Pass back next available sub key name, assuming sub keys always
+  // follow the expected naming scheme. Expected naming scheme is that
+  // the subkeys of OtherProjects7 is 0 to n-1, so it's ok to use "n"
+  // as the name of the next subkey.
+  std::ostringstream ossNext;
+  ossNext << index;
+  nextAvailableSubKeyName = ossNext.str();
+
+
+  keyname = "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros\\RecordingProject7";
+  hkey = NULL;
+  result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(), 0, KEY_READ, &hkey);
+  if (ERROR_SUCCESS == result)
+    {
+    DWORD valueType = REG_SZ;
+    CHAR data1[256];
+    DWORD cch_data1 = sizeof(data1)/sizeof(data1[0]);
+    RegQueryValueEx(hkey, "Path", 0, &valueType, (LPBYTE) &data1[0], &cch_data1);
+
+    DWORD data2 = 0;
+    DWORD cch_data2 = sizeof(data2);
+    RegQueryValueEx(hkey, "Security", 0, &valueType, (LPBYTE) &data2, &cch_data2);
+
+    DWORD data3 = 0;
+    DWORD cch_data3 = sizeof(data3);
+    RegQueryValueEx(hkey, "StorageFormat", 0, &valueType, (LPBYTE) &data3, &cch_data3);
+
+    s2 = cmSystemTools::LowerCase(data1);
+    cmSystemTools::ConvertToUnixSlashes(s2);
+    if (s2 == s1)
+      {
+      macrosRegistered = true;
+      }
+
+    //std::cout << keyname << ":" << std::endl;
+    //std::cout << "  Path: " << data1 << std::endl;
+    //std::cout << "  Security: " << data2 << std::endl;
+    //std::cout << "  StorageFormat: " << data3 << std::endl;
+    //std::cout << std::endl;
+
+    RegCloseKey(hkey);
+    }
+  else
+    {
+    std::cout << "error opening key: " << keyname << std::endl;
+    std::cout << std::endl;
+    }
+
+  return macrosRegistered;
+}
+
+//----------------------------------------------------------------------------
+void WriteVSMacrosFileRegistryEntry(
+  const std::string& nextAvailableSubKeyName,
+  const std::string& macrosFile)
+{
+  std::string keyname = "Software\\Microsoft\\VisualStudio\\8.0\\vsmacros\\OtherProjects7";
+  HKEY hkey = NULL;
+  LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, keyname.c_str(), 0,
+    KEY_READ|KEY_WRITE, &hkey);
+  if (ERROR_SUCCESS == result)
+    {
+    // Create the subkey and set the values of interest:
+    HKEY hsubkey = NULL;
+    result = RegCreateKeyEx(hkey, nextAvailableSubKeyName.c_str(), 0, "", 0,
+      KEY_READ|KEY_WRITE, 0, &hsubkey, 0);
+    if (ERROR_SUCCESS == result)
+      {
+      DWORD dw = 0;
+
+      std::string s(macrosFile);
+      cmSystemTools::ReplaceString(s, "/", "\\");
+
+      result = RegSetValueEx(hsubkey, "Path", 0, REG_SZ, (LPBYTE) s.c_str(),
+        strlen(s.c_str()) + 1);
+      if (ERROR_SUCCESS != result)
+        {
+        std::cout << "error result 1: " << result << std::endl;
+        std::cout << std::endl;
+        }
+
+      // Security value is always "1" for sample macros files (seems to be "2"
+      // if you put the file somewhere outside the standard VSMacros folder)
+      dw = 1;
+      result = RegSetValueEx(hsubkey, "Security", 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
+      if (ERROR_SUCCESS != result)
+        {
+        std::cout << "error result 2: " << result << std::endl;
+        std::cout << std::endl;
+        }
+
+      // StorageFormat value is always "0" for sample macros files
+      dw = 0;
+      result = RegSetValueEx(hsubkey, "StorageFormat", 0, REG_DWORD, (LPBYTE) &dw, sizeof(DWORD));
+      if (ERROR_SUCCESS != result)
+        {
+        std::cout << "error result 3: " << result << std::endl;
+        std::cout << std::endl;
+        }
+
+      RegCloseKey(hsubkey);
+      }
+    else
+      {
+      std::cout << "error creating subkey: " << nextAvailableSubKeyName << std::endl;
+      std::cout << std::endl;
+      }
+    RegCloseKey(hkey);
+    }
+  else
+    {
+    std::cout << "error opening key: " << keyname << std::endl;
+    std::cout << std::endl;
+    }
+}
+
+//----------------------------------------------------------------------------
+void RegisterVisualStudioMacros(const std::string& macrosFile)
+{
+  bool macrosRegistered;
+  std::string nextAvailableSubKeyName;
+
+  macrosRegistered = IsVisualStudioMacrosFileRegistered(macrosFile,
+    nextAvailableSubKeyName);
+
+  if (!macrosRegistered)
+    {
+    int count = cmCallVisualStudioMacro::
+      GetNumberOfRunningVisualStudioInstances("ALL");
+
+    // Only register the macros file if there are *no* instances of Visual
+    // Studio running. If we register it while one is running, first, it has
+    // no effect on the running instance; second, and worse, Visual Studio
+    // removes our newly added registration entry when it quits. Instead,
+    // emit a warning instructing the user to re-run the CMake configure step
+    // after exiting all running Visual Studio instances...
+    //
+    if (0 == count)
+      {
+      WriteVSMacrosFileRegistryEntry(nextAvailableSubKeyName, macrosFile);
+      }
+    else
+      {
+      std::ostringstream oss;
+      oss << "Could not register Visual Studio macros file '" << macrosFile
+        << "' with instances of Visual Studio running. Please exit all"
+        << " running instances of Visual Studio and rerun this CMake"
+        << " configure to register CMake's Visual Studio macros file."
+        << std::endl;
+      cmSystemTools::Message(oss.str().c_str(), "Warning");
+      }
+    }
+}
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 92acb69ba2..575910ded6 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -36,10 +36,30 @@ public:
    */
   virtual void Generate();
 
+  /**
+   * Configure CMake's Visual Studio macros file into the user's Visual
+   * Studio macros directory.
+   */
+  virtual void ConfigureCMakeVisualStudioMacros();
+
+  /**
+   * Where does this version of Visual Studio look for macros for the
+   * current user? Returns the empty string if this version of Visual
+   * Studio does not implement support for VB macros.
+   */
+  virtual std::string GetUserMacrosDirectory();
+
+  /**
+   * Call the ReloadProjects macro if necessary based on
+   * GetFilesReplacedDuringGenerate results.
+   */
+  virtual void CallVisualStudioReloadMacro();
+
 protected:
   virtual void CreateGUID(const char*) {}
   virtual void FixUtilityDepends();
   const char* GetUtilityForTarget(cmTarget& target, const char*);
+
 private:
   void FixUtilityDependsForTarget(cmTarget& target);
   void CreateUtilityDependTarget(cmTarget& target);
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 33181f4324..bb3668c1de 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -199,6 +199,10 @@ void cmLocalVisualStudio7Generator
   cmGeneratedFileStream fout(fname.c_str());
   fout.SetCopyIfDifferent(true);
   this->WriteVCProjFile(fout,lname,target);
+  if (fout.Close())
+    {
+    this->GlobalGenerator->FileReplacedDuringGenerate(fname);
+    }
 }
 
 //----------------------------------------------------------------------------
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index dad2980b13..bec904d762 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -76,6 +76,10 @@
 #endif
 #include "cmGlobalUnixMakefileGenerator3.h"
 
+#if defined(_WIN32)
+#include "cmCallVisualStudioMacro.h"
+#endif
+
 #if !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
 # include "cmExtraCodeBlocksGenerator.h"
 #endif
@@ -1322,6 +1326,31 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
       return result;
       }
 
+#if defined(_WIN32)
+    // Internal CMake support for calling Visual Studio macros.
+    else if (args[1] == "cmake_call_visual_studio_macro" && args.size() >= 4)
+      {
+      // args[2] = full path to .sln file or "ALL"
+      // args[3] = name of Visual Studio macro to call
+      // args[4..args.size()-1] = [optional] args for Visual Studio macro
+
+      std::string macroArgs;
+
+      if (args.size() > 4)
+        {
+        macroArgs = args[4];
+
+        for (size_t i = 5; i < args.size(); ++i)
+          {
+          macroArgs += " ";
+          macroArgs += args[i];
+          }
+        }
+
+      return cmCallVisualStudioMacro::CallMacro(args[2], args[3], macroArgs);
+      }
+#endif
+
     // Internal CMake dependency scanning support.
     else if (args[1] == "cmake_depends" && args.size() >= 6)
       {
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 0f837f78cc..37562b1a97 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -492,11 +492,11 @@ void SystemTools::ReplaceString(kwsys_stl::string& source,
 #if defined(_WIN32) && !defined(__CYGWIN__)
 bool SystemTools::ReadRegistryValue(const char *key, kwsys_stl::string &value)
 {
-
+  bool valueset = false;
   kwsys_stl::string primary = key;
   kwsys_stl::string second;
   kwsys_stl::string valuename;
- 
+
   size_t start = primary.find("\\");
   if (start == kwsys_stl::string::npos)
     {
@@ -558,12 +558,24 @@ bool SystemTools::ReadRegistryValue(const char *key, kwsys_stl::string &value)
       if (dwType == REG_SZ)
         {
         value = data;
-        RegCloseKey(hKey);
-        return true;
+        valueset = true;
+        }
+      else if (dwType == REG_EXPAND_SZ)
+        {
+        char expanded[1024];
+        DWORD dwExpandedSize = sizeof(expanded)/sizeof(expanded[0]);
+        if(ExpandEnvironmentStrings(data, expanded, dwExpandedSize))
+          {
+          value = expanded;
+          valueset = true;
+          }
         }
       }
+
+    RegCloseKey(hKey);
     }
-  return false;
+
+  return valueset;
 }
 #else
 bool SystemTools::ReadRegistryValue(const char *, kwsys_stl::string &)
diff --git a/Templates/CMakeVSMacros1.vsmacros b/Templates/CMakeVSMacros1.vsmacros
new file mode 100644
index 0000000000000000000000000000000000000000..bfb60dc63deb72fcfc3a33a54525294114186a33
GIT binary patch
literal 88064
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

literal 0
HcmV?d00001

-- 
GitLab