From df9f3239ffbad5bf8c10b534effa3a65b4b54166 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20St=C3=BCrmer?= <michael.stuermer@schaeffler.com>
Date: Wed, 10 Feb 2016 14:38:56 +0100
Subject: [PATCH 2/2] implemented C# support

 - added implementation of C# support to cmVisualStudio10TargetGenerator
 - activated CSharp test in test suite
---
 Source/cmVisualStudio10TargetGenerator.cxx | 779 ++++++++++++++++++++++++++---
 Source/cmVisualStudio10TargetGenerator.h   |  13 +-
 Tests/CMakeLists.txt                       |   5 +
 3 files changed, 733 insertions(+), 64 deletions(-)

diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 09d4a90..1c0b1bb 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -40,6 +40,7 @@
 #include "cmVS14LinkFlagTable.h"
 #include "cmVS14LibFlagTable.h"
 #include "cmVS14MASMFlagTable.h"
+#include "cmVSCSharpFlagTable.h"
 
 #include <cmsys/auto_ptr.hxx>
 
@@ -133,6 +134,15 @@ cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetMasmFlagTable() const
   return 0;
 }
 
+cmIDEFlagTable const* cmVisualStudio10TargetGenerator::GetCSharpFlagTable() const
+{
+  if (this->MSTools)
+    {
+    return cmVSCSharpFlagTable;
+    }
+  return 0;
+}
+
 static std::string cmVS10EscapeXML(std::string arg)
 {
   cmSystemTools::ReplaceString(arg, "&", "&amp;");
@@ -165,6 +175,18 @@ static std::string cmVS10EscapeComment(std::string comment)
   return echoable;
 }
 
+static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
+{
+  std::string res;
+  res = ".vcxproj";
+
+  if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( t ))
+    {
+    res = ".csproj";
+    }
+  return res;
+}
+
 cmVisualStudio10TargetGenerator::
 cmVisualStudio10TargetGenerator(cmGeneratorTarget* target,
                                 cmGlobalVisualStudio10Generator* gg)
@@ -189,6 +211,7 @@ cmVisualStudio10TargetGenerator(cmGeneratorTarget* target,
     this->NsightTegraVersion[i] = 0;
     }
   this->MSTools = !this->NsightTegra;
+  this->Managed = false;
   this->TargetCompileAsWinRT = false;
   this->BuildFileStream = 0;
   this->IsMissingFiles = false;
@@ -216,7 +239,7 @@ cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
   if (this->BuildFileStream->Close())
     {
     this->GlobalGenerator
-      ->FileReplacedDuringGenerate(this->PathToVcxproj);
+      ->FileReplacedDuringGenerate(this->PathToProjectFile);
     }
   delete this->BuildFileStream;
 }
@@ -262,7 +285,15 @@ void cmVisualStudio10TargetGenerator::WriteString(const char* line,
   (*this->BuildFileStream ) << line;
 }
 
-#define VS10_USER_PROPS "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
+#define VS10_CXX_DEFAULT_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"
+#define VS10_CXX_PROPS "$(VCTargetsPath)\\Microsoft.Cpp.props"
+#define VS10_CXX_USER_PROPS "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props"
+#define VS10_CXX_TARGETS "$(VCTargetsPath)\\Microsoft.Cpp.targets"
+
+#define VS10_CSharp_DEFAULT_PROPS "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props"
+#define VS10_CSharp_PROPS ""
+#define VS10_CSharp_USER_PROPS ""
+#define VS10_CSharp_TARGETS "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"
 
 void cmVisualStudio10TargetGenerator::Generate()
 {
@@ -272,11 +303,23 @@ void cmVisualStudio10TargetGenerator::Generate()
     {
     return;
     }
+  // set file extension of generated project
+  this->ProjectFileExtension = computeProjectFileExtension(this->GeneratorTarget);
+  if (this->ProjectFileExtension == ".vcxproj")
+    {
+    this->ProjectType = vcxproj;
+    this->Managed = false;
+    }
+  else if (this->ProjectFileExtension == ".csproj")
+    {
+    this->ProjectType = csproj;
+    this->Managed = true;
+    }
   // Tell the global generator the name of the project file
   this->GeneratorTarget->Target
       ->SetProperty("GENERATOR_FILE_NAME",this->Name.c_str());
   this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
-                            ".vcxproj");
+                            this->ProjectFileExtension.c_str());
   if(this->GeneratorTarget->GetType() <= cmState::OBJECT_LIBRARY)
     {
     if(!this->ComputeClOptions())
@@ -299,10 +342,10 @@ void cmVisualStudio10TargetGenerator::Generate()
   std::string path =  this->LocalGenerator->GetCurrentBinaryDirectory();
   path += "/";
   path += this->Name;
-  path += ".vcxproj";
+  path += this->ProjectFileExtension;
   this->BuildFileStream =
     new cmGeneratedFileStream(path.c_str());
-  this->PathToVcxproj = path;
+  this->PathToProjectFile = path;
   this->BuildFileStream->SetCopyIfDifferent(true);
 
   // Write the encoding header into the file
@@ -339,7 +382,7 @@ void cmVisualStudio10TargetGenerator::Generate()
         (*this->BuildFileStream) << "9";
         }
       (*this->BuildFileStream) << "</NsightTegraProjectRevisionNumber>\n";
-      // Tell newer versions to upgrade silently when loading.
+      // Nsight Tegra 2.0 uses project revision 9.
       this->WriteString("<NsightTegraUpgradeOnceWithoutPrompt>"
                         "true"
                         "</NsightTegraUpgradeOnceWithoutPrompt>\n", 2);
