Domanda

Ho il progetto di C++ (VS2005) che include i file di intestazione con il numero di versione nella direttiva #define.Ora ho bisogno di comprendere esattamente lo stesso numero di twin progetto C#.Qual è il modo migliore per farlo?

Sto pensando su come includere questo file come una risorsa, quindi, di analizzare a runtime con regex per recuperare il numero di versione, ma forse c'è un modo migliore, voi cosa ne pensate?

Non posso spostare versione al di fuori .h file, anche costruire un sistema che dipende da esso, e il C# è un progetto che deve essere adattato.

È stato utile?

Soluzione

È possibile ottenere ciò che si desidera in pochi passaggi:

  1. Creare un'Attività MSBuild - http://msdn.microsoft.com/en-us/library/t9883dzc.aspx
  2. Aggiornare il file di progetto per includere una chiamata al compito creata prima di costruire

Il compito riceve un parametro con la posizione dell'intestazione .h file a cui si fa riferimento.Poi estrae la versione e mettere la versione in C# segnaposto file precedentemente creato.Oppure si può pensare utilizzando AssemblyInfo.cs, che tiene normalmente le versioni di se che è ok per voi.

Se avete bisogno di ulteriori informazioni non esitate a commentare.

Altri suggerimenti

Vorrei considerare l'utilizzo di un .tt file per il processo .h e di trasformarlo in un .cs file.La sua molto facile e il file di origine faranno poi parte del vostro C# soluzione (nel senso che sarà aggiornata con l' .h modifiche di file), è possibile fare clic su per aprire l'editor, etc.

Se hai solo 1 #define potrebbe essere un po ' eccessivo, ma se si dispone di un file pieno di loro (ad esempio, mfc in una risorsa.h forse) allora questa soluzione diventa una grande vittoria.

ad esempio:creare un file, DefineConverter.tt e aggiungere al vostro progetto, modificare la linea marcata di consultare il vostro .h file, e si otterrà una nuova classe nel progetto pieno di static const voci.(nota il file di input è relativo al tuo file di progetto, impostare hostspecific=false se si desidera che i percorsi assoluti).

<#@ 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 dice:

La direttiva #define non può essere utilizzato per dichiarare valori costanti come è in genere fatto in C e C++.Costanti in C# sono meglio definiti come statico i membri di una classe o di una struttura.Se si sono più costanti, in considerazione la creazione di un separato "Costanti" della classe per tenerli.

È possibile creare libreria utilizzando il managed C++ che comprende classe wrapper per le costanti.Quindi è possibile fare riferimento a questa classe da progetto C#.Basta non dimenticare di utilizzare readonly < tipo > invece di const < tipo > per la vostra dichiarazione delle costanti :)

Si può sempre utilizzare l'evento di pre-generazione per eseguire il preprocessore C sul .cs file e il post di costruire evento per annullare il pre-passaggio di generazione.Il preprocessore è solo un testo per la sostituzione di sistema, in modo che questo sia possibile:

// version header file
#define Version "1.01"

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

e il preprocessore genera:

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

È in grado di scrivere semplici C++/C utility che includono questo .h file e creare dinamicamente un file che può essere utilizzato in C#.
Questa utilità può essere eseguita come parte di un progetto C# come una pre-fase di creazione.
In questo modo si sono sempre sincronizzati con il file originale.

Ho scritto uno script python che converte #define PIPPO "bar" in qualcosa di utilizzabile in C# e lo sto usando in una pre-compilazione di passaggio nel mio progetto C#.Funziona.

# 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'

Edificio gbjbaanb soluzione, ho creato un .tt file che trova tutto .h i file in una directory specifica e li rotola in un' .cs file con più classi.

Differenze

  • Ho aggiunto il supporto per il doppio
  • Passato da try-catch per TryParse
  • Si legge di più .h file
  • Gli usi 'readonly' invece di 'const'
  • Finiture #define righe che terminano in ;
  • Spazio dei nomi viene impostato in base .tt posizione in progetto

<#@ 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]#>";
<#          
            }
        }
    } #>
    }
<#}#>     
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top