Delphi:从外部DLL调用函数后的访问冲突(C ++)

时间:2009-10-19 07:46:02

标签: c++ delphi dll dllimport access-violation

有一个用C ++编写并编译为DLL的函数,我想在我的Delphi应用程序中使用它。

Scraper.cpp:

SCRAPER_API bool ScraperGetWinList(SWin winList[100])
{
    iCurrWin=0;
    memset(winList,0,100 * sizeof(SWin));
    return EnumWindows(EnumProcTopLevelWindowList, (LPARAM) winList);
}

Scraper.h:

#ifdef SCRAPER_EXPORTS
#define SCRAPER_API __declspec(dllexport)
#else
#define SCRAPER_API __declspec(dllimport)
#endif

struct SWin
{
    char title[512];
    HWND hwnd;
};

extern "C" {
    SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
}

这就是我在 Delphi应用程序中声明该函数的方法:

type
  tWin = record
    Title: Array [0..511] of Char;
    hWnd: HWND;
  end;

  tWinList = Array [0..99] of tWin;

function ScraperGetWinList(var WinList: tWinList): Boolean; stdcall; external 'Scraper.dll';

该功能正常工作,但是当它完成时,我收到调试器故障通知:项目...出现错误消息:''访问冲突位于0x0012f773:写入地址0xffffffc0'。流程已停止。使用步骤或运行继续。

如果我在Scraper.cpp和Scraper.h中添加__stdcall(在SCRAPER_API bool之后),那么Delphi应用程序根本不会启动:过程入口点ScraperGetWinList不能位于动态链接库Scraper.dll。

4 个答案:

答案 0 :(得分:3)

您需要在__stdcall之后加bool。在所有宏扩展之后,完整的声明应该如下所示:

extern "C"
{
    __declspec(dllexport)
    bool __stdcall ScraperGetWinList(SWin winList[100]);
}

编辑:看起来你还需要一个.def文件。它是一个列出DLL中导出的每个函数的文件,在这种情况下,只需要强制C ++编译器不破坏导出的名称。内容如下:

EXPORTS
ScraperGetWinList

我不确定您使用的是哪种C ++编译器,但通常您只需指定.def文件和.cpp;例如,以下适用于VC ++:

cl.exe foo.cpp foo.def

此外,您还需要告诉Delphi使用stdcall,方法是在stdcall之前在Delphi函数声明中插入external关键字。

答案 1 :(得分:0)

如果使用char的压缩数组[1..512],则不需要ConvertToString()函数。

“打包的char数组”是与Delphi字符串兼容的赋值(这可以追溯到非常早期的Pascal形式 - 字符串类型的char WAS数组)。您可能需要为null($ 0)字符搜索结果以查找C字符串的结尾

您使用的是Delphi版本吗?如果是Delphi 2009 +你将需要使用 AnsiChar 的打包数组[1..512];

答案 2 :(得分:0)

最好知道您的访问冲突究竟发生在哪里。您的运行时尝试访问哪些变量/内存位置?

然后找出这个位置是否真的可以访问,如果是,那么为什么不是。

我的怀疑:您访问未正确初始化的数组元素。

  Index := 0;
  S := ConvertToString(myWinList[Index].Title); 
  while S <> '' do
  begin
    WinListMemo.Lines.Add(S);
    Inc(Index);
    //////// Is Index pointing to a valid entry here?  No check!
    S := ConvertToString(myWinList[Index].Title);
  end;

无论

  • dll没有正确初始化,
  • 或者有另一种方法来找出最后一个元素。
  • 或者您只是完全关闭了数组:第101个元素也被解除引用。如果该内存位置恰好包含0个字符,则为第102个。

答案 3 :(得分:-1)

检查Delphi函数的定义是否与声明C ++函数的定义相匹配。特别是,确保最后有stdcall,并且你的bool值将保持一致。 C ++和Delphi对bool使用不同的值和大小,具体取决于C ++编译器,因此使用适当大小的Integer可能更好。由于bool的大小可能与C ++大小不匹配,这可能会影响堆栈,从而导致访问冲突。

[编辑删除混合语言duff响应]