How to access a non-static method from a thread in C++ - methods

//In A.h I have the following code
include "afxwin.h"
include "msclr\auto_gcroot.h"
using namespace System;
using msclr::auto_gcroot;
namespace A
{
public ref class A
{
public:
virtual bool Func();
A();
~A();
virtual bool Connect();
protected:
DWORD WINAPI threadConnect(void* pParam);
};
public class AHelper
{
public:
auto_gcroot A;
};
}
//In A.cpp I have below code
// This is the main DLL file.
include "stdafx.h"
include "A.h"
include "string"
include "sstream"
include "stdlib.h"
include "strsafe.h"
include "windows.h"
include "tchar.h"
namespace A
{
A::A()
{
m_FuncHandle = mpsNil;
}
A::~A()
{
}
bool A::Func()
{
return true;
}
bool A::Connect()
{
AHelper* AHelper;
m_retVal = false;
AHelper = new AHelper();
AHelper->A = this;
HANDLE Handle_Of_Thread = 0;
DWORD dwThreadId;
//DWORD WINAPI threadConnect(void* pParam);
//If I declare the function declaration here I am getting
//error LNK2001: unresolved external symbol "unsigned long __stdcall threadConnect(void *)"
(?threadConnect##YGKPAX#Z)
Handle_Of_Thread = CreateThread
(NULL, 0, threadConnect, AHelper, 0, &dwThreadId); // with this code I am getting
//error C3867: 'A::A::threadConnect': function call missing argument list; use '&A::A::threadConnect' to create a pointer to member
return m_retVal;
}
DWORD WINAPI A::threadConnect(void* pParam)
{
AHelper* AHelper = reinterpret_cast(pParam);
//Here I need to call Func
return 0;
}
}

the usual trick is to have a static function that takes an id of some sort, this function determines which someFunc() to call (as each object will have its own someFunc, you obviously need to know which one) either using a lookup, or as is common in C/C++ apps, by passing the address of the object directly.
so you have something like:
static bool thread_func(object o)
{
return o->someFunc();
}
The trick is that the static function must be reentrant, so holds no state itself for the threads to interfere with (or if it does, make sure its thread safe)
That all supposes you're calling a method on an object that was not created within the thread. If you're just calling a function and you already have the object created within your thread, just call the function!

Related

dll to caller main dialog

I am desparately in search of MFC dll sample that updates an edit field on a dialog derived from CDialog with a string using only the callback function. I realize static functions are the ones that are used in the calback.
I guess you realise that the dll should have something (like a separate thread, or a certain third-party message handler for this model. So, this is out of scope for this question.
Back to the question:
In order to create a callback function you need to "typedef" its prototype and pass the address of this function from your calling app to the dll. In your dll "h" file specify this:
// This is the Mfcdll1.h header file
// You should have some code created by the wizard, similar to the following:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
// This is the typedef for your callback function type:
typedef void (CALLBACK* MY_DLL_CALLBACK)
(
LPVOID lpParam,
LPCTSTR lpszMessage
);
class CMyDllApp : public CWinApp
{
public:
CMyDllApp();
// etc.
void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm){m_pCallback = pCallback; m_pCallbackParm = pCallbackParm;}
private:
MY_DLL_CALLBACK m_pCallback;
LPVOID m_pCallbackParm;
};
MYDLL_API void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm);
In your dll's cpp file specify this:
CMyDllApp::CMyDllApp()
{
m_pCallback = NULL;
m_pCallbackParm = NULL;
}
MYDLL_API void SetCallBack(MY_DLL_CALLBACK pCallback, LPVOID pCallbackParm)
{
theApp.SetCallBack(pCallback, pCallbackParm);
}
Now, if your dll wants to call the callback function, all you need to do is:
CMyDllApp::SendCallbackToTheCaller(LPCTSTR lpszMessage)
{
if(m_pCallback) (*(m_pCallback))(m_pCallbackParm, lpszMessage);
}
At this stage you have done coding in the dll. Now, all you need to do is specify the static callback function in your dialog that will update you Edit control, similar to this:
In the h file:
// TestDlg.h - My Test dialog with the Edit Control
CTestDlg: public CDialog
{
public:
static void CALLBACK StatusCallback(LPVOID lpParam, LPCTSTR lpszMessage);
};
In the cpp file:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Insert this line along your stuff
::SetCallback((MY_DLL_CALLBACK)StatusCallback, (LPVOID)this);
}
void CALLBACK CTestDlg::StatusCallback(LPVOID lpParam, LPCTSTR lpszMessage)
{
CTestDlg* pTestDlg = reinterpret_cast<CTestDlg*>(lpParam);
ASSERT(pTestDlg!=NULL);
pTestDlg->m_edStatus.SetWindowText(lpszMessage);
}

C++ class member callback and external library

