Baza danych na liście jednokierunkowej w DLL

0

Witam, uczę się pisać w Delphi, obecnie do wykonania mam projekt "Bazy danych"(Gier w moim wypadku, z danymi typu nazwa, studio itp.), który ma operować na listach jednokierunkowych, a jego "silnik" (dodawanie, usuwanie z listy, zapis, wczytanie pliku typowanego) ma się znajdować wewnątrz Dynamicznej Biblioteki (DLL).
Gdy próbuję wykonać polecenia z biblioteki (Dodania do listy elementów stringgrida, a później ich zapisu do pliku) otrzymuję taki komunikat: First chance exceptation at $048AD82A. Exceptation class $C0000005 with message 'acces violation at 0x048ad82a: read of address 0x00000000'. Process Gry.exe(7256) i nie rozumiem dlaczego. Dzieje się tak niezależnie od tego, czy stringgrid jest pusty (poza pierwszym wierszem nagłówkowym), czy wypełniony prawidłowymi danymi.

Tak wyglądają funkcje w dll które wykonuję (debuger zaznacza zawsze pierwszą linijkę funkcji (po begin, try itp.) niezależnie od tego co się w niej znajduje.
type
  wskaznik = ^lista;

  TDane= record
    nazwa, studio:shortstring;
    gatunek:shortstring;
    data:TDateTime;
    ocena:Single;
  end;

  lista = record
    dane: TDane;
    next: wskaznik;
  end;

{$R *.res}

  ////////// ////////// ////////// ////////// //////////
  function Dodaj (var first: wskaznik; info: TDane):boolean; stdcall;
    var
      poprz,t:wskaznik;
  begin
    try
      if first=nil then
        begin
          new(first);
          first^.dane:=info;
          first^.next:=nil;
        end
      else
        begin
          t:=first;
          if info.nazwa<=first^.dane.nazwa then
            begin
              new(t);
              t^.dane:=info;
              t^.next:=first;
            end
          else
            begin
              while (t^.next<>nil)and(t^.dane.nazwa<info.nazwa) do
                begin
                  t:=t^.next;
                end;
              poprz:=t;
              new(t);
              t^.dane:=info;
              t^.next:=poprz^.next;
              poprz^.next:=t;
            end;
        end;
      result:=true;
    except
      result:=false;
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  function Usun (var usuwany,first:wskaznik):boolean;stdcall;
    var t, n:wskaznik;
  begin
    try
      t:=first;
      while t^.next<>usuwany do
        begin
          t:=t^.next;
          if t^.next=nil then raise Exception.Create('Nie znaleziono elementu do usunięcia.');
        end;
      n:=t;
      t:=t^.next;
      n^.next:=t^.next;
      dispose(t);
      result:=true;
    except
      result:=false;
    end;
  end;
  function Zapisz (var first:wskaznik; nazwa:shortstring):boolean;stdcall;
    var elem:TDane; fp:file of TDane;
  begin
      begin
        try
          if first=nil then raise Exception.Create('Brak danych do zapisu.');
          AssignFile(fp,nazwa);
          try
            rewrite(fp);
            while first<>nil do
              begin
                elem:=first^.dane;
                write(fp,elem);
                Usun(first,first);
              end;
          finally
            closefile(fp);
          end;
          result:=true;
        except
          result:=false;
        end;
      end
  end;
  exports
    Dodaj index 1,
    Usun index 2,
    Zapisz index 4;
begin
end.
A tak procedura i funkcje używane w głównym unicie (jest jeszcze zdarzenie oncreate dla Form1 gdzie `first:=nil`.
    type
      wskaznik = ^lista;
      TDane = record
        nazwa,studio:shortstring;
        gatunek:shortstring;
        data:TDateTime;
        ocena:Single;
    end;
    lista = record
      dane:TDane;
      next:wskaznik;
    end;

    var
      dana:TDane;first,current:wskaznik; xxx : HModule;

    insert:function(start:wskaznik;info:TDane):boolean;stdcall;
    save:function(start:wskaznik;nazwa:shortstring):boolean;stdcall;

implementation

{$R *.dfm}
///////////////////////////////////////////////////////////////////////////////////////////
function sprdata(data:shortstring):boolean;
begin
  try
    strtodate(data);
    result:=true;
  except
    result:=false;
  end;
end;
function sprocena(ocena:shortstring):boolean;
begin
  try
    strtofloat(ocena);
    result:=true;
  except
    result:=false;
  end;
end;

procedure TForm1.Zapisz(Sender: TObject);
var
  elem:TDane;
  i,n:integer;
begin
  try

    xxx:=loadlibrary('DLLTest.dll');
    if xxx<hinstance_error then raise Exception.Create('Nie można załadować biblioteki.');
    insert:=getprocaddress(xxx,pchar(1));
    save:=getprocaddress(xxx,pchar(4));
    if (@save = nil)or(@insert = nil) then raise Exception.Create('Nie mozna załadowac funkcji.');

    if (stringgrid1.Cells[0,stringgrid1.RowCount-1]='')and(stringgrid1.Cells[1,stringgrid1.RowCount-1]='')and(stringgrid1.Cells[2,stringgrid1.RowCount-1]='')and(stringgrid1.Cells[3,stringgrid1.RowCount-1]='')and(stringgrid1.Cells[4,stringgrid1.RowCount-1]='') then n:=stringgrid1.RowCount-1
    else n:=stringgrid1.RowCount;

    i:=1;
    while i<n do
      begin
        if sprdata(stringgrid1.Cells[3,i])=false then raise Exception.Create('Wiersz '+inttostr(i)+' zawiera niepoprawną datę.');
        if sprocena(stringgrid1.Cells[4,i])=false then raise Exception.Create('Wiersz '+inttostr(i)+' zawiera niepoprawną ocenę.');
        i:=i+1;
      end;

    i:=1;
    while i<n do
      begin
        with elem do
          begin
            nazwa:=stringgrid1.Cells[0,i];
            studio:=stringgrid1.Cells[1,i];
            gatunek:=stringgrid1.Cells[2,i];
            data:=strtodate(stringgrid1.Cells[3,i]);
            ocena:=strtofloat(stringgrid1.Cells[4,i]);
          end;

        insert(first,elem);
        i:=i+1;
      end;
    save(first,'Baza');

  finally
    freelibrary(xxx);
  end;
end;

Z góry dziękuję za wszelką pomoc.
2

Pamiętaj że DLL i twój program mają zupełnie różne przestrzeni adresów.
Czyli upraszczając jeżeli wskaźnik był przydzielony w DLL to nie możesz go czytać poza DLL, wyjątkiem są dane przekazywane/zwracane przez wartość.
- coś mi się tu nie zgadza, chyba @Azarien, w poście niżej http://4programmers.net/Forum/1207921 ma racje. To co mi się pamięta i nie działało było związane z dwoma programami oraz jedną DLL między nimi, która ma wspólny fragment pamięci, przez który te programy sobie "gadają".
W starszych Delphi nawet zwykłego napisu nie dawało się przekazać, potrzebna była specjalna DLL'ka: borlndmm.dll aby można było przekazywać napisy.
W nowszych Delphi - niestety nie wiem, nie potrzebowałem - nie badałem sprawy. - @kAzek mówi że wciąż tak jest - nie pamiętam aby kiedykolwiek istotnie mylił się w sprawie Delphi.
Alternatywą jest - SharedMemory.

0

Podążając za wskazówką zmieniłem zawartość DLL na:


type
  wskaznik = ^lista;

  TDane= record
    nazwa, studio:shortstring;
    gatunek:shortstring;      //stworzyc typ danych
    data:TDateTime;
    ocena:Single;   ////stworzyc typ
  end;

  lista = record
    dane: TDane;
    next: wskaznik;
  end;

var
  first: wskaznik;

{$R *.res}

  ////////// ////////// ////////// ////////// //////////
  function Dodaj (var info: TDane):boolean; stdcall;
    var
      poprz,t:wskaznik;
  begin
    try
      if first=nil then
        begin
          new(first);
          first^.dane:=info;
          first^.next:=nil;
        end
      else
        begin
          t:=first;
          if info.nazwa<=first^.dane.nazwa then
            begin
              new(t);
              t^.dane:=info;
              t^.next:=first;
            end
          else
            begin
              while (t^.next<>nil)and(t^.dane.nazwa<info.nazwa) do
                begin
                  t:=t^.next;
                end;
              poprz:=t;
              new(t);
              t^.dane:=info;
              t^.next:=poprz^.next;
              poprz^.next:=t;
            end;
        end;
      result:=true;
    except
      result:=false;
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  function Usunpierw ():boolean;stdcall;
    var t:wskaznik;
  begin
    try
      t:=first;
      first:=first^.next;
      dispose(t);
      result:=true;
    except
      result:=false;
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  function Zapisz (var nazwa:shortstring):boolean;stdcall;
    var fp:file of TDane;
  begin
      begin
        try
          if first=nil then raise Exception.Create('Brak danych do zapisu.');
          if first<>nil then
            begin
              try
                AssignFile(fp,nazwa);			//podkreślana linijka
                rewrite(fp);
                while first<>nil do
                  begin
                    write(fp,first^.dane);
                    Usunpierw();
                  end;
              finally
                closefile(fp);
              end;
              result:=true;
            end
          else
            begin
              result:=false;
            end;
        except
          result:=false;
        end;
      end
  end;
  ////////// ////////// ////////// ////////// //////////
  function nilfirst():boolean;stdcall;
  begin
    try
      first:=nil;
      result:=false;
    except
      result:=false;
    end;
  end;
//i tu export

Wywołuję praktycznie tak samo (z usunięciem niepotrzebnych parametrów i usunięciem typu wskaźnikowego z głównego unitu i co za tym idzie rekordu zawierającego wskaźjnik), dodatkowo wywołuję na początku 'nilfirst', tj.:


firstnil();
    n:=//ilosc wierszy stringgridu bez pierwszego (ilosc rekordow);
    i:=1;
    while i<n do
      begin
        with elem do
           //przyjmowanie przez elem wartości stringgrida
        insert(elem);
        i:=i+1;
      end;
    save('Baza');

Występuje jednak bardzo podobny komunikat, a podkreśla mi linijkę 'Assignfile(fp,nazwa);' z funkcji 'Zapisz'.
Podejrzewam, że w moim rozumowaniu pomijam jakiś mały, istotny szczegół, serdecznie dziękuję za sugestie(w tym oczywiście powyższą). :)

1
_13th_Dragon napisał(a):

Pamiętaj że DLL i twój program mają zupełnie różne przestrzeni adresów.
Nieprawda.

Czyli upraszczając jeżeli wskaźnik był przydzielony w DLL to nie możesz go czytać poza DLL,
Nieprawda. Pamięć przydzielona w DLL musi być zwolniona w DLL, a przydzielona w EXE zwolniona w EXE, ale z przekazaniem wskaźnika nie ma żadnego problemu.

nawet zwykłego napisu nie dawało się przekazać
Bo to nie jest „zwykły napis”, tylko string który w Delphi jest opatrzony dodatkową magią (swego rodzaju garbage collectorem).

potrzebna była specjalna DLL'ka
No czyli się da.

1

Chyba nie zrozumiałeś tego co napisałem.
Nie możesz odczytać nic chowanego pod wskaźnikiem, ale przechowywać wskaźniki sobie możesz bez ograniczeń.
No i oczywiście nil on nawet Afryce też Nil (to znaczy w DLL czy nie nil to nil).
Natomiast ewidentnie próbujesz przekazać do DLL napis o tu save('Baza'); - więc pytanie czy borlndmm.dll jest na ścieżce path lub folderze z programem?

3

Jak na mój gust, w takim przypadku należałoby nie używać typów z Delphi, a po prostu wskaźników na tablice znakowe. O ile dobrze pamiętam w Delphi to jest PChar. Wtedy powinno wszystko działać poprawnie, obędzie się nawet bez użycia borlndmm.dll

0

Przepraszam, ewidentnie nie zrozumiałem.
Próbując wyeliminować błąd (w najbardziej łopatologiczny sposób) zmieniłem w DLL AssignFile(fp,nazwa); na AssignFile(fp,'Baza');, w związku z czym usunąłem var nazwa:shortstring z definicji funkcji (i w DLL i Unicie).
Jednak podkreślane nadal jest to AssignFile(fp,'Baza') i wyrzuca w przybliżeniu ten sam, a przynajmniej podobny komunikat (ta sama treść, inne cyfry).
Prawdopodobnie nadal popełniam głupi błąd, którego wyjaśnienia nie zrozumiałem, za co przepraszam i dziękuję za chęć pomocy i wytrwałość w tłumaczeniu. :)

