Is it possible to share an enum declaration between C# and unmanaged C++?
You can use a single .cs file and share it between both projects. #include
in C++ on a .cs file should be no problem.
This would be an example .cs file:
#if !__LINE__
namespace MyNamespace
{
public
#endif
// shared enum for both C, C++ and C#
enum MyEnum { myVal1, myVal2 };
#if !__LINE__
}
#endif
If you want multiple enums in one file, you can do this (although you have to temporarily define public to be nothing for C / C++):
#if __LINE__
#define public
#else
namespace MyNamespace
{
#endif
public enum MyEnum { MyEnumValue1, MyEnumValue2 };
public enum MyEnum2 { MyEnum2Value1, MyEnum2Value2 };
public enum MyEnum3 { MyEnum3Value1, MyEnum3Value2 };
#if __LINE__
#undef public
#else
}
#endif
Is it possible to share an enum class between C++ and C#?
C# preprocessor is way more limited compared to the C++ preprocessor. You can leave C# syntax in the source file, and use C++ preprocessor trickery to make it valid C++ code. Like this:
// enum.cs
public enum MyEnum : int { ONE, TWO, THREE };
And to consume in C++:
// enum-cpp.h
#define public
#define enum enum struct
#include "enum.cs"
#undef enum
#undef public
Sharing an enum from C#, C++/CLI, and C++
Just put your #include "Enum.cs"
directive inside an outer namespace to resolve the naming collision.
EDIT: A variation suggested by Brent is to use #define
to substitute one of the namespaces (or even the enum name itself) declared in the .cs file. This also avoids the naming collision, without making the namespace hierarchy deeper.
How to expose constants from unmanaged C++ to C#
Use the public enum class
keywords to declare a managed enumeration type. And yes, this is ugly since you cannot export the native C++ enumeration. Repeating yourself is unfortunately required.
C++11 adopted the enum class
keyword as well but it is still distinct from the managed version. This caused a syntax ambiguity in C++/CLI since both language flavors now use the same keywords. The compiler can see the distinction from the accessibility keyword (use public
or private
), it is not valid for native C++.
Techniques to keep corresponding native and managed enumerations in sync
Place them into a separate C# file, #include from C++ side. #define away all the C# fluff (like the initial public
). Like this:
#define public
#include "enums.cs"
#undef public
Marshal unmanaged structure with enum member to c#
The enum looks like this:
public enum MMTPCnxNckRsn {
MMTPCnxNckRsn_NoAnswer = -2,
MMTPCnxNckRsn_SendError = -1,
MMTPCnxNckRsn_Ok = 0,
MMTPCnxNckRsn_InvalidMember,
MMTPCnxNckRsn_HubNotReady,
MMTPCnxNckRsn_UnknownMember,
MMTPCnxNckRsn_LastCnxTooRecent,
MMTPCnxNckRsn_InvalidVersion,
MMTPCnxNckRsn_InvalidOptions,
MMTPCnxNckRsn_TooManyCnx
}
The containing struct is:
public struct MMTPConxNack {
public MMTPCnxNckRsn Reason;
}
The union is:
[StructLayout(LayoutKind.Explicit)]
public struct MMTPMsgDataUnion
{
[FieldOffset(0)]
public MMTPConxReq ConxReq;
[FieldOffset(0)]
public MMTPConxAck ConxAck;
[FieldOffset(0)]
public MMTPConxNack ConxNack;
[FieldOffset(0)]
public MMTPErrInd ErrInd;
}
This is the tricky part. You use LayoutKind.Explicit
and FieldOffset
to specify that all the members of the C++ union is overlayed on each other. Obviously you need to have definitions for the other 3 types contained in this union, definitions that we cannot see in the C++ code in the question. I presume you already know how to define those.
Once you have the union declared, the final structure is simple:
public struct MMTPMMsg
{
public int Length;
public short Type;
public MMTPMsgDataUnion Data;
}
c# P/Invoke : Pass Enum value with IntPtr to Function; AccessViolationException
Normally, C++
enumerators are defined as follows:
enum class ENUM_FIELD
{
VAR1,
VAR2,
VAR3,
VAR4
};
By default, enum class types are int
sized, which means that you can translate them to C#
as follows:
public enum EnumField
{
VAR1,
VAR2,
VAR3,
VAR4
}
In such case, both enums will be mapped without problem within the interop environment. But if the C++
enum is defined in a different way, or if the unmanaged method requires a different type, you may need to change the underlying type in your C#
declaration in order to map the values correctly. For example:
public enum EnumField : short
{
VAR1,
VAR2,
VAR3,
VAR4
}
Anyway, I think the problem is not caused by the enum, but rather by what you pass as the const void*
parameter. Casting an enum value to IntPtr
doesn't look right to me:
UInt32 field = (UInt32)EnumField.VAR1;
GCHandle handle = GCHandle.Alloc(field, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
// pass the ptr variable to the unmanaged function
// and don't forget to handle.Free() when you are done
Marshalling C# array of enums to be modified in c++ Code
I managed to get it working. Some of these steps may be unnecessary, but they don't seem to hurt:
I added a SecurityPermission attribute to the top of the function:
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
and wrapped the calling code itself with a fixed block:
fixed (WrapperEnum* ptr_to_enum = &outArray[0]) { DoAThing(ref outArray, length); }
I also, wrapped the enum array in a GCHandle using GCHandle.Alloc and free'd it after the call to ensure it gets cleaned up properly.
Related Topics
What's the Best Way to Do a Backwards Loop in C/C#/C++
Generate PDF from ASP.NET from Raw HTML/CSS Content
Are P/Invoke [In, Out] Attributes Optional for Marshaling Arrays
How to Add Style from Code Behind
Is C# Really Slower Than Say C++
C# Convert Relative to Absolute Links in HTML String
Monodevelop + Naudio + Ubuntu Linux Tells Me Winmm.Dll Not Found
File Exists by File Name Pattern
C++, C# and JavaScript on Winrt
Gridview with Fixed Header and Full Page Width Grid
Multiple Producers, Single Consumer
Cefsharp 3 Set Proxy at Runtime
Detect Browser Close on Asp.Net
Is There Pointer in C# Like C++? Is It Safe