From 79ec7868d0f08c9ff2e6fa6454b205132acecc24 Mon Sep 17 00:00:00 2001 From: John Farrier Date: Mon, 29 Apr 2013 10:48:22 -0400 Subject: [PATCH] VS: Add Windows Forms Support Add support to maintain designer functionality for Visual Studio C++ Windows Forms projects. Also add a test project showing how to use the CMakeLists.txt file and, when successfully configured, will allow use of the designer for the included form. --- Source/cmGeneratorTarget.cxx | 12 +++ Source/cmGeneratorTarget.h | 4 + Source/cmVisualStudio10TargetGenerator.cxx | 66 +++++++++++++++- Source/cmVisualStudio10TargetGenerator.h | 3 +- Tests/CMakeLists.txt | 5 ++ Tests/VSWindowsFormsResx/CMakeLists.txt | 44 +++++++++++ .../WindowsFormsResx/Header.h | 0 .../WindowsFormsResx/MyForm.cpp | 1 + .../WindowsFormsResx/MyForm.h | 78 +++++++++++++++++++ .../WindowsFormsResx/MyForm.resx | 61 +++++++++++++++ .../WindowsFormsResx/Source.cpp | 4 + 11 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 Tests/VSWindowsFormsResx/CMakeLists.txt create mode 100644 Tests/VSWindowsFormsResx/WindowsFormsResx/Header.h create mode 100644 Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp create mode 100644 Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.h create mode 100644 Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx create mode 100644 Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 335ba0f25..f5d15607e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -98,6 +98,18 @@ void cmGeneratorTarget::ClassifySources() this->IDLSources.push_back(sf); if(isObjLib) { badObjLib.push_back(sf); } } + else if(ext == "resx") + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = sf->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + this->ExpectedResxHeaders.insert(hFileName); + this->ResxSources.push_back(sf); + } else if(header.find(sf->GetFullPath().c_str())) { this->HeaderSources.push_back(sf); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index cbcd8a579..5f7019deb 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -44,11 +44,15 @@ public: std::vector ObjectSources; std::vector ExternalObjects; std::vector IDLSources; + std::vector ResxSources; + std::string ModuleDefinitionFile; std::map Objects; std::set ExplicitObjectName; + std::set ExpectedResxHeaders; + /** Full path with trailing slash to the top-level directory holding object files for this target. Includes the build time config name placeholder if needed for the generator. */ diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1cb9f2370..933bf9573 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -291,6 +291,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteCustomCommands(); this->WriteAllSources(); this->WriteDotNetReferences(); + this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteString( @@ -455,6 +456,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() this->WriteString("true" "\n", 2); } + + if(!this->GeneratorTarget->ResxSources.empty()) + { + this->WriteString("true\n", 2); + } + this->WriteString("\n", 1); } } @@ -647,6 +654,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); } + std::vector resxObjs = this->GeneratorTarget->ResxSources; + if(!resxObjs.empty()) + { + this->WriteString("\n", 1); + for(std::vector::iterator oi = resxObjs.begin(); + oi != resxObjs.end(); ++oi) + { + std::string obj = (*oi)->GetFullPath(); + this->WriteString("ConvertToWindowsSlash(obj); + (*this->BuildFileStream ) << obj << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + this->WriteString("\n", 1); + } + // Add object library contents as external objects. std::vector objs; this->GeneratorTarget->UseObjectLibraries(objs); @@ -701,6 +725,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() << "\n"; this->WriteString("\n", 2); } + + if(!this->GeneratorTarget->ResxSources.empty()) + { + this->WriteString("\n", 2); + std::string guidName = "SG_Filter_Resource Files"; + this->GlobalGenerator->CreateGUID(guidName.c_str()); + this->WriteString("", 3); + std::string guid = + this->GlobalGenerator->GetGUID(guidName.c_str()); + (*this->BuildFileStream) << "{" << guid << "}" + << "\n"; + this->WriteString("rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3); + (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;"; + (*this->BuildFileStream) << "mfcribbon-ms\n"; + this->WriteString("\n", 2); + } + this->WriteString("\n", 1); this->WriteString("\n", 0); // restore stream pointer @@ -832,8 +873,20 @@ void cmVisualStudio10TargetGenerator::WriteSource( } this->ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); - (*this->BuildFileStream ) << tool << - " Include=\"" << sourceFile << "\"" << (end? end : " />\n"); + (*this->BuildFileStream ) << tool << " Include=\"" << sourceFile << "\""; + + if(sf->GetExtension() == "h" && + this->IsResxHeader(sf->GetFullPath())) + { + (*this->BuildFileStream ) << ">\n"; + this->WriteString("CppForm\n", 3); + this->WriteString("\n", 2); + } + else + { + (*this->BuildFileStream ) << (end? end : " />\n"); + } + ToolSource toolSource = {sf, forceRelative}; this->Tools[tool].push_back(toolSource); } @@ -1718,3 +1771,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } this->WriteString("\n", 1); } + +bool cmVisualStudio10TargetGenerator:: + IsResxHeader(const std::string& headerFile) +{ + std::set::iterator it = + this->GeneratorTarget->ExpectedResxHeaders.find(headerFile); + + return it != this->GeneratorTarget->ExpectedResxHeaders.end(); +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 55a850a1b..73d596159 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -62,6 +62,7 @@ private: void WriteWinRTReferences(); void WritePathAndIncrementalLinkOptions(); void WriteItemDefinitionGroups(); + bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); void WriteClOptions(std::string const& config, @@ -91,7 +92,7 @@ private: std::vector& ); void AddMissingSourceGroups(std::set& groupsUsed, const std::vector& allGroups); - + bool IsResxHeader(const std::string& headerFile); private: typedef cmVisualStudioGeneratorOptions Options; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e07bb69db..21c949073 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1448,6 +1448,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ADD_TEST_MACRO(SBCS SBCS) endif() + if(NOT "${CMAKE_TEST_GENERATOR}" MATCHES "Visual Studio [6789]( |$)" + AND NOT CMAKE_TEST_GENERATOR_TOOLSET) + ADD_TEST_MACRO(VSWindowsFormsResx VSWindowsFormsResx) + endif() + add_test(VSExternalInclude ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/VSExternalInclude" diff --git a/Tests/VSWindowsFormsResx/CMakeLists.txt b/Tests/VSWindowsFormsResx/CMakeLists.txt new file mode 100644 index 000000000..a313ac284 --- /dev/null +++ b/Tests/VSWindowsFormsResx/CMakeLists.txt @@ -0,0 +1,44 @@ +# +# Example CMakeLists.txt file to demonstrate how to make a designable Windows Forms project with CMake. +# +# Code modifications and example by John Farrier, john.farrier@helleboreconsulting.com +# + +cmake_minimum_required(VERSION 2.8.10) + +# Project Name +project(VSWindowsFormsResx CXX) + +include(CheckFunctionExists) +include(CheckCXXSourceCompiles) +include(CheckIncludeFile) + +# Note: The designable form is assumed to have a .h extension as is default in Visual Studio. +# Node: The designable form is assumed to have a .resx file with the same name and path (save extension) as is default in Visual Studio + +set(TARGET_H + WindowsFormsResx/MyForm.h + WindowsFormsResx/Header.h + ) + +set(TARGET_SRC + WindowsFormsResx/MyForm.cpp + WindowsFormsResx/Source.cpp + ) + +set(TARGET_RESX + WindowsFormsResx/MyForm.resx + ) + +set(TARGET_LIBRARIES ${SYSLIBS}) +add_executable(${PROJECT_NAME} ${TARGET_SRC} ${TARGET_H} ${TARGET_RESX}) + +# Note: The property VS_GLOBAL_KEYWORD must be set. +set_property(TARGET ${PROJECT_NAME} PROPERTY VS_GLOBAL_KEYWORD "ManagedCProj") + +# Note: The property VS_DOTNET_REFERENCES must be set. +set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_REFERENCES "System" "System.Data" "System.Drawing" "System.Windows.Forms" "System.Xml") + +# Note: Modification of compiler flags is required for CLR compatibility now that we are using .resx files. +string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") diff --git a/Tests/VSWindowsFormsResx/WindowsFormsResx/Header.h b/Tests/VSWindowsFormsResx/WindowsFormsResx/Header.h new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp new file mode 100644 index 000000000..154e268c7 --- /dev/null +++ b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp @@ -0,0 +1 @@ +#include "MyForm.h" \ No newline at end of file diff --git a/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.h b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.h new file mode 100644 index 000000000..16222c5d4 --- /dev/null +++ b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.h @@ -0,0 +1,78 @@ +#pragma once + +namespace Farrier { + + using namespace System; + using namespace System::ComponentModel; + using namespace System::Collections; + using namespace System::Windows::Forms; + using namespace System::Data; + using namespace System::Drawing; + + /// + /// Summary for MyForm + /// + public ref class MyForm : public System::Windows::Forms::Form + { + public: + MyForm(void) + { + InitializeComponent(); + // + //TODO: Add the constructor code here + // + } + + protected: + /// + /// Clean up any resources being used. + /// + ~MyForm() + { + if (components) + { + delete components; + } + } + private: System::Windows::Forms::Button^ button1; + protected: + + private: + /// + /// Required designer variable. + /// + System::ComponentModel::Container ^components; + +#pragma region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + void InitializeComponent(void) + { + this->button1 = (gcnew System::Windows::Forms::Button()); + this->SuspendLayout(); + // + // button1 + // + this->button1->Location = System::Drawing::Point(13, 13); + this->button1->Name = L"button1"; + this->button1->Size = System::Drawing::Size(75, 23); + this->button1->TabIndex = 0; + this->button1->Text = L"button1"; + this->button1->UseVisualStyleBackColor = true; + // + // MyForm + // + this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); + this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; + this->ClientSize = System::Drawing::Size(284, 261); + this->Controls->Add(this->button1); + this->Name = L"MyForm"; + this->Text = L"MyForm"; + this->ResumeLayout(false); + + } +#pragma endregion + }; +} diff --git a/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx new file mode 100644 index 000000000..e8ae276d9 --- /dev/null +++ b/Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp b/Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp new file mode 100644 index 000000000..aee9e2eb4 --- /dev/null +++ b/Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp @@ -0,0 +1,4 @@ +int main(int argc, char **argv) +{ + return 0; +}