The Perl Advent Calendar needs more articles for 2022. Submit your idea today!
#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "img_conv.h"
#include "guts.h"
#include "Window.h"
#include "Printer.h"
#include "DeviceBitmap.h"

#ifdef __cplusplus
extern "C" {
#endif


#define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#define var (( PWidget) self)->
#define HANDLE sys handle
#define DHANDLE(x) dsys(x) handle


ApiHandle
apc_prn_get_handle( Handle self)
{
	objCheck 0;
	return ( ApiHandle) sys ps;
}


Bool
apc_prn_create( Handle self) {
	objCheck false;
	apt_set(aptPrinter);
	return true;
}

static void ppi_create( LPPRINTER_INFO_2 dest, LPPRINTER_INFO_2 source)
{
#define SZCPY(field) dest-> field = duplicate_string( source-> field)
	memcpy( dest, source, sizeof( PRINTER_INFO_2));
	SZCPY( pPrinterName);
	SZCPY( pServerName);
	SZCPY( pShareName);
	SZCPY( pPortName);
	SZCPY( pDriverName);
	SZCPY( pComment);
	SZCPY( pLocation);
	SZCPY( pSepFile);
	SZCPY( pPrintProcessor);
	SZCPY( pDatatype);
	SZCPY( pParameters);
	if ( source-> pDevMode)
	{
		int sz = source-> pDevMode-> dmSize + source-> pDevMode-> dmDriverExtra;
		dest-> pDevMode = ( LPDEVMODE) malloc( sz);
		if ( dest-> pDevMode) memcpy( dest-> pDevMode, source-> pDevMode, sz);
	}
}


static void ppi_destroy( LPPRINTER_INFO_2 ppi)
{
	if ( !ppi) return;
	free( ppi-> pPrinterName);
	free( ppi-> pServerName);
	free( ppi-> pShareName);
	free( ppi-> pPortName);
	free( ppi-> pDriverName);
	free( ppi-> pComment);
	free( ppi-> pLocation);
	free( ppi-> pSepFile);
	free( ppi-> pPrintProcessor);
	free( ppi-> pDatatype);
	free( ppi-> pParameters);
	free( ppi-> pDevMode);
	memset( ppi, 0, sizeof( PRINTER_INFO_2));
}


Bool
apc_prn_destroy( Handle self)
{
	ppi_destroy( &sys s. prn. ppi);
	return true;
}


static int
prn_query( Handle self, const char * printer, LPPRINTER_INFO_2 info)
{
	DWORD returned, needed;
	LPPRINTER_INFO_2 ppi, useThis = NULL;
	int i;
	Bool useDefault = ( printer == NULL || strlen( printer) == 0);
	char * device;

	EnumPrinters( PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL, NULL,
			2, NULL, 0, &needed, &returned);

	ppi = ( LPPRINTER_INFO_2) malloc( needed + 4);
	if ( !ppi) return 0;

	if ( !EnumPrinters( PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL, NULL,
			2, ( LPBYTE) ppi, needed, &needed, &returned)) {
		apiErr;
		free( ppi);
		return 0;
	}

	if ( returned == 0) {
		apcErr( errNoPrinters);
		free( ppi);
		return 0;
	}

	device = apc_prn_get_default( self);

	for ( i = 0; i < returned; i++)
	{
		if ( useDefault && device && ( strcmp( device, ppi[ i]. pPrinterName) == 0))
		{
			useThis = &ppi[ i];
			break;
		}
		if ( !useDefault && ( strcmp( printer, ppi[ i]. pPrinterName) == 0))
		{
			useThis = &ppi[ i];
			break;
		}
	}
	if ( useDefault && useThis == NULL) useThis = ppi;
	if ( useThis) ppi_create( info, useThis);
	if ( !useThis) apcErr( errInvPrinter);
	free( ppi);
	return useThis ? 1 : -2;
}


PrinterInfo*
apc_prn_enumerate( Handle self, int * count)
{
	DWORD returned, needed;
	LPPRINTER_INFO_2 ppi;
	PPrinterInfo list;
	char *printer;
	int i;

	*count = 0;
	objCheck NULL;

	EnumPrinters( PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL, NULL, 2,
			NULL, 0, &needed, &returned);

	ppi = ( LPPRINTER_INFO_2) malloc( needed + 4);
	if ( !ppi) return NULL;

	if ( !EnumPrinters( PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL, NULL, 2,
			( LPBYTE) ppi, needed, &needed, &returned)) {
		apiErr;
		free( ppi);
		return NULL;
	}

	if ( returned == 0) {
		apcErr( errNoPrinters);
		free( ppi);
		return NULL;
	}

	printer = apc_prn_get_default( self);

	list = ( PPrinterInfo) malloc( returned * sizeof( PrinterInfo));
	if ( !list) {
		free( ppi);
		return NULL;
	}

	for ( i = 0; i < returned; i++)
	{
		strncpy( list[ i]. name,   ppi[ i]. pPrinterName, 255);   list[ i]. name[ 255]   = 0;
		strncpy( list[ i]. device, ppi[ i]. pPortName, 255);      list[ i]. device[ 255] = 0;
		list[ i]. defaultPrinter = (( printer != NULL) && ( strcmp( printer, list[ i]. name) == 0));
	}
	*count = returned;
	free( ppi);
	return list;
}

static HDC prn_info_dc( Handle self)
{
	LPPRINTER_INFO_2 ppi = &sys s. prn. ppi;
	HDC ret = CreateIC( ppi-> pDriverName, ppi-> pPrinterName, ppi-> pPortName, ppi-> pDevMode);
	if ( !ret) apiErr;
	return ret;
}

Bool
apc_prn_select( Handle self, const char* printer)
{
	int rc;
	PRINTER_INFO_2 ppi;
	HDC dc;

	objCheck false;

	rc = prn_query( self, printer, &ppi);
	if ( rc > 0)
	{
		ppi_destroy( &sys s. prn. ppi);
		memcpy( &sys s. prn. ppi, &ppi, sizeof( ppi));
	} else
		return false;

	if ( !( dc = prn_info_dc( self))) return false;
	sys res.      x = ( float) GetDeviceCaps( dc, LOGPIXELSX);
	sys res.      y = ( float) GetDeviceCaps( dc, LOGPIXELSY);
	sys lastSize. x = GetDeviceCaps( dc, HORZRES);
	sys lastSize. y = GetDeviceCaps( dc, VERTRES);
	if ( !DeleteDC( dc)) apiErr;
	return true;
}

char *
apc_prn_get_selected( Handle self)
{
	objCheck "";
	return sys s. prn. ppi. pPrinterName;
}

Point
apc_prn_get_size( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys lastSize;
}

Point
apc_prn_get_resolution( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys res;
}

char *
apc_prn_get_default( Handle self)
{
	objCheck "";

	GetProfileString("windows", "device", ",,,", sys s. prn. defPrnBuf, 255);
	if (( sys s. prn. device = strtok( sys s. prn. defPrnBuf, (const char *) ","))
				&& ( sys s. prn. driver = strtok((char *) NULL,
					(const char *) ", "))
				&& ( sys s. prn. port = strtok ((char *) NULL,
					(const char *) ", "))) {

	} else
		sys s. prn. device = sys s. prn. driver = sys s. prn. port = NULL;

	return sys s. prn. device;
}

Bool
apc_prn_setup( Handle self)
{
	void * lph;
	LONG sz, ret;
	DEVMODE * dm;
	HWND who = GetActiveWindow();
	HDC dc;

	objCheck false;
	if ( !OpenPrinter( sys s. prn. ppi. pPrinterName, &lph, NULL))
		apiErrRet;
	sz = DocumentProperties( NULL, lph, sys s. prn. ppi. pPrinterName, NULL, NULL, 0);
	if ( sz <= 0) {
		apiErr;
		ClosePrinter( lph);
		return false;
	}
	dm  = ( DEVMODE * ) malloc( sz);
	if ( !dm) {
		ClosePrinter( lph);
		return false;
	}

	sys s. prn. ppi. pDevMode-> dmFields = -1;
	ret = DocumentProperties( hwnd_to_view( who) ? who : NULL, lph, sys s. prn. ppi. pPrinterName,
		dm, sys s. prn. ppi. pDevMode, DM_IN_BUFFER|DM_IN_PROMPT|DM_OUT_BUFFER);
	ClosePrinter( lph);
	if ( ret != IDOK) {
		free( dm);
		return false;
	}
	free( sys s. prn. ppi. pDevMode);
	sys s. prn. ppi. pDevMode = dm;

	if ( !( dc = prn_info_dc( self))) return false;
	sys res.      x = ( float) GetDeviceCaps( dc, LOGPIXELSX);
	sys res.      y = ( float) GetDeviceCaps( dc, LOGPIXELSY);
	sys lastSize. x = GetDeviceCaps( dc, HORZRES);
	sys lastSize. y = GetDeviceCaps( dc, VERTRES);
	if ( !DeleteDC( dc)) apiErr;

	return true;
}

typedef struct _PrnKey
{
	long  value;
	char * name;
} PrnKey;

static PrnKey ctx_options[] = {
	{ DM_ORIENTATION     , "Orientation" },
	{ DM_PAPERSIZE       , "PaperSize" },
	{ DM_PAPERLENGTH     , "PaperLength" },
	{ DM_PAPERWIDTH      , "PaperWidth" },
	{ DM_SCALE           , "Scale" },
	{ DM_COPIES          , "Copies" },
	{ DM_DEFAULTSOURCE   , "DefaultSource" },
	{ DM_PRINTQUALITY    , "PrintQuality" },
	{ DM_COLOR           , "Color" },
	{ DM_DUPLEX          , "Duplex" },
	{ DM_YRESOLUTION     , "YResolution" },
	{ DM_TTOPTION        , "TTOption" },
	{ DM_COLLATE         , "Collate" },
	{ DM_FORMNAME        , "FormName" }
};

static PrnKey ctx_orientation[] = {
	{ DMORIENT_PORTRAIT   ,"Portrait" },
	{ DMORIENT_LANDSCAPE  ,"Landscape" }
};

static PrnKey ctx_papersize[] = {
	{ DMPAPER_LETTER             , "Letter" },
	{ DMPAPER_LETTERSMALL        , "LetterSmall" },
	{ DMPAPER_TABLOID            , "Tabloid" },
	{ DMPAPER_LEDGER             , "Ledger" },
	{ DMPAPER_LEGAL              , "Legal" },
	{ DMPAPER_STATEMENT          , "Statement" },
	{ DMPAPER_EXECUTIVE          , "Executive" },
	{ DMPAPER_A3                 , "A3" },
	{ DMPAPER_A4                 , "A4" },
	{ DMPAPER_A4SMALL            , "A4Small" },
	{ DMPAPER_A5                 , "A5" },
	{ DMPAPER_B4                 , "B4" },
	{ DMPAPER_B5                 , "B5" },
	{ DMPAPER_FOLIO              , "Folio" },
	{ DMPAPER_QUARTO             , "Quarto" },
	{ DMPAPER_10X14              , "10X14" },
	{ DMPAPER_11X17              , "11X17" },
	{ DMPAPER_NOTE               , "Note" },
	{ DMPAPER_ENV_9              , "ENV_9" },
	{ DMPAPER_ENV_10             , "ENV_10" },
	{ DMPAPER_ENV_11             , "ENV_11" },
	{ DMPAPER_ENV_12             , "ENV_12" },
	{ DMPAPER_ENV_14             , "ENV_14" },
	{ DMPAPER_CSHEET             , "CSheet" },
	{ DMPAPER_DSHEET             , "DSheet" },
	{ DMPAPER_ESHEET             , "ESheet" },
	{ DMPAPER_ENV_DL             , "ENV_DL" },
	{ DMPAPER_ENV_C5             , "ENV_C5" },
	{ DMPAPER_ENV_C3             , "ENV_C3" },
	{ DMPAPER_ENV_C4             , "ENV_C4" },
	{ DMPAPER_ENV_C6             , "ENV_C6" },
	{ DMPAPER_ENV_C65            , "ENV_C65" },
	{ DMPAPER_ENV_B4             , "ENV_B4" },
	{ DMPAPER_ENV_B5             , "ENV_B5" },
	{ DMPAPER_ENV_B6             , "ENV_B6" },
	{ DMPAPER_ENV_ITALY          , "ENV_Italy" },
	{ DMPAPER_ENV_MONARCH        , "ENV_Monarch" },
	{ DMPAPER_ENV_PERSONAL       , "ENV_Personal" },
	{ DMPAPER_FANFOLD_US         , "Fanfold_US" },
	{ DMPAPER_FANFOLD_STD_GERMAN , "Fanfold_Std_German" },
	{ DMPAPER_FANFOLD_LGL_GERMAN , "Fanfold_Lgl_German" }
#if(WINVER >= 0x0400)
	,
	{ DMPAPER_ISO_B4             , "ISO_B4" },
	{ DMPAPER_JAPANESE_POSTCARD  , "Japanese_Postcard" },
	{ DMPAPER_9X11               , "9X11" },
	{ DMPAPER_10X11              , "10X11" },
	{ DMPAPER_15X11              , "15X11" },
	{ DMPAPER_ENV_INVITE         , "ENV_Invite" },
	{ DMPAPER_RESERVED_48        , "RESERVED_48" },
	{ DMPAPER_RESERVED_49        , "RESERVED_49" },
	{ DMPAPER_LETTER_EXTRA       , "Letter_Extra" },
	{ DMPAPER_LEGAL_EXTRA        , "Legal_Extra" },
	{ DMPAPER_TABLOID_EXTRA      , "Tabloid_Extra" },
	{ DMPAPER_A4_EXTRA           , "A4_Extra" },
	{ DMPAPER_LETTER_TRANSVERSE  , "Letter_Transverse" },
	{ DMPAPER_A4_TRANSVERSE      , "A4_Transverse" },
	{ DMPAPER_LETTER_EXTRA_TRANSVERSE, "Per_Letter_Extra_Transverse" },
	{ DMPAPER_A_PLUS             , "A_Plus" },
	{ DMPAPER_B_PLUS             , "B_Plus" },
	{ DMPAPER_LETTER_PLUS        , "Letter_Plus" },
	{ DMPAPER_A4_PLUS            , "A4_Plus" },
	{ DMPAPER_A5_TRANSVERSE      , "A5_Transverse" },
	{ DMPAPER_B5_TRANSVERSE      , "B5_Transverse" },
	{ DMPAPER_A3_EXTRA           , "A3_Extra" },
	{ DMPAPER_A5_EXTRA           , "A5_Extra" },
	{ DMPAPER_B5_EXTRA           , "B5_Extra" },
	{ DMPAPER_A2                 , "A2" },
	{ DMPAPER_A3_TRANSVERSE      , "A3_Transverse" },
	{ DMPAPER_A3_EXTRA_TRANSVERSE, "A3_Extra_Transverse" }
#endif
};

static PrnKey ctx_defsource[] = {
	{ DMBIN_AUTO              , "Auto" },
	{ DMBIN_CASSETTE          , "Cassette" },
	{ DMBIN_ENVELOPE          , "Envelope" },
	{ DMBIN_ENVMANUAL         , "EnvManual" },
	{ DMBIN_FORMSOURCE        , "FormSource" },
	{ DMBIN_LARGECAPACITY     , "LargeCapacity" },
	{ DMBIN_LARGEFMT          , "LargeFmt" },
	{ DMBIN_LOWER             , "Lower" },
	{ DMBIN_MANUAL            , "Manual" },
	{ DMBIN_MIDDLE            , "Middle" },
	{ DMBIN_ONLYONE           , "OnlyOne" },
	{ DMBIN_TRACTOR           , "Tractor" },
	{ DMBIN_SMALLFMT          , "SmallFmt" },
	{ DMBIN_USER+0            , "User0" },
	{ DMBIN_USER+1            , "User1" },
	{ DMBIN_USER+2            , "User2" },
	{ DMBIN_USER+3            , "User3" },
	{ DMBIN_USER+4            , "User4" }
};

static PrnKey ctx_quality[] = {
	{ DMRES_HIGH    , "High" },
	{ DMRES_MEDIUM  , "Medium" },
	{ DMRES_LOW     , "Low" },
	{ DMRES_DRAFT   , "Draft" }
};

static PrnKey ctx_color[] = {
	{ DMCOLOR_COLOR , "Color" },
	{ DMCOLOR_MONOCHROME, "Monochrome" }
};

static PrnKey ctx_duplex[] = {
	{ DMDUP_SIMPLEX ,   "Simplex" },
	{ DMDUP_HORIZONTAL, "Horizontal" },
	{ DMDUP_VERTICAL,   "Vertical" }
};

static PrnKey ctx_ttoption[] = {
	{ DMTT_BITMAP,           "Bitmap" },
	{ DMTT_DOWNLOAD,         "Download" },
#if(WINVER >= 0x0400)
	{ DMTT_DOWNLOAD_OUTLINE, "Download_Outline" },
#endif
	{ DMTT_SUBDEV,           "SubDev" }
};

static char *
ctx_prn_find_string( PrnKey * table, int table_size, long value)
{
	int i;
	for ( i = 0; i < table_size; i++, table++) {
		if ( table-> value == value)
			return table-> name;
	}
	return NULL;
}

#define BADVAL -16384

static long
ctx_prn_find_value( PrnKey * table, int table_size, char * name)
{
	int i;
	for ( i = 0; i < table_size; i++, table++) {
		if ( strcmp( table-> name, name) == 0)
			return table-> value;
	}
	return BADVAL;
}

Bool
apc_prn_set_option( Handle self, char * option, char * value)
{
	long v, num;
	char * e;
	LPDEVMODE dev = sys s. prn. ppi. pDevMode;

	objCheck false;
	if ( !dev) return false;

	v = ctx_prn_find_value( ctx_options, sizeof(ctx_options)/sizeof(PrnKey), option);
	if ( v == BADVAL) return false;

	/* DM_FORMNAME string is special because it's a literal string */
	if ( v == DM_FORMNAME) {
		strncpy((char*) dev-> dmFormName, value, CCHFORMNAME);
		dev-> dmFormName[CCHFORMNAME-1] = 0;
		return true;
	}

	/* any other setting may be a number */
	num = strtol( value, &e, 10);

#define LOOKUP_INT(table) \
	if ( *e) { \
		/* not a numerical */ \
		v = ctx_prn_find_value( table, sizeof(table)/sizeof(PrnKey), value); \
		if ( v == BADVAL) return false; \
	} else { \
		v = num;\
	}

	switch ( v) {
	case DM_ORIENTATION:
		LOOKUP_INT( ctx_orientation);
		dev-> dmOrientation = v;
		break;
	case DM_PAPERSIZE:
		LOOKUP_INT( ctx_papersize);
		dev-> dmPaperSize = v;
		break;
	case DM_PAPERLENGTH:
		if (*e) return false;
		dev-> dmPaperLength = v;
		break;
	case DM_PAPERWIDTH:
		if (*e) return false;
		dev-> dmPaperWidth = v;
		break;
	case DM_SCALE:
		if (*e) return false;
		dev-> dmScale = v;
		break;
	case DM_COPIES:
		if (*e) return false;
		dev-> dmCopies = v;
		break;
	case DM_DEFAULTSOURCE:
		LOOKUP_INT( ctx_defsource);
		dev-> dmDefaultSource = v;
		break;
	case DM_PRINTQUALITY:
		LOOKUP_INT( ctx_quality);
		dev-> dmPrintQuality = v;
		break;
	case DM_COLOR:
		LOOKUP_INT( ctx_color);
		dev-> dmColor = v;
		break;
	case DM_DUPLEX:
		LOOKUP_INT( ctx_duplex);
		dev-> dmDuplex = v;
		break;
	case DM_TTOPTION:
		LOOKUP_INT( ctx_ttoption);
		dev-> dmTTOption = v;
		break;
	case DM_YRESOLUTION:
		if (*e) return false;
		dev-> dmYResolution = v;
		break;
	case DM_COLLATE:
		if (*e) return false;
		dev-> dmCollate = v;
		break;
	default:
		return false;
	}

	return true;
}


Bool
apc_prn_get_option( Handle self, char * option, char ** value)
{
	long v;
	char * c = NULL, buf[256];
	LPDEVMODE dev = sys s. prn. ppi. pDevMode;

	*value = NULL;

	objCheck false;
	if ( !dev) return false;

	v = ctx_prn_find_value( ctx_options, sizeof(ctx_options)/sizeof(PrnKey), option);
	if ( v == BADVAL) return false;

#define LOOKUP_STR(table,value) \
	/* is a defined string? */ \
	if (( c = ctx_prn_find_string( \
		table, sizeof(table)/sizeof(PrnKey), value) \
	) == NULL) { \
		/* return just a number */ \
		sprintf( c = buf, "%d", value); \
	}

	switch ( v) {
	case DM_ORIENTATION:
		LOOKUP_STR( ctx_orientation, dev-> dmOrientation);
		break;
	case DM_PAPERSIZE:
		LOOKUP_STR( ctx_papersize, dev-> dmPaperSize);
		break;
	case DM_PAPERLENGTH:
		sprintf( c = buf, "%d", dev-> dmPaperLength);
		break;
	case DM_PAPERWIDTH:
		sprintf( c = buf, "%d", dev-> dmPaperWidth);
		break;
	case DM_SCALE:
		sprintf( c = buf, "%d", dev-> dmScale);
		break;
	case DM_COPIES:
		sprintf( c = buf, "%d", dev-> dmCopies);
		break;
	case DM_DEFAULTSOURCE:
		LOOKUP_STR( ctx_defsource, dev-> dmDefaultSource);
		break;
	case DM_PRINTQUALITY:
		LOOKUP_STR( ctx_quality, dev-> dmPrintQuality);
		break;
	case DM_COLOR:
		LOOKUP_STR( ctx_color, dev-> dmColor);
		break;
	case DM_DUPLEX:
		LOOKUP_STR( ctx_duplex, dev-> dmDuplex);
		break;
	case DM_TTOPTION:
		LOOKUP_STR( ctx_ttoption, dev-> dmTTOption);
		break;
	case DM_YRESOLUTION:
		sprintf( c = buf, "%d", dev-> dmYResolution);
		break;
	case DM_COLLATE:
		sprintf( c = buf, "%d", dev-> dmCollate);
		break;
	case DM_FORMNAME:
		strncpy( c = buf, (char*)dev-> dmFormName, CCHFORMNAME);
		break;
	default:
		return false;
	}

	if ( c)
		*value = duplicate_string( c);

	return true;
}

Bool
apc_prn_enum_options( Handle self, int * count, char *** options)
{
	LPDEVMODE dev = sys s. prn. ppi. pDevMode;
	int i, size;
	PrnKey * table;

	*count = 0;
	objCheck false;
	if ( !dev) return false;

	if ( !(*options = malloc( sizeof(char*) * 32)))
		return false;

	for (
		i = 0,
			size = sizeof( ctx_options) / sizeof( PrnKey),
			table = ctx_options;
		i < size;
		i++, table++
		) {
		if ( dev-> dmFields & table-> value)
			(*options)[(*count)++] = table-> name;
	}

	return true;
}


#define apiPrnErr       {                  \
	rc = GetLastError();                    \
	if ( rc != 1223 /* ERROR_CANCELLED */)  \
		apiAltErr( rc)                       \
	else                                    \
		apcErr( errUserCancelled);           \
}