W wypadku Pcharow rozumiem, ze w DLL'u?
Jednak niestety mimo to, nadal otrzymuje ten sam błąd jak w powyższym przykładzie.
Przy czym, w ostrzeżeniu DLL'a było napisane, że można używać shortstring-ów zamiast stringów, zamiennie z pchar-ami. O ile dobrze je zinterpretowałem.

2

Według mnie wszelkie typy stringowe zastępujesz PChar. Poza tym nie korzystasz też raczej z typów file of cośtam tylko robisz to funkcjami WinAPI i bardziej pod tym kątem. Ewentualnie wszystkie wykorzystania obiektów przerabiasz na typy rekordowe w miarę możliwości. No chyba, że dllka ma być Delphi only. Ale to wtedy bez sensu, bo po co dllka. W implementacji po swojemu listy jednokierunkowej jestem lamerem, ale wział bym kod z artukułu http://4programmers.net/Delphi/Lista_jednokierunkowa i odpowiednio go dopasował do wymogów dllki. Skoro i tak siedzi to w dllce, to przy odpowiednim zachowaniu zasad i logicznym rozplanowaniu, będzie ona do wykorzystania rownież pod innymi językami. A to, że sobie użyjesz gotowego komponentu w jej kodzie, tylko raczej Tobie ułatwi całość przeprowadzenia prawidłowej implementacji.

