Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi TWideStriblist kann nicht zu TStringlist zugewiesen werden (https://www.delphipraxis.net/118617-twidestriblist-kann-nicht-zu-tstringlist-zugewiesen-werden.html)

Smiley 11. Aug 2008 16:32


TWideStriblist kann nicht zu TStringlist zugewiesen werden
 
Ich habe mir eine DLL geschrieben mit einigen Datenbankfunktionen und habe mit einer Procedure ein Problem bei der Übergabe.

Ich versuche eine TSringlist Variable von der DLL an das aufrufende Programm zu übertragen.
Dabei kommt der Fehler "TWideStriblist kann nicht zu TStringlist zugewiesen werden"

Folgendermaßen sieht der Aufruf im Programm aus:

Delphi-Quellcode:
Procedure DBListTables(var Liste:TStringList);
  external DllPath;

.
.
procedure TForm1.btnListTablesClick(Sender: TObject);
var
  xListe:TStringList;

begin
  lstTables.Clear; // ListBox löschen
  xListe:=TStringList.Create;
  DBListTables(xListe);
  lstTables.Items:=xListe;
  xListe.Free
end;
In der DLL sieht es so aus:

Delphi-Quellcode:
Procedure ListTables(Var Liste: TStringList);
Var
  i                          : Integer;

Begin
  Liste.Clear;
  Con1.GetTableNames(Liste, False);

  i := 0;
  Repeat
    Begin
      If (Pos('Cellinfo', Liste[i])) > 0 Then
        Liste.Delete(i);
      Inc(i);
    End;
  Until Liste.Count = i;

  i := 0;
  Repeat
    Begin
      Liste[i] := Copy(Liste[i], 1, Length(Liste[i]) - 4);
      Inc(i);
    End;
  Until Liste.Count = i;
End;
Wenn beides in einem Programm eingebunden ist, dann funktioniert es.
Wenn ich die Procedure über die DLL-Schnittstelle aufrufe, dann kommt beim Aufruf
DBListTables(xListe);
die Fehlermeldung.

Scheinbar gibt es Probleme mit der Übergabe von Stringlisten.

Kann mir dabei jemand helfen ?

DGL-luke 11. Aug 2008 16:42

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
jetzt müssten wir nur noch wissen wo in der DLL der fehler kommt. setz da mal n breakpoint rein.

und/oder versuch den code mal in deine exe zu kopieren und da auszuführen.
Und schau ob deine DB(?) eventuell mit widestrings operiert.

Smiley 11. Aug 2008 16:55

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Der Fehler kommt nicht in der DLL, sondern beim Aufruf der DLL.
In der DLL kann ich keinen Breakpoint setzen, da diese ja extern ist.
Wie ich schon erklärt habe, habe ich den SourceCode des DLL-Programmes zusammen mit der Procedure aus meinem Aufrufprogramm in einem Projekt getestet, dort funktioniert es ohne Probleme.
Es muss was mit der Übergabe von DLL-Prog an Aufrufprog zu tun haben.
Möglicherweise kann man keine Stringlist aus einem DLL-Prog übergeben.

DGL-luke 11. Aug 2008 17:03

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Der Fehler kommt nicht in der DLL, sondern beim Aufruf der DLL.
Diese zwei Aussagen schließen sich ja gegenseitig nicht aus.

Zitat:

Möglicherweise kann man keine Stringlist aus einem DLL-Prog übergeben.
Im Zweifelsfalle extrem möglich. Die VCL, die in die Exe einkompiliert ist, erkennt die VCL in der DLL nicht an. Laufzeitpackages helfen. Ein bisschen. DLL-Hölle ftw!

Smiley 11. Aug 2008 17:10

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Ich arbeite zum ersten mal mit DLLs und es hat mit den anderen Parametern bisher prima funktioniert, sogar Records mit vielen Variablen drin lassen sich problemlos übergeben.
Die sind aber eben alle genau definiert von der Größe.
Bei der Stringlist kann ich beim Aufruf noch nicht wissen wie viele Werte übergeben werden müssen.
Gibt es vielleicht eine andere Möglichkeit eine Liste zu übergeben, deren Anzahl der Elemente man beim Aufruf noch nicht kennt ?

Bernhard Geyer 11. Aug 2008 17:18

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Verwendest du gemeinsame Laufzeitpackages? Falls nein hast du zweit RTTI's und DLL.TObject <> Exe.TObject und jeder as/is Vergleich/Cast wird fehlschlagen.

Smiley 11. Aug 2008 17:23

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Ich habe beide Programmteile mit dem selben Entwicklungssystem erstellt und die DLL-Datei dann in das andere Projektverzeichnis kopiert.
Was sind RTTIs ?

himitsu 11. Aug 2008 17:24

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
EXE-DLL-übergreifende Dinge im Zusammenhang mit String, TStringList und anderen Sachen ergeben meistens Probleme.

die RTTI und der Standard-Speichermanager arbeiten da jeweils unabhängig und vertragen sich nicht untereinander.


es gibt schon mehrere Theman zu diesem Problem ... einfach mal etwas umschauen :stupid:


du könntest mal versuchen die Daten z.B. per PChar, statt per TStringList rauszubekommen.



z.B. DLL-intern den StringList-Inhalt in den übergebenen Puffer kopieren und dann wieder zurück
Delphi-Quellcode:
Procedure DBListTables(Liste: PChar; MaxLength: Integer);
  external DllPath;


DBListTables(@Buffer, BufferSize);
xListe := TStringList.Create;
xListe.CommaText := {Buffer};
lstTables.Items:=xListe;
xListe.Free;

// [add] warum so umständlich ??? *grübel*
// sollte auch direkt gehn *kopfauftischhau*
DBListTables(@Buffer, BufferSize);
lstTables.Items.CommaText := {Buffer};
[add]
Hier im Forum suchenRTTI
oder halt mal die Maus über RTTI :zwinker:

DGL-luke 11. Aug 2008 17:26

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
hmmm. da gibt es natürlich unschöne lösungen, in denen du z.B. hart auf TStringList castest.

Delphi-Quellcode:
Procedure ListTables(Var StrangeList: TObject);
Var
  i                          : Integer;
  Liste: TStringList;
Begin
  Liste := TStringList(StrangeList);

  Liste.Clear;
  Con1.GetTableNames(Liste, False);

  i := 0;
  //...
End;
Funktioniert garantiert solange, wie alle Module gegen die selbe VCL kompiliert werden (glaube ich).

Ansonsten: Alles in einen TMemoryStream packen und per WM_COPYDATA die Rohdaten "verschicken".

Smiley 11. Aug 2008 18:53

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Das Beispiel von himitsu gefällt mir, das werde ich mal ausprobieren.
Als MemoryManager benutze ich FASTMM4 in der DLL, da das mit dem Delphieigenen ja nicht so gut funktionieren soll.
Die umständliche Programmierung mit dem erstellen und löschen der Stringlist im Aufrufprogramm habe ich gemacht, da ich das ListenObjekt ja nur im Aufrufprogramm erzeugen und wieder freigeben kann.
Wenn ich es in der DLL erstellen und wieder freigeben würde, dann wäre das etwas ungünstig.

Wie ist das jetzt mit der Methode von himitsu?
Wo wird der Buffer angelegt, im Aufrufprogramm oder in der DLL.
Wie sieht das ganze dann in der DLL aus, dort muss die Stringlist mit den Daten ja auch erst noch in Commaseparated umgewandelt werden.

Elvis 11. Aug 2008 19:06

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Zitat von DGL-luke
Ansonsten: Alles in einen TMemoryStream packen und per WM_COPYDATA die Rohdaten "verschicken".

*hust*, *hust* Hö? :shock:

Ganz einfache Lösung (OHNE Hin- & Herkopierei!)
Generell würde ich empfehlen WideString statt AnsiString zu nehmen. Aber IMO sind ANSI Apps sowieso mehr als museumsreif.
Falls du AnsiString nimmst, solltest du FastMM in der App haben und in den DLLs. Aber mit AnsiString machst du C++-DLLs unmöglich..

Smiley 11. Aug 2008 19:20

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Also diese Lösung bekomme ich auch nicht hin, habe es gerade versucht.
Wie muss ich die Variable denn im Aufrufprogramm dann definieren, als TObject geht nicht und als TStringlist kommt der alte Fehler.
Delphi-Quellcode:
Procedure ListTables(Var StrangeList: TObject);
Var
  i                          : Integer;
  Liste: TStringList;
Begin
  Liste := TStringList(StrangeList);

  Liste.Clear;
  Con1.GetTableNames(Liste, False);

  i := 0;
  //...
End;
Funktioniert garantiert solange, wie alle Module gegen die selbe VCL kompiliert werden (glaube ich).

Smiley 11. Aug 2008 19:24

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Generell würde ich empfehlen WideString statt AnsiString zu nehmen. Aber IMO sind ANSI Apps sowieso mehr als museumsreif.
Falls du AnsiString nimmst, solltest du FastMM in der App haben und in den DLLs. Aber mit AnsiString machst du C++-DLLs unmöglich.
Ich benutze auf beiden Seiten die Fastmm4.

Kompatibilität ist nicht nötig, der Record den ich verwenden muss ist auch nicht C++ kompatibel, da macht diese Variable es auch nicht aus.

Wie würde der Aufruf mit AnsiString denn aussehen ?

Scheinbar führen hier viele Wege nach Rom.

DGL-luke 11. Aug 2008 19:52

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Elvis' Lösung ist wohl die klügste....

Zitat:

als TObject geht nicht
"Geht nicht" ist keine Fehlerbeschreibung... was genau geht nicht?

Smiley 11. Aug 2008 20:05

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Ich habe in der DLL und im aufrufprogramm die Variable als TObject angelegt.
Beim Aufruf greife ich als TStringlist zu.

es erscheint folgende Meldung:
[Pascal Fehler] uMainReadTest.pas(237): E2033 Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen

Delphi-Quellcode:
Procedure DBListTables(var Liste:TObject);
  external DllPath;
.
.
procedure TForm1.btnListTablesClick(Sender: TObject);
var
  xListe:TStringList;
//  i:Integer;

begin
  lstTables.Clear;
  xListe:=TStringList.Create;
  DBListTables(xListe);
  lstTables.Items:=xListe;
.
.

API 11. Aug 2008 20:16

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

"TWideStriblist kann nicht zu TStringlist zugewiesen werden"
Heißt die Fehlermeldung tatsächlich so? Kenne gar keine TWideStriblist...

Smiley 11. Aug 2008 20:51

TWideStringlist kann nicht zu TStringlist zugewiesen werden
 
Zitat:

Zitat von API
Zitat:

"TWideStriblist kann nicht zu TStringlist zugewiesen werden"
Heißt die Fehlermeldung tatsächlich so? Kenne gar keine TWideStriblist...

Es soll natürlich heißen:
TWideStringlist kann nicht zu TStringlist zugewiesen werden

DGL-luke 11. Aug 2008 20:55

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Zitat von Smiley
es erscheint folgende Meldung:
[Pascal Fehler] uMainReadTest.pas(237): E2033 Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen

Und Zeile 237 von uMainReadTest ist welche genau?

Smiley 11. Aug 2008 21:02

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Delphi-Quellcode:
procedure TForm1.btnListTablesClick(Sender: TObject);
var
  xListe:TStringList;
//  i:Integer;

begin
  lstTables.Clear;
  xListe:=TStringList.Create;
  DBListTables(xListe);         // Zeile 237
  lstTables.Items:=xListe;
.

Elvis 11. Aug 2008 21:17

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Zitat von Smiley
Also diese Lösung bekomme ich auch nicht hin, habe es gerade versucht.

Und was hast du versucht?
Also welche schritte hast du gemacht, was für Meldungen kamen, was hast du dann versucht?
"Geht nicht" ist keine Frage und "Hab ich versucht" ist keine Antwort.

Ich versuche mal dir trotz der fehlenden Infos einen Ansatz zu geben:

Nehmen wir an, du hast das Interface als SharedStringListIntf.pas gespeichert un die Klasse als SharedStringListImpl.pas.
Die DLL braucht nur das Interface, die Unit mit der Implementierung hat da drin NIX zu suchen.

Delphi-Quellcode:
library ShareIntfTestDLL;

uses
  FastMM4,
  uSharedInterface in '..\SharedStringListIntf.pas';

procedure FillTableNames(const aTableNames : ISharedStringList); stdcall;
var
  i : Integer;
begin
  for i := 1 to 10 do
    aTableNames.Add('Table' + StrToInt(i));
end;

exports
  FillTableNames;

Ausgeführt werden kann das ganz einfach. Die Echse muss beide Units enthalten, SharedStringListIntf & SharedStringListImpl.

Da Delphi automatisch die Referenzen von interfaces zählt muss man die "Verpackung" um die Stringlist NICHT manuell freigeben.
Delphi-Quellcode:
procedure FillTableNamesCore(const aTableNames : ISharedStringList); stdcall;
  external DllPath name 'FillTableNames';

procedure FillTableNames(const aTableNames : TStrings);
begin
  FillTableNamesCore(TSharedStringListWrapper.Wrap(aTableNames));
end;

procedure DeinForm.SomeButtonClickHandler(aSender : TObject);
begin
  FillTableNames(deineListBox.Items);
end;
Da shabe ich mir mangels Delphi nur aus den Fingern gesaugt. Können also noch ein paar Eier drin versteckt sein.
wenn es nicht so geht wie du willst, sei bitte ausführlich damit WAS du WIE versucht hast, WELCHE Fehlermeldungen du bekamst und was du daraufhin versucht hast.

DGL-luke 11. Aug 2008 21:58

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Nimm Elvis' Ansatz oder meinen; zu meinem kann ich jetzt nur sagen: warum deklarierst du den parameter als "var"? das wird ja nirgends neu zugewiesen.

Smiley 11. Aug 2008 22:24

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Über den Typ ISharedStringList habe ich jetzt den Beitrag von Elvis gefunden in dem das Problem näher erläutert wird.
Wenn ich das richtig verstanden habe, dann muss ich die Typendeklaration und das Interface Programm in meine DLL mit einbauen und auch in das Aufrufende Programm.
Ansonsten sind die Begriffe "ISharedStringList" und "TSharedStringListWrapper.Wrap" ja gar nicht bekannt.

DGL-luke 11. Aug 2008 23:54

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Du musst das Interface in beiden Modulen deklarieren.
Die Implementation nur im Hauptprogramm.

So als Codebrocken ist es ganz nett von Elvis, aber schlecht zu verstehen wenn man das Konzept von Interfaces nicht so gut kennt.

Smiley 12. Aug 2008 09:49

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nachdem ich versucht habe alles zu verstehen, wie dieses Interface arbeitet und wie es eingebunden werden muss, habe ich folgendes

gemacht.

1. Den Typ ISharedStringList in die DLL eingebaut bei der Typen deklaration.
Delphi-Quellcode:
Unit uCellDB;

Interface
Uses
  FastMM4,
  SysUtils,
  Classes,
  ComObj,
  ADODB,
  DB,
  Variants,
  Windows,
  StdCtrls,
  Dialogs;


// ********************** ISharedStringlist Interface ***************************
type
  ISharedStringList = interface
  ['{3F5E3362-121A-4EC4-B399-9F8CD321FC34}']
    procedure Clear; stdcall;
    function GetCount : Integer; stdcall;

    function Add(const aValue : String) : Integer; stdcall;
    procedure Delete(aIndex : Integer); stdcall;
    procedure Exchange(aIndex1, aIndex2 : Integer); stdcall;
    function IndexOf(const aValue : string) : Integer; stdcall;
    procedure Insert(aIndex : Integer; const aValue : string); stdcall;

    function GetItem(aIndex : Integer) : String; stdcall;
    procedure SetItem(aIndex : Integer; const aValue : String); stdcall;

    property Item[aIndex : Integer] : String
      read GetItem
      write SetItem; default;
  end;

// ********************** TCEll Objekt *****************************************
Type
  TDBCell = Record
    Name: String; // name der Zelle, wird auromatisch aus col und row generiert (A5 bei Zelle(1,5))
    Row: Integer; // Zeile der Zelle
    Col: Integer; // Spalte der Zelel
    FontName: String; // Schriftart
    FontSize: Byte; // Schriftgröße
    FontColor: Word; // Schriftfarbe
    FontStyle: Byte; //normal, Fett, italic, Underline, Strikeout (0,1,2,4,8)
    RecHight: Byte; // Höhe des Zellenrechtecks
    RecWidth: Byte; // Breite des Zellenrechtecks
    RecColor: Word; // Hintergrundfarbe des Zellenrechtecks
    RecLine: Byte; // Umrandungsstriche der Zelle 0=keine, 1=unten,2=links,4=oben,8=rechts,15=alle
    // Kombinationen einfach addieren z.B. Links und rechts ergibt 2+8=10)
    Formula: String; // Formel
    FormulaActive: Boolean; // Wenn True dann ist eine Formel in der Zelle
    Pre: String; //Vorangestellter String vor Data
    Post: String; //Stringanhängsel nach Data
    Format: String; //Datenformat z.B. ###.##
    Datatype: Byte; // Datentyp des Wertes (0=String,1=Integer;2=Float,3=Date)
    Data: String; // Datenwert, abhängig von DataType wird über den Datentyp entschieden
  End;
  //******************************************************************************

Function InitDB: Boolean;
Function DestroyDB: Boolean;
Function CreateDB(DBName: String; DelIfExists: Boolean = False): String;
Function CreateTable(DBName, Tabelle: String): String;
Function OpenDB(DBName, TableName: String): String;
Function OpenTable(TableName: String): String;
Function ReadCell(Var DBCell: TDBCell): String;
Function ReadNextData(var Data: String; var Datatype: Integer): Boolean;
Function ReadNextInfo(var DBCell: TDBCell): Boolean;
Function WriteCell(Var DBCell: TDBCell; WriteInfo: Boolean): String;
Function SelectRowRange(Tabelle: String; RowVon, RowBis: Integer): Boolean;
Function SelectColRange(Tabelle: String; ColVon, ColBis: Integer): Boolean;
Function SelectRowColRange(Tabelle: String; RowVon, RowBis, ColVon, ColBis: Integer): Boolean;
Function SelectNext(DBCell: TDBCell): Boolean;
Function FieldCount: Integer;

Procedure DBListTables(const Liste: ISharedStringList); stdcall; //<------------------------------
Procedure DBCompress(DBName: String);
Procedure DeleteTable(Tabelle:String);

Function SelectDB(DBName: String): String;
Function SelectInfo(Tabelle: String; Row, Col: Integer): Boolean;
Function SelectData(Tabelle: String; Row, Col: Integer): Boolean;

Procedure ReadCellInfo(Var DBCell: TDBCell);
Procedure ReadData(Var DBCell: TDBCell);
Procedure WriteCellInfo(Var DBCell: TDBCell);
Procedure WriteData(Var DBCell: TDBCell);
.
.
.

2. Die Procedure in der DLL angepasst
Delphi-Quellcode:
//******************************************************************************
//***************** Vorhandene Tabellen in der DB anzeigen *********************
//******************************************************************************
Procedure DBListTables(const Liste: ISharedStringlist); stdcall;
Var
  i               : Integer;
  xListe:TStringList;

Begin
 xListe := TStringList(Liste);
 xListe.Clear;
 Con1.GetTableNames(xListe, False);

  i := 0;
  Repeat
    Begin
      If (Pos('Cellinfo', xListe[i])) > 0 Then
        xListe.Delete(i);
      Inc(i);
    End;
  Until xListe.Count = i;

  i := 0;
  Repeat
    Begin
      xListe[i] := Copy(xListe[i], 1, Length(xListe[i]) - 4);
      Inc(i);
    End;
  Until xListe.Count = i;

  for i:= 0 to xListe.Count - 1 do
    Liste.Add(xListe.Strings[i]);

  xListe.Free;
End;
Das hat soweit funktioniert und lies sich compilieren

3. Dann habe ich die erzeugte DLL-Datei in mein TestProgramm Verzeichnis kopiert.

4. Einbinden der Typ ISharedStringList und TSharedStringListWrapper in das Testprogramm.
5. Einbinden der Wrapper Funktionen in das Testprogramm.

Delphi-Quellcode:
Unit uMainReadTest;

Interface

Uses
  FastMM4, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, uCellDB;

Type
  TForm1 = Class(TForm)
    btnStart: TButton;
    lblText: TLabel;
    lblDauer: TLabel;
    lblText1: TLabel;
    lblText1D: TLabel;
    lblFehlerText: TLabel;
    lblFehlerDaten: TLabel;
    btnDropTable: TButton;
    btnListTables: TButton;
    lstTables: TListBox;
    btnReadRowRange: TButton;
    btnReadColRange: TButton;
    btnListFields: TButton;
    btnCreateTable: TButton;
    Procedure btnCreateTableClick(Sender: TObject);
    Procedure btnDropTableClick(Sender: TObject);
    Procedure btnListFieldsClick(Sender: TObject);
    Procedure btnReadColRangeClick(Sender: TObject);
    Procedure btnReadRowRangeClick(Sender: TObject);
    Procedure btnListTablesClick(Sender: TObject);
    Procedure btnStartClick(Sender: TObject);
    Procedure FormShow(Sender: TObject);
    Procedure FormClose(Sender: TObject; Var Action: TCloseAction);
  Private
    { Private-Deklarationen }
  Public
    { Public-Deklarationen }
  End;

type
  ISharedStringList = interface
  ['{3F5E3362-121A-4EC4-B399-9F8CD321FC34}']
    procedure Clear; stdcall;
    function GetCount : Integer; stdcall;

    function Add(const aValue : String) : Integer; stdcall;
    procedure Delete(aIndex : Integer); stdcall;
    procedure Exchange(aIndex1, aIndex2 : Integer); stdcall;
    function IndexOf(const aValue : string) : Integer; stdcall;
    procedure Insert(aIndex : Integer; const aValue : string); stdcall;

    function GetItem(aIndex : Integer) : String; stdcall;
    procedure SetItem(aIndex : Integer; const aValue : String); stdcall;

    property Item[aIndex : Integer] : String
      read GetItem
      write SetItem; default;
  end;

type
  TSharedStringListWrapper = class(TInterfacedObject, ISharedStringList)
  private
    fInnerList: TStrings;
  protected
    function GetCount: Integer; stdcall;

    procedure Clear; stdcall;

    function Add(const aValue: String): Integer; stdcall;
    procedure Delete(aIndex : Integer); stdcall;
    procedure Exchange(aIndex1, aIndex2 : Integer); stdcall;
    function IndexOf(const aValue : String) : Integer; stdcall;
    procedure Insert(aIndex : Integer; const aValue : String); stdcall;

    function GetItem(aIndex: Integer): String; stdcall;
    procedure SetItem(aIndex: Integer; const aValue: String); stdcall;
  public
    property InnerList : TStrings read fInnerList;

    constructor Create(aInnerList : TStrings);

    class function Wrap(aInnerList : TStrings) : ISharedStringList;
  end;
 
Var
  Form1                       : TForm1;
  DBError                    : String;
  ProgPath                   : String;
  DBCell                     : TDBCell;
  Cache                      : Array[1..50, 1..10] Of TDBCell;

Function InitDB: Boolean;
Function DestroyDB: Boolean;
Function CreateDB(DBName: String; DelIfExists: Boolean = False): String;
Function CreateTable(DBName, Tabelle: String): String;
Function OpenDB(DBName, TableName: String): String;
Function OpenTable(TableName: String): String;
Function ReadCell(Var DBCell: TDBCell): String;
Function WriteCell(Var DBCell: TDBCell; WriteInfo: Boolean): String;

Function SelectDB(DBName: String): String;
Function SelectData(Tabelle: String; Row, Col: Integer): Boolean;
Procedure ReadCellInfo(Var DBCell: TDBCell);
Procedure WriteCellInfo(Var DBCell: TDBCell);
Procedure DBCompress(DBName: String);

Procedure DeleteTable(Tabelle: String);
Procedure DBListTables(Const Liste: ISharedStringList); stdcall;
//Procedure DBListTables(var Liste:TObject);

Function SelectRowRange(Tabelle: String; RowVon, RowBis: Integer): Boolean;
Function SelectColRange(Tabelle: String; ColVon, ColBis: Integer): Boolean;
Function ReadNextData(Var Data: String; Var Datatype: Integer): Boolean;
Function ReadNextInfo(Var DBCell: TDBCell): Boolean;
Function FieldCount: Integer;

Implementation

{$R *.dfm}

Const
  DllPath                    = 'CellDB.dll';

Function InitDB: Boolean;
  External DllPath;
Function DestroyDB: Boolean;
  External DllPath;
Function CreateDB(DBName: String; DelIfExists: Boolean = False): String;
  External DllPath;
Function CreateTable(DBName, Tabelle: String): String;
  External DllPath;
Function OpenDB(DBName, TableName: String): String;
  External DllPath;
Function OpenTable(TableName: String): String;
  External DllPath;
Function ReadCell(Var DBCell: TDBCell): String;
  External DllPath;
Function WriteCell(Var DBCell: TDBCell; WriteInfo: Boolean): String;
  External DllPath;
Function SelectDB(DBName: String): String;
  External DllPath;
Function SelectData(Tabelle: String; Row, Col: Integer): Boolean;
  External DllPath;
Procedure ReadCellInfo(Var DBCell: TDBCell);
  External DllPath;
Procedure WriteCellInfo(Var DBCell: TDBCell);
  External DllPath;
Procedure DBCompress(DBName: String);
  External DllPath;
Function SelectRowRange(Tabelle: String; RowVon, RowBis: Integer): Boolean;
  External DllPath;
Function SelectColRange(Tabelle: String; ColVon, ColBis: Integer): Boolean;
  External DllPath;
Procedure DBListTables(Const Liste: ISharedStringlist); stdcall;
//Procedure DBListTables(var Liste:TObject);
External DllPath;
Procedure DeleteTable(Tabelle: String);
  External DllPath;
Function ReadNextData(Var Data: String; Var Datatype: Integer): Boolean;
  External DllPath;
Function ReadNextInfo(Var DBCell: TDBCell): Boolean;
  External DllPath;
Function FieldCount: Integer;
  External DllPath;

{ TSharedStringListWrapper }

function TSharedStringListWrapper.Add(const aValue : String) : Integer;
begin
  result := InnerList.Add(aValue);
end;

procedure TSharedStringListWrapper.Clear;
begin
  InnerList.Clear();
end;

constructor TSharedStringListWrapper.Create(aInnerList : TStrings);
begin
  inherited Create();
  fInnerList := aInnerList;
end;

procedure TSharedStringListWrapper.Delete(aIndex : Integer);
begin
  InnerList.Delete(aIndex);
end;

procedure TSharedStringListWrapper.Exchange(aIndex1, aIndex2 : Integer);
begin
  InnerList.Exchange(aIndex1, aIndex2);
end;

function TSharedStringListWrapper.GetCount : Integer;
begin
  result := InnerList.Count;
end;

function TSharedStringListWrapper.GetItem(aIndex : Integer) : String;
begin
  result := InnerList[aIndex];
end;

function TSharedStringListWrapper.IndexOf(const aValue : String) : Integer;
begin
  result := InnerList.IndexOf(aValue);
end;

procedure TSharedStringListWrapper.Insert(aIndex : Integer;
  const aValue : String);
begin
  InnerList.Insert(aIndex, aValue);
end;

procedure TSharedStringListWrapper.SetItem(aIndex : Integer;
  const aValue : String);
begin
  InnerList[aIndex] := aValue;
end;

class function TSharedStringListWrapper.Wrap(aInnerList : TStrings) : ISharedStringList;
begin
  result := Create(aInnerList);
end;

6. Den Aufruf im Testprogramm angepasst.
Delphi-Quellcode:
//******************************************************************************
//*********************** Tabellen in DB auflisten *****************************
//******************************************************************************
Procedure TForm1.btnListTablesClick(Sender: TObject);

procedure FillTableNames(const aTableNames : TStrings);
begin
  DBListTables(TSharedStringListWrapper.Wrap(aTableNames));
end;

Begin
  FillTableNames(lstTables.Items); // Listbox füllen
End;
Sobald ich nun den Button btnListTables ausführe, kommt die angehängte Fehlermeldung, sobald die DLL angesprochen wird.

Was mache ich hier falsch ?

xaromz 12. Aug 2008 10:18

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Hallo,

Zitat:

Zitat von Smiley
Was mache ich hier falsch ?

das hier:
Delphi-Quellcode:
Procedure DBListTables(const Liste: ISharedStringlist); stdcall;
Var
  i               : Integer;
  xListe:TStringList;

Begin
 xListe := TStringList(Liste); <-------------
 xListe.Clear;
Du bekommst keine TStringList, sondern ein ISharedStringList. Damit musst Du arbeiten. Die beiden (TStringList und ISharedStringList) sind komplett unterschiedlich, und haben im Aufbau keinerlei Gemeinsamkeit.
Nutze einfach die von ISharedStringList zur Verfügung gestellten Methoden.

Gruß
xaromz

Smiley 12. Aug 2008 12:08

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Du meinst ich soll mit einer der TSharedStringListWrapper.xxx die Konvertierung in meine StringList machen.
Da ich aber nicht verstehe, welche Routine welche Umwandlung macht, weiß ich nicht wie die Übergabe aussehen soll.
Muss ich das mit einer Schleife machen oder kann ich eine der Routinen benutzen um das in einem zu übergeben ?

Moment mal, da sehe ich gerade was.
Die Zeile ist ja gar nicht gewollt, das war noch aus den anderen Versuchen.
Das sollte heißen
xListe:=TStringList.Create;

Das mit der Übergabe habe ich doch dann am Ende der Routine gemacht.

Smiley 12. Aug 2008 12:21

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
So funktioniert es:

Delphi-Quellcode:
//******************************************************************************
//***************** Vorhandene Tabellen in der DB anzeigen *********************
//******************************************************************************
Procedure DBListTables(Const Liste: ISharedStringList); Stdcall;
Var
  i                          : Integer;
  xListe                     : TStringList;

Begin
  xListe := TStringList.Create;
  xListe.Clear;
  Con1.GetTableNames(xListe, False);

  i := 0;
  Repeat
    Begin
      If (Pos('Cellinfo', xListe[i])) > 0 Then
        xListe.Delete(i);
      Inc(i);
    End;
  Until xListe.Count = i;

  i := 0;
  Repeat
    Begin
      xListe[i] := Copy(xListe[i], 1, Length(xListe[i]) - 4);
      Inc(i);
    End;
  Until xListe.Count = i;

  For i := 0 To xListe.Count - 1 Do
    Liste.Add(xListe.Strings[i]);

  xListe.Free;
End;

Danke für Eure Hilfe.
Ihr seid große Klasse!

DeddyH 12. Aug 2008 12:28

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Zitat:

Delphi-Quellcode:
i := 0;
  Repeat
    Begin
      If (Pos('Cellinfo', xListe[i])) > 0 Then
        xListe.Delete(i);
      Inc(i);
    End;
  Until xListe.Count = i;

Bist Du sicher, dass das so funktioniert? Ich würde eher eine absteigende for-Schleife verwenden.
Delphi-Quellcode:
for i := xliste.Count - 1 downto 0 do
  Begin
    If (Pos('Cellinfo', xListe[i])) > 0 Then
      xListe.Delete(i);
  End;

Smiley 12. Aug 2008 12:55

Re: TWideStriblist kann nicht zu TStringlist zugewiesen werd
 
Ja, meine Routine funktioniert auch, ich habe sie step für step durchgeprüft und zugesehen was der zähler und die Liste dabei macht.
Dazu muss man wissen, dass in meiner Liste pro Tabbellenname zwei Tabellen vorhanden sind.
Eine mit dem Anhängsel Cellinfo und eine mit dem Anhängsel Data.
z.B. Test1Cellinfo und Test1Data.
Nach außen soll aber nur der Name Test1 erscheinen, daher der ganze Aufwand.

Deine Routine ist aber kürzer und schöner, daher werde ich sie verwenden.
Ich hatte es anfangs auch mit For-Next probiert, aber ohne Downto und das ging natürlich nicht, daher kam ich auf diese anderen Version mit Repeat.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:36 Uhr.

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