Statyczna Dll, access violation przy zmiennych

0

Witam,
mam problem z którym siłuje się kilka dni i chyba poległem. Łączę się statycznie z komercyjną dll w celu uzyskania wyników obliczeń. Informacja z oficjalnego helpa do biblioteki:

General information for using the MYDLL DLL with Delphi:

  1. All the variables must be passed by address (not just the output); for example:
type
  T_Chaine10000 = Array[0..10000] of Char;
  T_Chaine255 = Array[0..255] of Char;
  T_Chaine3 = Array[0..3] of Char;

procedure SET_dll (var i: Integer;  
                    var params: T_Chaine10000 ; 
                    var files: T_Chaine255;
                    var aaa: T_Chaine3);  stdCall; 
                    external 'MYDLL.DLL';

procedure LICZ_dll (var a: Double;  
                    var b: Double; 
                    var c : Double);  stdCall; 
                    external 'MYDLL.DLL';

Mam w zasadzie 2 problemy.
Problem 1 - w procedurze LICZ_dll podaje zmienne "a" i "b" a otrzymuje "c". Jeśli chce gdzieś wykorzystać wartość z "c" to dostaje Access Violation. Co ciekawe (może tylko dla mnie) wartości liczą się poprawnie, w c po wyjściu w procedury mam wartość ale każda próba przepisania wartości lub jakiegokolwiek operowania na niej wyrzuca wyjątek.

Problem 2 - W procedure SET_dll w zmiennej files mam pliki konfiguracyjne. Zauważyłem, że program nie zawsze może je poprawnie znaleźć. Ze względu na ograniczenie w ilości znaków nie mogę wpisać tam bezpośredniej ścieżki do plików. Biblioteka dysponuje za to procedurą SETPATCH (path) do podania ścieżki do tych plików. Niestety każde dodanie do programu tej procedury wywala program już na samym początku na "Application.Initialize". Domyślam się, że setpatch może być rozpoznawane jako wewnętrzna procedura delphi która coś miesza (używam delphi 7).
Wydawca biblioteki raczej mi nie pomoże bo nie ma wsparcia dla łączenia z biblioteką - jedynie odnośnie samych obliczeń itp. Biblioteka ma opisane podłączenia dla C++, Matlaba, Excela itd. W Excelu jest nawet arkusz który wykorzystuje bibliotekę i wszystko działa. Dodam, że biblioteka na 90% została skompilowana w Fortranie.

Pierwszy raz napotykam na taki problem. Prosiłbym o pomoc jeśli ktoś spotkał się z czymś podobnym.

zamiana znacznika <code> na <quote> - @furious programming

0

daj kod jak wywołujesz dane metody

0
procedure Oblicz(var wynik : double);
var
 param_str, file_str, aaa_str : string;
 param_a : T_Chaine10000;
 file_a : T_Chaine255;
 aaa_a : T_Chaine3;
 i : Integer;
 a, b, c : Double;
 sciezka : T_Chaine255;

begin

 param_str := 'QWERTYUIOP';
 file_str := 'plika|plikb|plikc';
 aaa_str := 'ABC';
 i := 3;
 a := 1;
 b := 2;

 StrPCopy(param_a, param_str);
 StrPCopy(file_a, file_str);
 StrPCopy(aaa_a, aaa_str);

 StrPCopy(sciezka, ExtractFilePath( Application.ExeName ));
 //SETPATCH(sciezka);  //<-- po załączeniu program nie startuje

 SET_dll (i, param_a, file_a, aaa_a);
 LICZ_dll( a, b, c);   // <-- po wyjściu jest poprawna wartość "c"
 wynik := c;
end; 

procedure Licz;
var
 wynik_a : double;

begin
 Oblicz(wynik_a);
 ShowMessage(FloatToStr(wynik_a));  // <-- AV
end;

Dodam, że AV wychodzi podczas debugowania. Przy odpalaniu exe program wyłącza się bez komunikatu.

//EDIT Trochę uprościłem kod na początku i akurat w takim zapisie jak przed edycją działa ok. Wstawiłem poprawny kod.

0

W załączniku przesyłam nagłówki dla C++ z przykładowym kodem programu (z helpa) oraz help z informacjami odnośnie podłączenia do biblioteki [na końcu jest rozdział dla Delphi].
Kod który zamieściłem wcześniej jest uproszczony w stosunku do oryginalnej wersji, ale ilość zmiennych czy wywoływanych procedur nie ma tutaj raczej znaczenia więc przedstawiłem ogólnie na czym polega problem.

//EDIT
LICZ_dll to przykład, korzystam np. z TPRHOdll, WMOLdll. WMOLdll, jest tutaj najbliższa LICZ_dll. Podaje jeden parametr i otrzymuje drugi. Chodzi o sam mechanizm przekazywania parametrów. Której procedury bym nie użył to po wyjściu z procedury "Oblicz" gdzie chce przekazać coś przez referencje dostaje AV. Tak jakby biblioteka niszczyła? zmienną kiedy wychodzę z "Oblicz". Wstawiam oryginalny kod bez uproszczeń to co testuje i to co mi nie działa.

unit Unit1;

interface

uses
  Windows, Messages, Forms, SysUtils, StdCtrls, Classes, Controls, dialogs,
  cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters,
  cxContainer, cxEdit, cxTextEdit, cxMaskEdit, cxSpinEdit;


type
  TForm1 = class(TForm)
    Button1: TButton;
    cxSpinEdit1: TcxSpinEdit;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Wyznacz(const a : Double; var ax, ay, az : Double; err : String);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  T_Chaine10000 = Array[0..10000] of Char;
  T_Chaine255 = Array[0..255] of Char;
  T_Chaine3 = Array[0..3] of Char;
  T_ArrDbl  = array[0..20] of Double;

implementation

{$R *.dfm}

procedure SETUPdll (var nc: Integer;  // number of components
                    var hfiles: T_Chaine10000 ;  // fluid file names
                    var hfmix: T_Chaine255;  // mixture file name
                    var hrf: T_Chaine3;  // reference state
                    var ierr: Integer;  // error message number
                    var herr: T_Chaine255);  stdCall;  // error message string
                    external 'refprop.DLL';
                    //external 'refprp64.DLL';

procedure TPRHOdll(var t: Double;
                   var p: Double;
                   var x: T_ArrDbl;
                   var j: Integer;
                   var i: Integer;
                   var d: Double;
                   var ierr: Integer;
                   var herr: T_Chaine255); stdcall;
                   external 'refprop.DLL';

procedure TRNPRPdll(var tz: Double;
                  var rho: Double;
                  var x: T_ArrDbl;
                  var eta: Double;
                  var tcx: Double;
                  var ierr: Integer;
                  var herr: T_Chaine255); stdcall;
                  external 'refprop.DLL';

procedure WMOLdll (var x: T_ArrDbl;
                   var wm: Double); stdcall;
                   external 'refprop.DLL';
                   
procedure SETPATH (var path : T_Chaine255); stdcall;
                  external 'refprop.DLL';

procedure TForm1.Button1Click(Sender: TObject);
var
  a, b, c, _a : Double;
  err : string;
