Link to home
Start Free TrialLog in
Avatar of quiklearner
quiklearner

asked on

Function pointer type mismatch

I am using MSVC++ 6.0.  I have an application and a client, both mine.  I was attempting to handle some emulated file i/o stuff within the client, however the work is being perfomred by a set of libraries (not mine) called by the application.  Basically I have to maintain/retain the structure (type defined in the 3rd party library) that holds the pointers to the three functions (read, write, seek) inside of the application.  Where i attempt to set the pointers (example):
channel[iLineNumber - 1].ChanUIO.u_read = channel[iLineNumber - 1].MCPCli->uio_read;
I get:
error C2440: '=' : cannot convert from 'int (__thiscall McpRef::McpClient::*)(int,char *,unsigned int)' to 'int (__cdecl *)(int,char *,unsigned int)'

I had changed the calling convention on these to __cdecl but it didn't get me any further.  I believe this will be real easy, but if not, how should I go about it?
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Normally we don't have to think about a function's calling convention: The compiler assumes __cdecl as default if you don't specify another convention. The calling convention tells the compiler things like how to pass the arguments or how to generate the name of a function.Thus functions and function pointers with different calling convention are incompatible with each other.Microsoft compilers you specify a specific calling convention between the return type and the function's or function pointer's name.
Like:
void __cdecl DoIt(float a, char b, char c);

Did you try this?
Best Regards,
DeepuAbrahamK
>>Did you try this?

With a class member function?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Although this may not be a very elegant way of doing it, you can get the address of the member function, store it in a global var and then pass it along to the fn ptr in the 3rd party lib. I did use this hack sometime back, and it worked although I cannot say it is a very robust soln. Probably itsmeandnobodyelse & jkr can comment on it
As jkr told you can't convert a pointer to a non-static member function to a static or gobal function pointer cause the argument lists were different. A cast to be able to store the member pointerwill work but the call must crash if the 'this' was used in the function. The 'this' was stored in the ECX register for normal calls of non-static member functions. If it was called by using a casted function pointer the ECX  most likely is invalid.

Note, if your member function doesn't need an instance to operate on you should define it as a static function. If it needs to use non-static members it will crash when using the hack above.

Regards, Alex
Avatar of quiklearner
quiklearner

ASKER

It does need to be an instanced set and I do not use the this pointer in them.  In fact, the way i am using them, seek and write do nothing but return something emulating a standard result.  The problem is that these are going to be called back by the third party library and I will have no idea before hand how to identify which instance to use.  What I am dealing with here is an audio buffer stored in a list<string>.  I was hoping to have the "client" dealing with the buffers and buffering so that my application wouldn't have to deal with it.  Sounds like I may have to move some of that to my app though..
Why didn't you give it a try and make the functions static functions as jkr already has recommended twice? Static member function work wonderfully as callbacks as long as you don't try to access non-static members within. Then, the compiler will complain.

How to do?

Simply add the keyword static before the declaration of member function uio_read in class McpClient.

Regards, Alex
but if a static member is not seperate based on instancing, then i can only use it once..  I think i can pull it off by creating local functions in my app that get used for the call back and then within those determine which channel the callback applies to (i should be able to in the context of my main appliaction) and call the functions myself directly on the object.
>>>> static member is not seperate based on instancing, then i can only use it once

As I showed you above with my code a static function has to 'find' the current instance, e. g. by evaluating a static array that contains all instances (clients) and using the arguments it get passed. Or, if it doesn't find/have a current instance, it may create one. After it has a instance it could call non-static member function using the instance found. You should tell us what is the trigger of the callback and what is the meaning of the arguments.

Regards, Alex
 
This function is called back to when the third party's device is giong to be playing from the audio i have captured from the network.  The "client" is the network audio piece i found source for and have now modified to contain its own buffers.  I was hoping to have the client buffer and deal with all of the audio and simply have the application direct where it goes.  A "channel" is a structure representing a single third party device .  It contains, within it, one instance of the client's class.  A client class isn't exactly aware of others that may exist.  Maybe I got into all of this trouble because I am most familiar with VB..
Ok that sounds all good and the only thing we have to achieve is to find either client or channel.

What is the meaning of the arguments passed to the callback function?

Regards, Alex
since i am not even using write and seek functions, I will just talk about the read function.  At first i was lead to believe the first arg was junk and the two latter ones are the buffer (char*) and size.  If my return != size then it assumes EOF.  As it turns out, the first is a handle i have in my channel.  If i create i/o functions in my app that these get pointed to, i will then be able to identify the channel and call the functions in the particular client instance myself, if i am understanding the shortfall of the instancing correctly.  This will probably be the quickest from where i am at!?!?
>>>> i will then be able to identify the channel

Bingo. That's the idea of all callbacks. One argument is an identifier that allows you to looking up some global (or static class) arrays (containers) for the object to operate on further.

Good luck.