diff options
Diffstat (limited to 'Source/cmGlobalVisualStudioGenerator.cxx')
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 355 |
1 files changed, 355 insertions, 0 deletions
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"); + } + } +} |