Reputation: 55
I've written a C program that uses an array of pointers to functions. The functions are both inside my program and in loadable DLL's. My problem comes when I try to use a DLL that came from a C++ program. Here's a simplified snippit of the code in the C++ (DLL) program:
#ifdef __cplusplus
#define EXPORT extern "C" __declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
typedef struct { float x,y,z; } VECT;
EXPORT VECT norm(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col)
{
VECT npt;
...
*pt = npt; /* give pt a new value */
...
}
The problem is it crashes as soon as I try to do anything with pt. It's not NULL, but if I try to write to it or even just access it's members, it crashes. I've kind of solved the problem by converting the C++ code to C, but I would really like to know why this crashes. If I take out any attempt to access pt, the program works fine (except for missing the functionality that would come with a correct pt). BTW, here's another weird thing - when I do the following in the now C DLL code:
EXPORT VECT norm(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col)
it crashes. But if I do:
EXPORT VECT norm(obj, ray, t, pt, col)
OBJECT *obj;
VECT *pt;
RAY ray;
float t;
RGB *col;
It doesn't crash. Is there any way to get C++ to accept the second way of specifying parameters?
Extra info, in case necessary... I load the DLL functions with:
typedef struct Funcs
{
int (*inter)();
VECT (*normal)();
} FUNCS;
/*
I've also tried:
typedef VECT (WINAPI *FNORMAL)(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col);
(FNORMAL)GetProcAddress...
*/
funcs[i].normal = (VECT *)GetProcAddress(dll2, "norm");
if (funcs[i].normal == NULL) { printf("Error: No norm procedure in '%s'\n", objstr); quit(); }
and call them with:
hit.normal = funcs[p->type].normal(p, ray, mint, &pt, &colm);
and I have tried fully specifying the type (instead of just VECT *) in the GetProcAddress typecast.
I've even tried doing this in my linux version. It crashes too, so it's not a Windows only problem.
Any ideas?
Upvotes: 1
Views: 1322
Reputation: 612964
To me the problem looks to stem from this declaration:
VECT (*normal)();
Here you are telling the compiler that normal
is a pointer to a function that returns VECT
. But you have not specified the parameters of the function and so the compiler will let you pass anything you like and it will attempt to work out what types to pass. That's very bad practice. You should stop doing this. Change the declaration of normal to be as follows:
VECT (*normal)(OBJECT *obj, RAY ray, float t, VECT *pt, RGB *col);
I cannot see anywhere in the C++ code that specifies calling convention so the assumption is that the default of cdecl
is in effect. Obviously you need to match that on your side of the interface and if you specify no calling convention for your function pointer then you'll get the default of cdecl
as well.
Upvotes: 2
Reputation: 17163
You must make sure that all involved compile parameters are compatible during DLL build and client build. Special attention is needed to:
If all those looks fine, break at the point you call the function, and show everything you pass as argument. Then step into the function and check everything looks the same.
Upvotes: 0