@@ -354,7 +397,10 @@ void cmVisualStudio10TargetGenerator::Generate()
     this->WriteString("</PropertyGroup>\n", 1);
     }
 
-  this->WriteProjectConfigurations();
+  if (csproj != this->ProjectType)
+    {
+    this->WriteProjectConfigurations(); 
+    }
   this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1);
   this->WriteString("<ProjectGUID>", 2);
   (*this->BuildFileStream) <<  "{" << this->GUID << "}</ProjectGUID>\n";
@@ -370,9 +416,15 @@ void cmVisualStudio10TargetGenerator::Generate()
     this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES");
   if(vsProjectTypes)
     {
-    this->WriteString("<ProjectTypes>", 2);
-    (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectTypes) <<
-      "</ProjectTypes>\n";
+    std::string tagName = "ProjectTypes";
+    if (csproj == this->ProjectType)
+      {
+      tagName = "ProjectTypeGuids";
+      }
+    this->WriteString("", 2);
+    (*this->BuildFileStream) << "<" << tagName << ">" <<
+        cmVS10EscapeXML(vsProjectTypes) <<
+        "</" << tagName << ">\n";
     }
 
   const char* vsProjectName =
@@ -474,13 +526,29 @@ void cmVisualStudio10TargetGenerator::Generate()
                              << "</" << globalKey << ">\n";
     }
 
+
+  if (this->Managed)
+    {
+    this->WriteProjectGlobalsManaged();
+    }
+
   this->WriteString("</PropertyGroup>\n", 1);
-  this->WriteString("<Import Project="
-                    "\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n",
-                    1);
+
+  if (csproj == this->ProjectType)
+    {
+    this->WriteString("<Import Project=\"" VS10_CSharp_DEFAULT_PROPS "\" />\n", 1);
+    }
+  else
+    {
+    this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n", 1);
+    }
+
   this->WriteProjectConfigurationValues();
-  this->WriteString(
-    "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n", 1);
+
+  if (csproj != this->ProjectType)
+    {
+    this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1);
+    }
   this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1);
   if (this->GlobalGenerator->IsMasmEnabled())
     {
@@ -489,9 +557,28 @@ void cmVisualStudio10TargetGenerator::Generate()
     }
   this->WriteString("</ImportGroup>\n", 1);
   this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1);
-  this->WriteString("<Import Project=\"" VS10_USER_PROPS "\""
-                    " Condition=\"exists('" VS10_USER_PROPS "')\""
-                    " Label=\"LocalAppDataPlatform\" />\n", 2);
+  {
+  const char* props = 0;
+  if (csproj != this->ProjectType)
+    {
+    props = this->GeneratorTarget->GetProperty("VS_USER_PROPS_CXX");
+    if (!props)
+      {
+      props = VS10_CXX_USER_PROPS;  
+      }
+    }
+  else
+    {
+    props = this->GeneratorTarget->GetProperty("VS_USER_PROPS_CSHARP");
+    }
+  if (props)
+    {
+    this->WriteString("", 2);
+    (*this->BuildFileStream) << "<Import Project=\"" << props << "\"" 
+        << " Condition=\"exists('" << props << "')\"" <<
+        " Label=\"LocalAppDataPlatform\" />\n";
+    }
+  }
   this->WritePlatformExtensions();
   this->WriteString("</ImportGroup>\n", 1);
   this->WriteString("<PropertyGroup Label=\"UserMacros\" />\n", 1);
@@ -506,9 +593,15 @@ void cmVisualStudio10TargetGenerator::Generate()
   this->WriteWinRTReferences();
   this->WriteProjectReferences();
   this->WriteSDKReferences();
-  this->WriteString(
-    "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\""
-    " />\n", 1);
+  if (csproj == this->ProjectType)
+    {
+    this->WriteString("<Import Project=\"" VS10_CSharp_TARGETS "\" />\n", 1);
+    }
+  else
+    {
+    this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1);
+    }
+
   this->WriteTargetSpecificReferences();
   this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1);
   if (this->GlobalGenerator->IsMasmEnabled())
@@ -517,6 +610,26 @@ void cmVisualStudio10TargetGenerator::Generate()
                       "BuildCustomizations\\masm.targets\" />\n", 2);
     }
   this->WriteString("</ImportGroup>\n", 1);
+  if (csproj == this->ProjectType)
+    {
+    bool first = true;
+    for(std::vector<std::string>::const_iterator
+          i = this->Configurations.begin();
+        i != this->Configurations.end(); ++i)
+      {
+      if (first)
+        {
+        this->WriteString("<PropertyGroup>\n", 1);
+        this->WriteEvents(*i);
+        this->WriteString("</PropertyGroup>\n", 1);
+        first = false;
+        }
+      this->WriteString("<PropertyGroup Condition=\"'$(Configuration)'=='", 1);
+      (*this->BuildFileStream) << *i << "'\">\n";
+      this->WriteEvents(*i);
+      this->WriteString("</PropertyGroup>\n", 1);
+      }
+    }
   this->WriteString("</Project>", 0);
   // The groups are stored in a separate file for VS 10
   this->WriteGroups();
