I'm trying to figure out how to wrap a boost::function member (used as an event callback) of an unmanaged class with a C++/CLI class event. I do not have control over the unmanaged class. All I can do is figure out how to write the C++/CLI class properly.
Here's the example unmanaged class:
class X
{
public:
boost::function<void (double)> XChanged;;
void Set(double x)
{
XChanged(x)
}
};
I've tried many things, but I keep running into problems. I'm sure it's easier than it appears to be. Any help would be greatly appreciated!
CLI probably won't let you declare a boost::function as a static member. Make it a pointer:
boost::function<void(double> *XChanged;
Then allocate/deallocate in the constructor and finalizer and call it with (*XChanged)(arg);
Related
I have a lot of native classes that accept some form of callbacks, usually a boost::signals2::slot-object.
But for simplicity, lets assume the class:
class Test
{
// set a callback that will be invoked at an unspecified time
// will be removed when Test class dies
void SetCallback(std::function<void(bool)> callback);
}
Now I have a managed class that wraps this native class, and I would like to pass a callback method to the native class.
public ref class TestWrapper
{
public:
TestWrapper()
: _native(new Test())
{
}
~TestWrapper()
{
delete _native;
}
private:
void CallbackMethod(bool value);
Test* _native;
};
now usually what I would do is the following:
Declare a method in the managed wrapper that is the callback I want.
Create a managed delegate object to this method.
Use GetFunctionPointerForDelegate to obtain a pointer to a function
Cast the pointer to the correct signature
Pass the pointer to the native class as callback.
I also keep the delegate alive since I fear it will be garbage collected and I will have a dangling function pointer (is this assumption correct?)
this looks kind of like this:
_managedDelegateMember = gcnew ManagedEventHandler(this, &TestWrapper::Callback);
System::IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(_managedDelegateMember);
UnmanagedEventHandlerFunctionPointer functionPointer = static_cast<UnmanagedEventHandlerFunctionPointer >(stubPointer.ToPointer());
_native->SetCallback(functionPointer);
I Would like to reduce the amount of code and not have to perform any casts nor declare any delegate types. I want to use a lambda expression with no delegate.
This is my new approach:
static void SetCallbackInternal(TestWrapper^ self)
{
gcroot<TestWrapper^> instance(self);
self->_native->SetCallback([instance](bool value)
{
// access managed class from within native code
instance->Value = value;
}
);
}
Declare a static method that accepts this in order to be able to use C++11 lambda.
Use gcroot to capture the managed class in the lambda and extend its lifetime for as long as the lambda is alive.
No casts, no additional delegate type nor members, minimal extra allocation.
Question:
Is this approach safe? I'm fearing I'm missing something and that this can cause a memory leak / undefined behavior in some unanticipated scenario.
EDIT:
this approach leads to a MethodAccessException when the lambda calls a private method of its managed wrapper class. seems like this method must at least be internal.
I think that you should not be using gcroot but a shared pointer. Shared pointer are made to keep an object alive as long as someone is using it.
You should also use a more c++ style in your whole code by replacing raw pointer with smart pointer and template instead of std::function (a lambda can be stored in a compile time type).
For example using the code you posted :
class Test
{
// set a callback that will be invoked at an unspecified time
// will be removed when Test class dies
template <class T>
void SetCallback(T callback); // Replaced std::function<void(bool)> with T
}
public ref class TestWrapper
{
public:
TestWrapper()
: _native()
{}
private:
void CallbackMethod(bool value);
std::unique_ptr<Test> _native; // Replaced Test* with std::unique_ptr<Test>
};
After replacing the old method with this new method all over my code base, I can report that it is safe, more succinct, and as far as I can tell, no memory leaks occur.
Hence I highly recommend this method for passing managed callbacks to native code.
The only caveats I found were the following:
Using lambda expressions forces the use of a static method as a helper for the callback registration. This is kinda hacky. It is unclear to me why the C++-CLI compiler does no permit lambda expressions within standard methods.
The method invoked by the lambda must be marked internal so to not throw MethodAccessException upon invocation. This is sort of make sense as it is not called within the class scope itself. but still, delegates / lambdas with C# don't have that limitation.
Assume we have next code:
class ISampleInterface
{
public:
virtual ~ISampleInterface() {} ;
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class SampleClass : public ISampleInterface
{
public:
SampleClass() { };
~SampleClass() override { };
void Method1() { };
void Method2() { };
};
int main()
{
ISampleInterface *pObject = (ISampleInterface*)new SampleClass();
delete pObject;
return 0;
}
Is it better explicitly declare ~SampleClass() as override or don't care?
P.S. Please, focus on override and don't care the implementation of destructor itself. It could be defined, I just put example here in order to make my question clear.
I wouldn't do that. I also don't see any point in declaring explicitly a trivial destructor. Let the compiler do its job. You might need to introduce a virtual destructor into your class to (i) make the class polymorphic - although any function will do for that - and (ii) to assist in memory management, but that's not strictly relevant here.
Or, if you must do such a thing, consider using = default notation rather than supplying the empty body explicitly.
IMHO opinion any answer would be biased (i.e., opinion based). Generally, using the override specifier amongst many advantages has the advantage of eliminating:
inadvertent overriding : Inadvertently override a virtual function by declaring a member function that accidentally has the same name and signature as a base class’s virtual member function.
signature mismatches: Define a function in derived class that intended to override a virtual function in the base class but the two functions have different signatures.
There are even people that back up the opinion that the use of override specifier should be mandatory in future version of C++.
Now, in the particular case of a destructor, attaching the override specifier seems to me a little verbose.
And I'll try to clear my stand. A destructor is a special member function. Considering a class hierarchy, a derived class's destructor overrides by default the destructor of the base class (that for the known reasons should be declared virtual). Furthermore, you don't have the advantages mentioned earlier (i.e., there can't be either inadvertent overriding nor signature mismatch in a case of a destructor).
Thus, I wouldn't specify a destructor override.
Looks like I found at least one reason why it is better to make destructor override.
override for destructors prevents to make mistake when destructor of interface base class is not declared as virtual.
I have a library which exposes callback functions, and needs to be called from both managed and native code. I implemented this by doing:
typedef struct { DWORD blah; } MY_STRUCT;
class ICallbackInterface
{
public:
virtual HRESULT CallbackFunc1(const MY_STRUCT* pStruct) { return S_OK; }
// helper for overriding the vtable (used later on by the managed code)
class VTable
{
public:
void* pfnCallbackFunc1;
};
};
The native code receives a pointer to an ICallbackInterface, and calls CallbackFunc1.
In C++/CLI code, I'm allocating an ICallbackInterface, and overriding its vtable to point to delegates of the managed functions I want to call. (The following snippet is from the constructor):
public ref class MyManagedClass
{
...
m_pCallbackClass = new ICallbackInterface;
if (!m_pCallbackClass)
return E_OUTOFMEMORY;
m_pNewCallbackVtable = new ICallbackInterface::VTable;
if (!m_pNewCallbackVtable)
{
delete m_pCallbackClass;
m_pCallbackClass = nullptr;
return E_OUTOFMEMORY;
}
// Get the (hidden) pointer to the vtable
ICallbackInterface::VTable** ppAddressOfInternalVtablePointer =
(ICallbackInterface::VTable**)m_pCallbackClass;
ICallbackInterface::VTable* pOldVtable = *ppAddressOfInternalVtablePointer;
// Copy all the functions from the old vtable that we don't want to override
*m_pNewCallbackVtable = *pOldVtable;
// Manually override the vtable entries with our delegate functions
m_pNewCallbackVtable->pfnCallbackFunc1 = Marshal::GetFunctionPointerForDelegate(gcnew delCallbackFunc1(this, &MyManagedClass::CallbackFunc1)).ToPointer();
...
And here's the callback function & its delegate
[UnmanagedFunctionPointer(CallingConvention::StdCall)]
delegate HRESULT delCallbackFunc1(const MY_STRUCT* pMyStruct);
HRESULT CallbackFunc1(const MY_STRUCT* pMyStruct)
{
// do something with pMyStruct.
}
}
When I compile the native library for x86, all works well.
(I don't know why CallingConvention::StdCall is used there, but the alternatives seem to cause problems with esp.)
When I compile it for x64, the callback function gets called, and rsp is fine when I return, but pMyStruct is trashed. It appears the native code likes to pass things in to rdx, but somewhere in the native->managed transition (which the debugger won't let me step into), rdx is being filled with garbage.
Is there some attribute I can use to on my delegate to fix this on x64? Or do I need to do something less pleasant like wrap my entire managed class in a native class to do the callbacks? Or did I just find a managed codegen bug?
you're invoking undefined bwhavior left and right, and relying on implementation details such as vtable layout and virtual member function calling convention. it's no wonder that things broke when you changed platforms.
you need to write derived vl lass if the native interface. the implementation can call function pointers or managed delegates directly. and stop messing with the vtsble pointer.
Found the problem.
The managed code has its "this" pointer that comes when initializing the delegate.
But the native function has its own "this" pointer which is being passed along too. Changing the managed signatures to the following totally fixes the bug, and now the function gets access to both "this" pointers.
[UnmanagedFunctionPointer(CallingConvention::ThisCall)]
delegate HRESULT delCallbackFunc1(ICallbackInterface* NativeThis, const MY_STRUCT* pMyStruct);
HRESULT CallbackFunc1(ICallbackInterface* NativeThis, const MY_STRUCT* pMyStruct)
{
// do something with pMyStruct.
}
This works on x86 and x64.
i'm having trouble with syntax regarding c++ Windows Forms..
this is how you obviously do it in a regular cpp project: http://www.cplusplus.com/doc/tutorial/structures/
but its not the same in windows forms :/
any help??
THANKS!
btw, i figured it out!
you must create a new class in the project...
call it, Player.h
in the new class, you must instantiate the class like below
to make it a managed class so it fits well with the managed code
in the forms (notice ref class keyword)
struct markedPos
{
int xPos;
int yPos;
};
ref class Player
{
public:
Player()
{
}
protected:
private:
};
then simply in the forms.h file, you must include the new class like any other class:
#include "Player.h"
and all you have to do is make an instance of the player in your forms and it'll work like magic! What i've learned: Do all your heavy lifting in the managed classes outside of the forms... which work just like your regular c++ classes...
cheers!
** You don't need to use managed code! if your getting problems with it, just remove 'ref' before class name
If I use /clr:oldSyntax the following should work:
public __value enum IceCreamFlavors
{
Vanilla,
Chocolate,
Sardine,
};
what is the equivalent in non-oldSyntax? How do I declare a "managed" enum in Managed C++ for .NET 2.0?
Edit:
when I follow JaredPar's advice, then if I try to pass an IceCreamFlavor to a function with the signature:
OrderFlavor(IceCreamFlavors flav)
by running
OrderFlavor(IceCreamFlavors::Sardine)
I get the error:
'IceCreamFlavors Sardine' : member function redeclaration not allowed
Try
enum class IceCreamFlavors {
Vanilla,
Chocolate,
Sardine,
};
Are you, by any chance, trying to declare your enum inside another class?
ie:
public ref class Icecream
{
public enum class flavours
{
Mint,
Vanilla,
Guac
};
};
If you are, I would guess that you need to move it out so that it is its own class instead of a nested one. (Does managed c++ allow nested classes?) My impression is that you used to be able to do it unmanaged style inside another class, but since its its own class now, you probably shouldn't be nesting them. I might be wrong. My knowledge of managed c++ and c# is kind of weak.