Home

History

Blog

'C' Lesson

<<

>>


Programmer en 'C' sous Windows
MinPrg03: Les contrôles Windows basiques.

Le système fournit un ensemble de fenêtres spécialisées qu'on appèle "contrôle" et qui permet de fabriquer des interfaces utilisateur graphique (GUI = Graphic User Interface). Ce sont des boutons, des listes, des boites de saisie etc... L'exemple qui suit montre comment mettre en oeuvre de tels contrôles.

MinPrg03 : Basic Window Controls


Les Fichiers Organisation du Source Code
MiniPrg_03.exe (260KB 21-MAR-2008)
MiniPrg_03.zip (83KB 21-MAR-2008)
minprg.h
minprg.c
minprg.rc
tools.h
tools.c
MinPrg02 : Source Organization

Que fait ce programme ? :
On continue d'étoffer notre précédent exemple en ajoutant 4 contrôles Windows différents : Une boite d'édition (Edit Box), une boite à choix multiples (Combo Box), un bouton poussoir (Push Button) et un liste à droite (List Box).
  • Quand on bouge le Slider, chaque modification crée une entrée supplémentaire dans la liste, la boite de saisie est mise à jour avec la valeur courante du Slider, la combo box est aussi mise à jour en fonction de la position du Slider.
  • Quand on saisie une valeur dans l'Edit Box, le Slider et la Combo box sont automatiquement mis à jour, à chaque nouveau caractère tapé.
  • La Combo Box permet aussi de changer la valeur du Slider.
  • La liste Box stock tous les mouvements du Slider et la sélection d'une entrée de la liste rappelle la position du curseur en mettant à jour les autres contrôles.
  • un Clic gauche sur le fond de la fenêtre affiche toujours une boite bleu avec l'état des touches CTRL et SHIFT. Un clic droit déclenche l'ouverture d'un Popup menu.


  • Les grands principes évoqués :
    Les contrôles sont aussi des fenêtres (se créant avec la fonction CreateWindow) mais dont la classe est déjà définie. On a vu, puisqu'on l'a déjà fait, que la classe d'une fenêtre est associée à une Callback qui s'occupe de tout son comportement et de ses fonctionnalités. Dans le cas des contrôles Windows, toute cela est déjà définit par le système pour les classes dénommées : "edit", "button", "combobox", "listbox" etc... Ces contrôles sont usuellement des fenêtres filles qui s'affichent dans la partie cliente de la fenêtre père. L'ordre de leur création donne le Z-Order, c'est à dire l'ordre dans lequel les fenêtres sont empilées les unes sur les autres. Si vous affichez deux contrôles au même endroit, c'est le dernier créé qui sera visible.

    Selon le principe qui veut qu'une fenêtre prenne en charge l'affichage de sa zone client et tous les événements qui s'y rapportent, vous n'avez plus à gérer l'affichage de votre zone client occupée par un contrôle fils. Dans l'exemple, nous n'affichons d'ailleurs rien sous la "list box", ni en réponse à WM_ERASEBKGND ni en réponse à WM_PAINT, c'est inutile. De même tous les événements souris se rapportant à cette zone seront gérés par la Callback du contrôle concerné. Faites l'expérience de passer la souris sur le bouton poussoir par exemple, notre programme ne reçoit plus les messages WM_MOUSEMOVE et donc n'affiche plus les coordonnées souris pour cette zone.

    Communication avec les contrôles.
    A partir du moment où l'on crée des contrôles Windows pour gérer certaines actions utilisateur, il faut pouvoir être prévenus, notifiés, ou au moins être en capacité de récupérer l'information qui découle des ces actions. L'essentiel de la communication entre contrôles Windows passe par des "Messages". On envoie des messages aux contrôles pour changer leur état ou leur aspect et l'on reçoit des messages quand le contrôle est manipulé.

    Pour envoyer un message, on a grosso modo le choix entre deux fonctions :
    - SendMessage(.) qui est une fonction dites "synchrone" car elle est bloquante, c'est un peu comme si vous appeliez directement la Callback d'un contrôle.
    - PostMessage(.) qui est une fonction dites "asynchrone" car elle ne fait que déposer le message dans la file de messages (Message Queue) et n'attend donc pas la réponse du contrôle visé.

    Notons que d'autres API (d'autres fonctions du système) peuvent être l'équivalent d'un envoi de Message. Par exemple la fonction SetWindowText() qui permet de changer le "WindowName" d'une fenêtre (ou d'un contrôle) est équivalente à l'utilisation d'un message WM_SETTEXT. Il faut retenir que l'ensemble des contrôles Windows se gère par l'utilisation de message et qu'il y a un jeu spécifique de messages pour chaque type de contrôle.


    Quelques points du source :
    On a conservé l'intégralité du source code de la leçon précédente et l'on a ajouté une fonction CreateOurControls(.) qui s'occupe de créer nos controles windows dans notre fenêtre principale. En réponse à WM_ERASEBKGND nous affichons toujours notre Bitmap de fond mais, comme notre Bitmap ne couvre pas forcément toute la surface, nous dessinons aussi un fond gris dessous en fonction de la taille courante de notre zone client. Les messages qui nous arrivent des contrôles Windows sont essentiellement des notifications, donc passent par le message WM_COMMAND que l'on traite dans notre fonction ManageMenu(.). Dans le paramètre WPARAM sont codés l'ident du contrôle (dans la partie LOWORD) et l' éventuel message de notification (dans la partie HIWORD).

    Pour la List BOX on traite le message de notification LBN_SELCHANGE qui nous arrive à chaque fois que l'utilisateur choisi un item dans la liste. Pour L'Edit Box on traite le message EN_CHANGE qui nous est transmit à chaque saisie d'un nouveau caractère. Pour la Combo Box on répond à la notification CBN_SELCHANGE qui est envoyée quand l'utilisateur sélectionne un autre item de la liste de choix. Le Bouton poussoir ayant été définit avec l'Ident IDM_ABOUT va avoir la même fonction que l'item du Menu IDM_ABOUT qui est déjà traité.

    Relations entre les contrôles :
    La difficulté de notre exemple se situe dans la manière de gérer nos relations entre nos contrôle et notre Slider, relations que l'on a voulues temps réel, c'est à dire que tout changement est pris en compte immédiatement. Donc si vous suivez la section WM_MOUSEMOVE vous voyez que pour chaque mouvement du Slider, on va ajouter une entrée dans la liste box, mettre à jour la boite d'édition et la combo-box.

    De même, dès que vous allez taper un caractère dans l'Edit Box, on va recevoir une notification EN_CHANGE (voir fonction ManageMenu). Après avoir pris connaissance de la nouvelle valeur de notre Slider, on va l'afficher à sa nouvelle position et mettre à jour le Combo-Box. Donc simplement pour chaque modification sur un contrôle donné, on va mettre à jour tous les autres contrôles qui dépendent de la même donnée, ici la valeur de notre Slider. Seule exception, la ListBox sert d'historique de mouvement souris du Slider et n'est pas mise à jour quand on utilise un autre contrôles que le Slider.

    Dans le code source, vous verrez qu'on a fait une gestion au cas par cas, notamment pour faire apparaître clairement un phénomène de réentrance qu'il faut gérer quand on met en place ce genre de relations croisées entre contrôles Windows. En effet l'appel à SetWindowText() pour mettre à jour une EditBox par exemple, va déclencher la notification EN_CHANGE, sans passer par la boucle de messages. Cet notification EN_CHANGE, si elle est traité comme une action utilisateur, peut déclencher la mise à jour d'autres contrôles, qui à leur tour, peuvent générer d'autres messages de notification et ainsi de suite... c'est le blocage par boucle infini où Paul appelle Pierre qui appelle Paul qui rappelle Pierre etc...

    Donc pour éviter ce phénomène on met en place des variables d'état que l'on appelle drapeau (flag en anglais) telles que fMoveSlider, fUpdateFromComboBox, fUpdateFromEditBox, pour savoir qu'est ce qu'on est en train de faire, et différencier une notification qui serait le produit d'une action utilisateur d'une notification qui découle d'une mise à jour par programme. Contre exemple : dans la gestion de notre ListBox, en réponse à LBN_SELCHANGE on se sert de cette réentrance pour mettre à jour tout le monde en faisant seulement un SetWindowText(lpapp->hw_EditBox...) parce que l'on sait que cet appel va engendrer un EN_CHANGE qui va mettre à jour la position du Slider et le ComboBox.

    Le menu contextuel :
    Le menu contextuel n'est pas un contrôle (il a un peu les mêmes propriétés 'popup' que la DialogBox) mais constitue une manière assez pratique de permettre à l'utilisateur de changer des données ou de faire des actions. Il y'a tout un jeu d'API pour fabriquer des menus, nous utiliserons que CreatePopupMenu(), AppendMenu() et pour l'afficher : la fonction TrackPopupMenu() que nous appelons sur le message WM_RBUTTONDOWN.


    Questions / Réponses:
    Quand on redimensionne notre fenêtre, comment les contrôles sont repositionnés / redimensionnés ?
    En réponse au message WM_SIZE, on repositionne ou redimensionne nos contrôles à l'aide de la fonction SetWindowPos(...).

    atof ? que fait cette fonction ?
    C'est une fonction 'C' générique qui convertie une chaîne de caractères en une valeur numérique réelle (double ou float).

    Dans le source tools.c la fonction TOOL_MemZERO semble être défini dans un autre langage ?
    C'est de l'assembleur inline, et cette fonction, qui met à zéro une plage mémoire définit par un pointeur (target) et une taille (nbByte), constitue une bonne introduction à l'usage de l'assembleur dans un programme en C/C++ avec les outils Microsoft.

    Qu'est ce que la "Ré-Entrance" ?
    Pour une fonction donnée, la réentrance est l'action d'être rappelé avant d'être sortie de la fonction (avant la fin de la fonction). Dans notre exemple, vous pouvez tracer l'action de l'utilisateur qui sélectionne un item dans la ListBox. Notre Callback est d'abord appelée pour un LBN_SELCHANGE, pour lequel on fait un SetWindowText(lpapp->hw_EditBox,sss); mais cet appel va engendrer une réentrance : notre Callback va être rappelée avec la notification EN_CHANGE. Ce n'est qu'après le traitement EN_CHANGE que le code concernant LBN_SELCHANGE se finira.


    Source : minprg.c

    /*--------------------------------------------------------------------------------*/
    /* 'C' Programming Under WIN32                                     V.Burel (c)2008*/
    /*                                                                                */
    /*  WEB  : http://pagesperso-orange.fr/vb-audio/fr/pub/programming/index.htm      */
    /*--------------------------------------------------------------------------------*/
    /* This MinPrg is a minimal program under windows (like a Hello World)            */
    /* To demonstrate how to use basic Windows Control                                */
    /* Edit Box, Push Button, Combo Box, List Box and contextual popup menu           */
    /*--------------------------------------------------------------------------------*/
    /*  To compile With Microsoft VC2005 you need to create an empty Win32 project    */
    /*  with the following options :                                                  */
    /*  - Configuration Properties / General : Char Set = NOT SET                     */
    /*  - Configuration Properties / C/C++ / Preprocessor : _CRT_SECURE_NO_DEPRECATE  */
    /*--------------------------------------------------------------------------------*/
    #ifndef __cplusplus
       #ifndef STRICT
          #define STRICT
       #endif
    #endif
    #include <windows.h>
    #include <stdio.h>
    #include "minprg.h"
    #include "tools.h"
    
    //
    //define globals 
    //
    static HWND         G_hwnd_MainWindow   =NULL;
    static HINSTANCE   G_hinstance         =NULL;
    
    // we create a strcuture to store GDI Resources.
    typedef struct tagCOLORPENBRUSH
    {
       COLORREF   color;
       HPEN      pen;
       HBRUSH      brush;
    } T_COLORPENBRUSH, *PT_COLORPENBRUSH, *LPT_COLORPENBRUSH;
    
    //we create a main structure and data to store application data.
    typedef struct tagAPP_CONTEXT
    {
       //resources
       HBITMAP bmp_bkg;
       HBITMAP bmp_cursor;
    
       HFONT   font_small;
       HFONT   font_med;
       HFONT   font_big;
    
       T_COLORPENBRUSH   gdiobjects_gray1;
       T_COLORPENBRUSH   gdiobjects_gray2;
       T_COLORPENBRUSH   gdiobjects_bleu;
       T_COLORPENBRUSH   gdiobjects_red;
       //controls:
       HWND   hw_ListBox;
       HWND   hw_EditBox;
       HWND   hw_ComboBox;
       HWND   hw_PushButton;
       HMENU   hPopupMenu;
       long   nbHistoryValue;
       BOOL   fUpdateFromEditBox;
       BOOL   fUpdateFromComboBox;
       //data
       long   mouse_x, mouse_y;
       float   slider_value;
       long   lastmouse_x;
       HWND   LastCapture;
       BOOL   fMoveSlider;
    } T_APP_CONTEXT, *PT_APP_CONTEXT, *LPT_APP_CONTEXT;
    
    static T_APP_CONTEXT G_MainAppCtx;
    
    /*******************************************************************************/
    /**                           INIT / END Resources                            **/
    /*******************************************************************************/
    
    long CreateColorPenBrush(LPT_COLORPENBRUSH lpgdi, COLORREF color)
    {
       LOGBRUSH   lb;
       if (lpgdi == NULL) return -1;
       lpgdi->color=color;
       lpgdi->pen=CreatePen(PS_SOLID,0,color);
    
       lb.lbStyle=BS_SOLID;
       lb.lbColor=color;
       lpgdi->brush=CreateBrushIndirect(&lb);
       return 0;
    }
    
    long DestroyColorPenBrush(LPT_COLORPENBRUSH lpgdi)
    {
       if (lpgdi == NULL) return -1;
       
       lpgdi->color=0;
       if (lpgdi->pen != NULL) DeleteObject(lpgdi->pen);
       lpgdi->pen=NULL;
       if (lpgdi->brush != NULL) DeleteObject(lpgdi->brush);
       lpgdi->brush=NULL;
       return 0;
    }
    
    
    long InitResources(LPT_APP_CONTEXT lpapp)
    {
       LOGFONT      lf;
    
       if (lpapp == NULL) return -1;
       //Load Bitmap Resources
       lpapp->bmp_bkg      =LoadBitmap(G_hinstance,MAKEINTRESOURCE(100));
       lpapp->bmp_cursor   =LoadBitmap(G_hinstance,MAKEINTRESOURCE(101));
    
       //make Font
       memset(&lf,0, sizeof(LOGFONT));
       lf.lfHeight   = 14;
       lf.lfWeight   = 400;
       strcpy(lf.lfFaceName,"Arial");
       lpapp->font_small =CreateFontIndirect(&lf);
    
       lf.lfHeight   = 22;
       lf.lfWeight   = 400;
       strcpy(lf.lfFaceName,"Arial");
       lpapp->font_med =CreateFontIndirect(&lf);
       
       lf.lfHeight   = 40;
       lf.lfWeight   = 400;
       strcpy(lf.lfFaceName,"Arial");
       lpapp->font_big =CreateFontIndirect(&lf);
       //make pen brush 
       CreateColorPenBrush(&(lpapp->gdiobjects_gray1), RGB(100,100,100));
       CreateColorPenBrush(&(lpapp->gdiobjects_gray2), RGB(150,150,150));
       CreateColorPenBrush(&(lpapp->gdiobjects_bleu), RGB(0,0,250));
       CreateColorPenBrush(&(lpapp->gdiobjects_red), RGB(255,0,0));
       return 0;
    }
    
    long EndResources(LPT_APP_CONTEXT lpapp)
    {
       if (lpapp == NULL) return -1;
       //Delete Bitmap Object
       if (lpapp->bmp_bkg != NULL) DeleteObject(lpapp->bmp_bkg);
       lpapp->bmp_bkg=NULL;
       if (lpapp->bmp_cursor != NULL) DeleteObject(lpapp->bmp_cursor);
       lpapp->bmp_cursor=NULL;
       //Delete font Object
       if (lpapp->font_small != NULL) DeleteObject(lpapp->font_small);
       lpapp->font_small=NULL;
       if (lpapp->font_med != NULL) DeleteObject(lpapp->font_med);
       lpapp->font_med=NULL;
       if (lpapp->font_big != NULL) DeleteObject(lpapp->font_big);
       lpapp->font_big=NULL;
       //Delete Pen Brush
       DestroyColorPenBrush(&(lpapp->gdiobjects_gray1));
       DestroyColorPenBrush(&(lpapp->gdiobjects_gray2));
       DestroyColorPenBrush(&(lpapp->gdiobjects_bleu));
       DestroyColorPenBrush(&(lpapp->gdiobjects_red));
       return 0;
    }
    
    /*******************************************************************************/
    /**                                QUIT & ABOUT                               **/
    /*******************************************************************************/
    
    void ManageCloseMessage(HWND hw)
    {
       int rep;
       char titre[]="Close Application...";
       char message[512];
       
       //Get the string from resource, otherwise we use a constant.
       if (LoadString(G_hinstance, IDS_CONFIRMCLOSE, message, 512) == 0)
          strcpy(message,"Do you Want To Close This Application ?\n"
                      "(but there is a problem to load resources)");
       //Open System Dialog Box 
       rep=MessageBox(hw,message,titre,MB_APPLMODAL | MB_YESNO | MB_ICONQUESTION);
       if (rep == IDNO) return;
    
       PostMessage(hw,WM_DESTROY,0,0L); //DestroyWindow(G_hwnd_MainWindow);
    }
    
    void ManageAboutBox(HWND hw)
    {
       char titre[]="About...";
       char message[512];
       strcpy(message,SZPUBLICNAME);
       strcat(message,"\nVersion : ");
       strcat(message,SZPUBLICVERSION);
       strcat(message,"\nStandalone Application\n");
       strcat(message,"\nExample of 'C' Source code\n");
       
       MessageBox(hw,message,titre,MB_APPLMODAL | MB_OK | MB_ICONINFORMATION);
    }
    
    
    /*******************************************************************************/
    /*******************************************************************************/
    /*******************************************************************************/
    
    BOOL InitSoftware(HWND hw)
    {
       InitResources(&G_MainAppCtx);
       
       return TRUE;
    }
    
    BOOL EndSoftware(HWND hw)
    {
       EndResources(&G_MainAppCtx);
       return TRUE;
    }
    
    /*******************************************************************************/
    /*                        Display information in LCD                           */
    /*******************************************************************************/
    
    void DisplayMousePosition(LPT_APP_CONTEXT lpapp, HDC dc)
    {
       char sss[64];
       long dx,dy;
       RECT rect;
       HFONT oldfont;
       //let's define some local data
       dx=190;
       dy=34;
       rect.left = 297;
       rect.top=14;
       rect.right=rect.left+dx;
       rect.bottom=rect.top+dy;
       //Draw background by using bitmap
       TOOL_DrawPartOfBitmap(dc, lpapp->bmp_bkg, rect.left,rect.top, rect.left,rect.top,dx,dy);
       //Draw X
       oldfont=(HFONT)SelectObject(dc,lpapp->font_med);
       SetTextColor(dc,lpapp->gdiobjects_gray1.color);
       SetBkMode(dc,TRANSPARENT);
    
       strcpy(sss,"x:");
       TextOut(dc,rect.left,rect.top+12,sss,(int)strlen(sss));
    
       sprintf(sss,"%i",lpapp->mouse_x);
       SelectObject(dc,lpapp->font_big);
       SetTextColor(dc,lpapp->gdiobjects_gray2.color);
       TextOut(dc,rect.left+15,rect.top,sss,(int)strlen(sss));
       //Draw Y
       rect.left +=100;
       SelectObject(dc,lpapp->font_med);
       SetTextColor(dc,lpapp->gdiobjects_gray1.color);
       strcpy(sss,"y:");
       TextOut(dc,rect.left,rect.top+12,sss,(int)strlen(sss));
    
       sprintf(sss,"%i",lpapp->mouse_y);
       SelectObject(dc,lpapp->font_big);
       SetTextColor(dc,lpapp->gdiobjects_gray2.color);
       TextOut(dc,rect.left+15,rect.top,sss,(int)strlen(sss));
    
       //replace previous GDI object in DC
       SelectObject(dc,oldfont);
    }
    
    void DisplaySlider(LPT_APP_CONTEXT lpapp, HDC dc)
    {
       float fmin,fmax,fratio;
       long dx_curs;
       long dx,dy,xx;
       RECT rect;
       //let's define some local data
       dx=250;         //width of the slider
       dy=18;         //height of the slider
       rect.left =13;   //position of the slider in the Client Area
       rect.top =24;
       rect.right=rect.left+dx;
       rect.bottom=rect.top+dy;
       //compute Cursor coordinates
       dx_curs=34;
       fmin=-24.0f;
       fmax=+24.0f;
       fratio=(dx-dx_curs)/(fmax-fmin);
       xx=(long)((lpapp->slider_value-fmin)*fratio);
       if (xx<0) xx=0;
       if (xx>(dx-dx_curs)) xx=dx-dx_curs;
       //Draw Slider and Cursor in 3 steps to minimize flickering effects.
       if (xx>0) TOOL_DrawPartOfBitmap(dc, lpapp->bmp_bkg, rect.left,rect.top, rect.left,rect.top,xx,dy);
       TOOL_DrawBitmap(dc,rect.left+xx,rect.top,lpapp->bmp_cursor);
       if ((xx+dx_curs)<dx) TOOL_DrawPartOfBitmap(dc, lpapp->bmp_bkg, rect.left+xx+dx_curs,rect.top, 
                                        rect.left+xx+dx_curs,rect.top,dx-(xx+dx_curs),dy);
    
    }
    
    void DisplaySliderValueInLCD(LPT_APP_CONTEXT lpapp, HDC dc)
    {
       HFONT oldfont;
       char sss[128];
       long dx,dy;
       RECT rect;
       //let's define some local data
       dx=190;
       dy=16;
       rect.left = 297;
       rect.top=52;
       rect.right=rect.left+dx;
       rect.bottom=rect.top+dy;
       //Draw background of the slider using bmp
       TOOL_DrawPartOfBitmap(dc, lpapp->bmp_bkg, rect.left,rect.top, rect.left,rect.top,dx,dy);
       //Draw value
       oldfont=(HFONT)SelectObject(dc,lpapp->font_small);
       SetTextColor(dc,lpapp->gdiobjects_red.color);
       SetBkMode(dc,TRANSPARENT);
       sprintf(sss,"Slider Value = %0.2f",lpapp->slider_value);
       DrawText(dc,sss,(int)strlen(sss),&rect,DT_SINGLELINE | DT_LEFT | DT_VCENTER);
       //replace previous GDI object in DC
       SelectObject(dc,oldfont);
    }
    
    void DisplayOurStuff(LPT_APP_CONTEXT lpapp, HDC dc)
    {
       DisplayMousePosition(lpapp,dc);
       DisplaySlider(lpapp,dc);
       DisplaySliderValueInLCD(lpapp, dc);
    }
    
    /*******************************************************************************/
    /**                               Manage Menu                                 **/
    /*******************************************************************************/
    
    static float extractValueFromListString(char *lpchar)
    {
       float ff;
       while ((*lpchar != 0) && (*lpchar != '=')) lpchar++;
       if (*lpchar != '=') return 0.0f;
       lpchar++;
       if (*lpchar == 0) return 0.0f;
       ff=(float)atof(lpchar);
       return ff;
    }
    
    void IMAIN_ProcessPopupCommand(HWND hparent, int nuCommand)
    {
       char sss[1024];
       switch(nuCommand)
       {
          case IDM_CTXPOPUP_INFO:
             TOOL_GetAppDirectory(sss);
             TOOL_GetPathOnly(sss);
             ShellExecute(hparent,"open","readme.txt",NULL,sss,SW_SHOW );
             break;
          case IDM_CTXPOPUP_WEB:
             ShellExecute(hparent,"open","http://www.vb-audio.com",NULL,NULL,SW_SHOW );
             break;
          case IDM_CTXPOPUP_MAIL:
             ShellExecute(hparent,"open","mailto:vincent.burel@nospam-vb-audio.com",NULL,NULL,SW_SHOW );
             break;
       }
    }
    
    
    void ManageMenu(LPT_APP_CONTEXT lpapp, HWND hw, WPARAM p,LPARAM w)
    {
       char sss[256];
       float ff;
       HPEN oldpen;
       HBRUSH oldbrush;
       long vi,x0,y0,nuCommand, nNotify,iSelect;
       HDC dc;
       nuCommand=(long)LOWORD(p);
       nNotify  =(long)HIWORD(p);
       switch(nuCommand)
       {
          case IDM_DRAWSOMETHING:
             dc=GetDC(hw);
             x0=300;
             y0=80;
             //Draw pixel.
             for (vi=0;vi<255;vi=vi+4)
             {
                SetPixel(dc,x0+(vi>>1),y0,RGB(vi,0,255-vi));
                SetPixel(dc,x0+1+(vi>>1),y0+1,RGB(vi,10,255-vi));
                SetPixel(dc,x0+(vi>>1),y0+2,RGB(vi,20,255-vi));
                SetPixel(dc,x0+1+(vi>>1),y0+3,RGB(vi,30,255-vi));
             }
             //Draw line.
             x0=x0+150;
             oldpen=(HPEN)SelectObject(dc,GetStockObject(BLACK_PEN));
             for (vi=0;vi<16;vi++)
             {
                MoveToEx(dc,x0+(vi<<1),y0,NULL);
                LineTo(dc,x0+(vi<<1),y0+4+vi);
             }
             //Draw empty rectangle
             x0=300;
             y0=90;
             oldbrush=SelectObject(dc,GetStockObject(NULL_BRUSH));
             Rectangle(dc,x0,y0,x0+20,y0+20);
             x0=x0+25;         
             RoundRect(dc,x0,y0,x0+20,y0+20,5,5);
             //Draw empy circle
             x0=x0+25;         
             Ellipse(dc,x0,y0,x0+20,y0+20);
             
             //Draw full rectangle
             SelectObject(dc,GetStockObject(WHITE_BRUSH));
             x0=x0+30;         
             Rectangle(dc,x0,y0,x0+20,y0+20);
             x0=x0+25;         
             RoundRect(dc,x0,y0,x0+20,y0+20,5,5);
             //Draw full circle
             x0=x0+25;         
             Ellipse(dc,x0,y0,x0+20,y0+20);
             
             //always select old objects, before releasing a DC.
             SelectObject(dc,oldpen);
             SelectObject(dc,oldbrush);
             ReleaseDC(hw,dc);
             break;
          case IDM_QUIT:
             ManageCloseMessage(hw);
             break;
          case IDM_ABOUT:
             ManageAboutBox(hw);
             break;
          //manage control
          case IDC_LISTBOX:
             if (nNotify == LBN_SELCHANGE) //something changed in the combo Box
             {
                //here the change comes from slider
                if (lpapp->fMoveSlider == TRUE) break;   
                //get Text from List Box Select Item
                iSelect=(long)SendMessage(lpapp->hw_ListBox, LB_GETCURSEL,0, 0);
                sss[0]=0;
                SendMessage(lpapp->hw_ListBox, LB_GETTEXT,(WPARAM)iSelect, (LPARAM)sss);
                ff=extractValueFromListString(sss);
                if (ff<-24.0f) ff=-24.0f;
                if (ff>24.0f) ff=24.0f;
                //let's update the Edit Box, this will update other controle
                sprintf(sss,"%0.2f",ff);
                SetWindowText(lpapp->hw_EditBox,sss);
             }
             break;
          case IDC_EDITBOX:
             if (nNotify == EN_CHANGE) //something changed in the Edit Box
             {   
                //here the value is already updated by slider
                if (lpapp->fMoveSlider == TRUE) break;   
                //here the value is already updated by combo
                if (lpapp->fUpdateFromComboBox == TRUE) break;
                //get new string in Edit Box
                GetWindowText(lpapp->hw_EditBox,sss,32);
                sss[32]=0;
                //convert to float and bind value
                ff=(float)atof(sss);
                if (ff<-24.0f) ff=-24.0f;
                if (ff>24.0f) ff=24.0f;
                //update slider value and display it
                lpapp->slider_value=ff;
                dc=GetDC(hw);
                DisplaySlider(lpapp,dc);
                DisplaySliderValueInLCD(lpapp, dc);
                ReleaseDC(hw,dc);
                //update combo Box
                lpapp->fUpdateFromEditBox=TRUE;
                if (lpapp->slider_value == -24.0f) SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,0,0L);
                else
                {
                   if (lpapp->slider_value == +24.0f) SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,2,0L);
                   else SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,1,0L);
                }
                lpapp->fUpdateFromEditBox=FALSE;
                
             }
             break;
          case IDC_COMBOBOX:
             if (nNotify == CBN_SELCHANGE) //something changed in the combo Box
             {
                //here the value is already updated by slider
                if (lpapp->fMoveSlider == TRUE) break;   
                //here the value is already updated by Edit Box
                if (lpapp->fUpdateFromEditBox == TRUE) break;
                iSelect=(long)SendMessage(lpapp->hw_ComboBox, CB_GETCURSEL,0, 0);
                //update slider value and siplay it
                if (iSelect == 0) lpapp->slider_value=-24.0f;
                if (iSelect == 1) lpapp->slider_value=0.0f;
                if (iSelect == 2) lpapp->slider_value=+24.0f;
                //update slider value and display it
                dc=GetDC(hw);
                DisplaySlider(lpapp,dc);
                DisplaySliderValueInLCD(lpapp, dc);
                ReleaseDC(hw,dc);
                //update Edit Box
                lpapp->fUpdateFromComboBox=TRUE;
                sprintf(sss,"%0.2f",lpapp->slider_value);
                SetWindowText(lpapp->hw_EditBox,sss);
                lpapp->fUpdateFromComboBox=FALSE;
             }
             break;
          
          //manage Contextual Popup
          default:
             IMAIN_ProcessPopupCommand(hw, nuCommand);
             break;
    
       }
    }
    
    
    /*******************************************************************************/
    /*                        Create Basic Window Controls                         */
    /*******************************************************************************/
    
    static long CreateOurControls(LPT_APP_CONTEXT lpapp, HWND hw)
    {
       char sss[256];
       //create a list box on the right.
       lpapp->hw_ListBox=CreateWindowEx(WS_EX_CLIENTEDGE,"listbox",NULL,
                       WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_VSCROLL 
                       | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
                       507,0,100,300,
                      hw,(HMENU)IDC_LISTBOX,G_hinstance,NULL);
       if (lpapp->hw_ListBox ==NULL) return -1;
       SendMessage(lpapp->hw_ListBox,WM_SETFONT,(WPARAM)lpapp->font_small,MAKELPARAM(1,0));
       //Create an Edit Box on the bottom :
       strcpy(sss,"0.0");
       lpapp->hw_EditBox=CreateWindowEx(WS_EX_CLIENTEDGE,"edit",sss,
                    WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP,
                    10,150,100,30,
                    hw,(HMENU)IDC_EDITBOX,G_hinstance,NULL);
       if (lpapp->hw_EditBox ==NULL) return -1;
       SendMessage(lpapp->hw_EditBox,WM_SETFONT,(WPARAM)lpapp->font_med,MAKELPARAM(1,0));
       SendMessage(lpapp->hw_EditBox,EM_SETMARGINS,EC_LEFTMARGIN | EC_RIGHTMARGIN,(LPARAM) MAKELONG(2,2));
       //Create a combo box
       lpapp->hw_ComboBox=CreateWindowEx(WS_EX_CLIENTEDGE,"combobox",NULL,
                      WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_DROPDOWNLIST,
                      120,150,150,300,
                      hw,(HMENU)IDC_COMBOBOX,G_hinstance,NULL);
       if (lpapp->hw_ComboBox ==NULL) return -1;
       SendMessage(lpapp->hw_ComboBox,WM_SETFONT,(WPARAM)lpapp->font_med,MAKELPARAM(1,0));
       strcpy(sss,"Min Value");
       SendMessage(lpapp->hw_ComboBox,CB_ADDSTRING,0,(LPARAM)sss);
       strcpy(sss,"Intermediate...");
       SendMessage(lpapp->hw_ComboBox,CB_ADDSTRING,0,(LPARAM)sss);
       strcpy(sss,"Max Value");
       SendMessage(lpapp->hw_ComboBox,CB_ADDSTRING,0,(LPARAM)sss);
       SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,1,0L);
       //Create Push Button
       lpapp->hw_PushButton=CreateWindow("button","About Box",WS_CHILD | WS_VISIBLE | WS_TABSTOP,
                    300,150,150,30,
                    hw,(HMENU)IDM_ABOUT,G_hinstance,NULL);
       if (lpapp->hw_PushButton ==NULL) return -1;
       SendMessage(lpapp->hw_PushButton,WM_SETFONT,(WPARAM)lpapp->font_med,MAKELPARAM(1,0));
       //Create Contextual Popup Menu
       lpapp->hPopupMenu=CreatePopupMenu();
       if (lpapp->hPopupMenu ==NULL) return -1;
       strcpy(sss,"info...");
       AppendMenu(lpapp->hPopupMenu,MF_STRING,IDM_CTXPOPUP_INFO,sss);
       strcpy(sss,"See VB's Web Pages...");
       AppendMenu(lpapp->hPopupMenu,MF_STRING,IDM_CTXPOPUP_WEB,sss);
       strcpy(sss,"E-mail me...");
       AppendMenu(lpapp->hPopupMenu,MF_STRING,IDM_CTXPOPUP_MAIL,sss);
    
    
       return 0;
    }
    
    static void DestroyOurControls(LPT_APP_CONTEXT lpapp)
    {
       DestroyWindow(lpapp->hw_ListBox);
       DestroyWindow(lpapp->hw_EditBox);
       DestroyWindow(lpapp->hw_ComboBox);
       DestroyWindow(lpapp->hw_PushButton);
       DestroyMenu(lpapp->hPopupMenu);
    
    }
    /*******************************************************************************/
    /*                                  CALL BACK                                  */
    /*******************************************************************************/
    
    LRESULT CALLBACK MainWindowManageEvent(HWND hw, //handle of the window.
                                     UINT msg,      //Message Ident.
                                     WPARAM p1,     //parameter 1.
                                     LPARAM p2)     //parameter 2
    {
       LPT_APP_CONTEXT lpapp;
       WPARAM vv;
       POINT po;
       HPEN oldpen;
       HBRUSH oldbrush;
       HFONT oldfont;
       float ff;
       RECT rect;
       long xx,yy,bmpdx,bmpdy;
       long dx,dy,rep;
       char sss[256];
       HDC dc;
       PAINTSTRUCT ps;
       lpapp=&G_MainAppCtx;
       switch (msg)
       {
    
    
          case WM_CREATE:
             //return -1 here cancel the window creation
             if (InitSoftware(hw) == FALSE) return -1;   
             rep=CreateOurControls(lpapp, hw);
             //if there is a problem :
             if (rep != 0) 
             {
                MessageBox(NULL,"Failed to create Controls...","Application error",
                                  MB_APPLMODAL | MB_OK | MB_ICONERROR);
                return -1;
             }
             break;
          case WM_COMMAND:
             ManageMenu(lpapp, hw,p1,p2);
             break;
          case WM_SIZE:
             //position control after window re-sizing
             dx=(long)LOWORD(p2);
             dy=(long)HIWORD(p2);
             TOOL_GetBitmapSize(lpapp->bmp_bkg,&bmpdx,&bmpdy);
             //position List
             xx=dx-bmpdx;
             if (xx<100) xx=100;
             yy=dy;
             if (yy<100) yy=100;
             SetWindowPos(lpapp->hw_ListBox,HWND_TOP,bmpdx,0, xx,yy, SWP_NOMOVE | SWP_SHOWWINDOW);
             //Position EditBox, Combo and Button on bottom
             yy=dy-40;
             if (yy<150) yy=150;
             SetWindowPos(lpapp->hw_EditBox,HWND_TOP,10,yy, 0,0, SWP_NOSIZE | SWP_SHOWWINDOW);
             SetWindowPos(lpapp->hw_ComboBox,HWND_TOP,120,yy, 0,0, SWP_NOSIZE | SWP_SHOWWINDOW);
             SetWindowPos(lpapp->hw_PushButton,HWND_TOP,300,yy, 0,0, SWP_NOSIZE | SWP_SHOWWINDOW);
    
             break;
          case WM_PAINT:
             dc=BeginPaint(hw,&ps);
             strcpy(sss,"This Text Is always displayed");
             TextOut(dc,10,70,sss,(int)strlen(sss));
    
             SetBkMode(dc,TRANSPARENT);
             strcpy(sss,"This Text lets you see the background...");
             TextOut(dc,10,90,sss,(int)strlen(sss));
    
             DisplayOurStuff(lpapp,dc);
             EndPaint(hw,&ps);
               break;
          
    
          case WM_LBUTTONDOWN:
             xx=(long)LOWORD(p2);
             yy=(long)HIWORD(p2);
             //test if it's in the slider.
             rect.left =13-1;
             rect.top =24-1;
             rect.right=rect.left+250+2;
             rect.bottom=rect.top+18+2;
             if ((xx>rect.left) && (xx<rect.right) && (yy>rect.top) && (yy<rect.bottom))
             {
                lpapp->LastCapture=SetCapture(hw);
                lpapp->fMoveSlider=TRUE;
                lpapp->lastmouse_x=xx;
                break;
             }
             //otherwise display the name of the pressed key.
             sss[0]=0;
             if ((p1 & MK_CONTROL) != 0) strcat(sss,"CTRL ");
             if ((p1 & MK_SHIFT) != 0) strcat(sss,"SHIFT ");
             
             rect.left=xx;
             rect.top=yy;
             rect.right=rect.left+100;
             rect.bottom=rect.top+20;
    
             dc=GetDC(hw);
             oldpen=(HPEN)SelectObject(dc,GetStockObject(WHITE_PEN));         
             oldbrush=(HBRUSH)SelectObject(dc,lpapp->gdiobjects_bleu.brush);         
             Rectangle(dc,rect.left,rect.top,rect.right,rect.bottom);
             oldfont=(HFONT)SelectObject(dc,lpapp->font_med);
             SetTextColor(dc,RGB(255,255,255));
             SetBkMode(dc,TRANSPARENT);
             DrawText(dc,sss,(int)strlen(sss),&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
             SelectObject(dc,oldbrush);
             SelectObject(dc,oldpen);
             SelectObject(dc,oldfont);
             ReleaseDC(hw,dc);
             
             break;
          case WM_LBUTTONUP:
             if (lpapp->fMoveSlider == TRUE)
             {
                ReleaseCapture();
                if (lpapp->LastCapture != NULL) SetCapture(lpapp->LastCapture);
                lpapp->fMoveSlider=FALSE;
             }
             break;
          case WM_MOUSEMOVE:
             xx=(long)(short int)LOWORD(p2);
             yy=(long)(short int)HIWORD(p2);
             
             //display mouse position in real time
             lpapp->mouse_x=xx;
             lpapp->mouse_y=yy;
             dc=GetDC(hw);
             DisplayMousePosition(lpapp, dc);
             ReleaseDC(hw,dc);
             //check if we are moving the slider.
             if (lpapp->fMoveSlider == TRUE)
             {
                ff=(float)(xx-lpapp->lastmouse_x)*0.1f;
                if (ff != 0.0f)
                {
                   lpapp->slider_value +=ff;
                   if (lpapp->slider_value < -24.0f) lpapp->slider_value=-24.0f;
                   if (lpapp->slider_value > 24.0f) lpapp->slider_value=24.0f;
                   dc=GetDC(hw);
                   DisplaySlider(lpapp, dc);
                   DisplaySliderValueInLCD(lpapp, dc);
                   ReleaseDC(hw,dc);
                   //add Value in List Box
                   lpapp->nbHistoryValue++;
                   sprintf(sss,"[%04i] Slider Value = %0.3f",lpapp->nbHistoryValue, lpapp->slider_value);
                   vv=(WPARAM)SendMessage(lpapp->hw_ListBox,LB_ADDSTRING,0,(LPARAM)sss);      
                   SendMessage(lpapp->hw_ListBox,LB_SETCURSEL,vv,0);      
                   //update Edit Box
                   sprintf(sss,"%0.1f",lpapp->slider_value);
                   SetWindowText(lpapp->hw_EditBox,sss);
                   //update combo Box
                   if (lpapp->slider_value == -24.0f) 
                      SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,0,0L);
                   else
                   {
                      if (lpapp->slider_value == +24.0f) 
                         SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,2,0L);
                      else SendMessage(lpapp->hw_ComboBox,CB_SETCURSEL ,1,0L);
                   }
                }
                lpapp->lastmouse_x=xx;
             }
             break;
    
    
          case WM_RBUTTONDOWN:
             po.x=(int)(short int)LOWORD(p2);
             po.y=(int)(short int)HIWORD(p2);
             ClientToScreen(hw,&po);
             TrackPopupMenu(lpapp->hPopupMenu,0,po.x,po.y,0,hw,NULL);
             break;
          
    
          case WM_CLOSE:
             ManageCloseMessage(hw);
             break;
             //here we display the background of our client area.
          case WM_ERASEBKGND:
             dc=(HDC)p1;
             //display background bitmap on the top-left
             TOOL_DrawBitmap(dc, 0, 0, lpapp->bmp_bkg);
             //draw gray background below the bitmap according the client area size
             TOOL_GetBitmapSize(lpapp->bmp_bkg,&bmpdx,&bmpdy);
             GetClientRect(hw,&rect);
             dx=rect.right-rect.left;
             dy=rect.bottom-rect.top;
             if (dx>bmpdx) dx=bmpdx;
             dy=dy-bmpdy;
             if (dy>0)
             {
                oldpen=(HPEN)SelectObject(dc,GetStockObject(NULL_PEN));
                oldbrush=(HBRUSH)SelectObject(dc,GetStockObject(GRAY_BRUSH));
                Rectangle(dc,0,bmpdy,dx+1,bmpdy+dy);
                SelectObject(dc,oldbrush);
                SelectObject(dc,oldpen);
             }
             return 1;
          case WM_DESTROY:
             EndSoftware(hw);
             DestroyOurControls(lpapp);
             PostQuitMessage(0);
             break;
          default:
             return (DefWindowProc(hw,msg,p1,p2));
    
       }
       return (0L);
    }
    
    
    /*******************************************************************************/
    /**                              MAIN PROCDURE                                **/
    /*******************************************************************************/
    
    int APIENTRY WinMain(HINSTANCE handle_app,   //Application hinstance.
                         HINSTANCE handle_prev,  //NULL.
                         LPTSTR param,           //Command Line Parameter.
                         int com_show)           //How to display window (optionnal).
    {
       long   wstyle;
       MSG      msg;    
       char   szWindowClassName[]="MainWindowClass";
       char *   title="Sorry";
    
       WNDCLASS   wc;
       //we first store the APP Hinstance
       G_hinstance=handle_app;
    
       //here you can make some early initialization and analyze command line if any.
       TOOL_MemZERO(&G_MainAppCtx, sizeof(T_APP_CONTEXT)); //initialize our structure with ZERO value
       TOOL_StoreOriginalAppDirectory();
    
       //we define a window class to create a window from this class 
       wc.style      =CS_HREDRAW | CS_VREDRAW;         //property.
       wc.lpfnWndProc=(WNDPROC)MainWindowManageEvent;  //Adresse of our Callback.
       wc.cbClsExtra =0;                               //to store byte inside a class object.
       wc.cbWndExtra =0;                               //to store byte inside a window object.
       wc.hInstance  =handle_app;                      //handle of the application hinstance.
       wc.hIcon      =LoadIcon(NULL, IDI_APPLICATION); //handle of icon displayed in the caption.
       wc.hCursor    =LoadCursor(NULL,IDC_ARROW);      //handle of cursor mouse .
       wc.hbrBackground=(HBRUSH)(COLOR_MENU+1);        //Background color.
       wc.lpszMenuName="MyMainAppMenu";                //pointer on menu defined in resource.
       wc.lpszClassName=szWindowClassName;             //pointer on class name.
    
       //register class.
       if (RegisterClass(&wc)==0)
       {
          MessageBox(NULL,"Failed to register main class...",title,MB_APPLMODAL | MB_OK | MB_ICONERROR);
          return 0;
       }
       //then we can create a windows from this class.
       
       //Classical Window without Sizing border.
       //wstyle=WS_DLGFRAME | WS_OVERLAPPED | WS_VISIBLE | WS_MINIMIZEBOX | WS_SYSMENU;
       
       //classical Main Window
       wstyle=WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
       G_hwnd_MainWindow=CreateWindow(szWindowClassName,// address of registered class name.
                       SZPUBLICNAME,                    // address of window name string
                       wstyle,                          // window style
                       CW_USEDEFAULT,                   // horizontal position of window
                       CW_USEDEFAULT,                   // vertical position of window
                       UI_WIN_DX,                       // window width
                       UI_WIN_DY,                       // window height
                       NULL,                            // parent handle is NULL.
                       NULL,                            // menu name defined in resource.
                       handle_app,                      // handle of application instance
                       NULL);                           // address of window-creation data
    
       if (G_hwnd_MainWindow==NULL)
       {
          MessageBox(NULL,"Failed to create window...",title,MB_APPLMODAL | MB_OK | MB_ICONERROR);
          return 0;
       }
       ShowWindow(G_hwnd_MainWindow,SW_SHOW);         //Display the window.
       UpdateWindow(G_hwnd_MainWindow);               //Send WM_PAINT.
       /*---------------------------------------------------------------------------*/
       /*                             Messages Loop.                                */
       /*---------------------------------------------------------------------------*/
       while (GetMessage(&msg,NULL,0,0)) //Get Message if any.
       {
          TranslateMessage(&msg);        //Translate the virtuel keys event.
          DispatchMessage(&msg);         //DispatchMessage to the related window.
       }
    
       //here you can make last uninitialization and release
       return (int)(msg.wParam);
    }
    
    
    

    Source : minprg.h

    #ifndef __MINPRG_H__
    #define __MINPRG_H__
    
    //version information (for program)
    #define SZPUBLICVERSION      "1.0.0.0"            //displayed version in about box
    #define SZPUBLICNAME      "Basic Windows Controls"//displayed title in main window 
    
    //Information for Main window 
    #define UI_WIN_DX   750
    #define UI_WIN_DY   400
    
    //version information (used in resource file)
    #define __FILEVERSION__         1,0,0,0
    #define __PRODUCTVERSION__      1,0,0,0
    #define __SZFILEVERSION__      "1, 0, 0, 0\0"
    #define __SZPRODUCTVERSION__   "1, 0, 0, 0\0"
     
       #define __COMMENTS__         "Example of source code"
       #define __COMPANYNAME__      "Audio Mechanic & Sound Breeder\0"
       #define __FILEDESCRIPTION__  "Minimal Windows Application\0"
       #define __INTERNALNAME__     "MinPrg"
       #define __LEGALCOPYRIGHT__   "Copyright V.Burel©2008\0"
       #define __ORIGINALFILENAME__ "MinPrg.EXE\0"
       #define __PRODUCTNAME__      "MinPrg\0"
    
    
    //definitions for MENU
    
    #define IDM_DRAWSOMETHING   50
    #define IDM_QUIT            100
    #define IDM_ABOUT           101
    
    //definitions for Control
    #define IDC_LISTBOX         500
    #define IDC_EDITBOX         501
    #define IDC_COMBOBOX        502
    
    //definitions for Popup Menu
    #define IDM_CTXPOPUP_INFO   888
    #define IDM_CTXPOPUP_WEB    890
    #define IDM_CTXPOPUP_MAIL   891
    
    //definitions for STRING-TABLE
    #define IDS_CONFIRMCLOSE    100
    
    #endif /*__MINPRG_H__*/
    
    

    Source : minprg.rc

    #include "minprg.h"
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    
    MyMainAppMenu MENU DISCARDABLE 
    BEGIN
        POPUP "&Command"
        BEGIN
            MENUITEM "&Draw basic stuff in LCD",   IDM_DRAWSOMETHING
            MENUITEM SEPARATOR
            MENUITEM "&About",                     IDM_ABOUT
            MENUITEM "&Quit",                      IDM_QUIT
        END
    END
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // STRING
    //
    
    STRINGTABLE
    BEGIN
       IDS_CONFIRMCLOSE      "Do you want to close this application ?"
    END
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Bitmap (can be whatever BMP file (2 bits to 24 bits color)
    //
    
    100 BITMAP "bkg.bmp"
    101 BITMAP "cursor.bmp"
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Version
    //
    
    1 VERSIONINFO
     FILEVERSION __FILEVERSION__
     PRODUCTVERSION __PRODUCTVERSION__
     FILEFLAGSMASK 0x3fL
    #ifdef _DEBUG
     FILEFLAGS 0x1L
    #else
     FILEFLAGS 0x0L
    #endif
     FILEOS 0x0L
     FILETYPE 0x1L
     FILESUBTYPE 0x0L
    BEGIN
        BLOCK "StringFileInfo"
        BEGIN
            BLOCK "000004b0"
            BEGIN
                VALUE "Comments", __COMMENTS__
                VALUE "CompanyName", __COMPANYNAME__
                VALUE "FileDescription", __FILEDESCRIPTION__
                VALUE "FileVersion", __SZFILEVERSION__
                VALUE "InternalName", __INTERNALNAME__
                VALUE "LegalCopyright", __LEGALCOPYRIGHT__
                VALUE "OriginalFilename", __ORIGINALFILENAME__
                VALUE "ProductName", __PRODUCTNAME__
                VALUE "ProductVersion", __SZPRODUCTVERSION__
          END
        END
        BLOCK "VarFileInfo"
        BEGIN
            VALUE "Translation", 0x0, 1200
        END
    END
    

    Source : tools.c

    #ifndef __cplusplus
       #ifndef STRICT
          #define STRICT
       #endif
    #endif
    
    #include <windows.h>
    #include <stdio.h>
    #include "tools.h"
    
    //Make this following define if your compiler does 
    //not support microsoft inline assembly language:
    
    //#define MY_COMPILER_DOESNOT_SUPPORT_MSASM
    
    /*****************************************************************/
    /* Manage Application Directory                                  */
    /*****************************************************************/
    
    static char G_CurrentDirectory[1024];
    
    void TOOL_StoreOriginalAppDirectory(void)
    {
       GetCurrentDirectory(1020,G_CurrentDirectory);
    }
    
    void TOOL_GetAppDirectory(char *  dir)
    {
       if (dir != NULL) strcpy(dir,G_CurrentDirectory);
    }
    
    void TOOL_GetPathOnly(char *  sss)
    {
       long ll;
       ll=(long)strlen(sss);
       while ((ll>0) && (sss[ll]!='\\')) ll--;
       if (sss[ll] == '\\') sss[ll]=0;
    }
    
    /*****************************************************************/
    /* Memory Block Functions                                        */
    /*****************************************************************/
    
    // Initialize a memory block with ZERO 
    
    void __cdecl TOOL_MemZERO(void * target, long nbByte)
    {
    #ifdef MY_COMPILER_DOESNOT_SUPPORT_MSASM
       memset(target,0,nbByte);
    #else
       __asm {
          push edi
          push esi
          mov eax,DWORD PTR nbByte;
          mov edi,DWORD PTR target;
          xor edx,edx
          cld
          mov ecx,eax
          shr ecx,3
          jz SHORT P_MZ_next1
       P_MZ_loop1:
          mov DWORD PTR [edi],edx
          mov DWORD PTR [edi+0x00000004],edx
          add edi,0x00000008
          dec ecx
          jnz SHORT P_MZ_loop1
       P_MZ_next1:
          and eax,0x00000007
          jz SHORT P_MZ_end1      
          mov ecx,eax
          xor eax,eax
          rep stosb
       P_MZ_end1:
          pop esi
          pop edi
       }
    #endif
    }
    
    
    
    /*****************************************************************/
    /* Bitmap Functions                                              */
    /*****************************************************************/
    
    long TOOL_GetBitmapSize(HBITMAP bmp,long * dx,long * dy)
    {
       BITMAP   bmpinfo;
       if (bmp == NULL) return -1;
       GetObject(bmp,sizeof(BITMAP),&bmpinfo);
       if (dx != NULL) *dx=bmpinfo.bmWidth;
       if (dy != NULL) *dy=bmpinfo.bmHeight;
       return 0;
    }
    
    void TOOL_DrawBitmap(HDC dc, int x0, int y0, HBITMAP hbmp)
    {
       HBITMAP      oldBitmap;
       BITMAP bm;
       HDC dcmem;
       dcmem = CreateCompatibleDC(dc);
       oldBitmap=(HBITMAP)SelectObject(dcmem,hbmp);
       GetObject(hbmp,sizeof(BITMAP),&bm);
       BitBlt(dc,x0,y0,bm.bmWidth,bm.bmHeight,dcmem,0,0,SRCCOPY);
       SelectObject(dcmem,oldBitmap);
       DeleteDC(dcmem);
    }
    
    void TOOL_DrawPartOfBitmap(HDC dc,HBITMAP hbmp,int x0, int y0,int bmpx0,int bmpy0, int bmpcx,int bmpcy)
    {
       HBITMAP      oldBitmap;
       HDC       bitmapDC;
       bitmapDC=CreateCompatibleDC(dc);
       oldBitmap=(HBITMAP)SelectObject(bitmapDC,hbmp);
       BitBlt(dc,x0,y0,bmpcx,bmpcy,bitmapDC,bmpx0,bmpy0,SRCCOPY);
       SelectObject(bitmapDC,oldBitmap);
       DeleteDC(bitmapDC);
    }
    
    
    
    /*****************************************************************/
    /* Get Window Metrics Info                                       */
    /*****************************************************************/
    
    #ifndef SM_CXPADDEDBORDER
       #define SM_CXPADDEDBORDER 92
    #endif
    
    typedef struct tagVBNONCLIENTMETRICS 
    {  
       UINT cbSize;
       int iBorderWidth;
       int iScrollWidth;
       int iScrollHeight;
       int iCaptionWidth;
       int iCaptionHeight;
       LOGFONT lfCaptionFont;
       int iSmCaptionWidth;
       int iSmCaptionHeight;
       LOGFONT lfSmCaptionFont;
       int iMenuWidth;
       int iMenuHeight;
       LOGFONT lfMenuFont;
       LOGFONT lfStatusFont;
       LOGFONT lfMessageFont;
       int iPaddedBorderWidth;
    } VBNONCLIENTMETRICS,  *LPVBNONCLIENTMETRICS;
    
    
    void TOOL_GetMetricInfoWindow(long * win_bordersize, long * win_captiondy,long * win_menudy)
    {
       long xyadjust=0;
       BOOL ok;
       VBNONCLIENTMETRICS ncm;
       ncm.cbSize=sizeof(VBNONCLIENTMETRICS);
       //For Vista
       ok=SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(VBNONCLIENTMETRICS),&ncm,0L); 
       if (ok != 0)
       {
          xyadjust=ncm.iPaddedBorderWidth+2;
          if (win_menudy != NULL)         *win_menudy      =ncm.iMenuHeight;
          if (win_bordersize != NULL)     *win_bordersize  =xyadjust+ncm.iBorderWidth;
          if (win_captiondy != NULL)      *win_captiondy   =ncm.iCaptionHeight;
          return;
       }
       //For Windows 2000/XP
       xyadjust=GetSystemMetrics(SM_CXPADDEDBORDER);
       if (win_menudy != NULL)      *win_menudy=GetSystemMetrics(SM_CYMENU);
       if (win_bordersize != NULL)  *win_bordersize= xyadjust+GetSystemMetrics(SM_CXDLGFRAME);
       if (win_captiondy != NULL)   *win_captiondy=GetSystemMetrics(SM_CYCAPTION);
    }
    
    

    Source : tools.h

    #ifndef __TOOLS_H__
    #define __TOOLS_H__
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    //Application Directory
    void TOOL_StoreOriginalAppDirectory(void);
    void TOOL_GetAppDirectory(char *  dir);
    
    void TOOL_GetPathOnly(char *  sss);
    
    //Memory Block Functions
    
    void __cdecl TOOL_MemZERO(void * target, long nbByte);
    
    
    
    //Bitmap Functions
    
    long TOOL_GetBitmapSize(HBITMAP bmp,long * dx,long * dy);
    void TOOL_DrawBitmap(HDC dc, int x0, int y0, HBITMAP hbmp);
    void TOOL_DrawPartOfBitmap(HDC dc,HBITMAP hbmp,int x0, int y0,int bmpx0,int bmpy0, int bmpcx,int bmpcy);
    
    //Window info functions
    void TOOL_GetMetricInfoWindow(long * win_bordersize, long * win_captiondy,long * win_menudy);
    
    
    //End Of Header.
    
    #ifdef __cplusplus 
    }
    #endif
    
    
    #endif /*__TOOLS_H__*/
    
    
    








    Contact Us!

    Privacy Policy

    Social Network:
    VB-Audio On Facebook
    VB-Audio On Instagram
    VB-Audio On Twitter
    VB-Audio On Youtube

    VB-Audio Forums
    VB-Audio Discord Server
    Voicemeeter on Reddit



    Audio Apps:
    VB-Cable
    Hi-Fi Cable & ASIO Bridge
    Voicemeeter
    Voicemeeter Banana
    Voicemeeter Potato
    VBAN Protocol & Tools
    Spectralissime
    VB-Audio Matrix

    About Donationware model...
    About Licensing / Distribution...



    Other web sites:
    VOICEMEETER.COM
    SPECTRALISSIME.COM
    DOWNLOAD.VB-AUDIO.COM

    Freeware:
    LF-Generator
    TimeCalc
    FFX-4

    About us:
    Our history / Blog



    Audio Pro:
    MT32-Splite
    MT64-Standard
    MT128-Pro
    MT128-Integration
    WWW.MT128.COM

    Buy Online:
    VB-Audio WebShop
    General Terms
    Last Newsletter



    Copyright V.Burel ©1998-2023. All rights reserved. All technical specifications and any informations of the products specified on this web site may be subject to change without notice.