Frage

Ich habe C ++ Projekt (VS2005), die Header-Datei mit der Versionsnummer in # define-Direktive enthält. Jetzt muss ich genau die gleiche Anzahl in Twin C # Projekt enthalten. Was ist der beste Weg, es zu tun?

Ich denke, diese Datei als eine Ressource zu erfahren, wie, dann analysieren sie bei einer Laufzeit mit regex Versionsnummer zu erholen, aber vielleicht gibt es eine bessere Art und Weise, was denken Sie?

Ich kann nicht Version außerhalb .h-Datei verschieben, auch System hängt davon ab, es bauen und das C # Projekt ist eine, die angepasst werden soll.

War es hilfreich?

Lösung

können Sie erreichen, was Sie in nur wenigen Schritten wollen:

  1. Erstellen Sie eine MSBuild-Aufgabe - http://msdn.microsoft.com/ en-us / library / t9883dzc.aspx
  2. die Projektdatei aktualisieren einen Aufruf an die Aufgabe vor geschaffen sind bauen

Die Aufgabe erhält einen Parameter mit der Position des Kopfes .h Sie Datei bezeichnet. Es extrahiert dann die Version und setzt diese Version in einer Platzhalter-Datei C # Sie zuvor erstellt haben. Oder Sie können AssemblyInfo.cs denken verwenden, die normalerweise Versionen gilt, wenn das ok für Sie.

Wenn Sie zusätzliche Informationen benötigen wenden Sie sich frei zu äußern.

Andere Tipps

Ich würde eine .tt Datei mit dem .h zu verarbeiten und sie in eine CS-Datei drehen. Es ist sehr einfach und die Quelldateien werden dann Teil Ihrer C # Lösung sein (was bedeutet, wird sie als die H-Datei Änderungen aktualisiert) angeklickt werden kann im Editor zu öffnen, usw.

Wenn Sie nur 1 #define haben es vielleicht ein wenig übertrieben sein, aber wenn Sie eine Datei voll von ihnen haben (zB ein mfc resource.h Datei vielleicht), dann diese Lösung wird ein großer Gewinn.

zB: Erstellen Sie eine Datei, DefineConverter.tt und fügen Sie es zu einem Projekt, die markierte Zeile ändern, um Ihre .h-Datei zu verweisen, und Sie haben eine neue Klasse im Projekt voll von statischen const Einträgen erhalten. (Beachten Sie die Eingabedatei zu Ihrer Projektdatei relativ ist, gesetzt hostspecific = false, wenn Sie absolute Pfade wollen).

<#@ template language="C#v3.5" hostspecific="True" debug="True" #>
<#@ output extension="cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>

<#
string input_file = this.Host.ResolvePath("resource.h");             <---- change this
StreamReader defines = new StreamReader(input_file);
#>
//------------------------------------------------------------------------------
//     This code was generated by template for T4
//     Generated at <#=DateTime.Now#>
//------------------------------------------------------------------------------

namespace Constants
{
    public class <#=System.IO.Path.GetFileNameWithoutExtension(input_file)#>
    {
<#
    // constants definitions

    while (defines.Peek() >= 0)
    {
        string def = defines.ReadLine();
        string[] parts;
        if (def.Length > 3 && def.StartsWith("#define"))
        {
            parts = def.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
            try {
                Int32 numval = Convert.ToInt32(parts[2]);
                #>
        public static const int <#=parts[1]#> = <#=parts[2]#>;
<#
            }
            catch (FormatException e) {
            #>
        public static const string <#=parts[1]#> = "<#=parts[2]#>";
<#
            }
        }
    } #> 
    }
}

MSDN sagt uns:

  

Die # define-Direktive kann nicht verwendet werden   konstante Werte zu erklären, wie   typischerweise in C und C ++ durchgeführt. Konstanten   in C # am besten als statisch definiert   Mitglieder einer Klasse oder Struktur. Wenn du   mehr solche Konstanten haben, betrachten   eine separate „Konstanten“ class Schaffung   um sie zu halten.

Sie können Bibliothek verwaltete C ++ erstellen, die Klasse umfasst - Wrapper um Ihre Konstanten. Dann können Sie diese Klasse von C # Projekt verweisen. Nur nicht vergessen, zu verwenden, nur lesbar statt const für Ihre Konstanten Deklaration:)

