call a delegate from click event using C++/CLI - delegates

In C#, We can call a new function from button click with arguments like this,
////My function
public static void Method1(int x)
{
Console.WriteLine("Method 1");
}
and set this function on click event of a command button like this,
button1.Click += delegate { mydelegate with argument };
Eg:
delegate void Procedure( int x);
public partial class Window1 : Window
{
public Window1()
{
Procedure pProcedure = new Procedure(Method1);
InitializeComponent();
button1.Click += delegate { pProcedure(10); };
}
public static void Method1(int x)
{
Console.WriteLine("Method 1");
}
}
Now when we click on the button1, then the function "Method1" will be invoke.
How can I do the same using C++/CLI?
I need to find the added delegate from the click event and need to remove. How can i do this?

If you're asking about how to use anonymous delegates in C++/CLI, then the answer is you can't. In C++/CLI, delegates must be bound to a named function.
To accomplish what inline anonymous delegates actually do in C#, you can use the concept of a 'functor' or function object. The following C++/CLI sample illustrates how to create a function object and "bind" it to a specific value and then show how to use it as an event subscriber.
using namespace System;
// Sample class with one event 'Started'
public ref class Widget
{
public:
Widget()
{
}
event EventHandler ^ Started;
void Start()
{
Console::WriteLine("Starting...");
Started(this, EventArgs::Empty);
}
};
// Declare 'functor' class to capture state
private ref class Functor
{
public:
Functor(int input)
: input_(input)
{
}
// This is what we will use as the handler method
void Handler(Object ^ sender, EventArgs ^ e)
{
Console::WriteLine(L"Invoked with input {0}.", input_);
}
private:
int input_;
};
// Entry point
int wmain(int argc, wchar_t ** argv)
{
// Create a functor to capture value '10'
Functor ^ f = gcnew Functor(10);
Widget ^ widget = gcnew Widget();
// Subscribe to event using functor's handler
// (note that we bind to the instance 'f' here)
EventHandler ^ handler = gcnew EventHandler(f, &Functor::Handler);
widget->Started += handler;
// Should print "Invoked with input 10."
widget->Start();
// Remove the handler
widget->Started -= handler;
// Should not print anything extra now
widget->Start();
return 0;
}

Thank you for your help.
With your help I can solve my problem.
The solution is like this,
//FirstWindow.h
#pragma once
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Controls;
ref class Functor;
ref class FirstWindow : Window
{
Canvas^ maincanvas;
Button^ addbutton1;
Button^ addbutton2;
Functor^ pFunctor;
public:
FirstWindow(void);
void InitControls(void);
void MyFunction( int x, int y );
};
//FirstWindow.cpp
#include "FirstWindow.h"
#include "Functor.h"
FirstWindow::FirstWindow(void)
{
Title = "First Avalon App";
Width = 400;
Height = 400;
ResizeMode = System::Windows::ResizeMode::NoResize;
InitControls();
}
void FirstWindow::InitControls(void)
{
addbutton1 = gcnew Button();
addbutton1->Width = 80;
addbutton1->Height = 25;
addbutton1->Content = "Add";
pFunctor = gcnew Functor(this, 10, 20);
addbutton1->Click += gcnew RoutedEventHandler( pFunctor, &Functor::Handler);
Canvas::SetTop(addbutton1, 45);
Canvas::SetLeft(addbutton1, 200);
pFunctor = gcnew Functor(this, 100, 200);
addbutton2 = gcnew Button();
addbutton2->Width = 80;
addbutton2->Height = 25;
addbutton2->Content = "Add";
addbutton2->Click += gcnew RoutedEventHandler(pFunctor, &Functor::Handler);
Canvas::SetTop(addbutton2, 85);
Canvas::SetLeft(addbutton2, 200);
maincanvas = gcnew Canvas();
maincanvas->Children->Add(addbutton1);
maincanvas->Children->Add(addbutton2);
Content = maincanvas;
}
void FirstWindow::MyFunction( int x, int y )
{
MessageBox::Show("This function is call by Button Click with values " + x.ToString() + " , " + y.ToString() );
}
//Functor.h
#pragma once
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Controls;
ref class FirstWindow;
private ref class Functor
{
public:
Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg);
// This is what we will use as the handler method
void Handler(Object ^ sender, RoutedEventArgs ^ e);
private:
int m_pFirstArg;
int m_pSecArg;
FirstWindow^ m_pFirstWindow;
};
//Functor.cpp
#include "Functor.h"
#include "FirstWindow.h"
Functor::Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg) : m_pFirstWindow( pFirstWindow ), m_pFirstArg(pFirstArg), m_pSecArg( pSecArg )
{
}
void Functor::Handler(Object ^ sender, RoutedEventArgs ^ e)
{
if ( m_pFirstWindow )
m_pFirstWindow->MyFunction(m_pFirstArg, m_pSecArg );
}
Now when we click on button one, then the application call the function "MyFunction" with value 10,20 and when we click on button 2 then the same function "MyFunction" with value 100,200.
Thank you for your help.
Sabeesh

