Entwickler-Ecke

Dateizugriff - Pointer und Funktionsaufrufe


jackle32 - So 24.05.15 11:00
Titel: Pointer und Funktionsaufrufe
Hallo zusammen,

ich bin gerade dabei mich in Dll´s und alles was damit zusammenhängt einzuarbeiten.

Dabei bin ich auf die Möglichkeit gestoßen, DLL´s dynamisch einzubinden.

Dabei habe ich gesehen, dass es den klassischen Weg gibt in dem ich die Funktion im "Type" abschnitt vordefiniere, mir eine Variable davon anlege und mittels @Variable und GetProcAddress die Adresse aus der Dll hole.

In einem anderem Programm habe ich gesehen, dass das Ergebnis von GetProcAddress direkt auf eine Variable vom Typ TFarProc übergeben wird. Nach etwas nachlesen in den Units bin ich drauf gekommen, dass es sich dabei ja eigentlich um einen ganz normalen Pointer handelt. (Hoffe des stimmt soweit)

Jetzt zu meiner Frage.

Warum geht so etwas (Beispiel aus einem Forum), speziell der markierte Bereich sollte analog meinen unteren Beispiel sein:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
var
  i, j: Integer;
  p1: ^Integer;
  p2: Pointer;
begin
  i := 1;
 
  { typisiert }
 
  p1 := @i;       // dem Zeiger wird die Adresse der Integer-Variable übergeben
  p1^ := p1^ + 1// hier wird der Wert um eins erhöht
  j := p1^;       // typisiert: der Variable j wird 2 übergeben
 
  { untypisiert }
 
  p2 := @i;       // analog oben
  Integer(p2^) := i + 1;
  j := Integer(p2^);
end.


Das hier aber nicht:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
type

  TFNFunktion = procedure (); stdcall;

var
  FunktionsPointer: TFarProc = Nil;

procedure DllEinlesen()
var
  DllHandle: THandle;
begin
  DllHandle := LoadLibrary('DllName');

  FunktionsPointer := GetProcAddress(DllHandle, 'Funktionsname');
end;

procedure TForm1.Button1Click(Sender: TObject)
begin
  TFNFunktion(FunktionsPointer^);
end;


Ich für mein Verständnis würde sagen es müsste gehen, tut es aber nicht. Vom Mechanismus her müsste des doch sein, schau auf die Adresse und mache abhängig von dem Typ das was an der Adresse steht.

Was schon geht um alle zu erklären was ich getestet habe ist:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
type

  TFNFunktion = procedure (); stdcall;

var
  FunktionsPointer: TFarProc = Nil;
  Funktion: TFNFunktion = Nil;

procedure DllEinlesen()
var
  DllHandle: THandle;
begin
  DllHandle := LoadLibrary('DllName');

  FunktionsPointer := GetProcAddress(DllHandle, 'Funktionsname');
end;

procedure TForm1.Button1Click(Sender: TObject)
begin
  @Funktion := FunktionsPointer;
  Funktion;
end;


(Ich habe meine Beispiele frei runter geschrieben, da mein Programm noch umfangreicher ist und daraus wahrscheinlich nicht klar geworden wäre auf was ich hinaus will. Daher ist es gut möglich, dass ein Rechtschreib- oder Formellerfehler drin ist. Darum geht es mir auch nicht, sondern nur um das Verhalten von Pointer bei Funktionsaufrufen.)

Ach so der Fehler den ich bekomme wenn ich das mittlere Beispiel versuche ist:


Quelltext
1:
Zugriffsverletzung bei Adresse 00000000006F5EC2 in Modul 'Anwendung.exe'. Lesen von Adresse FFFFFFFFFFFFFFFF.                    


Bin schon auf eure Antworten gespannt.

Gruß,
Jack


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am So 24.05.2015 um 22:46


Sinspin - So 24.05.15 12:05

1. Du brauchst das Dll Handle noch um die Dll später wieder entladen zu können. Daher ist es ziemlich unklug dieses in der procedure zu deklarieren.
2. Dein mittleres Beispiel... :gruebel:
3. Probier mal das :


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:
27:
28:
29:
30:
31:
32:
type
  TFNFunktion = procedure (); stdcall// beim festlegen des Typs beachten welche Parameter die Procedure hat

var
  DllHandle: THandle;
  Funktion: TFNFunktion = Nil;

procedure DllLaden();
begin
  DllHandle := LoadLibrary('DllName');
  if DllHandle <> 0 then
  begin
    Funktion := GetProcAddress(DllHandle, 'Funktionsname');
  end;
end;

procedure DllEntladen;
begin
  if DllHandle <> 0 then
    FreeLibrary(DllHandle);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DllLaden;
  try
    if Assigned(Funktion) then
      Funktion;
  finally
    DllEntladen;
  end;
end;


Mir ist klar das in dem Beispiel so ziemlich die ganze Fehlerauswertung fehlt, aber zum rumspielen reicht das erstmal.

€: Falschen Bezeichner entfernt, "FunctionPointer" ersetzt durch "Funktion".


jackle32 - So 24.05.15 17:13

Hallo Sinspin,

danke für deine Antwort.

zu 1.: Ja ich weiß, wie gesagt war ja auch kein reales Beispiel und sollte nicht zum nachmachen aufrufen... :wink:

zu 2.: im zweiten Beispiel mache ich eigentlich das gleiche wie im Ersten mit Integern gemacht wird nur eben mit Funktionen, aber leider mit beschriebenen Problemen.

zu 3.: Sieht auf den ersten Blick ja nach dem "normalen" Weg aus. Eine kleine Frage: Wie und wo definierst du "FunktionsPointer"?

Und grundsätzlich, natürlich ist auch in meinen original Code noch einiges an Fehlerbehandlung außen rum. Das habe ich aber mit Absicht weg gelassen um meine eigentliche Frage nicht zu sehr zu verstecken.

Gruß,
Jack


GuaAck - So 24.05.15 21:58

Hallo jackle32,

mit Strings habe ich in diesem Zusammenhang gelegentlich Probleme gehabt.

mit

var
name: string;

geht es mit der expliziten Umwandlung:

p := GetProcAddress(dllHandle, pansichar(name));

Probieren,
Gruß Gueack


jackle32 - So 24.05.15 23:36

Mein Problem dreht sich nicht um den Aufruf von GetProcAddress.

Vielleicht nochmal kurz:

Es geht darum wie ich


Delphi-Quelltext
1:
2:
@Funktion := FunktionsPointer;
Funktion;

anders und idealerweise kürzer schreiben kann.

(Deklaration der Variablen aus obigen Beispiel Nummer 3)


Gruß,
Jack


Sinspin - Mo 25.05.15 06:44

Oh sorry, da ist mir ein Fehler unterlaufen. Ich habe das mal angepasst.