CppHeaderToCSharpConverter
A compile-time tool for converting C/C++ header constants, enums, and structures to C#.
Install / Use
/learn @SunsetQuest/CppHeaderToCSharpConverterREADME
Passing C/C++ Constants, enums, and structs to C# at compile time
A compile-time tool for converting C/C++ header constants, enums, and structures to C#.
Original Article CppHeader2CS by Ryan Scott White Rating: 4.81 (24 votes)
- Latest releases
- Past .NET 4 source - 16 KB (MD5 hash: 2b424e4deb7b2ee0e0034845f85ae58d)
- Past .NET 4 executable - 10 KB (MD5 hash: 15f6f4fa221e8b64cfba71d5d9877f0f)
Introduction
This command line tool extracts C/C++ constants, predefinitions, structs, and enums from a C/C++ header file and then outputs it to a C# file. This tool is not a full featured C/C++ to C# converter - it does not convert functions to C#. This tool is meant to copy header information from a C/C++ file to a C# file so that constants, predefinitions, structs, and enums can be shared between C/C++ project and C# projects. This conversion would typically be done using Visual Studio's pre-build command line events. The goal is to keep one set of constants and enums for both a C/C++ and C# project. These constants and enums are extracted from a given C/C++ file, converted, and are then written to a generated C# file that is usually already added to a C# project. The conversion is extremely quick so it should not have much impact on your total compile time.
Since C# does not support predefinitions at the same level as C/C++, the program converts #define values to C# constants in a default class. Since the C/C++ #define values are typeless, CppHeader2CS tries to figure out the best constant type to use for the C# output. In a nutshell, it first tries parsing an int, followed by a float, followed by bool, and if all else fails it just saves it as a string. Example: #Define cat 5 is translated into public const int cat = 5; whereas #define cat 5.0 is translated into public const float cat = 5;. Any type can also be forced by appending the C2CS_TYPE command in a comment following the #define. For Example, #Define cat 5 // C2CS_TYPE: float is translated to public const float cat = 5;.
To accomplish the conversions Regular Expressions are used to gather the information, then the data is converted into to its C# equivalent and then saved into one of three destination areas. The three C# destination areas are the top, namespace, and class area. (see orange boxes in diagram) StringBuilders are used to gather the converted three areas. The first, 'Top Area' StringBuilder writes to the very top of the C# file. This can be something like using system.IO; and added by using a special command in the C/C++ source file, //C2CS_Top_Write using system.IO;. The second StringBuilder outputs to the namespace area and would typically consist of structs and enums. The final location is in a default class area and this mainly holds constants. In the end, these are merged into one document and are outputted either to a file or to the console. Below you will find an output image with some orange boxes on it. Each orange box represents a StringBuilder.
Inspiration
In the past, I have had many instances where I had a need to pass constants, enums or simple structures from a C/C++ to a C# project. Searching online, I could not find anything that would do what I wanted. Other solutions were full C/C++ to C# conversions that were too slow to run on each compile. I did find a nice T2 templates project that did some of the stuff I wanted but overall the T2 template was hard to read and do not support the functionality I needed. I decided on a regular expressions approach. RegEx can be a little annoying and hard to read but they work great for some problems.
Using the code
Usage Instructions
-
Copy the CppHeader2CS.exe file to some location
-
Open the Project Properties for the C# project and then navigate to the Build Events Section.
-
In the Pre-build event command line enter something like the following: _C:\[tool location]\CppHeader2CS.exe "$(ProjectDir)MyInput.h" "$(ProjectDir)myCppSharedItems.cs"_Depending on your needs you will need to adjust the file names and locations above. Visual Studio helps with this using the macros button.
Command Line Usage
CppHeader2CS.exe input_file.h \[output_file.cs]
input_file - this is the C/C++ source header file. It should be a simple file meant for the C/C++ to C# sharing.
output_file - (optional) This is the name of the C# output file. If a name is not supplied it will use the input filename with a cs extension.
Command Line Help
This program supports a number of commands that can be entered in the source file. The commands are added by adding them like comments. Example: // C2CS_TYPE MyType These can be used to write or adjust the output. The three C2CS_*_Write commands can be used to write anything in the C# file using comments in the C/C++ source file. The other options can be used to set a custom namespace or class name as well as force a type or skip a line in the source all together.
CppHeader2CS.exe -h
_// C2CS_TOP_Write text to write - C2CS_TOP_Write is a direct pass-through that writes text above the namespace. This can be useful whenever there is a need to print at the top of the output file. Example: _//C2CS_TOP_Write using System.IO;
_// C2CS_NS_Write text to write - C2CS_NS_Write is a direct pass-through that writes text above the default class but in the namespace area. This area usually contains enums and structs.
_// C2CS_Class_Write text to write - C2CS_Class_Write is a direct pass-through that writes text in the class area. CppHeader2CS writes only to a single class.
_// C2CS_Set_Namespace MyNsName - C2CS_Set_Namespace sets the namespace name. This is optional and if unspecified defaults to C2CS.
_// C2CS_Set_ClassName MyClass - C2CS_Set_ClassName sets the class name to use. This is optional and if unspecified defaults to Constants.
_// C2CS_TYPE MyType - C2CS_TYPE is used in the comments after a #define to specify what type to use. This is required if the automatic detection does not work as expected or the programmer wants to force a type. Example: _#Default mySum (2+1) //C2CS_TYPE int;
_// C2CS_SKIP - Adding C2CS_SKIP in any comment forces CppHeader2CS to ignore the current line.
Examples
Example 1 - #define ->int
#DEFINE MyDouble 3.2
...gets added to the class area as...
public const double MyDouble = 3.2f;
Points of Interest
- automatically recognized as an int.
Example 2 - #define ->float
#DEFINE expr1 my_float + 2
...gets added to the class area as...
public const float expr1 = my_float + 2;
Points of Interest
-
#DEFINE will always get translated to lower case
-
#DEFINE MyFloat 3.2f with the "f" will result in a float output.
-
#DEFINE MyFloat 3.2d with the "d" will result in a double output.
-
when no suffix is given the output will be double
-
scientific notation is supported
Example 3 - #define -> handles very simple expressions
Given my_float is an existing float...
#DEFINE expr1 my_float + 2
...gets added to the class area as...
public const float expr1 = my_float + 2;
Points of Interest
-
The converter recognized that this must be a float. It is very limited however as it only works with +, -, /, * and for logic true, false, &&, ||
-
If it does not auto-detect as expected, the command // C2CS_TYPE MyType can always be used.
Example 4 - #define -> string
#DEFINE MyString New World Test!
...gets added to the class area as...
public const string MyString = "New World Test!";
Points of Interest
- If int.TryParse, float.TryParse, and bool.TryParse all fail then type string is used
Example 5 - simple #define with no value
#DEFINE FullDebug
is slightly modified and moved to the top...
#define FullDebug
Points of Interest
-
not shown, but #define is moved near the top of the C# file (as required by C#)
-
case was change to lowercase
Example 6 - Struct
// C2CS_NS_Write [StructLayout(LayoutKind.Sequential)]
struct SomeStruct1{unsigned char a; unsigned char b;};
...gets added to the namespace area as...
[StructLayout(LayoutKind.Sequential)]
public struct SomeStruct1
{
public byte a;
public byte b;
}
Points of Interest
-
Here we prefix a // C2CS_NS_Write [StructLayout(LayoutKind.Sequential)] This will cause the struct to be laid out more like a C/C++ struct. Only add this if you need it.
-
Single line structs are supported but they get converted to standard format.
-
Only basic items are supported here like int, short, long, long long, char, char*, unsigned, floats, and doubles.
Example 7 - Struct #2
struct SomeStruct1{
unsigned long long test123; //some comments
public long test124;
} someStruct1Instance; // my instance notes
...gets added to the namespace area as...
public struct SomeStruct1
{
public ulong test123; //some comments
public long test124;
}
...and the following also get added to the class section...
public SomeStruct1 someStruct1Instance; // my instance notes
Points of Interest
- '//' style comments are brought over when on the s
