我在Visual Studio中编译了一个DLL(源代码是用C ++编写的,我几乎不懂)。这是一篇 Scraper.h :
struct SWin
{
char title[512];
HWND hwnd;
};
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
现在我正在尝试在我的Delphi应用程序中使用上述函数:
type
tWin = record
title: String;
hwnd: HWND;
end;
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';
var
myWinList: Array [1..100] of tWin;
procedure TMainForm.GetWinListButtonClick(Sender: TObject);
begin
ScraperGetWinList(myWinList);
...
项目无法编译,我收到以下消息:程序入口点ScraperGetWinList无法位于动态链接库中:Scraper.dll 。
我做错了什么?
答案 0 :(得分:6)
从我的Linux经验来看,我说你遇到了所谓的“name-mangling”问题。您的过程的入口点不称为“ScraperGetWinList”,而是类似“_ZN18ScraperGetWinListEpN4SWin”。
问题在于,与C语言不同,在C ++语言中,入口点的名称与函数名称不同。难怪:假设你有一组重载函数;它们应该在您的DLL中有不同的入口点。这就是名称改变发挥作用的地方。
这个问题最常见的解决方案是以一种使用C调用约定的方式定义库的接口。接口函数不会发生名称错误。
请注意,您不必在C中编写整个库,只有声明函数才能发出类似C的入口点。
通常它是这样写的:
extern "C" {
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
// More functions
}
重新编译您的库并在Delphi中使用它而不会出现问题。
注意,你还应该调整它们的调用约定(stdcall或cdecl)以匹配你的C ++头文件和Delphi代码。但是,这在另一个问题中得到了最好的解释。
答案 1 :(得分:4)
名称重整很可能是问题所在。名称修改通常是C ++代码, 当用C ++写一个DLL时,应该由其他语言中的代码使用, 你应该像Pavel Shved已经建议的那样使用Extern“C”结构。
使用DLL时,尤其是在使用其他语言写入时,您也应该保留 关注召集惯例。我建议您在delphi和c ++中指定使用stdcall调用conversnstion。这是windows api也使用的调用约定,因此它保证了不同编译器之间的最佳互操作性。
这意味着
extern“C”{
SCRAPER_API __stdcall bool ScraperGetWinList(SWin winList [100]);
}
和
function ScraperGetWinList(var WinList:tWin的数组):Boolean;外部'Scraper.dll';
但并非全部,stdcall调用约定对名称修改产生影响,结果会像_ScraperGetWinList @ 4(其中4是参数的大小,其中数组将指向第一个元素,所以4个字节)
要确认要使用的正确符号,我建议使用Dependency Walker (http://www.dependencywalker.com/)此程序显示dll正好输出函数名称。确认名称为'_ScraperGetWinList @ 4'后,您可以像这样在delpgi中添加:
function ScraperGetWinList(var WinList:tWin的数组):Boolean;外部'Scraper.dll'名称'_ScraperGetWinList @ 4';
答案 2 :(得分:2)
答案 3 :(得分:1)
您是否真的在c ++代码中导出了入口点函数?当我第一次在Visual Studio中编译C ++ dll以在dotnet应用程序中使用时,这真的让我很难过。
例如,我需要在非托管代码中公开打印驱动程序,以便其他一些开发人员可以在VB.net中访问它。这就是我所做的。
在foo.cpp中:
extern "c" {
___declspec(dllexport) bool FooBar()
{
// Call some code on my cpp objects to implement foobar
}
}
然后在一个名为foo.def的文件中:
LIBRARY "mylib"
EXPORTS
FooBar
AnyOtherFunctionsItExports
这就是我开始工作的方式。我可能不会以最好的方式做事。我对C ++经验有点了解,也主要不在windows上工作。