@@ -525,29 +638,101 @@ void cmVisualStudio10TargetGenerator::Generate()
 void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
 {
   std::vector<std::string> references;
-  if(const char* vsDotNetReferences =
+  typedef std::pair<std::string, std::string> HintReference;
+  std::vector<HintReference> hintReferences;
+  if (const char* vsDotNetReferences =
      this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES"))
     {
     cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
     }
-  if(!references.empty())
+
+  cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
+  for (cmPropertyMap::const_iterator i = props.begin(); i != props.end(); ++i)
+    {
+    if (i->first.find("VS_DOTNET_REFERENCE_") == 0)
+      {
+      std::string name = i->first.substr(20);
+      if (name != "")
+        {
+        std::string path = i->second.GetValue();
+        if (!cmsys::SystemTools::FileIsFullPath(path))
+        {
+            path = std::string(this->GeneratorTarget->Target->GetMakefile()->GetCurrentSourceDirectory())
+                + "/" + path;
+        }
+        this->ConvertToWindowsSlash(path);
+        hintReferences.push_back(HintReference(name, path));
+        }
+      }
+    }
+  if(!references.empty() || !hintReferences.empty())
     {
     this->WriteString("<ItemGroup>\n", 1);
     for(std::vector<std::string>::iterator ri = references.begin();
         ri != references.end(); ++ri)
       {
-      this->WriteString("<Reference Include=\"", 2);
-      (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n";
-      this->WriteString("<CopyLocalSatelliteAssemblies>true"
-                        "</CopyLocalSatelliteAssemblies>\n", 3);
-      this->WriteString("<ReferenceOutputAssembly>true"
-                        "</ReferenceOutputAssembly>\n", 3);
-      this->WriteString("</Reference>\n", 2);
+      // if the entry from VS_DOTNET_REFERENCES is an existing file, generate
+      // a new hint-reference and name it from the filename
+      if (cmsys::SystemTools::FileExists(*ri, true))
+        {
+        std::string name = 
+            cmsys::SystemTools::GetFilenameWithoutExtension(*ri);
+        std::string path = *ri;
+        this->ConvertToWindowsSlash(path);
+        hintReferences.push_back(HintReference(name, path));
+        }
+      else
+        {
+        this->WriteDotNetReference(*ri, "");
+        }
+      }
+    for (std::vector<std::pair<std::string, std::string> >::const_iterator 
+        i = hintReferences.begin(); i != hintReferences.end(); ++i)
+      {
+      this->WriteDotNetReference(i->first, i->second);
       }
     this->WriteString("</ItemGroup>\n", 1);
     }
 }
 
+void cmVisualStudio10TargetGenerator::WriteDotNetReference(std::string const& ref,
+    std::string const& hint)
+{
+  this->WriteString("<Reference Include=\"", 2);
+  (*this->BuildFileStream) << cmVS10EscapeXML(ref) << "\">\n";
+
+  const char* copy = "true";
+  if (const char* value = this->GeneratorTarget->GetProperty(
+      "VS_COPY_LOCAL_SATELLITE_ASSEMBLIES"))
+    {
+    if (!this->GeneratorTarget->GetPropertyAsBool(
+        "VS_COPY_LOCAL_SATELLITE_ASSEMBLIES"))
+      {
+      copy = "false";
+      }
+    }
+  this->WriteString("<CopyLocalSatelliteAssemblies>", 3);
+  (*this->BuildFileStream) << copy
+      << "</CopyLocalSatelliteAssemblies>\n";
+
+  this->WriteString("<ReferenceOutputAssembly>true"
+                    "</ReferenceOutputAssembly>\n", 3);
+  if (!hint.empty())
+    {
+      this->WriteString("<HintPath>", 3);
+      (*this->BuildFileStream) << hint
+          << "</HintPath>\n";
+      if (const char *priv = this->GeneratorTarget->GetProperty(
+          "VS_REFERENCES_PRIVATE"))
+        {
+        this->WriteString("<Private>", 3);
+        (*this->BuildFileStream) << priv
+            << "</Private>\n";
+        }
+    }
+  this->WriteString("</Reference>\n", 2);
+}
+
 void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
 {
   std::vector<cmSourceFile const*> resxObjs;
@@ -563,22 +748,73 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup()
       this->ConvertToWindowsSlash(obj);
       (*this->BuildFileStream ) << obj << "\">\n";
 
-      this->WriteString("<DependentUpon>", 3);
-      std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
-      (*this->BuildFileStream) << hFileName << "</DependentUpon>\n";
+      if (csproj != this->ProjectType)
+        {
+        this->WriteString("<DependentUpon>", 3);
+        std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
+        (*this->BuildFileStream) << hFileName << "</DependentUpon>\n";
 
-      for(std::vector<std::string>::const_iterator
+        for (std::vector<std::string>::const_iterator
             i = this->Configurations.begin();
-          i != this->Configurations.end(); ++i)
+            i != this->Configurations.end(); ++i)
+          {
+          this->WritePlatformConfigTag("LogicalName", i->c_str(), 3);
+          if (this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"))
+            {
+            (*this->BuildFileStream) << "$(RootNamespace).";
+            }
+          (*this->BuildFileStream) << "%(Filename)";
+          (*this->BuildFileStream) << ".resources";
+          (*this->BuildFileStream) << "</LogicalName>\n";
+          }
+        }
+      else
         {
-        this->WritePlatformConfigTag("LogicalName", i->c_str(), 3);
-        if(this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"))
+        // determine if this is a manually managed resource or if it is generated for other .Designer.cs component
+        std::string fileNameBase = (*oi)->GetFullPath();
+        fileNameBase = fileNameBase.substr(0, obj.length() - 5); // subtract ".resx" from filename
+        if (cmsys::SystemTools::FileExists(fileNameBase + ".cs"))
+          {
+          (*this->BuildFileStream) << "      "
+              << "<DependentUpon>" 
+              << cmsys::SystemTools::GetFilenameName(fileNameBase + ".cs")
+              << "</DependentUpon>\n";
+          }
+        else
+          {
+          fileNameBase.clear();
+          }
+        std::string genOutFile = obj;
+        std::string link;
+        std::string pathname = this->Makefile->GetCurrentSourceDirectory();
+        this->ConvertToWindowsSlash(pathname);
+        if (genOutFile.find(pathname) != std::string::npos)
+          {
+          link = genOutFile;
+          genOutFile = genOutFile.substr(pathname.length() + 1);
+          link = link.substr(pathname.length() + 1);;
+          }
+        else
+          {
+          genOutFile = cmsys::SystemTools::GetFilenameName(genOutFile);
+          }
+        genOutFile = cmsys::SystemTools::GetFilenameName(genOutFile);
+        std::size_t pos = genOutFile.find(".resx");
+        genOutFile.replace(pos, 5, ".Designer.cs");
+        this->ConvertToWindowsSlash(genOutFile);
+        if (fileNameBase.empty())
           {
-          (*this->BuildFileStream ) << "$(RootNamespace).";
+          this->WriteString("<Generator>PublicResXFileCodeGenerator</Generator>\n", 3);
+          (*this->BuildFileStream) << "      "
+              << "<LastGenOutput>" 
+              << genOutFile
+              << "</LastGenOutput>\n";
+          }
+        if (!link.empty())
+          {
+          (*this->BuildFileStream) << "      "
+              << "<Link>" << link << "</Link>\n";
           }
-        (*this->BuildFileStream ) << "%(Filename)";
-        (*this->BuildFileStream ) << ".resources";
-        (*this->BuildFileStream ) << "</LogicalName>\n";
         }
 
       this->WriteString("</EmbeddedResource>\n", 2);
@@ -608,12 +844,27 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup()
         {
         xamlType = "Page";
         }
-
       this->WriteSource(xamlType, *oi, ">\n");
+      if (csproj == this->ProjectType)
+        {
+        std::string filename = obj; 
+        this->ConvertToWindowsSlash(filename);
+        std::string link;
+        std::string pathname = this->Makefile->GetCurrentSourceDirectory();
+        this->ConvertToWindowsSlash(pathname);
+        if (filename.find(pathname) != std::string::npos)
+          {
+          link = filename.substr(pathname.length() + 1);
+          }
+        if (!link.empty())
+          {
+          (*this->BuildFileStream) << "      "
+            << "<Link>" << link << "</Link>\n";
+          }
+        }
       this->WriteString("<SubType>Designer</SubType>\n", 3);
       this->WriteString("</", 2);
       (*this->BuildFileStream) << xamlType << ">\n";
-
       }
     this->WriteString("</ItemGroup>\n", 1);
     }
@@ -686,6 +937,46 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurations()
   this->WriteString("</ItemGroup>\n", 1);
 }
 
+void cmVisualStudio10TargetGenerator::WriteProjectGlobalsManaged()
+{
+  std::string outputType = "<OutputType>";
+  switch (this->GeneratorTarget->GetType())
+    {
+    case cmState::OBJECT_LIBRARY:
+    case cmState::STATIC_LIBRARY:
+    case cmState::SHARED_LIBRARY:
+      outputType += "Library";
+      break;
+    case cmState::MODULE_LIBRARY:
+      outputType += "Module";
+      break;
+    case cmState::EXECUTABLE:
+      if (this->GeneratorTarget->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))
+        {
+        outputType += "WinExe";
+        }
+      else
+        {
+        outputType += "Exe";
+        }
+      break;
+    case cmState::UTILITY:
+    case cmState::GLOBAL_TARGET:
+      outputType += "Utility";
+      break;
+    case cmState::UNKNOWN_LIBRARY:
+    case cmState::INTERFACE_LIBRARY:
+      break;
+    }
+  outputType += "</OutputType>\n";
+  this->WriteString(outputType.c_str(), 2);
+
+  (*this->BuildFileStream) << "    "
+    << "<AppDesignerFolder>"
+    << "Properties"
+    << "</AppDesignerFolder>\n";
+}
+
 void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
 {
   for(std::vector<std::string>::const_iterator
@@ -695,6 +986,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
     this->WritePlatformConfigTag("PropertyGroup",
                                  i->c_str(),
                                  1, " Label=\"Configuration\"", "\n");
+
+    if (csproj != this->ProjectType)
+      {
     std::string configType = "<ConfigurationType>";
     switch(this->GeneratorTarget->GetType())
       {
@@ -736,10 +1030,18 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues()
       }
     configType += "</ConfigurationType>\n";
     this->WriteString(configType.c_str(), 2);
+      }
 
     if(this->MSTools)
       {
-      this->WriteMSToolConfigurationValues(*i);
+      if (!this->Managed)
+        {
+        this->WriteMSToolConfigurationValues(*i);
+        }
+      else
+        {
+        this->WriteMSToolConfigurationValuesManaged(*i);
+        }
       }
     else if(this->NsightTegra)
       {
@@ -812,6 +1114,64 @@ void cmVisualStudio10TargetGenerator
 
 //----------------------------------------------------------------------------
 void cmVisualStudio10TargetGenerator
+::WriteMSToolConfigurationValuesManaged(std::string const& config)
+{
+  cmGlobalVisualStudio10Generator* gg =
+    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+
+  Options& o = *(this->ClOptions[config]);
+
+  if (o.IsDebug())
+    {
+    this->WriteString("<DebugSymbols>true</DebugSymbols>\n", 2);
+    this->WriteString("<DefineDebug>true</DefineDebug>\n", 2);
+    }
+
+  std::string outDir = this->GeneratorTarget->GetDirectory(config.c_str()) + "/";
+  this->ConvertToWindowsSlash(outDir);
+  (*this->BuildFileStream) << "    "
+      << "<OutputPath>" << outDir << "</OutputPath>\n";
+
+  if (o.HasFlag("Platform"))
+    {
+    (*this->BuildFileStream) << "    "
+        << "<PlatformTarget>" << o.GetFlag("Platform") << "</PlatformTarget>\n";
+    o.RemoveFlag("Platform");
+    }
+
+  if(const char* toolset = gg->GetPlatformToolset())
+    {
+    std::string pts = "<PlatformToolset>";
+    pts += toolset;
+    pts += "</PlatformToolset>\n";
+    this->WriteString(pts.c_str(), 2);
+    }
+
+  std::string postfixName = cmSystemTools::UpperCase(config);
+  postfixName += "_POSTFIX";
+  std::string assemblyName = this->GeneratorTarget->GetOutputName(config, false);
+  if(const char* postfix = this->GeneratorTarget->GetProperty(postfixName))
+    {
+    assemblyName += postfix;
+    }
+  (*this->BuildFileStream) << "    "
+    << "<AssemblyName>" << assemblyName << "</AssemblyName>\n";
+
+  if (cmState::EXECUTABLE == this->GeneratorTarget->GetType())
+    {
+    (*this->BuildFileStream) << "    "
+      << "<StartAction>Program</StartAction>\n";
+
+    (*this->BuildFileStream) << "    "
+      << "<StartProgram>" << outDir <<
+      assemblyName << ".exe</StartProgram>\n";
+    }
+
+  o.OutputFlagMap(*this->BuildFileStream, "    ");
+}
+
+//----------------------------------------------------------------------------
+void cmVisualStudio10TargetGenerator
 ::WriteNsightTegraConfigurationValues(std::string const&)
 {
   cmGlobalVisualStudio10Generator* gg =
@@ -1002,6 +1362,11 @@ void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s)
 }
 void cmVisualStudio10TargetGenerator::WriteGroups()
 {
+  if (csproj == this->ProjectType)
+    {
+    return;
+    }
+
   // collect up group information
   std::vector<cmSourceGroup> sourceGroups =
     this->Makefile->GetSourceGroups();
@@ -1028,7 +1393,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
   std::string path =  this->LocalGenerator->GetCurrentBinaryDirectory();
   path += "/";
   path += this->Name;
-  path += ".vcxproj.filters";
+  path += computeProjectFileExtension(this->GeneratorTarget);
+  path += ".filters";
   cmGeneratedFileStream fout(path.c_str());
   fout.SetCopyIfDifferent(true);
   char magic[] = {char(0xEF), char(0xBB), char(0xBF)};
@@ -1306,6 +1672,9 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf)
   std::string shaderEntryPoint;
   std::string shaderModel;
   std::string shaderAdditionalFlags;
+  std::string settingsGenerator;
+  std::string settingsLastGenOutput;
+  std::string sourceLink;
   std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
   if(ext == "hlsl")
     {
@@ -1348,6 +1717,61 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf)
     {
     tool = "XML";
     }
+  else if (ext == "settings")
+    {
+	std::string settingsFullFileName = sf->GetFullPath();
+    settingsLastGenOutput = settingsFullFileName;
+	std::string currentSourceDir = this->Makefile->GetCurrentSourceDirectory();
+	this->ConvertToWindowsSlash(settingsFullFileName);
+    this->ConvertToWindowsSlash(currentSourceDir);
+	// remove path to current source dir (if files are in current source dir)
+    if (settingsFullFileName.find(currentSourceDir) != std::string::npos)
+      {
+      sourceLink = settingsFullFileName.substr(currentSourceDir.length() + 1);
+      settingsLastGenOutput = sourceLink;
+      }
+    std::size_t pos = settingsLastGenOutput.find(".settings");
+    settingsLastGenOutput.replace(pos, 9, ".Designer.cs");
+    settingsGenerator = "SettingsSingleFileGenerator";
+    toolHasSettings = true;
+    }
+  if (csproj == this->ProjectType && !toolHasSettings)
+    {
+	// EVERY extra source file must have a <Link>, otherwise it might not
+    // be visible in Visual Studio at all. The path relative to current
+	// source- or binary-dir is used within the link, if the file is
+    // in none of these paths, it is added with the plain filename without
+	// any path. This means the file will show up at root-level of the csproj
+	// (where CMakeLists.txt etc. are).
+    toolHasSettings = true;
+    std::string fullFileName = sf->GetFullPath();
+	std::string currentCheckDir = this->Makefile->GetCurrentSourceDirectory();
+	this->ConvertToWindowsSlash(fullFileName);
+    this->ConvertToWindowsSlash(currentCheckDir);
+    if (fullFileName.find(currentCheckDir) != std::string::npos)
+      {
+      sourceLink = fullFileName.substr(currentCheckDir.length() + 1);
+      }
+    else
+      {
+      currentCheckDir = this->Makefile->GetCurrentBinaryDirectory();
+      this->ConvertToWindowsSlash(currentCheckDir);
+      if (fullFileName.find(currentCheckDir) != std::string::npos)
+        {
+        sourceLink = "";
+        toolHasSettings = false;
+        }
+      else
+        {
+        // fallback: add plain filename without any path
+        std::size_t p = fullFileName.find_last_of('\\');
+        if (std::string::npos != p)
+          {
+          sourceLink = fullFileName.substr(p+1);
+          }
+        }
+      }
+    }
 
   if(this->NsightTegra)
     {
@@ -1453,6 +1877,25 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf)
       (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags)
                                << "</AdditionalOptions>\n";
       }
+    if (!settingsGenerator.empty())
+      {
+      this->WriteString("<Generator>", 3);
+      (*this->BuildFileStream) << cmVS10EscapeXML(settingsGenerator)
+                               << "</Generator>\n";
+      }
+    if (!settingsLastGenOutput.empty())
+      {
+      this->WriteString("<LastGenOutput>", 3);
+      (*this->BuildFileStream) << cmVS10EscapeXML(settingsLastGenOutput)
+                               << "</LastGenOutput>\n";
+      }
+    if (!sourceLink.empty())
+      {
+      this->WriteString("<Link>", 3);
+      (*this->BuildFileStream) << cmVS10EscapeXML(sourceLink)
+                               << "</Link>\n";
+      }
+
     this->WriteString("</", 2);
     (*this->BuildFileStream) << tool << ">\n";
     }
@@ -1559,6 +2002,10 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
       {
       tool = "ResourceCompile";
       }
+    else if (lang == "CSharp")
+      {
+      tool = "Compile";
+      }
 
     if (!tool.empty())
       {
@@ -1782,6 +2229,112 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
     std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
     (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n";
     }
+  if (csproj == this->ProjectType)
+    {
+    // Two steps are done here:
+	// 1. the <Link> tag is set for all source files in the cmake current source dir
+    //    This has to be done for proper visualization of the files within Visual Studio.
+    // 2. Depending on the  source file extension it is checked if there exists a file
+    //    on which the current soure file depends. the <DependentUpon> tag is set and
+    //    some other additional tags as well (depending on the actual file type).
+    std::string f = source->GetFullPath();
+	typedef std::map<std::string, std::string> CsPropMap;
+	CsPropMap sourceFileTags;
+    //
+    // step 1.: set <Link> tag if necessary
+    //
+    const std::string stripFromPath = this->Makefile->GetCurrentSourceDirectory();
+    if (f.find(stripFromPath) != std::string::npos)
+      {
+      std::string link = f.substr(stripFromPath.length()+1);
+      this->ConvertToWindowsSlash(link);
+      sourceFileTags["Link"] = link;
+      }
+	//
+	// step 2.: set <DependentUpon> tag and some others (if necessary)
+	//
+	static const std::string designerExtension(".Designer.cs");
+    static const std::string xamlExtension(".xaml.cs");
+    const bool isDesignerCs = f.find(designerExtension) != std::string::npos;
+    const bool isXamlCs = f.find(xamlExtension) != std::string::npos;
+    if (isDesignerCs || isXamlCs)
+      {
+      if (isDesignerCs)
+        {
+        f = f.substr(0, f.length() - designerExtension.size());
+        }
+      if (isXamlCs)
+        {
+        f = f.substr(0, f.length() - xamlExtension.size());
+        }
+      if (sourceFileTags.find("Link") == sourceFileTags.end())
+        {
+        sourceFileTags["Link"] = cmsys::SystemTools::GetFilenameName(f);
+        }
+      std::vector<std::string> extensions;
+      extensions.push_back(".cs");
+      extensions.push_back(".resx");
+      extensions.push_back(".settings");
+      extensions.push_back(".xaml");
+      for (std::vector<std::string>::iterator i = extensions.begin();
+          i != extensions.end();)
+        {
+        if (!cmsys::SystemTools::FileExists(f + *i))
+          {
+          i = extensions.erase(i);
+          }
+        else
+          {
+          ++i;
+          }
+        }
+      std::string dependExt;
+      if (extensions.size() != 1)
+        {
+        for (int j = 0; j < extensions.size(); j++)
+          {
+          if (extensions[j] == ".cs")
+            {
+            dependExt = ".cs";
+            break;
+            }
+          }
+        }
+      else
+        {
+        dependExt = extensions[0];
+        }
+      if (dependExt == ".resx")
+        {
+        sourceFileTags["DesignTime"] = "True";
+        sourceFileTags["AutoGen"] = "True";
+        }
+      else if (dependExt == ".settings")
+        {
+        sourceFileTags["DesignTimeSharedInput"] = "True";
+        sourceFileTags["AutoGen"] = "True";
+	    }
+      sourceFileTags["DependentUpon"] = cmsys::SystemTools::GetFilenameName(f) + dependExt;
+      }
+	// 
+	// Write source file specific tags
+	//
+	if (!sourceFileTags.empty())
+      {
+      hasFlags = true;
+      (*this->BuildFileStream) << firstString;
+      firstString = "";
+      for (CsPropMap::const_iterator i = sourceFileTags.begin();
+         i != sourceFileTags.end(); ++i)
+        {
+          (*this->BuildFileStream) << "      "
+            << "<" << i->first << ">"
+            << i->second
+            << "</" << i->first << ">\n";
+          hasFlags = true;
+        }
+      }
+	}
 
   return hasFlags;
 }
@@ -1794,6 +2347,10 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
     {
     return;
     }
+  if (csproj == this->ProjectType)
+    {
+    return;
+    }
 
   this->WriteString("<PropertyGroup>\n", 2);
   this->WriteString("<_ProjectFileVersion>10.0.20506.1"
@@ -1840,6 +2397,13 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
       *this->BuildFileStream << cmVS10EscapeXML(intermediateDir)
                              << "</IntDir>\n";
 
+      if (const char* workingDir = this->GeneratorTarget->GetProperty("VS_DEBUGGER_WORKING_DIRECTORY"))
+        {
+        this->WritePlatformConfigTag("LocalDebuggerWorkingDirectory", config->c_str(), 3);
+        *this->BuildFileStream << workingDir
+            << "</LocalDebuggerWorkingDirectory>\n";
+        }
+
       std::string name =
         cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
       this->WritePlatformConfigTag("TargetName", config->c_str(), 3);
@@ -1872,6 +2436,10 @@ OutputLinkIncremental(std::string const& configName)
     {
     return;
     }
+  if (csproj == this->ProjectType)
+    {
+    return;
+    }
   // static libraries and things greater than modules do not need
   // to set this option
   if(this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY
@@ -1933,10 +2501,19 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
   // much of this was copied from here:
   // copied from cmLocalVisualStudio7Generator.cxx 805
   // TODO: Integrate code below with cmLocalVisualStudio7Generator.
-
-  cmsys::auto_ptr<Options> pOptions(
-    new Options(this->LocalGenerator, Options::Compiler,
-                this->GetClFlagTable()));
+  cmsys::auto_ptr<Options> pOptions;
+  if (this->GlobalGenerator->TargetIsCSharpOnly(this->GeneratorTarget))
+    {
+    pOptions = cmsys::auto_ptr<Options>(
+                 new Options(this->LocalGenerator, Options::Compiler,
+                 this->GetCSharpFlagTable()));
+    }                                                                                     
+  else
+    {
+    pOptions = cmsys::auto_ptr<Options>(
+                 new Options(this->LocalGenerator, Options::Compiler,
+                 this->GetClFlagTable()));
+    }
   Options& clOptions = *pOptions;
 
   std::string flags;
@@ -1950,7 +2527,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
     return false;
     }
   if(linkLanguage == "C" || linkLanguage == "CXX"
-     || linkLanguage == "Fortran")
+     || linkLanguage == "Fortran" || linkLanguage == "CSharp")
     {
     std::string baseFlagVar = "CMAKE_";
     baseFlagVar += linkLanguage;
@@ -1980,16 +2557,32 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
       this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags();
   if(this->MSTools)
     {
-    clOptions.FixExceptionHandlingDefault();
+    int exceptionIndent = 3;
+    if (csproj == this->ProjectType)
+      {
+      exceptionIndent = 2;
+      }
+    clOptions.FixExceptionHandlingDefault(exceptionIndent);
     clOptions.AddFlag("PrecompiledHeader", "NotUsing");
     std::string asmLocation = configName + "/";
-    clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str());
+    if (this->ProjectType != csproj)
+      {
+      clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str());
+      }
     }
   clOptions.Parse(flags.c_str());
   clOptions.Parse(defineFlags.c_str());
   std::vector<std::string> targetDefines;
-  this->GeneratorTarget->GetCompileDefinitions(targetDefines,
-                                      configName.c_str(), "CXX");
+  if (this->ProjectType != csproj)
+    {
+    this->GeneratorTarget->GetCompileDefinitions(targetDefines,
+                                        configName.c_str(), "CXX");
+    }
+  else
+    {
+    this->GeneratorTarget->GetCompileDefinitions(targetDefines,
+                                        configName.c_str(), "CSharp");
+    }
   clOptions.AddDefines(targetDefines);
   if(this->MSTools)
     {
@@ -2038,7 +2631,19 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
       }
     }
 