Bool
apc_prn_begin_doc( Handle self, const char* docName)
{
	LPPRINTER_INFO_2 ppi = &sys s. prn. ppi;
	DOCINFO doc;
	doc. cbSize = sizeof( DOCINFO);
	doc. lpszDocName = docName;
	doc. lpszOutput = NULL;
	doc. lpszDatatype = NULL;
	doc. fwType = 0;

	objCheck false;
	if ( !( sys ps = CreateDC( ppi-> pDriverName, ppi-> pPrinterName, ppi-> pPortName, ppi-> pDevMode)))
		apiErrRet;

	if ( StartDoc( sys ps, &doc) <= 0) {
		apiPrnErr;
		DeleteDC( sys ps);
		sys ps = NULL;
		return false;
	}
	if ( StartPage( sys ps) <= 0) {
		apiPrnErr;
		DeleteDC( sys ps);
		sys ps = NULL;
		return false;
	}

	hwnd_enter_paint( self);
	if (( sys pal = palette_create( self))) {
		SelectPalette( sys ps, sys pal, 0);
		RealizePalette( sys ps);
	}
	return true;
}

Bool
apc_prn_begin_paint_info( Handle self)
{
	LPPRINTER_INFO_2 ppi = &sys s. prn. ppi;

	objCheck false;
	if ( !( sys ps = CreateDC( ppi-> pDriverName, ppi-> pPrinterName, ppi-> pPortName, ppi-> pDevMode)))
		apiErrRet;

	hwnd_enter_paint( self);
	sys pal = palette_create( self);
	return true;
}


