Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Pointer - ein schwarzes Tuch (https://www.delphipraxis.net/129150-pointer-ein-schwarzes-tuch.html)

gmc616 13. Feb 2009 13:05


Pointer - ein schwarzes Tuch
 
Hallo DP,

ich möchte mich in die API-Programmierung einarbeiten, hatte nur bisher noch keine sinnvolle Idee, was ich als "Übungsaufaufgabe" probieren könnte. Nun habe ich aber ein Thema: RAPI (Remote-API)

Dafür habe ich mir eine RAPI.pas von Pegasus Remote API besorgt.
Jetzt wollte ich die function CeFindAllDatabases rufen, die erwartet aber als vierten Parameter einen "Berg" von Pointern.

Mit Pointern habe ich schon immer Probleme.
Irgendwie ist mir die ganze Sache zu hoch. Ich hab mir schon eine ganze Reihe vom Pointer-Tuts durchgelesen - aktuell habe ich wieder das Tut von Manuel Pöter vor mir - ich kapiere es einfach nicht. Die Beispiele die dort aufgeführt werden, sind alle nach zu vollziehen - mehr oder weniger - aber an der praktischen Umsetzung hapert's bei mir.
Deshalb hab ich in den letzten Jahren, in alle Sprachen mit denen ich zu tun hatte, einen großen Bogen um Pointer gemacht. Ich wills aber verstehen, denn schließlich soll das Arbeiten mit Pointer relativ einfach sein, wenn man's erst mal kapiert hat.


Mein Problem deklariert sich so:
Delphi-Quellcode:
[...]
TCeDBaseInfo = record
      dwFlags:DWORD;
      szDbaseName:array [0..CeDB_MAXDBASENAMELEN-1] of WCHAR  ;
      dwDbaseType:DWORD;
      wNumRecords:WORD;
      wNumSortOrder:WORD;
      dwSize:DWORD;
      ftLastModified:TFileTime;
      rgSortSpecs:array [0..CeDB_MAXSORTORDER-1] of TSortOrderSpec;
end;

TCeDB_File_Data = record
      OidDb:CeOID ;
      DbInfo:TCeDBaseInfo ;
end;
PCeDB_File_Data=^TCeDB_File_Data;

TCeDB_File_Data_Array = array [0..MaxInt div sizeof(TCeDB_File_Data)-1] of TCeDB_File_Data;
PCeDB_File_Data_Array = ^TCeDB_File_Data_Array;

[...]

function CeFindAllDatabases(dwDbaseType:DWORD; wFlags:WORD; var cFindData:DWORD; var ppFindData:PCeDB_File_Data_Array):BOOL ;
Der Aufruf von CeFindAllDatabases funktioniert. Also scheinen ja Datenbank vorhanden zu sein, aber wie komme ich z.B. an den Namen (CeDBaseInfo.szDbaseName) rann ?

Könnt ihr mir Zeigen wie ich das bewerkstelligen muß.

1000 Dank schon mal im Voraus.

gmc

[edit=SirThornberry]Titel korrigiert - Mfg, SirThornberry[/edit]

Luckie 13. Feb 2009 13:14

Re: Pionter - ein schwarzes Tuch
 
Du bist jetzt eigentlich schon lange genug dabei, dass du wissen müsstest, dass man für seinen Beitrag einen aussagekräftigen Titel wählen sollte. :roll:

gmc616 13. Feb 2009 13:54

Re: Pionter - ein schwarzes Tuch
 
Das finde ich Schade, dass du meinst, mein Hilferuf bedürfe einen noch genaueren Titel.

Ich habe den Post ins Board API-Programmierung geschrieben.
Der Titel "Pointer" besagt, es hier um Pointer geht wird.
Vielleicht kennst du die Redewendung "Ein schwarzes Tuch" nicht, welche eigentlich besagt "Depp, der nix kapiert".

Ich denke damit habe ich mein Problem grob rum rissen.

Ich hätte nur gern gezeigt, an einem konkreten Beispiel, wie man mit Pointer arbeitet, denn alle Tuts die ich lesen habe, helfen mir nicht weiter. Wahrscheinlich bin ich zu blöd dafür. :stupid:

Das es in meinem Post um RAPI, speziell CeFindAllDatabases, geht, ist eigentlich nur zweitrangig. Wäre aber schön genau diese Problem erklärt zu bekommen.

Vor diesem Hintergrund habe ich den Titel so gewählt.

Ich glaube mir hilft kein weiteres Tut weiter, noch ein Link aufs mdsn. Davon hab ich genug.
Nur eine Erklärung im Umgang mit Pointern, speziell an diesem Beispiel, wäre hilfreich.

Okay, da du ein Moderator über dieses Board bist, möchte ich dich bitten, meinem Thema einen angemessenen Titel zu geben, denn mir fällt i.M. keiner ein. :wink:

Danke.

Luckie 13. Feb 2009 13:59

Re: Pionter - ein schwarzes Tuch
 
Und wie wäre es mit: "Verständsnisproblem bezüglich Pointern"?

mr_emre_d 13. Feb 2009 14:04

Re: Pionter - ein schwarzes Tuch
 
Du musst es dereferenzieren

Ein ganz simples Pointer HowTo
Delphi-Quellcode:
{
Grundlegende Sachen zu Pointern:
  o Pointer belegen immer 4 Bytes
  o Pointer beinhalten die Adresse zur "hingepointetten"(hingezeigten) Variable und natürlich die eigene Adresse (sowie alle anderen Typen)
  o Es gibt 2 verschiedene Pointertypen:
    a) typisierte Pointer (bsp "PInteger") // so nenne ich sie mal .. da gibts sicher andere Begriffe dafür - ist mir aber jetzt wurscht
    b) untypisierte Pointer ("Pointer")
  o a Pointer können direkt dereferenziert werden wohingegen
  o b Pointer gecastet werden müssen
}
// -- A.)
var
  X: Integer;
  P: PInteger; // Pointer auf einen Integer !
...
// Adressen sind zum Demonstrationszweck frei gewählt !

X := 12345; // Adresse von X - $00ABCDEF; Wert von X = 12345
P := @X;    // Adresse von P - $00FEEFEE; Wert von P = $00ABCDEF

// jetzt zeigt unser Pointer P auf X
// wenn wir nun die Werte verändern wollen "dereferenzieren" wir es wie folgt

P^ := 54321; // Adresse von P - $00FEDCAB; Wert von P = $00ABCDEF
// der Wert & die Adresse haben sich nicht geändert
// da wir sie aber dereferenziert haben, haben wir somit auf X zugegriffen:
// X hat jetzt den Wert 54321!

// -- B.)
var
  PInt: Pointer;
...
  PInt := @X;
  Integer( PInt^ ) := 113245;
Ich garantiere keine 100% Korrektheit :)

p80286 13. Feb 2009 16:55

Re: Pointer - ein schwarzes Tuch
 
Hallo mr_emre_d,

ich hab's überflogen und dem ist eigentlich nichts hizuzufügen, bis auf...
(der Hinweis auf bigendian ist nicht so offensichtlich)
Wenn ich mich richtig an API-Aufrufe erinnere, dann sind dort die "Pointer" das, was in Delphi/Pascal die var -Übergaben sind.
Wenn also etwa folgendes verlangt wird:
Delphi-Quellcode:
API_funktion(pbytearr):bool
dann solte das in Pascal/Delpi so gelöst werden:
Delphi-Quellcode:
var
  mybytearr : array[0..255] of byte;


if API_Funktion(@mybytearray) then ...
oder
Delphi-Quellcode:
type
  tmybytearray = array [0..255] of byte;
var
  mybytearray : tmybytearray;
  pmybytearray : ^tmybytearray;
 
...

  pmybytearray:=@mybytearray;
  if API_Funktion(pmybytearray) then ...
da gibt's bestimmt Empfehlungen wie's am Besten ist, aber die hab ich gerade nicht zur Hand.
Vielleicht ist in diesem Zusammenhang "Adresse" eine bessere Übersetzung als "Zeiger".
(Fehlinterpretatinen meinerseits bitte ich zu berichtigen)


Gruß
K-H

nuclearping 13. Feb 2009 17:18

Re: Pointer - ein schwarzes Tuch
 
Der vierte Parameter in der Funktion enthält die Daten.

In deinem konkreten Fall:
Delphi-Quellcode:
var
  ppFindData: PCeDB_File_Data_Array
  i: Integer;
begin

  // ...

  New (ppFindData);
  try
    if CeFindAllDatabases(.., .., ..., ppFindData) then
      begin
        // ...
        i := 0;
        while TRUE do
          begin
            ShowMessage (ppFindData^[i].DbInfo.szDbaseName);
            inc (i);
            // Abbruchbedingung is mir grad unklar
          end;
      end;
  finally
    Dispose (ppFindData);
  end;

  // ...
end;

mr_emre_d 13. Feb 2009 19:13

Re: Pointer - ein schwarzes Tuch
 
Zitat:

Zitat von p80286
API_funktion(pbytearr):bool
dann solte das in Pascal/Delpi so gelöst werden:
Delphi-Quellcode:
var
  mybytearr : array[0..255] of byte;
...
if API_Funktion(@mybytearray) then

Das ist genau das selbe Spielchen (z.B) mit
Delphi-Quellcode:
GetWindowText( hWnd, Buf );
buf = PChar --> Pointer zu (m ersten) Char (acter eines Strings, das Null-Terminiert ist)

dh. man könnte sich ein Buffer wie folgt definieren:
Delphi-Quellcode:
buf: Array[Byte] of Char;
welches 256 Zeichen beinhalten kann und somit ->Buf entspricht !

