The Revised DEVCAPS Program

The original DEVCAPS1 program in Chapter 11 displays all the information available from the GetDeviceCaps function for the video display and the current printer. The new version, shown in Figure 15-3, displays a menu of all the printers from the [devices] section of WIN.INI and lets you choose one. In addition to the DEVCAPS2 files shown here, you'll also need the DEVCAPS.C file from Chapter 11 (Figure 11-1).

DEVCAPS2.MAK

#-----------------------

# DEVCAPS.MAK make file

#-----------------------

devcaps2.exe : devcaps2.obj devcaps.obj devcaps2.res devcaps2.def

link devcaps2 devcaps, /align:16, NUL, /nod slibcew libw, devcaps2

rc devcaps2.res

devcaps2.obj : devcaps2.c devcaps2.h

cl -c -Gsw -Ow -W2 -Zp devcaps2.c

devcaps.obj : devcaps.c

cl -c -Gsw -Ow -W2 -Zp devcaps.c

devcaps2.res : devcaps2.rc devcaps2.h

rc -r devcaps2.rc

DEVCAPS2.C

/*------------------------------------------------------------------

DEVCAPS2.C -- Displays Device Capability Information (Version 2)

(c) Charles Petzold, 1990

------------------------------------------------------------------*/

#include <windows.h>

#include <string.h>

#include "devcaps2.h"

void DoBasicInfo (HDC, HDC, short, short) ; // in DEVCAPS.C

void DoOtherInfo (HDC, HDC, short, short) ;

void DoBitCodedCaps (HDC, HDC, short, short, short) ;

typedef VOID (FAR PASCAL *DEVMODEPROC) (HWND, HANDLE, LPSTR, LPSTR) ;

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

static char szAppName[] = "DevCaps2" ;

HWND hwnd ;

MSG msg ;

WNDCLASS wndclass ;

if (!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = szAppName ;

wndclass.lpszClassName = szAppName ;

RegisterClass (&wndclass) ;

}

hwnd = CreateWindow (szAppName, NULL,

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, nCmdShow) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;

}

void DoEscSupport (HDC hdc, HDC hdcInfo, short cxChar, short cyChar)

{

static struct

{

char *szEscCode ;

short nEscCode ;

}

esc [] =

{

"NEWFRAME", NEWFRAME,

"ABORTDOC", ABORTDOC,

"NEXTBAND", NEXTBAND,

"SETCOLORTABLE", SETCOLORTABLE,

"GETCOLORTABLE", GETCOLORTABLE,

"FLUSHOUTPUT", FLUSHOUTPUT,

"DRAFTMODE", DRAFTMODE,

"QUERYESCSUPPORT", QUERYESCSUPPORT,

"SETABORTPROC", SETABORTPROC,

"STARTDOC", STARTDOC,

"ENDDOC", ENDDOC,

"GETPHYSPAGESIZE", GETPHYSPAGESIZE,

"GETPRINTINGOFFSET", GETPRINTINGOFFSET,

"GETSCALINGFACTOR", GETSCALINGFACTOR } ;

static char *szYesNo [] = { "Yes", "No" } ;

char szBuffer [32] ;

POINT pt ;

short n, nReturn ;

TextOut (hdc, cxChar, cyChar, "Escape Support", 14) ;

for (n = 0 ; n < sizeof esc / sizeof esc [0] ; n++)

{

nReturn = Escape (hdcInfo, QUERYESCSUPPORT, 1,

(LPSTR) & esc[n].nEscCode, NULL) ;

TextOut (hdc, 6 * cxChar, (n + 3) * cyChar, szBuffer,

wsprintf (szBuffer, "%-24s %3s", (LPSTR) esc[n].szEscCode,

(LPSTR) szYesNo [nReturn > 0 ? 0 : 1])) ;

if (nReturn > 0 && esc[n].nEscCode >= GETPHYSPAGESIZE

&& esc[n].nEscCode <= GETSCALINGFACTOR)

{

Escape (hdcInfo, esc[n].nEscCode, 0, NULL, (LPSTR) &pt) ;

TextOut (hdc, 36 * cxChar, (n + 3) * cyChar, szBuffer,

wsprintf (szBuffer, "(%u,%u)", pt.x, pt.y)) ;

}

}

}

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