+  if (csproj != this->ProjectType && clOptions.IsManaged())
+    {
+    this->Managed = true;
+    std::string managedType = clOptions.GetFlag("CompileAsManaged");
+    if (managedType == "Safe")
+      {
+      // force empty calling convention if safe clr is used
+      clOptions.AddFlag("CallingConvention", "");
+      }
+    }
+
   this->ClOptions[configName] = pOptions.release();
+
   return true;
 }
 
@@ -2048,6 +2653,10 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
   std::vector<std::string> const& includes)
 {
   Options& clOptions = *(this->ClOptions[configName]);
+  if (this->ProjectType == csproj)
+    {
+    return;
+    }
   this->WriteString("<ClCompile>\n", 2);
   clOptions.OutputAdditionalOptions(*this->BuildFileStream, "      ", "");
   clOptions.AppendFlag("AdditionalIncludeDirectories", includes);
@@ -2285,7 +2894,7 @@ void cmVisualStudio10TargetGenerator::WriteManifestOptions(
     this->WriteString("</Manifest>\n", 2);
     }
 }
-
+//----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
   std::string const& configName)
@@ -2711,6 +3320,10 @@ cmVisualStudio10TargetGenerator::WriteLinkOptions(std::string const& config)
     {
     return;
     }
+  if (csproj == this->ProjectType)
+    {
+    return;
+    }
   Options& linkOptions = *(this->LinkOptions[config]);
   this->WriteString("<Link>\n", 2);
 
