1
0
Эх сурвалжийг харах

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.
John Farrier 12 жил өмнө
parent
commit
79ec7868d0

+ 12 - 0
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);

+ 4 - 0
Source/cmGeneratorTarget.h

@@ -44,11 +44,15 @@ public:
   std::vector<cmSourceFile*> ObjectSources;
   std::vector<cmSourceFile*> ExternalObjects;
   std::vector<cmSourceFile*> IDLSources;
+  std::vector<cmSourceFile*> ResxSources;
+
   std::string ModuleDefinitionFile;
 
   std::map<cmSourceFile const*, std::string> Objects;
   std::set<cmSourceFile const*> ExplicitObjectName;
 
+  std::set<std::string> 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.  */

+ 64 - 2
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("<WindowsAppContainer>true"
                         "</WindowsAppContainer>\n", 2);
       }
+
+    if(!this->GeneratorTarget->ResxSources.empty())
+      {
+      this->WriteString("<CLRSupport>true</CLRSupport>\n", 2);
+      }
+
     this->WriteString("</PropertyGroup>\n", 1);
     }
 }
@@ -647,6 +654,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
     this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups);
     }
 
+  std::vector<cmSourceFile*> resxObjs = this->GeneratorTarget->ResxSources;
+  if(!resxObjs.empty())
+    {
+    this->WriteString("<ItemGroup>\n", 1);
+    for(std::vector<cmSourceFile*>::iterator oi = resxObjs.begin();
+        oi != resxObjs.end(); ++oi)
+      {
+      std::string obj = (*oi)->GetFullPath();
+      this->WriteString("<EmbeddedResource Include=\"", 2);
+      this->ConvertToWindowsSlash(obj);
+      (*this->BuildFileStream ) << obj << "\">\n";
+      this->WriteString("<Filter>Resource Files</Filter>\n", 3);
+      this->WriteString("</EmbeddedResource>\n", 2);
+      }
+    this->WriteString("</ItemGroup>\n", 1);
+    }
+
   // Add object library contents as external objects.
   std::vector<std::string> objs;
   this->GeneratorTarget->UseObjectLibraries(objs);
@@ -701,6 +725,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
                              << "</UniqueIdentifier>\n";
     this->WriteString("</Filter>\n", 2);
     }
+
+  if(!this->GeneratorTarget->ResxSources.empty())
+    {
+    this->WriteString("<Filter Include=\"Resource Files\">\n", 2);
+    std::string guidName = "SG_Filter_Resource Files";
+    this->GlobalGenerator->CreateGUID(guidName.c_str());
+    this->WriteString("<UniqueIdentifier>", 3);
+    std::string guid =
+      this->GlobalGenerator->GetGUID(guidName.c_str());
+    (*this->BuildFileStream) << "{" << guid << "}"
+                             << "</UniqueIdentifier>\n";
+    this->WriteString("<Extensions>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</Extensions>\n";
+    this->WriteString("</Filter>\n", 2);
+  }
+
   this->WriteString("</ItemGroup>\n", 1);
   this->WriteString("</Project>\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("<FileType>CppForm</FileType>\n", 3);
+      this->WriteString("</ClInclude>\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("</ItemGroup>\n", 1);
 }
+
+bool cmVisualStudio10TargetGenerator::
+  IsResxHeader(const std::string& headerFile)
+{
+  std::set<std::string>::iterator it =
+      this->GeneratorTarget->ExpectedResxHeaders.find(headerFile);
+
+  return it != this->GeneratorTarget->ExpectedResxHeaders.end();
+}

+ 2 - 1
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<cmSourceGroup>& );
   void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed,
                               const std::vector<cmSourceGroup>& allGroups);
-
+  bool IsResxHeader(const std::string& headerFile);
 
 private:
   typedef cmVisualStudioGeneratorOptions Options;

+ 5 - 0
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"

+ 44 - 0
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, [email protected]
+#
+
+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}")

+ 0 - 0
Tests/VSWindowsFormsResx/WindowsFormsResx/Header.h


+ 1 - 0
Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.cpp

@@ -0,0 +1 @@
+#include "MyForm.h"

+ 78 - 0
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>
+  /// Summary for MyForm
+  /// </summary>
+  public ref class MyForm : public System::Windows::Forms::Form
+  {
+  public:
+    MyForm(void)
+    {
+      InitializeComponent();
+      //
+      //TODO: Add the constructor code here
+      //
+    }
+
+  protected:
+    /// <summary>
+    /// Clean up any resources being used.
+    /// </summary>
+    ~MyForm()
+    {
+      if (components)
+      {
+        delete components;
+      }
+    }
+  private: System::Windows::Forms::Button^  button1;
+  protected:
+
+  private:
+    /// <summary>
+    /// Required designer variable.
+    /// </summary>
+    System::ComponentModel::Container ^components;
+
+#pragma region Windows Form Designer generated code
+    /// <summary>
+    /// Required method for Designer support - do not modify
+    /// the contents of this method with the code editor.
+    /// </summary>
+    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
+  };
+}

+ 61 - 0
Tests/VSWindowsFormsResx/WindowsFormsResx/MyForm.resx

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 4 - 0
Tests/VSWindowsFormsResx/WindowsFormsResx/Source.cpp

@@ -0,0 +1,4 @@
+int main(int argc, char **argv)
+{
+  return 0;
+}