[cmake-commits] david.cole committed CMakeLists.txt 1.384 1.385 cmGeneratedFileStream.cxx 1.18 1.19 cmGeneratedFileStream.h 1.22 1.23 cmGlobalGenerator.cxx 1.211 1.212 cmGlobalGenerator.h 1.97 1.98 cmGlobalVisualStudio7Generator.cxx 1.91 1.92 cmGlobalVisualStudio8Generator.cxx 1.25 1.26 cmGlobalVisualStudio8Generator.h 1.10 1.11 cmGlobalVisualStudio9Generator.cxx 1.2 1.3 cmGlobalVisualStudio9Generator.h 1.1 1.2 cmGlobalVisualStudioGenerator.cxx 1.4 1.5 cmGlobalVisualStudioGenerator.h 1.3 1.4 cmLocalVisualStudio7Generator.cxx 1.204 1.205 cmake.cxx 1.331 1.332 cmCallVisualStudioMacro.cxx NONE 1.1 cmCallVisualStudioMacro.h NONE 1.1

cmake-commits at cmake.org cmake-commits at cmake.org
Fri Nov 16 07:02:00 EST 2007


Update of /cvsroot/CMake/CMake/Source
In directory public:/mounts/ram/cvs-serv7407/Source

Modified Files:
	CMakeLists.txt cmGeneratedFileStream.cxx 
	cmGeneratedFileStream.h cmGlobalGenerator.cxx 
	cmGlobalGenerator.h cmGlobalVisualStudio7Generator.cxx 
	cmGlobalVisualStudio8Generator.cxx 
	cmGlobalVisualStudio8Generator.h 
	cmGlobalVisualStudio9Generator.cxx 
	cmGlobalVisualStudio9Generator.h 
	cmGlobalVisualStudioGenerator.cxx 
	cmGlobalVisualStudioGenerator.h 
	cmLocalVisualStudio7Generator.cxx cmake.cxx 
Added Files:
	cmCallVisualStudioMacro.cxx cmCallVisualStudioMacro.h 
Log Message:
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.


Index: cmLocalVisualStudio7Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmLocalVisualStudio7Generator.cxx,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- cmLocalVisualStudio7Generator.cxx	12 Nov 2007 20:42:37 -0000	1.204
+++ cmLocalVisualStudio7Generator.cxx	16 Nov 2007 12:01:58 -0000	1.205
@@ -199,6 +199,10 @@
   cmGeneratedFileStream fout(fname.c_str());
   fout.SetCopyIfDifferent(true);
   this->WriteVCProjFile(fout,lname,target);
+  if (fout.Close())
+    {
+    this->GlobalGenerator->FileReplacedDuringGenerate(fname);
+    }
 }
 
 //----------------------------------------------------------------------------

Index: cmGlobalVisualStudio8Generator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudio8Generator.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- cmGlobalVisualStudio8Generator.h	4 Apr 2007 18:49:35 -0000	1.10
+++ cmGlobalVisualStudio8Generator.h	16 Nov 2007 12:01:58 -0000	1.11
@@ -49,6 +49,14 @@
    */
   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.

Index: cmGlobalVisualStudio8Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudio8Generator.cxx,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- cmGlobalVisualStudio8Generator.cxx	12 Nov 2007 20:42:37 -0000	1.25
+++ cmGlobalVisualStudio8Generator.cxx	16 Nov 2007 12:01:58 -0000	1.26
@@ -72,6 +72,34 @@
 }
 
 //----------------------------------------------------------------------------
+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()
 {
   // Add a special target on which all other targets depend that

Index: cmGeneratedFileStream.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGeneratedFileStream.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- cmGeneratedFileStream.h	1 Aug 2007 14:53:28 -0000	1.22
+++ cmGeneratedFileStream.h	16 Nov 2007 12:01:58 -0000	1.23
@@ -44,7 +44,7 @@
   // 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 @@
    * destionation file if the stream is still valid when this method
    * is called.
    */
-  cmGeneratedFileStream& Close();
+  bool Close();
 
   /**
    * Set whether copy-if-different is done.

Index: cmGlobalGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalGenerator.h,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -d -r1.97 -r1.98
--- cmGlobalGenerator.h	13 Nov 2007 03:33:00 -0000	1.97
+++ cmGlobalGenerator.h	16 Nov 2007 12:01:58 -0000	1.98
@@ -230,6 +230,11 @@
 
   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 @@
   std::map<cmStdString, std::vector<cmTarget *> > TargetDependencies;
 
   cmExternalMakefileProjectGenerator* ExtraGenerator;
+
+  // track files replaced during a Generate
+  std::vector<std::string> FilesReplacedDuringGenerate;
 };
 
 #endif

Index: cmGlobalGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalGenerator.cxx,v
retrieving revision 1.211
retrieving revision 1.212
diff -u -d -r1.211 -r1.212
--- cmGlobalGenerator.cxx	13 Nov 2007 03:36:26 -0000	1.211
+++ cmGlobalGenerator.cxx	16 Nov 2007 12:01:58 -0000	1.212
@@ -737,6 +737,10 @@
 
 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 @@
 {
   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));
+}

Index: cmake.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmake.cxx,v
retrieving revision 1.331
retrieving revision 1.332
diff -u -d -r1.331 -r1.332
--- cmake.cxx	12 Nov 2007 21:58:05 -0000	1.331
+++ cmake.cxx	16 Nov 2007 12:01:58 -0000	1.332
@@ -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 @@
       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)
       {

Index: cmGlobalVisualStudio9Generator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudio9Generator.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cmGlobalVisualStudio9Generator.h	17 Sep 2007 19:20:54 -0000	1.1
+++ cmGlobalVisualStudio9Generator.h	16 Nov 2007 12:01:58 -0000	1.2
@@ -51,5 +51,12 @@
   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

Index: cmGlobalVisualStudioGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudioGenerator.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- cmGlobalVisualStudioGenerator.h	10 Apr 2007 17:09:03 -0000	1.3
+++ cmGlobalVisualStudioGenerator.h	16 Nov 2007 12:01:58 -0000	1.4
@@ -36,10 +36,30 @@
    */
   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);

