Error converting void(__cdecl MyClass::*)() to void * - c++

I am trying to link to an external library in my QT application. The external library has a header file with the following relevant code I'm trying to call:
extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);
In the demo C++ program provided, which has no problems compiling, the following relevant code is:
// in main.cpp
void _stdcall MyFrameSizeCallback(T x) {
do_stuff;
}
int main(int argc, char* argv[]) {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}
I am trying to incorporate this code into my QT application, but getting problems. In my mainwindow.cpp file:
void _stdcall MainWindow::MyFrameSizeCallback(T x) {
do_stuff;
}
void MainWindow::someFunction() {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}
The error I'm getting is:
error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible
What do I need to do? Thanks.

You have two problems. First, void* is a data pointer, not a function pointer. According to the C++ standard, casting between the two is not expected to work. Some platforms provide a stronger guarantee... for example Windows GetProcAddress and *nix dlsym mix the two.
Next, your &MainWindow::MyFrameSizeCallback is not a function pointer, it is a pointer-to-member-function. Calling it requires a MainWindow object, which the external library doesn't know anything about.
You need to provide an ordinary function, not a member function, to the library. If you have some way to get ahold of the MainWindow* object pointer, you can then call its member function to do the real work. Sometimes the library provides a "context" parameter which is passed to your callback; that's a great place to put the object pointer. Otherwise, you'll need to store your MainWindow* in a global variable. Easy if you have just one, while if you have more than one you might go with std::map<IGrabChannel*, MainWindow*>.
Code:
MainWindow* MainWindow::the_window;
void MainWindow::MyFrameSizeCallback(T x)
{
do_stuff;
}
void _stdcall MyFrameSizeCallbackShim(T x)
{
MainWindow::the_window->MyFrameSizeCallback(x);
}
void MainWindow::someFunction()
{
IGrabChannel* pChannel0 = something;
the_window = this;
V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}
If the parameter x isn't an IGrabChannel, change the map datatype and insertion logic accordingly. If the parameter x isn't some sort of unique predictable identifier, you may be limited to only doing callbacks to one MainWindow instance.

Related

Using function pointer as callback

In some SDK I have a method which takes function pointer.
int AutoRead(nAutoRead aEventFun)
where parameter is:
typedef int (__stdcall *nAutoRead)(char *data);
Now I want to use this function in my code like this:
// First need to get pointer to actual function from DLL
CV_AutoRead AutoRead; // CV_AutoRead is typedef for using function pointer
AutoRead = (CV_AutoRead)GetProcAddress(g_hdll,"AutoRead");
// Now I want to use the SDK method and set callback function,
// but I get error on the next line
// error is: 'initializing' : cannot convert from 'int (__cdecl *)(char *)' to 'TOnAutoRead'
nAutoRead f = &callbackFunc;
if(0 == AutoRead(f)) // AutoRead - now refers to the SDK function shown initially
{
}
where callbackFunc is:
int callbackFunc(char *data)
{
}
Apparently I am doing something wrong. But what?
ps. This is typedef for CV_AutoRead
typedef int (CALLBACK* CV_AutoRead)(nAutoRead aEventFun);
This has to do with the calling convention specifier __stdcall that the callback requires. By default your callbackFunc uses __cdecl, causing an error.
To fix this problem, declare callbackFunc as follows:
int __stdcall callbackFunc(char *);
You also need to add __stdcall to the function definition.
See Argument Passing and Naming Conventions for more information on this subject.

Create a new thread using C in Qt4.8

