简体   繁体   English

从C程序调用C ++ DLL时,当我尝试访问DLL中的调用参数指针时会崩溃

[英]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. 我编写了一个C函数,该函数使用指向函数的指针数组。 The functions are both inside my program and in loadable DLL's. 这些功能都在我的程序内部和可加载的DLL中。 My problem comes when I try to use a DLL that came from a C++ program. 当我尝试使用来自C ++程序的DLL时,出现了我的问题。 Here's a simplified snippit of the code in the C++ (DLL) program: 这是C ++(DLL)程序中代码的简化片段:

#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. 问题是,一旦我尝试对pt做任何操作,它就会崩溃。 It's not NULL, but if I try to write to it or even just access it's members, it crashes. 它不是NULL,但是如果我尝试对其进行写入甚至只是访问它的成员,它都会崩溃。 I've kind of solved the problem by converting the C++ code to C, but I would really like to know why this crashes. 我已经通过将C ++代码转换为C来解决了这个问题,但是我真的很想知道为什么会崩溃。 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). 如果我尝试访问pt,则程序运行正常(除了缺少正确pt附带的功能外)。 BTW, here's another weird thing - when I do the following in the now C DLL code: 顺便说一句,这是另一个奇怪的事情-当我在现在的C DLL代码中执行以下操作时:

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? 有什么办法让C ++接受指定参数的第二种方法?

Extra info, in case necessary... I load the DLL functions with: 额外信息,以备不时之需...我通过以下方式加载DLL函数:

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. 并且我尝试在GetProcAddress类型转换中完全指定类型(而不只是VECT *)。

I've even tried doing this in my linux version. 我什至尝试在我的Linux版本中执行此操作。 It crashes too, so it's not a Windows only problem. 它也会崩溃,所以这不是Windows唯一的问题。

Any ideas? 有任何想法吗?

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 . 在这里,您告诉编译器normal是指向返回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: 将normal的声明更改为如下:

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. 我看不到C ++代码中指定调用约定的任何地方,因此我们假设默认的cdecl有效。 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. 显然,您需要在接口侧进行匹配,并且如果您没有为函数指针指定调用约定,那么您cdecl获得默认的cdecl

You must make sure that all involved compile parameters are compatible during DLL build and client build. 您必须确保在DLL构建和客户端构建期间所有涉及的编译参数都兼容。 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. 然后进入该函数并检查一切看起来是否相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM