summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMakeLists.txt5
-rw-r--r--Source/cmCallVisualStudioMacro.cxx464
-rw-r--r--Source/cmCallVisualStudioMacro.h49
-rw-r--r--Source/cmGeneratedFileStream.cxx14
-rw-r--r--Source/cmGeneratedFileStream.h4
-rw-r--r--Source/cmGlobalGenerator.cxx18
-rw-r--r--Source/cmGlobalGenerator.h8
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx17
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx28
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h8
-rw-r--r--Source/cmGlobalVisualStudio9Generator.cxx27
-rw-r--r--Source/cmGlobalVisualStudio9Generator.h7
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx355
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h20
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx4
-rw-r--r--Source/cmake.cxx29
-rw-r--r--Source/kwsys/SystemTools.cxx22
-rw-r--r--Templates/CMakeVSMacros1.vsmacrosbin0 -> 88064 bytes
18 files changed, 1064 insertions, 15 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 86c4579..d4ec11a 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 0000000..635e264
--- /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 0000000..ea3cc10
--- /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 660d9d5..1bd8669 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 9d718e1..2dfeaf3 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 5299a1c..7acd92b 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 160c728..8e1bf12 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 5136779..3556d79 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 5013a68..3ea9f75 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -72,6 +72,34 @@ void cmGlobalVisualStudio8Generator::Configure()
}
//----------------------------------------------------------------------------
+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
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 38963e3..b7250a1 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 c0d31e6..06d959b 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 565d762..03c422a 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 658516c..9e6817e 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,11 +58,100 @@ 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()
{
// For VS versions before 8:
@@ -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 92acb69..575910d 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 33181f4..bb3668c 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 dad2980..bec904d 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 0f837f7..37562b1 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 0000000..bfb60dc
--- /dev/null
+++ b/Templates/CMakeVSMacros1.vsmacros
Binary files differ