Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Warper-Class und Ungültige Zeigeroperation (https://www.delphipraxis.net/8990-warper-class-und-ungueltige-zeigeroperation.html)

theomega 16. Sep 2003 13:43


Warper-Class und Ungültige Zeigeroperation
 
Hallo Leute
nachdem ich mit eurer Hilfe zumindest den Fehler in meinem Code gefunden habe, habe ich einen zweiten Anlauf gestartet, meinen Datenbankzugriff in eine DLL auszulagern. Das funktioniert auch schon ganz gut, nur bekomme ich nach jedem Query den Fehler "Ungültige Zeigeroperation". Ich weiß nicht, ob der Fehler von der DLL kommt oder von der Hauptanwendung.

Erstmal der Code:

database.dll:
Delphi-Quellcode:
library database;

uses
  SysUtils,
  Classes,
  IBCustomDataSet,
  IBQuery,
  IBDatabase,
  inifiles,
  dialogs,db,
  IBServices;

{$R *.res}

var qrmain:TIBQuery;
    trmain:TIBTransaction;
    dbmain:TIBDatabase;


procedure dll_initdatabase;
var ini:TIniFile;
begin;
ini := TInifile.create('./config.ini');

try
dbmain := TIBDatabase.Create(nil);
trmain := TIBTransaction.Create(nil);
qrmain := TIBQuery.Create(nil);

dbmain.LoginPrompt := false;
dbmain.DefaultTransaction := trmain;
dbmain.IdleTimer := 0;
dbmain.AllowStreamedConnected := false;

trmain.DefaultDatabase := dbmain;
trmain.Params.Add('concurrency');
trmain.Params.Add('nowait');
trmain.AutoStopAction := saNone;

qrmain.Database := dbmain;
qrmain.Transaction := trmain;
qrmain.CachedUpdates := false;


dbmain.DatabaseName := ini.ReadString('database','databasename','');
dbmain.SQLDialect := ini.ReadInteger('database','sqldialect',3);
dbmain.Params.Text :=
'password='+ini.ReadString('database','password','')+#10#13+
'lc_ctype='+ini.ReadString('database','charset','')+#10#13+
'user_name='+ini.ReadString('database','user_name','');
dbmain.Connected := true;
trmain.Active := true;
finally
  ini.Free;
end;
end;

procedure dll_execquery(str:pchar;passv:boolean);
begin;
qrmain.Close;
qrmain.SQL.Clear;
qrmain.SQL.Add(str);
if (passv) then qrmain.Open
else qrmain.ExecSQL;
end;

procedure dll_commit;
begin;
if trmain.intransaction then trmain.Commit;
Trmain.StartTransaction;
end;

function dll_getinsertid(tab:pchar;fi:pchar):integer;
begin;
dll_execquery(pchar('SELECT max('+fi+') as m FROM '+tab+';'),true);
result := database.qrmain.fieldbyname('m').AsInteger;
end;

procedure dll_next;
begin;
qrmain.Next;
end;

function dll_eof:boolean;
begin;
result := qrmain.Eof;
end;

function dll_recordcount:integer;
begin;
result:= qrmain.RecordCount;
end;

function dll_fieldbyname(name:pchar):TField;
begin;
result:=qrmain.fieldbyname(name);
end;

procedure dll_desinit;
begin;
qrmain.Free;
trmain.Free;
dbmain.Free;
end;


exports dll_initdatabase,dll_execquery,dll_commit,dll_getinsertid,dll_next,dll_eof,dll_recordcount,dll_fieldbyname,dll_desinit;


begin
end.
und im Hauptprogramm:

Erstmal meine Unit mit der Warper-Classe:
Delphi-Quellcode:
unit Udllquery;

interface

uses db;

type TDLLQuery=class
    public
      constructor create;
      destructor destory;
      function fieldbyname(name:string):TField;
      procedure execquery(str:string;passv:boolean);
      procedure commit;
      function recordcount:integer;
      function eof:boolean;
      procedure next;
      function getinsertid(tab:string;fi:string):integer;
end;

implementation


      procedure dll_initdatabase; external 'database.dll';
      function dll_getquery:pointer; external 'database.dll';
      procedure dll_commit; external 'database.dll';
      procedure dll_execquery(str:pchar;passv:boolean); external 'database.dll';
      function dll_fieldbyname(name:pchar):TField; external 'database.dll';
      procedure dll_next;external 'database.dll';
      function dll_eof:boolean;external 'database.dll';
      function dll_recordcount:integer;external 'database.dll';
      function dll_getinsertid(tab:pchar;fi:pchar):integer;external 'database.dll';
      procedure dll_desinit;external 'database.dll';

constructor TDLLquery.create;
begin;
  dll_initdatabase;
  inherited;
end;

destructor TDLLquery.destory;
begin;
  dll_desinit;
  inherited;
end;

procedure TDLLQuery.commit;
begin;
  dll_commit;
end;

procedure TDLLQuery.execquery(str:string;passv:boolean);
begin;
  dll_execquery(pchar(str),passv);
end;

function TDLLQuery.fieldbyname(name:string):TField;
begin;
  result := dll_fieldbyname(pchar(name));
end;

function TDLLQuery.recordcount:integer;
begin;
  result := dll_recordcount;
end;


function TDLLQuery.eof:boolean;
begin;
  result:=dll_eof;
end;

procedure TDLLQuery.next;
begin;
  dll_next;
end;

function TDLLQuery.getinsertid(tab:string;fi:string):integer;
begin;
result:=dll_getinsertid(pchar(tab),pchar(fi));
end;

end.
und mein Zugriff darauf:
Delphi-Quellcode:
var
  Form1: TForm1;
  qrmain:TDllQuery;

procedure TForm1.Button1Click(Sender: TObject);
begin
qrmain := TDLLQuery.create;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
qrmain.execquery('SELECT * FROM sachbuch',true);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
while not qrmain.eof do begin;
    showmessage(qrmain.fieldbyname('sbnr').asstring);
    qrmain.next;
end;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
qrmain.Destroy;
end;
Das komische ist: Die Debug-Meldung in meinem Programm wird noch angezeigt: "Query fertig". Erst danach tritt die Exception auf. Eigentlich wird zu der Zeit nirgends Code ausgeführt.

Wer kann mir helfen?

Danke
TO

jbg 16. Sep 2003 13:48

Re: Warper-Class und Ungültige Zeigeroperation
 
Zitat:

function dll_fieldbyname(name:pchar):TField;
Das PChar ist schon mal gut und erspart dir die Unit ShareMem. Aber diesen Vorteil machst du gleich wieder zu nichte, indem du TField zurücklieferst.

Ghostwalker 16. Sep 2003 13:50

Re: Warper-Class und Ungültige Zeigeroperation
 
hi,

TDLLQuery ist im Hauptprogramm eine Klasse, die so nur eine Typ-Definition ist (ähnlich wie ein Record).

Um nun das ganze nutzen zu können mußt du, bevor du irgendwas anderes damit machst, erstmal eine Instanz erzeugen.

Code:
  :
  :
  QRMain := TDLLQuery.create;
  :
  :
Jetzt kannst du damit arbeiten. Zum abschluß, wenn du die Instanz nicht mehr brauchst solltest du noch QRMain.free aufrufen, damit der Speicher den das Objekt verbraucht, wieder freigegeben wird.

theomega 16. Sep 2003 14:18

Re: Warper-Class und Ungültige Zeigeroperation
 
@Ghostwalker: bringt leider nichts!
@jbg: ich bekomme aber das Ergebnis geliefert, kann es trotzdem daran liegen?

Ich habe jetzt oben den Code mal so geändert, das Create und Destory belegt werden!

Grüße
TO

theomega 16. Sep 2003 20:22

Re: Warper-Class und Ungültige Zeigeroperation
 
Weiß den keiner eine Lösung? Wann zeigt Delphi überhaupt den Fehler normalerweise an? Wo kann ich suchen?

Grüße
TO

jbg 16. Sep 2003 20:54

Re: Warper-Class und Ungültige Zeigeroperation
 
Zitat:

Zitat von theomega
Wann zeigt Delphi überhaupt den Fehler normalerweise an?

Delphi zeigt diesen Fehler an, wenn du einen Zeiger dereferenzierst, der ins Nirvana zeigt. Das sagt dir aber auch die Fehlermeldung.

Zitat:

Wo kann ich suchen?
Überall und nirgends. Das ist nun mal der Fluch von Zeigern.


Hast du es schon mal mit ShareMem probiert, oder anstatt einer DLL ein Package zu nehmen?

Ghostwalker 16. Sep 2003 22:42

Re: Warper-Class und Ungültige Zeigeroperation
 
Hi,

hab da noch was entdeckt. Du gibst aus einer DLL ein Object (TField) zurück (GetFieldbyName). Das funktioniert aber nicht mit DLL's, da sie einen eigenen Speicherbereich nutzen, auf den das Hauptprogramm nicht zugreifen kann (mal etwas grob umschrieben).

Entwerder du machst wirklich ein Package draus (mal nach dem Stichwort dynamische Packages suchen). Oder du gibst die relevanten Infos des TField-Objectes einzeln zurück und generierst im Hauptprogramm ein TField daraus (mal so auf die schnelle gedacht).

Werd mir das Morgen noch mal genauer angugen :)

theomega 17. Sep 2003 11:20

Re: Warper-Class und Ungültige Zeigeroperation
 
Es funktioniert ja aber alles. Ich komme problemlos an die Daten des Felds heran. Kann also eigentlich nicht daran liegen oder?

Ghostwalker 18. Sep 2003 06:53

Re: Warper-Class und Ungültige Zeigeroperation
 
Na..so problemlos wohl nicht, sonst gäbs keine Fehlermeldung.

Wenn du das Programm ohne IDE laufen läßt wirst du auch feststellen das das Progi beendet wird.

Du mußt dir eine DLL, was die Speicherverwaltung betrifft, vorstellen wie ein richtiges Hauptprogramm. Sie besitzt einen eigenen Speicherbereich, eine eigene VMT usw. auf die ein anderes Programm nicht zugreifen kann.

Folglich kennt dein Hauptprogramm das TField-Objekt aus deiner DLL nicht. Das du trotzdem an die Daten kommst ist reiner Zufall (hängt wohl auch von der Speicherbelegung und dem BS ab).


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz