/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
/******************************************************************************\
*
* PROGRAM: PRINTER.C
*
* PURPOSE: This is a sample application demostrating some of the new
* printing functionality in Windows NT. This app allows the
* user to select between various GDI graphics primitives,
* to choose pen & brush colors, styles, and sizes, and to
* the print these graphics to a printer. Also, the app
* provides the user the ability to query information (reso-
* lution, etc.) about the various printers & drivers by
* making calls to GetDeviceCaps, etc.
*
* Functionality for PRINTER is split into six different
* modules as follows:
*
* printer.c - main event loop
* main window procedure
* about & abort dialog procedures
* printing thread
*
* paint.c - handles all painting printers & most painting
* to window
*
* enumprt.c - manages the display of information returned
* from calling EnumPrinters, EnumPrinterDrivers
*
* devcapsx.c- manages the display of information returned
* from calling DeviceCapabilitiesEx
*
* getpdriv.c- manages the display of information returned
* from calling GetPrinterDriver
*
* getcaps.c - manages the display of information returned
* from calling GetDeviceCaps
*
* FUNCTIONS: WinMain - initialization, create window, msg loop
* MainWndProc - processes main window msgs
* AboutDlgProc - processes About dlg msgs
* InvalidateClient - invalidates graphics part of client wnd
* RefreshPrinterCombobox- updates list of printers
* PrintThread - printing done here
* AbortProc - msg loop for abort
* AbortDlgProc - processes abort dialog messages
*
\******************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // for _mbstrlen
#include <winspool.h>
#include <commdlg.h>
#include "common.h"
#include "resource.h"
#include "printer.h"
// for internationalization
#define My_mbslen _mbstrlen
/******************************************************************************\
*
* FUNCTION: WinMain (standard WinMain INPUTS/RETURNS)
*
* COMMENTS: Register & create main window, loop for messages
*
\******************************************************************************/
int WINAPI WinMain (HINSTANCE ghInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
ghInst = ghInstance;
if (!hPrevInstance)
{
WNDCLASS wc;
wc.style = MAIN_CLASS_STYLE;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ghInst;
wc.hIcon = LoadIcon (ghInst, MAKEINTRESOURCE(MAIN_ICON));
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = (LPCSTR) MAIN_MENU_NAME;
wc.lpszClassName = (LPCSTR) MAIN_CLASS_NAME;
if (!RegisterClass (&wc))
{
MessageBox (NULL, "WinMain(): RegisterClass() failed",
GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONHAND);
return FALSE;
}
}
if (!(ghwndMain = CreateWindow ((LPCSTR) MAIN_CLASS_NAME,
(LPCSTR) GetStringRes(MAIN_WND_TITLE),
MAIN_WND_STYLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, ghInst, NULL)))
return FALSE;
ShowWindow (ghwndMain, nCmdShow);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
/******************************************************************************\
*
* FUNCTION: MainWndProc (standard window procedure INPUTS/RETURNS)
*
* COMMENTS: Handles main app window msg processing
*
\******************************************************************************/
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMappingModesSubMenu;
static HMENU hGraphicsSubMenu;
static HMENU hPenWidthSubMenu;
static HMENU hPenStyleSubMenu;
static HMENU hBrushStyleSubMenu;
static HWND hwndCombobox;
static int iComboboxWidth;
static LONG lTextHeight;
int i;
switch (msg)
{
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_PRINT:
case IDM_PRINTDLG:
{
DWORD threadId;
HANDLE hThread;
if (!(hThread = CreateThread (NULL, 0,
(LPTHREAD_START_ROUTINE) PrintThread,
(LPVOID) wParam, 0, &threadId)))
MessageBox (hwnd,
"MainWndProc(): Error creating print thread",
GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONHAND);
else
CloseHandle(hThread);
break;
}
case IDM_GETDEVICECAPS:
DialogBox (ghInst, (LPCTSTR) "List", hwnd,
(DLGPROC) GetDeviceCapsDlgProc);
break;
case IDM_ENUMPRINTERS:
DialogBox (ghInst, (LPCTSTR) "List", hwnd,
(DLGPROC) EnumPrintersDlgProc);
break;
case IDM_GETPRINTERDRIVER:
if (strcmp (gszDeviceName, "Display"))
DialogBox (ghInst, (LPCTSTR) "List", hwnd,
(DLGPROC) GetPrinterDriverDlgProc);
else
MessageBox (hwnd, (LPCTSTR) GetStringRes(IDS_ASKSELPRT),
(LPCTSTR) "PRINTER.EXE:", MB_OK);
break;
case IDM_ENUMPRINTERDRIVERS:
DialogBox (ghInst, (LPCTSTR) "List", hwnd,
(DLGPROC) EnumPrinterDriversDlgProc);
break;
case IDM_REFRESH:
RefreshPrinterCombobox (hwndCombobox);
break;
case IDM_ABOUT:
DialogBox (ghInst, (LPCTSTR) "About", hwnd, (DLGPROC) AboutDlgProc);
break;
case IDM_EXIT:
DestroyWindow (hwnd);
break;
case IDM_HIENGLISH:
case IDM_HIMETRIC:
case IDM_LOENGLISH:
case IDM_LOMETRIC:
case IDM_TWIPS:
case IDM_ISOTROPIC:
case IDM_ANISOTROPIC:
case IDM_TEXT:
//
// Uncheck the last map mode menuitem, check the new map mode
// menuitem, set iMappingMode according to menu id, cause a
// repaint
//
for (i = 0; i < MAX_MAP_MODES; i++)
if (giMapMode == gaMMLookup[i].iMapMode)
{
CheckMenuItem (hMappingModesSubMenu, gaMMLookup[i].wMenuItem,
MF_UNCHECKED | MF_BYCOMMAND);
break;
}
CheckMenuItem (hMappingModesSubMenu, LOWORD (wParam),
MF_CHECKED | MF_BYCOMMAND);
for (i = 0; i < MAX_MAP_MODES; i++)
if (LOWORD (wParam) == gaMMLookup[i].wMenuItem)
{
giMapMode = gaMMLookup[i].iMapMode;
break;
}
//
// invalidate the entire client so toolbar text gets updated
//
InvalidateRect (hwnd, NULL, TRUE);
break;
case IDM_ARC:
case IDM_ELLIPSE:
case IDM_LINETO:
case IDM_PIE:
case IDM_PLGBLT:
case IDM_POLYBEZIER:
case IDM_POLYGON:
case IDM_POLYLINE:
case IDM_POLYPOLYGON:
case IDM_RECTANGLE:
case IDM_ROUNDRECT:
case IDM_STRETCHBLT:
{
//
// Retrieve the DWORD flag value for the particular menuitem,
// toggle (un/check) the menuitem, set/clear the flag in
// gdwGraphicsOptions, cause a repaint
//
DWORD dwGraphic;
for (i = 0; i < MAX_GRAPHICS; i++)
if (LOWORD (wParam) == gaGraphicLookup[i].wMenuItem)
{
dwGraphic = gaGraphicLookup[i].dwGraphic;
break;
}
if (GetMenuState (hGraphicsSubMenu, LOWORD(wParam), MF_BYCOMMAND)
& MF_CHECKED)
{
gdwGraphicsOptions &= ~dwGraphic;
CheckMenuItem (hGraphicsSubMenu, LOWORD(wParam),
MF_UNCHECKED | MF_BYCOMMAND);
}
else
{
//
// Clear/uncheck the ENUMFONTS flag/menuitem
//
gdwGraphicsOptions &= ~ENUMFONTS;
CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
MF_UNCHECKED | MF_BYCOMMAND);
gdwGraphicsOptions |= dwGraphic;
CheckMenuItem (hGraphicsSubMenu, LOWORD(wParam),
MF_CHECKED | MF_BYCOMMAND);
}
InvalidateClient ();
break;
}
case IDM_ALLGRAPHICS:
//
// Clear/uncheck the ENUMFONTS flag/menuitem, set/check all
// other graphics flags/menuitems, cause a repaint
//
CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
MF_UNCHECKED | MF_BYCOMMAND);
for (i = 0; i < MAX_GRAPHICS; i++)
CheckMenuItem (hGraphicsSubMenu, IDM_ARC + i,
MF_CHECKED | MF_BYCOMMAND);
gdwGraphicsOptions = ALLGRAPHICS | (gdwGraphicsOptions & DRAWAXIS);
InvalidateClient ();
break;
case IDM_NOGRAPHICS:
//
// Clear/uncheck all graphics flags/menuitems, cause a repaint
//
for (i = 0; i < MAX_GRAPHICS; i++)
CheckMenuItem (hGraphicsSubMenu, IDM_ARC + i,
MF_UNCHECKED | MF_BYCOMMAND);
gdwGraphicsOptions &= (DRAWAXIS | ENUMFONTS);
InvalidateClient ();
break;
case IDM_ENUMFONTS:
//
// Set/clear ENUMFONTS flag, toggle (un/check) menuitem, if
// checking IDM_ENUMFONTS then uncheck all other items,
// cause a repaint
//
if (GetMenuState (hGraphicsSubMenu, IDM_ENUMFONTS, MF_BYCOMMAND)
& MF_CHECKED)
{
gdwGraphicsOptions &= DRAWAXIS;
CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
MF_UNCHECKED | MF_BYCOMMAND);
}
else
{
SendMessage (hwnd, WM_COMMAND, IDM_NOGRAPHICS, 0);
gdwGraphicsOptions = ENUMFONTS | (gdwGraphicsOptions & DRAWAXIS);
CheckMenuItem (hGraphicsSubMenu, IDM_ENUMFONTS,
MF_CHECKED | MF_BYCOMMAND);
}
InvalidateClient ();
break;
case IDM_DRAWAXIS:
//
// Set/clear DRAWAXIS flag, toggle (un/check) menuitem,
// cause a repaint
//
if (GetMenuState (hGraphicsSubMenu, IDM_DRAWAXIS, MF_BYCOMMAND)
& MF_CHECKED)
{
gdwGraphicsOptions &= ~DRAWAXIS;
CheckMenuItem (hGraphicsSubMenu, IDM_DRAWAXIS,
MF_UNCHECKED | MF_BYCOMMAND);
}
else
{
gdwGraphicsOptions |= DRAWAXIS;
CheckMenuItem (hGraphicsSubMenu, IDM_DRAWAXIS,
MF_CHECKED | MF_BYCOMMAND);
}
InvalidateClient ();
break;
case IDM_SETPENCOLOR:
case IDM_SETBRUSHCOLOR:
case IDM_TEXTCOLOR:
{
CHOOSECOLOR cc;
static DWORD adwCustColors[16];
memset ((void *) &cc, 0, sizeof (CHOOSECOLOR));
cc.lStructSize = sizeof (CHOOSECOLOR);
cc.hwndOwner = hwnd;
cc.Flags = CC_RGBINIT;
cc.lpCustColors = adwCustColors;
if (LOWORD (wParam) == IDM_SETPENCOLOR)
cc.rgbResult = gdwPenColor;
else if (LOWORD (wParam) == IDM_SETBRUSHCOLOR)
cc.rgbResult = gdwBrushColor;
else
cc.rgbResult = gdwTextColor;
//
// bring up choose color common dialog
//
ChooseColor (&cc);
if (LOWORD (wParam) == IDM_SETPENCOLOR)
gdwPenColor = cc.rgbResult;
else if (LOWORD (wParam) == IDM_SETBRUSHCOLOR)
gdwBrushColor = cc.rgbResult;
else
gdwTextColor = cc.rgbResult;
InvalidateClient ();
break;
}
case IDM_PENWIDTH_1:
case IDM_PENWIDTH_2:
case IDM_PENWIDTH_3:
case IDM_PENWIDTH_4:
case IDM_PENWIDTH_5:
case IDM_PENWIDTH_6:
case IDM_PENWIDTH_7:
case IDM_PENWIDTH_8:
//
// uncheck old pen width menuitem, check new one, cause a repaint
//
for (i = 0; i < MAX_PENWIDTHS; i++)
if (giPenWidth == gaPenWidths[i].iPenWidth)
{
CheckMenuItem (hPenWidthSubMenu, gaPenWidths[i].wMenuItem,
MF_UNCHECKED | MF_BYCOMMAND);
break;
}
for (i = 0; i < MAX_PENWIDTHS; i++)
if (LOWORD(wParam) == gaPenWidths[i].wMenuItem)
{
CheckMenuItem (hPenWidthSubMenu, gaPenWidths[i].wMenuItem,
MF_CHECKED | MF_BYCOMMAND);
giPenWidth = gaPenWidths[i].iPenWidth;
break;
}
InvalidateClient ();
break;
case IDM_PENCOLOR_SOLID:
case IDM_PENCOLOR_DASH:
case IDM_PENCOLOR_DOT:
case IDM_PENCOLOR_DASHDOT:
case IDM_PENCOLOR_DASHDOTDOT:
case IDM_PENCOLOR_NULL:
case IDM_PENCOLOR_INSIDEFRAME:
//
// uncheck old pen style menuitem, check new one, cause a repaint
//
for (i = 0; i < MAX_PENSTYLES; i++)
if (giPenStyle == gaPenStyles[i].iPenStyle)
{
CheckMenuItem (hPenStyleSubMenu, gaPenStyles[i].wMenuItem,
MF_UNCHECKED | MF_BYCOMMAND);
break;
}
for (i = 0; i < MAX_PENSTYLES; i++)
if (LOWORD(wParam) == gaPenStyles[i].wMenuItem)
{
CheckMenuItem (hPenStyleSubMenu, gaPenStyles[i].wMenuItem,
MF_CHECKED | MF_BYCOMMAND);
giPenStyle = gaPenStyles[i].iPenStyle;
break;
}
InvalidateClient ();
break;
case IDM_BRUSHSTYLE_HORIZONTAL:
case IDM_BRUSHSTYLE_VERTICAL:
case IDM_BRUSHSTYLE_FDIAGONAL:
case IDM_BRUSHSTYLE_BDIAGONAL:
case IDM_BRUSHSTYLE_CROSS:
case IDM_BRUSHSTYLE_DIAGCROSS:
for (i = 0; i < MAX_BRUSHSTYLES; i++) {
// Uncheck the old option
if (giBrushStyle == gaBrushStyles[i].iBrushStyle) {
CheckMenuItem (hBrushStyleSubMenu, gaBrushStyles[i].wMenuItem,
MF_UNCHECKED | MF_BYCOMMAND);
}
// Check the new option
if (LOWORD(wParam) == gaBrushStyles[i].wMenuItem) {
CheckMenuItem (hBrushStyleSubMenu, gaBrushStyles[i].wMenuItem,
MF_CHECKED | MF_BYCOMMAND);
giBrushStyle = gaBrushStyles[i].iBrushStyle;
}
}
InvalidateClient ();
break;
case ID_COMBOBOX:
switch (HIWORD(wParam))
{
case CBN_SELCHANGE:
{
DWORD dwIndex;
char buf[BUFSIZE];
//
// User clicked on one of the items in the toolbar combobox;
// figure out which item, then parse the text apart and
// copy it to the gszDriverName, gszDeviceName, and gszPort
// variables.
//
dwIndex = (DWORD) SendMessage ((HWND) lParam,
CB_GETCURSEL, 0, 0);
SendMessage ((HWND) lParam, CB_GETLBTEXT, dwIndex,
(LONG) buf);
if (!strcmp (buf, "Display"))
{
strcpy (gszDeviceName, "Display");
gszPort[0] =
gszDriverName[0] = '\0';
}
else
{
LPSTR lpszSrc;
LPSTR lpszDst;
for (lpszSrc = buf, lpszDst = gszDeviceName;
*lpszSrc && *lpszSrc != ';'; ) {
if (IsDBCSLeadByte(*lpszSrc)) {
*lpszDst++ = *lpszSrc++;
}
*lpszDst++ = *lpszSrc++;
}
*lpszDst = '\0';
for (lpszSrc++, lpszDst = gszPort;
*lpszSrc && *lpszSrc != ';'; ) {
if (IsDBCSLeadByte(*lpszSrc)) {
*lpszDst++ = *lpszSrc++;
}
*lpszDst++ = *lpszSrc++;
}
*lpszDst = '\0';
for (lpszSrc++, lpszDst = gszDriverName; *lpszSrc; ) {
if (IsDBCSLeadByte(*lpszSrc)) {
*lpszDst++ = *lpszSrc++;
}
*lpszDst++ = *lpszSrc++;
}
*lpszDst = '\0';
}
break;
}
}
break;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rect;
HRGN hrgn;
HPEN hpen, hpenSave;
HBRUSH hbr;
char buf[BUFSIZE];
POINT p;
BeginPaint (hwnd, &ps);
//
// paint 3d toolbar background & client size text
//
GetClientRect (hwnd, &rect);
rect.bottom = 2*glcyMenu;
FillRect (ps.hdc, &rect, GetStockObject (LTGRAY_BRUSH));
SelectObject (ps.hdc, GetStockObject (WHITE_PEN));
MoveToEx (ps.hdc, 0, 2*glcyMenu - 2, NULL);
LineTo (ps.hdc, 0, 0);
LineTo (ps.hdc, (int) rect.right, 0);
hpen = CreatePen (PS_SOLID, 1, 0x808080);
hpenSave = SelectObject (ps.hdc, hpen);
MoveToEx (ps.hdc, 0, (int) 2*glcyMenu-1, NULL);
LineTo (ps.hdc, (int) rect.right - 1, (int) 2*glcyMenu-1);
LineTo (ps.hdc, (int) rect.right - 1, 1);
SelectObject (ps.hdc, hpenSave);
DeleteObject (hpen);
GetClientRect (hwnd, &rect);
//
// positioning of the string based upon x,y,cx,cy of combobox
//
SetBkMode (ps.hdc, TRANSPARENT);
p.x = rect.right;
p.y = (rect.bottom - 2*glcyMenu < 0 ? 0 : rect.bottom - 2*glcyMenu);
SetMapMode (ps.hdc, giMapMode);
DPtoLP (ps.hdc, &p, 1);
if ((giMapMode != MM_TEXT) && (giMapMode != MM_ANISOTROPIC))
//
// p.y will come out negative because we started with origin in
// upper left corner
//
p.y = -p.y;
SetMapMode (ps.hdc, MM_TEXT);
sprintf (buf, "cxClient = %ld (%ld)", rect.right, p.x);
TextOut (ps.hdc, iComboboxWidth + (int) 3*glcyMenu/2, (int) glcyMenu/8,
buf, strlen (buf));
sprintf (buf, "cyClient = %ld (%ld)",
rect.bottom - 2*glcyMenu < 0 ? 0 : rect.bottom - 2*glcyMenu,
p.y);
TextOut (ps.hdc, iComboboxWidth + (int) 3*glcyMenu/2,
(int) (glcyMenu/8 + lTextHeight),
buf, strlen (buf));
//
// paint graphics background white
//
rect.top += 2*glcyMenu;
FillRect (ps.hdc, &rect, GetStockObject (WHITE_BRUSH));
if (rect.bottom <= 4*glcyMenu)
//
// we don't want to overpaint the toolbar, so just skip Paint() call
//
goto done_painting;
//
// set up a clip region so we don't draw all over our toolbar
//
GetClientRect (hwnd, &rect);
rect.top += 2*glcyMenu;
hrgn = CreateRectRgnIndirect (&rect);
SelectClipRgn (ps.hdc, hrgn);
DeleteObject (hrgn);
//
// set up view port, pens/brushes, & map mode, then paint
//
rect.top -= 2*glcyMenu;
if (giMapMode == MM_TEXT || giMapMode == MM_ANISOTROPIC)
SetViewportOrgEx (ps.hdc, glcyMenu, 3*glcyMenu, NULL);
else
SetViewportOrgEx (ps.hdc, glcyMenu, rect.bottom - glcyMenu, NULL);
rect.bottom -= 4*glcyMenu;
rect.right -= 2*glcyMenu;
hpen = CreatePen (giPenStyle, giPenWidth, gdwPenColor);
SelectObject (ps.hdc, hpen);
hbr = CreateHatchBrush (giBrushStyle, gdwBrushColor);
SelectObject (ps.hdc, hbr);
SetTextColor (ps.hdc, gdwTextColor);
SetMapMode (ps.hdc, giMapMode);
Paint (ps.hdc, &rect);
DeleteObject (hpen);
DeleteObject (hbr);
done_painting:
EndPaint (hwnd, &ps);
break;
}
case WM_CREATE:
{
HDC hdc;
TEXTMETRIC tm;
SIZE size;
HMENU hmenu, hPenSubMenu, hBrushSubMenu;
//
// initialize the globals
//
glcyMenu = (LONG) GetSystemMetrics (SM_CYMENU);
hmenu = GetMenu (hwnd);
hMappingModesSubMenu = GetSubMenu (hmenu, 2);
hGraphicsSubMenu = GetSubMenu (hmenu, 3);
hPenSubMenu = GetSubMenu (hmenu, 4);
hPenWidthSubMenu = GetSubMenu (hPenSubMenu, 1);
hPenStyleSubMenu = GetSubMenu (hPenSubMenu, 2);
hBrushSubMenu = GetSubMenu (hmenu, 5);
hBrushStyleSubMenu = GetSubMenu (hBrushSubMenu, 1);
GetTextMetrics ((hdc = GetDC (hwnd)), &tm);
lTextHeight = tm.tmHeight;
//
// create combobox to display current printers in. the width
// is caluculated by getting the text extent of a typical
// entry in the listbox.
//
#define ASTRING "long printer name;long port name;long driver name"
GetTextExtentPoint (hdc, ASTRING, sizeof (ASTRING), &size);
iComboboxWidth = (int) size.cx;
ReleaseDC (hwnd, hdc);
hwndCombobox = CreateWindow ((LPCSTR) "COMBOBOX", (LPCSTR) "",
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL,
(int) glcyMenu/2,
(int) glcyMenu/2 - 2, // - 2 = fudge factor
iComboboxWidth,
(int) 6*glcyMenu,
hwnd, NULL, ghInst, NULL);
SetWindowLong (hwndCombobox, GWL_ID, ID_COMBOBOX);
PostMessage (hwnd, WM_COMMAND,
(WPARAM) MAKELONG (IDM_REFRESH, 0),
(LPARAM) 0);
PostMessage (hwnd, WM_COMMAND,
(WPARAM) MAKELONG (IDM_POLYPOLYGON, 0),
(LPARAM) 0);
break;
}
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return (DefWindowProc (hwnd, msg, wParam, lParam));
}
return 0;
}
/******************************************************************************\
*
* FUNCTION: AboutDlgProc (standard dialog procedure INPUTS/RETURNS)
*
* COMMENTS: Handles "About" dialog messages
*
\******************************************************************************/
LRESULT CALLBACK AboutDlgProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDOK:
EndDialog (hwnd, TRUE);
return 1;
}
break;
}
return 0;
}
/******************************************************************************\
*
* FUNCTION: InvalidateClient
*
* COMMENTS: Eliminates the flashing of the toolbar when we redraw
*
\******************************************************************************/
void InvalidateClient ()
{
RECT rect;
GetClientRect (ghwndMain, &rect);
rect.top += 2*glcyMenu;
InvalidateRect (ghwndMain, &rect, TRUE);
}
/******************************************************************************\
*
* FUNCTION: RefreshPrinterCombobox
*
* INPUTS: hwndCombobox- handle of the toolbar combobox
*
* COMMENTS: The idea here is to enumerate all printers & list them in
* then combobox in the form: "DEVICE_NAME;PORT;DRIVER_NAME".
* Then later, when a user selects one of these, we just
* query out the string & parse it apart, sticking the
* appropriate parts into the DriverName, DeviceName, and
* Port variables.
*
* Also, the "Display" option is added to the combobox so
* that user can get DevCaps info about it.
*
\******************************************************************************/
void RefreshPrinterCombobox (HWND hwndCombobox)
{
DWORD dwFlags = PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL;
LPPRINTER_INFO_2 pPrinters;
DWORD cbPrinters;
DWORD cReturned, i;
char buf[256];
SendMessage (hwndCombobox, CB_RESETCONTENT, 0, 0);
//
// add the "Display" option to the combobox
//
strcpy (buf, "Display");
SendMessage (hwndCombobox, CB_INSERTSTRING, (UINT)-1, (LONG) buf);
//
// get byte count needed for buffer, alloc buffer, the enum the printers
//
EnumPrinters (dwFlags, NULL, 2, NULL, 0, &cbPrinters,
&cReturned);
if (!(pPrinters = (LPPRINTER_INFO_2) LocalAlloc (LPTR, cbPrinters + 4)))
{
MessageBox (ghwndMain, (LPCTSTR) GetStringRes(IDS_LALLOCFAIL),
(LPCTSTR)GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONEXCLAMATION);
goto done_refreshing;
}
if (!EnumPrinters (dwFlags, NULL, 2, (LPBYTE) pPrinters,
cbPrinters, &cbPrinters, &cReturned))
{
MessageBox (ghwndMain, (LPCTSTR) GetStringRes(IDS_ENUMPRTFAIL),
(LPCTSTR) GetStringRes2(ERR_MOD_NAME), MB_OK | MB_ICONEXCLAMATION);
goto done_refreshing;
}
if (cReturned > 0)
for (i = 0; i < cReturned; i++)
{
//
// for each printer in the PRINTER_INFO_2 array: build a string that
// looks like "DEVICE_NAME;PORT;DRIVER_NAME"
//
strcpy (buf, (pPrinters + i)->pPrinterName);
strcat (buf, ";");
strcat (buf, (pPrinters + i)->pPortName);
strcat (buf, ";");
strcat (buf, (pPrinters + i)->pDriverName);
SendMessage (hwndCombobox, CB_INSERTSTRING, (UINT)-1, (LONG) buf);
}
else
MessageBox (ghwndMain, GetStringRes(IDS_NOPRTLST), "PRINTER.EXE", MB_OK);
done_refreshing:
SendMessage (hwndCombobox, CB_SELECTSTRING, (UINT) -1, (LONG) buf);
PostMessage (ghwndMain, WM_COMMAND,
(WPARAM) MAKELONG (ID_COMBOBOX, CBN_SELCHANGE),
(LPARAM) hwndCombobox);
LocalFree (LocalHandle (pPrinters));
}
/******************************************************************************\
*
* FUNCTION: PrintThread
*
* INPUTS: wParam - wParam of a WM_COMMAND message containing menuitem id
*
* COMMENTS: This is the code for the print thread created when the user
* selects the "Print" or "PrintDlg" menuitems. A thread is used
* here more demostration purposes only, since we really don't
* have any background processing to do. A real app would want
* to have alot more error checking here (e.g. check return of
* StartDoc, StartPage...).
*
\******************************************************************************/
void PrintThread (LPVOID wParam)
{
DOCINFO di;
RECT rect;
HPEN hpen;
HBRUSH hbr;
switch (LOWORD((WPARAM) wParam)) {
case IDM_PRINT:
{
if (!strcmp (gszDeviceName, "Display"))
{
MessageBox (ghwndMain, GetStringRes(IDS_ASKSELPRT),
"PRINTER.EXE:", MB_OK);
return;
}
else if (!(ghdc = CreateDC (gszDriverName, gszDeviceName, gszPort, NULL)))
{
MessageBox (ghwndMain, "PrintThread(): CreateDC() failed",
GetStringRes2(ERR_MOD_NAME), MB_OK);
return;
}
break;
}
case IDM_PRINTDLG:
{
PRINTDLG pd;
//
// Initialize a PRINTDLG struct and call PrintDlg to allow user to
// specify various printing options...
//
memset ((void *) &pd, 0, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner = ghwndMain;
pd.Flags = PD_RETURNDC;
pd.hInstance = NULL;
PrintDlg(&pd);
ghdc = pd.hDC;
if (pd.hDevMode)
GlobalFree (pd.hDevMode);
if (pd.hDevNames)
GlobalFree (pd.hDevNames);
if (!ghdc)
{
MessageBox (ghwndMain, GetStringRes(IDS_PRTDLGFAIL),
GetStringRes2(ERR_MOD_NAME), MB_OK);
return;
}
}
}
//
// put up Abort & install the abort procedure
//
gbAbort = FALSE;
ghwndAbort = CreateDialog (ghInst, (LPCTSTR) "Abort", ghwndMain,
(DLGPROC) AbortDlgProc);
EnableWindow (ghwndMain, FALSE);
SetAbortProc (ghdc, AbortProc);
//
// create & select pen/brush
//
hpen = CreatePen (giPenStyle, giPenWidth, gdwPenColor);
SelectObject (ghdc, hpen);
hbr = CreateHatchBrush (giBrushStyle, gdwBrushColor);
SelectObject (ghdc, hbr);
SetTextColor (ghdc, gdwTextColor);
SetMapMode (ghdc, giMapMode);
SetRect(&rect, 0,0, GetDeviceCaps (ghdc, HORZRES), GetDeviceCaps (ghdc, VERTRES));
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = GetStringRes(IDS_PRTTST);
di.lpszOutput = NULL;
StartDoc (ghdc, &di);
if (gdwGraphicsOptions) {
Paint (ghdc, &rect);
} else {
LPSTR pBuf = GetStringRes(IDS_BLANKPG);
TextOut (ghdc, 5, 5, (LPCTSTR) pBuf, My_mbslen(pBuf));
}
// If we didn't abort the job
if (!gbAbort)
{
EndPage (ghdc);
EndDoc (ghdc);
DestroyWindow (ghwndAbort);
}
// Clean up
DeleteDC (ghdc);
DeleteObject(hpen);
DeleteObject(hbr);
EnableWindow (ghwndMain, TRUE);
}
/******************************************************************************\
*
* FUNCTION: AbortProc
*
* COMMENTS: Standard printing abort proc
*
\******************************************************************************/
BOOL CALLBACK AbortProc (HDC hdc, int error)
{
MSG msg;
while (!gbAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
if (!IsDialogMessage (ghwndAbort, &msg)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
return !gbAbort;
}
/******************************************************************************\
*
* FUNCTION: AbortDlgProc (standard dialog procedure INPUTS/RETURNS)
*
* COMMENTS: Handles "Abort" dialog messages
*
\******************************************************************************/
LRESULT CALLBACK AbortDlgProc (HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
EnableMenuItem (GetSystemMenu (hwnd, FALSE), SC_CLOSE, MF_GRAYED);
return TRUE;
case WM_COMMAND: // There's only one
switch (LOWORD (wParam)) {
case DID_CANCEL:
MessageBeep(MB_OK);
gbAbort = TRUE;
AbortDoc (ghdc);
DestroyWindow (hwnd);
break;
}
break;
}
return 0;
}
/******************************************************************************\
*
* FUNCTION: GetStringRes (int id INPUT ONLY)
*
* COMMENTS: Load the resource string with the ID given, and return a
* pointer to it. Notice that the buffer is common memory so
* the string must be used before this call is made a second time.
*
\******************************************************************************/
LPTSTR GetStringRes (int id)
{
static TCHAR buffer[MAX_PATH];
buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}
LPTSTR GetStringRes2 (int id)
{
static TCHAR buffer[MAX_PATH];
buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}