Использование функций из C++ .DLL в Delphi

Я пытаюсь получить доступ к различным функциям из «Приблизительного ближайшего соседа» (ANN) библиотеку из Delphi (на самом деле это 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;
}

А вот моя попытка получить доступ к функции annMaxPtsVisit из Lazarus (представьте, что это delphi, если вы не знаете, что такое Lazarus):

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.

Программа компилируется, но когда я пытаюсь ее запустить, я получаю сообщение об ошибке:

"Точка входа в процедуру annMaxPtsVisit не найдена в библиотеке динамической компоновки ANN.dll"

Если бы кто-нибудь мог помочь мне с этим, я был бы очень признателен.

Вот экспорт из 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)   

person Mike Furlender    schedule 11.08.2011    source источник
comment
Код, который вы публикуете, не может быть кодом, который у вас есть на самом деле. Код, который вы публикуете, не компилируется. Вы сообщаете об ошибке во время выполнения.   -  person David Heffernan    schedule 11.08.2011
comment
Вы уверены, что имя в DLL действительно annMaxPtsVisit? Я считаю, что это действительно маловероятно, учитывая, что код написан на C++ (это было бы даже маловероятно для многих библиотек DLL Windows, поскольку они часто используют соглашение о вызовах __stdcall и называются _func@4 и т.п.). Не могли бы вы использовать инструмент для дампа экспорта DLL для нас?   -  person user786653    schedule 11.08.2011
comment
@ Дэвид О чем ты говоришь? Дельфийский код? Возможно, он не компилируется, потому что технически это не Delphi, а freepascal/lazarus.   -  person Mike Furlender    schedule 11.08.2011
comment
@David Хорошо, я отредактировал свой первоначальный вопрос и добавил эту информацию.   -  person Mike Furlender    schedule 11.08.2011
comment
@Mike procedure TForm1.annMaxPtsVisit .... external .... не может быть действительным?   -  person David Heffernan    schedule 11.08.2011


Ответы (2)


Возможно, импорт по индексу работает:

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: обходчик зависимостей также показывает оформленные имена, как и подозревал @user786653. Это также, кажется, работает:

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

Хотя выглядит некрасиво.

person Heinrich Ulbricht    schedule 11.08.2011
comment
Это cдекл. Из дампа экспорта: void __cdecl annMaxPtsVisit(int) Возможно, вместо индекса нужно просто поставить подчеркивание перед именем (см. MSDN) - person user786653; 11.08.2011
comment
Использование index 39 сработало! Большое спасибо... как-то странно, что без него не работает, не так ли? - person Mike Furlender; 11.08.2011
comment
Я также привык использовать красивые имена. - person Heinrich Ulbricht; 11.08.2011
comment
Да, декорированная функция тоже работает. Огромное спасибо за помощь :) - person Mike Furlender; 11.08.2011
comment
Без проблем. Также в прошлом приходилось бороться с некоторыми библиотеками C++ DLL;) - person Heinrich Ulbricht; 11.08.2011
comment
Обратите внимание, что импорт по индексу действительно хрупок (и из-за искаженного имени C++ действительно уродлив). Если у вас есть контроль над созданием исходного кода, я бы рекомендовал экспортировать его с помощью extern "C", чтобы получить имя _annMaxPtsVisit. В целом экспорт интерфейсов C++ через библиотеки DLL довольно запутан. Но это было просто замечание, рад, что все получилось :) - person user786653; 11.08.2011
comment
@user786653 user786653 Судя по исходному коду, он использует DLL_EXPORT. Мне просто нужно заменить это на extern "C"? - person Mike Furlender; 11.08.2011
comment
@Mike Furlender: DLL_EXPORT - это что-то специфичное для этой программы (вероятно, #defined как __declspec(dllexport)), и никогда не бывает так просто просто изменить какую-то мелочь, когда мы говорим о DLL :). Я имел в виду то, что описано здесь< /а>. Если это не покрывает это, я думаю, вам, вероятно, следует начать новый вопрос. - person user786653; 11.08.2011

Прежде всего объявите annMaxPtsVisit как обычную процедуру, а не метод TForm1:

procedure annMaxPtsVisit(input: Integer); stdcall; external 'ANN.dll';
person kludg    schedule 11.08.2011
comment
См. мой комментарий к ответу @Heinrich. stdcall, по крайней мере, нужно изменить на cdecl - person user786653; 11.08.2011