I'm developing a simple instant-messaging software on Ubuntu 12.10, it's client requires GUI.
In the main window of the client, i need to create a thread to keep listening messages received from the server.
Here is the error message:
main.cpp:-1: In function 'int main(int, char**)':
main.cpp:27: error: invalid conversion from 'void*' to 'void* (*)(void*)' [-fpermissive]
/usr/include/pthread.h:225: error: initializing argument 3 of 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)' [-fpermissive]
In the maininterface.h:
Class MainInterface: public QWidget
{
public:
explicit MainInterface(QWidget *parent = 0);
~MainInterface();
void* ServerMSGWatch(void *threadArgs=NULL); // function run in the new thread
};
It's definition in maininterface.cpp is:
void* MainInterface::ServerMSGWatch(void *threadArgs)
{
pthread_detach(pthread_self());
char arrServerMSGRecv[SERVER_MSG_MAX_SIZE + 1];
while(1){
recv(Login::sockClnt, arrServerMSGRecv, SERVER_MSG_MAX_SIZE+1, 0);
Handle_Server_MSG(arrServerMSGRecv);
memset(arrServerMSGRecv, 0, SERVER_MSG_MAX_SIZE+1);
}
return NULL;
}
in main.cpp:
MainInterface mWindow;
mWindow.show();
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, mWindow.ServerMSGWatch(), NULL);
and in this question, i figured out that maybe there's something wrong with using a C++ compiler to compile c code.
so i tried to add a 'c_pthread.h':
#ifndef C_PTHREAD_H
#define C_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
void* ServerMSGWatch(void *threadArgs=NULL);
void Handle_Server_MSG(char *arrServerMSGRecv);
#ifdef __cplusplus
}
#endif
#endif // C_PTHREAD_H
and c_pthread.cpp:
void* ServerMSGWatch(void *threadArgs=NULL)
{
//definition
}
void Handle_Server_MSG(char *arrServerMSGRecv)
{
//definition
}
then invoke it in main.cpp:
#include "c_pthread.h"
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, ServerMSGWatch(), NULL);
but i still got the same error.
PS: sorry about some malapropisms.
You have two problems: The first is that you call the function instead of passing it. The other is more subtle, and is that you can't use a non-static class member function as a thread function.
The reason for the last problem is because non-static member function have a hidden first argument that is the this pointer.
In this case you can solve it by adding a static member function, and pass a pointer to the object as argument to the thread function. Then the static function calls the actual function in the object:
class MainInterface: public QWidget
{
public:
...
static void* StaticServerMSGWatch(void* arg)
{
reinterpret_cast<MainInterface*>(arg)->ServerMSGWatch();
return nullptr;
}
void ServerMSGWatch(); // function run in the new thread
};
...
pthread_create(&pthreadID, NULL, &MainInterface::StaticServerMSGWatch, &mWindow);
If you have a C++11 capable compiler and library, you could use std::thread instead:
std::thread myThread(&MainInterface::ServerMSGWatch, &mWindow);
As you see, you no longer need the static member function.
You're using Qt, so I strongly suggest using QThread. This will guarantee compatibility and the interop with the rest of your program will be better.
That being said, you need to pass a function pointer to pthread_create, and a member function pointer is not a function pointer: either make it static or make it a freestanding function.
In C++11, there's no need to muck around with low-level system libraries:
std::thread thread([&]{mWindow.ServerMSGWatch();});
If you're stuck with a historic version of C++ then, since you say you're using Qt, you might consider its thread class QThread.
If you're stuck with pthreads then, being a C API, it knows nothing about member functions, so you'll need a non-member, or static member function. (Strictly speaking, you should only use a non-member function declared extern "C", but in practice C++ functions will work on any sensible implementation).
So you'll need a wrapper function to call the member function:
void * CallServerMSGWatch(void * p) {
return static_cast<MainInterface*>(p)->ServerMSGWatch();
}
and tell pthread_create to pass a suitable pointer through to this:
pthread_create(&pthreadID, NULL, CallServerMSGWatch, &mWindow);
mWindow.ServerMSGWatch() is a function call.
mWindow.ServerMSGWatch is a function pointer.

Can't use SDL Threads

I'm using Visual Studio 2012 with SDL and I'm doing a simple threading task but I always get these errors:
argument of type "int (mainGame::*)(void *ptr)" is incompatible with parameter of type "int (__cdecl *)(void *)"
The other error I'm getting:
error C3867: 'mainGame::gameEvents': function call missing argument list; use '&mainGame::gameEvents' to create a pointer to member
This is how the function is written:
int gameEvents(void *ptr){
//do things here.
return 0;
}
This is the code I'm using to call the function:
SDL_Thread* gh;
gh = SDL_CreateThread(gameEvents,NULL);
Since you're using C++, you need to declare your function with C linkage, since that's what SDL expects, being a C library itself:
extern "C" int gameEvents(void *ptr);
Change gameEvents() to static. Otherwise your member function will have a "hidden" first argument for the this pointer that C APIs like SDL don't know about.
If you need access to instance data do something like this:
static int mainGame::gameEvents(void *ptr)
{
mainGame* game = (mainGame*)ptr;
//do things here.
return 0;
}
...
mainGame game;
SDL_Thread* gh;
gh = SDL_CreateThread( mainGame::gameEvents, &game );