0

Dlka może być "Delphi only" ponieważ jest mi potrzebna tylko do tego projektu, a nie mam raczej zamiaru się nią dzielić, ponieważ zdaję sobie sprawę, że używanie tu list prawdopodobnie nie jest najbardziej optymalne, a ona sama nie jest napisana perfekcyjnie.
Co do pchar-ów, to próbowałem i tak jak zedytowałem wyżej, jeśli moja interpretacja jest słuszna, to DLL zezwala na używanie PChar-ów lub ShortString-ów.
Jednak jestem w stanie uwierzyć, że błąd jest po stronie File of cośtam(w sumie jestem w stanie uwierzyć, że błąd jest po stronie mojego rozumowania), jednak jeśli tak, to jak można by to rozwiązać, lub zastąpić?
Jeszcze spróbuję z wcześniej sugerowanym "borlndmm.dll".
Serdecznie dziękuję wszystkim za aktywną pomoc.

1

A może najprościej zrobisz tak, ciut może mało elegancko. Ale niech ta dllka otrzymuje po prostu Handle do jakiegoś TListBoxa lub po prostu typ komponentu jaki sobie założyłeś do wyświetlenia danych i już kodem go wypełnia. Skoro ma być Delphi only. Ale fajniej by było nawet robiąc program na szybkie zaliczenie, zrobić go tak by był dopracowany.