@@ -2762,6 +3375,10 @@ WriteMidlOptions(std::string const& /*config*/,
     {
     return;
     }
+  if (csproj == this->ProjectType)
+    {
+    return;
+    }
 
   // This processes *any* of the .idl files specified in the project's file
   // list (and passed as the item metadata %(Filename) expressing the rule
@@ -2828,7 +3445,10 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups()
     //    output midl flags       <Midl></Midl>
     this->WriteMidlOptions(*i, includes);
     // write events
-    this->WriteEvents(*i);
+    if (csproj != this->ProjectType)
+      {
+      this->WriteEvents(*i);
+      }
     //    output link flags       <Link></Link>
     this->WriteLinkOptions(*i);
     //    output lib flags       <Lib></Lib>
@@ -2899,11 +3519,25 @@ void cmVisualStudio10TargetGenerator::WriteEvent(
     script += cmVS10EscapeXML(lg->ConstructScript(ccg));
     }
   comment = cmVS10EscapeComment(comment);
-  this->WriteString("<Message>",3);
-  (*this->BuildFileStream ) << cmVS10EscapeXML(comment) << "</Message>\n";
-  this->WriteString("<Command>", 3);
+  if (csproj != this->ProjectType)
+    {
+    this->WriteString("<Message>",3);
+    (*this->BuildFileStream ) << cmVS10EscapeXML(comment) << "</Message>\n";
+    this->WriteString("<Command>", 3);
+    }
+  else
+    {
+    if (!comment.empty())
+      {
+      (*this->BuildFileStream) << "echo " << cmVS10EscapeXML(comment) << "\n";
+      }
+    }
   (*this->BuildFileStream ) << script;
-  (*this->BuildFileStream ) << "</Command>" << "\n";
+  if (csproj != this->ProjectType)
+    {
+    (*this->BuildFileStream ) << "</Command>";
+    }
+  (*this->BuildFileStream) << "\n";
   this->WriteString("</", 2);
   (*this->BuildFileStream ) << name << ">\n";
 }
