int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
/*------------------------------------------------------------------------------------------------------------------------------------------
HelloWin.c - Afiseaza textul "Hello, Windows!" in zona client
------------------------------------------------------------------------------------------------------------------------------------------*/

#include<windows.h>

long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
static char             szAppName[]="HelloWin";
HWND                hwnd;
MSG                    msg;
WNDCLASS      wndclass;

if (!hPrevInstance)
    {
      wndclass.style                    =CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc      =WndProc;
      wndclass.cbClsExtra         =0;
      wndclass.cbWndExtra       =0;
      wndclass.hInstance            =hInstance;
      wndclass.hIcon                   =LoadIcon(NULL,IDI_APPLICATION);
      wndclass.hCursor               =LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground   =GetStockObject(WHITE_BRUSH);
      wndclass.lpszMenuName  =NULL;
      wndclass.lpszClassName  =szAppName;

      RegisterClass( &wndclass);
     }
     hwnd=CreateWindow  (szAppName,                                        //window class name
                                              "Program Win minimal",                     //window caption
                                              WS_OVERLAPPEDWINDOW,       //window style
                                               CW_USEDEFAULT,                        //initial x position
                                               CW_USEDEFAULT,                        //initial y position
                                               CW_USEDEFAULT,                        //initial x size
                                               CW_USEDEFAULT,                        //initial y size
                                               NULL,                                                 //parent window handle
                                               NULL,                                                 //window menu handle
                                               hInstance,                                           //program instance handle
                                               NULL);                                                //creation parameters

      ShowWindow (hwnd, nCmdShow);
      UpdateWindow(hwnd);
 
      while (GetMessage ( &msg, NULL, 0, 0))
            {
              TranslateMessage ( &msg);
              DispatchMessage (hwnd);
             }
      return  msg.wParam;
}
 

long FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wParam, LONG IParam)
    {
      HDC                     hdc;
      PAINTSTRUCT  ps;
      RECT                   rect;

      switch( message)
            {
               case WM_PAINT:
                             hdc= BeginPaint (hwnd, &ps);
                             GetClientRect (hwnd, &rect);

                              DrawText( hdc, 'Hello Windows!', -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
                              EndPaint (hwnd, &ps);
                              return 0;

                case WM_DESTROY:
                              PostQuitMessage (0);
                              return 0;
        return DefWindowProc (hwnd, message, WParam, IParam);
    } 
  
 

 Comentarii:

        Se poate observa in cadrul programului  anumiti termeni care au o denumire mai speciala (ex. lpszCmdParam, hInstance, nCmdShow, ...). Aceasta conventie de notare este denumita hungarian (a fost denumita astfel in onoarea legendarului programator de la Microsoft, Charles Simonyi) si este utilizata pentru a creea nme de variabile si functii; ea permite scrierea si depanarea unui cod lizibil. Prefixul plasat in fata unui nume descrie tipul de date la care se refera variabila: in acest context, prefixul lpsz din lpszCmdParam inseamna "long pointer to a string terminated by zero", prefixul "h" din hInstance reprezinta handle, etc. 
Programul incepe cu
     #include <windows.h>
      
pentru a include in program fisierul header ce contine declaratiile de functii si structuri aferente sistemului Windows, tipuri de date, constante numerice, etc. Apoi este declarata procedura WndProc, procedura care va fi definita mai tarziu si care se va ocupa de tratarea evenimentelor asociate ferestrei:
     long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
Apoi urmeaza descrierea functiei WinMain .

I. WinMain

Aceasta functie este echivalenta functiei main dintr-un program C pentru DOS si contine instructiunile programului propriu-zis (ea este absolut obligatorie intr-un program C pentru windows). Antetul functiei si semnificatia parametrilor e urmatoarea:
     int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
Aceasta functie utilizeaza secventa de apelare Pascal.

  • hInstance - instance handler, este un numar care identifica in mod unic instanta programului aflat in executie (la un moment dat pot rula mai multe copii ale aceluiasi program.
  • hPrevInstance - este identificatorul celei mai recente instante (anterioare) a programului, care este inca activ; daca nu exista copii ale programului incarcate in memorie acest parametru este NULL.
  • lpszCmdParam - o variabila de tip pointer ce puncteaza la un sir terminat cu octetul 0, ce contine parametrii din linia de comanda (spre deosebire de argv din C/C++ care puncteaza laun vector de siruri de caractere, lpszCmdParam puncteaza la un singur sir de caractere)
  • cmdShow - este un numar ce indica modul de afisare al primei ferestre executate: acest numar este atribuit de orice program ce executa programul ce ruleaza sub Windows.
              In interiorul functiei sunt declarate trei date:
  • wnd este pointer spre clasa fereastra;
  • msg este pointer spre o structura de date MSG;
  • hwnd este handle pentru fereastra curenta.

    I.1 Window Class

             Orice fereastra este caracterizata de o clasa window. Aeasta clasa identifica procedura window care prelucreaza mesajele sosite de la sistemul de operare pentru o fereastra si precizeaza o serie de alti parametrii ce caracterizeaza fereastra respectiva si care vor fi descrisi in cele ce urmeaza. Putem creea mai multe ferestre pe baza aceleiasi clase window (de pilda putem creea butoane). Inainte de a creea o fereastra pentru programul nostru va trebui sa inregistram clasa fereastra cu ajutorul functiei RegisterClass. Structura de date care descrie clasa fereastra ete WNDCLASS. Campurile acesteia sunt:

  • style - identifica stilul ferestrei; CS_VREDRAW si CS_HREDRAW semnaleaza faptul ca toate ferestrele create pe baza acestei clase vor fi reactualizate integral, ori de cate ori se modifica dimensiunea orizontala sau cea verticala.
  • lpfnWndProc - contine numele procedurii window (in cazul nostru WndProc) care se va ocupa cu tratarea evenimentelor adresate ferestrei.
  • cbClsExtra - rezerva spatiu suplimentar in structura class .
  • cbWndExtra - rezerva spatiu suplimentar in structura window . Un program poate utiliza acest spatiu in scopurile sale personale.
  • hInstance - identificatorul instantei programului.
  • hIcon - stabileste un icon pentru toate ferestrele create pe baza acestei clase. Functia LoadIcon este apelata pentru a obtine un handle al unei pictograme predefinite (IDI_APPLICATION ) sub forma unui patrat cu contur de culoare neagra.
  • hCursor - stabileste un cursor pentru mouse. Functia LoadCursor incarca un cursor predefinit al mousului (IDI_ARROW).
  • hbrBackground - specifica culoarea de fundal a zonei client a ferestrei create pe baza clasei window. Sistemul Windows poseda mai multe pensule standard. Functia GetStockObject inapoiaza un identificator (handle) al unei pensule de culoare alba (WHITE_BRUSH ).
  • lpszMenuName - sir de caractere care indica numele meniului ferestrei. Programul nostru nu va avea nici unul, drept urmare il setam la NULL.
  • lpszClassName - numele clasei fereastra.
               Dupa ca am initializat cele 10 campuri ale structurii wndclass putem inregistra clasa window cu ajutorul functiei RegisterClass. Singurul parametru al acestei rutine este o variabila de tip pointer la o structura WNDCLASS.

    I.2 CreateWindow

               Clasa window defineste carecteristicile generale ale unei ferestre, fapt ce permite utilizarea aceleiasi clase la crearea mai multor ferestre diferite. Cand cream o fereastra prin intermediul functiei CreateWindow, specificam informatii mai detaliate despre fereastra. In loc sa utilizeze o structura de date - asa cum procedeaza rutina RegisterClass - functia CreateWindow cere ca toate informatiile sa fie pasate ca parametrii ai functiei. Modul de apel al rutinei este urmatorul:
    hwnd=CreateWindow  (szAppName,                                      //window class name
                                          "Program Win minimal",                  //window caption
                                          WS_OVERLAPPEDWINDOW,      //window style
                                          CW_USEDEFAULT,                        //initial x position
                                          CW_USEDEFAULT,                        //initial y position
                                          CW_USEDEFAULT,                        //initial x size
                                          CW_USEDEFAULT,                        //initial y size
                                          NULL,                                               //parent window handle
                                          NULL,                                               //window menu handle
                                          hInstance,                                          //program instance handle
                                          NULL);                                              //creation parameters

    Parametrul window class name este numele clasei fereastra inregistrate. Fereastra creata a acestui program este o fereastra de tip overlapped    (peste care se pot suprapune alte ferestre), ce poseda o bara de titlu, o caseta  cu system menu (plasata la stanga barei de titlu),   butoanele minimize si maximize   (situate la dreapta barei de   titlu) si un cadru gros pentru redimensionarea ferestrei. Window caption   reprezinta textul afisat pe bara de titlu. Window style este WS_OVERLAPPEDWINDOW si este stilul standard al unei ferestre. Parametrii initial x position si initial y position  specifica pozitia initiala a coltului din stanga sus al ferestrei in raport cu coltul din stanga sus al ecranului. Valoarea CW_USEDEFAULT pentru acesti parametrii semnaleaza sistemului Windows ca dorim o pozitie implicita pentru fereastra noastra. In mod similar, parametrii initial x size si initial y size specifica prin valoarea CW_USEDEFAULT dimensiuni implicite pentru latimea si inaltimea ferestrei. Parametrul marcat parent window handle este stabilit la valoarea NULL deoarece fereastra programului nostru nu are o fereastra de tip parent   (adica un superior); daca exista o relatie de rudenie parent-child intre doua ferestre, atunci fereastra child apare intotdeauna deasupra ferestrei parent aferenta. Parametrul window menu handle este un handle de meniu; noi il fixam la NULL pentru ca fereastra noastra nu poseda meniu. Parametrul program instance handle va avea ca valoare identificatorul instantei ce este pasat programului ca parametru al functiei WinMain . In final, variabila pointer creation parameter este stabilita la valoarea NULL. Valoarea de retur a functiei CreateWindow este un handle de fereastra (o valoare de tipul HWND). Fiecare fereastra (in sistemul Windows poseda un handle, iar programul nostru il utilizeaza pentru a se referi la fereastra. 

    I.3 Afisarea ferestrei

              Dupa ce am creat fereastra, mai trebuie sa o afisam. Afisarea o facem cu functia ShowWindow:
              ShowWindow(hwnd, nCmdShow);
    Primul parametru este handler-ul de fereastra, iar al doilea este valoarea nCmdShow pasat functiei WinMain ca si parametru (acesta determina modul -initial- de afisare al ferestrei pe ecran; daca nCmdShow are valoarea SW_SHOWNORMAL (=1), fereastra este afisata normal; daca nCmdShow are valoarea SW_SHOWMINNOACTIVE (=7), fereastra este afisata sub forma de pictograma. Functia ShowWindow sfiseaza fereastra sau pictograma pe ecran. Daca nCmdShow=SW_SHOWNORMAL, va fi stearsa zona client cu pensula pentru fundal, specificata in clasa window . Rutina
             UpdateWindow(hwnd);
    produce reactualizarea zonei client; acest lucru se realizeaza prin expedierea mesajului WM_PAINT procedurii window (functia WndProc).

    I.4 Bucla de mesaje (the message loop)

            Dupa ce am afisat ferestra pe ecran (cu ShowWindow si UpdateWindow) programul este pregatit pentru a prelua date de la utilizator prin intermediul tastaturii si mouse-ului. Sistemul Windows intretine pentru fiecare fereastra o structura de date numita message queue (coada de mesaje). De fiecare data cand se produce un eveniment de intrare, sistemul Windows il converteste intr-un mesaj si-l plaseaza in coada de mesaje. Un program extrage aceste mesaje din message queue prin executia unui bloc numit message loop:
    while (GetMessage ( &msg, NULL, 0, 0)) 
          { 
            TranslateMessage ( &msg); 
             DispatchMessage (hwnd); 
          } 
    return  msg.wParam;
    Variabila msg este o structura de tip MSG care este definita in fisierul Window.h:
    typedef struct tagMSG
          {
            HWND         hwnd;
             UINT            message;
             WPARAM   wParam;
             LPARAM    lParam;
             DWORD     time;
             POINT        pt;
          } MSG;
    typedef struct tagPOINT
         {
           int x;
           int y;
         } POINT;
    Prin invocarea functiei GetMessage, bucla de prelucrare extrage un mesaj din message queue
    GETMessage( &msg, NULL, 0, 0);
    Acest apel paseaza sistemului Windows o veriabila pointer de timp far, care puncteaza la structura MSG. Parametrii doi, trei si patru sunt fixati la valoarea NULL/0 pentru a indica ca programul doreste toate mesajele aferente tuturor ferestrelor create de program. Mediul de operare va pune in campurile variabilei msg urmatoarele valori:
  • hwnd - indica handlerul ferestrei care primeste mesajul
  • message - un numar care identifica mesajul. Pentru fiecare mesaj exista un identificator corespunzator, care e definit in fisierul Window.h, care incepe cu prefixul WM (de la window message)
  • wParam - reprezinta un 16-bit message parameter, a carui valoare si semnificatie depind de tipul mesajului
  • lParam - este un 32-bit message parameter, a carui valoare depide de tipul mesajului
  • time - momentul in care mesajul a fost plasat in message queue
  • pt - coordonatele mouse-ului in momentul in care mesajul a fost plasat in queue

  • Daca campul message - extras din coada de mesaje - are orice alta valoare diferita de WM_QUIT (0x0012), atunci rutina GetMessage va inapoia o valoare diferita de zero. Mesajul WM_QUIT produce iesirea programului din bucla; ulterior programul se termina inapoiind membrul wParam al structurii msg. Instructiunea:
    TranslateMessage (&msg);
    paseaza inapoi sistemului Windows structura msg, pentru operarea unor conversii. Instructiunea
    DispatchMessage(&msg);
    repaseaza inapoi structura msg; ulterior, mediul de operare, va expedia mesajul procedurii window corespunzatoare (WndProc), pentru prelucrarea mesajului. Dupa ce rutina prelucreaza mesajul, ea va inapoia controlul sistemului Windows care va termina apelul DispatchMessage, iar apoi bucla va continua cu urmatorul apel al functiei GetMessage.