How do I obtain a function pointer to the main() method in C++?

I'm working on MS C++ compiler, and have done the next program:
#include <stdio.h>
void main(void)
{
void(*ptr)(void) = &main;
}
I wanted to make a pointer on main() method/function, but has got the next error:
error C2440: 'initializing' : cannot convert from 'int (__cdecl *)(void)' to 'void (__cdecl *)(void)'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
I wonder:
how can I get the pointer of function/method main()
why by default in output is info about int __decl..., but I have exactly wrote void on main() , not int?
Here’s how to obtain a pointer to the main function:
#define DECLARE_UNUSED( name ) (void) name; struct name
int main()
{
int(*ptr)() = &main;
DECLARE_UNUSED( ptr ); // Prevents using `ptr`.
// Don't use `ptr` here. In particular, don't call.
}
Note that
main must have result type int.
calling main (e.g. via that pointer) incurs Undefined Behavior.
It is not necessary to return anything from main; the default return value is 0.
As you can see main is a very special function.
Those rules do not (in general) apply to other functions.
Also note that Visual C++ is wrong in not diagnosing void result type.
Finally, note that writing non-standard void is one character more to type than standard int, i.e., it is just a very, very dumb thing to do. ;-)
PS: Visual C++ is probably mumbling things about int main because it (probably) translates void main to int main internally, and probably it does that to make things link with a non-intelligent linker while actively supporting void main so that e.g. Microsoft’s own non-standard examples in their documentation will compile. That’s my theory #1 anyway, since you ask. But it is, of course, pure guesswork, and it may be that even those who coded that up have no clear idea of why (theory #2).
Well, if you really want to change the entry point of an executable, find the Optional Header by following the steps here, offset 16 bytes and change the 4 bytes. You can find the PE specification here. In order to change the executable file itself while running, you will need some assembly trick, or emit another executable, run a batch and kill the running process.

C++ Windows Plugins - Passing Classes

I am working on a plugin system in C++ whereby a C++ executable loads a dll and runs plugin_start(someclass&) via GetProcAddress.
I fully understand how to pass function pointers to the dll, and visa versa, and how the dll may use anything defined in a header file, but I would like the dll to be able to use someclass where someclass is declared in someclass.h BUT DEFINED in someclass.cpp.
The catch is, someclass is compiled into the calling executable which means when the dll tries to call a function it gets a linker error. I even understand why this is, what I don't understand is how to achieve what I want.
I imagine I can pass a pointer to the object, and a pointer to the function ie someclass* somefunction* and then call it as someclass->*somefunction() but this means I would have to pass a pointer to every function in every class.
Is there an easier way to do this, or should I stick to C-style functions and function pointers alone and forget trying to pass entire classes between the two?
Thanks,
Ben
#ifndef EVENTREGISTRAR_H
#define EVENTREGISTRAR_H
#include <vector>
typedef void (__stdcall *error_callback_t)(const char *error);
class EventRegistrar
{
public:
void OnError(error_callback_t fn);
void FireError(const char *error);
private:
std::vector<error_callback_t> errors;
};
#endif
-- Cpp
#include "PluginLoader.h"
void EventRegistrar::OnError(error_callback_t fn)
{
this->errors.push_back(fn);
}
void EventRegistrar::FireError(const char *error)
{
for (std::vector<error_callback_t>::iterator it = this->errors.begin();
it != this->errors.end(); ++it)
{
(*it)(error);
}
}
-- DLL
#include "../plugin.h"
#include <stdio.h>
void __stdcall error(const char *error) { printf("Error: %s\n",error); }
extern "C" int __stdcall plugin_start(plugin_start_data& data)
{
error_callback_t fn = error;
data.events.OnError(fn);
return LOAD_SUCCESS;
}
--Error
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall EventRegistrar::OnError(void (__stdcall*)(char const *))" (?OnError#EventRegistrar##QAEXP6GXPBD#Z#Z) D:\Files\C++ Workspace\BLib\BLib\Example Plugin\main.obj Example Plugin
I did something like this a long time ago. I simply used a straight C interface to keep things simple.
There may be a better way but I think passing a pointer to the object is your best and most straight-forward approach.