/**************/ /* strlib.c */ /**************************************************************************** LIBRARY: STRLIB.C PURPOSE: "Malli DLL-kirjaston" työosa, joka voidaan liittää sellaisenaan myös tavalliseksi kirjastoksi. Editor: Vesa Lappalainen 10.11.1992 USAGE: 1) Lisätään omaan ohjelmaan #include "strlib.h" 2) Kutsut aliohjelmiin: KysyJono(...) ============================= Aliohjelmien tarkempi kuvaus: ============================= ------------------------------------------------------ int WINAPI_LIB KysyJono(LPSTR kysymys, LPSTR oletus, LPSTR jono, int max_pit) ------------------------------------------------------ Kysytään merkkijono käyttäjältä. Kysymykseen tulee dialogi, jonka otsikkona on kysymys. Dialogissa on kaksi nappulaa OK ja CANCEL. Mikäli valitaan OK (=Return), palautetaan vastatusta jonosta niin monta merkkiä kuin tulokseen sopii. Muuten (CANCEL = ESC) ei tulosta muuteta. Paluttaa: -1 = painettiin ESC tai CANCEL 0 <= annetun merkkijonon pituus LPSTR kysymys - dialogin otsikoksi tulostuva kysymys LPSTR oletus - edit-kenttään oletuksena tulostuva arvo LPSTR jono - tulosjono int max_pit - tulosjonon suurin sallittu pituus (myös \0) Tyyppi WINAPI_LIB on joko WINAPI tai WINAPI _export sen mukaan, tuleeko tästä .DLL vai ei. ------------------------------------------------------ int WINAPI_LIB KysyJonoPaikka(int x,int y); ------------------------------------------------------ Määrää kysymysdialogin paikan. Jollei tätä kutusta, niin sama paikka kuin ed. kerralla jäi. ***************************************************************************** Tämän kirjaston käyttämiseksi tavallisena kirjastona pitää projektissa olla Pääohjelma.c ALI\tsrlib.c (tai strlib.obj tai .lib, jossa tämä on mukana) ALI\strlib.rc ???.def Lisäksi tarvitaan strlib.h ***************************************************************************** KIRJASTOISTA (*.lib ja *.dll): ============================== Jos moduli halutaan lisätä johonkin kirjastoon, pitää tämä moduli ensin kääntää oikealla muistimallilla strlib.obj ja sitten objekti lisätään kirjastoon vaikkapa TLIB -komennolla: TLIB oma.lib +-strlib.obj eli otetaan vanha pois ja lisätään uusi tilalle (jos ei ole ennestään, tulee tietysti varoitus ettei vanhaa voi poistaa). Jos tästä kirjastosta halutaan .dll, niin ks. dllmain.c ***************************************************************************** ----------------------------------------------------------------------------- Toteutuksesta: ============== Kirjastossa on varattu taulukko globaaleja muuttujia varten. Kaikki globaalit muuttujat on pistetty yhteen tietueeseen joka sitten pystytään tallettamaan yhteen taulukon alkioon. Näin voidaan kullekin kutsun esiintymällä antaa omat globaalit muuttujat ikkunan kahvan perusteella. Tosin globaaleja ei nyt käytetä "staattisesti", eli kun kirjastosta poistutaan hävitettään esiintymän globaalit. Funktio GetG(hwnd) antaa osoitteen ikkunan globaaleihin muuttujiin ReleaseG(hwnd) vastaavasti vapauttaa ikkunan globaalit muuttujat. Globaalista taulukosta voidaan muutella niiden paikkoja, joten GetG -kutsulla saatavaan paikkaan saa luottaa vain sen ajan, kun Windows ei pääse saamaan uutta viestiä, eli suoritus pysyy omassa ohjelmassa. Aina kun on ollut vaara muuttua, pitää osoitin hakea uudelleen. Poistoalgoritmi voitaisiin rakentaa myös sellaiseksi, että poistettava merkitään vapaaksi ja paikkoja siirretään vain kun kaikki ovat vapaita. Uusi annettaisiin sitten 1. vapaasta. Nytkin käytetty menetelmä kuitenkin toimii vaikka se tuntuukin vaaralliselta. Globaalit saadaan tietysti "staattisiksi" lisäämällä kirjastoon aliohjelma, jonka kutsulla globaaleja vapautetaan ja normaalien rutiinien jälkeen niitä ei vapautettaisi. DLL-toteutuksessa DLL_G_hInstance on globaali kahva DLL-kirjaston esiintymään. Tavallisessa versiossa (tarvitaan DoModalDialog -aliohjelmassa) kahva otetaan selville kutsuneen ikkunan omistajasta. Myös kutsunut ikkuna selvitetään GetFocus-kutsulla, jottei sitä tarvitse tuoda parametrina. ----------------------------------------------------------------------------- Tehtäviä: 1) Käännä tästä .dll versio ja kokeile toimintaa useammalla eri pääohjelman esiintymällä (eli syöttö kesken kahdessa ohjelmassa yhtäaikaa). Toimiiko? 2) Käännä .dll versio, jossa määritelty vakio ONE_G, eli saadaan käyttöön vain yhdet "työglobaalit". Kokeile kuten edellä useammalla pääohjelman esiintymällä. Toimiiko? ****************************************************************************/ #include /* Tarvitaan kaikissa Windows C-ohjelmissa */ #include #include "strlib.h" typedef BOOL CALLBACK (*PDIALOGPROC)(HWND,unsigned,WPARAM,LPARAM); #ifdef __DLL__ /* DLL-versio tarvitsee useat rinnakaiset globaalit */ # include "dllmain.h" # define MAX_GLOBALS 50 #else /* Tavallinen versio ei tarvitse kuin yhden! */ # define MAX_GLOBALS 1 #endif typedef struct { /* Globaalien työmuuttujien tyyppi */ LPSTR jono; LPSTR oletus; LPSTR kysymys; int max_pit; HWND hwnd; /* Ikkuna joka "omistaa" muuttujat */ } StrGlobals; static StrGlobals Globals[MAX_GLOBALS]; static int Gnum = 1; /* Ensimmäinen (0) varattu virhetilanteita varten! */ #ifdef ONE_G /* Määrittele tämä vakio, jos haluat kokeilla toim.yhd. Glob.*/ static StrGlobals Gl; #endif #define NOPOS -9999 /***************************************************************************/ static POINT DlgPos={NOPOS,NOPOS}; static int SetAskDialogPos(int x,int y) { DlgPos.x = x; DlgPos.y = y; return 0; } static int QueryAskDialogPos(HWND hWnd) { RECT rc; GetWindowRect(hWnd,&rc); DlgPos.x = rc.left; DlgPos.y = rc.top; return 0; } static int MoveAskDialog(HWND hWnd) { if ( DlgPos.x == NOPOS || DlgPos.y == NOPOS ) return 1; SetWindowPos(hWnd,NULL,(int)DlgPos.x,(int)DlgPos.y, 0,0,SWP_NOSIZE | SWP_NOZORDER); return 0; } /***************************************************************************/ static StrGlobals *GetG(HWND hwnd,int child) /* Palauttaa sen globaalin osoitteen, jonka hwnd omistaa. ** Jos child-lippu päällä, otetaan hwnd:ksi isän hwnd ** Jos hwnd:tä ei vielä ole allokoitu, tehdään sille uusi. ** Virhetilanteessa palautetaan joukon 1. (indeksi 0) */ { int i; HWND hwndp=GetParent(hwnd); #ifdef ONE_G if ( child != -1 ) return &Gl; #endif if ( child ) hwnd = hwndp; for ( i = 1; i < Gnum; i++ ) if ( Globals[i].hwnd == hwnd ) return &Globals[i]; if ( Gnum >= MAX_GLOBALS ) return &Globals[0]; Globals[Gnum].hwnd = hwnd; return &Globals[Gnum++]; } /***************************************************************************/ static void ReleaseG(HWND hwnd) /* Poistetaan se globaali, jonka hwnd omistaa. Jos hwnd:tä ** ei ole allokoitu, niin ei poisteta mitään! */ { int i,j; for ( i = 1; i < Gnum; i++ ) if ( Globals[i].hwnd == hwnd ) { /* Jos löytyi, niin poistetaan */ for ( j = Gnum-1; j > i; j--) Globals[j-1] = Globals[j]; Gnum--; return; } } /***************************************************************************/ static int DoModalDialog(HWND hWnd,char *name,PDIALOGPROC func) { int ret; # ifndef __DLL__ /* DLL_versiossa käytetään globaalia! */ HINSTANCE DLL_G_hInstance = GetWindowInstance(hWnd); # endif FARPROC lpProcFunc; lpProcFunc = MakeProcInstance((FARPROC)func, DLL_G_hInstance); ret = DialogBox(DLL_G_hInstance, name, hWnd, (DLGPROC)lpProcFunc); (void)FreeProcInstance(lpProcFunc); return ret; } /***************************************************************************/ BOOL CALLBACK _export KysyJonoDialog(HWND hDlg,unsigned message, WPARAM wParam,LPARAM lParam) { #pragma argsused StrGlobals *G; switch (message) { case WM_INITDIALOG: G = GetG(hDlg,1); SetWindowText(hDlg,G->kysymys); SetDlgItemText(hDlg,EDITJONO,G->oletus); MoveAskDialog(hDlg); return (TRUE); case WM_COMMAND: switch ( GET_WM_COMMAND_ID(wParam,lParam) ) { case IDOK: G = GetG(hDlg,1); GetDlgItemText(hDlg,EDITJONO,G->jono,G->max_pit); EndDialog(hDlg,lstrlen(G->jono)); return (TRUE); case IDCANCEL: EndDialog(hDlg,-1); return (TRUE); } break; case WM_MOVE: QueryAskDialogPos(hDlg); break; } return (FALSE); } /***************************************************************************/ int WINAPI_LIB KysyJono(LPSTR kysymys, LPSTR oletus, LPSTR jono, int max_pit) { int ret; HWND hwnd = GetFocus(); StrGlobals *G = GetG(hwnd,0); G->oletus = oletus; G->kysymys = kysymys; G->jono = jono; G->max_pit = max_pit; ret=DoModalDialog(hwnd,"KYSYJONO",KysyJonoDialog); ReleaseG(hwnd); return ret; } /***************************************************************************/ int WINAPI_LIB KysyJonoPaikka(int x,int y) { return SetAskDialogPos(x,y); }