EDIT:
Bei der Übergabe eines Parameters an eine (API) Funktion kommt es darauf an, was verlangt wird:
Wenn ein Pointer verlangt wird, heißt es in meisten Fällen, dass der Wert verändert werden können muss! Deshalb könnte man auch vars übergeben, da sie (ne wage Behauptung - da Halbwissen -->) intern als Pointer verwertet werden !
Delphi-Quellcode:
a. procedure ChangeInput(Input: Integer);
b. procedure ChangeInput(var Input: Integer);
b. procedure ChangeInput(Input: PInteger);
Bei a wird nur der Inhalt von "Input" kopiert und übergeben!
Bei beiden bs wird die Referenz übergeben - man kann den Wert verändern !
Ist jetzt ziemlich weit hergeholt aber sollte halt das ganze ein bisschen veranschaulichen

Natürlich garantiere ich wieder nicht auf 100% Richtigkeit meiner Angaben - da sie auf Erfahrung beruhen :D

MfG

gmc616 13. Feb 2009 22:16

Re: Pointer - ein schwarzes Tuch
 
Erst mal Danke Leute, für die Hilfe.

Das was ihr geschrieben habt ist im groß und ganzen auch das, was ich aus den Tuts entnehemn konnte.
Was Pointer sind und wie sie funktionieren ist mir durchaus klar.

Natürlich habe ich das Beispiel von nuclearping probiert, aber ich bekomme ein EOutOfMemory - Zu wenig Arbeitsspeicher auf der Zeile
Delphi-Quellcode:
New (ppFindData);
"Ach, die Fehlermeldungen kennst! Gut!" dachte ich mir.
ppFindData weiß ja noch nicht, wohin er zeigen soll, damit das New weiß wieviel speicher es reservieren muß.

Also
Delphi-Quellcode:
procedure TFrom1.LeseDB();
var
  FindData : TCeDB_File_Data_Array;
  ppFindData: PCeDB_File_Data_Array;

// ...

ppFindData := @FindData;
New (ppFindData);
Nun stürzt das Programm bereits beim Aufruf der procedure LeseDB mit EStackOverflow ab.
Okay. Völlig Falsch. :oops:
Könnte wohl daran liegen, dass jetzt das New Speicher reservieren soll, der bereits reserviert ist. Oder? :gruebel: Das muß ja in die Hose gehen.

Letzten Endes müsste New eigentlich wissen, wie viel Speicher reserviert werden muß, da PCeDB_File_Data_Array bzw. ppFindData ein typisierter Pointer ist. Richtig ? :gruebel:

Aber eigentlich sollte das ganze doch auch ohne New funktionen, denn mit
Delphi-Quellcode:
ppFindData := @FindData;
habe ich doch meinen Zeiger auf das FindData : TCeDB_File_Data_Array ??
Knallt aber ebenfalls mit EStackOverflow.

Jetzt bin ich der gleichen Stelle, an der ich heute Mittag schon war. :cry:
Und nu?

Die Hilfe zu New sagt:
Zitat:

Ist nicht genug Speicher für die dynamische Variable verfügbar, wird eine EOutOfMemory-Exception ausgelöst.
Hmm ... nächste Versuch:
Delphi-Quellcode:
GetMem (ppData,SizeOf (TCeDB_File_Data_Array));
EOutOfMemory - Zu wenig Arbeitsspeicher

Bin ich echt zu blöd dafür?

:duck:

mr_emre_d 13. Feb 2009 23:51

Re: Pointer - ein schwarzes Tuch
 
Achtung - das ist nicht nur ein Pointer auf ne Variable sondern auf ein Array.

bsp:
Delphi-Quellcode:
type
  PByteArr = ^TByteArr;
  TByteArr = Array of Byte;

var
  X: PByteArr;
begin
  New( X );
  SetLength( X^, 10 );
  X^[0] := $FF;
  Dispose( X );
...
anderes, ähnliches bsp:
Delphi-Quellcode:
type
  PByteArr = ^TByteArr;
  TByteArr = Array[0..0] of Byte;
var
  X: PByteArr;
  Test: Array[0..10] of Byte;
  i: Integer;
begin
  Randomize;
  for i := 0 to High(Test) do
    Test[i] := Random(10);
  X := @Test;
  ShowMessage( inttostr(x^[0]) );
Edit: Hab gerade deinen Code ausprobiert und ja bei mir haut er auch "Zu wenig Arbeitsspeicher" raus ... ist iwie klar denn du hast ein Array, welches
( $7FFFFFFF div sizeof(TCeDB_File_Data)-1 ) * SizeOf( TCeDB_File_Data ) --> also $7FFFFFFF=2147483647 Bytes (~2050mb) groß ist ! Hast du mehr Ram zur Verfügung ? Falls ja dann dürfte es klappen :)

Ansonsten würde ich mal die Größe des Arrays verringern :)

MfG


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:39 Uhr.
Seite 1 von 2  1 2      

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