Einzelnen Beitrag anzeigen

Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.117 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: hilfe mit dll datei und englischem treat

  Alt 27. Feb 2007, 21:20
Moin Christian,

hier noch einmal die Einbindung von Phreax, allerdings kommentiert (und korrigiert )

Delphi-Quellcode:
//BOOL GetProductString(OUT PVOID Buffer, IN ULONG BufferLength);
function GetProductString(const Buffer: PChar; const Length: ULONG): Longbool; stdcall; external 'API.dll';

// Anwendung:

var
  pBuf: PChar;

begin
  pBuf := AllocMem(255);
  try
    if not GetProductString(pBuf,255) then begin
      ShowMessage(SysErrorMessage(GetLastError));
    end else begin
      ShowMessage(trim(pBuf));
    end;
  finally
    FreeMem(pBuf,255);
  end;
end;
Gehen wir mal der Reihe nach durch:
Das const habe ich mir angewöhnt, da es in C keine var-Parameter gibt, wie, z.B., in Delphi. Es ist zwar nicht zwingend erforderlich erleichtert aber oft die Anwendung von Beispielen, die in C geschrieben sind. Ausserdem sieht man oft Deklarationen, in denen ein Parameter, der als Rückgabewert der Funktion dienen soll, durch Angabe von nil ausgelassen werden kann, wenn der Wert nicht von Interesse ist. In Delphi-Übersetzungen findet man hier aber oft var-Parameter in der Deklaration, so dass dieses Weglassen so nicht möglich ist.
Den PChar habe ich mal so gelassen, da er hier Sinn zu machen scheint, PVOID entspricht eigentlich dem Pointer in Delphi.
ULONG kann man so lassen, da es in Delphi deklariert ist (als Cardinal). Ob man sich damit beim Wechsel auf 64-Bit-Compiler Probleme einhandeln kann (cardinal ist der generische, vorzeichenlose Integertyp, also 32-Bit gross bei einem 32-Bit Compiler, 64-Bit bei bei einem 64-Bit Compiler) weiss ich allerdings nicht genau.
IN/OUT sind in den Windows C-Headern als Makros ohne Inhalt deklariert, und dienen nur dokumentatorischen Zwecken, so dass man sie hier weglassen kann.
BOOL entspricht dem Delphi-Typ Longbool, und nicht boolean, da Longbool 4-Byte gross ist, und boolean ist 1-Byte gross. Einen booleschen Typen gibt es in C gar nicht. BOOL ist als int deklariert. Man könnte also eignentlich auch integer nehmen, aber mit BOOL (bzw. Longbool) kann man den Code lesbarer schreiben.
stdcall als Aufrufkonvention habe ich genommen, da diese unter Windows die verbreitetste ist. Es könnte auch cdecl sein.
Das wird man spätestens dann merken, wenn man beim Aufruf der Funktion eine AV erhält
Mit external 'API.DLL' gibt man dann noch die DLL an, in der sich die Funktion befindet.
Man könnte dann noch mit name 'NameDerFunktion' den Namen der Funktion mit angeben, wie er in der DLL lautet (ACHTUNG: Gross-/Kleinschreibung beachten), wenn der Funktionsname davon abweichen soll.
Viele Windows-Funktionen liegen als Ansi- und Widestring Versionen vor, und sind in den DLLs durch den Suffix A bzw. W unterschieden (z.B. MessageBoxA, MessageBoxW). Zur Vereinfachung ist dann, in Delphi, noch die Funktion MessageBox deklariert, wobei es sich um MessageBoxA handelt.
Beispiel:
function MessageBox(.....) : integer; stdcall; external 'user32.dllname 'MessageBoxA'; Nachteil der statischen Einbindung:
Ist die Funktion nicht auf dem Rechner vorhanden, schlägt schon der Programmstart fehl.

Um diese zu verhindern, kann man dann die Funktion dynamisch, also zur Laufzeit einbinden.
Hierzu deklariert man sich erst einmal einen Funktionstypen:

Delphi-Quellcode:
type
  TGetProductString = function(const Buffer: PChar; const Length: ULONG): Longbool; stdcall;
Einbinden kann man die Funktion dann mit

Delphi-Quellcode:
var
  hLib : DWORD;
  GetProductString : TGetProductString;

begin
  hLib := LoadLibrary('API.DLL'); // Versuchen die DLL zu laden
  if hLib = 0 then exit; // bekommen wir kein Handle, konnte die DLL nicht geladen werden
  try
    @GetProductString := GetProcAddress(hLib,'GetProductString'); // Adresse der Funktion auslesen
    if @GetProductString = nil then exit; // Fehlgeschlagen, dann gibt es nichts weiter zu tun
    // Jetzt kann mit der Funktion gearbeitet werden
   
  finally
    FreeLibrary(hLib); // und die DLL wieder entladen, wenn sie nicht mehr benötigt wird.
  end;
end;
Das nur als kurzes Beispiel für das dynamische Einbinden.
Meistens wird man allerdings das Laden und Freigeben der DLL nicht innerhalb der gleichen Routine machen.

Zur Vervollständigung:
INT kannst Du mit integer übersetzen.

Das einzige, was sonst noch schwieriger werden könnte (das übrige müsstest Du jetzt hinbekommen können) ist:
Code:
DWORD SetCallback(IN DWORD lpProc);
--- lpProc: pointer to the callback function:
--- VOID WINAPI keyProc(INT pressedKeys);
Hier finde ich die Deklaration schon etwas merkwürdig. Ich würde es so übersetzen:
function SetCallback(const lpProc : Pointer) : DWORD; stdcall; external 'API.DLL'; da es keinen Sinn macht die Adresse einer Funktion als DWORD anzugeben.
keyProc ist eine Funktion, die Du selber deklarieren musst (siehe z.B., MSDN-Library durchsuchenEnumWindowsProc), beispielsweise so:

Delphi-Quellcode:
function MeineKeyProc(const pressedKeys : integer) : DWORD; stdcall;
begin
  // Was auch immer mit pressedKeys passieren soll
end;
Der Aufruf wäre dann:
SetCallback(@MeineKeyProc); Die Deklaration von MeineKeyProc ergibt sich durch das davor stehende WINAPI. Wenn Du Dir mal die Header-Dateien des PSDK anschaust, die WinDef.h um genau zu sein, wirst Du feststellen, dass hier mit die Aufrufkonvention stdcall festgelegt wird.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat