【问题标题】:Using functions from a C++ .DLL within Delphi在 Delphi 中使用 C++ .DLL 中的函数
【发布时间】:2011-08-11 16:29:56
【问题描述】:

我正在尝试从 Delphi 中的“近似最近邻居”(ANN) 库中访问各种函数(实际上,它是 Lazarus/FreePascal,但这应该无关紧要)。

这是 C++ 中的减速:

#include <cstdlib>                      // C standard lib defs
#include <ANN/ANNx.h>                   // all ANN includes
#include <ANN/ANNperf.h>                // ANN performance 

using namespace std;                    // make std:: accessible
....
....
void annMaxPtsVisit(            // set limit on max. pts to visit in search
    int                 maxPts)         // the limit
{
    ANNmaxPtsVisited = maxPts;
}

这是我从 Lazarus 中访问 annMaxPtsVisit 函数的尝试(如果您不知道 Lazarus 是什么,请假装它的 delphi):

unit unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure annMaxPtsVisit(input:Integer); stdcall;
  private

    { private declarations }
  public
    { public declarations }

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}
{ TForm1 }
procedure TForm1.annMaxPtsVisit(input: Integer); stdcall; external 'ANN.dll' name 'annMaxPtsVisit';

procedure TForm1.Button1Click(Sender: TObject);
begin
           annMaxPtsVisit(10);
end;

end.

程序可以编译,但是当我尝试执行它时,我收到一条错误消息:

“无法在动态链接库ANN.dll中定位程序入口点anMaxPtsVisit”

如果有人能帮我解决这个问题,我将不胜感激。

以下是 DLL 的导出:

