I'm writing two processes using C# and WCF for one and C++ and WWSAPI for the second. I want to be able to define the address being used for communication between the two in a single place and have both C# and C++ use it. Is this possible?
The closest I've come is defining the constant in an IDL, then using MIDL and TLBIMP to get it into a DLL that can be consumed by C#. However this doesn't seem to expose the constant, or at least I can't figure out how to make it do so. Maybe it is limited to type definitions only.
Any other suggestions?
You can create a separate C++/CLI project and define all your constants in a .h
file. For example, create C++/CLI Class Library project called "ConstantBridge" and a C# project called "CSharpProgram":
namespace Constants
{
const int MAGIC_NUMBER = 42;
}
// String literals must be defined as macros
#define MAGIC_PHRASE "Hello World"
// Since stirngs must be macros it's arguably more consistent
// to use `define` throughout. This is for demonstration purpose.
#include "Constants.h"
namespace ConstantBridge { public ref class ConstantBridge {
public:
// The use of the `literal` keyword is important
// `static const` will not work
literal int kMagicNumber = Constants::MAGIC_NUMBER;
literal String ^ kMagicPhrase = MAGIC_PHRASE;
};}
Console.WriteLine(ConstantBridge.kMagicNumber); // "42"
Console.WriteLine(ConstantBridge.kMagicPhrase); // "Hello World"
Now, have the "CSharpProgram" project reference the "ConstantBridge" project. Your other native C++ projects can simply #include "Constants.h"
.
As long as you reference only literal
s from the ConstantBridge
project, a runtime dependency will not be generated. You can verify using ILSpy or ILdasm. const
in C# and literal
in C++/CLI are copied "literally" to the call site during compilation.
C# and C++ have differing models for constants. Typically, the constant won't even be emitted in the resulting C++ binary -- it's automatically replaced where it is needed most of the time.
Rather than using the constant, make a function which returns the constant, which you can P/Invoke from C#.
Thus,
#include <iostream>
const double ACCELERATION_DUE_TO_GRAVITY = 9.8;
int main()
{
std::cout << "Acceleration due to gravity is: " <<
ACCELERATION_DUE_TO_GRAVITY;
}
becomes
#include <iostream>
extern "C" double AccelerationDueToGravity()
{
return 9.8;
}
int main()
{
std::cout << "Acceleration due to gravity is: " <<
AccelerationDueToGravity();
}
which you should be able to P/Invoke from C#.
Wasn't happy with the other solutions for my use case so coded up a slightly hacky solution that seems to fit the original request better; a constant in one file that can be built into both a C# and a C++ project...
Like this:
// Version.cs
public static class MyAppVersion
{
//build
public static string Number = "1.0";
public static string Phase = "Alpha";
//configuration (these are the build constants I use, substitute your own)
#if BUILD_SHIPPING
public static string Configuration = "Shipping";
#elif BUILD_DEVELOPMENT
public static string Configuration = "Development";
#elif BUILD_DEBUG
public static string Configuration = "Debug";
#else
"build type not defined"
#endif
}
#include
Like this:
//include version information into a .cpp
#define class namespace
#define public
#define static
#define string const char*
#include "..\..\Version.cs" //or to where-ever your file is
;
#undef class
#undef public
#undef static
#undef string
MyAppVersion.Number
MyAppVersion::Number
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With