begin
  err := '';
  _a := cxSpinEdit1.Value + 273.15;
  wyznacz(_a, a ,b ,c , err);

  if err <> '' then
    ShowMessage(err)
  else
    ShowMessage('rho: '+FloatToStr(aaa)+#10#13+'z: '+FloatToStr(bbb)+#10#13+ 'eta: '+FloatToStr(ccc));
end;

procedure TForm1.Wyznacz(const a : Double; var ax, ay, az : Double; err : String);
 var
    hfiles: T_Chaine10000;
    hfiles_str: string;
    hrf : T_Chaine3;
    hrf_str : string;
    hfmix : T_Chaine255;
    herr : T_Chaine255;
    hfmix_str, herr_str : string;
    x{, xliq, xvap}: T_ArrDbl;
    ierr, nc : Integer;
    str : AnsiString;
    j, i : Integer;
    sciezka : T_Chaine255;

    t, p, rho, wm, rho_m, z, tcx, eta: Double;

begin
  err := '';
  hfiles_str:= 'Fluids\methane.fld|Fluids\nitrogen.fld|Fluids\CO2.fld|Fluids\ethane.fld|Fluids\propane.fld|';
  StrPCopy(hfiles, hfiles_str);
  hrf_str := 'DEF';
  StrPCopy(hrf, hrf_str);
  hfmix_str := 'hmx.bnc';
  StrPCopy(hfmix, hfmix_str);
  herr_str := 'Ok';
  strpcopy(herr, herr_str);

  // initialization (for nc = 3)
  nc := 5;

  x[0]:=0.97882;
  x[1]:=0.00811;
  x[2]:=0.00027;
  x[3]:=0.00640;
  x[4]:=0.00640;

  StrPCopy(sciezka, ExtractFilePath( Application.ExeName ));
  //SETPATH(sciezka);

  SETUPdll (nc,  // number of components
            hfiles,  // fluid file names
            hfmix,  // mixture file name
            hrf,  // reference state
            ierr,  // error message number
            herr);


  t := a;
  p := 101.325;

   j := 2;
   i := 0;
  TPRHOdll(t,p,x,j,i,rho,ierr,herr);

  if ierr <> 0 then
    begin
    for i := 0 to High(herr) do
      str := str + herr[i];
      err := str;
    //  Exit;
    end 
  else   
  begin
    WMOLdll(x, wm);
    rho_m := rho*wm;

    Z := p*1000/rho_m/(8314.472/wm)/t;

    TRNPRPdll(t,rho,x,eta,tcx,ierr,herr);
    if ierr <> 0 then
      begin
      for i := 0 to High(herr) do
        str := str + herr[i];
        err := str;
      //  Exit;
      end;
      
    eta := eta * 1e-6;

    ax := rho;
    ay := z;
    az := eta;

  end; 
end;

end. 
0

Nie mam pod ręką teraz delphi, żeby to szybko sprawdzić, ale na moje oko niestety przekazanie tam tablicy nie jest najlepszym pomysłem.
moim zdaniem powinno to wyglądać np tak:

procedure WMOLdll (var x;
                   var wm: Double); stdcall;
                   external 'refprop.DLL';
 

a wywołanie:

WMOLdll(x[0], wm);

ewentualnie:

procedure WMOLdll (x: PDouble;
                   var wm: Double); stdcall;
                   external 'refprop.DLL';
 

a wywołanie:

WMOLdll(@(x[0]), wm);

Tak byłoby najbezpiezniej.

0

Dzięki za sugestie. Niestety proponowane rozwiązania nic nie zmieniły. Na końcu kodu

 
    ax := rho;
    ay := z;
    az := eta; //<-- AV po przejściu do kolejnej linii

Mogę nawet wyrzucić wszystko poza SETUPdll żeby nie było przekazywania tablic a i tak się wywali na koniec bez przesyłania błędu z biblioteki. Wartości obliczane są poprawnie tylko 'znikają' po zakończeniu korzystania z dll-ki.

0

jeszcze jedno:

 
procedure TForm1.Wyznacz(const a : Double; var ax, ay, az : Double; err : String);

powinna chyba wyglądać tak:

 
procedure TForm1.Wyznacz(const a : Double; var ax, ay, az : Double; var err : String);

zmieniany jest err przecież!
Inna rzecz - coś jest nie tak z pamięcią - tak mi się wydaje - że gdzies jest mazanie - pokomentuj troszkę kod, żeby było go mniej i zobacz, gdzie się wywala. Zacznij od linii w ktorej się wywala, założe się, że to nie tu, jak zaremujesz ta linie, wywali ci się na linii wcześniej - gdzies jest cos nadpisywane.

3

ale jak się ma np. to

typedef void (__stdcall *fp_SETUPdllTYPE)(long *,char*,char*,char*,long *,char*,long ,long ,long ,long );

do tego

procedure SETUPdll (var nc: Integer;  // number of components
                    var hfiles: T_Chaine10000 ;  // fluid file names
                    var hfmix: T_Chaine255;  // mixture file name
                    var hrf: T_Chaine3;  // reference state
                    var ierr: Integer;  // error message number
                    var herr: T_Chaine255);  stdCall;  // error message string
                    external 'refprop.DLL';

gdzie pierwsze ma 10 parametrów a drugie 6. Poza tym char* powinno się przekazywać jako PChar

Generalnie Twoje deklaracje w Delphi nijak się mają do tych z pliku nagłówkowego

0

Panowie DZIĘKUJĘ. Już pisałem, że po wszystkich zmianach dalej coś nie działa ale przy tworzeniu posta zmodyfikowałem kilka rzeczy i ruszyło. Rozwiązaniem były poprawne deklaracje procedur. Skopiowałem je z Excela i po modyfikacjach wstawiłem do kodu. Biblioteka żąda przy większości procedur dołączania zmiennych tekstowych o określonej długości które na wyjściu nic nie dają ale bez nich na wejściu jak widać jest problem. Jeszcze raz dzięki!!

1 użytkowników online, w tym zalogowanych: 0, gości: 1