class ANNsampStat ann_average_err   
class ANNsampStat ann_rank_err  
const ANNbd_tree::`vftable' 
const ANNbruteForce::`vftable'  
const ANNkd_tree::`vftable' 
const ANNpointSet::`vftable'    
double * * __cdecl annAllocPts(int,int) 
double * __cdecl annAllocPt(int,double) 
double * __cdecl annCopyPt(int,double *)    
double __cdecl annDist(int,double *,double *)   
protected: void __thiscall ANNkd_tree::SkeletonTree(int,int,int,double * *,int *)   
public: __thiscall ANNbd_tree::ANNbd_tree(class ANNbd_tree const &) 
public: __thiscall ANNbd_tree::ANNbd_tree(class std::basic_istream<char,struct std::char_traits<char> > &)  
public: __thiscall ANNbd_tree::ANNbd_tree(double * *,int,int,int,enum ANNsplitRule,enum ANNshrinkRule)  
public: __thiscall ANNbd_tree::ANNbd_tree(int,int,int)  
public: __thiscall ANNbruteForce::ANNbruteForce(class ANNbruteForce const &)    
public: __thiscall ANNbruteForce::ANNbruteForce(double * *,int,int) 
public: __thiscall ANNkd_tree::ANNkd_tree(class ANNkd_tree const &) 
public: __thiscall ANNkd_tree::ANNkd_tree(class std::basic_istream<char,struct std::char_traits<char> > &)  
public: __thiscall ANNkd_tree::ANNkd_tree(double * *,int,int,int,enum ANNsplitRule) 
public: __thiscall ANNkd_tree::ANNkd_tree(int,int,int)  
public: __thiscall ANNpointSet::ANNpointSet(class ANNpointSet const &)  
public: __thiscall ANNpointSet::ANNpointSet(void)   
public: __thiscall ANNsampStat::ANNsampStat(void)   
public: class ANNbd_tree & __thiscall ANNbd_tree::operator=(class ANNbd_tree const &)   
public: class ANNbruteForce & __thiscall ANNbruteForce::operator=(class ANNbruteForce const &)  
public: class ANNkd_tree & __thiscall ANNkd_tree::operator=(class ANNkd_tree const &)   
public: class ANNpointSet & __thiscall ANNpointSet::operator=(class ANNpointSet const &)    
public: class ANNsampStat & __thiscall ANNsampStat::operator=(class ANNsampStat const &)    
public: double __thiscall ANNsampStat::max(void)    
public: double __thiscall ANNsampStat::mean(void)   
public: double __thiscall ANNsampStat::min(void)    
public: double __thiscall ANNsampStat::stdDev(void) 
public: int __thiscall ANNsampStat::samples(void)   
public: virtual __thiscall ANNbd_tree::~ANNbd_tree(void)    
public: virtual __thiscall ANNbruteForce::~ANNbruteForce(void)  
public: virtual __thiscall ANNkd_tree::~ANNkd_tree(void)    
public: virtual __thiscall ANNpointSet::~ANNpointSet(void)  
public: virtual double * * __thiscall ANNbruteForce::thePoints(void)    
public: virtual double * * __thiscall ANNkd_tree::thePoints(void)   
public: virtual int __thiscall ANNbruteForce::annkFRSearch(double *,double,int,int *,double *,double)   
public: virtual int __thiscall ANNbruteForce::nPoints(void) 
public: virtual int __thiscall ANNbruteForce::theDim(void)  
public: virtual int __thiscall ANNkd_tree::annkFRSearch(double *,double,int,int *,double *,double)  
public: virtual int __thiscall ANNkd_tree::nPoints(void)    
public: virtual int __thiscall ANNkd_tree::theDim(void) 
public: virtual void __thiscall ANNbruteForce::annkSearch(double *,int,int *,double *,double)   
public: virtual void __thiscall ANNkd_tree::annkSearch(double *,int,int *,double *,double)  
public: virtual void __thiscall ANNkd_tree::Dump(enum ANNbool,class std::basic_ostream<char,struct std::char_traits<char> > &)  
public: virtual void __thiscall ANNkd_tree::getStats(class ANNkdStats &)    
public: virtual void __thiscall ANNkd_tree::Print(enum ANNbool,class std::basic_ostream<char,struct std::char_traits<char> > &) 
public: void __thiscall ANNkd_tree::`default constructor closure'(void) 
public: void __thiscall ANNkd_tree::annkPriSearch(double *,int,int *,double *,double)   
public: void __thiscall ANNsampStat::operator+=(double) 
public: void __thiscall ANNsampStat::reset(void)    
void __cdecl annClose(void) 
void __cdecl annDeallocPt(double * &)   
void __cdecl annDeallocPts(double * * &)    
void __cdecl annMaxPtsVisit(int)    
void __cdecl annPrintStats(enum ANNbool)    
void __cdecl annResetCounts(void)   
void __cdecl annResetStats(int) 
void __cdecl annUpdateStats(void)   

【问题讨论】:

  • 您发布的代码不可能是您实际拥有的代码。您发布的代码无法编译。您正在报告运行时错误消息。
  • 你确定DLL中的名字是annMaxPtsVisit吗?我发现考虑到代码是 C++ 真的不太可能(对于许多 Windows DLL 来说甚至不太可能,因为它们经常使用 __stdcall 调用约定并被称为 _func@4 等)。您可以使用工具为我们转储 DLL 的导出吗?
  • @David 你在说什么?德尔福代码?也许它没有编译,因为它在技术上实际上不是 delphi - 它的 freepascal/lazarus。
  • @David Ok - 我编辑了最初的问题并添加了该信息。
  • @Mike procedure TForm1.annMaxPtsVisit .... external .... 无效?

标签: c++ dll export static-linking freepascal


【解决方案1】:

也许按索引导入有效:

procedure annMaxPtsVisit(input: Integer); stdcall; external 'ANN.dll' index 39;

(这是通过Dependecy Walker得到的索引)

您可能需要更改为 cdecl 调用约定,具体取决于 DLL 的构建方式:

procedure annMaxPtsVisit(input: Integer); cdecl; external 'ANN.dll' index 39; // could work

编辑:看起来cdecl 是正确的做法,查看您添加的导出。

Edit2:Dependency walker 还显示修饰名称,正如 @user786653 所怀疑的那样。这似乎也有效:

procedure annMaxPtsVisit(input: Integer); cdecl; external 'ANN.dll' Name '?annMaxPtsVisit@@YAXH@Z';

不过看起来很丑。

【讨论】:

  • 是cdecl。从导出转储中:void __cdecl annMaxPtsVisit(int) 它可能只需要在名称前加一个下划线,而不是按索引来做(参见MSDN
  • 使用index 39 成功了!非常感谢....没有它就无法工作,这有点奇怪,不是吗?
  • 我也习惯用“好”的名字。
  • 是的,装饰功能也可以。非常感谢您的帮助:)
  • 请注意,按索引导入确实很脆弱(而且由于 C++ 名称的损坏,真的很难看)。如果您可以控制构建源代码,我建议您使用extern "C" 导出以获取名称_annMaxPtsVisit。一般来说,通过 DLL 导出 C++ 接口相当麻烦。但这只是一个旁注,很高兴它成功了:)
【解决方案2】:

首先将annMaxPtsVisit声明为普通过程,而不是TForm1方法:

procedure annMaxPtsVisit(input: Integer); stdcall; external 'ANN.dll';

【讨论】:

  • 看我对@Heinrich 的回答stdcall 至少需要改成cdecl 的评论
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
  • 1970-01-01
相关资源
最近更新 更多