Some questions about writing a C++/CLI Wrapper

raygeee

01-01-2009 14:10:52

Hello everyone,

currently I am trying to write a small wrapper for PagedGeometry and I'm having some difficulties with the language. Maybe some of you guys with C++ knowledge can help me out? Some of my problems seem to be a general understanding problem, not a specific bug.
I'm used to write code in VB.NET or C#, in C++/CLI I can at least understand the code but I'm not completely familiar with the syntax.

I've got the wrapper class MPagedGeometry which has the following code in it:
public ref class MPagedGeometry : System::IDisposable {
private:
Forests::PagedGeometry* internalPagedGeometry;
public:
MPagedGeometry(Mogre::Camera ^cam, float pageSize) {
Ogre::Camera* cm = (Ogre::Camera*)cam;
internalPagedGeometry = new Forests::PagedGeometry(cm, pageSize);
}

void SetCamera(Mogre::Camera ^cam) {
Ogre::Camera* cm = (Ogre::Camera*)cam;
internalPagedGeometry->setCamera(cm); <--crashes here with AccessViolationException
}

In my VB.NET class I call the following (I translated it to C# to make it easier):
MForests.MPagedGeometry trees = new MForests.MPagedGeometry();
trees.SetCamera(camera);

When I call the first line (constructor), a new Forests::PagedGeometry instance gets created correctly as I can see in the debugger. The variable internalPagedGeometry is set. Now when I call the second line (SetCamera), I get an AccessViolationException. I understand the reason why this exception is thrown is because of the internal variable not set - the debugger tells me <undefined value>. But WHY is this? Why does the pointer loose the object? As far as I understand the code isn't very complicated. I tried to follow the wrapper patterns like in MET where it is exactly like that but working. Is it because of any specific C++/CLI environment setting?

My second problem is a pointer or cast issue:
// MPagedGeometry.h:
void SetPageLoader(MPageLoader ^loader) {
Forests::PageLoader* pl = *loader->_GetNativePtr(); <--type cast compiler error C2440.
SetPageLoader(pl);
internalPagedGeometry->setPageLoader(pl);
pageLoader = gcnew MPageLoader((Forests::PageLoader*)internalPagedGeometry->getPageLoader());
}

// MPageLoader.h:
public ref class MPageLoader : System::IDisposable {
private:
Forests::PageLoader *pageLoader;
internal:
MPageLoader(Forests::PageLoader* pl) {
pageLoader = pl;
}
public:
Forests::PageLoader* _GetNativePtr() {
return pageLoader;
}

The compiler complains about the cast in the first line of SetPageLoader. What's the correct syntax? I tried some ways but could'nt find the correct one.

I hope, someone can help me - would be very appreciated.

Cheers,
raygeee

Bekas

02-01-2009 02:13:21


MForests.MPagedGeometry trees = new MForests.MPagedGeometry();

That doesn't look right. You are not calling the constructor that initializes internalPagedGeometry (the one whose code you posted), this is a different constructor, one that doesn't accept parameters. Is this a typo ?

My second problem is a pointer or cast issue:
Forests::PageLoader* pl = *loader->_GetNativePtr(); <--type cast compiler error C2440.
The compiler complains about the cast in the first line of SetPageLoader. What's the correct syntax?

-'loader->_GetNativePtr()' returns a pointer.
-You put a star in front of the pointer, this gives as result the object where the pointer points to
-'pl' accepts a pointer but you are trying to set it to the object.

Just remove the star which is in front of 'loader->_GetNativePtr()'.

If you can find some time, read up on C/C++ pointers, it will make your wrapping life a whole lot easier :)

raygeee

02-01-2009 12:03:55

Thanks for your reply. The second problem is fixed now.

About the first one: Yes, sorry, that's a typo. I've got 4 constructors and by examining them I found a solution...
I had this one:
MPagedGeometry() {
MPagedGeometry(nullptr, 100);
}
MPagedGeometry(Mogre::Camera ^cam) {
MPagedGeometry(cam, 100);
}
MPagedGeometry(float pageSize) {
MPagedGeometry(nullptr, pageSize);
}
MPagedGeometry(Mogre::Camera ^cam, float pageSize) {
Ogre::Camera* cm = (Ogre::Camera*)cam;
internalPagedGeometry = new Forests::PagedGeometry(cm, pageSize);
}
Guess, C++ doesn't like a constructor calling another constructor? When I call the first constructor it seems the internal variable gets set but after leaving the block it disappears.
When I change the constructors to initialize the internal variable each for themselves everything works fine.

Seems like I'm gonna spend some time on msdn now... ;-)

Bekas

02-01-2009 13:07:00

Guess, C++ doesn't like a constructor calling another constructor? When I call the first constructor it seems the internal variable gets set but after leaving the block it disappears.
Yeah, you can't call another constructor from a constructor in C++. Try using a private method for the common initialization code.

Now you may be wondering what this does then:
MPagedGeometry() {
MPagedGeometry(nullptr, 100);
}

"MPagedGeometry(nullptr, 100);" creates a local temporary MPagedGeometry object which isn't assigned to any variable and is destroyed at the end of the function, kinda like this:
MPagedGeometry() {
MPagedGeometry temp_object = MPagedGeometry(nullptr, 100);
}

As you may have noticed, C++ doesn't have the most intuitive of syntaxes, in fact, there are certain aspects of it that are really dreadful. But this is the price that it paid for C compatibility.