/**************/ /* winlogin.c */ /****************************************************************************** PROGRAM: winlogin.c Windows: Win 3.1 PURPOSE: Ajaa halutut ohjelmat, kysyy käyttäjätietoja kunnes oikein ja ajaa taas halutut ohjelmat. Näyttää otsikkopalkissa valittua tekstiä. Ohjelmasta on kaksi tapaa poistua. Exit tai Close. Exit tulee joko ko. näppäintä painamalla tai otsikkopalkkia tuplaklikkaamalla. Close tulee close-nappulasta. Kummassakin tapausessa voidaan näyttää haluttu kysymys ja ajaa halutut eri ohjelmat. Editor: Vesa Lappalainen 13.9.1995 WinSocket -ohjelmointi matkittu Ossi Nykäsen (tm) esimerkeistä Inifile: [WinLogin] ExitWhenClose=1 ; Kun WinLogin -suljetaan, suljetaan myös Windows QuitAfterDone=1 ; WinLogin lopetetaan kun muut optiot on suoritettu. Tämä on lähinnä sitä varten, että WinLoginiä voidaan käyttäää alkeellisena "komentojonona", jos ajetaan [RUN]-kohdan ohjelmia (tällöin tarvitaan komentorivin optio -r tai DoRun0= HUOM! Jos molemmat em. ovat päällä ja WinLogin on StartUp-ryhmässä, sammuu Windows aina heti käynnistyksensä jälkeen! OnlyExitRun=1 ; WinExitin tilalla tehdään vain ExitRun-kohdan ; ohjelmat TitleBarClose=1 ; 0=ei suljeta, 1=close, 2=exit otsikkopalkin tuplaklikkauksella WindowText=vesal ; Otsikkopalkin teksti Format=Tunnus: %windowtext% ; Miten teksti tulostetaan Esimerkissä tulostuisi Tunnus: vesal ExitPrompt=Lopetetaanko? ; Windowsin sulkemisessa käytettävä kysymys ClosePrompt= ; Jollei tätä ole, suljetaan ilman kysymystä DoRun0=RUN ; Minkä kohdan "komennot" ajetaan ennen ; käynnistystä DoRun1=... ; Kohtia voi olla useita CloseRun0=RUN_C ; Minkä kohdan ohjelmat ajetaan sulkemisen ; yhteydessä CloseRun1=... ; näitäkin voi olla useita ExitRun0=RUN_EXIT ; Exitin yhteydessä ajettavat ohjelmat. Näitä voi olla useita HUOM! Thedään joko ExitRun tai CloseRun, muttei molempia! [RUN] show=1 ; Ajamisen tapa, ; 0=hide,1=normal,2=minimized,3=maximized run0=notebad ; 1. ajettava ohjelma run1=wincd ; 2. ajettava ohjelma [RUN_C] show=1 ; Ajamisen tapa, oletus jaksolle wait=0 ; Tämän jakson oletus odotus wait0=1 ; Odotetaanko run0:an loppu ennen jatkoa show0=2 ; Kumotaan jakson oletus tälle ajolle run0=connect %host% %userid% %passwd% [Desktop*] ; Taustaan liittyvät asiat, lue desktop.c [POS] AllWaysOnTop=1 ; Onko aina päällimmäisenä ; Lisäksi tulee automaattisesti edellisen ; kerran paikka nosize=1 ; ikkunan kokoa ei saa muutaa nomove=1 ; ikkunan paikkaa ei saa muuttaa sysmodal=0 ; ikkuna EI ole system modal (oletus) nosavepos=1 ; ikkunan paikka ja kokoa ei talleteta [InfoText] ; Info-ikkunaan tuleva teskti Täytä sitä= ; Info ikkunaan tulevat rivit = loppuisina. ja tätä= ; Jos halutaan käyttää = merkkiä, pitää tuota= ; se kirjoittaa \0x3d. Vpi käyttää jonoja ; %userid% jne.. ; JOS infotekstiä ei haluta lainkaan, pitää ; osion nimen [InfoText] olla, muttei sen alla ; saa olla mitään [FONT-InfoText-0] ; fontti-tiedot info-tekstiin. Tämä on ; helpointa täyttää siirtymällä info-text ; kohtaan ja painamalla ctrl-f [WindowText] ; Avustavat tekstit. Jos jätetään tyhjäksi HostText=&Kone: ; niin koko teksti ja sen viereinen kenttä pois UserIDText=Käyttäjä&tunnus: PasswdText=&Salasanasi: OKText=O&K ; OK-nappulaan tuleva teksti, & alleviivaa ExitText=E&xit Windows ; Exit-nappulaan tuleva teksti InfoScroll=1 ; Info-ikkunaan tulee Scroll-bar InfoAutosize=1 ; Info-ikkunan koko muuttuu ikkunan koon mukana [Login] ; Login informaatio NoHostText=0 ; Ei näytetä Host kysymystä NoUserIDText=0 ; -"- UserID -"- NoPasswdText=0 ; -"- Passwd -"- Host=tarzan UserId=vesal passwd= savelogin=1 ; tallettaa lopuksi kayttajatunnusen ja ; pääkoneen, EI salasanaa deffield=2 ; oletuskenttä dialogissa, 0 = host 1 = userid 2 = passwd [SockSend] ; Mitä lähetetään verkkoon ja mihin porttiin port=512 send=\0x00%userid%\0x00%passwd%\0x00NULL\0x00\r\n ok0=\0x00 ; Mikä jono tulkitaan hyväksytyksi, tässä ; kelpaa myös jokeri, eli esim. ; *vesal* ; Näitä voi olla useita, eli näin saadaan ; OR-operaatio. ; Esim. finger saadaan asetuksilla ; port=79 ; send=%userid% closeonok=1 ; suljetaan jos tulee OK-jono closeonlyok=1 ; suljetaan vain kun tulee OK-jono timeout=10000 ; Odotusaika ms allwaysok0=nobody ; aina kelpaava tunnus, näitä voi olla useita sockmodal=1 ; lähetys modaalinen NoEmptyPasswd=1 ; tyhjä salasana kelpaa vain jos OK ; painetaan salasanakentässä, jos ei olla ; salasanakentässä, siirrytään seuraavaan ; kenttään. Näin saadaan return vaihtamaan ; kenttiä kunnes tullaan salasanakenttään tai ; salasana ei ole tyhjä. Huom! Mm. format, send= ja run?= jonoissa jonot %host%, %userid%, %passwd% ja %windowtext% sekä %version% korvataan vastaavilla dialogista tai oletuksista saaduilla jonoilla Command: WinLogin [options] Options: Jos vastaava optio on myös -ini-tiedostossa, kumotaan tämä -i=inifilename ; luettavan initiedoston nimi, jollei polkua etsitään ensin oletushakemistosta, sitten windowshakemistosta ja lopuksi ohjelman käynnistyshakemistosta oletus: WinLogin.ini -r=runsection ; Minkä nimisen otsikon alta etsitään ajettavia ohjelmia. Ohjelmat ajetaan järjestyksessä run0, run1 kunnes ei ole runN määritystä. -r optioita voi olla useita, jolloin ajetaan kaikkien ko. otsikoiden alla olevat ohjelmat järjestyksessä (Huom! moniajo!) -c=closerunsec ; Minkä otsikon alle olevat ohjelmat ajetaan sulkemisen yheydessä? -x=exitrunsec ; Minkä otsikon alla olevat ajetaan exitin yhteydessä -w=title ; kumoaa mahd. ini-tiedoston WindowText asetuksen -p=message ; tulostetaan viesti Windowsin sulkemisen yhteydessä -e ; lopetetaan Windows samalla kun WinLogin [+|-] lopetetaan. Jos tämä optio on päällä, ei WinLogin -ohjelmaa voi sulkea sulkematta Windowsia. Jos optiot ei ole päällä INI-tiedostossa, niin nyt se laitetaan -e+ == -e == lopetetaan Windows -e- == ei lopeteta Windosia -q ; lopetetaan WinLogin kun muut optiot suoritettu -q+ == -q == lopetetaan -q- == ei lopeteta -p="Mitä?" ; sama kuin ExitPrompt -o="Tosiko?" ; sama kuin ClosePrompt -u=vesal ; -h=tarzan ; -a=salasana Example: WinLogin -i=win.ini -r=run -e -p="Oletko tosissaan" PROJECT: WinLogin.c WinLogin.rc WinLogin.def socksend.c winsock.lib ALI\tabhand.c ALI\savepos.c ALI\mjonot.c ALI\mdialog.c ALI\ininame.c ALI\allwtop.c ALI\fontti.c ALI\printw.c ALI\autotw.c - autojen liikuttelu näytöllä ALI\desktop.c - taustaikkunan näyttäminen ALI\bitmap.c Historia: Versio 13.9.1995 + tehty Ossi Nykäsen finger-esimerkkiä ja vl:n WinExitiä hakkeroimalla Versio 14.9.1995 + mahdollisuus odottaa edellisen ohjelman loppumista ennen uuden ajamista + sulkeutuu vain jos OK tai Windows sammutetaan + SockSend-ikkuna alkuperäisen ikkunan päälle Versio 22.9.1995 + system modal + nomove, nosize jne... Versio 0.4 23.9.1995/vl + [WindowText], [DeskTop] Versio 0.5 24.9.1995/vl + [Autot] + tautaikkuna omaksi aliohjelmakirjastokseen Korjattavaa: - automaattinen sammutus (Screen Saverin avulla?) ****************************************************************************/ #define VERSION "0.5 24.9.1995/vl" #include #include #include #include #include #include #include #include #include "mjonot.h" #include "tabhand.h" #include "savepos.h" #include "winlogin.rh" #include "ininame.h" #include "allwtop.h" #include "socksend.h" #include "fontti.h" /* f */ #include "desktop.h" #define WinLoginPOS "POS" typedef struct { int ExitWhenClose; int QuitAfterDone; int OnlyExitRun; int TitleBarClose; int sysmodal; char ExitPrompt[80]; char ClosePrompt[80]; char ini[200]; char closerun[100]; char exitrun[100]; char WindowText[100]; char Format[100]; HWND hWnd; HWND hWndBK; } tGlobalOptions; typedef struct { int port; char SendString[200]; char host[100]; char userid[100]; char passwd[100]; char receive[500]; char sendnow[300]; int closeonok; int closeonlyok; int wasok; int savelogin; int timeout; int deffield; int sockmodal; } tWinLogin; static tGlobalOptions G; static tWinLogin GW = { 512, "\\0x00%userid%\\0x00%passwd%\\0x00true\\0x00\r\n", "tarzan", "", "" }; static int winIDs[] = { IDC_INFOTEXT,0,0 }; /* f */ static tFontChange FontChange = {"InfoText",winIDs, NULL}; /* f */ /*****************************************************************************/ int ChangeDirToThisFile(const char *name) { char s[100],*p; int i; kopioi_jono(N_S(s),name); p = strrchr(s,'\\'); if ( p ) *p = 0; i = chdir(s); return i; } /*****************************************************************************/ /* Ikkunaluokan asetus siten, että tuplaklikkaus on mahd. ja dialogin tyylin */ /* vaihtaminen jos tarpeen. */ static void setwc(tCreWndSt *c) { DWORD far *style; if ( c->Dlg == NULL ) { c->wc.style = CS_DBLCLKS; return; } FindIniFileName(N_S(G.ini),NULL); ChangeDirToThisFile(G.ini); if ( c->Dlg->Tmpl == NULL ) return; style = (DWORD far *)(c->Dlg->Tmpl); if ( GetPrivateProfileInt(WinLoginPOS,"sysmodal",0,G.ini) ) *style |= DS_SYSMODAL; if ( GetPrivateProfileInt(WinLoginPOS,"nosize",0,G.ini) ) *style &= ~(DWORD)WS_THICKFRAME; } /*****************************************************************************/ /* "Pääohjelma" */ TblClassDlgMAINWC("WinLoginWClass","ikoni","Menu","WinLogin",MsgTbl,setwc); /*****************************************************************************/ /*****************************************************************************/ /* Versiotieto sellaisena kuin MDialogAbout sen haluaa */ static tVersionInfo Version = {IDC_VERSION,"Version "mPLATFORM":\r\n"VERSION}; /*****************************************************************************/ /*****************************************************************************/ /* Apualiohjelmia: */ /*****************************************************************************/ #define GETTEXT(id,s) if ( GetDlgItem(hWnd,id) ) GetDlgItemText(hWnd,id,s,sizeof(s)) /*****************************************************************************/ static int korvaa_jonot(HWND hWnd,char *s,int ms) /* Vaihdetaan %host% jne. esiintymat vastaaviksi muuttujiksi */ { int len; char stop[2]={0xff,0}; GETTEXT(IDC_HOST,GW.host); GETTEXT(IDC_USERID,GW.userid); GETTEXT(IDC_PASSWD,GW.passwd); vaihda_jonot(s,ms,"%windowtext%",G.WindowText); vaihda_jonot(s,ms,"%host%",GW.host); vaihda_jonot(s,ms,"%userid%",GW.userid); vaihda_jonot(s,ms,"%passwd%",GW.passwd); vaihda_jonot(s,ms,"%version%",VERSION); liita_jono(s,ms,stop); muunna_C_symbolit(s); for (len=0; len 0, + ja tyhjä => 1 */ /*****************************************************************************/ static int DoInit(HWND hWnd) /* Tekee ohjelman alustamisessa tarvittavat toimenpiteet, eli tulkitsee ** INI-tiedoston ja optiot, sekä alustaa systeemimenun. -----------------------------------------------------------------------------*/ { int i; // char s[100]; /* FindIniFileName(N_S(G.ini),NULL); // Tämä on jo tehty setwc-funktiossa */ tutki_scroll(hWnd); G.hWndBK = CheckDesktop(hWnd,G.ini,HandleDesktopText); RestorePos(hWnd,G.ini,WinLoginPOS,1); GetPrivateProfileString("WinLogin","ExitPrompt","",N_S(G.ExitPrompt),G.ini); GetPrivateProfileString("WinLogin","ClosePrompt","",N_S(G.ClosePrompt),G.ini); GetPrivateProfileString("WinLogin","WindowText","",N_S(G.WindowText),G.ini); GetPrivateProfileString("WinLogin","Format","- %windowtext% -",N_S(G.Format),G.ini); G.ExitWhenClose = GetPrivateProfileInt("WinLogin","ExitWhenClose",0,G.ini); G.QuitAfterDone = GetPrivateProfileInt("WinLogin","QuitAfterDone",0,G.ini); G.OnlyExitRun = GetPrivateProfileInt("WinLogin","OnlyExitRun",0,G.ini); G.TitleBarClose = GetPrivateProfileInt("WinLogin","TitleBarClose",0,G.ini); GetPrivateProfileString("Login","Host",GW.host,N_S(GW.host),G.ini); GetPrivateProfileString("Login","UserID","",N_S(GW.userid),G.ini); GetPrivateProfileString("Login","Passwd","",N_S(GW.passwd),G.ini); GW.savelogin = GetPrivateProfileInt("Login","savelogin",0,G.ini); GW.deffield = GetPrivateProfileInt("Login","deffield",0,G.ini); GW.port = GetPrivateProfileInt("SockSend","Port",GW.port,G.ini); GetPrivateProfileString("SockSend","Send",GW.SendString,N_S(GW.SendString),G.ini); GW.closeonok = GetPrivateProfileInt("SockSend","closeonok",0,G.ini); GW.closeonlyok = GetPrivateProfileInt("SockSend","closeonlyok",0,G.ini); GW.timeout = GetPrivateProfileInt("SockSend","timeout",0,G.ini); GW.sockmodal = GetPrivateProfileInt("SockSend","SockModal",1,G.ini); if ( GW.closeonlyok ) GW.closeonok = 1; /* Jotta yleensä voi sulkea! */ GW.wasok = 0; FOR_ARGS("-w=") kopioi_jono(N_S(G.WindowText),ARGV); FOR_ARGS("-e") G.ExitWhenClose = ARGB; FOR_ARGS("-q") G.QuitAfterDone = ARGB; FOR_ARGS("-p=") kopioi_jono(N_S(G.ExitPrompt),ARGV); FOR_ARGS("-o=") kopioi_jono(N_S(G.ClosePrompt),ARGV); FOR_ARGS("-c=") kopioi_jono(N_S(G.closerun),ARGV); FOR_ARGS("-x=") kopioi_jono(N_S(G.exitrun),ARGV); FOR_ARGS("-u=") kopioi_jono(N_S(GW.userid),ARGV); FOR_ARGS("-a=") kopioi_jono(N_S(GW.passwd),ARGV); FOR_ARGS("-h=") kopioi_jono(N_S(GW.host),ARGV); SetDlgItemText(hWnd,IDC_HOST,GW.host); SetDlgItemText(hWnd,IDC_USERID,GW.userid); SetDlgItemText(hWnd,IDC_PASSWD,GW.passwd); SetWindowTextReplace(hWnd,1); CheckSecRun(hWnd,G.ini,"DoRun"); FOR_ARGS("-r=") RunProgs(hWnd,G.ini,ARGV); InitMenu(hWnd,G.ini); if ( G.OnlyExitRun ) SetDlgItemText(hWnd,CM_WINEXIT,"E&xit"); alusta_fontit(hWnd,G.ini,&FontChange); /* f */ return G.QuitAfterDone; } #undef ARGB #undef ARGV #undef FOR_ARGS /*****************************************************************************/ static int DoCloseSave(HWND hWnd) { if ( GetPrivateProfileInt(WinLoginPOS,"nosavepos",0,G.ini) == 0 ) { SaveAllwaysOnTop(hWnd,G.ini); SavePos(hWnd,G.ini,WinLoginPOS,SAVEPOS_SIZE); } if ( GW.savelogin ) { WritePrivateProfileString("Login","Host",GW.host,G.ini); WritePrivateProfileString("Login","UserID",GW.userid,G.ini); } poista_fontit(hWnd,G.ini,&FontChange); /* f */ DestroyDesktop(G.hWndBK); return 0; } /*****************************************************************************/ static int Prompt(HWND hWnd,const char *s) { char st[150]; if ( s[0] == NULL ) return 0; kopioi_jono(N_S(st),s); korvaa_jonot(hWnd,N_S(st)); if ( MessageBox(hWnd,st,"WinLogin",MB_ICONQUESTION | MB_YESNOCANCEL) != IDYES ) return 1; return 0; } /*****************************************************************************/ static int DoExit(HWND hWnd) /* Tekee WIndowsin lopettamisessa tarvittavat toimenpiteet. Jos prompt -jono ** on olemassa, niin kysytään käyttäjältä varmistus Windowsin sulkemiseen -----------------------------------------------------------------------------*/ { if ( Prompt(hWnd,G.ExitPrompt) ) return 1; DoCloseSave(hWnd); RunProgs(hWnd,G.ini,G.exitrun); CheckSecRun(hWnd,G.ini,"ExitRun"); if ( G.OnlyExitRun ) { PostMessage(hWnd,WM_DESTROY,0,0); return 0; } if ( ExitWindows(0 ,0) == 0 ) return 1; return 0; } /*****************************************************************************/ static int DoClose(HWND hWnd) /* Itse ohjelman sulkeminen. Tallettaa arvot INI-tiedostoon ja jos ohjelman ** sulkemisen yhteydessä pitää sulkea myös Windows (-e optio), niin tehdään se. -----------------------------------------------------------------------------*/ { if ( G.ExitWhenClose ) return DoExit(hWnd); if ( Prompt(hWnd,G.ClosePrompt) ) return 1; DoCloseSave(hWnd); RunProgs(hWnd,G.ini,G.closerun); CheckSecRun(hWnd,G.ini,"CloseRun"); SendMessage(hWnd,WM_DESTROY,0,0); return 0; } /*****************************************************************************/ /* E V E N T S : */ static EVENT WM_command_CM_WINEXIT(tMSGParam *msg) { return DoExit(msg->hWnd); } static EVENT WM_initdialog(tMSGParam *msg) { if ( DoInit(msg->hWnd) ) return DoClose(msg->hWnd); // SetCapture(msg->hWnd); SetFocus(GetDlgItem(msg->hWnd,IDC_HOST+GW.deffield)); return DEFRETURN; } static EVENT WM_close(tMSGParam *msg) { if ( GW.wasok == 0 && GW.closeonlyok ) return 1; return DoClose(msg->hWnd); } static EVENT WM_killfocus(tMSGParam *msg) { #pragma argsused // SetFocus(msg->hWnd); return 0; // DEFRETURN; } static int this_ok(HWND hWnd) { GW.wasok = 1; if ( GW.closeonok ) PostMessage(hWnd,WM_CLOSE,0,0); return 0; } static EVENT WM_command_IDOK(tMSGParam *msg) { char s[10]; int sendlen; int err; // ReleaseCapture(); kopioi_jono(N_S(GW.sendnow),GW.SendString); sendlen = korvaa_jonot(msg->hWnd,N_S(GW.sendnow)); if ( GW.port == 0 ) return 0; if ( CheckOk(msg->hWnd,"allwaysok",G.ini,GW.userid) == 0 ) return this_ok(msg->hWnd); if ( GetPrivateProfileInt("SockSend","NoEmptyPasswd",0,G.ini) && GetDlgItemText(msg->hWnd,IDC_PASSWD,N_S(s)) == 0 ) { HWND hWndp = GetDlgItem(msg->hWnd,IDC_PASSWD); HWND hWndh = GetDlgItem(msg->hWnd,IDC_HOST); HWND hWndu = GetDlgItem(msg->hWnd,IDC_USERID); HWND hWndf = GetFocus(); if ( hWndf == hWndh ) { SetFocus(hWndu); return 0; } if ( hWndf == hWndu ) { SetFocus(hWndp); return 0; } } /* Pakkovaihto salasanakenttään */ err = SocketSendString(msg->hWnd,GW.port,GW.host,GW.sendnow,sendlen, GW.timeout,GW.sockmodal,N_S(GW.receive)); if ( err ) { MessageBox(msg->hWnd,GW.receive,"Error!",MB_ICONINFORMATION | MB_OK); return 0; } if ( CheckOk(msg->hWnd,"ok",G.ini,GW.receive) == 0 ) return this_ok(msg->hWnd); MessageBox(msg->hWnd,GW.receive,GW.host,MB_ICONINFORMATION | MB_OK); return 0; } static EVENT WM_command_DoC__EN_change(tMSGParam *msg) { SetWindowTextReplace(msg->hWnd,0); return 0; } static EVENT WM_nclbuttondblclk(tMSGParam *msg) { switch ( G.TitleBarClose ) { case 1: return DoClose(msg->hWnd); case 2: return DoExit(msg->hWnd); default: return 0; } } static EVENT WM_move(tMSGParam *msg) { if ( GetPrivateProfileInt(WinLoginPOS,"nomove",0,G.ini) == 0 ) return 0; RestorePos(msg->hWnd,G.ini,WinLoginPOS,SAVEPOS_NOSIZE); return 1; } static EVENT WM_size(tMSGParam *msg) { HWND hWndi = GetDlgItem(msg->hWnd,IDC_INFOTEXT); RECT rc,rci; if ( hWndi == NULL ) return 0; if ( GetPrivateProfileInt("WindowText","InfoAutosize",0,G.ini) == 0 ) return 0; GetClientRect(msg->hWnd,&rc); tGetClientWindowRect(msg->hWnd,hWndi,&rci); rci.right = rc.right - rci.left; if ( rc.bottom > rci.top ) rci.bottom = rc.bottom - rci.left; MoveWindow(hWndi,rci.left,rci.top,rci.right-rci.left,rci.bottom-rci.top,TRUE); return 0; } static EVENT WM_command_CM_OPTIONS_FONT(tMSGParam *msg) /* f */ { if ( GetFocus() == GetDlgItem(msg->hWnd,IDC_INFOTEXT) ) return vaihda_fontit(msg->hWnd,&FontChange); return 0; } /*****************************************************************************/ /* Viestitaulukko,johon on käsin lisätty valmiita käsittelijöitä */ /* ja samaistettu joitakin viestejä omiin käsittelijöihin. */ /*****************************************************************************/ #define DOC DoC static tMSGEntry MsgTbl[] = { EV_HANDLE_WM_DESTROY, EV_HANDLE_CM_ALLWAYSONTOP, EV_HANDLE_MABOUT(WM_SYSCOMMAND,CM_HELPABOUT,&Version), { WM_ENDSESSION , DoC , DoC , WM_close }, { WM_SYSCOMMAND , CM_WINEXIT , DoC , WM_command_CM_WINEXIT }, { WM_COMMAND , CM_WINEXIT , DoC , WM_command_CM_WINEXIT }, /*a*/ { WM_INITDIALOG , DoC , DoC , WM_initdialog }, /*a*/ { WM_CLOSE , DoC , DoC , WM_close }, /*a*/ { WM_KILLFOCUS , DoC , DoC , WM_killfocus }, /*a*/ { WM_COMMAND , IDOK , DoC , WM_command_IDOK }, /*a*/ { WM_COMMAND , DOC , EN_CHANGE , WM_command_DoC__EN_change }, /*a*/ { WM_NCLBUTTONDBLCLK , DoC , DoC , WM_nclbuttondblclk }, /*a*/ { WM_MOVE , DoC , DoC , WM_move }, /*a*/ { WM_SIZE , DoC , DoC , WM_size }, /*a*/ { WM_COMMAND , CM_OPTIONS_FONT , DoC , WM_command_CM_OPTIONS_FONT }, /*a*/ { 0 } };