Autor Beitrag
Sumara
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 16.10.07 16:59 
Hallöchen!

Ich hab grad ein ganz dringendes Problem mit einem LStrHandle von LabView.
Eine durch LabView generierte DLL soll in Delphi genutzt werden.
Eine Procedure verwendet den Parameter: LStrHandle * Parameter

Dieser ist wie folgt definiert:
ausblenden Quelltext
1:
2:
3:
4:
typedef struct {
  int32  cnt;    /* number of bytes that follow */
  uChar  str[1];    /* cnt bytes */
} LStr, *LStrPtr, **LStrHandle;


Leider bin ich in C++ überhaupt nicht fit! :cry:

Bisher hab ichs mit folgenden typen versucht:
ausblenden Delphi-Quelltext
1:
type LStr=Array of Byte					

Dieser Typ funktioniert bei einer anderen Procedur dieser DLL, die ebenfalls LStrHandle * Parameter als Übergabeparameter hat. (Nach Aussage des Entwicklers der C++ DLL heißt das aber noch lange nicht, dass diese Definition immer funktioniert)

Desweiteren hab ichs mit PChar und PAnsiChar probiert, bisher erfolglos.

Ich hoffe, dass mir jemand von Euch eine gute Delphi-Übersetzung für diesen Datentyp geben kann!!!

Vielen Dank für die Hilfe,

Susanne.
Aya
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1964
Erhaltene Danke: 15

MacOSX 10.6.7
Xcode / C++
BeitragVerfasst: Di 16.10.07 19:08 
Hi,

auch wenn ich nicht wirklich ein C++ genie bin und da auch immer mal wieder gerne in fallen tappe, aber ich würde es so interpretieren:


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  LStr = packed record
    cnt: Integer;
    str: Char;
  end;
  LStrPtr: ^LStr;
  LStrHandle: ^LStrPtr;


