2

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

刮板.cpp:

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

刮板.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'。进程停止。使用 Step 或 Run 继续。

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

4

4 回答 4

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之前插入关键字来告诉 Delphi 使用 stdcall。external

于 2009-10-19T07:47:59.550 回答
0

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

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

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

于 2009-10-19T22:01:45.453 回答
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 个元素也被取消引用。第 102 个,如果该内存位置恰好包含一个 0 字符。
于 2009-10-20T03:57:57.390 回答
-1

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

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

于 2009-10-19T07:59:01.583 回答