Related

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 marshaling .NET delegate to native delegate

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.

Fire an event in C++/CLI from unmanaged C / C++ function

I need to fire an event written in C++ / CLI from an unmanned function in c++.
What is the best way to do this?
Thanks in advance.
I figured out with some help from some help posts on codeproject
Thought of posting it here could be useful for others
#include "stdafx.h"
#include "windows.h"
using namespace System;
using namespace System::Runtime::InteropServices;
class Camera
{
public:
Camera()
{
}
~Camera(){}
void (*test)(void);
void OnNewCameraData();
void StartDataAcquisition();
};
void Camera::StartDataAcquisition()
{
int i;
while(i<10)
{
test();
i++;
Sleep(1000);
}
}
delegate void FunctionToCallDelegate();
ref class CameraAdapter
{
private:
Camera *_camera;
FunctionToCallDelegate ^_Function;
public:
CameraAdapter(FunctionToCallDelegate ^handler)
{
_Function = handler;
}
void Init()
{
_camera = new Camera();
pin_ptr<FunctionToCallDelegate^> tmp = &_Function;
_camera->test = (void (__cdecl *)(void))(Marshal::GetFunctionPointerForDelegate(_Function).ToPointer());
_camera->StartDataAcquisition();
}
~CameraAdapter()
{
delete _camera;
_camera = 0;
}
void OnNewCameraData()
{
Console::WriteLine("Received Frame \n");
}
};
int main(array<System::String ^> ^args)
{
FunctionToCallDelegate ^dsi;
dsi += gcnew FunctionToCallDelegate(gcnew CameraAdapter(dsi), &CameraAdapter::OnNewCameraData);
CameraAdapter ^camera = gcnew CameraAdapter(dsi);
camera->Init();
Console::ReadKey();
return 0;
}

How to hand a file path (text box value) to a file reading function in c++?

I created a file chooser for windows it returns me a chosen file path. I want to read the given file but I do not know how to pass the file path to the right function.
File Form1.h I have a button action and inside of it I can get openFileDialog1->FileName but I do not know how to pass this variable to a readFile() function inside of main.cpp file.
I created a method to return the path:
System::String^ filePath;
....
private: System::String^ getPath() { return filePath; }
Here is the file-pickers code:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Stream^ myStream;
OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;
openFileDialog1->InitialDirectory = "c:\\";
openFileDialog1->Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog1->FilterIndex = 2;
openFileDialog1->RestoreDirectory = true;
if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK ){
if ( (myStream = openFileDialog1->OpenFile()) != nullptr ){
// Insert code to read the stream here.
textBox1->Text = openFileDialog1->FileName; //text box displays the chosen path
myStream->Close();
}
}
}
The variable is set on button click:
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
filePath = textBox1->Text;
}
How to call the return methods in my main.cpp:
#include "stdafx.h"
#include "Form1.h"
using namespace main;
using namespace std;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
System::String^ p1 = /*Something missing her?*/getPath1(); //I am guessing it should look like this...
return 0;
}
Put the file name in a public property (public field, if it's what you prefer) in the Form1 class (or make your getPath() method public) then:
Form1^ form = gcnew Form1();
Application::Run(form);
String^ p1 = form->FileName;

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