Reuse define statement from.h file in C # code

I have a C ++ project (VS2005) that includes a header file with the version number in the #define directive. Now I need to include exactly the same number in the Twin C # project. What is the best way to do this?

I'm going to include this file as a resource and then parse it at runtime with a regex to restore the version number, but maybe there is a better way, what do you think?

I cannot move the version outside of the .h file, it also depends on it, and a C # project that needs to be adapted.

+6
c ++ c # c-preprocessor versioning header
source share
7 answers

You can achieve what you want in just a few steps:

The task receives a parameter with the location of the .h header file that you specified. Then it extracts the version and puts that version in the C # placeholder file that you previously created. Or you might think using AssemblyInfo.cs, which usually contains versions if that is ok for you.

If you need more information, feel free to comment.

+2
source share

I would like to use the .tt file to process the .h and turn it into a .cs file. Its very easy and the source files will become part of your C # solution (which means that they will be updated as the .h file changes), you can click to open it in an editor, etc.

If you have only 1 #define, this may be a bit crowded, but if you have a complete file (for example, the mfc resource.h file), then this solution will be a big win.

for example: create a DefineConverter.tt file and add it to your project, change the marked line to access your .h file, and you will get a new class in your project, full of static const entries. (note that the input file refers to your project file, set hostpecific = false if you want absolute paths).

<#@ 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]#>"; <# } } } #> } } 
+5
source share

MSDN tells us:

The #define directive cannot be used to declare constant values, as a rule, it is executed in C and C ++. Constants in C # are best defined as static members of a class or structure. if you have several such constants, consider creating a separate class "Constants" to hold them.

You can create a library using managed C ++, which includes a wrapper wrapper around your constants. You can then reference this class from a C # project. Just remember to use readonly <type> instead of const <type> for your const declaration :)

+3
source share

You can always use the pre-build event to fire the C preprocessor in the .cs file and the post build event to undo the pre-build step. A preprocessor is just text substitution, so it’s possible:

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

and the preprocessor will generate:

 // C# code // somewhere in a class string version = "1.01"; 
+2
source share

You can write a simple C ++ / C utility that includes this .h file and dynamically create a file that can be used in C #.
This utility can be launched as part of a C # project as a pre-build phase.
This way you are always in sync with the source file.

+1
source share

I wrote a python script that converts #define FOO "bar" to something used in C # and I use it in the pre-build phase of my C # project. It works.

 # 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' 
0
source share

Based on the gbjbaanb solution, I created a .tt file that finds all the .h files in a specific directory and translates them into a .cs file with several classes.

Differences

  • I added double support
  • Switching from try-catch to TryParse
  • Reads several .h files.
  • Uses 'readonly' instead of 'const'
  • Trim #define lines that end in ;
  • The namespace is set based on the .tt location in the project

 <#@ 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]#>"; <# } } } #> } <#}#> } 
0
source share

All Articles