I'm a harbour programmer and I need know how I can use different calling conventions in a same plain C function, because some DLL manufacturer use __stdcall and another use __cdecl but the functions are the same, example:
static int iCcv = 1;
HB_FUNC( foo )
{
if( iCcv == 1 )
typedef const char * ( __stdcall * pMYFUNC )( int n );
else
typedef const char * ( __cdecl * pMYFUNC )( int n );
pMYFUNC funcMy = (pMYFUNC) GetProcAddress( hLib, "myProc" );
const char * ret;
if( funcMy )
ret = funcMy( hb_parni( 1 ) );
hb_retc( ret );
}
CodePudding user response:
You need something more like:
const int CALLING_STDCALL=1;
const int CALLING_CDECL=2;
typedef const char * ( __stdcall * pMYFUNC_STDCALL )( int n );
typedef const char * ( __cdecl * pMYFUNC_CDECL )( int n );
//... The init() function where the library is linked...
int init(FARPROC* my_func){
*my_func=GetProcAddress( hLib, "myProc" );
if(*my_func==NULL){
return -1;
}
return 0; //Always check you loaded successfully!
}
//.. to call it
const char *CallMyFunc(FARPROC pFunc,int n,int conv){
assert(pFunc!=NULL);//Should never get this far badly loaded.
if(conv==STDCALL){
pMYFUNC_STDCALL func=(pMYFUNC_STDCALL)pFunc;
return pFunc(n);
}
assert(conv==CALLING_CDECL);//Good measure!
pMYFUNC_CDECL func=(pMYFUNC_CDECL)pFunc;
return pFunc(n);
}
The 'magic' here is that the code to call both conventions will be generated and the relevant version executed (assuming the flag was set correctly somehow - that wasn't in the question!).
There's not quite such a thing as a generic function-pointer (though you can round-trip function-pointers between function-pointer types) and there is no guarantee in C that void *
will do(*). But on the Windows Platform FARPROC
is provided for that purpose. Behaviour is defined in the platform for casting FARPROC
to the correct type.
The above would benefit from a bit more type-safety by wrapping the pointer in a safety struct
but I think that might bury the essence here.
Please. Please! Do put in a good dose of error checking and maybe elevate my debug asserts()
to permanent release build checks.
Having worked at a place where things were a mountain of peripherals and DLLs that didn't always do what they said on their box any help in diagnostics is worth its weight in gold.
(*) though on modern platforms usually does.