我将用户定义的类型参数从c客户端传递到c dll时遇到问题;我在client和dll中定义了以下结构:
typedef struct sBar{
double Open;
double High;
double Low;
double Close;
char NewDateTime[20];
} tBar;
在客户端,我将dll函数声明为
EXPORT int GetPastBars (int pDebug, char* pDebugPath[], char* pSymbol[],
char* pCurrentTime[], int pTotalBars, char* pTimeFrame[], int pIsFilled,
char* pOutputType[], tBar pPastBars[MAX_HISTORY_DEPTH],
tBar pFutureBar[PREDICTION_LENGTH]);
同样,在dll源代码中,该函数声明为:
EXPORT int __stdcall GetPastBars( int pDebug, char* pDebugPath[], char* pSymbol[],
char* pCurrentTime, int pTotalBars, char* pTimeFrame[], int pIsFilled,
char* pOutputType[], tBar pPastBar[MAX_HISTORY_DEPTH],
tBar pFutureBar[MAX_PREDICTION_LENGTH]){
我可以看到pPastBar
和pFutureBar
在dll代码结束之前正确填充;但是,当控件返回到exe时,pPastBar[]
的前n个元素归零,n是MAX_PREDICTION_LENGTH
(在dll中定义)和PREDICTION_LENGTH
之间的差异(在exe)。
有什么想法吗?
答案 0 :(得分:0)
正如评论中指出的那样,双方都没有使用相同的调用约定。你显然需要解决这个问题。
另一个问题是你可能会超越缓冲区。这至少部分是由函数声明中明显的混淆引起的。在编译DLL时,将参数pFutureBar
定义为具有一个长度,但在声明中对可执行文件使用不同的长度。
<强> DLL 强>
tBar pFutureBar[MAX_PREDICTION_LENGTH]
<强>可执行强>
tBar pFutureBar[PREDICTION_LENGTH]
编译器并不关心您在此处指定的数组的长度,只是将指针传递给第一个元素。所以真正重要的是DLL不能访问超出您传递的实际数组的长度。
虽然您没有显示代码,但似乎您可能将数组传递给太短的pFutureBar
参数。所以DLL写的超出了它的结尾。很可能你传递了一个长度为PREDICTION_LENGTH
的数组,而DLL写了MAX_PREDICTION_LENGTH
个元素。假设MAX_PREDICTION_LENGTH
大于PREDICTION_LENGTH
,那么您将获得经典的缓冲区溢出条件。
您需要做的是将签名更改为
int __stdcall GetPastBars(...,
size_t nPastBar, tBar pPastBar[],
size_t nFutureBar, tBar pFutureBar[]
);
新参数允许调用者说出它提供的数组有多大。这反过来使被调用者DLL能够避免写入当前正在发生的缓冲区末尾。
通过在DLL中使用相同的头文件以及调用它的代码,您可以使您的生活变得更加轻松。有许多教程和示例可用于说明如何执行此操作。我重复这些是没有意义的。