{

static char szAllDevices [4096], szDevice [32], szDriver [16],

szDriverFile [16], szWindowText [64] ;

static HANDLE hLibrary ;

static short n, cxChar, cyChar, nCurrentDevice = IDM_SCREEN,

nCurrentInfo = IDM_BASIC ;

char *szOutput, *szPtr ;

DEVMODEPROC lpfnDM ;

HDC hdc, hdcInfo ;

HMENU hMenu ;

PAINTSTRUCT ps ;

TEXTMETRIC tm ;

switch (message)

{

case WM_CREATE :

hdc = GetDC (hwnd) ;

SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

GetTextMetrics (hdc, &tm) ;

cxChar = tm.tmAveCharWidth ;

cyChar = tm.tmHeight + tm.tmExternalLeading ;

ReleaseDC (hwnd, hdc) ;

lParam = NULL ;

// fall through

case WM_WININICHANGE :

if (lParam != NULL && lstrcmp ((LPSTR) lParam, "devices") != 0)

return 0 ;

hMenu = GetSubMenu (GetMenu (hwnd), 0) ;

while (GetMenuItemCount (hMenu) > 1)

DeleteMenu (hMenu, 1, MF_BYPOSITION) ;

GetProfileString ("devices", NULL, "", szAllDevices,

sizeof szAllDevices) ;

n = IDM_SCREEN + 1 ;

szPtr = szAllDevices ;

while (*szPtr)

{

AppendMenu (hMenu, n % 16 ? 0 : MF_MENUBARBREAK, n, szPtr) ;

n++ ;

szPtr += strlen (szPtr) + 1 ;

}

AppendMenu (hMenu, MF_SEPARATOR, 0, NULL) ;

AppendMenu (hMenu, 0, IDM_DEVMODE, "Device Mode") ;

wParam = IDM_SCREEN ;

// fall through

case WM_COMMAND :

hMenu = GetMenu (hwnd) ;

if (wParam < IDM_DEVMODE) // IDM_SCREEN & Printers

{

CheckMenuItem (hMenu, nCurrentDevice, MF_UNCHECKED) ;

nCurrentDevice = wParam ;

CheckMenuItem (hMenu, nCurrentDevice, MF_CHECKED) ;

}

else if (wParam == IDM_DEVMODE)

{

GetMenuString (hMenu, nCurrentDevice, szDevice,

sizeof szDevice, MF_BYCOMMAND) ;

GetProfileString ("devices", szDevice, "",

szDriver, sizeof szDriver) ;

szOutput = strtok (szDriver, ", ") ;

strcat (strcpy (szDriverFile, szDriver), ".DRV") ;

if (hLibrary >= 32)

FreeLibrary (hLibrary) ;

hLibrary = LoadLibrary (szDriverFile) ;

if (hLibrary >= 32)

{

lpfnDM = GetProcAddress (hLibrary, "DEVICEMODE") ;

(*lpfnDM) (hwnd, hLibrary, (LPSTR) szDevice,

(LPSTR) szOutput) ;

}

}

else // info menu items

{

CheckMenuItem (hMenu, nCurrentInfo, MF_UNCHECKED) ;

nCurrentInfo = wParam ;

CheckMenuItem (hMenu, nCurrentInfo, MF_CHECKED) ;

}

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

case WM_INITMENUPOPUP :

if (lParam == 0)

EnableMenuItem (GetMenu (hwnd), IDM_DEVMODE,

nCurrentDevice == IDM_SCREEN ?

MF_GRAYED : MF_ENABLED) ;

return 0 ;

case WM_PAINT :

strcpy (szWindowText, "Device Capabilities: ") ;

if (nCurrentDevice == IDM_SCREEN)

{

strcpy (szDriver, "DISPLAY") ;

strcat (szWindowText, szDriver) ;

hdcInfo = CreateIC (szDriver, NULL, NULL, NULL) ;

}

else

{

hMenu = GetMenu (hwnd) ;

GetMenuString (hMenu, nCurrentDevice, szDevice,

sizeof szDevice, MF_BYCOMMAND) ;

GetProfileString ("devices", szDevice, "", szDriver, 10) ;

szOutput = strtok (szDriver, ", ") ;

strcat (szWindowText, szDevice) ;

hdcInfo = CreateIC (szDriver, szDevice, szOutput, NULL) ;

}

SetWindowText (hwnd, szWindowText) ;

hdc = BeginPaint (hwnd, &ps) ;

SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

if (hdcInfo)

{

switch (nCurrentInfo)

{

case IDM_BASIC :

DoBasicInfo (hdc, hdcInfo, cxChar, cyChar) ;

break ;

case IDM_OTHER :

DoOtherInfo (hdc, hdcInfo, cxChar, cyChar) ;

break ;

case IDM_CURVE :

case IDM_LINE :

case IDM_POLY : case IDM_TEXT :

DoBitCodedCaps (hdc, hdcInfo, cxChar, cyChar,

nCurrentInfo - IDM_CURVE) ;

break ;

case IDM_ESC :

DoEscSupport (hdc, hdcInfo, cxChar, cyChar) ;

break ;

}

DeleteDC (hdcInfo) ;

}

EndPaint (hwnd, &ps) ;

return 0 ;

case WM_DESTROY :

if (hLibrary >= 32)

FreeLibrary (hLibrary) ;

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;

}

DEVCAPS2.RC

/*-----------------------------

DEVCAPS2.RC resource script

-----------------------------*/

#include "devcaps2.h"

DevCaps2 MENU

{

POPUP "&Device"

{

MENUITEM "&Screen", IDM_SCREEN, CHECKED

}

POPUP "&Capabilities"

{

MENUITEM "&Basic Information", IDM_BASIC, CHECKED

MENUITEM "&Other Information", IDM_OTHER

MENUITEM "&Curve Capabilities", IDM_CURVE

MENUITEM "&Line Capabilities", IDM_LINE

MENUITEM "&Polygonal Capabilities",IDM_POLY

MENUITEM "&Text Capabilities", IDM_TEXT

MENUITEM SEPARATOR

MENUITEM "&Escape Support", IDM_ESC

}

}

DEVCAPS2.H

/*------------------------

DEVCAPS2.H header file

------------------------*/

#define IDM_SCREEN 1

#define IDM_DEVMODE 0x100

#define IDM_BASIC 0x101

#define IDM_OTHER 0x102

#define IDM_CURVE 0x103

#define IDM_LINE 0x104

#define IDM_POLY 0x105

#define IDM_TEXT 0x106

#define IDM_ESC 0x107

DEVCAPS2.DEF

;-------------------------------------

; DEVCAPS2.DEF module definition file

;-------------------------------------

NAME DEVCAPS2

DESCRIPTION 'Displays Device Capability Info (c) Charles Petzold, 1990'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE MULTIPLE

HEAPSIZE 1024

STACKSIZE 8192

EXPORTS WndProc

Because DEVCAPS2 obtains only an information context for the printer, you can select printers from DEVCAPS2's menu, even though they may have an output port of ”none.“ If you want to compare the capabilities of different printers, you can first use the Control Panel to add various printer drivers to WIN.INI.

DEVCAPS2 has an additional option on the Capabilities menu called Escape Support, which lets you see which of the more common Escape subfunctions are supported by the device driver. This information will become more meaningful a little later in this chapter, when we discuss the Escape function and its subfunctions.