Bool
apc_prn_end_doc( Handle self)
{
	apcErrClear;

	objCheck false;
	if ( EndPage( sys ps) < 0) apiPrnErr;
	if ( EndDoc ( sys ps) < 0) apiPrnErr;

	hwnd_leave_paint( self);
	if ( sys pal) DeleteObject( sys pal);
	DeleteDC( sys ps);
	sys pal = NULL;
	sys ps = NULL;
	return guts.apcError == errOk;
}

Bool
apc_prn_end_paint_info( Handle self)
{
	apcErrClear;
	objCheck false;
	hwnd_leave_paint( self);
	DeleteDC( sys ps);
	sys ps = NULL;
	return guts.apcError == errOk;
}

Bool
apc_prn_new_page( Handle self)
{
	apcErrClear;
	objCheck false;
	if ( EndPage( sys ps) < 0) apiPrnErr;
	if ( StartPage( sys ps) < 0) apiPrnErr;
	return guts.apcError == errOk;
}

Bool
apc_prn_abort_doc( Handle self)
{
	objCheck false;
	if ( AbortDoc( sys ps) < 0) apiPrnErr;
	hwnd_leave_paint( self);
	if ( sys pal) DeleteObject( sys pal);
	DeleteDC( sys ps);
	sys pal = NULL;
	sys ps = NULL;
	return guts.apcError == errOk;
}

#ifdef __cplusplus
}
#endif