Win32 Cpp

Mureakuha

Loikkaa: valikkoon, hakuun

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ä
Henkilökohtaiset työkalut