0

Słuszna uwaga, dziękuję za, że tak nazwę, sprowadzenie na właściwe tory, bo słusznie mówisz, że jak już robić, to porządnie. Zwłaszcza, że mam więcej czasu niż parę dni. :)
Postaram się nad tym przysiąść, przeczytać odpowiedzi dokładnie i ze zrozumieniem, i rozwiązać problem na spokojnie jutro, bo już dziś mi dość krwi to napsuło.

I ciekawa sprawa (wg. mnie, jednak nie wiem z czego wynikająca), jeśli w:

  function Zapisz (var nazwa:shortstring):boolean;stdcall;
    var fp:file of TDane;
  begin
      begin
        try
          if first=nil then raise Exception.Create('Brak danych do zapisu.');
          if first<>nil then
            begin
              try		///////////////
                AssignFile(fp,nazwa);//////////////
                rewrite(fp);
                while first<>nil do
                  begin
                    write(fp,first^.dane);
                    Usunpierw();
                  end;
              finally
                closefile(fp);
              end;
              result:=true;
            end
          else
            begin
              result:=false;
            end;
        except
          result:=false;
        end;
      end
  end; 

Zamienię miejscami linijki zaznaczone ///////, tj. try z AssignFile(fp,nazwa);, to mimo że występuje ten sam problem, to podkreślana jest linijka niżej, tj. AssignFile w powyższym kodzie i try przy ich zamianie.

1

Spróbuj zapisać za pomocą TFileStream

1

Nie wiem jak jest z shortstringami, ale w dllkach generalnie nie powinniśmy używać typu string i wszelkich "pochodnych". Oczywiście jeżeli chcemy sprawnie działającą dllkę bez problemów. Zgodnie z tym o czym informuje ostrzeżenie przy tworzeniu nowego projektu dllki.

0

Ostrzeżenie, jak wspomniałem czytałem i chciał, nie chciał stoi tam To avoid using DELPHIMM.DLL, pass string information using PChar or ShortString parameters., z czego rozumiem ze ShortStringów użyć mogę bez żadnych konsekwencji.
Zauważyłem też, że debugger zawsze podświetla mi dokładnie linijkę nr.100 i 117 DLLki (która to po drobnym przebudowaniu jej nie wchodzi w skład żadnej używanej(jeszcze) przeze mnie procedury(zamiast funkcji stosuję procedury)). Próbowałem z użyciem sharemem, jedynym wynikiem było przesunięcie podświetlenia.
DLLka wygląda teraz tak

library DLLTest;
uses
  SysUtils,
  Classes,
  Windows;
type
  wskaznik = ^lista;
  TDane= record
    nazwa, studio:shortstring;
    gatunek:shortstring;
    data:TDateTime;
    ocena:Byte;
  end;
  lista = record
    dane: TDane;
    next: wskaznik;
  end;
var
  first: wskaznik;
{$R *.res}
  ////////// ////////// ////////// ////////// //////////
  procedure Dodaj(var info: TDane); stdcall;
    var
      poprz,t:wskaznik;
  begin
    try
      if first=nil then
        begin
          new(first);
          first^.dane:=info;
          first^.next:=nil;
        end
      else
        begin
          t:=first;
          if info.nazwa<=first^.dane.nazwa then
            begin
              new(t);
              t^.dane:=info;
              t^.next:=first;
            end
          else
            begin
              while (t^.next<>nil)and(t^.dane.nazwa<info.nazwa) do
                begin
                  t:=t^.next;
                end;
              poprz:=t;
              new(t);
              t^.dane:=info;
              t^.next:=poprz^.next;
              poprz^.next:=t;
            end;
        end;
    except
      showmessage('Nastąpił błąd podczas dodawania elementu do listy.');
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  procedure Usunpierw();stdcall;
    var t:wskaznik;
  begin
    try
      t:=first;
      first:=first^.next;
      dispose(t);
    except
      showmessage('Wystąpił błąd podczas usuwania elementu z listy.')
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  Procedure Zapisz(var nazwa:pchar);stdcall;
    var fp:file of TDane;
  begin
    begin
      try
        AssignFile(fp,nazwa);
        if first=nil then raise Exception.Create('Brak danych do zapisu.');
        if first<>nil then
          begin
            rewrite(fp);
              while first<>nil do
                begin
                  write(fp,first^.dane);
                  Usunpierw();
                end;
            end;
          end
      finally
        closefile(fp);
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  procedure nilfirst();stdcall;
  begin
    try
      first:=nil;
    except
      showmessage('Wystąpił błąd podczas zmiany wartości elementu pierwszego listy jednokierunkowej.');
    end;
  end;
  ////////// ////////// ////////// ////////// //////////
  //Gdzieś w tym bloku znajduje się podświetlany element, w zależności od tego co jest w 100. linii, może być to begin, try, instrukcja if, a błąd jest zawsze ten sam
  ////////// ////////// ////////// ////////// //////////
  exports
    Dodaj index 1,
    Usunpierw index 2,
    nilfirst index 3,
    Zapisz index 4;
begin
end.

A próba jej użycia w przybliżeniu tak:

procedure TForm1.Zapisz(Sender: TObject);
var
  elem:TDane;
  i,n:integer;
begin
  try
    xxx:=loadlibrary('DLLTest.dll');
    if xxx<hinstance_error then raise Exception.Create('Nie można załadować biblioteki.');
    insert:=getprocaddress(xxx,pchar(1));
    save:=getprocaddress(xxx,pchar(4));
    firstnil:=getprocaddress(xxx,pchar(3));
    if (@save = nil)or(@insert = nil)or(@firstnil=nil) then raise Exception.Create('Nie mozna załadowac funkcji.');

    firstnil();

    n:=1;
    for i := 1 to stringgrid1.rowcount-1 do
      begin
        if stringgrid1.cells[0,i]='' then n:=n+1;
      end;
    if n=stringgrid1.rowcount-1 then raise Exception.Create('Brak danych do wprowadzenia. Nazwa rekordu jest wymagana.');

    for i := 1 to stringgrid1.RowCount-1 do
      begin
        if stringgrid1.Cells[0,i]<>'' then
          begin
            elem.nazwa:=stringgrid1.Cells[0,i];
            if stringgrid1.Cells[1,i]='' then elem.studio:='Brak' else elem.studio:=stringgrid1.Cells[1,i];
            if stringgrid1.Cells[2,i]='' then elem.gatunek:='Brak' else elem.gatunek:=stringgrid1.Cells[2,i];
            if (stringgrid1.Cells[3,i]='')or(stringgrid1.Cells[3,i]='Brak') then elem.nazwa:='30-12-1998' else elem.data:=strtodate(stringgrid1.Cells[3,i]);
            if (stringgrid1.Cells[3,i]='')or(strtoint(stringgrid1.Cells[4,i])>100) then elem.ocena:=0 else elem.ocena:=strtoint(stringgrid1.Cells[4,i]);

            insert(elem);
          end;
      end;
    save('Baza');
  finally
    freelibrary(xxx);
  end;
end;
1

Zapoznaj się z pojęciem formatowania http://4programmers.net/Forum/998482
Sformatuje tą metodę za ciebie:

Procedure Zapisz(var nazwa:pchar);stdcall;
var fp:file of TDane;
begin
  begin // Drugi begin ???
    try
      AssignFile(fp,nazwa);
      if first=nil then raise Exception.Create('Brak danych do zapisu.');
      if first<>nil then // brak wiedzy co to jest else
      begin
        rewrite(fp);
        while first<>nil do
        begin
          write(fp,first^.dane);
          Usunpierw();
        end;
      end;
    end  // end do try bez finally 
  finally // finally do drugiego begin'a
    closefile(fp);
  end;
end;

No i przydało się lepsza komunikacja, jak piszesz że "... debugger zawsze podświetla ..." to my rozumiemy że się skompilowało i możesz to debugować, nie patrzymy pod kątem że to się nie kompiluje.
Radzę przeczytania jakiegoś prostego kursu (skoro coś już ci idzie z programowaniem to łatwo pójdzie), chodzi o to że masz problem z nazwaniem tego z czym masz problem, kurs może to zmienić.

0