@@ -2932,6 +3566,11 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences()
       {
       continue;
       }
+    if (csproj == this->ProjectType && 
+        !this->GlobalGenerator->TargetIsCSharpOnly(dt))
+      { 
+      continue;
+      }
     this->WriteString("<ProjectReference Include=\"", 2);
     cmLocalGenerator* lg = dt->GetLocalGenerator();
     std::string name = dt->GetName();
@@ -2946,13 +3585,27 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences()
       path =  lg->GetCurrentBinaryDirectory();
       path += "/";
       path += dt->GetName();
-      path += ".vcxproj";
+      path += computeProjectFileExtension(dt);
       }
+    this->ConvertToWindowsSlash(path);
     (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n";
     this->WriteString("<Project>", 3);
+    if (csproj == this->ProjectType)
+      {
+      (*this->BuildFileStream) << "{";
+      }
+    (*this->BuildFileStream)
+      << this->GlobalGenerator->GetGUID(name.c_str());
+    if (csproj == this->ProjectType)
+      {
+      (*this->BuildFileStream) << "}";
+      }
     (*this->BuildFileStream)
-      << this->GlobalGenerator->GetGUID(name.c_str())
       << "</Project>\n";
+    this->WriteString("<Name>", 3);
+    (*this->BuildFileStream)
+      << name
+      << "</Name>\n";
     this->WriteString("</ProjectReference>\n", 2);
     }
   this->WriteString("</ItemGroup>\n", 1);
