Pregunta

He proyecto de C++ (VS2005) que incluye el archivo de cabecera con el número de versión en la directiva #define.Ahora tengo que incluye exactamente el mismo número de camas proyecto de C#.¿Cuál es la mejor manera de hacerlo?

Estoy pensando en la inclusión de este archivo como un recurso, a continuación, analizar en tiempo de ejecución con regex para recuperar el número de versión, pero tal vez hay una manera mejor, ¿qué te parece?

No me puedo mover versión fuera .h archivo, también en el sistema de compilación depende de ello y el proyecto de C# es uno que debe ser adaptado.

¿Fue útil?

Solución

Usted puede lograr lo que desee en pocos pasos:

  1. Crear una Tarea de MSBuild - http://msdn.microsoft.com/en-us/library/t9883dzc.aspx
  2. Actualizar el archivo de proyecto para incluir una llamada a la tarea de crear antes de construir

La tarea recibe un parámetro con la ubicación de la cabecera .h de archivo se refiere.Que, a continuación, extractos de la versión y puesto que la versión en C# archivo de marcador de posición que previamente hemos creado.O usted puede pensar en el uso de AssemblyInfo.cs que normalmente contiene versiones si que está bien para usted.

Si usted necesita más información, por favor siéntase libre de hacer comentarios.

Otros consejos

Me gustaría considerar el uso de un .tt archivo de proceso de la .h y convertirlo en una .cs archivo.Es muy fácil y los archivos de origen que luego van a ser parte de su solución de C# (lo que significa que se pueden actualizar como el .h los cambios en el archivo), puede hacer clic en abrir en el editor, etc.

Si sólo tienes 1 #define podría ser un poco demasiado, pero si usted tiene un archivo completo de ellos (por ejemplo, un mfc de recursos.h archivo tal vez), entonces esta solución se convierte en una gran victoria.

por ejemplo:crear un archivo, DefineConverter.tt y agregar a su proyecto, el cambio de la línea marcada para referirse a su .h archivo, y tendrás una nueva clase en el proyecto completo de static const entradas.(nota: el archivo de entrada es relativo a su archivo de proyecto, establecer hostspecific=false si desea rutas absolutas).

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

La directiva #define no se puede utilizar para declarar los valores constantes como es normalmente se hace en C y C++.Constantes en C# se define mejor como una estática los miembros de una clase o estructura.Si tiene varias de estas constantes, considere la posibilidad de la creación de una "Constantes" de la clase para contenerlos.

Usted puede crear biblioteca de C++ administrado que incluye la clase de contenedor alrededor de sus constantes.A continuación, puede hacer referencia a esta clase de proyecto de C#.Sólo no olvides usar readonly < type > en lugar de const < type > por sus constantes declaración :)

Siempre se puede usar el pre-evento de generación para ejecutar el preprocesador de C en el .cs archivo y en el post de eventos de generación para deshacer la generación previa de paso.El preprocesador es solo un texto de sustitución de sistema, así que esto es posible:

// version header file
#define Version "1.01"

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

y el preprocesador generará:

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

Usted puede escribir simple C++/C utilidad que se incluyen en esta .h archivo y crear dinámicamente el archivo que puede ser utilizado en C#.
Esta utilidad se puede ejecutar como parte de un proyecto de C# como una pre-etapa de construcción.
De esta manera usted siempre están sincronizados con el archivo original.

Escribí un script de python que se convierte #define FOO "bar" en algo utilizable en C# y lo estoy usando en un pre-construir paso en mi proyecto de C#.Funciona.

# 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 en gbjbaanb la solución, he creado un .tt archivo que encuentre todos .h archivos en un directorio específico y rollos en una .cs archivo con varias clases.

Las diferencias

  • He añadido soporte para el dobles
  • Pasó de try-catch para TryParse
  • Lecturas múltiples .h archivos
  • Utiliza 'readonly' en lugar de 'const'
  • Adornos #define las líneas que terminan en ;
  • Espacio de nombres se basa en .tt ubicación en el proyecto

<#@ 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]#>";
<#          
            }
        }
    } #>
    }
<#}#>     
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top