有一个函数,用 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 中。
最佳答案
您需要在bool
之后放置__stdcall
。在所有宏展开之后,完整的声明应该如下所示:
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 函数声明中的 external
之前插入 stdcall
关键字来告诉 Delphi 使用 stdcall。
关于c++ - Delphi:从外部 DLL (C++) 调用函数后发生访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1587410/