Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Get(anyPointer) Verständnisfrage (https://www.delphipraxis.net/174567-get-anypointer-verstaendnisfrage.html)

Nintendo 29. Apr 2013 14:32

Get(anyPointer) Verständnisfrage
 
Hallo,

ich experimentiere grad mit der Übergabe von Zeigern anstele von VAR Parametern und frage mich, wie ich das folgende erreichen kann:

Delphi-Quellcode:
procedure GetThis(pp: Pointer);
begin
  pp := value;
end;
Wenn ich die Prozedur selber definieren kann, könnte ich auch das hier schreiben:

Delphi-Quellcode:
procedure GetThis(var pp: Pointer);
begin
  pp := value;
end;
Wenn ich aber ein Interface nutze, sieht die Sache schon anders aus.

Wie erreiche ich dann, das auch die obere Funktion den Wert übergibt.

Gibt es da vielleicht eine Compiler-Option? Wenn ja, welche?

Hier ist noch ein Testbeispiel zur Verdeutlichung, was ich meine:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    Button1: TButton;
    Label2: TLabel;
    Label3: TLabel;
    lblShowString: TLabel;
    lblShowPChar: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FPChar: PChar;
    FString: String;
  public
    { Public-Deklarationen }
    procedure GetPChar(this: PChar);
    procedure GetString(this: String);
    procedure GetStringByReference(var this: String);
    procedure GetPCharByReference(var this: PChar);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var PCh: PChar; Str: String;
begin
  FString := Edit1.Text;
  FPChar := PChar(FString);
  GetStringByReference(Str);
  lblShowString.Caption := Str;
  GetPCharByReference(PCh);
  lblShowPChar.Caption := StrPas(PCh);
end;

procedure TForm1.GetPChar(this: PChar);
begin
  this := FPChar;
end;

procedure TForm1.GetPCharByReference(var this: PChar);
begin
  this := FPChar;
end;

procedure TForm1.GetString(this: String);
begin
  this := FString;
end;

procedure TForm1.GetStringByReference(var this: String);
begin
  this := FString;
end;

end.
Wenn ich hier GetStringByReference und GetPCharByReference aufrufe, dann klappt die Parameterübergabe.

Wenn ich jedoch die anderen beiden Prozeduren verwende, dann gibt

GetString() gar nichts aus, Wert bleibt komplett unverändert, wie ich das auch bei CallByValue erwarte.

GetPChar() gibt Datenmüll aus.

Wie kann ich nun Pointer in der Form wie in GetPChar() erhalten?

Wie gesagt, wenn ich ein Interface verwenden will/muss, dann kann ich die Deklaration nicht für mich passend ändern, das geht nur bei komplett eigener Defintion.

Neutral General 29. Apr 2013 14:51

AW: Get(anyPointer) Verständnisfrage
 
Hallo,

Deine Erklärung ist etwas verwirrend aber folgendes funktioniert gleich:

Delphi-Quellcode:
procedure Irgendwas1(var S: String);
begin
  S := FString;
end;

procedure Irgendwas2(S: PString); // oder statt PString einfach ^String
begin
  S^ := FString;
end;

procedure TForm1.Button1Click(Sender: TObject);
var test: String;
begin
  Irgendwas1(test);
  Caption := test;
  Irgendwas2(@test);
  Caption := test;
end;

uligerhardt 29. Apr 2013 15:04

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von Neutral General (Beitrag 1213404)
Deine Erklärung ist etwas verwirrend

Ja, etwas. :mrgreen:

Zitat:

Zitat von Neutral General (Beitrag 1213404)
Delphi-Quellcode:
procedure Irgendwas2(S: PString); // oder statt PString einfach ^String

Bei
Delphi-Quellcode:
S: ^String
nörgelt der Compiler. Man braucht schon einen benannten Typen.

DeddyH 29. Apr 2013 15:13

AW: Get(anyPointer) Verständnisfrage
 
Und man sollte IIRC auch sicherstellen, dass der reservierte Speicherplatz, auf den der übergebene Pointer zeigt, ausreichend dimensioniert wurde, bevor man hineinschreibt.

p80286 29. Apr 2013 15:26

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von Nintendo (Beitrag 1213400)
Wie kann ich nun Pointer in der Form wie in GetPChar() erhalten?

Was bitte willst Du (erreichen)?

Delphi-Quellcode:
procedure irgendwas(wert:integer);
begin wert:=66; end;

...
wert:=9;
irgendwas(wert);
// Hier ist wert immer noch 9 !!!!!
Ohne var werden keine Daten/werte aus der procedure zurück gegeben!
Ausnahme:

Delphi-Quellcode:
procedure irgendwas(pw:pinteger);
begin pw^:=100; end;

...
wert:=45;
irgendwas(@(wert);
// ab hier ist wert=100;
weil Du eine Adresse übergeben hast und an diese Adresse Daten geschrieben wurden. Die Adresse ist daran aber nicht direkt beteiligt.

Gruß
K-H

Furtbichler 29. Apr 2013 19:21

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von Nintendo (Beitrag 1213400)
Wie gesagt, wenn ich ein Interface verwenden will/muss, dann kann ich die Deklaration nicht für mich passend ändern, das geht nur bei komplett eigener Defintion.

Ich frage mich gerade, was Du erreichen willst. Wenn die Interfacemethode ein Call-By-Value definiert, dann hat sich der Autor schon etwas dabei gedacht. Damit musst Du leben. Dazu sind Interfaces da. Der Autor gibt die Verwendung vor.

:gruebel:

Nintendo 29. Apr 2013 20:01

AW: Get(anyPointer) Verständnisfrage
 
Danke für Eure Mithilfe aber

bei mir klappt es noch nicht.


Delphi-Quellcode:
unit UPChar;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Button1: TButton;
    Label2: TLabel;
    lbOut: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FValue: String;
  public
    { Public-Deklarationen }
    procedure GetValue(p: PChar);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var pc: PChar;
begin
  FValue := Edit1.Text;
  GetValue(@pc);
  lbOut.Caption := StrPas(pc);
  //Freemem(pc, Length(FValue) + 8 + 1);
  //Hier ungültige Zeifer Operation
  //wer slso gibt am Ende den Speicher wieder frei???
end;

procedure TForm1.GetValue(p: PChar);
begin
  getmem(p, Length(FValue) + 8 + 1);
  p := PChar(FValue);
end;

end.
Ich erhalte immer noch Datenmüll als Rückgabe.

@Furtbichler:

Wenn ich eine eigene Implementation wählen kann, übergebe ich sowas als call by reference.

Wenn ich aber auf ein Interface zugreifen will/muss und der das Interface festgelegt hat hat eine Get Methode mit dem Übergabeparameter call by value definiert, dann habe ich leider keine Wahl, dann muss die Wertübergaben eben damit funktionieren.

Ich habe dem PChar Parameter jetzt Speicher zugewiesen und dann erst den Wert übergeben. Dennoch erhalte ich Datenmüll.

Ich hab mir mal interessehalber das OpenTools API angeschaut

Zum Beispiel hier:

Delphi-Quellcode:
  TIEditReader = class(TInterface)
  public
    function GetText(Position: Longint; Buffer: PChar; Count: Longint): Longint;
      virtual; stdcall; abstract;
  end;
wollte ich dieses Interface verwenden, hätte ich keine Wahl. Für mich selber würde ich natürlich var Buffer: PChar definieren. Aber bei einem vorgegebenen Interface???

Deshalb will ich auch hier die Parameterübergabe beherrschen. Get heißt für mich, Wert holen. Also muss das doch irgendwie gehen, sobald es sich bei dem Parameter um einen Zeiger handelt. Aber wie.

Gibt es vielleicht eine Compileroption, die sagt, in diesem Fall keinen Stack FRame anlegen?

Oder gibt es eine andere Lösung?

Wie also kann ich aus der Methode GetValue() den PChar Wert erhalten, analog zur oben aufgeführten Interfacefunktion, die über den Buffer ihren Wert übergibt, obwohl Buffer dort nicht als VAR Parameter definiert ist.

Speicher ist zugewiesen. Klappt auch dann bei mir noch nicht mit der Übergabe, wenn ich entweder sowohl innerhalb der Methode als auch in Button1Click Speicher zuweise und auch nicht, wenn ich das nur in Button1Click mache.

Wenn also Compileroption, welche? (Delphi 7 oder 2006)

Furtbichler 29. Apr 2013 20:12

AW: Get(anyPointer) Verständnisfrage
 
Wieso? Der Pointer (Buffer) wird nicht verändert. Er enhält eine Adresse, an der mindestens 'Count' Bytes reserviert sind. So. Du übergibst die Adresse und hinterher steht an der Adresse etwas drin. Die Adresse selbst wird nicht verändert. Also wird diese auch als 'Call by Value' übergeben. Wenn Du das nicht machen würdest, hast Du etwas nicht richtig verstanden.
So, nun zu deinem Code: Der Aufrufer reserviert Speicher, der von der aufgerufenen Methode gefüllt wird.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var pc: PChar;
begin
   FValue := Edit1.Text;
   getmem(pc, Length(FValue) + 8 + 1); // DER AUFRUFER RESERVIERT DEN SPEICHER
   GetValue(pc);
   lbOut.Caption := StrPas(pc);
...
  FreeMem(pc, Length(FValue) + 8 + 1); // UND GIBT IHN WIEDER FREI ("Wer Müll macht, muss aufräumen")
end;

procedure TForm1.GetValue(p: PChar);
begin
   Move (@FValue[1],p, SizeOf(FValue[0]) * Length(FValue)); // Verschiebe Bytes (1 Zeichen könnte auch 2 Bytes lang sein(
end;

Nintendo 29. Apr 2013 20:41

AW: Get(anyPointer) Verständnisfrage
 
Danke! Muss mich aber erst mal mit Deiem Code beschäftigen.

Zitat:

Zitat von Furtbichler (Beitrag 1213454)
.... Also wird diese auch als 'Call by Value' übergeben. Wenn Du das nicht machen würdest, hast Du etwas nicht richtig verstanden.

Ja, so sieht es wohl aus. Genau deshalb beschäftige ich mich auch mit der Problematik. Ich habe wirklich noch nicht verstanden, warum in diesem Fall Call by Value übergeben wird.

Ich will doch gerade den Inhalt dieses Puffers lesen, sowohl mit der Methode GetValue wie es auch die IDE mit der Interface Methode TIEditReader macht.

Wie ich Call by reference verstanden habe, wird doch dort der Wert an die Adresse übergeben, die mit dem VAR Parameter angegeben ist.

Ich kann momentan zur obigen Übergabemethode keinen grundsätzlichen Unterschied erkennen, und richtig, ich habe noch nicht verstanden, warum im von mir betrachteten Fall call by value übergeben wird. Sonst übergebe ich call by value doch nur, wenn ich Werte an die Methode zur internen Verwendung übergeben will. In meinem Fall aber will ich den Wert von der Methode haben.

Nintendo 30. Apr 2013 09:22

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von p80286 (Beitrag 1213415)
Zitat:

Zitat von Nintendo (Beitrag 1213400)
Wie kann ich nun Pointer in der Form wie in GetPChar() erhalten?

Was bitte willst Du (erreichen)?

Delphi-Quellcode:
procedure irgendwas(wert:integer);
begin wert:=66; end;

...
wert:=9;
irgendwas(wert);
// Hier ist wert immer noch 9 !!!!!
Ohne var werden keine Daten/werte aus der procedure zurück gegeben!
Ausnahme:

Delphi-Quellcode:
procedure irgendwas(pw:pinteger);
begin pw^:=100; end;

...
wert:=45;
irgendwas(@(wert);
// ab hier ist wert=100;
weil Du eine Adresse übergeben hast und an diese Adresse Daten geschrieben wurden. Die Adresse ist daran aber nicht direkt beteiligt.

Gruß
K-H

Bis hierher ist mir die Sache klar.

Ohne var werden keine Daten/werte aus der procedure zurück gegeben!

Dann würde es umgekehrt gar nicht funktionieren, nämlich so hier:

procedure irgendwas(aWert: PChar);
begin
aWert := PChar(AnyString);
end;

Dieses Ergebnis, das

igendwas(@Wert) dann nicht funktioniert, erhalte ich auch.


Nun aber habe ich in den ToolsAPI die schon geannte Funktion GetText(Position: Integer, Buffer: PChar; ...

gefunden und dort scheint es anders zu sein. Zumindest geh ich davon aus, das Getxxx einen Wert holt, wie

GetText(1, @wert, 15)

mit

... GetText(Pos: Integer; Buffer: PChar; count: Integer)
begin
Buffer := PChar(AnyString);
end;

Wenn ich da falsch liege, müsste dann diese Funktion nicht Putxxx() doer Setxxx() heißen?

Dieser Punkt ist es, der mich verwirrt. Oder es gint tatsächlich einen Weg, so einen Wert an Buffer zzu übergeben, nur wie, wenn meine Annahme richtig ist.

Wie kommuniziert Delphi unter Verwendung dieser Funktion GetText()?

p80286 30. Apr 2013 09:48

AW: Get(anyPointer) Verständnisfrage
 
Ich denke Du solltest Dir noch einmal genau überlegen was du (fragen) willst.
Aus den verschiedenen Informationshäppchen (toolsAPI Gettext) habe ich dies herausdestilliert
Delphi-Quellcode:
 IOTAEditReader = interface(IUnknown)
    ['{26EB0E4F-F97B-11D1-AB27-00C04FB16FB3}']
    function GetText(Position: Longint; Buffer: PChar; Count: Longint): Longint;
  end;
Wenn es hierum geht, was daran ist unverständlich?

Was den Namen einer Funktion/Prozedur angeht, Du kannst ihr Namen geben wie es Dir einfällt("Pukkelmon","hh_136gtz_99","Bundesinnenmi nister"). Es entspricht aber gutem Stil, wenn der Name auch die Funktionalität wiederspiegelt.

Gruß
K-H

Nintendo 2. Mai 2013 12:36

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von p80286 (Beitrag 1213502)
Ich denke Du solltest Dir noch einmal genau überlegen was du (fragen) willst.
Aus den verschiedenen Informationshäppchen (toolsAPI Gettext) habe ich dies herausdestilliert
Delphi-Quellcode:
 IOTAEditReader = interface(IUnknown)
    ['{26EB0E4F-F97B-11D1-AB27-00C04FB16FB3}']
    function GetText(Position: Longint; Buffer: PChar; Count: Longint): Longint;
  end;
Wenn es hierum geht, was daran ist unverständlich?

Heißt das, das diese Funktion trotz ihres Namens einen Text in der Variablen Buffer erwartet, den die Fuktion dann an die an das Interface angeschlossene Software übergibt?

Andersherum klappt es nämlich nicht. Ich kann also nicht, wie ich bei dem Namen GET erwartet hätte einen Text aus der angeschlossenen Software über die Variable Buffer auslesen.

Zitat:

Zitat von p80286 (Beitrag 1213502)
Was den Namen einer Funktion/Prozedur angeht, Du kannst ihr Namen geben wie es Dir einfällt("Pukkelmon","hh_136gtz_99","Bundesinnenmi nister").

Bei dieser angenommenen Namensgebung würde ich allerdings erwarten, das ich von der Routine 3 Werte erhalte:

- Pukkelmon, das Computespiel (oder eine Kinderserie im Fernsehen?)
- eine Softwarebibliothek mit dem Namen "hh_136gtz_99"
- die Webseite des Bundesinnenministers

Da hier kein Routinenname angegeben ist, könnte mir letzterer Parameter natürlich auch den Namen des aktuell amtierenden Bundesinnenministers anzeigen oder mich zur Webseite des Bundesinnenministeriums leiten.

Zitat:

Zitat von p80286 (Beitrag 1213502)
Es entspricht aber gutem Stil, wenn der Name auch die Funktionalität wiederspiegelt.

Gruß
K-H

Konsens! :thumb:


Zurück zu meiner Frage: Leider weiß ich dummerweise nicht,wie ich hier richtig fragen soll. Ich kenne nur mein Problem und suche dafür eine Lösung.

Diese kann auch darin bestehen, das der Name der fraglichen Funktion, ja es geht um die obige Funktion, das dieser Name falsch gewählt wurde von Borland/Codegaer/Embarcadero, da diese Funktion nicht, wie ich angenommen habe, einen Text aus einem an das OTA angeschlossene IDE Plugin ausliest, sondern einen Text, der an die Variable Buffer übergeben und dann der Funktion übergeben wird, an das Plugin sendet.

Also, in welcher Richtung erfolgt hier die Übertragung des PChar-Strings?

Sendet diese Funktion den Text, den ich in Buffer übergebe oder liest die Funktion einen Text, den sie dann an Buffer übergibt, damit ich ihn verwenden kann?

DeddyH 2. Mai 2013 12:49

AW: Get(anyPointer) Verständnisfrage
 
Ich kenne die ToolsAPI zwar nicht auswendig, aber anhand der Parameter ist zu vermuten, dass das wie in Unmengen Win32-API-Funktionen auch gedacht ist: man reserviert Speicher und übergibt dessen Adresse dann samt der Angabe der Datengröße an die Routine, welche ihn dann mit Daten befüllt.

[edit] Beispielhaft sei hier mal GetWindowsDirectory genannt. [/edit]

Nintendo 2. Mai 2013 13:55

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von DeddyH (Beitrag 1213815)
Ich kenne die ToolsAPI zwar nicht auswendig, aber anhand der Parameter ist zu vermuten, dass das wie in Unmengen Win32-API-Funktionen auch gedacht ist: man reserviert Speicher und übergibt dessen Adresse dann samt der Angabe der Datengröße an die Routine, welche ihn dann mit Daten befüllt.

[edit] Beispielhaft sei hier mal GetWindowsDirectory genannt. [/edit]

Schon richtig, allerdings

Delphi-Quellcode:
UINT WINAPI GetWindowsDirectory(
  _Out_  LPTSTR lpBuffer,
  _In_   UINT uSize
);
gibt es da die Direktive _out die es ja in DElphi neben var auch gibt. Out bzw. Var fehlt aber in der Funktion GetText() oben.

und eben das verwirrt mich.

DeddyH 2. Mai 2013 14:16

AW: Get(anyPointer) Verständnisfrage
 
Die Übergabe eines Pointer-Parameters als Var-Parameter (also interne Verwendung eines weiteren Pointers darauf) macht in den wenigsten Fällen Sinn, und PChar ist nun einmal ein Pointer-Typ.

[edit] Ich habe gerade mal ein wenig gestöbert, der Kernsatz von MS zu [in] und [out] scheint mir zu sein:
Zitat:

The [in] and [out] attributes specify the direction in which the parameters are passed.
[/edit]

Nintendo 2. Mai 2013 18:36

AW: Get(anyPointer) Verständnisfrage
 
Zitat:

Zitat von DeddyH (Beitrag 1213837)
Die Übergabe eines Pointer-Parameters als Var-Parameter (also interne Verwendung eines weiteren Pointers darauf) macht in den wenigsten Fällen Sinn, und PChar ist nun einmal ein Pointer-Typ.

[edit] Ich habe gerade mal ein wenig gestöbert, der Kernsatz von MS zu [in] und [out] scheint mir zu sein:
Zitat:

The [in] and [out] attributes specify the direction in which the parameters are passed.
[/edit]

Das heißt dann also, das die GetText() Funktion aus dem ToolaAPI trotz ihres Namens einen String an Buffer übergibt?

Delphi-Quellcode:
var myText: PChar;

procedure SendText(Thisone: PChar);
begin
  GetText(1, THisOne, StrLen(ThisOne));
end;

begin
  myText := 'Das hier';
  SendText(myText);
end.
Denn die fragliche GetText() Funktion hat nämlich keinen Var bzw. Out Parameter. Also nicht

Delphi-Quellcode:
function GetText(Position: Integer; out Buffer: PChar; ...)

sondern

Delphi-Quellcode:
function GetText(Position: Integer; Buffer: PChar;...
Das hieße also dann das ich den Text nur senden, aber nicht von irgendwoher lesen kann?

.

Furtbichler 2. Mai 2013 18:54

AW: Get(anyPointer) Verständnisfrage
 
'_OUT_' (C) und
Delphi-Quellcode:
out
(Delphi) haben *nichts* miteinander zu tun.

Mann, und so schwer kann das doch nicht sein: Ich will Schweinswürstel essen. Du hast welche.

1. Ich nehme mir einen Schuhkarton (=Adresse), und sorge dafür, das dort 10 leckere Schweinswürste reinpassen (=alloziiere Speicher)
2. Ich gebe Dir den Schuhkarton und Du legst da deine leckeren Schweinswürste rein.
3. Du gibst mir den Schuhkarton zurück
4. Ich grille die Würste und esse sie auf.
5. Den Schuhkarton brauche ich nun nicht mehr und daher schmeisse ich ihn weg (=Speicher freigeben)

Preisfrage: Ist der Schuhkarton verändert worden?
[x] Nein, der Karton ist der Gleiche, nur der Inhalt wurde verändert
[ ] Ja, der Karton wurde verändert. Es ist ja nun kein Schuhkarton mehr, sondern ein Leckerschweinswürstelkarton :wall:

PS: Warum ich auf Schweinswürstel komme? Weil ich gerade welche gemacht habe!

DeddyH 2. Mai 2013 18:54

AW: Get(anyPointer) Verständnisfrage
 
Du musst Dir darüber im Klaren werden, was die Nutzdaten sind und was die Zeiger darauf. Die aufrufende Routine reserviert den zu befüllenden Speicher und gibt dessen Zeiger sowie die größe des reservierten Speichers an die Funktion weiter. Diese schreibt ihre Daten dann an diese Adresse. Stell Dir das so vor, als würde ich bei Dir 4 Kisten Bier bestellen und Dir zum Verladen meinen Autoschlüssel geben.
Delphi-Quellcode:
procedure VerladeBier(Ziel: PKofferraum; Anzahl: integer);
begin
  VerladeKisten(Ziel^, Anzahl);
end;
Ziel ist also mein Kofferraumschlüssel und Anzahl die Menge der zu verladenden Kisten. Dabei habe ich als Auftraggeber dafür zu sorgen, dass die bestellte Menge auch tatsächlich in den Kofferraum, zu dem der übergebene Schlüssel gehört, hineinpasst.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:24 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