This is an old revision of the document!
Table of Contents
Volání funkcí v DLL knihovnách
Ze skriptů GeoGetu lze volat funkce v externích DLL knihovnách.
Ve skriptu lze nadeklarovat svojí funkci či proceduru, jejíž implementace není ve skriptu, ale v externí DLL knihovně. Externí DLL knihovnu lze připravit v libovolném programovacím jazyce, který umí překládat do standardní DLL knihovny.
Pokud chcete deklarovat funkci uloženou v DLL knihovně, napište za hlavičku funkce klíčová slovo external a za něj řetězec ve formátu: 'functionname@dllname callingconvention'
Překladač pak nebude hledat ve skriptu implementaci funkce a v případě potřeby zavolá příslušnou funkci v DLL knihovně.
Všimněte si v příkladech při deklaraci funkcí z knihovny klíčového slova delayload na konci deklarace každé knihovní funkce. Není sice nutné, ale pokud nebude uvedeno a dojde k nějaké chybě, GeoGet pravděpodobně ošklivě zhavaruje hned při spouštění pluginu. Pokud klíčové slovo uvedete, plugin bude pracovat až narazí na příslušnou funkci, tam napíše, že nelze funkci spustit (neuvede však jakou funkci, ale uvede kde) a relativně korektně se ukončí.
Příklad:
function FindWindow(C1, C2: PChar): Longint; external 'FindWindowA@user32.dll stdcall delayload'; function ShowWindow(hWnd, nCmdShow: Longint): Integer; external 'ShowWindow@user32.dll stdcall delayload'; function SetWindowText(hWnd: Longint; Text: PChar): Longint; external 'SetWindowTextA@user32.dll stdcall delayload'; procedure something; var i: longint; wnd: longint; begin wnd := Findwindow('', 'Innerfuse Pascal Script III'); SetWindowText(Wnd, 'This is DLL demo, it calls some windows user32 routines. This will hide this window for a few seconds'); for i := 0 to 200000 do begin end; ShowWindow(Wnd, 0); // hide it for i := 0 to 200000 do begin end; SetWindowText(Wnd, 'Wasn''t that nice?'); ShowWindow(Wnd, 5); // show it for i := 0 to 200000 do begin end; SetWindowText(Wnd, 'Innerfuse Pascal Script III'); end;
Vyzkoušené deklarace Windowsích funkcí z knihoven
function GetShortPathName(lpszLongPath, lpszShortPath: PChar; cchBuffer: integer): integer; external 'GetShortPathNameA@Kernel32.dll stdcall delayload'; function GetShortPathNameLength(lpszLongPath: PChar; lpszShortPath, cchBuffer: integer): integer; external 'GetShortPathNameA@Kernel32.dll stdcall delayload'; function GetShortName(value: string): string; var l: integer; begin l := GetShortPathNameLength(value,0,0); SetLength(Result, l); l := GetShortPathName(value, Result, Length(Result)); SetLength(Result, l); end;
Vytvoření DLL knihovny pro použití v GeoGetu
Vytvoření knihovny v Delphi asi nebude dělat velké problémy, ale pro knihovnu vytvářenou v C++ je třeba si uvědomit odlišnosti mezi Delphi a C++. Jde zejména:
- o konvenci volání funkcí
- o dekorování jmen funkcí
Demonstrovat řešení budu na Microsoft Visual Studiu (já konkretně mám verzi 2010). U jiných verzí MSVC to bude podobné a analogie se najde jistě u jiných kompilátorů - když se ví, co hledat, je to jednodušší.
Konvence volání funkcí
Když máme správně pojmenované funkce v knihovně, můžeme se vrhnout na jejich volání.
Implicitní volaní v C/C++ je typu cdecl
, zatimco v Delphi je to stdcall
. Je tedy potřeba uvést do souladu knihovnu s pluginem. Jsou 2 cesty:
- přizpůsobit plugin
- přizpůsobit knihovnu
Přizpůsobení pluginu
Tato cesta mi připadá výrazně jednodušší a nemá navíc žádný další vliv na přípanou C/C++ aplikaci, která by táké tuto knihovnu používala. Řešení spočívá pouze v tom, že překladači pluginu přikážeme typ cdecl
místo stdcall
. Nic víc v tom není.
function SoucetInt(i1,i2: integer): integer; external 'SoucetInt@MojeKnihovna.dll cdecl delayload'; function SoucetStr(s1,s2: PChar): PChar; external 'SoucetStr@MojeKnihovna.dll cdecl delayload';
Přizpůsobení knihovny
Pro přizpůsobení knihovny je třeba změnit implicitní nastavení kompilátoru:
Configuration Properties –> C/C++ –> Advanced –> Calling Convetion na hodnotu __stdcall (/Gz)
a v souladu s ním deklarovat funkce v pluginu:
function SoucetInt(i1,i2: integer): integer; external 'SoucetInt@MojeKnihovna.dll stdcall delayload'; function SoucetStr(s1,s2: PChar): PChar; external 'SoucetStr@MojeKnihovna.dll stdcall delayload';
Pokud takto změníte volací konvenci a knihovnu použijete také ve své vlastní aplikaci vytvořené v C/C++, je na to třeba pamatovat a knihovní funkce použít správně.