lasermc
lasermc

Reputation: 55

When calling a C++ DLL from a C program it crashes when I try to access call parameter pointer in the DLL

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

Answers (2)

David Heffernan
David Heffernan

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

Balog Pal
Balog Pal

Reputation: 17163

You must make sure that all involved compile parameters are compatible during DLL build and client build. Special attention is needed to:

  • function call convention
  • structure packing
  • structure content

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

Related Questions