is there a possibility or a workaround to pass a member function to the Windows API function QueueUserAPC()?
Okay, I could pass a static member function.
But then I won't have full access to local member variables...
So is there a possibility to combine both, passing as member function and full access to non-static member variables?
I tried to work out a solution related to this but without any success yet.
Hopefully someone got an idea to solve this.
This is a kind of standard pattern to use when having C-style callbacks call your C++ functions.
You create a free function (or static member) that forwards the call ...
VOID CALLBACK ForwardTo_MyClass_func( _In_ ULONG_PTR dwParam )
{
auto* p = (MyClass*)dwParam;
p->func();
}
... and you then set it up by passing the instance pointer as the third parameter to QueueUserAPC:
QueueUserAPC( ForwardToMyClass_func, hThread, (ULONG_PTR)pMyClass );
If you need further arguments, you will have to create some kind of structure to hold both the instance pointer and the arguments.
The answer is no.
Windows API has a C interface, and therefor cannot handle name mangled signatures, such as C++ member functions. The function you pass must be a C style free function.
By the way, nesting it in a namespace is acceptable, if less scalable:
namespace apc_stuff
{
static MyStruct some_static_data;
static void __stdcall MyApcFunc(ULONG_PTR data); // PAPCFUNC
};
using namespace apc_stuff;
MyClass::DoSomething(...)
{
auto my_data = new MyData(...);
auto data = reinterpret_cast<ULONG_PTR>(my_data);
QueueUserAPC(MyApcFunc, hThread, data)
}
/*static*/ void __stdcall apc_stuff::MyApcFunc(ULONG_PTR data)
{
auto my_data = reinterpret_cast<MyData *>(data);
//
// use my_data
// use some_static_data
//
}
Related
So first I load in a DLL I need
local ffi = require("ffi")
local theDLL = ffi.load("thisDLL")
in the ffi cdef I have two different kinds of structs
ffi.cdef [[
typedef struct StructSession StructSession;
typedef struct {
/*
* begin_proj callback
*/
bool (__cdecl *begin_proj)(char *proj);
/*
* save_proj_state
*/
bool (__cdecl *save_proj_state)(unsigned char **buffer, int *len);
} StructCallbacks;
I also have this function in the cdef
__declspec(dllexport) int __cdecl start_session(StructSession **session,
StructCallbacks *cb);
Now I would like to call this function
print(theDLL.start_session(a,b))
vars a and b are obviously placeholders, the question is how can I pass the structs the function needs? And say we get StructSession working, is making a callback to a function WITHIN LuaJIT even going to be possible for StructCallbacks?
Creating the StructCallbacks is easy; you can create it with ffi.new and create FFI callbacks for the fields (see the FFI semantics for information on callbacks).
Creating the StructSession is trickier since it's an opaque type, but it's not much different from how you would do it in C.
Here is how you would create one in C:
StructSession* S = NULL;
start_session(*S, foo);
Notice how you are not directly allocating a StructSession. Instead, you allocate a pointer to one, and let start_session allocate the actual struct.
So we now translate this to LuaJIT code:
local S = ffi.new("StructSession*")
lib.start_session(getPointer(S), foo) -- getPointer should take the pointer of S, but...
...the FFI doesn't provide any way to take the pointer of an object (This is intentional; it allows for optimizations).
So how do we get a pointer to a StructSession? Well, recall that arrays are convertible to pointers, and we can access those through the FFI. So we instead create a single-slot array of pointers and pass that to start_session:
local S_slot = ffi.new("StructSession*[1]")
lib.start_session(S_slot, foo)
local S = S_slot[0]
And now you have a StructSession object.
I am using libusb to interact with a usb device. I have created a Class and a member function will receive the input from the device and process it. I am using Asynchronous api. Now the libusb_fill_bulk_transfer() function call throws a compilation error:
void MyDeviceClass::on_connectButton_clicked()
{
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
qDebug()<<"Init Error "<<r<<endl; //there was an error
return;
}
...
...
...
libusb_fill_bulk_transfer( transfer_in, dev_handle, USB_ENDPOINT_IN,
inBuffer, LEN_IN_BUFFER,readDataFromBuffer,NULL,0);
libusb_submit_transfer(transfer_in);
QtConcurrent::run (this,&MyDeviceClass::eventThread);
}
The compiler suggests using &MyDeviceClass::readDataFromBuffer as a function pointer but that still throws an error. I tried using static members, and even static non-member functions but all in vain. Please help me in passing the callback to this function. I am using Qt, and probably won't like to use boost libraries.
Please note that libusb_fill_bulk_transfer(...) is invoked inside a member function of MyDeviceClass.
I made the member function static and prototype needed to be modified:
static void LIBUSB_CALL readDataFromBuffer(struct libusb_transfer *);
what is the compile error when you use a non member function?
Edit: this should be LIBUSB_CALL:
void LIBUSB_CALL BulkTransferCallback(struct libusb_transfer *transfer) {
// This assumes that you set transfer::user_data to be a pointer to
// an instance of the MyDeviceClass class.
MyDeviceClass* mdc = reinterpret_cast<MyDeviceClass*>(transfer->user_data);
mdc->onBulkTransferCallback(transfer);
}
Then when you set the pointer, use:
transfer.callback = &BulkTransferCallback;
As you answered yourself, actually it should be __stdcall which is defined by LIBUSB_CALL. Their documentation should include this in the function pointer typedef to remove the ambiguity.
The lib_usb api defines the function libusb_fill_bulk_transfer with:
static void libusb_fill_bulk_transfer (struct libusb_transfer *transfer, libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *buffer, int length, libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
It is possible to add a static class function to your class and call the non-static member-function
of the class within this static function.
You this Object would be at the place of void *user_data.
In the static class function you would have to cast the member of
transfer->user_data correctly to your class.
I'm trying to pass 2 pointers as an arguement for another function typecasted into (void*)
How do I seperate those two in the final function?
Example:
class Backgrounder{
public:
MESSAGE_QUEUE* m_pMsgQueue;
LockSection* m_pLc;
static void __cdecl Run( void* args){
MESSAGE_QUEUE* s_pMsgQueue = (MESSAGE_QUEUE*)args[0]; // doesn't work
LockSection* s_pLc = (LockSection*)args[1]; // doesn't work
}
Backgrounder(MESSAGE_QUEUE* pMsgQueue,LockSection* pLc) {
m_pMsgQueue = pMsgQueue;
m_pLc = pLc;
_beginthread(Run,0,(void*)(m_pMsgQueue,m_pLc));
}
~Backgrounder(){ }
};
You should create a struct with these two pointer types as members, and pass a pointer to that around.
The expression (m_pMsgQueue,m_pLc) doesn't do what you think it does; it invokes the comma operator, which simply evaluates to the second argument.
Bundle the arguments into a struct and pass that.
You could wrap them together in a struct and pass a pointer to that struct. Be careful though, because that struct should not be declared locally to the Backgrounder constructor - that would cause undefined behaviour because the thread may still be running after the function that started it has terminated. It should either be dynamically allocated, a static class member, or a global variable.
Actually, I would pass the this pointer since you essentially want to be able to access the fields of the object within the Run function:
class Backgrounder{
public:
MESSAGE_QUEUE* m_pMsgQueue;
LockSection* m_pLc;
static void __cdecl Run (void *pThis) {
MESSAGE_QUEUE* s_pMsgQueue = ((Backgrounder *) pThis)->m_pMsgQueue;
LockSection* s_pLc = ((Backgrounder *) pThis)->m_pLc;
}
Backgrounder(MESSAGE_QUEUE* pMsgQueue,LockSection* pLc) {
m_pMsgQueue = pMsgQueue;
m_pLc = pLc;
_beginthread(Run, 0, (void *) this);
}
~Backgrounder(){ }
};
Of course, you'll need to make sure that the newly created Backgrounder object is not prematurely destroyed, that is, the thread should be finished before the destruction.
Also, if these fields are later modified from the parent thread, you'll need to employ the appropriate synchronisation mechanisms.
I am brushing up again and I am getting an error:
Cannot call member function without object.
I am calling like:
FxString text = table.GetEntry(obj->GetAlertTextID());
FxUChar outDescription1[ kCP_DEFAULT_STRING_LENGTH ];
IC_Utility::CP_StringToPString(text, &outDescription1[0] );
The line: IC_Utility::CP_StringToPString(text, &outDescription1[0] ); is getting the error
My function is:
void IC_Utility::CP_StringToPString( FxString& inString, FxUChar *outString)
{
}
I know it has to be something simple I am missing.
If you've written the CP_StringToPString function, you need to declare it static:
static void IC_Utility::CP_StringToPString( FxString& inString, FxUChar *outString)
Alternatively, if it's a function in third-party code, you need to declare an IC_Utility object to call it on:
IC_Utility u;
u.CP_StringToPString(text, &outDescription1[0] );
Your method isn't static, and so it must be called from an instance (sort of like the error is saying). If your method doesn't require access to any other instance variables or methods, you probably just want to declare it static. Otherwise, you'll have to obtain the correct instance and execute the method on that instance.
You have to declare the function with the 'static' keyword:
class IC_Utility {
static void CP_StringToPString( FxString& inString, FxUChar *outString);
You need to declare the function static in your class declaration. e.g.
class IC_Utility {
// ...
static void CP_StringToPString(FxString& inString, FxUChar *outString);
// ...
};
"static" is the right answer. or, you can pass it a NULL "this" pointer if it's not used in the function:
((IC_Utility*)NULL)->CP_StringToPString(...);
Using C++.
pthread_t threads[STORAGE]; // 0-99
...
void run()
Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL);
if (status != 0)
{
printf("pthread_create returned error code %d\n", status);
exit(-1);
}
...
void ClientHandler::updateMessages(void *)
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
...
Compile Error:
TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’
I can't figure out whats wrong.
Thanks in advance.
A pointer to a member function is different from a global function with the same signature since the member function needs an additional object on which it operates. Therefore pointers to these two types of functions are not compatible.
In this case this means that you cannot pass a member function pointer to pthread_create but only a pointer to a non-member (or static) function. A work around for this problem is to use the forth parameter of pthread_create to pass a pointer to a object to a global function which then calls the method of the passed object:
class ClientHandler {
public:
void updateMessages();
void run();
};
// Global function that will be the threads main function.
// It expects a pointer to a ClientHandler object.
extern "C"
void *CH_updateMessages(void *ch) {
// Call "real" main function
reinterpret_cast<ClientHandler*>(ch)->updateMessages();
return 0;
}
void ClientHandler::run() {
// Start thread and pass pointer to the current object
int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this);
...
}
It's nothing to do with threads, it's a normal C++ error, you're just passing an incompatible type of function pointer.
A function pointer is not the same as a member instance function pointer, even if their signature is the same; this is because there is an implicit reference to *this passed. You can't avoid this.
As pthread_create takes a free function, create a static function(is a free function) inside ClientHandler
static void Callback(void * this_pointer,int other_arg) {
ClientHandler* self = static_cast< ClientHandler*>(this_pointer);
self-> updateMessages(other_arg);
}
and call pthread_create as follows
pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg);
That works because Callback is free function
YoLinux has a nice pthread tutorial that my help you in learning about threads.
As others have already said, the problem is that the signatures between the functions are different. Class member functions always have a "secret" extra parameter, the this pointer. So you can never pass a member function where a global function is expected. You can hack around this either with libraries such as Boost.Bind, or by making the function a static member of the class.
But the simplest, and most elegant solution is to use a different threading API.
Boost.Thread is a very nice threading library for C++ (pthreads is designed for C, and that's why it doesnt play well with C++ features such as class methods).
I'd recommend using that.
Your code could be rewritten as something like this:
class ClientHandler {
public:
ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...}
void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
// whatever arguments you want to pass to the thread can be stored here as member variables
};
boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array
gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));
You're passing a member function instead of a global, normal, one.
Just define:
void updateMessages(void *) {
static ClientHandler c;
// use c..
}