Impression en win32 api avec options

Soyez le premier à donner votre avis sur cette source.

Vue 9 109 fois - Téléchargée 1 179 fois

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

Ajouter un commentaire

Commentaires

Messages postés
1
Date d'inscription
vendredi 12 août 2005
Statut
Membre
Dernière intervention
15 septembre 2010

Super, très clair. Et quelque soit le nommage... très compréhensif et utile.
Merci
Messages postés
10
Date d'inscription
mercredi 11 mars 2009
Statut
Membre
Dernière intervention
3 janvier 2010

Salut,
vraiment c'est un code très intéressant mais je me demande comment je pourrais spécifier le fichier à imprimer ou le voir avant l'impression car j'ai un problème dans l'exécution du crystal report dans mon application win32.
Merci
Messages postés
1910
Date d'inscription
vendredi 18 juin 2004
Statut
Modérateur
Dernière intervention
14 novembre 2014
12
Merci pour les commentaires et la note.
JFRANCOIS >> Désolé pour l'encre. Tu aurais pu décocher la case couleur avant l'impression afin d'imprimer en noir et blanc. Il est également possible d'imprimer sur une imprimante virtuelle donnant du pdf. J'avais beaucoup hésité pour le choix de l'image d'aperçu du code source. J'ai finalement penché pour l'interface du programme au lieu de la page de test imprimée. Je pense que je devrais les mettre tous les deux. J'avais également hésité sur le contenu de la page de test mais j'ai finalement opté pour la simplicité du code source.
Messages postés
1243
Date d'inscription
jeudi 31 mars 2005
Statut
Membre
Dernière intervention
3 août 2016
1
Source très intéressante RACPP :) comme d'habitude ;)
Messages postés
482
Date d'inscription
vendredi 26 août 2005
Statut
Membre
Dernière intervention
5 décembre 2009

Un bon code pour comprendre l'impression sous l'API Win32 malgré un nommage des variables assez particulier en effet.
MAIS ...
J'ai testé par curiosité, sans avoir vu les détails de la page imprimée, et là l'horreur !!! Une ellipse remplie de jaune sur toute la page (gondollée vu la quantité d'encre) !!! ASSASSIN !!! Une tonne d'encre bousillée ! Et je ne peux même pas essorer la page et remettre l'encre dans la cartouche ! Rien que ça cela mériterait un zéro pointé mais je mets 9, bon tutoriel quand même !
Afficher les 8 commentaires

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.