Managed wrappers to c++ functions that return pointers to classes

Started by
6 comments, last by Raeldor 17 years, 5 months ago
Hi All, I am writing managed wrappers for my C++ classes. How do I wrap a function that returns a pointer to an unmanaged class? Do I have to maintain a hash table of my unmanaged pointers with a pointer to their managed object? Thanks! Rael
Advertisement
Well the problem with pointers to native classes is that the managed code doesn't understand the native class. so you 've go to wrap these, too.
class native_A {};class native_B {};native_A *the_function() { retrn new native_A; }ref class managed_A {     public: managed_A() { ptr_ = new native_A; }    private: native_A *ptr_; };managed_A ^the_function() { return gcnew managed_A(); }

Basically you need to wrap *everything* that needs to be exposed to c# code.
If you don't need any of it's members, but just need to get the pointer later on, you can use the System.IntPtr type.
I definitely need to access the members. So, is it normal to do something similar to...
	public ref class MNWMatrix	{	private:		NW::NWMatrix* m_matrix;		bool m_owned;	public:		MNWMatrix() {m_matrix=new NW::NWMatrix(); m_owned=true;}		MNWMatrix(IntPtr in_unmanagedPtr) {m_matrix=(NW::NWMatrix*)in_unmanagedPtr.ToPointer();}		~MNWMatrix() {if (m_owned) delete m_matrix;}		IntPtr GetUnmanagedPtr() {return IntPtr(m_matrix);}	};

when building wrappers? I assume if you are getting a pointer back from another class that the object could have been created by yourself, or could exist on the heap somewhere... you don't know. So you have to create a new managed wrapper pointing to the memory area? I am also assuming because you don't know the origin of the memory area that you have to keep track of whether it is owned or not to know where to delete it? Does this make sense?
Quote:Original post by Raeldor
So, is it normal to do something similar to...
*** Source Snippet Removed ***
when building wrappers?
Yes. something along these lines.
Quote:Original post by Raeldor
I assume if you are getting a pointer back from another class that the object could have been created by yourself, or could exist on the heap somewhere... you don't know. So you have to create a new managed wrapper pointing to the memory area? I am also assuming because you don't know the origin of the memory area that you have to keep track of whether it is owned or not to know where to delete it? Does this make sense?

Well. personally i wouldn't expose the native pointer at all. This doesn't make any sense because a purely managed language wouldn't be able to do much with it. I see you're trying to facilitate and speed-up copying matrices around which is a very valid concern. You definitely don't need to create a new underlying native matrix instance with 'new' each time the constructor is called.
What you want to do instead, though, is to not expose the native pointer but to create a copy constructor for the managed class that just copies the underlying native pointer and employ some means of reference counting on the managed class so you can determine when to destroy the underlying native matrix pointer.
The method GetUnmanagedPtr() would not be typical or even recommended for a managed wrapper. your goal is to make the managed wrapper look to the user as if it were a genuine C# class with no pointer magic or anything beneath it.
You need to imagine what a c# user would think of your class. how he/she would see it through intellisense.. that's the guideline for a good managed wrapper. make it feel like it has been written in c# from day one. and hide the underlying c++ stuff like managing lifetimes of pointers and copy constructing via pointers only etc.. the stuff that gives you the power. just don't surface that in your interface.
The idea of the GetUnmanagedPtr is to be called from within another wrapper. For example if the managed matrix was passed as a paramater to another wrapped unmanaged function and it needed to pass the unmanaged matrix to the unmanaged function.

Does that make sense, or is there an easier way of doing it?

Thanks
Rael
class native_A {};ref class managed_A { public: IntPtr^ get_unmanaged_ptr(); };void do_something(native_A *a) {}void do_something(managed_A ^a) { do_something(a->get_unmanaged_ptr()); }
(Obviously pseudo-code)
Something along these lines? I think if you depend on this kind of functionality then you must indeed have a function like get_unmanaged_ptr(). This is often used for managed classes that wrap native COM objects. There's often a method to retrieve the underlying native pointer in order to get to the more gorey details. It would make sense in your case.
You wouldn't have to go this route, though, if your do_something() was a member function of both native_A and managed_A. A method for getting the underlying native pointer is, of course, only necessary if you choose do_something to be a non-member function.
void do_something_else(native_A *a) {}class native_A { public: do_something() { do_something_else(this); } };ref class managed_A {   public:  managed_A() { ptr_ = new native_A; }             ~managed_A() { /* ref count an delete ptr_ */ }             void do_something() { ptr_->do_something();     private: native_A *ptr_; };
You see? This would allow the deeper functions like do_something_else() to be non-member functions but you need the top level function (do_something() in this case) to have access to the private native_A pointer. I'd really try and avoid the public get_unmanaged_ptr() method you suggested. For a public interface these kind of methods introduce a tremendous risk, obviously.
If you decide to use this pointer accessor function you wouldn#t be on unknown paths... microsoft use this method for all of their managed wrappers to the office 2003/2007 component model.
Just because of safety issues and the clean "genuine c#" look and feel of your managed api, though, i'd try and stay away from these pointer accessor functions.
You first idea of having a table that maps from managed pointer to native would introduce quite a bit of house-keeping and source overhead, imo. I think the hidden cost of this technique would also be interesting as the garbage collector wouldn't like all your objects' handles to be stored in a table, basically keeping an additional reference over the lifetime of these objects. i don't say this method is not usable. however there are two other possible options (you and i wrote about) that don't have thet source/complexity overhead. looking up a pointer in a table on each call just doesn't seem elegant/performant/natural.

hope my views help a bit. 't is me, the anon from the dark realms of interop ;)
Yes, that does help, thank you. In my case though the pointer exists in another managed class, so I think I still need the accessor function. It seems to work, so I'll continue along the route I'm on until something breaks or I see someone else do it a better way. :P

This topic is closed to new replies.

Advertisement