C++/CLI managed Enum appears empty in CSharp

G

Guest

I'm trying to define an enum which will be used from unmanaged c++, C++/CLI
managed c++ and from C#.
I defined the following enum in a VS dll project set to be compiled with the
/clr switch:

public enum Days
{
Sunday
};

After building the project, I added the created DLL as a reference in a C#
project.
Trying to use this enum from inside the C# project, Days itself was visible
but none of its fields (Sunday) existed (Days was empty).
For verification, I right clicked on the DLL reference and selected "View in
Object Browser". Again, "Days" existed but was empty - Sunday simply wasn't
there.
I tried creating an enum class in the CLI managed c++ project:
public enum class Days
{
Sunday
};

And both the enum itself and its fields were visible and usable from C#.
However this cannot be my solution because the "enum class" cannot be used
from unmanaged c++.

The enum class reference on MSDN
(http://msdn2.microsoft.com/en-us/library/a6cskb49(VS.80).aspx) states:
"A named, standard enum compiled with /clr will be visible in the assembly
as a managed enum, and can be consumed by any other managed compiler."

How can I make Sunday accessible from C#?

Thanks in advance.
 
G

Guest

Hi Bruno,

I read the MSDN page you mentioned (I also referenced it in my post). The
problem is, as I mentioned in my question, that from inside C#, the enum
seems empty.
This code in CLI:

public enum Days
{
Sunday
};

Producing the following metadata:

public enum Days
{
}

- An empty enum. I know this contradicts what is written in the MSDN page
you mentioned.
Can you please explain why this happens.
 
M

Marcus Heege

Hi Marcus,
OOps It seems I read that question too quick.

Here is some background info:

For native types like structs, classes, enums, and unions, the C++/CLI
compiler generates managed wrapper types as soon as these are used in
managed code. However, these wrapper types are more primitive as one might
think. For structs, classes, and unions, they are value types without any
fields. Only the native size of the struct, class, or union is specified in
the metadata. For enums, a managed enum is created, however, it only
contains the standard field to store the value.

Here is the solution that I would suggest:

To see the enum values on both sides, you should define two enums:

In your assembly a public managed enum:
public enum class E
{ a, b, c };

In the header that is included in C++ projects, an equivalent native enum:
#ifndef _MANAGED
enum E
{ a, b, c };
#else
#using "yourAssembly.dll"
#endif

If the header is included in a file compiled with /clr:* or, the managed
enum will be visible, because
#using "yourAssembly.dll"
will be compiled with your code.
If the header is included in a file complied without /clr:*, the native enum
will be defined.
 
G

Guest

Hi Marcus,

Thanks alot for all the background information!
Your solution creates a double definition of the enum (This enum is defined
in two different places) and so, might create a problem in the future when
someone changes one enum and doesn't know he should also change the other one
accordingly.
This's why I wanted all factors to use the same enum definition.

The solution I used temporarly is:
enum Days
{
Day_Sunday,
Day_Monday
};

public enum class ManagedDays
{
Sunday = Day_Sunday,
Monday = Day_Monday,
};

This way values of the items in both enums corresponds.
I'll keep looking for a way to define only one enum which will be usable by
all. If I do find such a way, I'll post it in this thread.

Again, thanks for your help!
 
M

Marcus Heege

I guess I have to agree that there is no good solution to this problem ...

Marcus
 
M

Marcus Heege

Marcus Heege said:
I guess I have to agree that there is no good solution to this problem ...

Marcus
One last attempt. How about this:

[assembly: ComVisible(false)] // ensure that all other types do not end up
in the COM type library

[ComVisible(true)] // ensure that the enum type ends up
in the COM type library
public enum class Days
{
Monday, // ...
};

Managed clients can use this by just referencing the assembly. Native
clients can use this enum via #import.
 
B

Ben Voigt

Marcus Heege said:
I guess I have to agree that there is no good solution to this problem ...

#include the same header file twice, with different #defines:

#define ENUMDECL enum class
#include "enumdef.h"
#undef ENUMDECL

#define ENUMDECL enum
#include "enumdef.h"
#undef ENUMDECL
 
M

Marcus Heege

Ben Voigt said:
#include the same header file twice, with different #defines:

#define ENUMDECL enum class
#include "enumdef.h"
#undef ENUMDECL

#define ENUMDECL enum
#include "enumdef.h"
#undef ENUMDECL

The problem with this approach is that it break the rules of managed type
identity. Including this header in two different projects would produce two
different managed enums.

Marcus
 
B

Ben Voigt

Marcus Heege said:
The problem with this approach is that it break the rules of managed type
identity. Including this header in two different projects would produce
two different managed enums.

The header file is for the library and native clients (with appropriate
preprocessor conditionals to remove the C++/CLI definitions when used from
standard C++), while managed clients don't use #include at all but #import.
 
G

Guest

Dear Ben,

My solution includes a managed project (compiled with /clr), which is linked
to a DLL.
I have two classes in this DLL: a native worker and its managed (ref) wrapper.
This's why I need an enum which can be used by C# (which references this
library), managed c++ and native c++.
I already tried your solution (to include the header with the enum
definition twice). It causes a linkage error because both the native enum and
the managed enum are exported and visible for the DLL clients and therefore
cannot have the same name.
The problem is that the native enum is exported empty and its fields are not
exported.

I'm still battling this one and the temporary solution I mentioned a few
posts back is becoming more and more permanent...

Any suggestion will be appreciated.
 
B

Ben Voigt

Cmtk Software said:
Dear Ben,

My solution includes a managed project (compiled with /clr), which is
linked
to a DLL.
I have two classes in this DLL: a native worker and its managed (ref)
wrapper.
This's why I need an enum which can be used by C# (which references this
library), managed c++ and native c++.
I already tried your solution (to include the header with the enum
definition twice). It causes a linkage error because both the native enum
and
the managed enum are exported and visible for the DLL clients and
therefore
cannot have the same name.
Can you just give them different names, via a second #define?

Or else put them inside different namespaces?

namespace dotnet {
#define ENUMDECL enum class
#include "enumdef.h"
#undef ENUMDECL
}
namespace native {
#define ENUMDECL enum
#include "enumdef.h"
#undef ENUMDECL
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top