Sie könnten immer das Pre-Build-Ereignis den C-Präprozessor auf der CS-Datei und das Postbuildereignis ausführen, um den Pre-Build-Schritt rückgängig zu machen. Der Präprozessor ist nur ein Text-Substitution System, so ist dies möglich:

// version header file
#define Version "1.01"

// C# code
#include "version.h"
// somewhere in a class
string version = Version;

und der Präprozessor generiert:

// C# code
// somewhere in a class
string version = "1.01";

Sie können einfach C ++ / C-Dienstprogramm schreiben, die diese .h-Datei enthalten und dynamisch Datei erstellen, die in C # verwendet werden kann.
Dieses Dienstprogramm kann als Teil von C # Projekt als Pre-Build-Phase ausgeführt werden.
So sind Sie immer synchronisiert mit der Originaldatei.

Ich schrieb einen Python-Skript, die #define FOO „bar“ in etwas Brauchbares in C # konvertiert und ich verwende es in einem Pre-Build-Schritt in meiner C # -Projekt. Es klappt.

# translate the #defines in messages.h file into consts in MessagesDotH.cs

import re
import os
import stat

def convert_h_to_cs(fin, fout):
    for line in fin:
        m = re.match(r"^#define (.*) \"(.*)\"", line)
        if m != None:
            if m.group() != None:
                fout.write( "public const string " \
                + m.group(1) \
                + " = \"" \
                + m.group(2) \
                + "\";\n" )
        if re.match(r"^//", line) != None:
            fout.write(line)

fin = open ('..\common_cpp\messages.h')
fout = open ('..\user_setup\MessagesDotH.cs.tmp','w')

fout.write( 'using System;\n' )
fout.write( 'namespace xrisk { class MessagesDotH {\n' )

convert_h_to_cs(fin, fout)

fout.write( '}}' )

fout.close()

s1 = open('..\user_setup\MessagesDotH.cs.tmp').read()

s2 = open('..\user_setup\MessagesDotH.cs').read()

if s1 != s2:
    os.chmod('..\user_setup\MessagesDotH.cs', stat.S_IWRITE)
    print 'deleting old MessagesDotH.cs'
    os.remove('..\user_setup\MessagesDotH.cs')
    print 'remaming tmp to MessagesDotH.cs'
    os.rename('..\user_setup\MessagesDotH.cs.tmp','..\user_setup\MessagesDotH.cs')
else:
    print 'no differences.  using same MessagesDotH.cs'

Aufbauend auf gbjbaanb-Lösung, habe ich eine .tt Datei, die alle H-Dateien in einem bestimmten Verzeichnis findet und rollt sie in eine CS-Datei mit mehreren Klassen.

Die Unterschiede

  • I Unterstützung für Doppel
  • Switched von Try-Catch zu TryParse
  • Liest mehrere H-Dateien
  • Verwendet 'Read-only' anstelle von 'const'
  • Borte #define Linien, die in beenden;
  • Namespace wird basierend auf .tt Lage im Projekt

<#@ template language="C#" hostspecific="True" debug="True" #>
<#@ output extension="cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#
string hPath = Host.ResolveAssemblyReference("$(ProjectDir)") + "ProgramData\\DeltaTau\\";  
string[] hFiles = System.IO.Directory.GetFiles(hPath, "*.h", System.IO.SearchOption.AllDirectories);
var namespaceName = System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint");
#>
//------------------------------------------------------------------------------
//     This code was generated by template for T4
//     Generated at <#=DateTime.Now#>
//------------------------------------------------------------------------------

namespace <#=namespaceName#>
{
<#foreach (string input_file in hFiles)
{
StreamReader defines = new StreamReader(input_file);
#>
    public class <#=System.IO.Path.GetFileNameWithoutExtension(input_file)#>
    {
<#    // constants definitions

    while (defines.Peek() >= 0)
    {
        string def = defines.ReadLine();
        string[] parts;
        if (def.Length > 3 && def.StartsWith("#define"))
        {
            def = def.TrimEnd(';');
            parts = def.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
            Int32 intVal;
            double dblVal;
            if (Int32.TryParse(parts[2], out intVal))
            {
            #>
        public static readonly int <#=parts[1]#> = <#=parts[2]#>;           
<#
            }
            else if (Double.TryParse(parts[2], out dblVal))
            {
            #>
        public static readonly double <#=parts[1]#> = <#=parts[2]#>;            
<#
            }
            else
            {
            #>
        public static readonly string <#=parts[1]#> = "<#=parts[2]#>";
<#          
            }
        }
    } #>
    }
<#}#>     
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top