Win32 Cpp
Mureakuha
Kuten Win32_sanomat -osassa kerrottiin, osa viesteistä menee suoraan annetulle funktiolle eikä tule sanomajonon kautta. Jotta oliot voitaisiin ottaa käyttöön WinMainissa, on tehtävä muutamia muutoksia sanomien käsittelyyn. Tämä menetelmä ei ole helposti käytettävissä. Kannattaa siis ensisijaisesti käyttää C++:n kanssa MFC -luokkia.
Sisällysluettelo |
WNDCLASS
WNDCLASS -tietueen lpfnWndProc -jäsen määrittää suorien ja jonon kautta kulkevien viestien kohteen. Jotta viestien käsittelyyn käytettävä funktio voisi olla muuta tyyppiä kuin
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
on käytettävä erillistä funktiota, joka kutsuu haluttua funktiota. Jotta tämä taas olisi mahdollista, on luokan osoite otettava talteen ennen ikkunoiden perustamista.
DispatchMessage
Jonon kautta tulevien viestien välitysfunktio on hyvä korvattava omalla menetelmällä, jotta samaa viestiä ei tarvitsisi käsitellä moneen otteeseen. Näin ollen ohjelmassa pidetään kirjaa funktion osoitteista kullekin ikkunalle. Järjestelmän ikkunoitten (napit, tekstilaatikot) osoitteita ei tarvitse tietää, sillä niille lähetetään viestit edelleen DispatchMessage:n kautta.
Esimerkki
Seuraavassa Windowsin sanomatietue on sijoitettu luokan sisään. Luokka on itsessään hyvin simppeli.
MAIN.CPP
//Pääohjelman tiedosto #include "W32.h" //Käytettävän ikkunaproseduurifunktion esittely LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); const char ohjnimi[] = "TestiIkkuna"; const char ohjotsikko[] = "Testiohjelma"; static W32 *pw32; //Luokan ilmentymän muistiosoite //Ikkunan luokkatietueen alustus WNDCLASSEX wcOma = { sizeof(WNDCLASSEX), //Tietueen koko CS_BYTEALIGNWINDOW | CS_DBLCLKS, //Ikkunan tyyli (WNDPROC)WndProc, //Ikkunaproseduurin osoite 0, //Lisätavut ikkunan tietueelle 0, //Lisätavut ikkunalle NULL,//Ohjelman ilmentymän kahva (ei vielä tiedossa) NULL,//Luokan ikoni NULL,//Ikkunan kursori (ei vielä tiedossa) (HBRUSH)COLOR_APPWORKSPACE,//Taustaväri NULL, //Valikon kahva ohjnimi,//Ikkunan luokan nimi NULL //Luokan pieni ikoni }; //Pääohjelma (parametreja ei käytetä) int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) { W32 w32; //Luokan ilmentymä eli olio int i; pw32 = &w32; //Olion muistiosoite talteen wcOma.hInstance = GetModuleHandle(NULL); //Ohjelman ilmentymän kahva wcOma.hCursor = LoadCursor(NULL, IDC_ARROW); //Ikkunan kursori (nuoli) if(RegisterClassEx(&wcOma)) { //Luokan rekisteröinti //Luodaan päänäkymä (katso parametrit muualta) HWND hwnd = CreateWindowEx(0, ohjnimi, ohjotsikko, WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, NULL, NULL, wcOma.hInstance, NULL); ShowWindow(hwnd, SW_SHOWNORMAL); //Aktivoi ja näyttää ikkunan while(i = GetMessage(&w32.msg, NULL, 0, 0) && i != -1) { //Sanomasilmukka TranslateMessage(&w32.msg); //Muunnetaan näppäimistöviestit //Kaikki omat luokat käydään läpi ennen DLL:ssä olevia, jotta //viestiä ei tarvitsisi pompotella useampaan kertaan if(hwnd == w32.msg.hwnd) w32.WindowProc(); //Viestien käsittely luokan avulla else DispatchMessage(&w32.msg); //Muut viestit lähetetään 'normaalisti' } } #ifndef _DEBUG ExitProcess(0); //Lopetetaan säikeet ja prosessi #endif //Oletuksena viimeisen viestin paluuarvo on ohjelman paluuarvo return(w32.msg.wParam); } //Ikkunaproseduuri (päänäkymä) //hWnd=näkymän osoite, Msg=viesti näkymälle //wParam ja lParam: viestikohtainen tieto LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { //Seuraavassa käsitellään malliksi pari viestiä luokan olkopuolella switch(iMsg) { //Sanomien käsittelyrakenne case WM_CREATE: //Ikkuna on luotu //Luodaan OK -napin ikkuna (x=150,y=50,leveys=40,korkeus=20) CreateWindowEx(0, "BUTTON", "OK", WS_CHILD | WS_VISIBLE, 150, 50, 40, 20, hWnd, NULL, wcOma.hInstance, NULL); return 0; //Ikkunan käyttö voi jatkua case WM_DESTROY: //Lopetussanoman sanomakäsittelijä PostQuitMessage(0); //Säie lopetetaan (sanomasilmukka päättyy) return 0; } //ja loput viestit luokan avulla pw32->SetMessage(&hWnd); //Kopioidaan kaikki parametrit talteen return pw32->WindowProc(); //Viestien käsittely luokan avulla }
W32.H
//W32 luokka. //Esimerkki WIN32 sanomajonon käytöstä C++ -pohjassa #ifndef W32_h #define W32_h // SYSTEM INCLUDES #include <windows.h> #include <memory.h> // PROJECT INCLUDES // LOCAL INCLUDES // FORWARD REFERENCES class W32 { public: // LIFECYCLE // Default constructor W32(void); // Copy constructor // from - The value to copy to this object W32(const W32* from); // Destructor ~W32(void); // OPERATORS // Assignment operator // from - value to assign to this object W32& operator=(W32* from); // OPERATIONS // Save new message // from - message start position (hWnd) void SetMessage(void* from); // Application-defined callback function to process messages LRESULT WindowProc(); // ACCESS // INQUIRY MSG msg; //Messages to the program protected: private: // MEMBER VARIABLES }; // INLINE METHODS // EXTERNAL REFERENCES #endif // _W32_h_
W32.CPP
//WIN32 sanomajonon käyttö C++ -pohjassa //Luokka sisältää malliksi vain muutaman viestin käsittelyt #include "W32.h" // class implemented //////////////////////////////// PUBLIC //////////////////////////////////////// //============================== LIFECYCLE ===================================== W32::W32() { memset(this, 0, sizeof(W32)); }//W32 W32::W32(const W32* from) { memcpy(this, from, sizeof(W32)); }//W32 W32::~W32() { }//~W32 //============================== OPERATORS ===================================== W32& W32::operator=(W32* from) { memcpy(this, from, sizeof(W32)); return *this; }//= //============================== OPERATIONS ==================================== //4 -parametrisen viestin taltiointi //from - viestin alkupiste (hWnd -parametrin osoite) void W32::SetMessage(void* from) { memcpy(&msg, from, sizeof(void*)*4); } //Tulevien viestien käsittely LRESULT W32::WindowProc() { //Viivojen ääripisteet (X -kuvio) const POINT ppisteet[]={{0,0},{100,100},{0,100},{100,0}}; const DWORD npisteet[]={2,2}; //Pisteiden lukumäärä switch(msg.message) { //Sanomien käsittelyrakenne case WM_PAINT: //Ikkuna aiotaan piirtää HDC hDC; PAINTSTRUCT ps; //Piirron asetukset hDC = BeginPaint(msg.hwnd, &ps); //Aloitetaan piirto PolyPolyline(hDC, ppisteet, npisteet, 2); //Piirretään kaksi viivaa EndPaint(msg.hwnd, &ps); //Lopetetaan piirto return 0; case WM_COMMAND: //Kontrollien viestit if(HIWORD(msg.wParam) == BN_CLICKED) //Nappia klikattiin MessageBox(NULL,"OK nappia","Klikkasit",0); //Viesti käyttäjälle return 0; default: //Sanomien oletuskäsittely return DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); } } //============================== ACCESS ==================================== //============================== INQUIRY ==================================== //////////////////////////////// PROTECTED //////////////////////////////////// //////////////////////////////// PRIVATE ////////////////////////////////////
Winmain
Visual Studiolla on mahdollisuus poistaa turhat koodit ohjelmasta. Jos haluat ohjelman ilman C -kirjaston lisukkeita, korvaa edellä olevasta Winmain:
#ifdef _DEBUG int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) #else int WinMainCRTStartup(void) #endif
Asetuksia on hieman muutettava eli:
- Visual Studio 6: 'Ignore all default libraries' -kohta päälle ja 'Enable exception handling' -kohta pois päältä
- Visual Studio 2005: 'Ignore All Default Libraries' -kohta päälle, 'Enable C++ exceptions' -kohta pois päältä ja 'Buffer Security Check' pois päältä