I would like to solve this issue about class member function callback.
Imagine you have a function from an external library (which cannot be modified!) like this:
void fortranFunction(int n, void udf(double*) );
I would like to pass as the udf function above a function member of an existing class. Please look at the following code:
// External function (tipically from a fortran library)
void fortranFunction(int n, void udf(double*) )
{
// do something
}
// User Defined Function (UDF)
void myUDF(double* a)
{
// do something
}
// Class containing the User Defined Function (UDF)
class myClass
{
public:
void classUDF(double* a)
{
// do something...
};
};
int main()
{
int n=1;
// The UDF to be supplied is myUDF
fortranFunction(n, myUDF);
// The UDF is the classUDF member function of a myClass object
myClass myClassObj;
fortranFunction(n, myClassObj.classUDF); // ERROR!!
}
The last line of the code above results in a compilation error, because you cannot declare the classUDF member function as a static function.
Do you know if it is possible to solve this issue?
Probably Boost libraries could help me, but I do not know how (please consider that fortranFunction cannot be modified because is from an external library).
Thanks a lot!
Alberto
I don't understand, why can't you declare classUDF as static like this
class myClass {
public:
static void classUDF(double *a) {
...
}
};
and then pass it like
fortranFunction(n, myClass::classUDF);
You might try that solution (a little bit hacky, but I think, it should work for you):
void fortranFunction(int n, void udf(double*))
{
double d = static_cast<double>(n);
udf(&d);
}
class myClass {
public:
void classUDF(double* a) {
}
};
#ifdef _MSC_VER
#define THREADLOCALSTATIC __declspec(thread) static
#define THREADLOCAL
#else
#define THREADLOCALSTATIC static ___thread
#define THREADLOCAL ___thread
#endif
struct _trampolinebase {
THREADLOCALSTATIC _trampolinebase* current_trampoline;
};
THREADLOCAL _trampolinebase* _trampolinebase::current_trampoline = 0;
#undef THREADLOCAL
#undef THREADLOCALSTATIC
template<class CBRET, class CBARG1, class T>
struct _trampoline1 : _trampolinebase
{
typedef CBRET (T::*CALLBACKFN)(CBARG1);
_trampoline1(T& target, CALLBACKFN& callback)
: callback_(callback)
, target_(target)
{
assert(current_trampoline == 0);
current_trampoline = this;
}
static CBRET callback(CBARG1 a1) {
_trampoline1* this_ = static_cast<_trampoline1*>(current_trampoline);
current_trampoline = 0;
return this_->trampoline(a1);
}
private:
CBRET trampoline(CBARG1 a1) {
return (target_.*callback_)(a1);
}
CALLBACKFN& callback_;
T& target_;
};
template<class FRET, class FARG1, class CBRET, class CBARG1, class T, class F>
FRET call1_1(T& target, CBRET (T::*callback)(CBARG1), F& fortranfunction, FARG1 a)
{
typedef typename _trampoline1<CBRET, CBARG1, T> trampoline;
trampoline t(target, callback);
return fortranFunction(a, trampoline::callback);
}
int main()
{
int n=1;
myClass myClassObj;
call1_1<void,int,void,double*>(myClassObj, &myClass::classUDF, fortranFunction, 1);
}
With the 'threadlocal' stuff, this will work in multithreaded calls, too. You may omit that, if you don't use a multithreaded environment. It also works with recursive calls (e.g. if the callback calls another fortran function).
This solution works only for one single argument plus callback for the fortran function and one single argument in the callback function itself, but you should be able to extend it easily. This is also, why I called it 'call1_1' (fortran function with 1 argument, callbackfunction with 1 argument). FRET is the return type of the fortran function, FARG1 the type of the first argument (int in this case). CBRET and CBARG are the same for the callback function.
Before the fortran function is actually called, the target object is stored within a global (thread-local) variable. The fortran function calls a static callback function, which finally calls your member function.
I invented the trampolinebase to instantiate the static member, I could also have used a global variable for that (but for some reason, I don't like global variables too much) ;-)

Passing non static delegate property function as parameter in C++ / CLI

I make a interface class in C++ for voice recognition, i´m using the Julius API. http://julius.sourceforge.jp/en_index.php?q=index-en.html.
Well, my class has some events, these events will be triggered by the Julius API.
The Julius API has the function call callback_add with this signature:
int callback_add (Recog *recog, int code, void(*func)(Recog *recog, void *data), void data)
I using some 'proxy' functions to Invoke the events and passing this functions to callback_add.
If the property event is static, it works fine, but if is a non static, inside the proxy function the property not be recognized.
The difficult is because I have to use the callback_add function and can't modify this.
Here is a summary of the class with 2 events (static and non-static)
Header
#ifndef FALAENGINE_H_
#define FALAENGINE_H_
#pragma once
extern "C"{
#include <julius/julius.h>
}
namespace FalaAPI {
public ref class FalaEngine
{
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
static property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
}
#endif /* FALAENGINE_H_*/
Source
#include "stdafx.h"
using System::String;
using System::Console;
#include "FalaEngine.h"
#include <windows.h>
namespace FalaAPI{
void StartOnEngineStart()(Recog *recog, void * dummy){
if(FalaEngine::OnEngineStart->GetInvocationList()->Length > 0)
FalaEngine::OnEngineStart->Invoke();
}
void StartOnRecognized()(Recog *recog, void * dummy){
if(FalaEngine::OnRecognized->GetInvocationList()->Length > 0)
FalaEngine::OnRecognized->Invoke();
}
FalaEngine::FalaEngine(){
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, NULL);
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, NULL);
}
}
The problem occurs inside StartOnEngineStart function:
error C2227: left of '->GetInvocationList' must point to class/struct/union/generic type
A non-static member exists separately in each instance. You haven't specified which instance contains the delegate you want to inspect, you've only specified a class (and there may be many instances).
Try using the dummy parameter to pass your instance. But be careful, because the garbage collector will move objects around unless you have pinned them, so simply passing the address will not work. You need to create and pass a GCHandle instead. (Be careful not to leak the GCHandle, or your object will never be released)
Something like this should be effective:
ref class FalaEngine;
struct EngineHandle
{
gcroot<FalaEngine^> handle;
EngineHandle(FalaEngine^ engine) : handle(engine) {}
};
public ref class FalaEngine
{
clr_scoped_ptr<EngineHandle> callback_ptr;
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
void StartOnEngineStart(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnEngineStart(); // C++/CLI already checks if the invocation list is empty
}
void StartOnRecognized(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnRecognized(recog->get_result());
}
FalaEngine::FalaEngine()
: callback_ptr(new EngineHandle(this))
{
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, callback_ptr.get());
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, callback_ptr.get());
}
The clr_scoped_ptr class is here. There are not many license requirements, make sure you follow them though if you use it.

i am exporting dll but GetProcAddress returning 127 error ,how to resolve it?

#include "Calc.h"
#include<iostream>
#include <windows.h>
#include <WINERROR.H.>
typedef void (WINAPI * PCTOR) ();
int main()
{
HMODULE hMod = LoadLibrary (L"Calci.dll");
if (NULL == hMod)
{
printf ("LoadLibrary failed\n");
return 1;
}
CCalc *pCCalc = (CCalc *) malloc (sizeof (CCalc));
if (NULL == pCCalc)
{
printf ("memory allocation failed\n");
return 1;
}
PCTOR pCtor = (PCTOR) GetProcAddress (hMod, "CCalc");//127 error
int err = GetLastError();
if (NULL == pCtor)
{
printf ("GetProcAddress failed\n");
return 1;
}
__asm { MOV ECX, pCCalc };
pCtor ();
return 0;
}
//dll file
#include <tchar.h>
#ifdef CALC_EXPORTS
#define CALC_API __declspec (dllexport)
#else
#define CALC_API __declspec (dllimport)
#endif
#define SOME_INSTN_BUF 260
class CALC_API CCalc
{
private:
char m_szLastUsedFunc[SOME_INSTN_BUF];
public:
CCalc ();
int Add (int i, int j);
int Sub (int i, int j);
TCHAR* GetLastUsedFunc ();
};
Use dumpbin.exe to check the exact name of the export in the DLL. Maybe it doesn't exist at all?
If you have a chance to use import library instead of LoadLibrary API, it is better.
You're invoking GetProcAddress (hMod, "CCalc"), however "CCalc" isn't the name of a function: it's the name of a class.
You're trying to load the address of the CCalc::CCalc default constructor: to do that, use a tool (e.g. dumpbin) to discover the "decorated" name of the constructor.
However instead of trying to dynamic-load and invoke the constructor, a more usual way to implement this functionality would be to create a static factory method in the DLL, e.g. like this:
class CALC_API CCalc
{
public:
static CCalc* create() { return new CCalc(); }
private:
//doesn't need to be public because users instantiate this class using
//the static create method
CCalc();
public:
virtual int Add (int i, int j);
virtual int Sub (int i, int j);
virtual TCHAR* GetLastUsedFunc ();
virtual ~CCalc() {}
};
Then use GetProcAddress to get the address of the static CCalc::create function, which because it's static you can invoke without using assembly to mess with ECX.
You can't use GetProcAddress for classes. This does not work. Only functions you can resolve their names are unmangled "C" functions.
For example:
extern "C" __declspec(dllexport) CCalc *create_calc()
{
return new CCalc;
}
Now, you can resolve it using.
GetProcAddress(halnder,"create_calc");
As create_calc is not-mangled function.
Also you will have to provide abstract API class without implementation and make CCalc inherit ACalc, otherwise you'll get unresolved symbols tying to compile your application. Because actual add and remove member functions are not known to the application.
class ACalc {
public:
virtual add(int i,int j) = 0;
...
virtaul ~ACalc() {}
};
class CCalc : public ACalc {
public:
virtual add(int i,int j) { ... };
...
};
And in the main program
ACalc *ptr= call_for_dll_function

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