0

I've built a VRPN client on Linux. It's based on this: http://www.vrgeeks.org/vrpn/tutorial---use-vrpn

Here's some of the code:

vrpn_Analog_Remote * analog = NULL;
vrpn_Button_Remote * button = NULL;
vrpn_Tracker_Remote * tracker = NULL;

// Things happen...

analog = new vrpn_Analog_Remote("pathToAnalog");
analog->register_change_handler(NULL, handleAnalog);
button = new vrpn_Button_Remote("pathToButton");
button->register_change_handler(NULL, handleButton);
tracker = new vrpn_Tracker_Remote("pathToTracker");
tracker->register_change_handler(NULL, handleTracker);

Here are the callbacks refered to in this code:

void handleAnalog(void * userData, const vrpn_ANALOGCB a) {
  // Do stuff...
}
void handleButton(void * userData, const vrpn_BUTTONCB b) {
  // Do stuff...
}
void handleTracker(void * userData, const vrpn_TRACKERCB t) {
  // Do stuff...
}

And here is where all of these references to VRPN are defined:

https://github.com/vrpn/vrpn/blob/master/vrpn_Analog.h#L168 https://github.com/vrpn/vrpn/blob/master/vrpn_Button.h#L225 https://github.com/vrpn/vrpn/blob/master/vrpn_Tracker.h#L284

These compile without even a warning on Linux and can actually be used. Everything worked as expected. All the types here seem to satisfy the compiler, g++.

But on Windows, whether I use Visual Studio 2015 or MinGW's g++, I get this for the first two callback registrations:

invalid conversion from 'void (*)(void*, vrpn_ANALOGCB) {aka void (*)(void*, _vrpn_ANALOGCB)}' to 'vrpn_ANALOGCHANGEHANDLER {aka 
 void (__attribute__((__stdcall__)) *)(void*, _vrpn_ANALOGCB)}' [-fpermissive]

invalid conversion from 'void (*)(void*, vrpn_BUTTONCB) {aka void (*)(void*, _vrpn_BUTTONCB)}' to 'vrpn_BUTTONCHANGEHANDLER {aka 
 void (__attribute__((__stdcall__)) *)(void*, _vrpn_BUTTONCB)}' [-fpermissive]

And for the last one, I get a different error:

call of overloaded 'register_change_handler(NULL, void (&)(void*, vrpn_TRACKERCB))' is 
 ambiguous

Now that I'm typing this, I'm thinking maybe VRPN was compiled differently on Windows and that's why the compiler now has a problem with my code. But I'm very lost as to what to do.

eje211
  • 2,385
  • 3
  • 28
  • 44
  • 1
    Looks like the calling convention (`__stdcall__`) is being lost somewhere during the compilation process. Maybe you need to set a `#define` or a compiler preprocessor `-D` to compile successfully, – PaulMcKenzie Jan 29 '16 at 18:23
  • So just add `#define __stdcall__`? I'm not really used to C++ and all of its quirks.¨ – eje211 Jan 29 '16 at 18:25
  • I added `#define __stdcall` and I got a warning that it was already defined. I could find a reference to it in the Microsoft docs, then I changed it to `#define __stdcall__` and now I'm getting linker errors. So it worked. How did you know that was it? Was it in the header code? – eje211 Jan 29 '16 at 18:32
  • For a Windows C++ program, there are things such as calling conventions. The calling convention is considered part of the signature of a function. If the function includes `__stdcall__` as the signature, then your function's calling convention has to be `__stdcall__`. https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx The other calling conventions that is used (by default) is `__cdecl` – PaulMcKenzie Jan 29 '16 at 18:34
  • 1
    You should not be defining `__stdcall__`. You should instead read on what the appropriate preprocessor switches are for your library to compile correctly in Windows. This should have been given to you by the author of the library, or if not that, you have to discover them. Just taking source code from Linux to Windows and compiling is not seamless if you are creating libraries. If you don't know what you're doing, the chances are great that your library *may* build, but will be utterly useless when you try to use it (crashes, for example). – PaulMcKenzie Jan 29 '16 at 18:42
  • VRPN uses CMake. And CMake built it on Windows and things were weird and then it built it on Linux (which I'm much more familiar with) and it worked perfectly. I assumed the problem was with my code. But maybe it's a CMake setting. I'm looking into that now. – eje211 Jan 29 '16 at 18:49
  • 1
    Well, the error is differing function signatures, and the calling convention is missing from either your functions, or from the library's definition (a missing calling convention defaults to `__cdecl`). No different than if a function is declared as returning an `int` and takes a single `int` argument, and you attempt to assign a pointer to a function that returns a `double` and takes an `int` argument. For Windows, the additional gotcha is that the calling conventions have to match. – PaulMcKenzie Jan 29 '16 at 18:53
  • Final question (I hope), why does the Microsoft documentation specify `__stdcall`, which was already defined, and you immediately suggested `__stdcall__` instead and that worked? Where did the one with the underscores on both sides come from? – eje211 Jan 29 '16 at 18:58
  • Microsoft has several renditions of `__stdcall` (`_stdcall, _STDCALL,`). I am assuming it was another one of MS's version of the same thing. The bottom line is that you shouldn't need to define anything, unless you know **exactly** what you're doing, or the author(s) gave you explicit instructions on what preprocessor flags to set ./ unset for a proper build to be generated. – PaulMcKenzie Jan 29 '16 at 19:04
  • Also, does the library `typedef` the correct function signature to use? If so, then your function has to have the *exact* signature that fits the typedef. This includes return type, parameter number and type, **and calling convention type**. So if your function didn't have a calling convention, then it defaults to `__cdecl`, which does not fit `__stdcall`. – PaulMcKenzie Jan 29 '16 at 19:09
  • Probably this can give you a picture of what is probably happening. See this link to `EnumWindows`: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx Do you see the first parameter? Here is the description: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633498%28v=vs.85%29.aspx See the `CALLBACK` in the function signature? That is `__stdcall`. So if you declared your callback without `__stdcall`, you get errors similar to (maybe not exactly) as the errors you're seeing now. – PaulMcKenzie Jan 29 '16 at 19:14

1 Answers1

2

Try declaring your callbacks like this:

void VRPN_CALLBACK handleAnalog(void * userData, const vrpn_ANALOGCB a) {
  // Do stuff...
}

For linux, the VRPN_CALLBACK define is empty, so you did not notice any problems there. For windows, the VRPN library devs decided that they expect a callback that adheres to the __stdcall calling-convention. Thus you have to declare your function accordingly, and the most painless+portable way is to use the very same VRPN_CALLBACK define that they provide.

Clues to this came from your links to the code at github:

[vrpn_Analog.h]
typedef void(VRPN_CALLBACK *vrpn_ANALOGCHANGEHANDLER)(void *userdata,
                                                      const vrpn_ANALOGCB info);

and the callback define is made here:

[vrpn_Configure.h]
#ifdef _WIN32   // [ ...
#define VRPN_CALLBACK __stdcall
#else // ... ] WIN32 [
#define VRPN_CALLBACK
#endif // ] not WIN32
ThorngardSO
  • 1,191
  • 7
  • 7