/**************/ /* checker.c */ /***************************************************************************** MODULE: checker.c PURPOSE: Aliohjelmakirjasto moniajon toteuttamiseksi. (Tämä on vielä pahasti prototyyppiasteella!) AUTHOR: Vesa Lappalainen 10.9.1992 ja tulostus 30.10.1992 siirretty omaksi tiedostoksi 3.11.1992 USAGE: Kirjaston käyttämiseksi tarvitaan projektiin tiedostot: ALI\checker.c ALI\tulostus.c - jos halutaan tulostaa! ja #includeen: chekcer.h tulostus.h - jos halutaan tulostaa! Jollei tulostusta haluta, pitää määritellä vakio NOT_PRINTER Aliohjelmakirjaston käyttämiseksi pitää ohjelmoijan tehdä ohjelmaansa seuraavat muutokset: 1) lisättävä piirron pitkiin silmukoihin kutsu ---------------------------------------------- if ( CheckMessage() ) lopetetaan_piirto...; 2) lisättävä ikkunafunktioon ennen muiden viestien käsittelyä koodi: --------------------------------------------------------------------- CHECK_CHECKER_WIN(hWnd,message,wParam,lParam); tai dialogin ikkunafunktioon vastaavasti: CHECK_CHECKER_DIALOG(hWnd,message,wParam,lParam); HUOM! Nämä ovat makroja, jotka saattavat poistua ikkunafunktiosta heti samasta paikasta. 3) lopettettava piirtäminen EndPaint viestin sijasta kutsulla ------------------------------------------------------------- CheckEndPaint(hWnd,&ps); 4) lisättävä viestisilmukan loppuun ----------------------------------- while (GetMessage(&msg,NULL,NULL,NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); CheckDelayMessages(hWnd); /* Moniajo tarvitsee! ------------------------- } (CheckDelayMessages(hWnd) sijaan voidaan kutsua myös CheckEndPaint(hWnd,NULL), joka tekee saman asian. Tarvitaan jos on tiedosssa vain CheckEndPaintin osoite, esim tabhand.c) Tulostuksen takia moniajon tarkistuksessa pitää valvoa myös GlobalPrinter.Printing -lippua, jottei rekursiivisesti kutsuta piirto-ohjelmaa! Tästä seuraa se, että myös WM_PAINT -viesti pitää muuttaa viivästytesti suoritettavaksi. Jos ohjelma yritetään sulkea kesken toiminnon, jää sulkeminen odottamaan kunnes toiminto on valmis TAI saatu keskeytetyksi! Viivästytetystä sulkemisesta tulee viesti käyttäjälle ikkunan otsikkoon. ============ Aliohjelmat: (checker.c, checker.h) ============ CheckMessage() - halutaanko keskeyttää IsCheckingMessage(hWnd,message,wParam,lParam) - onko keskeyttäjän viesti CheckEndPaint(hWnd,&ps) - lopetetaan piirto CheckDelayMessages(hWnd) - onko viivästettyjä viestejä ============================= Aliohjelmien tarkempi kuvaus: ============================= ---------------------- int CheckMessage(void) - halutaanko keskeyttää ---------------------- Tämä funktio antaa aikaa muille ohjelmille suoritusta varten. Samalla se tutkii pitääkö piirtäminen lopettaa vai ei. Palauttaa: 0 = ei haluta keskeyttää 1 = halutaan keskeyttää ----------------------------------------------------------------------------- int IsCheckingMessage(HWND hWnd,unsigned message,WPARAM wParam,LPARAM lParam) ----------------------------------------------------------------------------- Funktiolla tutkitaan kuuluuko viesti keskeyttäjälle ja jos kuuluu, niin miten viesti on käsiteltävä jatkossa. Palauttaa: 0 = viesti ei kuulu keskeyttäjälle ja käsitellään normaalisti omassa ikkunafunktiossa 1 = viesti kuului keskeyttäjälle ja se on käsitelty täysin ikkunafunktion kuuluu palauttaa että viesti on käsitelty (NULL ikkunafunktiossa ja TRUE dialogin ikkunafunktiossa) -1 = viesti kuului keskeyttäjälle ja se pitää antaa oletuskäsittelijälle jatkossa (DefWindowProc ikkunafunktiossa ja FALSE dialogissa) ---------------------------- void CheckEndPaint(hWnd,&ps) - lopetetaan piirto ---------------------------- Tätä funktiota täytyy kutsua EndPaint -funktion tilalla, jotta keskeyttäjä tietää onko piirtäminen saatu rauhassa tehdä loppuun vaiko ei. Tämän perusteella määrätään osaltaa seuraavien piirtojen piirtoaluetta. ----------------------------- void CheckDelayMessages(hWnd) - onko viivästettyjä viestejä ----------------------------- Tämä funktio sijoitetaan viestisilmukan loppuun ja se tarkistaa onko jäänyt viivästetysti suoritettavia viestejä käsittelemättä. Vikoja: - suunniteltu toistaiseksi vain yhdelle prosessille (ikkunalle) kerrallaan. Eli ainakaan DLL:ää tästä ei saa ilman muutoksia, (ikkunan kahva -kohtaiset muuttujat) - ongelmia wm_syncpaint-viestin kanssa, eli jos ikkunan ulkopuolella siirretään toista ikkunaa piirron aikana, niin piirtävä ikkuna saa VM_PAINT-viestin, vaikkei sen sisältö tuhoudukaan! (tätä ongelmaa ei ole Windows 3.0:ssa!?) *****************************************************************************/ //#include #ifndef NOT_PRINTER #include "tulostus.h" /* Jos tulostus halutaan */ #endif #include "checker.h" #ifdef _TULOSTUS #define CMChecking ( CM.Checking || GlobalPrinter.Printing ) /* Tulostus */ #else #define CMChecking ( CM.Checking ) #endif /****************************************************************************/ /* Tarkistajan globaaleja muuttujia: */ typedef struct { int Stop; /* Tarkistan halutaan aina ilmoittavan 1 */ int Close; /* Viivästetty ikkunan sulkeminen */ int Checking; /* Tarkistaja toiminnassa */ int next_big_paint; /* Seuraava piirto isona! */ } CM_type; static CM_type CM = {0,0,0}; #ifndef NOT_CHECKER /****************************************************************************/ int CheckMessage(void) { MSG msg; #ifdef _TULOSTUS if ( GlobalPrinter.Printing ) return GlobalPrinter.BreakPrinting; #endif CM.Checking = 1; while ( !CM.Stop && PeekMessage(&msg,0,0,0,PM_REMOVE ) ) { TranslateMessage(&msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(&msg); /* Lähetetään viesti ikkunalle */ } CM.Checking = 0; return CM.Stop; } #endif /****************************************************************************/ void CheckDelayMessages(HWND hwnd) /* Tarkistetaan viivästytetyt viestit. */ { if ( CM.Close ) { /* Onko viivästetty tuhoaminen??? */ CM.Close = 0; SendMessage(hwnd,WM_DESTROY,0,0); /* viiväst. tuhoaminen */ return; } if ( CM.next_big_paint ) { InvalidateRect(hwnd,NULL,TRUE); CM.next_big_paint = 0; return; } return; } /****************************************************************************/ static int DelayClose(HWND hWnd) /* Tuleeko viivästetty sulkeminen? */ { if ( CMChecking ) { /* Tällöin tulee viivästetty close! */ SetWindowText(hWnd,"Closing when ready! Wait...."); CM.Stop = CM.Close = 1; return 1; } return 0; } /****************************************************************************/ #ifndef __WIN32__ void #else BOOL #endif WINAPI CheckEndPaint(HWND hWnd, const PAINTSTRUCT FAR *ps) /* Tutkitaan saiko piirtää rauhassa hommansa loppuun. */ { if ( ps == NULL ) { /* Jotta CheckDelayMessage voidaan tehdä vaikka olisi */ CheckDelayMessages(hWnd); /* vain tämän funktion osoite käytössä! */ #ifndef __WIN32__ return; #else return TRUE; #endif } EndPaint(hWnd,ps); if ( !CM.Stop ) /* Jos sai rauhassa piirtää loppuun */ CM.next_big_paint = 0; #ifdef __WIN32__ return TRUE; #endif } /****************************************************************************/ int IsCheckingMessage(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) /* ** Tarkistajan osuus ikkunafunktiosta ** ** Palauttaa: ** 1 jos kutsuneen aliohjelman kuuluu palauttaa OK (eli viesti käsitelty) ** -1 jos kuuluu kutsua oletuskäsittelijää ** 0 jos viesti täytyy käsitellä normaalisti omassa aliohjelmassa */ { #pragma argsused #ifndef __BORLANDC__ #define SIZE_MINIMIZED SIZEICONIC /* Ainakin QUICK-C tarvitsee: */ #endif switch (message) { case WM_PAINT: /* Viesti: Piirrä ikkuna uudelleen */ /* Jos viestin tarkistuksen aikana tulee WM_PAINT viesti, niin */ /* silloin viestin tarkistukselle on syytä ilmoittaa, että */ /* lopettaa piirtämisen. Kuitenkin piirtämisen jäädessä kesken */ /* on seuraava piirtäminen mahdollisesti vajaa! Siis parasta */ /* piirtää koko kuva uudelleen! Koko kuvan piirto on onnistunut */ /* mikäli piirtoa ei ole häiritty! (vrt. CheckEndPaint) */ if ( CMChecking ) { CM.Stop = 1; CM.next_big_paint = 1; return -1; } CM.Stop = 0; break; case WM_SIZE: /* Jos ikkuna ikoniksi, ei kannata piirtää */ if ( wParam == SIZE_MINIMIZED ) CM.Stop = 1; break; case WM_CLOSE: /* Ikkuna halutaan sulkea! */ /* Jos viestin tarkistuksen aikana tulee WM_CLOSE viesti, pitää */ /* tarkistuksen pyytänyt ohjelma lopettaa ja päästä tekemään */ /* sulkeminen pääviestisilmukassa. */ if ( DelayClose(hWnd) ) return 1; break; case WM_DESTROY: /* Viesti: ikkuna hävitetään */ if ( DelayClose(hWnd) ) return 1; break; } /* Tähän loppuu "moniajon" vaatimat muutokset! */ /*------------------------------------------------------------------------*/ return 0; }