C++/CLI marshaling .NET delegate to native delegate - delegates

I am trying to pass a delegate with managed parameters to native code to be invoked. My code below runs ok, but the string output is garbage.
Native Class
Header
#pragma once
typedef void (* SegmentCreatedDelegate)(char** arg);
public class SampleClass
{
public:
SampleClass(void);
~SampleClass(void);
void DoWork(SegmentCreatedDelegate callback);
};
Code
SampleClass::SampleClass(void)
{
}
SampleClass::~SampleClass(void)
{
}
void SampleClass::DoWork(SegmentCreatedDelegate callback)
{
for(int x = 0; x< 10; x++)
{
char* myStr2 = "newsegment!";
callback(&myStr2);
}
}
Managed Class
Header
#pragma once
public ref class SampleClassNet
{
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet(void);
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
Code
SampleClassNet::SampleClassNet(void)
{
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback)
{
SampleClass* nativeClass = new SampleClass();
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(segmentCreatedCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
System::GC::KeepAlive(segmentCreatedCallback);
}
This code runs fine with the follow c#.
var sampleClass = new SampleClassNet();
sampleClass.DoWork((Console.WriteLine));
Except I get the following output, instead of the expected 10 entries of "newsegment!".
(ÇÆX
(ÇÆX☺
(ÇÆX☻
(ÇÆX♥
(ÇÆX♦
(ÇÆX♣
(ÇÆX♠
(ÇÆX
(ÇÆX
(ÇÆX
Not exactly "newsegment!", but I am not sure why the marshaling is not working. Maybe I need I need some kind of "MarshalAs" attribute so that the System::String knows that I have 8-bit chars?

As mentioned in the comments, you should convert the char** to a String^. (Btw, why pass char**, not char*? String has a constructer taking char*, which might simplify things a lot.)
I haven't tried the following, but you might give it a try:
public ref class SampleClassNet {
private:
delegate void SegmentCreatedDelegateNative(char** str);
SegmentCreatedDelegateNet^ managedCallback;
SegmentCreatedDelegateNative^ nativeCallback;
void printString(char** string);
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet();
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
SampleClassNet::SampleClassNet() {
nativeCallback = printString;
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback) {
SampleClass* nativeClass = new SampleClass();
managedCallback = segmentCreatedCallback;
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(nativeCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
}
void SampleClassNet::printString(char** string) {
if (this->managedCallback != nullptr) {
String^ str = gcnew String(*string);
managedCallback(str);
}
}
The basic idea is to use another delegate, SegmentCreatedDelegateNative, handed to the native class, and to call the actual managed delegate from the function associated with the wrapper.

Related

No viable conversion from 'shared_ptr<Pin>' to 'shared_ptr<Component>s'

I have an assignment of creating a Circuit Sim and I'm having issues with NotGate class when I try to use it.
Components is an abstract class.
class Component
{
public:
virtual bool getOutput() = 0;
virtual void prettyPrint(string padding) = 0;
virtual void linearPrint() = 0;
};
Then I have Pin and NotGate, they inherit through dependency of Components.
class Pin {
private:
bool value;
string label;
public:
Pin::Pin(string theLabel) {
label = theLabel;
}
bool Pin::getOutput() {
return value;
}
void Pin::setValue(bool newVal) {
this->value = newVal;
}
};
class NotGate {
private:
shared_ptr<Component> input;
public:
NotGate::NotGate() {
input = make_shared<Component>();
}
bool NotGate::getOutput() {
if (input == 0) {
return true;
} else {
return false;
}
}
void NotGate::setInput(shared_ptr<Component> in) {
this->input = in;
}
};
I created a Pin "c" and a notGate "n1", I want to have "c" as the input for "n1". When I try to do it with the command:
n1->setInput(c);
It tells me that: No viable conversion from 'shared_ptr<Pin>' to 'shared_ptr<Component>s'
I tried creating a new shated_ptr of Components and a bunch of different things that didn't work.
The error message from the compiler is clear. If you want to be able to use a shared_ptr<Pin> when a shared_ptr<Component> is expected, you should make Pin a sub-class of Component. From an abstraction standpoint, it makes sense to me that Pin be a sub-class of Component.
class Pin : public Component
{
...
};

Adding a header to a QListView

I encountered a little problem with QListView. I wanted to add a header to this object. However, I found no method to do such a task. I have seen several posts on SO and Qt forums but did not found anything relevant to my needs. I remembered that, in the past, I have used something that could be adapted to QListView (I think it was inspired by a Qt example but do not remember which one).
For those who need to display a header on the top of the QListView, I will post the code here. If someone find something false, or unadapted, please let me know. Here is the code:
Header
class MainMenuListView : public QListView
{
Q_OBJECT
class Header : public QWidget
{
public:
Header(MainMenuListView* parent);
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent* event);
private:
MainMenuListView* menu;
};
public:
MainMenuListView(QWidget* parent = nullptr, const QString& header = QString("Header"));
void headerAreaPaintEvent(QPaintEvent *event);
int headerAreaWidth();
protected:
void resizeEvent(QResizeEvent* event);
private:
QWidget* headerArea;
QString headerText;
};
Implementation
MainMenuListView::Header::Header(MainMenuListView* parent) : QWidget(parent), menu(parent) {}
QSize MainMenuListView::Header::sizeHint() const
{
return QSize(menu->headerAreaWidth(), fontMetrics().height());
}
void MainMenuListView::Header::paintEvent(QPaintEvent* event)
{
menu->headerAreaPaintEvent(event);
}
MainMenuListView::MainMenuListView(QWidget* parent, const QString& header) : QListView(parent), headerText(header)
{
headerArea = new Header(this);
setViewportMargins(0, fontMetrics().height(), 0, 0);
}
void MainMenuListView::headerAreaPaintEvent(QPaintEvent* event)
{
QPainter painter(headerArea);
painter.fillRect(event->rect(), Qt::lightGray);
painter.setPen(Qt::black);
painter.drawText(0, 0, headerArea->width(), fontMetrics().height(), Qt::AlignCenter, headerText);
}
int MainMenuListView::headerAreaWidth()
{
return width();
}
void MainMenuListView::resizeEvent(QResizeEvent* event)
{
QListView::resizeEvent(event);
headerArea->adjustSize();
}
Tested and working under Debian Qt5.x.x
Result:

C++/CLI managed class member callback by managed code

I am designing a class in C++/CLR that uses a callback function provided by user code.
This works very nicely if the callback function is free ( i.e. not the member of a class ). It is almost the same as in pure C++.
Here is some sample code that works well:
ref class ClassThatUsesCallback
{
public:
typedef void (*callback_t)( String^ );
void setCallback( callback_t pfun )
{
myCallback = pfun;
}
void Run()
{
if( myCallback != nullptr ) {
myCallback("This is a test");
}
}
private:
callback_t myCallback;
};
void FreeFunction( String^ s )
{
Console::WriteLine( "Free Function Callback " + s );
}
int main(array<System::String ^> ^args)
{
ClassThatUsesCallback^ theClassThatUsesCallback
= gcnew ClassThatUsesCallback();
theClassThatUsesCallback->setCallback( FreeFunction );
theClassThatUsesCallback->Run();
}
However, I would like the callbacked function to be a member of a class in the user code ( so it can make use of and change the attributes of the user code class )
The following code does not compile
ref class ClassThatProvidesCallback
{
public:
void MemberFunction( String^ s )
{
Console::WriteLine( "Member Function Callback " + s );
}
void Run()
{
ClassThatUsesCallback^ theClassThatUsesCallback
= gcnew ClassThatUsesCallback();
theClassThatUsesCallback->setCallback(
&ClassThatProvidesCallback::MemberFunction );
theClassThatUsesCallback->Run();
}
};
I get this error
error C3374: can't take address of 'ClassThatProvidesCallback::MemberFunction'
unless creating delegate instance
When I research this, I find numerous explanations of how to call un-managed code from managed code ( and vice-versa ) I do not need to do this - all the code involved is managed. So I am hoping that someone can point me to a simple way to this.
This is full solution:
ref class ClassThatUsesCallback
{
public:
void setCallback( Action<String^>^ callback )
{
myCallback = callback;
}
void Run()
{
if( myCallback != nullptr ) {
myCallback("This is a test");
}
}
private:
Action<String^>^ myCallback;
};
ref class ClassThatProvidesCallback
{
public:
void MemberFunction( String^ s )
{
Console::WriteLine( "Member Function Callback " + s );
}
void Run()
{
ClassThatUsesCallback^ theClassThatUsesCallback
= gcnew ClassThatUsesCallback();
theClassThatUsesCallback->setCallback(gcnew Action<String^>(this,
&ClassThatProvidesCallback::MemberFunction));
theClassThatUsesCallback->Run();
}
};
int main(array<System::String ^> ^args)
{
ClassThatProvidesCallback^ c = gcnew ClassThatProvidesCallback();
c->Run();
return 0;
}
Native C++ style typedef is replaced with .NET Action delegate. Additional parameter this is added to setCallback call, it is required to define the class instance which contains the callback function.

c++/cli Best practice for free GCHandle in the finalizer

I have some functions in c and I would use this in a .net application.
For this I wrote an Wrapper class with C++/cli.
In the c interface is a callback function and wrapped this in a .net delegate.
But how should I release the unmanaged ressources for the callback gcHandle?
Is it allowd to call IsAllocated and Free from a GCHandle in the finalizer?
Because it is an managed ressource and is it possibile that the gc already release it?
Here is the code for the c interface:
// C functions
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*my_native_callback)(const uint8_t buffer[], uint32_t buffer_len);
void register_callback(my_native_callback c, uint32_t* id);
void remove_callback(uint32_t id);
#ifdef __cplusplus
}
#endif
And here the .net wrapper:
// .net wrapper (c++/cli)
public ref class MyWrapper
{
public:
MyWrapper()
{
RegisterCallback();
}
// Destructor.
~MyWrapper()
{
this->!MyWrapper();
}
protected:
// Finalizer.
!MyWrapper()
{
RemoveCallback(); // <- Is this safe?
// ... release other unmanaged ressorces
}
private:
void RegisterCallback()
{
uint32_t id = 0;
callbackDelegate_ = gcnew MyCallbackDelegate(this, &MyWrapper::OnCallback);
callbackHandle_ = System::Runtime::InteropServices::GCHandle::Alloc(callbackDelegate_);
System::IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callbackDelegate_);
register_callback(static_cast<my_native_callback>(delegatePointer.ToPointer()), &id);
callbackId_ = id;
}
void RemoveCallback()
{
if (callbackId_)
{
remove_callback(callbackId_);
callbackId_ = 0;
}
if (callbackHandle_.IsAllocated) // It this safe in the finalizer?
{
callbackHandle_.Free(); // It this safe in the finalizer?
}
callbackDelegate_ = nullptr; // It this safe in the finalizer?
}
void OnCallback(const uint8_t* buffer, uint32_t buffer_len)
{
// ...
}
private:
[System::Runtime::InteropServices::UnmanagedFunctionPointer(System::Runtime::InteropServices::CallingConvention::Cdecl)]
delegate void MyCallbackDelegate(const uint8_t* buffer, uint32_t buffer_len);
MyCallbackDelegate^ callbackDelegate_;
System::Runtime::InteropServices::GCHandle callbackHandle_;
int callbackId_;
// ...
};
Is the code snippet safe and what is best practice for this?
Thank you in advance.
There is no need to add an extra GCHandle reference to the delegate object. You are already correctly store a reference in the callbackDelegate_ field, enough to convince the garbage collector that the delegate is in use and should not be collected. No additional reference is required.
Just remove callbackHandle_ from your code.

How to use boost::bind in C++/CLI to bind a member of a managed class

I am using boost::signal in a native C++ class, and I now I am writing a .NET wrapper in C++/CLI, so that I can expose the native C++ callbacks as .NET events. When I try to use boost::bind to take the address of a member function of my managed class, I get compiler error 3374, saying I cannot take the address of a member function unless I am creating a delegate instance. Does anyone know how to bind a member function of a managed class using boost::bind?
For clarification, the following sample code causes Compiler Error 3374:
#include <boost/bind.hpp>
public ref class Managed
{
public:
Managed()
{
boost::bind(&Managed::OnSomeEvent, this);
}
void OnSomeEvent(void)
{
}
};
While your answer works, it exposes some of your implementation to the world (Managed::OnSomeEvent). If you don't want people to be able to raise the OnChange event willy-nilly by invoking OnSomeEvent(), you can update your Managed class as follows (based on this advice):
public delegate void ChangeHandler(void);
typedef void (__stdcall *ChangeCallback)(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
event ChangeHandler^ OnChange;
private:
void OnSomeEvent(void);
Native* native;
Callback* callback;
GCHandle gch;
};
Managed::Managed(Native* Nat)
: native(Nat)
{
callback = new Callback;
ChangeHandler^ handler = gcnew ChangeHandler( this, &Managed::OnSomeEvent );
gch = GCHandle::Alloc( handler );
System::IntPtr ip = Marshal::GetFunctionPointerForDelegate( handler );
ChangeCallback cbFunc = static_cast<ChangeCallback>( ip.ToPointer() );
*callback = native->RegisterCallback(boost::bind<void>( cbFunc ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
if ( gch.IsAllocated )
{
gch.Free();
}
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
Note the alternate bind<R>() form that's used.
After googling some more, I finally found a nice blog post about how to do this. The code in that post was a little more than I needed, but the main nugget was to use a global free function that takes an argument of the managed this pointer wrapped in a gcroot<> template. See the SomeEventProxy(...) in the code below for an example. This function then turns around and calls the managed member I was trying to bind. My solution appears below for future reference.
#include <msclr/marshal.h>
#include <boost/bind.hpp>
#include <boost/signal.hpp>
#include <iostream>
#using <mscorlib.dll>
using namespace System;
using namespace msclr::interop;
typedef boost::signal<void (void)> ChangedSignal;
typedef boost::signal<void (void)>::slot_function_type ChangedSignalCB;
typedef boost::signals::connection Callback;
class Native
{
public:
void ChangeIt()
{
changed();
}
Callback RegisterCallback(ChangedSignalCB Subscriber)
{
return changed.connect(Subscriber);
}
void UnregisterCallback(Callback CB)
{
changed.disconnect(CB);
}
private:
ChangedSignal changed;
};
delegate void ChangeHandler(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
void OnSomeEvent(void);
event ChangeHandler^ OnChange;
private:
Native* native;
Callback* callback;
};
void SomeEventProxy(gcroot<Managed^> This)
{
This->OnSomeEvent();
}
Managed::Managed(Native* Nat)
: native(Nat)
{
native = Nat;
callback = new Callback;
*callback = native->RegisterCallback(boost::bind( SomeEventProxy, gcroot<Managed^>(this) ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
void OnChanged(void)
{
Console::WriteLine("Got it!");
}
int main(array<System::String ^> ^args)
{
Native* native = new Native;
Managed^ managed = gcnew Managed(native);
managed->OnChange += gcnew ChangeHandler(OnChanged);
native->ChangeIt();
delete native;
return 0;
}

Resources