@@ -3182,7 +3835,7 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings()
       this->WriteString("<ApplicationTypeRevision>", 2);
       (*this->BuildFileStream) << cmVS10EscapeXML("10.0")
                                << "</ApplicationTypeRevision>\n";
-      // Visual Studio 14.0 is necessary for building 10.0 apps
+      // Visual Studio 12.0 is necessary for building 8.1 apps
       this->WriteString("<MinimumVisualStudioVersion>14.0"
         "</MinimumVisualStudioVersion>\n", 2);
 
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 044e0dd..8c5b0d6 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -54,8 +54,10 @@ private:
   void ConvertToWindowsSlash(std::string& s);
   void WriteString(const char* line, int indentLevel);
   void WriteProjectConfigurations();
+  void WriteProjectGlobalsManaged();
   void WriteProjectConfigurationValues();
   void WriteMSToolConfigurationValues(std::string const& config);
+  void WriteMSToolConfigurationValuesManaged(std::string const& config);
   void WriteHeaderSource(cmSourceFile const* sf);
   void WriteExtraSource(cmSourceFile const* sf);
   void WriteNsightTegraConfigurationValues(std::string const& config);
@@ -65,6 +67,8 @@ private:
                     std::vector<cmSourceFile const*> const&);
   void WriteAllSources();
   void WriteDotNetReferences();
