有一个函数用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';

该功能有效,但是完成后,我收到调试器错误通知:Project ...错误,消息:“在0x0012f773发生访问冲突:写入地址0xffffffc0'。进程已停止。使用“步骤”或“运行”继续。

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

最佳答案

您需要将__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之前插入external关键字,来告诉Delphi也使用stdcall。

10-02 02:11