/**************************************************************************** PROGRAM: whello.c Project: whello.c, whello.def EDITOR: Vesa Lappalainen malliohjelmien mukaisesti DATE: 10.8.1992 PURPOSE: "Pienin Windows-ohjelma". Tulostaa näyttöön tekstin Hello World tai sen tekstin, mikä on annettu ohjelman kutsun yhteydessä (esim. whello Terve!). Lisäksi tulostetaan esimerkin vuoksi esiintymän kahva (kokonaisluku) ja mahdollisen edellisen esiintymän kahva. FUNCTIONS: WinMain() - kutsuu alustuksia ja pyörittää viestisilmukkaa (tätä nimeä ei saa vaihtaa, muiden funktioiden nimet saa vaihtaa, kunhan vaihtaa kaikkialta). InitApplication() - alustaa ikkunaluokan InitInstance() - luo pääikkunan MainWndProc() - käsittelee viestit ----------------------------------------------------------------------------- Ohjelman periaate: Käyttäjä: | | WHELLO: | |-------------| ======= | | -+----------> WinMain | | Windows | InitApplication (kerrotaan MainWndProc) | | systeemi | InitInstance |-----+---> <+------------- GetMessage (W) <-------| viesti- | |------------->TranslateMessage (W) | silmukka | -----<+------------- DispatchMessage (W) | | | |----------------------o---------------- | | | | | | viesti | |--->-+----------> MainWndProc | <+------------- näyttöön piirtäminen tai muu toimenpide | | ja viestin kuittaus (W) | | |-------------| ----------------------------------------------------------------------------- COMMENTS: Windowsissa voi sama ohjelma olla käynnissä useita kertoja (esiintymä, instance). Windows-funktiot on alunperin kirjoitettu Pascalmaisiksi, joten ne täytyy esitettä avainsanalla Pascal. Muuttujien ja tyyppien nimeämisperiaatteita: h - alkuiset : kahvoja (Handle), kahva on kokonaisluku, jonka perusteella systeemi osaa valita jollekin toiminnalle oikean kohteen. wnd : ikkuna (WiNDow) dc : laiteyhteys (Device Context) ch : merkki (CHar) sz : NUL-loppuinen merkkijono (String Zero) p : osoitin (pointer) lp : pitkä (far) osoitin (Long Pointer) fn : funktio (FuNction) st : merkkijono (STring, yleensä sz) a : taulukko (Array) n : lukumäärä (couNt) c : lukumäärä (Count) b : tavu (Byte) f : lippu (Flag) WM_ : ikkunan viesti (Window Message) CM_ : komento viesti (Command Message) WC_ : ikkunan luonti (Window Create) WS_ : ikkunan tyyli (Window Style) msg : viesti (MeSsaGe) cmd : komento (CoMmaD) def : oletus (DEFault) br : sivellin, tyyli (BRush) cls : luokka (CLaSs) Esim: hDC : kahva ikkunan laiteyhteyteen cbClsExtra : luokan ylimääräisten tavujen lkm hbrBackground : kahva taustan värin siveltimeen lpszMenuName : far-osoitin Menun nimi-merkkijonoon (C-tyyli) ****************************************************************************/ #include /* Tarvitaan kaikissa Windows C-ohjelmissa */ #include #include /* Tämä ohjelma tarvitsee nämä */ #include #define MAINWNAME "WHelloWClass" /* Tunniste, jolla ikkunaluokka tunnetaan*/ /* Tämän ohjelman tarvitsemia globaaleja muuttujia: -----------------------*/ LPSTR lpCallText = "Hello World"; /*Osoitin näyttöön tulost. tekstille */ HINSTANCE hPrev; /* Edellisen esiint.nro vain näyttöön tulostamiseksi*/ /**************************************************************************** FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) PURPOSE: Käsittelee pääikkunalle tulevat viestit MESSAGES: WM_PAINT - piirrä ikkuna uudelleen WM_DESTROY - hävitä ikkuna ja lopeta ohjelma COMMENTS: Ohjelman näyttöön tulostus on tässä funktiossa ja sitä kutsutaan kun tulee viesti WM_PAINT. Mikäli näin ei tehtäisi, vaan tulostus olisi esim. fuktiossa InitInstance, niin teksti kyllä tulisi näyttöön, muttei piirtyisi uudelleen kun ikkuna peitettäisiin tilapäisesti jollakin toisella ikkunalla! Monimutkaisemmassa ohjelmassa täytyy pitää kirjaa siitä, mitä näyttöön on tulostettu, jotta ikkuna osataan piirtää uudelleen WM_PAINT viestin tullessa. Näyttöön piirtämistä varten täytyy luoda ikkunan näyttöyhteys (display context), joka pitää hävittää kun piirtäminen lopetetaan. ****************************************************************************/ LONG CALLBACK _export MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; /* BeginPaintin palauttama struktuuri, mm laiteyhdeyden*/ /* kahva hdc (handle device context) */ char st[80]; HINSTANCE hInst; /* Esiintymien numerot vain näyttöön tulostamiseksi */ HINSTANCE hpInst; switch (message) { case WM_PAINT: /* Tulostetaan näyttöön haluttu teksti ja tämän sekä */ /* edellisen esiintymän numerot, eli kahvat. */ if ( BeginPaint(hWnd,&ps) ) { TextOut(ps.hdc, 10, 10, lpCallText, _fstrlen(lpCallText) ); hInst = GetWindowInstance(hWnd); sprintf(st,"Tämä kutsu: %d (0x%08X), edellinen kutsu %d (0x%08X).", hInst,hInst, hPrev,hPrev); TextOut(ps.hdc, 10, 30, st, strlen(st) ); #ifndef __WIN32__ /* Huom! 2x _ */ hpInst = (HINSTANCE)GetClassWord(hWnd,GCW_HMODULE); #else hpInst = (HINSTANCE)GetClassLong(hWnd,GCL_HMODULE); #endif sprintf(st,"Ohjelma: %d (0x%08X).",hpInst,hpInst); TextOut(ps.hdc, 10, 50, st, strlen(st) ); EndPaint(hWnd,&ps); return NULL; } break; case WM_DESTROY: /* Viesti: ikkuna hävitetään */ PostQuitMessage(0); return NULL; default: /* Antaa Windowsin käsitellä muut */ break; } return DefWindowProc(hWnd, message, wParam, lParam); } /**************************************************************************** FUNCTION: InitInstance(HANDLE, int) PURPOSE: Luo ja näyttää pääikkunan COMMENTS: Tätä funkiota kutsutaan jokaista ohjelman käynnistyskertaa (esiintymää, instance) varten, jotta käynnistyskerran ikkunan tietous saadaan talteen. Tätä funktiota kutsutaan jokaisen uuden esiintymiskerran aluksi, eli sellaisten asioiden alustamiseksi, jotka ovat omia kullekin esiintymiskerralle. Tässä tapauksessa luodaan ja näytetään pääikkuna. ****************************************************************************/ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; /* Pääikkunan kahva */ /* Luodaan pääikkuna tätä esiintymää varten. */ hWnd = CreateWindow( MAINWNAME, /* Tunnus jota RegisterClass() käytti */ "Windows Hello", /* Ikkunan otsikoksi tulostuva teksti */ WS_OVERLAPPEDWINDOW, /* Ikkunan tyyli (tavallinen) */ CW_USEDEFAULT, /* Oletus x-paikka */ CW_USEDEFAULT, /* Oletus y-paikka */ CW_USEDEFAULT, /* Oletus leveys */ CW_USEDEFAULT, /* Oletus korkeus */ NULL, /* Pääikkunalla ei ole isä-ikkunaa */ NULL, /* Mitä menua käytetään */ hInstance, /* Tämä esiintymä omistaa ikkunan */ NULL /* Tässä ei tarvita tätä osoitinta. */ ); /* Jollei ikkunalle saatu kahvaa, palautetaan epäonnistuminen: */ if ( !hWnd ) return 1; /* Näytetään ikkuna ja lähetetään WM_PAINT-viesti: */ ShowWindow(hWnd, nCmdShow); /* Näytetään ikkuna */ UpdateWindow(hWnd); /* Lähetetään WM_PAINT viesti */ return 0; } /**************************************************************************** FUNCTION: InitApplication(HANDLE) PURPOSE: Alustaa ikkunan tiedot ja rekisteröi ikkunaluokan COMMENTS: Tätä funktiota kutsutaan vain kerran, vaikka ohjelmasta olisi pyörimässä useampia esiintymiä. Tässä funktiossa tehdään ne alustukset, joita saa tehdä vain 1. esiintymälle. Nyt alustetaan ikkunan luokka täyttämällä ikkunatietue ja kutsumalla ikkunan rekisteröintiä RegisterClass(). Koska kaikki esiintymät käyttävät samaa ikkunaluokkaa, riittää kutsun tekeminen vain yhden kerran. ****************************************************************************/ BOOL InitApplication(HINSTANCE hInstance) { WNDCLASS wc; /* Täytetään ikkunan luokkatietue tiedoilla, jotka kuvaavat pääikkunaa */ wc.style = NULL; /* Oletustyyli */ wc.lpfnWndProc = MainWndProc; /* Ikkunaluokan viestit käsit. funktio */ wc.cbClsExtra = 0; /* Ei muuta dataa tälle luokalle */ wc.cbWndExtra = 0; /* Ei muuta dataa ikkunalla */ wc.hInstance = hInstance; /* Ohjelma, joka omistaa luokan */ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Ohjelman ikoni; oletus */ wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Ohjelman kursori; oletus*/ wc.hbrBackground = GetStockObject(WHITE_BRUSH); /* Taustan tyyli */ wc.lpszMenuName = NULL; /* Ei menuja tässä ohjelmassa */ wc.lpszClassName = MAINWNAME; /* Luokan tunnisteteksti, ks. */ /* CreateWindow */ /* Rekisteröidään luokka ja palautetaan sen onnistuminen. */ return RegisterClass(&wc) == NULL; } /**************************************************************************** FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) PURPOSE: Kutsuu alustuksia ja huolehtii viestisilmukasta COMMENTS: Windows löytää tämän funktion nimen perusteella (WinMain), joten tämän funktion nimeä EI SAA MUUTTAA. Tämän funktion tulee alustaa tarvitavat yleiset resurssit ja aina alustaa esiintymäkohtaiset (instance) resurssit. Tämän jälkeen ylläpidetään esiintymän viestisilmukkaa. Silmukan tulee päättyä kun GetMessage paluttaa arvon 0. Tämä tapahtuu, kun on kutsuttu funktiota PostQuitMessage. Paluussa pitää palauttaa PostQuitMessage()-funktion palauttama arvo (joka on valmiina viestissä). Mikäli funktiosta pitää poistua ennen viestisilmukkaa, palautetaan arvo 1. ****************************************************************************/ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; /* Viesti */ /* Jos ohjelman kutsussa on ollut parametrejä, niin talletetaan ne */ if ( *lpCmdLine ) lpCallText = lpCmdLine; hPrev = hPrevInstance; if ( !hPrevInstance ) /* Onko muita esiintymiä käynnisssä? */ if ( InitApplication(hInstance) ) /* Alustetaan yhtesiset osat: */ return 1; /* Pois jollei alustus onnistu */ /* Alustukset jotka tulevat jokaiselle esiintymälle: */ if ( InitInstance(hInstance, nCmdShow) ) return 1; /* Pyöritetään viestisilmukkaa kunnes ohjelmasta halutaan pois */ while (GetMessage(&msg, /* Viestitietue */ NULL, /* Minkä ikkunan viestejä tulkitaan; ohjelman kaikkien */ NULL, /* Ensimmäisen tulkittavan viestin nro */ NULL)) /* Viimeisen tulkittavan viestin nro */ { TranslateMessage(&msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(&msg); /* Lähetetään viesti ikkunalle */ } return msg.wParam; /* Palautetaan PostQuitMessage-funktion arvo */ }