+  void WriteDotNetReference(std::string const& ref,
+                   std::string const& hint);
   void WriteEmbeddedResourceGroup();
   void WriteWinRTReferences();
   void WriteWinRTPackageCertificateKeyFile();
@@ -135,6 +139,7 @@ private:
   cmIDEFlagTable const* GetLibFlagTable() const;
   cmIDEFlagTable const* GetLinkFlagTable() const;
   cmIDEFlagTable const* GetMasmFlagTable() const;
+  cmIDEFlagTable const* GetCSharpFlagTable() const;
 
   bool ForceOld(const std::string& source) const;
 
@@ -145,7 +150,12 @@ private:
   OptionsMap RcOptions;
   OptionsMap MasmOptions;
   OptionsMap LinkOptions;
-  std::string PathToVcxproj;
+  std::string PathToProjectFile;
+  std::string ProjectFileExtension;
+  enum VsProjectType {
+      vcxproj,
+      csproj
+  } ProjectType;
   std::vector<std::string> Configurations;
   cmGeneratorTarget* GeneratorTarget;
   cmMakefile* Makefile;
@@ -153,6 +163,7 @@ private:
   std::string GUID;
   std::string Name;
   bool MSTools;
+  bool Managed;
   bool NsightTegra;
   int  NsightTegraVersion[4];
   bool TargetCompileAsWinRT;
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 7bb0721..ab44df4 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -3033,6 +3033,11 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     endif ()
   endif()
 
+  if(MSVC)
+    ADD_TEST_MACRO(CSharp CSharp)
+    #add_test(CSharp )
+  endif()
+  
   if(CMAKE_Fortran_COMPILER)
     add_test(Fortran ${CMAKE_CTEST_COMMAND}
       --build-and-test
-- 
2.7.0.windows.1

