Cannot cast C# enum to C++ enum when enum is in third assembly - c++-cli

I've got a C# class:
public class MyManagedClass
{
public ManagedEnum EnumValue {get; set;}
}
which uses the C# enum
public enum ManagedEnum
{
Enum1,
Enum2
}
This is accessed by a C++/CLI wrapper class and enum:
enum NativeEnum
{
Enum1,
Enum2
};
class WrapperClass
{
public:
WrapperClass(ManagedNamespace::MyManagedClass^ inManaged):
_Managed(inManaged)
{}
NativeEnum GetEnumValue()
{
return (NativeEnum)_Managed->EnumValue;
}
private:
gcroot<ManagedNamespace::MyManagedClass^> _Managed;
};
Now, as long as the C# class and C# enum are in the same assembly, this works fine.
But if the C# enum is in a different C# assembly, the C# class still builds fine, but trying to compile the C++ class yields the error:
error C2440: 'type cast' : cannot convert from 'OtherNamespace::ManagedEnum' to 'OtherNamespace::NativeEnum'
1> Conversion requires a constructor or user-defined-conversion operator, which can't be used by const_cast or reinterpret_cast

Try deriving the underlying value, then cast to the native enum.
This is a crude way of doing it, but may be sufficient in your case.
NativeEnum someMethod(ManagedEnum myEnum)
{
return (NativeEnum)(int)myEnum;
}
Another way is to create a native template method taking both types and the managed enum input, and returning the native type. In such a case, you would have to use reflection to ascertain the underlying type of the managed enum.

In trying out Aaron P's answer, I discovered that the problem was that my C++ project didn't have the C# assembly with the enums in it as a reference. Once I added that reference, it all worked fine.

Related

Property same name as type - can i get rid of the explicit namespace?

This does not compile without explicit namespaces.
namespace A
{
public enum class Foo {};
public interface class Bar
{
public:
property A::Foo Foo
{
virtual A::Foo get();
};
};
} // namespace A
I used the common .NET/C# style to name the type and property identical here. The explicit namespaces are annoying, especially if they are nested/verbose in a real example.
Can i get rid of the explicit namespaces somehow?
Any way to "beautify" this? I tried using/typedef of the enum in the implementation of the property in the .cpp file to get the enum in the surrounding scope. No success.

Using Directx members between c++\CLI assemblies C3767

