Kai kalba eina apie Borland Delphi programavimo terpę, dauguma atsimena labai patogią programą, kurioje per kelias minutes galima sukurti paprastą tektinį tekstinį redaktorių, muzikinį grotuvą ir pan.
Delphi labai greitai pakeitė programą Turbo Pascal (nors ji dar tebėra viena pagrindinių mokymo priemonių įvairiose mokymo įstaigose). Nuo trečiosios versijos Delphi pradėjo labai keistis į gerąją pusę ir dabar jau galime įsigyti aštuntąją versiją (kurios dauguma kol kas nepripažįsta). Teoriškai naujoji versija reiškia daugiau galimybių, daugiau patogumų, mažiau klaidų ir pan., tačiau taip yra tik teoriškai. Su naujom Delphi versijom vis rimtėja ir du pagrindiniai programavimo su ja minusai: greitis ir dydis. Deja, su Delphi pagalba rašomos programos labai atsilieka savo greičiu ir dydžiu, lyginant su C++ programomis ir ilgainiui “rimti” programuotojai tai pradeda gerai pastebėt. Tačiau yra viena išeitis.
Delphi bėda ta, kad į kuriamas programas „prikiša“ daug nereikalingo kodo. Pripažinkime, juk didžiąja dalimi formos savybių mes net nesinaudojam! Tačiau jos yra ir jų atsikratyti neina. Taip pat visi komponentai turi savo modulius, kurie nemažai „sveria“. Kiekvienas prijungtas modulis prideda prie kuriamos programos papildomus kilobaitus „svorio“. Kai kurie moduliai – po šimtą ir daugiau! Visi dažnai naudojasi standartiniu mygtuku „TButton”, tačiau jo modulyje aprašyti net keli skirtingi mygtukai, kurie programoje nenaudojami ir visai nereikalingi. Taigi jau paprastos programos, kurios susidaro tik iš savo lango, užima kompiuterio diske nuo ~0,5 iki ~1Mb vietos ir veikia gan lėtai (ypač jei naudojamas permatomumas).
Kaip išspręsti šią problemą? Reikia visad stengtis programos kode valyti „šiukšles“, t.y. nenaudoti jokių papildomų, nereikalingų modulių. Daugiausia vietos programai prideda „SysUtils“ ir „Dialogs“ moduliai. Norint atsikratyt kai kuriais moduliais, galima tiesiog į savo programą nusikopijuoti jame esantį naudojamos funkcijos aprašą. Tačiau tai ne visada labai padeda. Ką tokiu atveju daryti? Naudoti konsolines programas? Nešiuolaikiška… Iš naujo išradinėti dviratį? Būtent!
Konsolinių programų beveik niekas nebevartoja, tačiau ir Windows programos gali būti tokios pat greitos ir užimti labai mažai vietos, dėl to reikia viską kurti iš pradžių. Prie to labai dažnai grįžta programuotojai. Čia naudojamos jau ne standartinės Object Pascal funkcijos, o WinAPI. Paprastas programos langas kurtas Delphi vizualinės aplinkos pagalba užima apie 500Kb, o WinAPI pagalba – 20Kb.
WinAPI programavimas – ne kiekvienam, kadangi reikalauja nemažai žinių ir darbo. Aš jus šiek tiek supažindinsiu su WinAPI ir sukursiu paprastą langą.
WinAPI programos (taip jas vadinsiu, nors tai nėra geras variantas) naudoja pagrinde du modulius – Windows ir Messages. Windows modulio pagalba bus kuriamas langas, o Messages pagalba bus “gaudomos” operacinės sistemos žinutės. Taigi jungiame File->New->Other ir renkamies Console Application. Beliko viską ištrint ir pradėt savo kodą.
Kiekvienoje WinAPI programoje turi būti lango procedūra. Lango procedūra – tai funkcija, kurioje vykdomos programos reakcijos į įvairias jai siunčiamas žinutes. Funkcijos grąžinamas tipas yra LResult. Ši funkcija privalo turėti keturis parametrus, o atrodo viskas taip:
function WndProc(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): lResult; begin end;
Pirmasis parametras – rodyklė į langą. Jis labai svarbus, kadangi programa gali turėti kelis langus. Antrasis parametras – žinutė, t.y. kintamasis, kuris laiko žinutę vėliau perduodamą pačiai programai, kad ta galėtų sureaguoti į ją. Trečias ir ketvirtas parametrai priklauso nuo žinutės. Visos žinutės prasideda priešdėliu „WM“ (Windows Message), ir dabar kaip tik vieną pridėsim.
function WndProc( wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM ): lResult; stdcall; begin if Msg = WM_DESTROY then begin PostQuitMessage( 0 ); Result:= 0; end else Result:= DefWindowProc(wnd, Msg, wParam, lParam); end;
Žinutė vadinasi WM_DESTROY ir yra naudojama, kai programą reikia „sunaikinti“ (kitaip tariant, uždaryti). Kaip veikia ši visa funkcija? Ji gauna rodyklę į langą, su kuria reikia atlikti veiksmus, ir žinutę, į kurią reikia sureaguot. Jei ši žinutė bus WM_DESTROY, tada mes sėkmingai uždarysime programą PostQuitMessage pagalba. Kadangi įvairių žinučių yra šimtai, likusių mes nenagrinėsime ir programa į jas reaguos default būdu. Tam tereikia iškviesti DefWindowsProc funkciją (Default Window Procedure), kuri į likusias žinutes reaguoja pagal nutylėjimą.
WinAPI programos kūrimas susideda iš šių keturių dalių:
- 1. Lango savybių nustatymas
- 2. Lango kūrimas
- 3. Lango registravimas operacinėje sistemoje
- 4. Lango rodymas ekrane
Programa turi daug savybių, tokių kaip lango stilius, ikona, lango spalva, kursorius ir t.t. Visa tai aprašoma programos klasėje, kuriai sukūriau kintamąjį Wc (ne nuo „WC“, o nuo „Window Class“ ;). Nurodžius visas savybes, programą reikia užregistruoti operacinėje sistemoje RegisterClassEx pagalba. Klasė nurodo pagrindines programos savybes, bet šiai programai langas kuriamas atskirai CreateWindowEx pagalba, taip pat nurodant lango savybes (dydis, antraštė ir pan). Sukūrus langą, jį reikia parodyti ekrane ShowWindow pagalba ir kaskart atnaujinti UpdateWindow pagalba. Atnaujinimas reikalingas, kad langas būtų perpiešiamas, keičiant jo dydį ir pan. Tada jau prasideda ciklas, kuriame yra gaudomos ir perduodamos žinutės. Pačioje pabaigoje – išėjimas iš programos.
Tai WinAPI programos kūrimo principai. Į patį kodavimą nesileisiu, tad štai visas kodas.
uses Windows, // Darbui su langu Messages; // Darbui su žinutėmis const WndClass = 'WndApi'; // Programos klasės pavadinimas WndCaption = 'Sveiki!'; // Lango antraštė var Wc: TWndClassEx; // Kintamasis klasės apibūdinimui Wnd: HWND; // Rodyklė į langą Msg: TMsg; // Čia bus laikomos žinutės function WndProc( wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM ): lResult; stdcall; begin if Msg = WM_DESTROY then begin PostQuitMessage( 0 ); // Programos uždarymas Result:= 0; end else Result:= DefWindowProc(wnd, Msg, wParam, lParam); end; begin with Wc do begin Style:= CS_VREDRAW or CS_HREDRAW; // Lango stilius hIcon:= LoadIcon( 0, IDI_APPLICATION ); // Programos ikona hIconSm:= LoadIcon( 0, IDI_APPLICATION ); // Mažoji ikona (esanti antraštėje) hCursor:= LoadCursor( 0, IDC_ARROW ); // Kursorius hInstance:= hInstance; // Programos pavyzdys cbSize:= SizeOf( WndClassEx ); // Struktūros dydis cbClsExtra:= 0; // Papildoma atmintis, naudojama Windows cbWndExtra:= 0; // Papildoma atmintis, naudojama Windows hbrBackground:= HBRUSH( COLOR_BACKGROUND ); // Fonas lpszMenuName:= nil; // Meniu pavadinimas (dabar meniu nėra) lpszClassName:= WndClass; // Klasės pavadinimas lpfnWndProc:= @WndProc; // Rodyklė į lango procedūrą end; RegisterClassEx( Wc ); // Klasės registravimas Wnd:= CreateWindowEx( 0, WndClass, WndCaption, WS_OVERLAPPEDWINDOW, 10, 10, // Lango pozicija 640, 480, // Lango dydis 0, 0, hInstance, nil ); ShowWindow( Wnd, CmdShow ); // Rodome langą UpdateWindow( Wnd ); // Atnaujinam langą // Darbo su žinutėmis ciklas While GetMessage( Msg, 0, 0, 0 ) do begin TranslateMessage( Msg ); DispatchMessage( Msg ); end; Halt( Msg.wParam ); // Išėjimas end.
Programa tikrai veikianti ir diske užima 15Kb.
2007-05-22 | 15:35
uoj vargas su tuom winapi. kai buvo dalykas univere po keletos pirmu paskaitu supratau,kad bergzdzias su tuom reikalas,nes reikia skirt begale laiko ir pastangu
2007-05-23 | 15:59
Taciau dazniausiai visa tai pasiteisina, kadangi taip igyjama visiska programos kontrole.
2007-05-24 | 11:41
visiška programos kontrolė - ir vėžliška programos kūrimo eiga.. :)
2008-04-04 | 20:12
Nors ir vėlokai rašau, bet gal kas dar pamatys šį kometarą :)
Kaip šį reikalą pritaikyti prktiškai, ta prasme, kaip toliau delphi’je programuoti turint šį šabloną? Tarkim, kaip kūriami mygtukai, koks formos pavadinimas ? Ar čia jau skaitosi nebe delphi o WinApi?
2008-05-26 | 10:06
tik nereikia lialia apie stulbinanti c++ pranasuma pries delphi. pats ilga laika programinau assembler/pascal/delphi ir kazkiek bovinaus po c/c++ tai kodo ilgis tose pat salygose yra +/- 20-30% (neretai i pascal nauda), o greiciu tikrai neatsilieka 20 kartu. aisku jei lygint su iline/macros tai c/c++ laimi, bet ne kodo ilgiu. o jei lygint assembler ir c/c++ tai cia assembler is vis tada dievas.
P.S. teisingiausia butu sakyt: tie, kas nepatyre programavimo ZX Spectrum/Micro 80/IBM PC x88 tai nesugeba rasyt greito ir kokybisko kodo/formu po delphi/c++builder/m$ visualc/visual basic ir t.t.