Serißl - 18. dφl
Mal² ·vod do API
18. Mal² ·vod do API
18.1 Co je to API
18.2 Deklarace funkcφ API
18.3 P°φklad pou₧itφ
18.4 Chyby
18. Mal² ·vod do API
V dneÜnφm dφle se dozvφte n∞co o technologii, kterß d∞lß z Visual Basicu
siln² programovacφ jazyk, dφky kterΘ m∙₧e obstßt v silnΘ konkurenci ostatnφch
produkt∙.
18.1 Co je to API
Funkce API (Application Programming Interface) jsou funkce, kterΘ
jsou obsa₧eny v knihovnßch DLL (Dynamic Link Library). Ve skuteΦnosti
jsou funkce API vyu₧φvßny vÜemi programy ve Windows. V₧dy kdy₧ vytvo°φte okno,
prvek, zm∞nφte vlastnost prvku, je volßna n∞jakß API funkce. Abyste
nemuseli znovu psßt ji₧ jednou vytvo°enΘ funkce, m∙₧ete proto vyu₧φvat ty ze soubor∙
DLL. Jak z t∞ch, kterΘ jsou souΦßstφ systΘmu Windows, nap°. GDI32.DLL, SHELL32.DLL atd. tak
i z t∞ch, kterΘ napsal n∞kdo jin². Shrneme-li si v²hody pou₧itφ DLL do n∞kolika bod∙, byly
by to asi tyto:
- ┌spora programovΘho k≤du, tj. i mφsta na disku. Nap°. funkci pro vykreslenφ kru₧nice
nemusφte vytvß°et znovu, pou₧ijete tu zknihovny GDI32.DLL. Stejn∞ tak ji mohou vyu₧φvat
jinΘ aplikace.
- Jednoduchß ·prava k≤du. Nemusφte m∞nit ka₧dou aplikaci, kterß by vyu₧φvala stejn² k≤d,
jednoduÜe zm∞nφte knihovnu DLL (samoz°ejm∞ pokud jde o VaÜi, asi t∞₧ko
budete m∞nit systΘmovΘ).
- Rychlost. Spousta knihoven je napsßna v jazyce C++. Dnes u₧ sice nenφ o tolik rychlejÜφ
ne₧ VB, ale p°esto volßte funkci p°φmo a ne p°es n∞jakΘ objekty, kterΘ nakonec stejn∞ volajφ
API funkce.
- ┌spora pam∞ti. Pokud spustφte vßÜ program, je nahrßn do pam∞ti. Pokud vÜak volßte n∞jakou
funkci z knihovny DLL, je a₧ v tΘ chvφli nahrßna do pam∞ti. Tzn. dokud ji nepou₧ijete, co₧
se m∙₧e klidn∞ stßt po celou dobu b∞hu programu, nezabφrß pam∞¥.
Samoz°ejm∞ ₧e nebudete (alespo≥ doufßm) od te∩ pou₧φvat na vÜechno funkce API mφsto
p°φkaz∙ Visual Basicu. Bylo by to mnohem pracn∞jÜφ. Pro n∞kterΘ akce, nap°. zßpis
kamkoliv do registru, vÜak Visual Basic nemß ₧ßdnΘ objekty a proto musφte pou₧φt API.
Zp∞t na obsah
18.2 Deklarace funkcφ API
Deklaraci funkce API m∙₧ete napsat v podstat∞ kdekoliv. Ve t°φd∞, v modulu i ve formulß°i,
stejn∞ jako ka₧dou jinou funkci. Rozdφl je pouze v tom, ₧e mßli b²t globßlnφ, tedy
Public , musφ b²t v modulu. Ve formulß°i nebo ve t°φd∞ m∙₧e b²t pouze lokßlnφ,
tedy Private .
Popis deklarace si ukß₧eme na p°φkladu.
Declare Function WritePrivateProfileString Lib "kernel32" _
Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, ByVal lpString As Any, _
ByVal lpFileName As String) As Long
Samotnou deklaraci uvozuje klφΦovΘ slovo Declare . Po n∞m nßsleduje
bu∩ Function nebo Sub , podle toho, zda vracφ nebo
nevracφ hodnotu (v∞tÜina je Function ). T°etφm parametrem je jmΘno
funkce, kterΘ bude pou₧ito k volßnφ ve VB (nemusφ b²t v₧dy jmΘno funkce
v knihovn∞ DLL - vysv∞tlφm pozd∞ji). ╚tvrt² parametr je nßzev knihovny
DLL uvozen² klφΦov²m slovem Lib . ╪et∞zec za klφΦov²m
slovem Alias je opravdov²m nßzvem funkce v knihovn∞. Takov² zßpis
se provßdφ z vφce d∙vod∙. Prvnφm m∙₧e b²t kolize nßzvu funkce API s ji₧ existujφcφ
funkcφ ve VB. Proto se v klauzuli Alias uvede prav² nßzev
funkce, ale volß se nßzev zadan² za slovem Declare . Druh²m
d∙vodem je takΘ skuteΦnost, ₧e mnoho funkcφ API je vytvo°eno v jazyku C, tj.
mohou obsahovat v nßzvu znaky, kterΘ VB nepodporuje. Funkce API takΘ
nemusφ mφt v₧dy nßzev, jsou urΦeny po°adov²m Φφslem. Potom je v klauzuli
Alias uvedeno po°adovΘ Φφslo, uvozeno znakem #, a funkce je op∞t
volßnß nßzvem za slovem Declare . Dßle u₧ nßsledujφ jednotlivΘ
parametry stejn∞ jako u normßlnφch funkcφ a nakonec typ nßvratovΘ hodnoty.
Funkce m∙₧ete deklarovat dv∞ma zp∙soby. Bu∩ znßte jejφ nßzev, vφte ve kterΘ
knihovn∞ se nachßzφ, znßte poΦet i typy vÜech jejich parametr∙ a napφÜete ji sami.
Tento zp∙sob nenφ moc vhodn², proto₧e m∙₧ete lehce ud∞lat chybu, zvlßÜt∞ ze zaΦßtku
a navφc mßlokdo znß zpam∞ti vÜechny tyto informace. Druhß mo₧nost je pou₧φt program
API Viewer, kter² je dodßvan² s VB. Jeho pou₧itφ je velmi jednoduchΘ. Spus¥te
jej a z menu File zvolte polo₧ku Load text file. S programem jsou
dodßvßny t°i soubory s deklaracemi, vßs bude za zaΦßtku zajφmat Win32api.txt. Ten tedy
otev°ete. V hornφm rozbalovacφm seznamu (API Type) si vybφrßte mezi funkcemi, konstantami
a u₧ivatelsky definovan²mi typy. Vyberete po₧adovanou polo₧ku (funkci, typ ...),
zadßte zda mß b²t Private nebo Public a stisknete tlaΦφtko Add. Tφm se p°idß do dolnφho
textovΘho pole. Mßte-li vybrßny po₧adovanΘ polo₧ky, stiskn∞te tlaΦφtko Copy, kterΘ
zkopφruje text do schrßnky a pak u₧ staΦφ jej ve VB ze schrßnky vlo₧it. Tento
postup vßm oproti prvnφmu zaruΦφ bezchybnou syntaxi funkcφ nehled∞ na to, ₧e je
mnohem rychlejÜφ, ne₧ kdybyste vÜe m∞li psßt sami. Pokud program API viewer nemßte
(VB 6.0 learning edition ho ·dajn∞ neobsahuje - nevφm, nem∞l jsem tu mo₧nost
seznßmit se s touto verzφ), m∙₧ete zkusit jeÜt∞ mnohem poveden∞jÜφ program
API Guide.
Zp∞t na obsah
18.3 P°φklad pou₧itφ
P°esto₧e se dnes u₧ moc nepou₧φvajφ INI soubory, p°esto si ukß₧eme, jak s nimi pracovat
pomocφ funkcφ API. Registr Windows (nßhrada INI) bude pozd∞ji samostatn² dφl naÜeho serißlu.
I p°esto m∙₧ete nφ₧e uvedenΘ funkce s ·sp∞chem vyu₧φt, nap°. pro uklßdßnφ n∞jak²ch jednoduch²ch
strukturovan²ch informacφ kterΘ se do registru nehodφ.
Spus¥te Visual Basic a otev°ete nov² projekt. Spus¥te API Viewer a vlo₧te z n∞j
do k≤du formulß°e deklaraci funkcφ WritePrivateProfileString (pro zßpis
hodnoty do INI souboru), GetPrivateProfileInt (pro Φtenφ ΦφselnΘ
hodnoty), GetPrivateProfileString (pro Φtenφ °et∞zce), vÜechny
jako lokßlnφ pro formulß°, tj. Private . Deklarace by m∞la vypadat takto:
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
Private Declare Function GetPrivateProfileInt Lib "kernel32" Alias "GetPrivateProfileIntA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal nDefault As Long, ByVal lpFileName As String) As Long
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
POZOR - pokud budete funkce psßt sami, m∞jte na pam∞ti, ₧e Win32 rozliÜuje
malß a velkß pφsmena.
Pou₧itφ funkcφ API je dßle stejnΘ jako pou₧φvßnφ jak²chkoliv jin²ch funkcφ.
V naÜem p°φkladu zapφÜeme do INI souboru dv∞ hodnoty, Φφslo a °et∞zec. Tyto
hodnoty nßsledn∞ p°eΦteme a zobrazφme v okn∞ Immediate. K≤d pro takovou
akci je velmi jednoduch² (umφstit ho m∙₧ete t°eba do udßlosti Load
formulß°e):
Dim ret As Long, sTmp As String
'zßpis
ret = WritePrivateProfileString("PRVNI", "pocet", "10", "C:\priklad.ini")
ret = WritePrivateProfileString("DRUHA", "jmeno", "visual basic", "C:\priklad.ini")
'Φtenφ Φφsla
ret = GetPrivateProfileInt("PRVNI", "pocet", 0, "C:\priklad.ini")
Debug.Print ret
'Φtenφ °et∞zce
sTmp = Space(260)
ret = GetPrivateProfileString("DRUHA", "jmeno", "", sTmp, 260, "C:\priklad.ini")
Debug.Print Left(sTmp, ret)
Te∩ si p°φklad podrobn∞ji popφÜeme. Prvnφ dva °ßdky (mimo deklaraci prom∞nn²ch)
zapisujφ hodnoty do souboru C:\priklad.ini. Prvnφ zapφÜe °ßdek pocet s hodnotou
10 do sekce PRVNI a druh² zapφÜe °ßdek jmeno s hodnotu visual basic do sekce DRUHA. V²sledn²
INI soubor bude vypadat takto:
[PRVNI]
pocet=10
[DRUHA]
jmeno=visual basic
V²slednß hodnota je ulo₧ena do prom∞nnΘ ret . Zde by bylo vhodnΘ testovat, zda
se nerovnß 0. Pokud ano, vznikla p°i zßpisu n∞jakß chyba. DalÜφ °ßdek
Φte Φφselnou hodnotu pocet ze sekce PRVNI. Jedin² parametr, kter² by mohl b²t nejasn², je
nDefault (v naÜem p°φpad∞ 0). Tato hodnota je vrßcena v p°φpad∞, ₧e funkce
hodnotu pocet nem∙₧e p°eΦφst (INI soubor neexistuje, Üpatnß sekce atp.).
Jinak je samoz°ejm∞ vrßcena zjiÜt∞nß hodnota. V²pis hodnoty pocet p°eskoΦφme,
to ji₧ pro vßs nenφ ₧ßdnß novinka. DalÜφ dva °ßdky zajistφ p°eΦtenφ hodnoty jmeno. Tato
funkce funguje trochu jinak ne₧ pro zjiÜt∞nφ Φφsla. Nadefinujete-li ve VB prom∞nnou
jako String , mß nulovou dΘlku. Z toho d∙vodu do nφ nenφ API funkce schopna
nic zapsat. Proto musφte tuto prom∞nnou nejd°φve nastavit na po₧adovanou dΘlku. V tomto
p°φpad∞ by m∞la staΦit hodnota 260. Prvnφ °ßdek tedy naplnφ prom∞nnou sTmp
260 mezerami. Funkci GetPrivateProfileString p°edßte parametry nßzev sekce,
nßzev °ßdku, default hodnotu (pracuje stejn∞ jako u GetPrivateProfileInt ),
prom∞nnou do kterΘ se ulo₧φ p°eΦtenß hodnota, dΘlku prom∞nnΘ (260) a nßzev INI souboru.
Funkce vracφ dΘlku °et∞zce, v tomto p°φpad∞ 12 (visual basic). Tφmto zp∙sobem fungujφ
v podstat∞ vÜechny funkce API, kterΘ pracujφ s °et∞zci. Je to z toho d∙vodu, ₧e jazyk
C pracuje s °et∞zci pon∞kud odliÜn²m zp∙sobem a v p°φpad∞, ₧e ne°eknete, jak dlouh² mß
b²t, nenφ schopen rezervovat po₧adovanou pam∞¥. Mφsto napln∞nφ mezerami m∙₧ete
taky deklarovat °et∞zec s pevnou dΘlkou, Dim sTmp As String * 260 . Visual
Basic .NET u₧ vÜak tuto mo₧nost podporovat nebude, proto rad∞ji pou₧φvejte °et∞zce
s prom∞nnou dΘlkou.
Zp∞t na obsah
18.4 Chyby
Zde si ukß₧eme jak zachytßvat a obsluhovat chyby, kterΘ nastanou v API funkcφch. Narozdφl od chyb, kterΘ nastanou v ostatnφm k≤du, nem∙₧eme chyby, kterΘ nastanou v API funkcφch zachytßvat pomocφ konstrukce On Error ... . OvÜem objekt Err pou₧φt m∙₧eme, a to konkrΘtn∞ jeho vlastnost LastDllError , kterß obsahuje Φφslo chyby, kterß nastala p°i volßnφ API funkce. Stejnou funkΦnost nabφzφ i API funkce GetLastError .
Declare Function GetLastError Lib "kernel32" () As Long
U API funkcφ z knihoven standardn∞ dodßvan²ch s Windows jsou v zßsad∞ pou₧φvßny t°i rozdφlnΘ zp∙soby obsluhy chyb v API funkcφch. Prvnφ a dnes ji₧ nep°φliÜ pou₧φvan² zp∙sob pochßzφ z 16-bitov²ch dob, kdy je n∞kdy nutnΘ provßd∞t obsluhu chyb individußln∞ v zßvislosti na pou₧itΘ API funkci. Tento zp∙sob je pou₧φvßn pouze u funkcφ, kterΘ jsou poskytovßny pro zp∞tnou kompatibilitu. Typick²m p°φkladem je nap°φklad funkce GetProfileString , kterß v p°φpad∞ problΘm∙ vracφ dva chybovΘ stavy, indikovanΘ vrßcenou hodnotou, je₧ je zßvislß na hodnot∞ poslednφho parametru.
Druh² zp∙sob vyu₧φvß nßvratovΘ hodnoty funkce. V p°φpad∞, ₧e funkce prob∞hla v po°ßdku, vratφ hodnotu ERROR_SUCCESS Φili 0, jinak je vrßcenß hodnota Φφslem chyby. Takto se nap°φklad chovajφ API funkce pro prßci s registrem. Nßsledujφcφ p°φklad ilustruje zachytßvßnφ chyb na funkci pro testovßnφ existence klφΦe v registru.
'Chybov² k≤d
Const ERROR_BADKEY = 1010&
'P°edefinovanΘ handly klφΦ∙ (hKey)
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS = &H80000003
Const HKEY_PERFORMANCE_DATA = &H80000004
Const HKEY_CURRENT_CONFIG = &H80000005
Const HKEY_DYN_DATA = &H80000006
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" ( _
ByVal hKey As Long, ByVal lpSubKey As String, _
ByVal ulOptions As Long, ByVal samDesired As Long, _
phkResult As Long) As Long
Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Public Function KeyExist(hKey As Long, lpSubKey As String) As Boolean
Dim retVal As Long, phkResult As Long
retVal = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, phkResult)
If lRetVal <> ERROR_BADKEY Then
RegCloseKey phkResult
KeyExist = True
Else
KeyExist = False
End If
End Function
T°etφ a nejrozÜφ°en∞jÜφ zp∙sob funguje tak, ₧e v p°φpad∞ chyby je zavolßna API funkce SetLastError v parametru s Φφslem chyby a v nßvratovΘ hodnot∞ funkce API je p°edßna 0. V praxi se postupuje tak, ₧e je otestovßna nßvratovß hodnota funkce a v p°φpad∞, ₧e je rovna nule, je zavolßna API funkce GetLastError a zjiÜt∞no Φφslo chyby, kterß nastala. Tento zp∙sob je nejb∞₧n∞jÜφ. Pokud funkce prob∞hla v po°ßdku, je nßvratovß hodnota nenulovß. U tohoto zp∙sobu m∙₧ete narazit po ·sp∞ÜnΘm provedenφ API funkce na dva mo₧nΘ stavy. Bu∩ je ponechßno nastavenφ chyby, kterß nastala p°ed provßd∞nφm danΘ funkce, beze zm∞ny, nebo API funkce zavolß SetLastError v parametru s hodnotou ERROR_SUCCESS Φili 0. V nßsledujφcφm p°φklad∞ testujeme uveden² postup na API funkci GetWindowRect . Je z°ejmΘ, ₧e zadßvat handle okna staticky je nesmysl, ale pro ilustraci oÜet°enφ chyby to lze p°ejφt (na mφst∞ Φφsla 1234 by se m∞lo nachßzet nap°φklad Me.hwnd ).
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
...
Dim r As RECT, retVal As Long
retVal = GetWindowRect(1234, r)
If retVal = 0 Then
MsgBox "Chyba: " & GetLastError()
End If
Nastane-li chyba, je dobrΘ mimo jejφ Φφslo znßt takΘ jejφ popis. K tomu slou₧φ API funkce FormatMessage , kterß po zadßnφ n∞kolika parametr∙, z nich₧ nejd∙le₧it∞jÜφ je Φφslo chyby, vrßtφ popis chyby. Pro zjednoduÜenφ uvßdφm v nßsledujφcφm p°φkladu funkci, kterß omezφ zadßvßnφ parametr∙ pouze na Φφslo chyby.
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" ( _
ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, _
ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, _
Arguments As Long) As Long
Public Function ErrorDescription(nErr As Long) As String
Dim retVal As Long, bufStr As String * 255
retVal = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, 0, nErr, 0, bufStr, 255, 0)
ErrorDescription = Left$(bufStr, retVal)
End Function
MsgBox GetLastError() & ":" & ErrorDescription(GetLastError()), vbOKOnly, "Chyba!"
Zp∞t na obsah
|