AutoIt/Biblioteki
Co to jest UDF?
edytujUDF (z ang. User Defined Functions) w dosłownym tłumaczeniu oznacza funkcje zdefiniowane przez użytkownika.
Najczęściej pod tym znaczeniem rozumiemy zbiór funkcji napisanych w AutoIt i zawartych w oddzielnym pliku.
Z funkcji tych można korzystać w pisanych skryptach bez konieczności kopiowania ich kodu.
Służy do tego dyrektywa include (patrz rozdział: AutoIt/Dyrektywy i funkcje konfiguracyjne translatora).
Dyrektywa ta powoduje dołączenie do skryptu kodu z zewnętrznego pliku. Dołączenie to odbywa się nie w czasie edycji jako proste wklejenie tekstu, lecz w czasie wykonywania lub kompilacji skryptu.
Funkcje wbudowane i funkcje biblioteczne
edytujTranslator AutoIt zawiera pewną ilość wbudowanych funkcji, z których możemy korzystać bezpośrednio.
Funkcji tych jest całkiem sporo (prawie wszystkie opisane w tym podręczniku należą do tej kategorii), ale z oczywistych względów nie mogą one obejmować wszystkich możliwych zastosowań.
Na szczęście istnieje w AutoIt prosty sposób na zwiększenie możliwości języka poprzez tworzenie i korzystanie z zewnętrznych bibliotek funkcji.
Pokaźna standardowa biblioteka funkcji dołączona jest do dystrybucji języka i po zainstalowaniu znajduje się w katalogu /Include.
Opis funkcji biblioteki standardowej, podobnie jak opis funkcji wbudowanych znajduje się w pliku pomocy AutoIt. Nazwy wszystkich funkcji bibliotecznych rozpoczynają się od podkreślenia (np.: _IsPressed).
Proszę zwrócić uwagę, że nie wszystkie pliki biblioteki standardowej są UDF'ami, niektóre zawierają definicje stałych globalnych (np. /AVIConstants). Nazw tych stałych można używać zamiast parametrów liczbowych, w niektórych funkcjach wbudowanych (po dołączeniu dyrektywą include, np.: include<AVIConstants>).
Istnieje także całe mnóstwo różnych innych bibliotek dostępnych w sieci (np.: do obsługi przeglądarki Firefox, drukarki itp.).
Zasady tworzenie bibliotek funkcji
edytujAby stworzony przez nas UDF zasługiwała na miano porządnej biblioteki musimy przy jego tworzeniu zachować pewne reguły. Jeżeli chcemy naszą pracą podzielić się z innymi, to musimy zadbać by nasz kod był przejrzysty i łatwy do analizy.
Z doświadczenie wiadomo, że chaotycznie napisany kod, bez komentarzy, staje się szybko trudny do analizy nawet przez samego autora, a co dopiero przez osobę postronną.
Taki kod trudno zrozumieć, a co za tym idzie trudno ulepszyć, poprawić czy rozwinąć.
Poniżej kilka zasad jakich powinniśmy przestrzegać pisząc UDF, który będziemy chcieli upublicznić:
1. Biblioteki powinny być tematyczne, tzn. powinny zawierać funkcje w jakim stopniu pokrewne (np. biblioteka graficzna, matematyczna, multimedialna itp.)
2. Dokumentacja kodu powinna zawierać:
- opis biblioteki
- wykaz zdefiniowanych stałych i funkcji
- opis stałych i funkcji
- opis parametrów przekazywanych do funkcji (ile ich jest, jakiego typu wartości przekazują, które są obowiązkowe, a które opcjonalne)
- opis wartości zwracanej przez funkcję (co ona reprezentuje i jakiego jest typu)
- opis ewentualnych wartości zwracanych przez makra @error i @extended
2. Kod funkcji:
- obsługa błędów (makro @error)
- obsługa parametrów opcjonalnych i wartości domyślnych
- deklarowanie zmiennych używanych wewnątrz funkcji
Zalecenia dotyczące nazewnictwa zmiennych
edytujAby łatwiej orientować w używanych w skrypcie zmiennych w tworzeniu ich nazw zaleca się stosować następujące reguły:
1. Po znaku $ stosować dodatkowy prefiks określający typ wartości przechowywanej przez zmienną:
Prefiks | Typ wartości | Inicjalizacja (przykład) --------------------------------------------------------- i | liczbowa | $iVar = 0 --------------------------------------------------------- a | tablica | $aVar = 0 or $aVar[0] --------------------------------------------------------- s | string | $sVar = "" --------------------------------------------------------- f | logiczna | $fVar = False lub $fVar = True --------------------------------------------------------- b | binarna | $bVar = "" --------------------------------------------------------- h | uchwyt, ID | $hVar = 0 --------------------------------------------------------- p | wskaźnik | $pVar = 0 --------------------------------------------------------- tag | struktura | | predefiniowana | --------------------------------------------------------- t | struktura | $tVar = 0 --------------------------------------------------------- o | obiekt | $oVar = 0 --------------------------------------------------------- v | nieokreślona | $vVar = 0 or $vVar = "" ---------------------------------------------------------
2. Nazwy powinny kojarzyć się z działaniem lub obiektem, którego dotyczą.
I tak dla zmiennej przechowującej uchwyt do okna GUI zamiast np. nazwy $x2 użyjemy $hGUI.
Pamiętajmy, żeby jednak nie przesadzać, np. w liczniku pętli możemy spokojnie użyć zmiennej $i zamiast $iLicznik_petli.
Podział linii kodu
edytujW AutoIt nie ma możliwości pisania dwóch lub więcej instrukcji w jednym wierszu tekstu (jedynym znakiem rozdzielającym instrukcje jest znak końca wiersza). Można natomiast zapisać jedną instrukcję w wielu wierszach.
Jest to czasami niezbędne przy bardzo długich instrukcjach. Podzielenie ich na kilka wierszy może zdecydowanie poprawić przejrzystość i czytelność kodu.
Do podziału instrukcji na wiersze służy znak podkreślenia "_", który musi być poprzedzony spacją.
Długa instrukcja:
MsgBox(64,"Okno demonstracyjne wyświetlania bardzo długich wierszy tekstu", "To jest bardzo, ale to bardzo długi tekst do wyświetlenia w oknie MsgBox!" & @LF & "A to drugi wiersz wyświetlany w tym oknie.")
I jej przykładowy podział:
MsgBox _ ;można wewnątrz instrukcji wstawić komentarz
(64, _
"Okno demonstracyjne wyświetlania bardzo długich wierszy tekstu", _
"To jest bardzo, ale to bardzo długi tekst do wyświetlenia w oknie MsgBox!" & _
@LF & "A to drugi wiersz wyświetlany w tym oknie.")
Nie można w ten sposób dzielić stringów. Próba takiego podziału spowoduje błąd:
MsgBox(64, "Okno demonstracyjne wyświetlania bardzo długich wierszy tekstu", "To jest bardzo, _
ale to bardzo długi tekst do wyświetlenia w oknie MsgBox!" & _
@LF & "A to drugi wiersz wyświetlany w tym oknie.")
Trzeba to zrobić tak:
MsgBox(64, "Okno demonstracyjne wyświetlania bardzo długich wierszy tekstu", "To jest bardzo," & _
"ale to bardzo długi tekst do wyświetlenia w oknie MsgBox!" & _
@LF & "A to drugi wiersz wyświetlany w tym oknie.")
A oto inny przykład prawidłowego podziału instrukcji:
Dim $a="a", $b=0
If ($a="a" Or _
$a="B" Or _
$a="c" Or _
$a="d") And _
$b<>2 And _
$b<>5 Then _
MsgBox(64, "Test podziału instrukcji", _
"Warunek został spełniony!")
Tworzymy prosty UDF
edytujPrzed przystąpieniem do pisania UDF'u dobrze jest przyjrzeć się bibliotekom dostępnym w dystrybucji AutoIt'a. Są one napisane z zachowaniem pewnej standardowej formy, którą będziemy mogli wykorzystać.
Załóżmy, że chcemy stworzyć bibliotekę funkcji matematycznych, niedostępnych w interpreterze:
_max - wartość maksymalna _min - wartość minimalna _sign - znak liczby _am - średnia arytmetyczna _gm - średnia geometryczna _log10 - logarytm dziesiętny _logA - logarytm o dowolnej podstawie _sinh - sinus hiperboliczny _cosh - cosinus hiperboliczny _QRoots - pierwiastki równania kwadratowego _factorial - silnia _combination - kombinacja bez powtórzeń _combinationWR - kombinacja z powtórzeniami _variation - wariacja bez powtórzeń _variationWR - wariacja z powtórzeniami _permutation - permutacja _Bin - zamiana liczby na string liczby dwójkowej _BinToDec - zamiana stringu liczby dwójkowej na liczbę dziesiętną
Ponieważ naszą pracę będziemy chcieli udostępnić całemu światu, nazwy funkcji wywodzą się z języka angielskiego i zwyczajowo rozpoczynają znakiem podkreślenia.
Podobnie opisy powinny być w języku angielskim lub dwujęzyczne. I nie zapomnijmy o obowiązkowym #include-once na początku kodu.
Oto początek naszego UDF'a:
#include-once
; #INDEX# =======================================================================
; Nazwa .........: Mathematic function
; AutoIt Version : 3.3.8.1
; Language ......: Polish
; Description ...: Dodatkowe funkcje matematyczne (Additional math functions)
; Author(s) .....: Wasta (2012)
; ===============================================================================
; #CURRENT# =====================================================================
;Const $_PI
;_max
;_min
;_sign
;_am
;_gm
;_log10
;_logA
;_sinh
;_cosh
;_QRoots
;_factorial
;_combination
;_combinationWR
;_variation
;_variationWR
;_permutation
;_Bin
;_BinToDec
; ===============================================================================
Global Const $_PI = 3.14159265358979323846264338328
; #FUNCTION# ====================================================================
; Name...........: _max
; Description ...: Większy z dwóch parametrów (The larger of the two parameters)
; Syntax.........: _max($iVar1, $iVar2)
; Parameters ....: Dwie liczby rzeczywiste (Two real numbers)
; Return values .: Większy z dwóch parametrów (The larger of the two parameters)
Func _max ($iVar1, $iVar2)
If $iVar1>=$iVar2 Then Return $iVar1
Return $iVar2
EndFunc
; ...
; ...
; ... itd.
UWAGA: W edytorze SciTe rozbudowany nagłówek funkcji możemy uzyskać wciskając kombinację klawiszy Ctrl+Alt+H (kursor musi znajdować się w wierszu z początkiem definicji funkcji).
Dalszy ciąg w ramach ćwiczeń.
Jak nieczytelny może być kod w AutoIt?
edytujMały przykład użycia zdefiniowanej powyżej funkcji _max, (skrypt wypisuje większą z podanych liczb):
Dim $a=7, $b=2
MsgBox(64, "Liczba większa", _max($a,$b))
Func _max ($iVar1, $iVar2)
If $iVar1>=$iVar2 Then Return $iVar1
Return $iVar2
EndFunc
A teraz całkowicie równoważna mu wersja mało czytelna (wygląda jakby małpa tłukła w klawiaturę, ale działa!):
Dim $a=7, $b=2 ;wprowadzenie danych jak w poprzednim przykładzie, ale dalej to już trochę trudniej
$____ _;_ ___$
= _
msgbOX-(1-1==1=1)
$______ _
= _
biNarytOSTrinG&"biNarytOSTrinG"
$___ _;_ __$
=( _;_)=
1--(1=1=1))^(1-- _
(1=1=1))^(1--(1= _
1)--(1=1=1)) _
/(-((1=1-1)-1))
$_____= _
$______(0x20617a736bea6957)&$______(0x202061627a63696c)
$_=( _
$a/((1=1)--1))- _
-($b/(1--(--1=1) _
))
fUnC _ _
($_,$__)
$_-=-1-1=--1
retuRN _
--$_--$__>--$_---$__?--$_----$__:----$_-----$__
enDfunC
$__=($a/((1==1)--1))-($b/(1--(--1=1)))
$____($___, $_____, _($_,$__))
Tego typu techniki zaciemniania kodu są czasem stosowane celem jego ochrony przed wykorzystaniem przez osoby niepowołane. Metoda ta nosi nazwę obfuskacji (z ang. obfuscation). Nie uniemożliwia ona wprawdzie całkowicie analizy kody, ale znacznie ją utrudnia (co widać na powyższym przykładzie).
Zalecenia dotyczące przejrzystego programowania
edytujNa koniec kilka zaleceń, aby nasz kod był elegancki i łatwy do analizowania:
Czytelna struktura programu, kolejno:
1. Dyrektywy Include. 2. Inne dyrektywy i funkcje konfiguracyjne translatora. 3. Definicje skrótów klawiszowych, jeżeli mają zasięg globalny. 4. Deklaracje zmiennych i stałych globalnych i lokalnych segmentu głównego 5. Kod segmentu głównego. 6. Kod definicji funkcji w jakiejś rozsądnej kolejności (na początku te najważniejsze). Jeżeli funkcja A w definicji wywołuje funkcję B, to logicznym jest, że definicja funkcji A powinna być przed definicją funkcji B.
Jak pisać kod i czego unikać:
1. Stosować wcięcia w pętlach, instrukcjach warunkowych i definicjach funkcji. Dzięki temu łatwo będzie rozpoznać zakres tej konstrukcji. Szczególnie jest to pomocne przy wielokrotnych zagłębieniach. 2. Nazwy zmiennych i funkcji powinny logicznie kojarzyć się z obiektem lub działaniem, którego dotyczą. 3. Przy tworzeniu GUI grupować instrukcje dotyczące jednego obiektu, np. kontrolki czy okna. Taką grupę można wydzielić za pomocą pustych wierszy przed i za nią. 4. Nie wstawiać po każdej linii kodu pustych wierszy. Puste wiersze powinny jedynie podkreślać pewną odrębność danego fragmentu kodu. 5. Komentować trudniejsze i ważniejsze fragmenty kodu. 6. Stosować prefiksy nazw zmiennych określające typ wartości jaką zawiera taka zmienna.
Ćwiczenia
edytuj1. Napisać pozostałą część biblioteki matematycznej, oraz prosty skrypt testujący jej działanie.
Przykładowe rozwiązania: AutoIt/Ćwiczenia dla zaawansowanych - przykładowe rozwiązania