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.dll' name '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.,
EnumWindowsProc), 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.