Impression en win32 api avec options

Description

Vu le très peu de codes sources traitant de l'impression sur le site, et en réponse à certaines questions du forum, voici un petit projet montrant comment définir les options d'impression avant de lancer le tirage sur papier. Ce petit programme permet de définir les options suivantes:
- Choisir l'imprimante à utiliser.
- Choisir le format de papier pour l'imprimante choisie.
- Choisir entre l'impression en couleur ou en noir et blanc pour les imprimantes couleur.
- Choisir la qualité d'impression.
- Choisir le mode d'impression portrait ou paysage.
- Choisir le nombre de copies.
A noter que ces options sont applicables seulement pendant l'impression du document en cours pour notre application. Ce qui présente l'avantage de ne pas toucher aux paramètres de l'imprimante. La boite de dialogue commune PrintDlg n'est pas utilisée afin de communiquer directement avec le spooler. Le code récupère la structure DEVMODE associée à une imprimante grâce à la fonction DocumentProperties(). Il suffit de modifier certains membres de cette strucure pour définir les options voulues. Elle sera ensuite passée en dernier paramètre à la fonction CreateDC(). Cette dernière retourne le HDC de l'imprimante permettant ainsi d'écrire ou de dessiner dessus.
Ce petit projet a été réalisé en C sous Visual C 2005. Etant en Win32 API, il est facilement adaptable aux autres outils.
Pour tester directement l'exécutable figurant dans le dossier Release, renommez le en impression.exe
Ce programme a été testé sans problème sous XP et Vista.
Toutes les questions, commentaires ou remarques sont les bienvenus.

Source / Exemple :


#include <windows.h>
#include <commctrl.h>

#pragma comment(lib,"comctl32.lib")

#define EDIT_COPIES 1001 // Identificateur de l'Edit du nombre de copies