Index: cmGlobalVisualStudio9Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudio9Generator.cxx,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cmGlobalVisualStudio9Generator.cxx	22 Oct 2007 16:48:39 -0000	1.2
+++ cmGlobalVisualStudio9Generator.cxx	16 Nov 2007 12:01:58 -0000	1.3
@@ -53,9 +53,36 @@
   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;
+}

Index: cmGlobalVisualStudio7Generator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudio7Generator.cxx,v
retrieving revision 1.91
retrieving revision 1.92
diff -u -d -r1.91 -r1.92
--- cmGlobalVisualStudio7Generator.cxx	22 Oct 2007 16:48:39 -0000	1.91
+++ cmGlobalVisualStudio7Generator.cxx	16 Nov 2007 12:01:58 -0000	1.92
@@ -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 @@
     configs += ";";
     configs += this->Configurations[i];
     }
-  
+
   mf->AddCacheDefinition(
     "CMAKE_CONFIGURATION_TYPES",
     configs.c_str(),
@@ -219,6 +219,13 @@
 
   // 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 @@
     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)
     {

Index: CMakeLists.txt
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CMakeLists.txt,v
retrieving revision 1.384
retrieving revision 1.385
diff -u -d -r1.384 -r1.385
--- CMakeLists.txt	6 Nov 2007 19:14:18 -0000	1.384
+++ CMakeLists.txt	16 Nov 2007 12:01:58 -0000	1.385
@@ -208,6 +208,11 @@
 
 
 IF (WIN32)
+  SET(SRCS ${SRCS}
+    cmCallVisualStudioMacro.cxx
+    cmCallVisualStudioMacro.h
+    )
+
   IF(NOT UNIX)
     SET(SRCS ${SRCS}
       cmGlobalBorlandMakefileGenerator.cxx

Index: cmGeneratedFileStream.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGeneratedFileStream.cxx,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- cmGeneratedFileStream.cxx	27 Sep 2007 18:44:10 -0000	1.18
+++ cmGeneratedFileStream.cxx	16 Nov 2007 12:01:58 -0000	1.19
@@ -90,7 +90,7 @@
 }
 
 //----------------------------------------------------------------------------
-cmGeneratedFileStream&
+bool
 cmGeneratedFileStream::Close()
 {
   // Save whether the temporary output file is valid before closing.
@@ -100,9 +100,7 @@
   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::Close()
+bool cmGeneratedFileStreamBase::Close()
 {
+  bool replaced = false;
+
   std::string resname = this->Name;
   if ( this->Compress && this->CompressExtraExtension )
     {
@@ -200,12 +200,16 @@
       {
       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;
 }
 
 //----------------------------------------------------------------------------

--- NEW FILE: cmCallVisualStudioMacro.cxx ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmCallVisualStudioMacro.cxx,v $
  Language:  C++
  Date:      $Date: 2007/11/16 12:01:58 $
  Version:   $Revision: 1.1 $

  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;
}

--- NEW FILE: cmCallVisualStudioMacro.h ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmCallVisualStudioMacro.h,v $
  Language:  C++
  Date:      $Date: 2007/11/16 12:01:58 $
  Version:   $Revision: 1.1 $

  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

Index: cmGlobalVisualStudioGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmGlobalVisualStudioGenerator.cxx,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cmGlobalVisualStudioGenerator.cxx	22 May 2007 14:24:59 -0000	1.4
+++ cmGlobalVisualStudioGenerator.cxx	16 Nov 2007 12:01:58 -0000	1.5
@@ -16,6 +16,7 @@
 =========================================================================*/
 #include "cmGlobalVisualStudioGenerator.h"
 
+#include "cmCallVisualStudioMacro.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmTarget.h"
@@ -57,11 +58,100 @@
   // 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()
 {
   // For VS versions before 8:
@@ -224,3 +314,268 @@
   // 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");
+      }
+    }
+}



More information about the Cmake-commits mailing list