ALTE DOCUMENTE
|
||||||||||
félév folyamán a következõ témákkal fogunk foglalkozni:
I. A Windows Programozás alapjai
Bevezetés, eseményvezérelt programozás alapjai
Windows program felépítése, készítése, fordítása. Erõforrások (Menük, dialógus ablakok, ikonok, bitmappek, sztringek, stb...). Common dialógus ablakok(FileOpen, FileSave, Color, Font, Print setup, Find, Replace, stb..)
GDI(Graphic Device Interface), memória és fájlkezelés, DL 11111u2010l L-ek készítése.
DDE (Dynamic Data Exchange), OLE (Object Linking and Embedding), Help készítése
II. Windows Programozás Visual C++ környzetben
VC++ : elõnyei, lehetõségei.
Az MFC (MICROSOFT FOUNDATION CLASSES) szerkezete, elõnyei. Néhány osztály (CWinApp, CFrameWnd, CDocument, CView, CDialog, CFile, stb..) részletes tárgyalása.
Wizardok használata egy program készítéséhez.
Erõforrások kezelése.
Az elsõ részben tárgyalt elemek felhasználása a VC++-ban.
Irodalom:
Charles Petzold Programming Windows 3.1 (Angolul)
Könnyû a Windows-t programozni (Magyarul)
Windows 95 programozása C és C++ nyelven(Magyarul)
Windows Programming with Borland C++ (Angolul)
Microsoft VISUAL C++ 1.52 leírása: MFC Library volume 3 of 3 (Angolul)
VISUAL C++ Hargittai Péter-Kaszanyiczki László(Magyarul)
VISUAL C++ 2 Developer's Guide Naba Barkakati (SAMS kiadó) (Angolul)
VISUAL C++ Tutorials ( Developement system for Windows 95 and Windows NT)
Microsoft TechNet CD-k (Developer's Tools)
Microsoft Developement Studio online Books (Help)
I.
Windows programozás alapjai
A grafikus ferlhasználói felületek GUI (Graphical User Interface) a 70-es években láttak napvilágot. Az elsõ GUI rendszert a Xerox's Palo Alto Research Center (PARC) dolgozta ki. Ez a GUI volt a felülete az objektum orientált Smalltalk fejlesztési rendszernek.
A GUI fejlesztõi az objektum orientált programozás ideális eszközeinek tekintik a GUI rendszereket. A PARC rendszer után számos grafikus felület jelent meg, például: "Apple Lisa", "OS/2 presentation", "X-Windows ", stb...
A MICROSOFT Windows is egy ilyen GUI felületet biztosító program. Amikor kezdték a Windows fejlesztését az objektum orientált programozás még nem volt eléggé átgondolt és még nem volt annyira ismert, ezért a Windows-t procedurális nyelven írták meg (C nyelven ). Az elsõ windows verzió 1985-ben jelent meg, azóta számos változáson ment át.
Év |
Verzió |
Megjegyzés |
320 KB RAM |
||
Hasonlított az OS/2 Presentation managerre |
||
286 és 386 |
||
Real, Standard, Enhanced mod támogatása |
||
Standard, Enhanced mod támogatása |
||
Windows for WorkGroups 3.1 |
(Peer to Peer) hálózat támogatás |
|
(3.1 továbbfejlesztett változata) |
Ezek a verziók nem rendelkeztek saját fájl rendszerrel és mind 16 bitesek voltak. 1993-ban adta ki a Microsoft a Windows NT 3.5-t és utána az NT 3.51-t, ami igazi 32 bites multitaszkos operációs rendszer. Az NT-nek létezik ALPHA, MIPS és INTEL változata, azonban a PC világban nem tudta helyettesíteni a "Sima" Windows-t a Hardver igénye miatt. 1995-ben megjelent a Windows 95, ami igazi 32 bites operációs rendszer. A Microsoft 1996 nyárra tervezi az igéretes Windows NT 4.0-t, ami a jelenlegi hírek szerint a Windows 95 és az NT 3.51 ötvözete lesz.
A Windows egy olyan grafikus felületet biztosító program, amely lehetõvé teszi, hogy az alatta megírt programok párhuzamosan fussanak, üzeneteken keresztül kommunikáljanak egymással. A Windows a fájlkezelésen kívül az összes program menedzselési funkciót saját maga végzi. A fájlkezelés a Windows alatt mûködõ DOS operációs rendszer feladata.
A Windows mint bármilyen más DOS program, programként indítható. Amikor betöltõdik számos feladatot vesz át a DOS-tól.
A Windows-hoz van egy olyan program(kiegészítés), amely 32 bites réteget biztosít a Windows felett, ez a Win32s program. Ennek segítségével 32 bites applikációk is futtathatók a Windows alatt.
Elõnyei:
- Egyszerû, egységes kezelés
- hardver eszközök jobb kihasználása
- multitaszkos (nempreemptív)
- nagyon hasonlít más számítógépek operációs rendszeréhez
- hardver független programot írhatunk alatta
- esemény vezérelt
- stb...
Hátrányai:
- Nagy méret
- csak PC-n fut
- alacsony szintû I/O kezelés hiányossága.
Mivel a Windows alatt egyszerre több program fut, ezért rendet kell tennie a memóriában. Szükség esetén a Windows adat és kód blokkokat mozgat a memórián belül ( természetesen ez mind akkor igaz, ha mi engedélyeztük neki ezt a program megírása során). Ha nagy igény van a memóriára, akkor a Windows a nem használt blokkokat kiteszi a memóriából, és amikor újból szükség van rá, akkor tölti be az Exe fájlból. Egy program több példányban is futhat a Windows alatt úgy, hogy a kód egy példányban lesz jelen a memóriában és az adat annyiszor, ahány példány fut éppen.
A Windows programok általában egy futtatható exe fájlból és számos DLL (Dynamic Link Library)-bõl állnak. A DLL-ek olyan adat-, erõforrás- és függvény-gyûjtemények, amelyek dinamikusan töltõdnek be a memóriában, ha valamelyik applikáció hivatkozik rájuk, így nem linkelõdnek statikusan a programhoz. A futtatható fájl információt tartalmaz arról, hogy melyik DLL melyik függvényét fogja meghívni. Természetesen ezeknek a függvényeknek "exportáltan"(lásd késõbb) kell szerepelniük.
A Windows rendszer 3 részbõl áll:
KERNEL : ez a könyvtár fõleg a memória menedzselési funkciókat tartalmazza
USER : A felhasználói felületet biztosítja. Menük, dialógus ablakok, stb,...
GDI : A rajzolási rutinokat és az ezekkel kapcsolatos funkciókat tartalmazza.
API alatt a Windows alatt használt és a fent említett DLL-ekben definiált fõleg függvények, (változótípusok és konstansok) összességét értjük. Ezek az elemek nem nyelvfüggõek. Bármilyen Windows alatt használt programozási nyelvben alkalmazhatók (C, C++, MS-ACCESS, VISUAL BASIC, FOXPRO, stb).
Természetesen minden nyelvnek vannak saját változótípusai. Ezeken a "hagyományos" típusokon kívül vannak olyan típusok, amelyek windows specifikusok. A C nyelv esetén ezek a <windows.h> fájlban vannak definiálva. Ezek közül néhány: LONG, WORD, DWORD, LPSTR, HWND, HANDLE, LRESULT, stb... Számos struktúra típus is van, ezek közül néhányat említünk:
typedef struct tagPOINTPOINT
typedef struct tagMSG MSG;
typedef struct tagRECT RECT, stb...
Magyar jelõlési rendszer:
A Windows programozás során a változó neveket -Simonyi Károly nyomán- úgy szokás felvenni, hogy a név kezdõbetûi utaljanak a változó típusára. pl
b : char n :int
p : 16 bites pointer l :long
lp : 32 bites pointer,stb (Lásd 1. sz. melléklet mellek1.doc)
Kb. 6000 elõre definiált konstans van az API-ban. Ezeknek az a jellegzetessége, hogy az elnevezésük prefixumokkal (2, 3 nagybetû) kezdõdik. A prefixum utal az attributum jellegére. A prefixum után egy aláhuzás jel következik és utána jön maga a konstans nagybetûvel. Néhány példa illusztrációként (Lásd még az 1. sz. melléklet mellek1.doc):
CS : (Class Style) ablakosztály stílus CS_HREDRAW
IDI : (IDentifier Icon) ikon azonosító IDI_APPLICATION
IDC : (IDentifier Cursor) Kurzor azonosító IDC_WAIT
WS : (Window Style) ablak típus WS_ICONIC
CW : (Create Window) ablak létrehozás CW_DEFAULT
WM : (Windows Message) Windows üzenet WM_PAINT
DT : (Display Text) szöveg megjelenítés DT_CENTER
BM : (Box Message) Check- vagy RadioBox üzenete BM_GETCHECK
CB : (Combo Box) kombó doboz CB_GETCURSEL
LB : (List Box) lista doboz LB_SETCURSEL
EM : (Editor Message) editor üzenet EM_LIMITTEXT
CF : (Clipboard Format) vágólap formátuma CF_BITMAP
ERR : (ERRor) hibakódok, stb... ERR_CREATEDLG
Több mint 1000 API függvény van (lásd 1. sz. melléklet mellek1.doc). A függvények nevei általában több angol szóból állnak. A szavak elsõ betûje mindig nagybetû pl. SetWindowText(....). Természetesen a saját függvényeinket úgy nevezzük, ahogy akarjuk. Figyelembe kell venni, hogy a C nyelv különbséget tesz a nagy és a kis betû között (Case Sensitive). Ha ugyanazt az API függvényt akarjuk meghívni egy másik programozási nyelven pl. a BORLAND PASCAL-ban vagy VISUAL BASIC-ben vagy MS-ACCESS-ben, akkor nem kell különbséget tenni a kis és a nagy betû között, de érdemes (esztétikailag) úgy írni a függvény nevét, ahogy a C-ben írjuk és ahogy szerepelt a gyûjteményben.
Az API függvények FAR PASCAL típusúak. A FAR jelzõ azt jelenti, hogy távoli hívás (más kódszegmensben levõ program is elérheti õket) és a PASCAL jelzõ azt jelenti, hogy a függvényhívás a Pascal konvenció szerint történik. Mint ismeretes a Pascal konvenció azt jelenti, hogy a függvény paraméterei a deklarálási sorrendjükben kerülnek a stack-be és a stack kiûrítése (takarítása) a hívott függvény feladata. A Win32s és a Windows'95 alatt (Win32c) a FAR PASCAL elnevezés helyett a WINAPI jelzõ használatos. A Windows'95 támogatja a sík modellû (flat model) memóriakezelést, ezért a FAR jelzõ nem szükséges. Vannak olyan kitüntetett szerepû függvények, amelyeket az operációs rendszer hív meg (jelen esetben a Windows !) ezeket a függvényeket CALLBACK függvényeknek nevezzük. A CALLBACK függvényeknek FAR PASCAL típusuaknak kell lenniük és "exportálni" kell õket, hogy a Windows meg tudja hívni. Az exportálás kétféleképpen történhet: vagy felsoroljuk õket a definiciós fájl (lásd késõbb) EXPORTS szekciójában, vagy a függvény elé tesszük az _export jelzõt.
long FAR PASCAL _export EditDlgProc (HWND, UINT, UINT, LONG) ;
A Windows alatt futó programok futási menetét a felhasználói események határozzák meg. A program ezekre az eseményekre reagál. Egy programhoz több ablak tartozhat. Minden ablaknak van saját ablakkezelõ függvénye (CALLBACK függvény), amely gondoskodik az ablakhoz érkezõ események kezelésérõl. Ebbõl adódik, hogy egy Windows programban legalább egy ablakkezelõ függvény van. A felhasználói eseményeket (egér, billentyûzet, idõzítés, menü stb..) a Windows saját üzenet formátummá konvertálja. Az üzenet a következõket tartalmazza: a cimzett (ablak leíró HWND), az üzenet tárgya (UINT típusú szám), az üzenet tartalma(WORD wParam, LONG lParam), az üzenet keltének idõpontja és az üzenet keltésekor érvényes kurzor pozíció.
typedef struct tagMSG
MSG;
Mint említettem az elõbb, egyszerre több programot lehet indítani a Windows alatt. Aktív applikáció alatt azt az applikációt értjük, amely éppen elfogadja a felhasználói eseményeket. Egy applikáción belül aktív ablakról is beszélhetünk. A felhasználói eseményeket az üzenetté való konvertálása után a rendszer egy hosszú rendszer várakozási sorba (System queue) helyezi el. Minden futó applikációhoz tartozik egy üzenet sor (Message queue). A system queue -ba érkezõ üzenetek továbbításra kerülnek az applikációk üzenet soraiba (1. ábra). Az applikáció maga gondoskodik az üzenet kiszedésérõl és feldolgozásáról.
Egy tipikus Windows program a következõ részekbõl áll:
- Inicializálás: ebben a részben történik az ablak osztály regisztrálása a rendszerben és a változók inicializálása.
- A fõablak létrehozása.
- Az üzenetkezelõ ciklus (kiolvassa a várakozási sorból az üzeneteket és továbbítja a Windowsnak, hogy ezekkel a paraméterekkel hívja meg az ablakkezelõ függvényt.
A fõablak kezelõ függvénye (Window procedure): az üzenetekre való reagálás
A kilépés elõtti takarítás, kilépés.
Tehát majdnem minden windows programunk a következõképpen fog kinézni:
#include <windows.h>
#include <másfájlok.h>
#include "myfiles.h"
#define ....
// globális változók deklarálás
WinMain(.............................)
return msg.wParam;
// Ablak kezelő függvény
LONG CALLBACK _export MyWP(HWND hwnd,UINT msg,WPARAM wParam, LPARAM lParam)
return 0;
case WM_DESTROY:
memóriafelszabaditas() // pl. memória felszabadítás
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
Mint tudjuk a C nyelvben a main() függvény a belépési pontja a programnak. A Windows alatt a main függvény helyet a WinMain-t kell használni. Az API elemek a windows.h-ban vannak deklarálva ezért a program elején be kell "inkludolni" a "windows.h" fájlt.
Mint látható a fenti példában a üzenetkezelõ ciklus 3 részbõl áll (természetesen más is lehet benne). Az elsõ az üzenet kiolvasása a sorból, ezután az üzenet konvertálása és az üzenet továbbítása a Windowsnak, hogy ezekkel a paraméterekkel hívja meg az ablakkezelõ függvényt. A sor hossza alapértelmezésben 8. De ezt az értéket növelhetjük a
SetMessageQueue(int n)
fügvénnyel, ahol n maximális értéke 120. Ez a függvény új sort hoz létre és megsemmisíti az elözõt. Csak az ablak létrehozása elött szabad meghívni!
Az üzenet kiolvasására két API függvény létezik az egyik a GetMessage, a másik a PeekMessage.
BOOL GetMessage(MSG FAR *lpMsg,HWND hWnd,WORD wMinFilter,WORD wMaxFilter)
Ha a függvény talál a sorban üzenetet, akkor azt kiveszi, ha nem, akkor vár és visszaadja a vezérlést a Windowsnak. A Windows ilyenkor átkapcsol egy másik applikációra, amelynek a várakozási sorában vannak üzenetek. Ez képezi a Windows nonpreemptív multitaszkos (nem elõre megszerzett jogokon alapuló többfeladatos) jellegét. Egyszerre csak egy program futhat, ez az aktív applikáció. A nem aktív applikációk mûködése addig van felfüggesztve, amíg az aktív applikáció vissza nem adja a vezérlést a Windowsnak.
A függvény elsõ paramétere egy MSG struktúrára mutató long pointer, ide kerül az üzenet a várakozó sorból. A másik három paraméter szûrési célokra használható. A hWnd jelzi, hogy melyik ablak üzeneteire vagyunk kíváncsiak. A wMinFilter azt az értéket adja meg, amelynél csak nagyobb értékû üzenetekre vagyunk kíváncsiak. Hasonló célt szolgál a wMaxFilter paraméter, de maximumra. Az utóbbi paraméter hasznos lehet az egér és billentyûzet események esetén, hiszen ha valaki folyamatosan nyom egy billentyût, elõfordulhat, hogy ennyi idõ alatt nem kerülnek feldolgozásra ezek az üzenetek, ilyenkor ha ennek a paraméternek (WM_KEYFIRST, WM_MOUSEFIRST, WM_KEYLAST, WM_MOUSELAST) értéket adunk, akkor csak az elsõ vagy az utolsó eseményt veszi figyelembe.
Ha a függvény WM_QUIT (kilépési) üzenetet talál a sorban, akkor FALSE-szal tér vissza különben TRUE értékkel.
A PeekMessage hasonló funkciót lát el mint a GetMessage azzal a különbséggel, hogy nem vár az üzenetre a visszatérés elõtt. Ennek a függvénynek újabb UINT típusú paramétere is van. Ez a paraméter az üzenetek kezelésére szogálhat (maradjon az üzenet a sorban a feldolgozás után vagy sem , ne adja vissza a vezérlést a Windowsnak). A függvény visszatérési értéke attól függ, hogy talált-e üzenetet vagy sem.
Az applikációhoz érkezõ üzenetek átalakíthatók. Erre általában billentyûzet események esetében van szükség. Erre a célra a TranslateMessage függvényt lehet használni. A függvény a WM_KEYDOWN és WM_KEYUP közé beszúr egy WM_CHAR üzenetet. A WM_CHAR üzenetre akkor van szükségünk, ha a lenyomott billentyûhöz tartozó karakterre vagyunk kívancsiak.
BOOL TranslateMessage(const MSG FAR *lpMsg)
Miután kiolvastuk az üzenetet a sorból, ezt az üzenetet el kell juttatni az ablakkezelõ függvénynek. Mivel az ablakkezelõ fügvény CALLBACK függvény, ezért a Windowsnak kell továbbítani az üzenetet és a Windows hívja meg ezt a függvényt a megfelelõ paraméterekkel. Az üzenet továbbítására a DispatchMessage szolgál.
LONG DispatchMessage(const MSG FAR* lpMsg)
Amennyiben az üzenet WM_TIMER és a timer létrehozásakor egy timerkezelõ függvényt adtunk, akkor az üzenet hatására, ez a függvény hívódik meg és ez az üzenet nem továbbítódik az ablakkezelõ függvénynek.
Üzeneteket két féleképpen küldhetünk egy ablaknak. Vagy a várakozási soron keresztül vagy ennek elkerülésével. Az üzenetek két csoportba sorolhatók: az elsõ a "queued" , amelyek a várakozási sorba kerülnek, a másik a "nonqueued", amelyek elkerülik a várakozási sort.
Queued üzenetet a PostMessage függvénnyel küldhetünk, nonqueued-ot a SendMessage függvény segítségével.
PostMessage(HWND, UINT, WPARAM, LPARAM)
SendMessage(HWND, UINT, WPARAM, LPARAM)
Az üzenetek nem hasonlítanak a megszakításokhoz. Az egyik üzenet feldolgozását egy másik üzenet nem szakíthatja meg. Ennek elkerülésére használhatjuk a SendMessage-et úgy, hogy az üzenet feldolgozása közben egy másik üzenetet küldünk.
Általában egy Windows program a következõ fájlokat tartalmazza: egy definiciós(.def) fájl, egy erõforrás fájl (.rc) és legalább egy forrás fájl (C vagy CPP).
A programozási nyelvek új változatai szinte kivétel nélkül rendelkeznek saját fejlesztési környezettel. Pl. a Borland C++ esetén az IDE környezet, ami rendelkezik, editorral, Debugerrel, stb.. és resource editorként a WorkShop használható. A Visual C++ esetén szintén hasonló a helyzet más elnevezésekkel.
Az erõforrás fájl (.rc) az erõforrás editorral beállított adatokat tartalmazza. Tulajdonképpen ez egy text fájl, amely bármilyen text editorral is szerkeszthetõ csak vigyázni kell a szintaktikajára. Általában ikonokat, kurzorokat, bittérképeket, sztring táblákat, menüket, dialógus ablakokat tartalmaz. Ezeknek az erõforrásoknak a kezelésérõl a program maga gondoskodik. Minden erõforrás elemhez tartozik egy azonosító, amire hivatkozunk a programban.
A definiciós fájl beállításokat tartalmaz a létrehozandó programról. Ebben a fájlban olyan adatok szerepelnek, amelyek alapján dönt a Windows, hogy pl. ennek a programnak a kód, illetve adat szegmense mozgatható-e a memórian belül vagy sem, illetve szükség esetén kitehetõ-e ideiglenesen a memóriából vagy sem. További beállításokat tartalmaz a stack és heap méretérõl. A program CALLBACK függvényeinek export típusra való beállítására is szolgál, amennyiben az említett függvények nevei elött nem szerepelt az _export jelzõ.
Példa 1
Írjunk egy Windows programot, amely kiírja a képernyõn a "Hello Windows" szöveget. A szöveg az ablak közepén jelenjen meg.
/*----- ----- --------------- Példa1.c ----- ----- ----------------*/
#include <windows.h>
long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG) ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,LPSTR lpszCmdParam, int nCmdShow)
hwnd = CreateWindow (szAppName, // Ablak osztály neve
"The Hello Program", // Ablak címe
WS_OVERLAPPEDWINDOW | WS_SYSMENU |WS_MINIMIZEBOX,// stílusa
CW_USEDEFAULT, // x pozició
CW_USEDEFAULT, // y pozició
CW_USEDEFAULT, // x méret
CW_USEDEFAULT, // y méret
NULL, // Szülő ablak leirója
NULL, // Menü leírója
hInstance, // Példány leírója
NULL) ; // Létrehozási paraméterek
ShowWindow (hwnd, nCmdShow) ; // Megjelenítés
UpdateWindow (hwnd) ; // Ablak újra rajzolása
while (GetMessage (&msg, NULL, 0, 0))
return msg.wParam ;
long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam,LONG lParam)
return DefWindowProc (hwnd, message, wParam, lParam) ;
;----- ----- -------Példa.DEF definició file----- ----- --------------
NAME HELLOWIN ;// Az elkészítendő EXE file neve
DESCRIPTION 'Hello ' ;// Ez az EXE file -ba kerül, általában a program neve
EXETYPE WINDOWS ;// Windows program
STUB 'WINSTUB.EXE' ; // Ha nem windows alól hívjuk, akkor hiba üzenet
CODE PRELOAD MOVEABLE DISCARDABLE
;// PRELOAD: a program aktivizálásakor a kód azonnal bekerül a memóriába
MOVEABLE: feljogosítja a windows-t arra, hogy ha szükséges, akkor ;megváltoztathatja a programkód
;// memóriabeli helyét
;// DISCARDABLE: feljogosítja a windows-t arra, hogy kitörölje a programot a memóriából, ;ha helyre van szüksége.Ilyenkor, ha újra szükség van a program kódjára, akkor az exe. file-;ból újra betöltődik
DATA PRELOAD MOVEABLE MULTIPLE
;// MULTIPLE: a program példányai saját adatterülettel dolgoznak.
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
|