wobei ich nicht verstehe warum das "str" ein Array ist... ausser es wird dann einfach ein Array an der stelle zurückgegeben und nur der Pointer gesetzt, dann müßte es denke ich so aussehen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  TStr = Array[0..0of Char;
  LStr = packed record
    cnt: Integer;
    str: ^TStr;
  end;
  LStrPtr: ^LStr;
  LStrHandle: ^LStrPtr;


Drauf zugreifen kannst du dann einfach wie bei einem normalen Array, also z.B.:

ausblenden Delphi-Quelltext
1:
2:
for i:=0 to myLStr.cnt - 1 do
  DoSomethingWith(myLStr.str[i]);


Aya~

_________________
Aya
I aim for my endless dreams and I know they will come true!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 17.10.07 11:01 
UChar in C\C++ ist Byte in Delphi., ansonsten sollte das soweit stimmen ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 17.10.07 11:42 
Ganz große Vorsicht mit solchen C/C++ Typdeklarationen!
Das was bei einem solchen Typ zurück geliefert werden kann, kann 5 Byte aber auch 5000 Byte, oder viel mehr sein.
Relevant ist, das als erstes bei einem solchen Typ immer die Größe des Datensatzes geliefert wird und im Anschluss eine variable Menge an Daten, mindestens aber ein Byte.

ausblenden Quelltext
1:
2:
3:
4:
typedef struct {
  int32  cnt;    /* number of bytes that follow */
  uChar  str[1];    /* cnt bytes */
} LStr, *LStrPtr, **LStrHandle;

Zusammen kommt man so : int32 = 4 byte + uChar = 1 Byte -> 5 Byte.

in delphi würde sowas so aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  LStr = packed record  
    cnt: Integer; // die länge des folgenden Arrays
    str: Array[0..0of Char; // die eigentlichen daten, mindestens ein byte 
  end;
  // dem stimme ich zu, du solltest eh an dieser stelle nur mit zeigern arbeiten
  LStrPtr: ^LStr;
  LStrHandle: ^LStrPtr;

Ob "packed" oder nicht ist wieder so eine Frage. Das hängt von der Datenausrichtung in der DLL ab. Geh einfach mal davon aus das es so passt.

Die Deklaration
ausblenden Delphi-Quelltext
1:
str: Array[0..0of Char;					

sieht zwar komisch aus, ermöglicht es aber einfach auf die Daten in str zu zugreifen.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Sumara Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 17.10.07 12:56 
Titel: Problem gelöst
Mittlerweile hab ich mir aus verschiedenen Antworten (war auch noch in einem anderen Forum) das zusammen gebastelt.
Das passt ja auch zu dem was SinSpin sagt.
Es klappt, allerdings muss bei der übergabe einer var vom Typ LSTR, wenn cnt auf 0 ist. Ich versteh's ehrlich gesagt nicht so ganz! Hauptsache es geht.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type
  TStr = Array[0..0of Char;
  LStr = packed record
    cnt: Integer;
    str: ^TStr;
  end;


Das mit den Zeigern hab ich jetzt nicht, weil ich's nicht zum laufen gebracht hab.

Ich übergebe jetzt an die Funktion, die den Parameter: LStrHandle * Parameter erwartet:
ausblenden Delphi-Quelltext
1:
Procedure(var param:LStr)					


Habt ihr vielleicht noch ein Beispiel, wie's mit den Zeigern aussehen müsste?

Danke.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mi 17.10.07 13:21 
Das mit dem Zeiger ist Falsch. Denn ein Zeiger würde einen dynamischem Array gleich kommen. Was in diesem Falle aber ja nicht der Fall ist, da die Daten nun mal direkt mit in dem Record stecken. Solche Records kannst du aber auch nicht normal benutzen die müssen grundsätzlich immer über GetMem erstellt werden. In C/C++ auch, wenn ich mich nicht vertue. Wenn man sie selbst Erstellen muss.

Im Übrigen solltest du die Bereichprüfung dann bei der Benutzung aussstellen. Aber das mit dem Array[1..1] ist mehr oder weniger der einzig funktionierende Weg.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 17.10.07 14:12 
user profile iconLossy eX hat folgendes geschrieben:
Das mit dem Zeiger ist Falsch. Denn ein Zeiger würde einen dynamischem Array gleich kommen. Was in diesem Falle aber ja nicht der Fall ist, da die Daten nun mal direkt mit in dem Record stecken. Solche Records kannst du aber auch nicht normal benutzen die müssen grundsätzlich immer über GetMem erstellt werden. In C/C++ auch, wenn ich mich nicht vertue. Wenn man sie selbst Erstellen muss.

Im Übrigen solltest du die Bereichprüfung dann bei der Benutzung aussstellen. Aber das mit dem Array[1..1] ist mehr oder weniger der einzig funktionierende Weg.


Ich schließe mich deiner Meinung an. So wie ich den Record deklariert habe müsste es gehen, wenn man nicht eine Variable sondern einen Zeiger auf ein Stück Speicher des Types übergeben wird.
Nur ist ja in diesem Fall das Interessante das man nichts übergibt, sondern was bekommt. Das heißt der Speicher wird in der Procedure angelegt und die Adresse an den Zeiger übergeben.
Was ja eigentlich bedeutet das man einfach nur einen Zeiger auf diesen Typ übergeben bräuchte.

-- habe ich schonmal erwähnt das ich C/C++ nicht für den ganz großen Wurf halte? --

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
type
  LStr = packed record  
    cnt: Integer; // die länge des folgenden Arrays
    str: Array[0..0of Char; // die eigentlichen daten, mindestens ein byte 
  end;
  // dem stimme ich zu, du solltest eh an dieser stelle nur mit zeigern arbeiten
  LStrPtr: ^LStr;
  LStrHandle: ^LStrPtr;

procedure DoIt;
var
  myPtrStr: LStrPtr;
  l: integer;

begin
  GetMem(myPtrStr, SizeOf(LStrPtr)); // speicher anlegen
  Initialize(myPtrStr, SizeOf(LStrPtr)); // mit nullen füllem

  DeineProc(myPtrStr^); // der aufruf wo dur die daten bekommst

  {$R-} // bereichsprüfung zum auslesen auschalten
  for l := 0 to myPtrStr^.cnt-1 do
   // hier dir daten in myPtrStr^.str[l] verarbeiten 
  {$R+}
  FreeMem(myPtrStr); // speicher wieder freigeben (wie groß er dann auch immer sein mag)
end;

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 18.10.07 12:59 
Alternativ sollte das auch so gehen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  LStr = packed record  
    cnt: Integer; // die länge des folgenden Arrays
    str: record end// Datenpuffer beliebiger Größe
  end;
  // dem stimme ich zu, du solltest eh an dieser stelle nur mit zeigern arbeiten
  LStrPtr: ^LStr;
  LStrHandle: ^LStrPtr;


Wichtig bei dieser Definition ist, dass die C-Semantik übernommen wird, Delphi aber als größe nur die ersten 4 Byte liefert. Von daher vorsicht in DElohi mit dieser Variante.

Der Zugriff auf die Daten erfolgt mit Move.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.