/**************/ /* mdialog.c */ /**************************************************************************** MODULE: mdialog.c PURPOSE: Modeless ja modal dialogien käsittely. Kirjaston avulla modal ja modeless dialogien käyttö on yhteneväistä, eikä esim. dialogin funktiossa tarvitse miettiä kummastako tyypistä on kyse. AUTHOR: Vesa Lappalainen 15.7.1993 UPADTE: 2.12.1993/vl: DialogSethInastance ja Get - jotta voidaan tehdä isättömiä dialogeja 19.8.1994/vl: + DoClass.. ja kaikki ...Param -funktiot + makroja valmiin pääohjelman tekemiseksi + m-alkuiset funktiot (mm. mMessageLoop) 1.10.1994/vl + WC-loppuisia makroja ja näistä johtuvia aliohjelmien muutoksia (kuitenkin yhteensopiva edellisen kanssa), jotta luokan tietoihin voi vaikuttaa enemmän 15.10.1994/vl + mGetChildRect 22.10.1994/vl + muutoksi WC-loppuisiin fuktioihin ja makroihin 22.9.1995/vl + WC loppuisia Do...ParamWC dialogin luonteja, joiden avulla voidaan muuttaa dialogin ominaisuuksia ennen dialogin ilmenstymistä (esim. tyyliä), ks. lokaalin aliohjelman FindUserDialog kommentit USAGE: Kirjaston käyttämiseksi tarvitaan tiedostot: mdialog.c mdialog.h Aliohjelmakirjaston käyttämiseksi pitää ohjelmoijan tehdä ohjelmaansa seuraavat muutokset: 1) Luotava kaikki dialogit jollakin kutsuista DoModalDialog(hWnd, name, dialFunc); DoModelessDialog(hWnd, name, dialFunc); DoMultiModelessDialog(hWnd, name, dialFunc); DoModalDialogParam(hWnd, name, dialFunc,lParam); DoModelessDialogParam(hWnd, name, dialFunc,lParam); DoMultiModelessDialogParam(hWnd, name, dialFunc,lParam); DoClassDialogParam(hInstance,classname,iconname,hWnd,name,wndFunc,lParam); DoModelessDialogParamWC(hWnd, name, dialFunc,lParam,wcfunc); DoMultiModelessDialogParamWC(hWnd, name, dialFunc,lParam,wcfunc); DoClassDialogParamWC(hInst...iconname,hWnd,name,wndFunc,lParam,wcfunc); Modal - dialogin aikana muut saman ohjelman ikkunat eivät voi tulla aktiivisiksi Modeless - dialogeja voi olla käynnissä 0-1 kerrallaan, muut ikkunat voivat tulla aktiivisiksi MultiModeless - dialogeja voi olla 0-n kerrallaan, muut ikkunat voivat tulla aktiivisiksi. Dialogin funktio täytyy olla totetutettu siten, ettei sen staattiset muutujat häiritse muita saman dialogin esiintymiä. Käytänössä kaikki tieto voidaan tallettaa dialogin kenttiin ja siirtää sieltä ennen dialogin sulkemista pääohjelmaan jollakin sopivalla aliohjelmakutsulla. Toinen tapa on käyttää dialogin lokaalia muistia, ks DialogAlloc jne... ClassDialog - luodaan dialogille luokka ja käynnistetään dialogi MultiModeless-kutsulla Param - välitetään arvo viestin WM_INITDIALOG lParam:ksi. wcfunc - Dialogin asetuksia muuttvat funktio, ks. lokaalin aliohjelman FindUserDialog kommentit Jos halutaan käyttää hWnd = NULL, täytyy dialogeille kertoa ohjelman esiintymän kahva (pääohjelmassa) kutsulla DialogSethInstance(hInstance) 2) Dialogin loppuessa käytettävä kutsua: DestroyDialog(hDlg, retval); tai KillDialog(hDlg, retval); 3) Lisättävä viestisilmukkaan: while (GetMessage(&msg,NULL,NULL,NULL)) { if ( IsModelessMessage(&msg) ) continue; // Tämä lisää! ... TranslateMessage(&msg); DispatchMessage(&msg); } ( tai käytettävä kutsua mMessageLoop ) 4) Lisättävä ohjelman loppuun: FreeAllModeless(); 5) Jos halutaan käyttää lokaalia, jokaiselle dialogille omaa muistialuetta, pitää dialogin funktio kirjoittaa muotoon: typedef struct { ... } *pLocalStruct; BOOL CALLBACK _export DialogFunc(...) { pLocalStruct lp = (pLocalStruct)DialogLock(hDlg); ... if ( !lp ) { lp = (pLocalStruct)DialogAlloc(hDlg,sizeof(lp *)) if ( !lp ) return FALSE; lp->... = alustukset } ... switch (message) { ... viittauksia lp->... ... } DialogUnlock(hDlg); return ret_val; } Tosin usein poistumisen joutuu tekemään jopa goto-lauseella, aliohjelman loppuun, koska pelkälle return-lauseella DialogUnlock jää kunkin case-kohdan jälkeen muuten tekemättä. 6) About-tyylisten dialogien käsittelyyn on valmis funktio nimeltä MDialogAbout. Jos dialogi "About" luodaan kutsulla DoModalDialogParam(hWnd,"About",MDialogAbout,(LPARAM)&Version); missä static tVersionInfo Version = {IDC_VERSION,"Versio 0.2 10.8.1994"}; niin tämä funktio vaihtaa dialogin IDC_VERSION kohdassa olevaksi tekstiksi tekstin "Versio 0.2 10.8.1994". Näin versionumero voidaa säilyttää varsinaisessa pääohjelmassa tarvitsematta aina olla muuttamassa .RC-tiedostoa! Tätä ominaisuuttahan ei ole pakko käyttää ja MDialogAbout toimii hyvin pelkällä seuraavalla kutsulla DoModalDialog(hWnd,"About",MDialogAbout); Näin About-dialogien eteen ei tarvitse tehdä muuta kuin pelkkä "About"-niminen dialogi .RC-tiedostoon ja em. kutsu sitten sopivassa kohti ohjelmaa. MDialogAbout sopii tarvittaessa minkä tahansa dialogin tilapäis-funktioksi, kunnes varsinainen funktio "jaksetaan" rakentaa! ============ Aliohjelmat: (mdialog.c, mdialog.h) (M = makro) ============ HWND DoModalDialog(HWND, char *, PDIALOGPROC); (M) HWND DoModelessDialog(HWND, char *, PDIALOGPROC); (M) HWND DoMultiModelessDialog(HWND, char *, PDIALOGPROC); (M) HWND DoClassDialog(HINSTANCE,char *,char *,HWND,char *,WPR,DPR);(M) HWND DoModalDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoModelessDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoMultiModelessDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoClassDialogParam(HINSTANCE hInstance, char *classname, char *iconname, HWND hWnd, char *dialogname, WNDPROC MainWndProc, DLGPROC MainDlgProc, LPARAM lParam); HWND DoClassDialogParamCMD(HINSTANCE hInstance, char *classname, char *iconname, HWND hWnd, char *dialogname, WNDPROC MainWndProc, DLGPROC MainDlgProc, LPARAM lParam, int CmdShow, tWNDCLASSHandler wcHandler) int mRegisterWndClass(HINSTANCE hInstance, char *classname, char *iconname, WNDPROC MainWndProc, tWNDCLASSHandler wcHandler) void FreeAllModeless(void); int DestroyDialog(HWND, int); int KillDialog(HWND, int); int IsModelessMessage(MSG *); void *DialogAlloc(HWND hWnd,UINT size) void *DialogLock(HWND hWnd) BOOL DialogUnlock(HWND hWnd) BOOL DialogFree(HWND hWnd) void DialogSethInstance(HINSTANCE hInstance) HINSTANCE DialogGethInstance(HWND hWnd) BOOL CALLBACK _export MDialogAbout(HWND hDlg,unsigned message, WPARAM wParam,LPARAM lParam); LPARAM GetDialogCreateLParam(HWND hWnd); int mAddAccelerator(HWND hWnd,char *name); int mMessageLoop(void); int mIsAcceleratorMessage(MSG *msg); int mDeleteAccelerator(HWND hWnd); int mGetChildRect(HWND hWnd,int id,RECT *rc) ============================= Muut makrot: ============================= mDlgMAIN(accel,dial,fun) mClassDlgMAIN(dclass,icon,accel,dial,fun) ============================= Aliohjelmien tarkempi kuvaus: ============================= ---------------------- HWND DoModalDialog(HWND, char *, PDIALOGPROC); HWND DoModelessDialog(HWND, char *, PDIALOGPROC); HWND DoMultiModelessDialog(HWND, char *, PDIALOGPROC); HWND DoModalDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoModelessDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoMultiModelessDialogParam(HWND, char *, PDIALOGPROC,LPARAM); HWND DoClassDialogParam(HINSTANCE hInstance, char *classname, char *iconname, HWND hWnd, char *dialogname, WNDPROC MainDlgProc, LPARAM lParam); HWND DoClassDialogParamCMD(HINSTANCE hInstance, char *classname, char *iconname, HWND hWnd, char *dialogname, WNDPROC MainWndProc, DLGPROC MainDlgProc, LPARAM lParam, int CmdShow, tWNDCLASSHandler wcHandler) lisäksi samat makroina ilman Param-loppua ---------------------- Näillä funktiolla luodaan haluttu dialogi tyyppi. Palauttaa: NULL = dialogia ei voitu luoda kahva = dialogin kahva Modal-tapauksessa dialogin palauttama arvo. Parametrit: HWND hWnd = isäikkunan kahva (jos NULL, pitää olla käytetty kutsua DialogSethInstance) char *name = dialogin nimi PDIALOGPROC func = osoitin dialogin funktioon LPARAM lParam = Param-loppuisten funktioiden WM_INITDIALOG-viestille vietävä lParam arvo. int CmdShow = tapa miten ikkuna näytetään (SW_SHOW jos ei muuta keksi) tWNDCLASSHandler wcHandler = käsittelijä funktio, joka muuttaa ikkunaluokan ominaisuuksia, esim. void setwc(WNDCLASS *wc) { wc->style = CS_OWNDC;} Modeless-kutsut tallettavat dialogin tiedot sisäiseen tietorakenteeseen. DoMultiModelessDialog luo aina uuden dialogin esiintymän ja DoModelessDialog ottaa käyttöön entisen esiintymän, mikäli sellainen on DoClass.. = luo dialogin tarvitseman luokan ja synnyttää dialogin. Tämä on tarkoitettu niihi tilanteisiin, joissa dialogi esiintyy ohjelman pääikkunana. Kutsu voi esiintyä useasti samassa pääohjemassa. Kutsussa on kaksi funktiota, joista WNDPROC on ikkunaluokan oletusfunktio ja DLGPROC on dialogin funktio, jota kutsutaan, jos oletusfunktio ei käsitellyt viestiä. Esim. WM_CREATE-viesti saadaan vain WNDPROCille ja WM_INITDIALOG vain DLGPROCille. Tämän funktion avulla on tarkoitus päästä yksinkertaiseen pääohjelmaan, esim. tyyliin: -------------------------------------------------------------------------- int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { #pragma argsused HWND hWnd = DoClassDialog(hInstance,"DaDWClass","ikoni", NULL,"DaDSave",DefDlgProc,MainDlgProc); if ( !hWnd ) return 1; mAddAccelerator(hWnd,"Pika"); return mMessageLoop(); } -------------------------------------------------------------------------- Sama saadaan aikaan myös makrolla mClassDlgMAIN: mClassDlgMAIN("DaDWClass","ikoni","Pika","DaDSave",DefDlgProc,MainDlgProc) Pääohjelma luokattomille dialogeille saadaan kutsulla: mDlgMAIN("DaDSave","ikoni",MainDlgProc,"Pika") Tämän suurin vika on siinä, ettei saada ikonia pääikkunalle. ---------------------- int mRegisterWndClass(HINSTANCE hInstance, char *classname, char *iconname, WNDPROC MainWndProc, tWNDCLASSHandler wcHandler) ---------------------- Suorittaa ikkunaluokan rekisteröinnin. ---------------------- void FreeAllModeless(void); ---------------------- Tätä pitää kutsua ohjelma lopuksi (mikäli on käytetty yhdenkin kerran kutsua DoModelessDialog). Turhaan kutsuminen ei haittaa! ---------------------- int DestroyDialog(HWND, int); ---------------------- Tällä kutsulla poistetaan dialogi, kun sitä ei enää käytetä. Jos dialogi luotu kutsulla DoModelessDialog ja se poistetaan tällä kutsulla, käytetään seuraavan luonnin DoModelessDialog yhteydessä tätä samaa dialogia. Vain ensimmäisen kutsun aikana saadaan WM_INITDIALOG -viesti. Parametrit: HWND hWnd = poistettavan dialogin kahva int RetVal = arvo joka halutaan palauttaa kutsuneelle ohjelmalle (merkitystä vain Modal-dialogeissa) ---------------------- int KillDialog(HWND, int); ---------------------- Kuten edellä, mutta poistetaan dialogi kokonaan, eli uusi DoModelessKutsu luo kokonaan uuden dialogin. Tällöin edellisen kerran arvot menetetään ja luonnin yhteydessä saadaan WM_INITDIALOG -viesti. ---------------------- int IsModelessMessage(MSG *); ---------------------- Tutkitaan kuuluuko viesti jollekin ModelessDialogille. Tämä kutsu täytyy lisätä pääohjelman viestisilmukkaan. Jos yhtään dialogia ei ole käynnissä, kutsu ei aiheuta mitään. Palauttaa: 0 = ei ole minkään dialogin viesti 1 = on dialogin viesti, viesti käsitelty ---------------------- void *DialogAlloc(HWND hWnd,UINT size) ---------------------- Varataan ja lukitaan tila dialogin omille lokaaleille muuttujille. Palautetaan käyttökelpoinen osoite tai NULL-jos epäonnistuu. Voidaan käyttää myös Realloc-tarkoitukseen. ---------------------- void *DialogLock(HWND hWnd) ---------------------- Lukitaan dialogin lokaali muisti. Jos tilaa ei ole edes varattu palautetaan NULL, muuten käyttökelpoinen osoite. ---------------------- BOOL DialogUnlock(HWND hWnd) ---------------------- Poistetaan lukitus dialogin lokaaleilta muuttujilta. Jos halutaan takaisin, pitää kutsua DialogLock-funktiota. ---------------------- BOOL DialogFree(HWND hWnd) ---------------------- Vapautetaan dialogin viemä lokaali muistitila. Tämä tehdään automaattisesti kunkin dialogin hävittämisen yhteydessä, joten DestroyDialog ja FreeAllModeless -kutsut riittävät. ---------------------- void DialogSethInstance(HINSTANCE hInstance) ---------------------- Laitetaan ohjelman hInstance jemmaan, jos halutaan kutsua luonteja NULL-kahvalla. Kutsutaan yleensä pääohjelman alussa. ---------------------- HINSTANCE DialogGethInstance(HWND hWnd) ---------------------- Palauttaa hWnd:tä vastaavan esiintymän kahvan jos hWnd <> NULL. Muuten palauttaa DialogSethInstancella asetetun kahvan (tai NULL). ---------------------- LPARAM GetDialogCreateLParam(HWND hWnd); ---------------------- Jos dialogia on ruvettu luomaan kutsulla Create...Param, niin tämä palauttaa kutsussa olleen lParam arvon. Tätä käytetään oikeasti WM_INITDIALOG-viestissä, mutta jos dialogi on luotu luokkana (sille on annettu CLASS), niin WM_INITDIALOGia ei kutsuta. Tällä funktiolla voidaan hakea luontiparametri näissä tapauksissa esim. WM_CRETE-viestissä tai WM_SHOWWINDOW-viestissä. (tabhand.h hoitelee tämän automaattisesti, ks. sieltä). ---------------------- int mMessageLoop(void) ---------------------- Hoitaa viestisilmukkaa. Palauttaa msg.wParam arvon. Käytetään esim. pääohjelmassa: return MMessageLoop(); ---------------------- int mIsAcceleratorMessage(MSG *msg); ---------------------- Tarkistaa onko viesti jokin pikanäppäin joka ilmoitettu kutsulla MAddAccelerator. ---------------------- int mAddAccelerator(HWND hWnd,char *name); ---------------------- Lisää sisäiseen taulukkoon pikanäppäintarkistuksen name ikkunalle hWnd. Tästä on hyötyä jos käytetään MMessageLoop-kutsua, tai käytettäessä kutsua MIsAccelerator (jota MMEssageLoop-käyttää). ---------------------- int mDeleteAccelerator(HWND hWnd); ---------------------- Poistetaan ikkunan hWnd pikanäppäimet sisäisestä taulukosta. Tätä kutsuttava ennen ikkunan tuhoamista. ---------------------- int mGetChildRect(HWND hWnd,int id,RECT *rc) ---------------------- Palauttaa lapsi-ikkunan koordinaatit Client-alueessa. ---------------------- EVENT EVENT_handler_About(tMSGParam *msg) ---------------------- Valmis tabhand.h:n mukainen käsittelijäfunktio About-viestiin vastaamiseksi Tämän lisäämiseksi viestitaulukkoon on myös makro (ks. tabhand.h) EV_HANDLE_WM_COMMAND_CM_HELPABOUT(Version) ****************************************************************************/ #include #include #include #include "mdialog.h" #include "tabhand.h" #define MODE_MODAL 2 #define MODE_MODELESS 0 #define MODE_MULTI_MODELESS 1 /* Seuraava muuttuja on ...CreateParam kutsujen parametrin säilyttämiseksi */ /* Se täytyy jossakin vaiheessa korvata taulukolla, jossa on jemmassa */ /* usamman dialogin luontiin liittyvät lParam:it. Tämä toimii vain jos */ /* vain yhtä dialogia ollaan luomassa kerrallaan. */ static LPARAM GlobalLParam = 0; typedef struct { /* Tyyppi, johon talletetaan voimassa olevat modeless-dial*/ char name[20]; /* Dialogin-nimi */ int visible; /* 1 = on näkyvissä */ HWND hwnd; /* Dialogin kahva */ FARPROC lpProcFunc; /* Dialogin funktion osoite */ int mode; /* 0 = vain 1 esiintymä, 1 = useita esiintymiä */ /* 2 = modal dialog */ HLOCAL hloc; /* Varatun muistin kahva */ int size; /* Varatun tilan koko */ } modeless_type; #define MAX_DIALOGS 10 static struct { int n; /* Dialogien lukumäärä */ HINSTANCE hInstance;/* Esiintymän kahva */ modeless_type dialogs[MAX_DIALOGS]; } Modeless = {0,NULL}; /***************************************************************************/ void DialogSethInstance(HINSTANCE hInstance) { if ( hInstance == NULL ) return; Modeless.hInstance = hInstance; } /***************************************************************************/ HINSTANCE DialogGethInstance(HWND hWnd) { if ( hWnd ) return GetWindowInstance(hWnd); return Modeless.hInstance; } /***************************************************************************/ static void mFreeProcInstance(FARPROC lpProcFunc) { if ( lpProcFunc == NULL ) return; FreeProcInstance(lpProcFunc); } /***************************************************************************/ static int FindModelessIndex(HWND hWnd) { int i; for (i=0; iname,name) == 0 && m->mode == MODE_MODELESS) return m; } return NULL; } /***************************************************************************/ static BOOL FreeModelessMem(modeless_type *m) /* Vapautetaan mahdollinen lokaalin alueen muisti! */ { UINT nlocs; unsigned int i; if ( !m || !m->hloc ) return FALSE; nlocs = LocalFlags(m->hloc) & 0xff; for (i=1; i<=nlocs; i++) LocalUnlock(m->hloc); if ( LocalFree(m->hloc) == NULL ) { /* Jos vapautus onnistui */ m->hloc = NULL; m->size = 0; return TRUE; } return FALSE; } /***************************************************************************/ static void RemoveModelessIndex(int index, int retval) /* Poistaa i:en modeless-dialogin kokonaan joukosta */ { int i; modeless_type *m = &Modeless.dialogs[index]; if ( m->mode != MODE_MODAL ) DestroyWindow(m->hwnd); else EndDialog(m->hwnd,retval); mFreeProcInstance(m->lpProcFunc); FreeModelessMem(m); for (i=index; iDlg); Omat arvonsa käyttäjä voi laittaa sitten lukittuun osoitteeseen ja jos hän haluaa muistialueen tuhoutuvan dialogin luomisen jälkeen, on palautettava Del=1. Eli käyttäjän on aluetta muuttaessaan palautettava sekä kahva että lukittu muistiosoite tai lukitsematon kahva ja NULL. Jos käyttäjä haluaa pelkästään muuttaa dialogin tietoja, niin hän voi sen tehdä käyttämällä suoraan dialogin tietojen kahvaa. Käyttäjän funktiota wcHandler voidaan kutsua siten että tietueen tCreWndSt kenttä Dlg == NULL, jolloin ei haluta dialogin tietoja, vaan ikkunaluokan luomiseen liittyvyä arvoja. Esimerkiksi dialogi muutetaan systemmodaaliksi seuraavalla käsittelyllä static void setwc(tCreWndSt *c) { if ( c->Dlg == NULL ) return; FindIniFileName(N_S(G.ini),NULL); if ( c->Dlg->Tmpl && GetPrivateProfileInt(WinLoginPOS,"sysmodal",0,G.ini) ) { DWORD far *style = (DWORD far *)(c->Dlg->Tmpl); *style = *style | DS_SYSMODAL; } } -----------------------------------------------------------------------------*/ { tCreWndSt c; tDlgInfo Dlg; HRSRC hres = FindResource(hInstance,name,RT_DIALOG); c.Dlg = &Dlg; Dlg.hgl = LoadResource(hInstance,hres); Dlg.Tmpl = LockResource(Dlg.hgl); Dlg.Del = 1; if ( wcHandler ) wcHandler(&c); if ( Dlg.hgl && Dlg.Tmpl == NULL ) Dlg.Tmpl = LockResource(Dlg.hgl); return Dlg; } /***************************************************************************/ void UnlockDialogInfo(tDlgInfo *Dlg) { if ( Dlg && Dlg->Tmpl ) { (void)UnlockResource(Dlg->hgl); Dlg->Tmpl = NULL; } } /***************************************************************************/ void DeleteDialogInfo(tDlgInfo *Dlg) { UnlockDialogInfo(Dlg); if ( Dlg && Dlg->Del ) { if ( Dlg->hgl) FreeResource(Dlg->hgl); Dlg->hgl = NULL; Dlg->Del = 0; } } /***************************************************************************/ static HWND DoNewModelessWC(HWND hWnd,const char *name,PDIALOGPROC func, int mode,LPARAM lParam, tWNDCLASSHandler wcHandler) /* Luodaan uusi Modeless Dialog-ikkuna */ /* Jos kutsutaan Modal-dialogille, pitää kahva olla valmiina hWnd:ssä ja */ /* mode = MODE_MODAL */ /* Koska CreateDialog kutsuu dialogin funktiota alustusviestillä, ja tämä */ /* saattaa jo pyytää luomaan DialogAllocilla muistia, pitää tässä olla */ /* varovainen ja pitää huoli, että dialogin tiedot ovat valmiina jo ennen */ /* kuin CreateDialogista on palattu. Muut tiedothan saadaankin kohdalleen */ /* Mutta dialogin kahva jää tuntemattomaksi. Siksi se merkitäänkin */ /* arvolla 0, joka muissa aliohjelmissa (FindModelessIndex) */ /* tulkitaan keskeneräiseksi luonniksi. */ { HWND nhWnd; HINSTANCE hInstance = DialogGethInstance(hWnd); modeless_type *m; if ( Modeless.n >= MAX_DIALOGS ) return 0; m = &Modeless.dialogs[Modeless.n]; Modeless.n++; strncpy(m->name,name,sizeof(m->name)); m->visible = 1; m->mode = mode; m->lpProcFunc = NULL; m->hloc = NULL; m->size = 0; m->hwnd = 0; /* Luonti menossa! */ if ( mode == MODE_MODAL ) m->hwnd = hWnd; /* kahva pitää olla jo valmiina*/ else { /* Ei modal */ tDlgInfo Dlg = FindUserDialog(hInstance,name,wcHandler); m->lpProcFunc = MakeProcInstance((FARPROC)func, hInstance); GlobalLParam = lParam; nhWnd = NULL; if ( Dlg.Tmpl ) nhWnd = CreateDialogIndirectParam(hInstance, Dlg.Tmpl, hWnd, (DLGPROC)m->lpProcFunc,lParam); DeleteDialogInfo(&Dlg); #if 0 m->lpProcFunc = MakeProcInstance((FARPROC)func, hInstance); GlobalLParam = lParam; nhWnd = CreateDialogParam(hInstance, name, hWnd, (DLGPROC)m->lpProcFunc,lParam); #endif /* CreateDialog kutsuu dialogin funktiota, ja tämä saattaa tarvita */ /* lokaalia muistia, jolloin m->hwnd saatetaan saada selville jo */ /* ennen CreateDialogista paluuta eikä se siis paluun jälkeen ole 0 */ /* Mutta mitäpä jos luonteja on ollut useita yhtäaikaa, mistä tunnistaa*/ /* mille luonnille mikäkin muistialue kuuluu??? */ /* Ongelmia ei pitäisi tulla, mikäli DialogAlloc-kutsu on heti */ /* dialogin alustusviestin käsittelyn alussa tai jopa ennen! */ if ( m->hwnd && m->hwnd != nhWnd ) { /* Tätä ei koskaan testattu/vl-93 */ MessageBox(hWnd,"Useita luonteja yhtäaikaa","Vikaa!!!",MB_OK); nhWnd = NULL; } m->hwnd = nhWnd; } if ( !m->hwnd ) RemoveModelessIndex(Modeless.n-1,1); return m->hwnd; } /***************************************************************************/ HWND DoModelessDialogParamWC(HWND hWnd,const char *name,PDIALOGPROC func, LPARAM lParam,tWNDCLASSHandler wcHandler) /* Luodaan uusi Modeless Dialog-ikkuna */ /* Mikäli ennestään on olemassa vastaava ikkuna, niin käytetään sen */ /* valmiiksitehtyä funktiota. */ /* Mikäli dialogi on ennestään, ei luoda uutta esiintymää, vaan laitetaan */ /* vanha aktiiviseksi. */ /* Palautetaan 0, mikäli ikkunaa ei voi luoda, muuten kahva ikkunaan */ { modeless_type *m; m = FindModelessName(name); if ( !m ) return DoNewModelessWC(hWnd,name,func,MODE_MODELESS,lParam,wcHandler); if ( m->visible == 0 ) /* Jollei näkyvissä, niin näkyviin */ ShowWindow(m->hwnd,SW_SHOWNORMAL); m->visible=1; SetFocus(m->hwnd); /* Vaihdetaan focus aina jos on ik. */ return m->hwnd; } /***************************************************************************/ HWND DoMultiModelessDialogParamWC(HWND hWnd,const char *name,PDIALOGPROC func, LPARAM lParam,tWNDCLASSHandler wcHandler) /* Luodaan uusi Modeless Dialog-ikkuna */ /* Sallitaan saman esiintyä useita kertoja. */ { return DoNewModelessWC(hWnd,name,func,MODE_MULTI_MODELESS,lParam,wcHandler); } /***************************************************************************/ void FreeAllModeless(void) { int i; for (i=Modeless.n-1; i>=0; i--) RemoveModelessIndex(i,1); } /***************************************************************************/ void RemoveModeless(HWND hWnd,int retval) /* Poistaa i:en modeless-dialogin kokonaan joukosta */ { int index = FindModelessIndex(hWnd); RemoveModelessIndex(index,retval); } /***************************************************************************/ int DestroyDialog(HWND hWnd,int retval) /* Tuhoaa modeless dialogit DestroyWindow-komennolla ja muut dialogit */ /* EndDialog -komennolla (Modal) */ /* Jos mode = 1, jätetään dialogi olemaan. */ { modeless_type *m = FindModeless(hWnd); if ( !m ) { EndDialog(hWnd,retval); return retval; } m->visible = 0; if ( m->mode != 0 ) RemoveModeless(hWnd,retval); else ShowWindow(m->hwnd,SW_HIDE); return retval; } /***************************************************************************/ int KillDialog(HWND hWnd,int retval) /* Tuhoaa modeless dialogit DestroyWindow-komennolla ja muut dialogit */ /* EndDialog -komennolla (Modal) */ { modeless_type *m = FindModeless(hWnd); mDeleteAccelerator(hWnd); if ( !m ) { EndDialog(hWnd,retval); return retval; } RemoveModeless(hWnd,retval); return retval; } /***************************************************************************/ /* Modeless aliohjelmat loppuivat */ /***************************************************************************/ /***************************************************************************/ HWND DoModalDialogParamWC(HWND hWnd,const char *name,PDIALOGPROC func, LPARAM lParam,tWNDCLASSHandler wcHandler) { int ret = 0; HINSTANCE hInstance = DialogGethInstance(hWnd); FARPROC lpProcFunc; tDlgInfo Dlg = FindUserDialog(hInstance,name,wcHandler); lpProcFunc = MakeProcInstance((FARPROC)func, hInstance); GlobalLParam = lParam; // ret = DialogBoxParam(hInstance, name, hWnd, (DLGPROC)lpProcFunc,lParam); if ( Dlg.hgl ) { UnlockDialogInfo(&Dlg); ret = DialogBoxIndirectParam(hInstance, Dlg.hgl, hWnd, (DLGPROC)lpProcFunc,lParam); } DeleteDialogInfo(&Dlg); mFreeProcInstance(lpProcFunc); return (HWND)ret; } /***************************************************************************/ LPARAM GetDialogCreateLParam(HWND hWnd) { #pragma argsused LONG lp = GlobalLParam; GlobalLParam = 0; return lp; } /***************************************************************************/ /* Lokaalin muistin aliohjelmat alkavat */ /***************************************************************************/ /***************************************************************************/ void *DialogLock(HWND hWnd) /* Palautetaan lukittu muistialue hWnd:n lokaaleille muuttujille. */ /* Jos hWnd:tä ei ole rekisteröity TAI muistia ei ole varattu, palautetaan */ /* NULL */ { modeless_type *m = FindModeless(hWnd); if ( !m ) return NULL; if ( !m->hloc ) return NULL; return LocalLock(m->hloc); } /***************************************************************************/ void *DialogAlloc(HWND hWnd,UINT size) /* Allokoidaan muistia ja palautetaan muistille lukittu kahva. */ /* Jos jo allokoitu tälle dialogille, palautetaan vanha kahva. */ /* Jos epäonnistuu, palautetaan NULL */ /* Jos dialogi ei ole listassa, lisätään se sinne Modal-dialogina */ /* Tätä voidaan käyttää myös ReAllocina, kunhan vaan kaikki lukot on pois */ { modeless_type *m = FindModeless(hWnd); if ( !m ) { DoNewModelessWC(hWnd,"",NULL,MODE_MODAL,0,NULL); m = FindModeless(hWnd); if ( !m ) return NULL; } if ( !m->hloc ) { /* Muistia ei vielä ole */ m->hloc = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,size); m->size = size; } else if ( size != (UINT)(m->size) ) { /* Jos kokoa tarvitsee muuttaa! */ if ( LocalFlags(m->hloc) & 0xff ) return NULL; /* Kokoa ei voi muutt. */ m->hloc = LocalReAlloc(m->hloc,size,LMEM_MOVEABLE); m->size = size; } if ( !m->hloc ) m->size = 0; return DialogLock(hWnd); } /***************************************************************************/ BOOL DialogUnlock(HWND hWnd) /* Poistetaan lukitus dialogin muistista. Muistin hävitys tulee */ /* samalla kuin dialogin tuhoaminenkin. */ { modeless_type *m = FindModeless(hWnd); if ( !m ) return FALSE; if ( !m->hloc ) return FALSE; return LocalUnlock(m->hloc); } /***************************************************************************/ BOOL DialogFree(HWND hWnd) /* Vapautetaan dialogin lokaali muisti */ { return FreeModelessMem(FindModeless(hWnd)); } /***************************************************************************/ BOOL CALLBACK _export MDialogAbout(HWND hDlg,UINT message, WPARAM wParam,LPARAM lParam) { #pragma argsused switch (message) { case WM_INITDIALOG: { tVersionInfo *v = (tVersionInfo *)lParam; if ( v == NULL ) return TRUE; SetWindowText(GetDlgItem(hDlg,v->id),v->version); return TRUE; } case WM_COMMAND: { int id = GET_WM_COMMAND_ID(wParam,lParam); if ( id == IDOK || id == IDCANCEL ) { DestroyDialog(hDlg, TRUE); return (TRUE); } break; } } return FALSE; } /***************************************************************************/ /* Pikanäppäinten käsittely */ /***************************************************************************/ typedef struct { HWND hWnd; HACCEL hAccel; int loose; } tOneAccel; #define MAX_ACCEL 30 typedef struct { int n; tOneAccel a[MAX_ACCEL]; } tAccels; static tAccels Accels = {0}; /***************************************************************************/ int mDeleteAccelerator(HWND hWnd) /* Poistaa pikanäppäintaulukon tarkistettavien joukkosta */ { int w,r; for (r=0,w=0; r ei tarvitse olla omassa ikkunassa, loose = 0 => täytyy olla */ { HACCEL hAccel; int i; if ( name == NULL || name[0] == 0 ) return -1; if ( Accels.n >= MAX_ACCEL ) return -2; hAccel = LoadAccelerators(GetWindowInstance(hWnd),name); if ( hAccel == NULL ) return -3; i = Accels.n++; Accels.a[i].hWnd = hWnd; Accels.a[i].hAccel = hAccel; Accels.a[i].loose = loose; return 0; } /****************************************************************************/ int mIsAcceleratorMessage(MSG *msg) /* Tarkistaa onko jokin käytössä oleva pikanäppäinviesti */ { int i; HWND hWnd = GetActiveWindow(); (void)hWnd; for (i=0; itop = 0; rc->bottom = 0; rc->left = 0; rc->right = 0; if ( hWndChild == NULL ) return -1; wndpl.length = sizeof(wndpl); GetWindowPlacement(hWndChild,&wndpl); *rc = wndpl.rcNormalPosition; return 0; } /****************************************************************************/ EVENT EVENT_handler_About(tMSGParam *msg) { return (int)DoModalDialogParam(msg->hWnd,"About",MDialogAbout,msg->extra); } #if 0 /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ /* 1995 */ //#include /***************************************************************************/ static HWND DoNewModelessSet(HWND hWnd,const char *name,PDIALOGPROC func, int mode,LPARAM lParam) /* Luodaan uusi Modeless Dialog-ikkuna */ /* Jos kutsutaan Modal-dialogille, pitää kahva olla valmiina hWnd:ssä ja */ /* mode = MODE_MODAL */ /* Koska CreateDialog kutsuu dialogin funktiota alustusviestillä, ja tämä */ /* saattaa jo pyytää luomaan DialogAllocilla muistia, pitää tässä olla */ /* varovainen ja pitää huoli, että dialogin tiedot ovat valmiina jo ennen */ /* kuin CreateDialogista on palattu. Muut tiedothan saadaankin kohdalleen */ /* Mutta dialogin kahva jää tuntemattomaksi. Siksi se merkitäänkin */ /* arvolla 0, joka muissa aliohjelmissa (FindModelessIndex) */ /* tulkitaan keskeneräiseksi luonniksi. */ { HWND nhWnd; HINSTANCE hInstance = DialogGethInstance(hWnd); modeless_type *m; if ( Modeless.n >= MAX_DIALOGS ) return 0; m = &Modeless.dialogs[Modeless.n]; Modeless.n++; strncpy(m->name,name,sizeof(m->name)); m->visible = 1; m->mode = mode; m->lpProcFunc = NULL; m->hloc = NULL; m->size = 0; m->hwnd = 0; /* Luonti menossa! */ if ( mode == MODE_MODAL ) m->hwnd = hWnd; /* kahva pitää olla jo valmiina*/ else { /* Ei modal */ HRSRC hres = FindResource(hInstance,name,RT_DIALOG); HGLOBAL hglDlg = LoadResource(hInstance,hres); void FAR *dlgtmpl = LockResource(hglDlg); DWORD *style = (DWORD *)dlgtmpl; *style = *style | DS_SYSMODAL; m->lpProcFunc = MakeProcInstance((FARPROC)func, hInstance); GlobalLParam = lParam; nhWnd = CreateDialogIndirectParam(hInstance, dlgtmpl, hWnd, (DLGPROC)m->lpProcFunc,lParam); UnlockResource(hglDlg); FreeResource(hglDlg); /* CreateDialog kutsuu dialogin funktiota, ja tämä saattaa tarvita */ /* lokaalia muistia, jolloin m->hwnd saatetaan saada selville jo */ /* ennen CreateDialogista paluuta eikä se siis paluun jälkeen ole 0 */ /* Mutta mitäpä jos luonteja on ollut useita yhtäaikaa, mistä tunnistaa*/ /* mille luonnille mikäkin muistialue kuuluu??? */ /* Ongelmia ei pitäisi tulla, mikäli DialogAlloc-kutsu on heti */ /* dialogin alustusviestin käsittelyn alussa tai jopa ennen! */ if ( m->hwnd && m->hwnd != nhWnd ) { /* Tätä ei koskaan testattu/vl-93 */ MessageBox(hWnd,"Useita luonteja yhtäaikaa","Vikaa!!!",MB_OK); nhWnd = NULL; } m->hwnd = nhWnd; } if ( !m->hwnd ) RemoveModelessIndex(Modeless.n-1,1); return m->hwnd; } /***************************************************************************/ HWND DoMultiModelessDialogParamSet(HWND hWnd,const char *name,PDIALOGPROC func,LPARAM lParam) /* Luodaan uusi Modeless Dialog-ikkuna */ /* Sallitaan saman esiintyä useita kertoja. */ { return DoNewModelessSet(hWnd,name,func,MODE_MULTI_MODELESS,lParam); } /****************************************************************************/ HWND DoClassDialogParamCMDSet(HINSTANCE hInstance, const char *classname, const char *iconname, HWND hWnd, const char *dialogname, WNDPROC MainWndProc, DLGPROC MainDlgProc, LPARAM lParam, int nCmdShow, tWNDCLASSHandler wcHandler) { HWND dhWnd; /* Dialogin kahva */ DialogSethInstance(hInstance); mRegisterWndClass(DialogGethInstance(hWnd),classname,iconname, MainWndProc,wcHandler); dhWnd = DoMultiModelessDialogParamSet(hWnd,dialogname,MainDlgProc,lParam); ShowWindow(dhWnd,nCmdShow); return dhWnd; } #endif