I am trying to call a member function from a C++/CLI assembly from another one, but when I start using DirectX struct I get C3767 error : candidate function not accessib
from Utilities.dll
#pragma once
#include "define.h"
namespace Utilities
{
public ref class Data
{
public:
BOOL CreateBuffer( LPDIRECT3DDEVICE9 dev)
{
...
return TRUE;
}
{
}
And using it from a renderer
#include "Renderer.h"
namespace SomeNamespace
{
SceneRenderer::SceneRenderer(void)
{
}
void SceneRenderer::Render(LPDIRECT3DDEVICE9 dev)
{
...
m_vbo->CreateBuffer(dev); //error C3767: 'Utilities::Data::CreateBuffer': candidate function(s) not accessible
...
}
}
I know that using the address of the device int* (&dev) I can cast back to a LPDIRECT3DDEVICE9, but im looking for a better solution
A managed C++ assembly will not export unmanaged types in its public interface by default. LPDIRECT3DDEVICE9 is an unmanaged type, so your CreateBuffer method will be marked private, regardless of the access specifier provided (kind of stupid that the compiller isn't even generating a warning about this).
Use #pragma make_public or, better yet, do not use unmanaged types in managed interfaces.
Suggestion: Use slimDx or Xna if you want to use DirectX in managed code. These libraries already provide managed wrappers for everything.

Runtime exception when calling C++/CLI derived class

Edited by the OP 5 August 2014:
Much simplified code:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename) : XmlTextWriter(sFilename, System::Text::Encoding::Unicode)
{
}
~CXmlWriter()
{
}
};
Call a function containing code that instantiates CXmlWriter (you don't have to execute that instantiation code) and you get the exception.
Comment out the destructor and you don't get the exception. Making the destructor virtual doesn't fix it.
End of edit
I am using Version 4 of the .NET framework.
I have C++/CLI classes CXmlWriter derived from System::Xml::XmlTextWriter and CMinMaxXmlWriter derived from CXmlWriter.
Implementation is pretty simple for both classes and everything compiles without error. However, when I try to instantiate CMinMaxXmlWriter at runtime I get a TypeLoadException with the error message:
Declaration referenced in a method implementation cannot be a final method
with a mention of CXmlWriter
This used to work without any problem in Version 2 of the framework.
Here's the header for CXmlWriter:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename);
~CXmlWriter();
!CXmlWriter() {}
virtual bool Open();
virtual void Close() override;
virtual bool WriteValueAndAttribute(System::String ^sElementName, System::String ^sElementValue, System::String ^sAttrName, System::String ^sAttrValue);
virtual bool WriteValueAndAttribute(System::String ^sElementName, double dElementValue, System::String ^sAttrName, System::String ^sAttrValue);
protected:
bool m_bIsOpen;
};
CMinMaxXmlWriter is defined in a very similar way.
Please can someone explain why the exception occurs and what I should do to avoid it.

Different function definition after compilation

I have my Keyboard class:
namespace BSGameFramework
{
namespace Input
{
static public ref class Keyboard
{
public:
static KeyboardState GetState();
};
}
}
Where KeyboardState is a ref struct.
After compilation as dll from my C# application I see the function from metadata as follow:
namespace BSGameFramework.Input
{
public class Keyboard
{
public Keyboard();
public static void GetState(ref KeyboardState value);
}
}
Keyboard class has lost its static state and the function GetState is now returning void and taking a KeyboardState as referenced parameter!
Somebody know why? Thanks in advance :D
The reason is because of the return type, ref struct KeyboardState.
In C++/CLI, the "ref" vs. "value" is the thing that determines whether a type is a reference type or a value type, not "class" vs. "struct". ref class and ref struct are both the same thing as C#'s class. value class and value struct are both the same thing as C#'s struct.
Therefore, you have a C++/CLI method declared as returning a reference type, but without the ^. This data type does exist in C++/CLI, but not in C#. The method signature you see is a workaround.
There are two possible solutions to this issue:
Change KeyboardState to a value struct. From what you said, it sounds like you intended for this to be a value type from the beginning, so this is probably the best solution.
Change the return type of the method to KeyboardState^. This will let the method show up in C# the same as it does in C++/CLI. However, if you do this, you'll want to switch all uses of KeyboardState to KeyboardState^. It's a reference type, it should be used with a ^.

c++ native code using an abstract class into a wrapper

I need to implement a c# GUI for my unmanaged code. So i have designed a wrapper to deal with my native code, but this does not work porperly.
I have a method which requires to make an instance to an abstract class and i'm not sure how to deal with it.
First for my C++ classes i used an abstract class:
class Interface abstract
{
public: Interface (void);
public: ~Interface (void);
public: virtual double Get() = 0;
};
And i used a ClassSpecific1 and a ClassSpecific2 depending on my current application, and i inherited the functions from the abstract class for each one.
class ClassSpecific1 : public Interface
{
public: ClassSpecific1 (void);
public: ~ClassSpecific1 (void);
private: double Get();//based on the abstract class
};
class ClassSpecific2 : public Interface
{
public: ClassSpecific2 (void);
public: ~ClassSpecific2 (void);
private: double Get();//based on the abstract class
};
Later i used another class, it works as a general class and uses the ClassSpecific1 or the ClassSpecific2 with an instance of the abstract class.
class ClassAPI
{
public: ClassLaserAPI(void);
public: ~ClassLaserAPI(void);
public: double Get(Interface *objToInterface);//This Get() calls the Get() in ClassSpecific1 or ClassSpecific2
};
Until here everything seems all right. I have tested everything and works as expected. My big problem is that i don't know how to make my method Get(Interface *objToInterface) from ClassAPI into my wrapper. Do i need to make a wrapper for my abstract class first in order to be able to create the instance**(Interface *objToInterface)** on the wrapper?
This is what i have so far, i hope someone can give me some help, i'm getting lost in how to proceed.
namespace API
{
public __gc class APIManaged
{
public: APIManaged(void);
public: ~APIManaged(void);
/** Unmanaged pointer to ClassAPI
*
*/
private: ClassAPI __nogc* cAPI;
public: double Get(Interface __nogc* objInterface);
};
I'm also having the same problem and got it resolved using this topic:
C++/CLI Inheriting from a native C++ class with abstract methods and exposing it to C#
I too am using an unmanaged abstract class and got things working by following the tips outlined in the link. I ended up with a few errors to fix and fixed them by changing my linker options in my unmanaged projects to not compile with /clr and only the wrapper project compiles using /clr.
Posting your output errors may help clarify some of the troubles you are having...