BOOL CALLBACK ImpressionProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hsImprimante,hsPapier,hsCouleur,hsQualite,hsMode,hsCopies;
	static HWND hradioPortrait,hradioPaysage,hudCopies,heCopies,hbImprimer;
	static HWND hcomboImprimantes,hcomboPapier,hcomboQualite,hcheckCouleur;
	static HBRUSH hbrFond;
	static UINT nmaxcopies;
	static HICON hicon;
	static char buffer[260];
	static char* szqualite[]={"Meilleure","Moyenne","Basse","Brouillon"};
	switch (message)
	{
	case WM_INITDIALOG:
		{
			BOOL bret;
			UINT i;
			DWORD dwneeded=0;
			DWORD dwreturned=0;
			HFONT guifont;
			HWND hwndchild=0;
			// Charger l'icone depuis les ressources et l'appliquer à notre boite de dialogue:
			hicon=(HICON)LoadImage(GetModuleHandle(0),"IDI_00",IMAGE_ICON,16,16,0);
			SendMessage(hwnd,WM_SETICON,0,(LPARAM)hicon);
			// Mettre le texte de la barre de titre:
			SetWindowText(hwnd," Impression en Win32 avec options");
			// Créer un brush pour la couleur du fond de la boite:
			hbrFond=CreateSolidBrush(RGB(124,164,224));
			// Créer les controles:
			hsImprimante=CreateWindowEx(0,"static","Imprimante :  ",WS_CHILD | WS_VISIBLE | SS_RIGHT ,20,22,80,20,hwnd,0,0,0);
			hsPapier=CreateWindowEx(0,"static","Papier :  ",WS_CHILD | WS_VISIBLE | SS_RIGHT ,20,62,80,20,hwnd,0,0,0);
			hsCouleur=CreateWindowEx(0,"static","Couleur :  ",WS_CHILD | WS_VISIBLE  | SS_RIGHT,20,102,80,20,hwnd,0,0,0);
			hsQualite=CreateWindowEx(0,"static","Qualité :  ",WS_CHILD | WS_VISIBLE | SS_RIGHT ,20,142,80,20,hwnd,0,0,0);
			hsMode=CreateWindowEx(0,"static","Mode :  ",WS_CHILD | WS_VISIBLE  | SS_RIGHT,20,182,80,20,hwnd,0,0,0);
			hsCopies=CreateWindowEx(0,"static","Copies :  ",WS_CHILD | WS_VISIBLE  | SS_RIGHT,20,222,80,20,hwnd,0,0,0);
			hcomboImprimantes=CreateWindowEx(WS_EX_CLIENTEDGE ,"combobox",0,WS_CHILD | WS_VISIBLE  | WS_VSCROLL| CBS_DROPDOWNLIST | WS_TABSTOP,100,20,250,300,hwnd,0,0,0);
			hcomboPapier=CreateWindowEx(WS_EX_CLIENTEDGE ,"combobox",0,WS_CHILD | WS_VISIBLE  | WS_VSCROLL| CBS_DROPDOWNLIST | WS_TABSTOP,100,60,250,250,hwnd,0,0,0);
			hcheckCouleur=CreateWindowEx(0,"button","Oui",WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP,100,100,60,20,hwnd,0,0,0);
			hcomboQualite=CreateWindowEx(WS_EX_CLIENTEDGE ,"combobox",0,WS_CHILD | WS_VISIBLE  | WS_VSCROLL| CBS_DROPDOWNLIST | WS_TABSTOP,100,140,100,500,hwnd,0,0,0);
			hradioPortrait=CreateWindowEx(0,"button","Portrait",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_TABSTOP,100,180,60,20,hwnd,0,0,0);
			hradioPaysage=CreateWindowEx(0,"button","Paysage",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_TABSTOP,180,180,60,20,hwnd,0,0,0);
			heCopies=CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("edit"),"1",WS_CHILD | WS_VISIBLE | ES_NUMBER | ES_CENTER | WS_TABSTOP,100,220,70,20,hwnd,(HMENU)EDIT_COPIES,0,0);
			hudCopies=CreateWindowEx(0,UPDOWN_CLASS,0,WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS,0,0,20,20,hwnd,0,0,0);
			hbImprimer=CreateWindowEx(0,"button","Imprimer la page de test",WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP,120,280,160,20,hwnd,0,0,0);
			// Attacher notre controle UpDown à l'Edit du nombre de copies:
			SendMessage(hudCopies,UDM_SETBUDDY  ,(WPARAM)heCopies,0);
			// Obtenir la police par défaut des boites de dialogue:
			guifont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
			//Appliquer cette police à tous les controles:
			while(hwndchild=FindWindowEx(hwnd,hwndchild,0,0)) SendMessage(hwndchild,WM_SETFONT,(WPARAM)guifont,0);
			// Déterminer la quatité de mémoire nécessaire pour charger les noms des imprimantes installées:
			bret=EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,NULL,4,0,0,&dwneeded,&dwreturned);
			// Vérifier que bret est null. dwneeded contient la quantité de mémoire requise:
			if(!bret && dwneeded)
			{
				// Allouer la quantité de mémoire requise:
				PRINTER_INFO_4 *ppi=(PRINTER_INFO_4*)GlobalAlloc(GPTR,dwneeded);
				if(ppi)// mémoire allouée avec succès
				{
					// Remplir notre mémoire avec les infos sur les imprimantes installées:
					bret=EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,NULL,4,(PBYTE)ppi,dwneeded,&dwneeded,&dwreturned);
					// Activer le combobox des imprimantes si au moins une a été trouvée:
					EnableWindow(hcomboImprimantes,dwreturned);
					// Remplir le combobox avec les noms des imprimantes trouvées:
					for(i=0;i<dwreturned;i++) SendMessage(hcomboImprimantes,CB_ADDSTRING,0,(LPARAM)ppi[i].pPrinterName);
					// Selectionner l'imprimante par défaut si des imprimantes ont été trouvées:
					if(dwreturned)SendMessage(hcomboImprimantes,CB_SETCURSEL,0,(LPARAM)0);
					GlobalFree(ppi);
				}
			}
			// Remplir le combobox des qualités d'impression:
			for(i=0;i<4;i++) SendMessage(hcomboQualite,CB_ADDSTRING,0,(LPARAM)szqualite[i]);
			// Simuler changement de sélection du combo des imprimantes pour forcer l'initialisation des autres controles:
			SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(0,CBN_SELCHANGE),(LPARAM)hcomboImprimantes);
			//Simulation de l'appui sur la touche ALT pour permettre l'affichage du rectangle de focus sur les controles:
			keybd_event(VK_MENU,0,0,0);
			keybd_event(VK_MENU,0,KEYEVENTF_KEYUP,0);
			// Rendre notre boite active suite à la simulation d'appui sur la touche ALT:
			SetForegroundWindow(hwnd);
		}
		break;

	case WM_CTLCOLORDLG:
		// Appliquer la couleur du fond de notre boite de dialogue:
		return (BOOL)hbrFond;

	case WM_CTLCOLORSTATIC:
		// Rendre le fond des statics, radios et checkboxes transparent:
		SetBkMode((HDC)wParam,TRANSPARENT);
		// Leur appliquer la couleur de fond:
		return (BOOL)hbrFond;

	case WM_COMMAND:
		if(HIWORD(wParam)==EN_CHANGE)
		{
			BOOL b1,b2,b3;
			UINT copies;
			// S'assurer que le contenu des controles est valide:
			b1=SendMessage(hcomboImprimantes,CB_GETCURSEL,0,0)>=0;
			b2=SendMessage(hcomboPapier,CB_GETCURSEL,0,0)>=0;
			copies=GetDlgItemInt(hwnd,EDIT_COPIES,0,0);
			b3=copies>0 && copies<=nmaxcopies;
			// Griser ou dégriser le bouton d'impression selon le cas:
			EnableWindow(hbImprimer,b1 && b2 && b3);
			return 0;
		}
		if(HIWORD(wParam)==CBN_SELCHANGE)
		{
			if((HWND)lParam==hcomboImprimantes)
			{
				DWORD dwreturned;
				UINT i;
				int cursel;
				// Griser le bouton d'impression:
				EnableWindow(hbImprimer,0);
				// Vider le combobox contenant les formats de papier:
				SendMessage(hcomboPapier,CB_RESETCONTENT,0,0);
				// Initialiser les autres controles:
				SendMessage(hcomboQualite,CB_SETCURSEL,0,0);
				SendMessage(hradioPortrait,BM_SETCHECK,1,0);
				SendMessage(hradioPaysage,BM_SETCHECK,0,0);
				SendMessage(hcheckCouleur,BM_SETCHECK,0,0);
				SetWindowText(heCopies,"1");
				// Déterminer la sélection courante du combobox des imprimantes:
				cursel=(int)SendMessage(hcomboImprimantes,CB_GETCURSEL,0,0);
				// Récupérer le nom de l'imprimante sélectionnée:
				SendMessage(hcomboImprimantes,CB_GETLBTEXT,cursel,(LPARAM)buffer);
				// Obtenir le nombre de formats de papier pour l'imprimante sélectionnée:
				dwreturned=DeviceCapabilities(buffer,0,DC_PAPERNAMES,0,0);
				if(dwreturned)
				{
					// Allouer la quantité de mémoire requise pour les noms de formats de papiers:
					char* pnames=(char*)GlobalAlloc(GPTR,dwreturned*64);
					if(pnames)
					{
						// Récupérer les noms de formats de papier:
						dwreturned=DeviceCapabilities(buffer,0,DC_PAPERNAMES,pnames,0);
						// Remplir le combobox des formats de papiers:
						for(i=0;i<dwreturned;i++)SendMessage(hcomboPapier,CB_ADDSTRING,0,(LPARAM)pnames+(i*64));
						// Libérer la mémoire allouée:
						GlobalFree(pnames);
					}
				}
				// Déterminer le nombre maximal de copies autorisé par l'imprimante sélectionnée:
				nmaxcopies=DeviceCapabilities(buffer,0,DC_COPIES,0,0);
				// Appliquer ce nombre comme limite supérieure de notre controle UpDown:
				SendMessage(hudCopies,UDM_SETRANGE ,0,MAKELONG(nmaxcopies,1));
				// S'assurer que l'imprimante sélectionnée supporte le mode paysage:
				dwreturned=DeviceCapabilities(buffer,0,DC_ORIENTATION,0,0);
				// Griser ou dégriser le bouton radio paysage selon le cas:
				EnableWindow(hradioPaysage,dwreturned);
				//S'assurer que l'imprimante sélectionnée supporte la couleur:
				dwreturned=DeviceCapabilities(buffer,0,DC_COLORDEVICE,0,0);
				// Griser ou dégriser le checkbox couleur selon le cas:
				EnableWindow(hcheckCouleur,dwreturned);
				// Rendre le checkbox couleur coché par défaut si la couleur est supportée:
				SendMessage(hcheckCouleur,BM_SETCHECK,dwreturned,0);
			}
			// Simuler un chagement dans un Edit pour actualiser l'état du bouton d'impression:
			SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(0,EN_CHANGE),(LPARAM)0);
			return 0;
		}
		if((HWND)lParam==hbImprimer)
		{
			BOOL bret;
			HANDLE hprinter;
			int cursel;
			// Déterminer la sélection courante du combobox des imprimantes:
			cursel=(int)SendMessage(hcomboImprimantes,CB_GETCURSEL,0,0);
			// Récupérer le nom de l'imprimante sélectionnée:
			SendMessage(hcomboImprimantes,CB_GETLBTEXT,cursel,(LPARAM)buffer);
			// Ouvrir l'imprimante sélectionnée:
			bret=OpenPrinter(buffer,&hprinter,0);
			if(bret)
			{
				DEVMODE* dvm;
				DWORD dwRet;
				BOOL bcheck;
				RECT rect;
				HDC pDC;
				DOCINFO di;
				HFONT hpolice,oldfont;
				HBRUSH oldbrush,hbrush;
				int cursel,largeur,hauteur,taillepolice;
				char szpapername[64];
				// Obtenir la taille de la structure DEVMODE utilisée par cette imprimante:
				dwRet = DocumentProperties( 0,hprinter, 0, 0,0, 0 ); 
				//Allouer la mémoire nécessaire pour notre structure:
				dvm=(DEVMODE*)GlobalAlloc(GPTR ,dwRet);
				// Copier le contenu de la strcture DEVMODE de l'imprimante dans la notre:
				dwRet = DocumentProperties( 0,hprinter,buffer, dvm,  0, DM_OUT_BUFFER); 
				// Obtenir l'état du checkbox paysage:
				bcheck=(BOOL)SendMessage(hradioPaysage,BM_GETCHECK,0,0);
				// Mettre la valeur correspondante dans le membre définissant l'orientation de l'impression:
				if(bcheck)dvm->dmOrientation=DMORIENT_LANDSCAPE;
				else dvm->dmOrientation=DMORIENT_PORTRAIT;
				// Obtenir le nom du format de papier sélectionné:
				cursel=(int)SendMessage(hcomboPapier,CB_GETCURSEL,0,0);
				SendMessage(hcomboPapier,CB_GETLBTEXT,cursel,(LPARAM)szpapername);
				// Limiter la longueur du nom à 31 pour compatibilité avec la structure DEVMODE:
				if(lstrlen(szpapername)>31)szpapername[31]=0;
				// Copier le nom du format dans le membre correspondant de la structure DEVMODE:
				lstrcpy(dvm->dmFormName,szpapername);
				// Récupérer et définir le nombre de copies à imprimer:
				dvm->dmCopies=GetDlgItemInt(hwnd,EDIT_COPIES,0,0);
				// Appliquer ou nom la couleur selon l'état du checkbox couleur:
				if(SendMessage(hcheckCouleur,BM_GETCHECK,0,0))dvm->dmColor=DMCOLOR_COLOR;
				else dvm->dmColor=DMCOLOR_MONOCHROME;
				// Récupérer et définir la qualité d'impression:
				dvm->dmPrintQuality=(short)SendMessage(hcomboQualite,CB_GETCURSEL,0,0)-4;
				// Définir les membres à prendre en charge de notre structure DEVMODE:
				dvm->dmFields= DM_FORMNAME | DM_ORIENTATION | DM_COPIES  | DM_COLOR | DM_PRINTQUALITY;
				// Fermer le handle de l'imprimante:
				ClosePrinter(hprinter);
				// Créer le HDC de l'imprimante en l'associant à notre structure DEVMODE:
				pDC = CreateDC (0,buffer, 0, dvm) ;
				// Initialiser les membres de la structure DOCINFO
				memset(&di, 0, sizeof(DOCINFO));
				di.cbSize = sizeof(DOCINFO);
				di.lpszDocName = "RACPP Impression";
				// Obtenir les dimensions de la zone imprimable:
				largeur=GetDeviceCaps(pDC, HORZRES);
				hauteur=GetDeviceCaps(pDC, VERTRES);
				SetRect(&rect,0,0,largeur,hauteur);
				// Calculer la taille de notre police selon le mode portrait ou paysage:
				if(dvm->dmOrientation==DMORIENT_PORTRAIT)taillepolice=largeur/16;
				else taillepolice=hauteur/16;
				// Créer notre police:
				hpolice=CreateFont(taillepolice,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
				// Appliquer notre police:
				oldfont=(HFONT)SelectObject(pDC,hpolice);
				// Créer un brush de couleur jaune pour la coloriation des formes:
				hbrush=CreateSolidBrush(RGB(255,255,0));
				// Appliquer notre brush:
				oldbrush=(HBRUSH)SelectObject(pDC,hbrush);
				// Initialiser l'impression de notre document:
				StartDoc(pDC, &di);
				// Initialiser l'impression de notre page:
				StartPage(pDC);
				// Dessiner une ellipse jaune:
				Ellipse(pDC,0,0,largeur,hauteur);
				// Définir la couleur du texte à imprimer:
				SetTextColor(pDC,RGB(0,0,255));
				// Rendre le fond du texte transparent:
				SetBkMode(pDC,TRANSPARENT);
				// Ecrire le texte avec centrage horizontal et vertical:
				DrawText(pDC,"Ceci est une page de test",-1,&rect,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
				// Lancer l'impression de la page:
				EndPage(pDC);
				// Fermer notre document:
				EndDoc(pDC);
				// Restaurer la police et le brush originaux de notre HDC de l'imprimante:
				SelectObject(pDC,oldfont);
				SelectObject(pDC,oldbrush);
				// Détruire notre HDC de l'imprimante:
				DeleteDC(pDC);
				// Détruire notre police et notre brush:
				DeleteObject(hbrush);
				DeleteObject(hpolice);
				// Libérer la mémoire allouée pour notre structure DEVMODE:
				GlobalFree(dvm);
			}
			return 0;
		}
		break;

	case WM_CLOSE:
		// Fermer la boite de dialogue:
		EndDialog(hwnd,0);
		break;

	case WM_DESTROY:
		// Détruire le brush de la couleur de fond et notre icone:
		DeleteObject(hbrFond);
		DestroyIcon(hicon);
		break;

	default:
		break;
	}
	return 0;
}
int APIENTRY WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR szcmd, int ishow)
{
	LPDLGTEMPLATE lpdt;
	INITCOMMONCONTROLSEX icm;
	icm.dwSize=sizeof(INITCOMMONCONTROLSEX);
	icm.dwICC=ICC_UPDOWN_CLASS;
	// Initialiser la librairie common controls pour le controle UpDown:
	InitCommonControlsEx(&icm);
	//Allouer de la mémoire pour notre dialog template:
	lpdt = ( LPDLGTEMPLATE) GlobalAlloc(GPTR, 512);   
	// Définir les styles de la boite de dialogue:
	lpdt->style =  WS_DLGFRAME| DS_CENTER  |WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
	// Définir les dimensions de la boite de dialogue:
	lpdt->cx = 200; lpdt->cy = 160;       
	//Lancer la boite de dialogue
	DialogBoxIndirectParam(hinst,lpdt,0,(DLGPROC)ImpressionProc,0);
	//Libération de la mémoire allouée:
	GlobalFree((HGLOBAL)lpdt);
	return 0;
}

Conclusion :


Le projet complet est dans le zip.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.