不能在Delphi中使用DLL(用C ++编写):无法找到过程入口点

时间:2009-10-18 09:02:46

标签: c++ delphi dll dllimport

我在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

我做错了什么?

4 个答案:

答案 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)

还要确保在c ++和delphi中使用相同的调用约定。看看jn answer herehere

答案 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上工作。