Windowsin sanomanvälitys Juha Järvensivu juha.jarvensivu@tut.fi 2008
Sisällys Windowsin sanomat ja Sanomanvälitysmekanismi Ikkunan kahva ja Sanomien lähettäminen Windows API ohjelmointi Resurssit
Sanomat WM_SIZE WM_PAINT WM_COMMAND
Sanoma Define avainsanalla määriteltyjä numerovakioita define WM_SIZE 0005 Käyttäjän omille sanomille varattu oma lukualue WM_USER through 0x7FFF
Sanoman parametrit Sanomaan liitetään 2 32 bittistä parametria WPARAM = 32bit integer LPARAM = 32bit integer
Ikkunaproseduuri Sanomien käsittelijäfunktio Ikkunaproseduuri liittyy tiettyyn ikkunaluokkaan, joten useampi ikkuna (ilmentymä) voi käyttää samaa ikkunaproseduuria LRESULT CALLBACK WndProc (HWND hwnd, UINT imsg, WPARAM wparam, LPARAM lparam)
DefWindowProc Sanomien oletuskäsittelijä-funktio Jos sanomakäsittelijässä ei reagoida sanomaan, se pitää välittää oletuskäsittelijälle Oletuskäsittelijä voi olla tyhjä toteutus, mutta se voi synnyttää myös uusia sanomia Esim Valitaan järjestelmävalikosta valinta Sulje WM_SYSCOMMAND WM_CLOSE WM_DESTROY WM_QUIT Sovellus sulkeutuu
DefWindowProc Oletustoteutus WM_PAINT sanomalle case WM_PAINT: BeginPaint( ); EndPaint( ); return 0; Ohjelmoija vastaa itse siitä, että toteuttaa sanomakäsittelijät oikein. Esimerkki Virheellisestä WM_PAINT käsittelijästä case WM_PAINT: return 0; // Virhe!!!
Makrot LOWORD Palauttaa 32 bittisen luvun 16 ensimmäistä bittiä HIWORD Palauttaa 32 bittisen luvun 16 viimeistä bittiä LOWORD HIWORD
Esimerkki Esim WM_MOUSEMOVE imsg = WM_MOUSE_MOVE fwkeys = wparam; xpos = LOWORD(lParam); ypos = HIWORD(lParam);
Sanomastruktuuri MSG struct MSG { HWND hwnd; UINT message; WPARAM wparam; LPARAM lparam; DWORD time; Point pt; } // Ikkunan kahva // viestin ID // viestin parametri // viestin parametri. // aika jolloin viesti on lähetetty // Kursorin sijainti
Sanoman vastaanotto WM_PAINT WM_SIZE Sanomajono WM_DESTROY WM_COMMAND Ohjelma Sanomasilmukka IkkunaProseduuri Sanomakäsittelijä Sanomakäsittelijä Sanomakäsittelijä Sanomakäsittelijä Sanoman oletuskäsittelijä DefWindowProc
Sanomajono Kun windows-sovellus käynnistyy, windows luo ohjelmalle (säikeelle) sanomajonon Käyttöjärjestelmä laittaa ikkunoille lähetetyt viestit sanomajonoon, josta sovellus käy ne hakemassa
Sanomasilmukka Hakee sanomat yksitellen sanomajonosta ja lähettää ne edelleen oikealle ikkunaproseduurille while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
DispatchMessage This function dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessage function.
TranslateMessage This function translates virtual-key messages into character messages. The character messages are posted to the calling thread's message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.
Näppäinsanomat WM_KEYDOWN (vrt.net KeyDown) WM_CHAR (vrt.net KeyPress) WM_KEYUP (vrt.net KeyUp) while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
Sanoman lähettäminen
Sanoman lähettäminen SendMessage(hwnd,msg,wParam,lParam) Palaa vasta kun vastaanottaja on käsitellyt viestin PostMessage(hwnd,msg,wParam,lParam) Palaa heti kun viesti on lähetetty
Sanoman lähettäminen toiselle ohjelmalle 1. Selvitetään ikkunan kahva 2. Selvitetään mitä sanomia ohjelma kuuntelee 3. Lähetetään sanoma SendMessage funktiolla
Ikkunan alustussanoma WM_CREATE Ensimmäinen ikkunaproseduurille lähetettävä sanoma. Kutsutaan kun ikkuna luodaan CreateWindow-funktiolla Käsittelijässä suoritetaan kertaluonteisia ikkunan alustustoimenpiteitä (vrt.net InitializeComponent)
Ikkunan päivityssanoma WM_PAINT Piirtää näytön uudelleen Piirron aloittaminen BeginPaint Piirron lopettaminen EndPaint Oletustoteutus asettaa vain ikkunan kelvolliseksi, mutta ei piirrä mitään uudelleen UpdateWindow(hwnd); Ikkunan päivittäminen ohjelmallisesti
Sovelluksen sulkeva sanoma WM_DESTROY Kertoo ohjelmalle, että ikkunaa ollaan tuhoamassa käyttäjän toimesta Ohjelma suljetaan kutsumalla PostQuitMessage-funktiota, joka aiheuttaa WM_QUIT = 0 sanoman lähettämisen WM_DESTROY WM_QUIT Sovellus sulkeutuu
Lapsi-ikkunat ja sanomat Esimerkki ListBox Lista-komponentin luominen HWND hlista = CreateWindow(_T("LISTBOX"), _T("Lista"), WS_CHILD WS_VISIBLE WS_BORDER, 100, 0, 200, 200, hwnd, (HMENU) 1, hinst, NULL); Alkion lisääminen listaan SendMessage(hwndLista, LB_ADDSTRING, 0, (LPARAM) buf); Alkion poistaminen listasta SendMessage(hwndLista, LB_DELETESTRING, 0, (LPARAM) NULL); Muita sanomia: LB_FINDSTRING, LB_GETCOUNT, LB_GETTEXT
WinAPI sovellus
Sovelluksen rakenne Sisältää: Pääohjelman WinMain Ikkunaluokan rekisteröinnin ja ikkunan luomisen Ikkunaluokan sanomakäsittelijän WndProc Sanomasilmukan
Ikkunaluokka Ikkunat perustuvat ikkunaluokkaan Esim Button Ikkunaluokka pitää rekisteröidä ennen ensimmäisen ikkunan luomista WNDCLASSEX wndclass RegisterClassEx (&wndclass) ;
Ikkunan kahva yksikäsitteinen ikkunan tunniste, jonka käyttöjärjestelmä luo ikkunan luontivaiheessa HWND hwnd = CreateWindow ( IkkunaLuokka", )
Koodiesimerkki WinMain ja sanomasilmukka #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void MyRegisterClass(HINSTANCE hinstance); void MyCreateWindow(HINSTANCE hinstance, int icmdshow); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdline, int icmdshow) { MSG msg; MyRegisterClass(hInstance); MyCreateWindow(hInstance, icmdshow); // Sanomasilmukka while (GetMessage (&msg, NULL, 0, 0) == TRUE) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wparam ; // käyttöjärjestelmälle palautuva arvo }
Koodiesimerkki Ikkunaluokan alustaminen ja rekisteröinti void MyRegisterClass(HINSTANCE hinstance) { WNDCLASSEX wndclass ; wndclass.cbsize = sizeof (wndclass) ; // struktuurin koko wndclass.style = CS_HREDRAW CS_VREDRAW ; // ikkunan tyyli wndclass.lpfnwndproc = WndProc ; // ikkunaproseduurin nimi wndclass.cbclsextra = 0 ; // ikkunan luokan sisältä ohjelman... wndclass.cbwndextra = 0 ; //...omaan käyttöön varattua tilaa wndclass.hinstance = hinstance ; // ohjelman ilmentymän kahva wndclass.hicon = LoadIcon (NULL, IDI_APPLICATION) ; // suuri ikoni wndclass.hcursor = LoadCursor (NULL, IDC_ARROW) ; // kursori wndclass.hbrbackground = (HBRUSH) COLOR_WINDOW ; // taustaväri wndclass.lpszmenuname = NULL ; // valikon kahva wndclass.lpszclassname = "OmaLuokka" ; // ikkunan luokan nimi wndclass.hiconsm = LoadIcon (NULL, IDI_APPLICATION) ; // pieni ikoni } RegisterClassEx (&wndclass) ; // ikkunan luokan rekisteröinti
Koodiesimerkki WinMain ja sanomasilmukka #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void MyRegisterClass(HINSTANCE hinstance); void MyCreateWindow(HINSTANCE hinstance, int icmdshow); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdline, int icmdshow) { MSG msg; MyRegisterClass(hInstance); MyCreateWindow(hInstance, icmdshow); // Sanomasilmukka while (GetMessage (&msg, NULL, 0, 0) == TRUE) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wparam ; // käyttöjärjestelmälle palautuva arvo }
Koodiesimerkki Ikkunaolion luominen ja piirto ruudulle void MyCreateWindow(HINSTANCE hinstance, icmdshow) { HWND hwnd = CreateWindow ("OmaLuokka", // ikkunan luokan nimi "Päivää maailma!", // ikkunan otsikko WS_OVERLAPPEDWINDOW, // ikkunan tyyli CW_USEDEFAULT, // x-positio aluksi CW_USEDEFAULT, // y-positio aluksi CW_USEDEFAULT, // leveys aluksi CW_USEDEFAULT, // korkeus aluksi NULL, // emoikkunan kahva NULL, // ikkunan valikon kahva hinstance, // ohjelman ilmentymän kahva NULL) ; // luontiparametrit } ShowWindow (hwnd, icmdshow) ; // ikkunan piirto
Koodiesimerkki WinMain ja sanomasilmukka #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void MyRegisterClass(HINSTANCE hinstance); void MyCreateWindow(HINSTANCE hinstance, int icmdshow); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdline, int icmdshow) { MSG msg; MyRegisterClass(hInstance); MyCreateWindow(hInstance, icmdshow); // Sanomasilmukka while (GetMessage (&msg, NULL, 0, 0) == TRUE) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wparam ; // käyttöjärjestelmälle palautuva arvo }
Koodiesimerkki Sanomakäsittelijä LRESULT CALLBACK WndProc (HWND hwnd, UINT imsg, WPARAM wparam, LPARAM lparam) { } switch (imsg) { case WM_DESTROY: } PostQuitMessage (0); return 0; // Sanoman oletuskäsittelijä return DefWindowProc (hwnd, imsg, wparam, lparam) ;
Koodiesimerkki WinMain ja sanomasilmukka #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void MyRegisterClass(HINSTANCE hinstance); void MyCreateWindow(HINSTANCE hinstance, int icmdshow); int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdline, int icmdshow) { MSG msg; MyRegisterClass(hInstance); MyCreateWindow(hInstance, icmdshow); // Sanomasilmukka while (GetMessage (&msg, NULL, 0, 0) == TRUE) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wparam ; // käyttöjärjestelmälle palautuva arvo }
Resurssit
Resurssikuvaustiedosto Resurssit määritellään resurssikuvaustiedostossa Tavallinen ASCII-tiedosto, jonka tunniste on.rc Resurssityyppejä Merkkijonjot Valikot Pikanäppäimet Dialogit jne.
Resurssien kääntämnien.rc.res Resurssikuvaustiedosto Käännetty resurssitiedosto DemoProject.rc DemoProject.res
Valikko resurssi Menu.rc resurssikuvaustiedosto MenuDemo MENU { POPUP &Tiedosto { MENUITEM Item 1 1 MENUITEM SEPARATOR MENUITEM Item 2 2 } POPUP &Muokkaa { MENUITEM Item 3 3 } }
Valikon luominen Valikko voidaan liittää suoraan ikkunastruktuuriin tai vasta ikkunan luonnin yhteydessä Ikkunastruktuurille wndclass.lpszmenu = MyMenu ; Ikkunan luonnin yhteydessä hmenu = LoadMenu(hInstance, MyMenu ); hwnd = CreateWindow(...,hMenu,...);
Pikanäppäin resurssit HACCEL hacceltable; hacceltable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINAMPUI)); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hacceltable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
Resurssitiedosto.rc ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_WINAMPUI ACCELERATORS BEGIN "/", IDM_ABOUT, ASCII, ALT, NOINVERT "?", IDM_ABOUT, ASCII, ALT, NOINVERT "P", NOINVERT ID_ACCELERATOR32773, VIRTKEY, CONTROL, END
Dialogiresurssi Myös dialogit toteutetaan usein resurssien avulla DialogBox(HINSTANCE, LPCTSTR, HWND, DLGPROC); BOOL CALLBACK DialogWndProc(HWND, UINT, WPARAM, LPARAM)
Dialogiresurssi IDD_ABOUTBOX DIALOG 22, 17, 230, 75 STYLE DS_SETFONT DS_MODALFRAME WS_CAPTION WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN ICON IDI_WINAMPUI,IDC_MYICON,14,9,16,16 LTEXT WinampUI",IDC_STATIC,49,10,119,8,SS_NOPREFIX LTEXT "Copyright (C) 2006",IDC_STATIC,49,20,119,8 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP END
Dialogin avaaminen DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About); // Dialogi-ikkunan sanomakäsittelijä INT_PTR CALLBACK About(HWND hdlg, UINT message, WPARAM wparam, LPARAM lparam) { switch(imsg) { // } }
Omistajan ja parentin selvittäminen HWND GetWindow(HWND hwnd, UINT cmd) cmd GW_CHILD, GW_ENABLEDPOPUP, GW_HWNDFIRST, GW_HWNDLAST, GW_HWNDNEXT, GW_HWNDPREV, GW_OWNER HWND GetParent(HWND hwnd);
Pääikkunan päivittäminen dialogista HWND hwnd = GetWindow(hDlg, GW_OWNER); UpdateClientRect(hwnd,NULL,true); UpdateWindow(hwnd);
Lähteitä Charles Petzold Programming windows http://www.charlespetzold.com/pw5/ How to communicate with Winamp http://forums.winamp.com/showthread.php?th readid=180297