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