Dziękuję za słuszne rady, postaram się stosować! :)
A kod owszem, kompiluje się, jeśli uruchomię skompilowany projekt bez debuggera i wduszę przycisk ze zdarzeniem "onClick - Zapisz" to wszystko się zamyka bez żadnego komunikatu, przy użyciu debuggera dostaję wcześniej wspominany First chance exception at..., gdy każę mu kontynuować otrzymuję kilka podobnych komunikatów, przy "break" otwiera mi zakładkę DLLki, tudzież System, lub CPU (i tam na czerwono znaczy jakiś pojedynczy wiersz). Muszę ewidentnie popracować nad nazywaniem własnych problemów.
A i dziękuję za zauważenie tego begin,end, finaly.

1

To nie może się kompilować, bo masz try bez finali i bez except oraz zwykły begin z finally.
Program się nie kompiluje zaś IDE odpala starą wersje.
Zacznij czytać komunikaty.

0
DeXo napisał(a):

A kod owszem, kompiluje się, jeśli uruchomię skompilowany projekt bez debuggera i wduszę przycisk ze zdarzeniem "onClick - Zapisz" to wszystko się zamyka bez żadnego komunikatu, przy użyciu debuggera dostaję wcześniej wspominany First chance exception at...,
Postaw breakpointa na pierwszej lini zdarzenia OnClick i potem wykonuj program krokowo po 1 instrukcji z wchodzeniem do funkcji. Wtedy zobaczysz na jakiej instrukcji dokładnie się program wywala. Jak będziesz miał otwarte 2 projekty to IDE będzie wchodzić nawet w funkcje w dll'ce i będziesz mógł śledzić wykonanie funkcji listy.

0

Mi ten szczegół niestety wiele nie mówi, jednak myślę że tu na forum znajdzie się ktoś, komu to wyjaśni w czym leży problem, a ten ktoś zechce ze mną się przemyśleniami podzielić.
Utworzyłem nowy guzik na formatce, którego zdarzenie "onClick" wygląda tak:

procedure TForm1.Testklik(Sender: TObject);
begin
  try
    xxx:=loadlibrary('DLLTest.dll');
    if xxx<hinstance_error then raise Exception.Create('Nie można załadować biblioteki.');
    insert:=getprocaddress(xxx,pchar(1));
    save:=getprocaddress(xxx,pchar(4));
    firstnil:=getprocaddress(xxx,pchar(3));
    if (@save = nil)or(@insert = nil)or(@firstnil=nil) then raise Exception.Create('Nie mozna załadowac funkcji.');

    firstnil();

  finally
    freelibrary(xxx);
  end;
end;
 

z firstnil:procedure();stdcall; przed implementation
a firstnill() wygląda tak:

procedure nilfirst();stdcall;
begin
  try
    showmessage('Paparapa');
    //first:=nil;
  except
    showmessage('Wystąpił błąd podczas zmiany wartości elementu pierwszego listy jednokierunkowej.');
  end;
end;

z Exports nilfirst index 3,
Problem nadal występuje przy próbie wywołania tej procedury, jeśli zrobię // firstnil(); to się nie pokazuje, co może komuś inteligentniejszemu ode mnie i bardziej obeznanemu podsunie pomysł na miejsce narodzin mojego access violation.

1

Jesteś pewien że aktualnie to się kompiluje?
Skasowałeś fizycznie EXE?
Ja to ściągnąłem z tego ostatniego posta uzupełniłem brakujące deklaracje byle czym i idzie bez problemu.
Może powinieneś zapoznać się z Project|Build All Project

0

Dziękuję serdecznie!
DLLka z jakiegoś powodu się nie kompilowała od dłuższego czasu poprawnie i nie pokazywała przy próbie kompilacji błędów, po usunięciu .exe i .dll wyrzucać zaczęła błędy (jakiś brakujący :, niezgodność typów) i po przejrzeniu tego w końcu ujrzałem piękne okienko, wywołane z DLLki, z napisem "Pamparampampam".
W życiu nie podejrzewałem że mi coś takiego radości tyle sprawi! :D
Serdecznie dziękuję raz jeszcze i liczę, że zamiana "Pamparampampama" na coś bardziej użytecznego mnie nie pokona już! :D
I przepraszam wszystkich zaangażowanych za swoją niekompetencję!

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