Home

History

Blog

'C' Lesson

<<

>>


Programmer en 'C' sous Windows
MinPrg02: Les bases de l'affichage et de la gestion souris.

A partir du moment où nous avons une fenêtre, c'est à dire un objet qui reçoit des événements utilisateur et qui gère une surface d'affichage, nous pouvons déjà faire tout un tas de choses amusantes. Le programme suivant, se propose de vous familiariser avec la gestion de la souris et les fonctions de base de l'affichage.

MinPrg02 : Mouse and Drawing, the basic


Les Fichiers Organisation du Source Code
MiniPrg_02.exe (256KB 14-MAR-2008)
MiniPrg_02.zip (79KB 14-MAR-2008)
minprg.h
minprg.c
minprg.rc
tools.h
tools.c
MinPrg02 : Source Organization

Que fait ce programme ? :
Ce programme affiche une fenêtre aux dimensions de la Bitmap de fond et fait plusieurs choses en fonction d'événements souris :
  • Le menu permet d'afficher quelques exemples d'utilisation de fonctions basiques de dessin dans la partie qui ressemble à un LCD.
  • Le fait de bouger la souris sur la fenêtre provoque l'affichage des coordonnées dans le LCD (coordonnées relatives au coin haut gauche de la zone client de notre fenêtre).
  • On peut attraper le curseur du Slider par un clic gauche et ensuite le faire bouger. Cela modifie sa valeur de manière logique (par pas de 0.1) et l'affiche dans le LCD (en rouge).
  • Si on clic en dehors du Slider, cela affiche une boite bleu qui dit si la touche CTRL ou SHIFT est pressée en même temps que le clic souris.

  • Les grands principes évoqués :
    Pour dessiner sous Windows, il faut avoir sous la main des objets GDI : des Bitmap, des Icon, mais aussi, des Pen (pour faire des lignes), des Brush (pour remplir des surfaces), des Color (pour définir la couleur de nos objets) et des Font pour écrire nos textes. Le système peut vous fournir des objets d'affichage (voir fonction GetStockObject par exemple) mais notre programme utilisera que des objets fabriqués main. Dès le lancement (voir notre fonction InitSoftware), nous chargeons nos 2 Bitmaps (qui sont dans les ressources) et fabriquons 3 fontes et 4 trio d'objets Pen/Brush/Color.

    Le principe de l'affichage sous Windows est relativement simple : on obtient une DC (Device Context) sur une zone d'affichage (généralement la zone client d'une fenêtre, mais ça peut être l'écran entier ou même une imprimante) et on configure cette DC en fonction de ce qu'on veux faire. Par exemple si l'on veut dessiner un Rectangle, on va d'abord sélectionner un Pen pour la bordure et une Brush pour la surface, c'est le rôle de la fonction SelectObject. Si vous ne sélectionnez pas d'objets, les fonctions de dessin utiliseront les objets couramment ou dernièrement sélectionnés dans cette DC. Un principe fondamentale cependant, consiste à toujours restaurer les objets d'une DC pour chaque type d'objet GDI : Bitmap, Pen, Brush, Font. Il faut sauvegarder ce que renvoie la fonction SelectObject (elle renvoie l'ancien objet sélectionné) pour pouvoir le restaurer en fin d'affichage (avant de rendre la DC au système par un ReleaseDC ou un EndPaint). Et surtout ne pas détruire un objet d'affichage qui pourrait être sélectionné ou pire en usage dans une DC !

    Pour la souris, nous allons traiter 3 nouveaux messages : WM_LBUTTONDOWN, WM_MOUSEMOVE et WM_LBUTTONUP et avec ceux ci, gérer la logique de déplacement du curseur de notre "Slider". Quand l'utilisateur clic sur le Slider (dont on connaît les coordonnées) on va considérer que l'utilisateur veux bouger le curseur en bougeant sa souris horizontalement. Pour se faire nous avons définit 3 variables : fMoveSlider pour indiquer que nous sommes dans le mode qui consiste à prendre en compte les mouvements souris pour bouger notre curseur. lastmouse_x qui nous permettra d'évaluer la taille des déplacement entre deux messages WM_MOUSEMOUVE. Et LastCapture qui stock ce que renvoie la fonction système SetCapture(). Cette dernière fonction est primordiale car elle permet de capturer les événements souris, garantissant que notre fenêtre recevra les WM_MOUSEMOUVE et WM_LBUTTONUP même si la souris sort de la fenêtre. Ce qui n'est pas le cas autrement ! Vous avez du le remarquer, les coordonnées souris sont mises à jour uniquement quand vous bougez la souris dans la zone cliente de notre fenêtre, en dehors nous ne recevons plus d'événement WM_MOUSEMOUVE. Dès que vous utilisez le Slider, un SetCapture() est fait, et vous voyez les coordonnées se mettre à jour, même si la souris est en dehors de la fenêtre.

    Quelques points du source :
    Dans notre Callback nous répondons à un nouveau Message : WM_ERASEBKGND qui est appelé avant le WM_PAINT pour afficher le fond. Dans l'exemple précédent, nous n'y répondions pas, c'est la DefWindowProc qui utilisait la Brush (hbrBackground) de la classe de la fenêtre pour dessiner le fond de la zone client. Le fait est que ce message est pratique pour afficher les parties statiques d'une interface graphique, notamment quand cette interface est basée sur une image. Ici nous répondons au message WM_ERASEBKGND en affichant notre image de fond à l'aide de notre nouvelle fonction : TOOL_DrawBitmap.

    TOOL.C et TOOL.H : forment ce que l'on pourrait appeler une "librairie" sous la forme de codes sources, qui vont venir s'ajouter à notre projet (il faut les inclure dans la compilation). Dans cette librairie, nous mettrons les fonctions générales qui pourront nous servir dans tout autres programmes sous Windows. Donc des fonctions dépendantes de Windows (O/S dépendant) mais indépendante de l'application qui les utilise. Pour l'instant, nous y avons placé les fonctions de gestion de Bitmap et une fonction TOOL_GetMetricInfoWindow qui tente de trouver les informations sur la taille des bordures, barre de titre et menu d'une fenêtre classique.

    Programmer, c'est d'abord une question d'organisation. Organiser le source dans les fichiers, organiser les données, les objets, les fonctions, les noms, les préfixes... Petit à petit, nous allons mettre en place les prémices d'une telle organisation. Vous remarquerez le regroupement de toute nos données d'application dans la structure G_MainAppCtx de type T_APP_CONTEXT . En 'C' c'est une première étape pour aller vers un programmation "Orienté Objet" (POO)


    Questions / Réponses:
    Pourquoi, quand je bouge très vite le curseur du Slider, y'a parfois comme un scintillement.
    C'est du "Flickering" c'est du au fait que nous affichons notre Slider avec des "overlap" (des chevauchements d'images). En effet dans la méthode d'affichage utilisée, certains points (pixels de l'écran) subissent deux affichages différents. La zone sous le curseur subit d'abord l'affichage du bitmap de fond, avant de voir celui du Bitmap du curseur. Comme le suggère le schéma ci-dessous, une méthode convenable consisterait à faire l'affichage en 3 étapes pour éviter l'overlap, d'abord la partie de tirette à gauche du curseur, ensuite le curseur, enfin la partie de tirette à droite du curseur.
    MinPrg02 : Drawing Slider Method

    Pourquoi quand j'élargie la taille de la fenêtre il se dessine n'importe quoi ?
    Parce que dans cet exemple, nous répondons au message WM_ERASEBKGND et nous ne gérons que la zone définie par notre Bitmap de fond (507x129). Nous ne tenons pas compte de la taille réelle de la fenêtre, et nous ne dessinons rien d'autre que notre Bitmap. Donc quand on élargie la fenêtre, la zone client s'élargie, mais aucun processus ne dessine quoi que ce soit dans les zones autour de notre bitmap, c'est pourquoi elles comportent n'importe quoi. Une solution consisterait à interdire le re-dimensionnement de la fenêtre en changeant les styles de création de notre fenêtre principale, voir ligne commentée : wstyle= WS_DLGFRAME | WS_OVERLAPPED | WS_VISIBLE | WS_MINIMIZEBOX | WS_SYSMENU .


    Source : minprg.c

    /*--------------------------------------------------------------------------------*/
    /* 'C' Programming Under WIN32                                     V.Burel (c)2007*/
    /*                                                                                */
    /*  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 Mouse functions and basic drawing API                           */
    /*--------------------------------------------------------------------------------*/
    /*  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;
    
       //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   = 16;
       lf.lfWeight   = 800;
       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;
       dy=18;
       rect.left =13;
       rect.top =24;
       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);
       //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;
       TOOL_DrawBitmap(dc,rect.left+xx,rect.top,lpapp->bmp_cursor);
    }
    
    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                                 **/
    /*******************************************************************************/
    
    void ManageMenu(HWND hw, WPARAM p,LPARAM w)
    {
       HPEN oldpen;
       HBRUSH oldbrush;
       long vi,x0,y0;
       HDC dc;
       switch(LOWORD(p))
       {
          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;
    
       }
    }
    
    
    
    /*******************************************************************************/
    /*                                  CALL BACK                                  */
    /*******************************************************************************/
    
    LRESULT CALLBACK MainWindowManageEvent(HWND hw,    //handle of the window.
                                           UINT msg,   //Message Ident.
                                           WPARAM p1,  //parameter 1.
                                           LPARAM p2)  //parameter 2
    {
       HPEN oldpen;
       HBRUSH oldbrush;
       HFONT oldfont;
       float ff;
       RECT rect;
       long win_bordersize,win_captiondy,win_menudy;
       long bmpdx,bmpdy,xx,yy;
       char sss[256];
       HDC dc;
       PAINTSTRUCT ps;
       switch (msg)
       {
    
    
          case WM_CREATE:
             if (InitSoftware(hw) == FALSE) return -1;
             //adjust window size according background bitmap.
             TOOL_GetMetricInfoWindow(&win_bordersize, &win_captiondy,&win_menudy);
             TOOL_GetBitmapSize(G_MainAppCtx.bmp_bkg,&bmpdx,&bmpdy);
             SetWindowPos(hw,HWND_TOP, 0,0,bmpdx+(win_bordersize*2),
    		              bmpdy+win_menudy+win_captiondy+(win_bordersize*2),
    					  SWP_NOMOVE | SWP_SHOWWINDOW);
             break;
          case WM_COMMAND:
             ManageMenu(hw,p1,p2);
             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(&G_MainAppCtx,dc);
             EndPaint(hw,&ps);
               break;
          
    
          case WM_LBUTTONDOWN:
             xx=(long)LOWORD(p2);
             yy=(long)HIWORD(p2);
             //test if it is 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))
             {
                G_MainAppCtx.LastCapture=SetCapture(hw);
                G_MainAppCtx.fMoveSlider=TRUE;
                G_MainAppCtx.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,G_MainAppCtx.gdiobjects_bleu.brush);         
             Rectangle(dc,rect.left,rect.top,rect.right,rect.bottom);
             oldfont=(HFONT)SelectObject(dc,G_MainAppCtx.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 (G_MainAppCtx.fMoveSlider == TRUE)
             {
                ReleaseCapture();
                if (G_MainAppCtx.LastCapture != NULL) SetCapture(G_MainAppCtx.LastCapture);
                G_MainAppCtx.fMoveSlider=FALSE;
             }
             break;
          case WM_MOUSEMOVE:
             xx=(long)(short int)LOWORD(p2);
             yy=(long)(short int)HIWORD(p2);
             
             //display mouse position in real time
             G_MainAppCtx.mouse_x=xx;
             G_MainAppCtx.mouse_y=yy;
             dc=GetDC(hw);
             DisplayMousePosition(&G_MainAppCtx, dc);
             ReleaseDC(hw,dc);
             //check if we are moving the slider.
             if (G_MainAppCtx.fMoveSlider == TRUE)
             {
                ff=(float)(xx-G_MainAppCtx.lastmouse_x)*0.1f;
                if (ff != 0.0f)
                {
                   G_MainAppCtx.slider_value +=ff;
                   if (G_MainAppCtx.slider_value < -24.0f) G_MainAppCtx.slider_value=-24.0f;
                   if (G_MainAppCtx.slider_value > 24.0f) G_MainAppCtx.slider_value=24.0f;
                   dc=GetDC(hw);
                   DisplaySlider(&G_MainAppCtx, dc);
                   DisplaySliderValueInLCD(&G_MainAppCtx, dc);
                   ReleaseDC(hw,dc);
                }
                G_MainAppCtx.lastmouse_x=xx;
             }
             break;
    
          case WM_CLOSE:
             ManageCloseMessage(hw);
             break;
             //here we display the background of our client area.
          case WM_ERASEBKGND:
             dc=(HDC)p1;
             TOOL_DrawBitmap(dc, 0, 0, G_MainAppCtx.bmp_bkg);
             return 1;
          case WM_DESTROY:
             EndSoftware(hw);
             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.
    
       //Zero initialize our main structure.
       memset(&G_MainAppCtx, 0, sizeof(T_APP_CONTEXT));
    
       //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 some byte inside a class object.
       wc.cbWndExtra =0;                               //to store some 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_ICONEXCLAMATION);
          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;
       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 for a main window.
                       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_ICONEXCLAMATION);
          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      "Mouse and Drawing"   //displayed title in main window 
    
    //Information for Main window 
    #define UI_WIN_DX   600
    #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©2007\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 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

    /*****************************************************************/
    /* TOOLS                                                 V.Burel */
    /*****************************************************************/
    /* General Functions to be used in MinPrg Samples                */
    /*****************************************************************/
    
    #ifndef __cplusplus
       #ifndef STRICT
          #define STRICT
       #endif
    #endif
    
    #include <windows.h>
    #include "tools.h"
    
    
    /*****************************************************************/
    /* 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
    
    //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.