V
Vijay
Hi,
I am faced with the following common managed/unmanaged C++ interop
problem:
- I have a .NET form that acts as a front end GUI to a processing
engine in the background. The processing engine runs as a thread that
is managed by the front-end form class.
- The processing engine must have a callback mechanism to update the
form about progress, and to send status messages that will be displayed
by the GUI.
I am looking for the *simplest* solution that involves least changes to
the processing engine code and doesn't involve writing wrappers for
everything. Based on reading previous posts from this newsgroup, I
ended up with the following pattern:
// Form.h
class Form
{
// controls.
// event handlers.
void btnStart_Click(...);
// GUI status update functions.
void updateStatus(...);
};
---------
// Form.cpp
// the engine object - global variable :-(
Engine myEngine;
// form function implemetations.
void run_engine()
{
try
{
// ... setup the engine ...
myEngine.set_listener(this);
myEngine.process();
// ... cleanup the engine ...
}
catch(/* any exception thrown by Engine */)
{
// exception handler code
}
};
---------
// Engine.h
#include <vcclr.h>
public __gc class Form;
class Engine
{
gcroot<Form *> _pListener;
// engine related variables.
public:
void set_listener(gcroot<Form *> pListener);
// engine related member functions.
};
--------
// Engine.cpp
#include "Engine.h"
#include "Form.h"
#define STATUS(x) {/*format the message*/;_pListener->updateStatus();}
void Engine:rocess()
{
// processing code.
STATUS(("Running test %d of %d.", ...));
// processing code.
}
The method is low-impact because the only changes I did to the Engine
source code were to add 3-4 lines to setup the listener inside the
class, and change the status "#define" to update the status in the
listener. The rest of the code remains untouched and no wrappers were
written.
But, I am unable to have a Engine object as a member variable of the
Form class because of the presence of <gcroot> in the Engine class. I
worked around it by instantiating Engine as a global variable (yuk !)
in Form.cpp, but it *works* so far.
I'd appreciate it if the .NET gurus in this group would make a
constructive critique of my pattern, and/or make any suggestions to
make it more elegant. Is it possible to follow the same pattern, but
avoid the global variable (or is wrappers the only way to go) ?
Thanks,
Vijay.
I am faced with the following common managed/unmanaged C++ interop
problem:
- I have a .NET form that acts as a front end GUI to a processing
engine in the background. The processing engine runs as a thread that
is managed by the front-end form class.
- The processing engine must have a callback mechanism to update the
form about progress, and to send status messages that will be displayed
by the GUI.
I am looking for the *simplest* solution that involves least changes to
the processing engine code and doesn't involve writing wrappers for
everything. Based on reading previous posts from this newsgroup, I
ended up with the following pattern:
// Form.h
class Form
{
// controls.
// event handlers.
void btnStart_Click(...);
// GUI status update functions.
void updateStatus(...);
};
---------
// Form.cpp
// the engine object - global variable :-(
Engine myEngine;
// form function implemetations.
void run_engine()
{
try
{
// ... setup the engine ...
myEngine.set_listener(this);
myEngine.process();
// ... cleanup the engine ...
}
catch(/* any exception thrown by Engine */)
{
// exception handler code
}
};
---------
// Engine.h
#include <vcclr.h>
public __gc class Form;
class Engine
{
gcroot<Form *> _pListener;
// engine related variables.
public:
void set_listener(gcroot<Form *> pListener);
// engine related member functions.
};
--------
// Engine.cpp
#include "Engine.h"
#include "Form.h"
#define STATUS(x) {/*format the message*/;_pListener->updateStatus();}
void Engine:rocess()
{
// processing code.
STATUS(("Running test %d of %d.", ...));
// processing code.
}
The method is low-impact because the only changes I did to the Engine
source code were to add 3-4 lines to setup the listener inside the
class, and change the status "#define" to update the status in the
listener. The rest of the code remains untouched and no wrappers were
written.
But, I am unable to have a Engine object as a member variable of the
Form class because of the presence of <gcroot> in the Engine class. I
worked around it by instantiating Engine as a global variable (yuk !)
in Form.cpp, but it *works* so far.
I'd appreciate it if the .NET gurus in this group would make a
constructive critique of my pattern, and/or make any suggestions to
make it more elegant. Is it possible to follow the same pattern, but
avoid the global variable (or is wrappers the only way to go) ?
Thanks,
Vijay.