Accueil > > > BASE POUR L'UTILISATION DU GDI (API WINDOWS)
BASE POUR L'UTILISATION DU GDI (API WINDOWS)
Information sur la source
Description
J'ai eu assez de mal à savoir commment utiliser le GDI (la solution n'est pas donnée toute faite dans msdn) et donc je voulais faire partager ma très modeste experience. Comme ça quelqu'un au bord de la crise de nerf pourra toujours copier-coller ce code sans se farcir toutes les docs pour déterminer comment faire marcher ce sacré bazard (API + GDI). Le GDI, de mon point de vue, est assez compliqué, mais permet de faire tout ce qu'on veux faire pour des application simples, et ne necessite pas d'ajouter des bibliothèques graphiques comme la SDL, OpenGL (je veux parler de GLUT et WGL), GTK, Qt... qui encapsulent carrement l'API Windows. Ainsi le GDI s'integre parfaitement dans une programme basé sur l'API Windows (normal puisqu'il fait partie de l'API Windows), et ne la limite pas dans l'utilisation des controls (menus, boutons, dialog boxes...). Cette source est juste un départ qui permet d'utiliser un pseudo "double buffering", une technique qui permet de ne pas afficher l'écran pendant la création du dessin. Même dans des application simple, on est rapidement obliger de faire comme ça, sinon c'est vraiment trop moche. Je dis "pseudo" car même si au final ça donne le même effet, on ne procède pas pareil que si on veut faire du vrai "double buffering" : normalement il faut avoir deux buffers video, un qui est affiché ("front buffer") et un dans lequel on compose l'image ("back buffer"), et les permuter quand on veux redessiner l'écran (le "front buffer" devient "back buffer" et vis-versa). Il suffit de permuter deux adresse mémoires, ce qui est extremement rapide. Avec le GDI, on a pas acces à la mémoire video (ou alors je veux absolument savoir comment), donc il faut ruser. On crée un "memory device context", c'est à dire un espace mémoire qui fait office de "back buffer", et quand on veut réafficher il faut le copier dans la mémoire vidéo affichable. Mais au final, me direz-vous, c'est la même chose : une copie. Mais non, car là il faut copier octet par octet toute la mémoire, et pas seulement changer deux pointeurs. On le fait avce BitBlt(), une fonction du GDI. Avec cette source, on a également la possiblité d'acceder directement à la mémoire du bitmap et donc de créer ses propres fonctions graphiques sans passer par le très très long SetPixel() ou même SetPixelV(). Pour cela, on utilise CreateDIBSection() au lieu de CreateCompatibleBitmap() lors de la création du bitmap. Encore faut-il que le device (écran) sur lequel on affiche supporte le 24bpp, mais normalement il y a pas de problème... En résumé, dans ce code de base il y a les deux techniques élementaires qui permettent d'utiliser facilement le GDI. Evidement, on a pas toutes les performances qu'on peut espérer avec des librairies graphiques comme OpenGL ou DirectX, mais pour autre chose qu'une application graphique, c'est pour moi la meilleur solution.
Source
- #include <windows.h>
- #include <time.h>
- #include <stdlib.h>
-
-
- #define LARGEUR 600
- #define HAUTEUR 400
-
- HBITMAP hBmp;
- BITMAP Bmp;
- HDC hMDC; // Memory Device Context
-
- HINSTANCE hInstance;
- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
- // Note : ne pas oublier de supprimer l'objet avec DeleteObject() quand on n'en a plus besoin.
- long BitmapCreation (unsigned long taille_x, unsigned long taille_y, HBITMAP *hBitmap, BITMAP *Bitmap);
-
-
- int WINAPI WinMain(HINSTANCE hThisHinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- HWND hwnd;
- MSG msg;
- WNDCLASS wc;
- RECT Client;
-
- UNREFERENCED_PARAMETER (hPrevInstance);
- UNREFERENCED_PARAMETER (lpCmdLine);
-
- hInstance = hThisHinstance;
-
- wc.style = 0;
- wc.lpfnWndProc = WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "Classe principale";
-
- if(!RegisterClass(&wc)) return FALSE;
-
- Client.left = 0;
- Client.top = 0;
- Client.right = LARGEUR;
- Client.bottom = HAUTEUR;
- AdjustWindowRectEx (&Client, WS_OVERLAPPEDWINDOW & (~(WS_THICKFRAME | WS_MAXIMIZEBOX)), FALSE, 0);
-
- if ((hwnd = CreateWindowEx (
- 0,
- "Classe principale",
- "Test de l'utilisation de memory DC pour le \"double buffering\".",
- WS_OVERLAPPEDWINDOW & (~(WS_THICKFRAME | WS_MAXIMIZEBOX)),
- CW_USEDEFAULT, CW_USEDEFAULT,
- Client.right - Client.left, Client.bottom - Client.top,
- NULL,
- NULL,
- hInstance,
- NULL)
- ) == NULL
- ){
- return FALSE;
- }
-
- ShowWindow(hwnd, nCmdShow);
- UpdateWindow(hwnd);
-
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return msg.wParam;
- }
-
- LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- HDC hDC; // Display Device Context
- PAINTSTRUCT ps;
- HBRUSH hBrush, hOldBrush;
-
- switch (uMsg)
- {
- case WM_CREATE:
- // Determine le handle du DC
- if ((hDC = GetDC (hwnd)) == NULL) {
- return -1;}
-
- // Crée un memory DC
- if ((hMDC = CreateCompatibleDC (hDC)) == NULL) {
- return -1;}
-
- // Crée un bitmap
- if (BitmapCreation (LARGEUR, HAUTEUR, &hBmp, &Bmp) == EXIT_FAILURE) {
- return -1;}
-
- // Selectionne ce bitmap dans hMDC
- if (SelectObject (hMDC, hBmp) == NULL) {
- return -1;}
-
- ReleaseDC (hwnd, hDC);
-
- // Initialise l'affichage
- Ellipse (hMDC, 0, 0, LARGEUR, HAUTEUR);
-
- // Initialise le générateur de nombres aléatoires
- srand ((unsigned int)time (NULL));
-
- return 0;
-
- case WM_DESTROY:
- DeleteDC (hMDC);
- DeleteObject (hBmp);
- PostQuitMessage(0);
- return 0;
-
- case WM_KEYDOWN:
- // Nouvel affichage dans hMDC
- hBrush = CreateSolidBrush (RGB (rand()%256, rand()%256, rand ()%256));
- hOldBrush = SelectObject (hMDC, hBrush);
- Ellipse (hMDC, 0, 0, LARGEUR, HAUTEUR);
- SelectObject (hMDC, hOldBrush);
- DeleteObject (hBrush);
-
- // Raffraichit l'écran
- RedrawWindow (hwnd, NULL, NULL, RDW_INVALIDATE);
- return 0;
-
- case WM_PAINT:
- // Copie hMDC dans hDC
- hDC = BeginPaint (hwnd, &ps);
- BitBlt (hDC, 0, 0, LARGEUR, HAUTEUR, hMDC, 0, 0, SRCCOPY);
- EndPaint (hwnd, &ps);
- return 0;
-
- default:
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- }
-
-
- long BitmapCreation (unsigned long taille_x, unsigned long taille_y, HBITMAP *hBitmap, BITMAP *Bitmap)
- {
- BITMAPINFO BitmapInfo;
- void *tmp;
-
- // Crée le bitmap
- BitmapInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- BitmapInfo.bmiHeader.biWidth = taille_x;
- BitmapInfo.bmiHeader.biHeight = taille_y;
- BitmapInfo.bmiHeader.biPlanes = 1;
- BitmapInfo.bmiHeader.biBitCount = 32;
- BitmapInfo.bmiHeader.biCompression = BI_RGB;
- BitmapInfo.bmiHeader.biSizeImage = taille_x * taille_y * 4;
- BitmapInfo.bmiHeader.biXPelsPerMeter = 0;
- BitmapInfo.bmiHeader.biYPelsPerMeter = 0;
- BitmapInfo.bmiHeader.biClrUsed = 0;
- BitmapInfo.bmiHeader.biClrImportant = 0;
- if ((*hBitmap = CreateDIBSection (NULL, &BitmapInfo, DIB_RGB_COLORS, &tmp, NULL, 0)) == NULL) {
- return EXIT_FAILURE;
- }
-
- // Obtient la structure BITMAP
- if (GetObject (*hBitmap, sizeof (BITMAP), Bitmap) != sizeof (BITMAP)){
- DeleteObject (*hBitmap);
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
- }
#include <windows.h>
#include <time.h>
#include <stdlib.h>
#define LARGEUR 600
#define HAUTEUR 400
HBITMAP hBmp;
BITMAP Bmp;
HDC hMDC; // Memory Device Context
HINSTANCE hInstance;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// Note : ne pas oublier de supprimer l'objet avec DeleteObject() quand on n'en a plus besoin.
long BitmapCreation (unsigned long taille_x, unsigned long taille_y, HBITMAP *hBitmap, BITMAP *Bitmap);
int WINAPI WinMain(HINSTANCE hThisHinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;
RECT Client;
UNREFERENCED_PARAMETER (hPrevInstance);
UNREFERENCED_PARAMETER (lpCmdLine);
hInstance = hThisHinstance;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Classe principale";
if(!RegisterClass(&wc)) return FALSE;
Client.left = 0;
Client.top = 0;
Client.right = LARGEUR;
Client.bottom = HAUTEUR;
AdjustWindowRectEx (&Client, WS_OVERLAPPEDWINDOW & (~(WS_THICKFRAME | WS_MAXIMIZEBOX)), FALSE, 0);
if ((hwnd = CreateWindowEx (
0,
"Classe principale",
"Test de l'utilisation de memory DC pour le \"double buffering\".",
WS_OVERLAPPEDWINDOW & (~(WS_THICKFRAME | WS_MAXIMIZEBOX)),
CW_USEDEFAULT, CW_USEDEFAULT,
Client.right - Client.left, Client.bottom - Client.top,
NULL,
NULL,
hInstance,
NULL)
) == NULL
){
return FALSE;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; // Display Device Context
PAINTSTRUCT ps;
HBRUSH hBrush, hOldBrush;
switch (uMsg)
{
case WM_CREATE:
// Determine le handle du DC
if ((hDC = GetDC (hwnd)) == NULL) {
return -1;}
// Crée un memory DC
if ((hMDC = CreateCompatibleDC (hDC)) == NULL) {
return -1;}
// Crée un bitmap
if (BitmapCreation (LARGEUR, HAUTEUR, &hBmp, &Bmp) == EXIT_FAILURE) {
return -1;}
// Selectionne ce bitmap dans hMDC
if (SelectObject (hMDC, hBmp) == NULL) {
return -1;}
ReleaseDC (hwnd, hDC);
// Initialise l'affichage
Ellipse (hMDC, 0, 0, LARGEUR, HAUTEUR);
// Initialise le générateur de nombres aléatoires
srand ((unsigned int)time (NULL));
return 0;
case WM_DESTROY:
DeleteDC (hMDC);
DeleteObject (hBmp);
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
// Nouvel affichage dans hMDC
hBrush = CreateSolidBrush (RGB (rand()%256, rand()%256, rand ()%256));
hOldBrush = SelectObject (hMDC, hBrush);
Ellipse (hMDC, 0, 0, LARGEUR, HAUTEUR);
SelectObject (hMDC, hOldBrush);
DeleteObject (hBrush);
// Raffraichit l'écran
RedrawWindow (hwnd, NULL, NULL, RDW_INVALIDATE);
return 0;
case WM_PAINT:
// Copie hMDC dans hDC
hDC = BeginPaint (hwnd, &ps);
BitBlt (hDC, 0, 0, LARGEUR, HAUTEUR, hMDC, 0, 0, SRCCOPY);
EndPaint (hwnd, &ps);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
long BitmapCreation (unsigned long taille_x, unsigned long taille_y, HBITMAP *hBitmap, BITMAP *Bitmap)
{
BITMAPINFO BitmapInfo;
void *tmp;
// Crée le bitmap
BitmapInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth = taille_x;
BitmapInfo.bmiHeader.biHeight = taille_y;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
BitmapInfo.bmiHeader.biSizeImage = taille_x * taille_y * 4;
BitmapInfo.bmiHeader.biXPelsPerMeter = 0;
BitmapInfo.bmiHeader.biYPelsPerMeter = 0;
BitmapInfo.bmiHeader.biClrUsed = 0;
BitmapInfo.bmiHeader.biClrImportant = 0;
if ((*hBitmap = CreateDIBSection (NULL, &BitmapInfo, DIB_RGB_COLORS, &tmp, NULL, 0)) == NULL) {
return EXIT_FAILURE;
}
// Obtient la structure BITMAP
if (GetObject (*hBitmap, sizeof (BITMAP), Bitmap) != sizeof (BITMAP)){
DeleteObject (*hBitmap);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Conclusion
Vous aurez sans doute remarqué, si vous avez testé cette source, qu'on peut constater un effet assez désagréable : de temps en temps on peut apercevoir un trait horizontal lors du réaffichage de l'écran. Selon moi c'est un problème de syncronisation verticale, comme dans les jeux vidéos : BitBlt() n'a pas fini de copier hMDC dans hDC quand l'écran affiche physiquement l'image. (J'ai un écran LCD réglé à 60Hz.) Dites moi si on peut régler ça.
Historique
- 30 avril 2008 00:54:08 :
- Correction de choses peu rigoureuses.
- 30 avril 2008 18:22:22 :
- Modification du code pour pouvoir accéder à la mémoire du bitmap.
- 30 avril 2008 18:26:18 :
- Modification du code pour pouvoir accéder à la mémoire du bitmap.
- 19 février 2009 22:04:49 :
- Ajout de l'executable à la demande du public.
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Tracer graphique en fonction d'un tableau [ par Bobbix ]
Bonjour,Dans le cadre d'un projet, j'ai besoin de votre aide sur le graphisme en WIN32. Nous avons réalisé une carte électronique d'un oscilloscope qu
include GDI [ par Malkuth ]
Bonjour,Voilà je voudrais comprendre je créer un projet (Application console WIN32) sous visual studio 2005 je rajoute #include <gdiplus.h>je co
win32 interface graphique devcpp [ par Stephane ]
Salut a tous Voila je fait le pas progressif Visual Basic vers CPP (j'utilise devcpp). Je commence à """"""maitriser"""""" les class et pointeur
Win32 affichage graphique fuite mémoire [ par _Jonathan ]
Bonjour a tous,j'ai fait une petite application affichant un graphique. Mais lorsque je le lance, le programme me bouffe toutes les ressources sous wi
Problème affichage Double buffering [ par _Jonathan ]
Bonjour,Dans une fenetre windows, je crée un objet nommé graphique a l'aide de WNDCLASS (CreateWindow(..."graphique"...)). Dans cette zone, je dessine
augmentation objets GDI [ par neomorpheus01 ]
Bonjour,Je me pose une question à propos de la gestion des objets GDI dans une application MFC (type boite de dialogue) développée sous VC++6 Quand j'
Clignotement graphique [ par sephiro ]
je travail en C/C++ Win32 (no MFC)J'ouvre un context de peripherie HDC, je dessine des lignes, copies des BITMAP, efface des zones or j'ai un effet de
projet win32 application [ par moumouteb ]
Salut. Après avoir lut les éloges de Visual C++ 2005, je viens de passer dessu. Mais qu'elle est l'équivalent sous VC++ 2005 de : projet win32 applic
cherche code source d'un application graphique de chute de balle [ par prado ]
salut les amis je suis un jeune etudiant au senegal debutant en programmation ; j'ai un probeme avec un progamme en c , avec affichage graphique . en
besoin d'aide pour programme d'affichage graphique [ par prado ]
salut je suis un jeune etudiant senegalais debutant en informatique . j'ai un probleme avec mon programme .le libele est le suivant : on souhaite simu
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|