HaO2022-01-31: To store the settings of a Windows printer, the DEVMODE structure must be stored. This structure may be stored as a memory block or as partly meaningful values.
The following sketch is an extract of a Windows printer driver with the DEVMODE structure converted to a dict and back. In the application, parts of the DEVMODE dict may be edited, like orientation and paper size.
There is also an interface to get the allowed values per key and the possible key list.
Enjoy, Harald
#pragma warning(disable : 4201 4214 4514)
#define STRICT
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
// Taget Windows Server 2003
#define WINVER 0x0502
#define _WIN32_WINNT 0x0502
// TCL Defines
#define DLL_BUILD
#define USE_TCL_STUBS
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "tcl.h"
//------------------------------------------------------------------------------
// >>>> Helper defines
//------------------------------------------------------------------------------
// Values of the Res variable
// Succes, result value set or not necessary
#define RET_OK 0
// Error and result set
#define RET_ERROR -1
// Printer i/o error
#define RET_ERROR_PRINTER_IO -2
// Out of memory error
#define RET_ERROR_MEMORY -3
// Parameter error
#define RET_ERROR_PARAMETER -4
// User abord
#define RET_ERROR_USER -5
//------------------------------------------------------------------------------
// >>>> File Global Variables
static BOOL fg_f_pdlg_initialized = FALSE;
static PRINTDLG fg_pdlg;
// subcommand pagesetup orientation Option list and indexes
static const char *fg_orient_sub_cmds[] = {
"portrait", "landscape", NULL};
static const short fg_orient_i_command[] = {
DMORIENT_PORTRAIT, DMORIENT_LANDSCAPE};
// subcommand pagesetup pagesize
static const char *fg_papersize_sub_cmds[] = {
"Letter", "LetterSmall", "Tabloid", "Ledger", "Legal", "Statement",
"Executive", "A3", "A4", "A4Small", "A5", "B4", "B5", "Folio", "Quarto",
"10X14", "11X17", "Note", "Env_9", "Env_10", "Env_11", "Env_12", "Env_14",
"CSheet", "DSheet", "ESheet", "Env_Dl", "Env_C5", "Env_C3", "Env_C4",
"Env_C6", "Env_C65", "Env_B4", "Env_B5", "Env_B6", "Env_Italy",
"Env_Monarch", "Env_Personal", "Fanfold_Us", "Fanfold_Std_German",
"Fanfold_Lgl_German", "Iso_B4", "Japanese_Postcard", "9X11", "10X11",
"15X11", "Env_Invite", "Reserved_48", "Reserved_49", "Letter_Extra",
"Legal_Extra", "Tabloid_Extra", "A4_Extra", "Letter_Transverse",
"A4_Transverse", "Letter_Extra_Transverse", "A_Plus", "B_Plus",
"Letter_Plus", "A4_Plus", "A5_Transverse", "B5_Transverse", "A3_Extra",
"A5_Extra", "B5_Extra", "A2", "A3_Transverse", "A3_Extra_Transverse",
"Dbl_Japanese_Postcard", "A6", "JEnv_Kaku2", "JEnv_Kaku3", "JEnv_Chou3",
"JEnv_Chou4", "Letter_Rotated", "A3_Rotated", "A4_Rotated", "A5_Rotated",
"B4_JIS_Rotated", "B5_JIS_Rotated", "Japanese_Postcard_Rotated",
"Dbl_Japanese_Postcard_Rotated", "A6_Rotated", "JEnv_Kaku2_Rotated",
"JEnv_Kaku3_Rotated", "JEnv_Chou3_Rotated", "JEnv_Chou4_Rotated", "B6_JIS",
"B6_Jis_Rotated", "12X11", "Jenv_You4", "Jenv_You4_Rotated", "P16K", "P32K",
"P32Kbig", "PEnv_1", "PEnv_2", "PEnv_3", "PEnv_4", "PEnv_5", "PEnv_6",
"PEnv_7", "PEnv_8", "PEnv_9", "PEnv_10", "P16K_Rotated", "P32K_Rotated",
"P32Kbig_Rotated", "PEnv_1_Rotated", "PEnv_2_Rotated", "PEnv_3_Rotated",
"PEnv_4_Rotated", "PEnv_5_Rotated", "PEnv_6_Rotated", "PEnv_7_Rotated",
"PEnv_8_Rotated", "PEnv_9_Rotated", "PEnv_10_Rotated",
"User",
NULL };
static const short fg_papersize_i_command[] = {
DMPAPER_LETTER,
DMPAPER_LETTERSMALL,
DMPAPER_TABLOID,
DMPAPER_LEDGER,
DMPAPER_LEGAL,
DMPAPER_STATEMENT,
DMPAPER_EXECUTIVE,
DMPAPER_A3,
DMPAPER_A4,
DMPAPER_A4SMALL,
DMPAPER_A5,
DMPAPER_B4,
DMPAPER_B5,
DMPAPER_FOLIO,
DMPAPER_QUARTO,
DMPAPER_10X14,
DMPAPER_11X17,
DMPAPER_NOTE,
DMPAPER_ENV_9,
DMPAPER_ENV_10,
DMPAPER_ENV_11,
DMPAPER_ENV_12,
DMPAPER_ENV_14,
DMPAPER_CSHEET,
DMPAPER_DSHEET,
DMPAPER_ESHEET,
DMPAPER_ENV_DL,
DMPAPER_ENV_C5,
DMPAPER_ENV_C3,
DMPAPER_ENV_C4,
DMPAPER_ENV_C6,
DMPAPER_ENV_C65,
DMPAPER_ENV_B4,
DMPAPER_ENV_B5,
DMPAPER_ENV_B6,
DMPAPER_ENV_ITALY,
DMPAPER_ENV_MONARCH,
DMPAPER_ENV_PERSONAL,
DMPAPER_FANFOLD_US,
DMPAPER_FANFOLD_STD_GERMAN,
DMPAPER_FANFOLD_LGL_GERMAN,
DMPAPER_ISO_B4,
DMPAPER_JAPANESE_POSTCARD,
DMPAPER_9X11,
DMPAPER_10X11,
DMPAPER_15X11,
DMPAPER_ENV_INVITE,
DMPAPER_RESERVED_48,
DMPAPER_RESERVED_49,
DMPAPER_LETTER_EXTRA,
DMPAPER_LEGAL_EXTRA,
DMPAPER_TABLOID_EXTRA,
DMPAPER_A4_EXTRA,
DMPAPER_LETTER_TRANSVERSE,
DMPAPER_A4_TRANSVERSE,
DMPAPER_LETTER_EXTRA_TRANSVERSE,
DMPAPER_A_PLUS,
DMPAPER_B_PLUS,
DMPAPER_LETTER_PLUS,
DMPAPER_A4_PLUS,
DMPAPER_A5_TRANSVERSE,
DMPAPER_B5_TRANSVERSE,
DMPAPER_A3_EXTRA,
DMPAPER_A5_EXTRA,
DMPAPER_B5_EXTRA,
DMPAPER_A2,
DMPAPER_A3_TRANSVERSE,
DMPAPER_A3_EXTRA_TRANSVERSE,
DMPAPER_DBL_JAPANESE_POSTCARD,
DMPAPER_A6,
DMPAPER_JENV_KAKU2,
DMPAPER_JENV_KAKU3,
DMPAPER_JENV_CHOU3,
DMPAPER_JENV_CHOU4,
DMPAPER_LETTER_ROTATED,
DMPAPER_A3_ROTATED,
DMPAPER_A4_ROTATED,
DMPAPER_A5_ROTATED,
DMPAPER_B4_JIS_ROTATED,
DMPAPER_B5_JIS_ROTATED,
DMPAPER_JAPANESE_POSTCARD_ROTATED,
DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED,
DMPAPER_A6_ROTATED,
DMPAPER_JENV_KAKU2_ROTATED,
DMPAPER_JENV_KAKU3_ROTATED,
DMPAPER_JENV_CHOU3_ROTATED,
DMPAPER_JENV_CHOU4_ROTATED,
DMPAPER_B6_JIS,
DMPAPER_B6_JIS_ROTATED,
DMPAPER_12X11,
DMPAPER_JENV_YOU4,
DMPAPER_JENV_YOU4_ROTATED,
DMPAPER_P16K,
DMPAPER_P32K,
DMPAPER_P32KBIG,
DMPAPER_PENV_1,
DMPAPER_PENV_2,
DMPAPER_PENV_3,
DMPAPER_PENV_4,
DMPAPER_PENV_5,
DMPAPER_PENV_6,
DMPAPER_PENV_7,
DMPAPER_PENV_8,
DMPAPER_PENV_9,
DMPAPER_PENV_10,
DMPAPER_P16K_ROTATED,
DMPAPER_P32K_ROTATED,
DMPAPER_P32KBIG_ROTATED,
DMPAPER_PENV_1_ROTATED,
DMPAPER_PENV_2_ROTATED,
DMPAPER_PENV_3_ROTATED,
DMPAPER_PENV_4_ROTATED,
DMPAPER_PENV_5_ROTATED,
DMPAPER_PENV_6_ROTATED,
DMPAPER_PENV_7_ROTATED,
DMPAPER_PENV_8_ROTATED,
DMPAPER_PENV_9_ROTATED,
DMPAPER_PENV_10_ROTATED,
DMPAPER_USER
};
// subcommand pagesetup default source Option list and indexes
// Additional user values may be coded by positive integers
static const char *fg_default_source_sub_cmds[] = {
"upper", "onlyone", "lower", "middle", "manual",
"envelope", "envmanual", "auto", "tractor", "smallfmt",
"largefmt", "largecapacity", "cassette", "formsource", NULL};
static const short fg_default_source_i_command[] = {
DMBIN_UPPER, DMBIN_ONLYONE, DMBIN_LOWER, DMBIN_MIDDLE, DMBIN_MANUAL,
DMBIN_ENVELOPE, DMBIN_ENVMANUAL, DMBIN_AUTO, DMBIN_TRACTOR, DMBIN_SMALLFMT,
DMBIN_LARGEFMT, DMBIN_LARGECAPACITY, DMBIN_CASSETTE, DMBIN_FORMSOURCE};
// subcommand pagesetup print quality Option list and indexes
// Additional x resolution may be specified in DPI by positive values.
static const char *fg_print_quality_sub_cmds[] = {
"high", "medium", "low", "draft", NULL};
static const short fg_print_quality_i_command[] = {
DMRES_HIGH, DMRES_MEDIUM, DMRES_LOW, DMRES_DRAFT};
// subcommand pagesetup print color list and indexes
static const char *fg_color_sub_cmds[] = {
"color", "monochrome", NULL};
static const short fg_color_i_command[] = {
DMCOLOR_COLOR, DMCOLOR_MONOCHROME};
// subcommand pagesetup duplex print list and indexes
static const char *fg_duplex_sub_cmds[] = {
"simplex", "vertical", "horizontal", NULL};
static const short fg_duplex_i_command[] = {
DMDUP_SIMPLEX, DMDUP_VERTICAL, DMDUP_HORIZONTAL};
// subcommand pagesetup TTOptions list and indexes
static const char *fg_tt_option_sub_cmds[] = {
"bitmap", "download", "subdev", "downloadoutline", NULL};
static const short fg_tt_option_i_command[] = {
DMTT_BITMAP, DMTT_DOWNLOAD, DMTT_SUBDEV, DMTT_DOWNLOAD_OUTLINE};
// subcommand pagesetup NUp list and indexes
static const char *fg_n_up_sub_cmds[] = {
"system", "oneup", NULL};
static const DWORD fg_n_up_i_command[] = {
DMNUP_SYSTEM, DMNUP_ONEUP};
// subcommand pagesetup ICMMethod list and indexes
static const char *fg_icm_method_sub_cmds[] = {
"none", "system","driver",
"device", NULL};
static const DWORD fg_icm_method_i_command[] = {
DMICMMETHOD_NONE, DMICMMETHOD_SYSTEM, DMICMMETHOD_DRIVER,
DMICMMETHOD_DEVICE};
// subcommand pagesetup ICMIntent list and indexes
static const char *fg_icm_intent_sub_cmds[] = {
"saturate", "contrast","colorimetric", "abscolorimetric", NULL};
static const DWORD fg_icm_intent_i_command[] = {
DMICM_SATURATE, DMICM_CONTRAST, DMICM_COLORIMETRIC, DMICM_ABS_COLORIMETRIC};
// subcommand pagesetup MediaType list and indexes
static const char *fg_media_type_sub_cmds[] = {
"standard", "transparency","glossy", NULL};
static const DWORD fg_media_type_i_command[] = {
DMMEDIA_STANDARD, DMMEDIA_TRANSPARENCY, DMMEDIA_GLOSSY};
// subcommand pagesetup DitherType list and indexes
static const char *fg_dither_type_sub_cmds[] = {
"none", "coarse", "fine", "lineart",
"errordiffusion", "reserved6", "reserved7",
"reserved8", "reserved9", "grayscale", NULL};
static const DWORD fg_dither_type_i_command[] = {
DMDITHER_NONE, DMDITHER_COARSE, DMDITHER_FINE, DMDITHER_LINEART,
DMDITHER_ERRORDIFFUSION, DMDITHER_RESERVED6, DMDITHER_RESERVED7,
DMDITHER_RESERVED8, DMDITHER_RESERVED9, DMDITHER_GRAYSCALE};
// List of device dict index indexes
enum fg_device_dict_index {
dli_devicename=0,
dli_driverversion=1,
dli_orientation=2,
dli_papersize=3,
dli_paperlength=4,
dli_paperwidth=5,
dli_scale=6,
dli_copies=7,
dli_defaultsource=8,
dli_printquality=9,
dli_color=10,
dli_duplex=11,
dli_yresolution=12,
dli_ttoption=13,
dli_collate=14,
dli_formname=15,
dli_nup=16,
dli_icmmethod=17,
dli_icmintent=18,
dli_mediatype=19,
dli_dithertype=20,
dli_driverextra=21,
};
// List of devicedict indexes
// Indexes are in enum fg_device_dict_index
static const char *fg_device_index[] = {
"devicename", // 0
"driverversion", // 1
"orientation", // 2
"papersize", // 3
"paperlength", // 4
"paperwidth", // 5
"scale", // 6
"copies", // 7
"defaultsource", // 8
"printquality", // 9
"color", // 10
"duplex", // 11
"yresolution", // 12
"truetypeoption", // 13
"collate", // 14
"formname", // 15
"nup", // 16
"icmmethod", // 17
"icmintent", // 18
"mediatype", // 19
"dithertype", // 20
"driverextra", // 21
NULL
};
enum fg_device_dict_spec_type {
dds_list=0,
dds_num=1,
dds_float=2,
dds_listnum=3,
dds_binary=4,
dds_yn=5,
dds_text=6
};
static const char *fg_device_dict_spec_type_text[] = {
"list", // 0
"num", // 1
"float", // 2
"listnum", // 3
"binary", // 4
"yn", // 5
"text" // 6
};
struct DeviceDictChoice {
enum fg_device_dict_spec_type Type;
int Min;
int Division;
const char **Choices;
};
enum dds_max {
dds_max_short=0,
dds_max_word=1,
dds_max_dword=2
};
static const long fg_dds_max_values[] = {
32767, // 0 SHORT
65535, // 1 WORD
4294967, // 2 DWORD
};
static const struct DeviceDictChoice fg_device_dict_choices[] = {
{dds_text, 0, CCHDEVICENAME, NULL}, // 0 DEVICENAME
{dds_num, 0, dds_max_word, NULL}, // 1 DRIVERVERSION
{dds_list, 0, 0, fg_orient_sub_cmds}, // 2 ORIENTATION
{dds_list, 0, 0, fg_papersize_sub_cmds}, // 3 PAPERSIZE
{dds_float, 0, 10, NULL}, // 4 PAPERLENGTH
{dds_float, 0, 10, NULL}, // 5 PAPERWODTH
{dds_float, 0, 100, NULL}, // 6 SCALE
{dds_num, 0, dds_max_short, NULL}, // 7 COPIES
{dds_list, 0, 0, fg_default_source_sub_cmds}, // 8 DEFAULTSOURCE
{dds_listnum, 0, 0, fg_print_quality_sub_cmds}, // 9 PRINTQUALITY
{dds_list, 0, 0, fg_color_sub_cmds}, // 10 COLOR
{dds_list, 0, 0, fg_duplex_sub_cmds}, // 11 DUPLEX
{dds_num, 0, dds_max_short, NULL}, // 12 YRESOLUTION
{dds_list, 0, 0, fg_tt_option_sub_cmds}, // 13 TRUETYPEOPTION
{dds_yn, 0, 0, NULL}, // 14 COLLATE
{dds_text,0,CCHFORMNAME, NULL}, // 15 FORMNAME
{dds_listnum,256, dds_max_dword, fg_n_up_sub_cmds}, // 16 NUP
{dds_listnum,256, dds_max_dword, fg_icm_method_sub_cmds},// 17 ICMMETHOD
{dds_listnum,256, dds_max_dword, fg_icm_intent_sub_cmds},// 18 ICMINTENT
{dds_listnum,256, dds_max_dword, fg_media_type_sub_cmds},// 19 MEDIATYPE
{dds_listnum,256, dds_max_dword, fg_dither_type_sub_cmds},// 20 DITHERTYPE
{dds_binary,0, 0, NULL} // 21 DRIVEREXTRA
};
//------------------------------------------------------------------------------
// >>> local Prototypes
static int WinPrintCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]);
static TCHAR * ReturnLockedDeviceName( HGLOBAL hDevNames );
static char GetDeviceName(
Tcl_Interp *interp,
HGLOBAL hDevNames,
char Flags );
static char PrintPrinterSetup( Tcl_Interp *interp, TCHAR *pPrinter,
Tcl_Obj * pDeviceDict);
static char CreateDevMode( Tcl_Interp *interp, TCHAR * pPrinter,
Tcl_Obj * pDeviceDict, int fShowPropertySheet,
int fDictOnlySameDriverVersion);
static char ListChoices(Tcl_Interp *interp, const char *ppChoiceList[]);
static char DeviceDictSpecGet(Tcl_Interp *interp, char *KeyIn);
static char LoadDefaultPrinter( );
//------------------------------------------------------------------------------
// >>>>> DLL entry point
//------------------------------------------------------------------------------
BOOL __declspec(dllexport) WINAPI DllEntryPoint(
HINSTANCE hInstance,
DWORD seginfo,
LPVOID lpCmdLine)
{
/* Don't do anything, so just return true */
return TRUE;
}
//------------------------------------------------------------------------------
// >>>>> Initialisation Procedures
//------------------------------------------------------------------------------
int __declspec(dllexport) Winprint_Init (Tcl_Interp *Interp)
{
if (Tcl_InitStubs(Interp, "8.1", 0) == NULL)
{
return TCL_ERROR;
}
Tcl_CreateObjCommand(Interp, "winprint", WinPrintCmd, (ClientData)NULL,
(Tcl_CmdDeleteProc *)NULL);
Tcl_PkgProvide (Interp, "winprint", "1.0");
return TCL_OK;
}
//------------------------------------------------------------------------------
// Unload Procedures
//------------------------------------------------------------------------------
int __declspec(dllexport) Winprint_Unload (Tcl_Interp *Interp, int flags)
{
PrintReset( 0 );
return TCL_OK;
}
//------------------------------------------------------------------------------
// >>>>> Called routine
//------------------------------------------------------------------------------
// Decode tcl commands
int WinPrintCmd(ClientData unused, Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[])
{
// Option list and indexes
const char *subCmds[] = {
"devicedictkeys", "devicedictspec", "printersetup"
NULL};
enum iCommand {
iDeviceDictKeys, iDeviceDictSpec, iPrinterSetup,
};
// State variables
// choice of option
int Index;
// Result flag
char Res;
Tcl_Obj *resultPtr;
Tcl_DString sPar1;
//--------------------------------------------------------------------------
// > Check if option argument is given and decode it
if (objc > 1)
{
if (TCL_ERROR ==
Tcl_GetIndexFromObj(interp, objv[1], subCmds, "subcmd", 0, &Index))
return TCL_ERROR;
} else {
Tcl_WrongNumArgs(interp, 1, objv, "subcmd");
return TCL_ERROR;
}
//--------------------------------------------------------------------------
// > Check parameters and give usage messages
switch (Index) {
case iDeviceDictSpec:
if (objc != 3)
{
Tcl_WrongNumArgs(interp, 2, objv, "argument");
return TCL_ERROR;
}
break;
}
//--------------------------------------------------------------------------
// > Default result
Res = RET_OK;
//--------------------------------------------------------------------------
// >> Intermediate decode tasks
//--------------------------------------------------------------------------
// > One String parameter
// if this option is not given, a 0 pointer is present.
Tcl_DStringInit(& sPar1);
switch (Index) {
case iPrinterSetup:
if ( objc > 2 ) {
char *pStr;
int lStr;
pStr = Tcl_GetStringFromObj(objv[2],&lStr);
Tcl_WinUtfToTChar( pStr, lStr, &sPar1);
} else {
// As we need two 0's for a wide character to contain a zero,
// we set this here.
// The default single zero was interpreted as data.
Tcl_WinUtfToTChar("", 0, &sPar1);
}
}
//--------------------------------------------------------------------------
// >> Decode parameters and invoke
//--------------------------------------------------------------------------
switch (Index) {
case iDeviceDictKeys:
return ListChoices( interp, fg_device_index );
break;
case iDeviceDictSpec:
Res = DeviceDictSpecGet(interp, Tcl_GetStringFromObj(objv[2],NULL));
break;
case iPrinterSetup:
{
unsigned short MaxPage;
double Double;
Tcl_Obj * pDeviceDict;
TCHAR *pPrinter;
// > Argument 2: Printer is already in sPar or NULL
// It is critical to check it for length, as the leading 0
// is not sufficient, as TCHAR is 16 bit and two 0's are needed
pPrinter = (TCHAR *)Tcl_DStringValue(& sPar1);
// > PrinterSettingDict
if ( objc > 3 )
pDeviceDict = objv[3];
else
pDeviceDict = NULL;
switch (Index) {
case iPrinterSetup:
if ( Res == RET_OK )
Res = PrintPrinterSetup( interp, pPrinter, pDeviceDict);
break;
}
break;
}
//--------------------------------------------------------------------------
// >> Free any intermediated strings
//--------------------------------------------------------------------------
// String parameter
Tcl_DStringFree(& sPar1);
//----------------------------------------------------------------------
// >> format return value
//----------------------------------------------------------------------
resultPtr = Tcl_GetObjResult(interp);
switch (Res)
{
case RET_OK:
return TCL_OK;
case RET_ERROR_PRINTER_IO:
Tcl_SetStringObj( resultPtr, "Printer I/O error",-1);
return TCL_ERROR;
case RET_ERROR_MEMORY:
Tcl_SetStringObj( resultPtr, "Out of memory",-1);
return TCL_ERROR;
case RET_ERROR_PARAMETER:
Tcl_SetStringObj( resultPtr, "Wrong parameter",-1);
return TCL_ERROR;
case RET_ERROR_USER:
Tcl_SetStringObj( resultPtr, "User abort",-1);
return TCL_ERROR;
default:
case RET_ERROR:
return TCL_ERROR;
}
}
//------------------------------------------------------------------------------
// >>>>>> ReturnLockedDeviceName
//------------------------------------------------------------------------------
// Extract the device name from the hDevNames structure and return its pointer.
// > hDevNames must be unlocked un succes (which looses the return value).
static TCHAR * ReturnLockedDeviceName( HGLOBAL hDevNames )
{
LPDEVNAMES pDevNames;
pDevNames = (LPDEVNAMES) GlobalLock( hDevNames );
if ( NULL == pDevNames )
return NULL;
if ( pDevNames->wDeviceOffset == 0)
{
GlobalUnlock( hDevNames );
return NULL;
}
return ( (TCHAR *) pDevNames ) + ( pDevNames->wDeviceOffset );
}
//------------------------------------------------------------------------------
// >>>>> GetShortListStringObj
//------------------------------------------------------------------------------
static Tcl_Obj *GetShortListStringObj(
short ValueCur, const short pValues[], const char *pStrings[])
{
int IndexCur;
for (IndexCur = 0; pStrings[IndexCur] != NULL ; IndexCur++) {
if ( ValueCur == pValues[IndexCur] )
return Tcl_NewStringObj(pStrings[IndexCur], -1 );
}
return NULL;
}
//------------------------------------------------------------------------------
// >>>>> GetDWordListStringObj
//------------------------------------------------------------------------------
static Tcl_Obj *GetDWordListStringObj(
DWORD ValueCur, const DWORD pValues[], const char *pStrings[])
{
int IndexCur;
for (IndexCur = 0; pStrings[IndexCur] != NULL ; IndexCur++) {
if ( ValueCur == pValues[IndexCur] )
return Tcl_NewStringObj(pStrings[IndexCur], -1 );
}
return NULL;
}
//------------------------------------------------------------------------------
// >>>>> GetWideStringObj
//------------------------------------------------------------------------------
static Tcl_Obj * GetWideStringObj( WCHAR *pWideString, int CharacterCountMax)
{
int LengthCur, PosCur;
Tcl_DString Recoded;
Tcl_Obj * pObj;
// Find length of DeviceName
LengthCur = CharacterCountMax;
for (PosCur = 0; PosCur < CharacterCountMax; PosCur++) {
if (pWideString[PosCur] == 0) {
LengthCur = PosCur;
break;
}
}
Tcl_DStringInit(&Recoded);
Tcl_WinTCharToUtf(pWideString, LengthCur*sizeof(WCHAR), &Recoded);
pObj = Tcl_NewStringObj(
Tcl_DStringValue(&Recoded),
Tcl_DStringLength(&Recoded));
Tcl_DStringFree(&Recoded);
return pObj;
}
//------------------------------------------------------------------------------
// >>>>> DevmodeToDeviceDict
//------------------------------------------------------------------------------
static char DevmodeToDeviceDict(
Tcl_Interp *interp, DEVMODE * pDevMode, Tcl_Obj *pDeviceDict)
{
Tcl_Obj *pObj;
int fUser = 0;
//--------------------------------------------------------------------------
// DeviceName
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_devicename],-1),
GetWideStringObj(pDevMode->dmDeviceName, CCHDEVICENAME)))
return RET_ERROR;
//--------------------------------------------------------------------------
// DriverVersion
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_driverversion],-1),
Tcl_NewIntObj(pDevMode->dmDriverVersion) ))
return RET_ERROR;
//--------------------------------------------------------------------------
// > Orientation
if ( (pDevMode->dmFields & DM_ORIENTATION) != 0) {
pObj = GetShortListStringObj(pDevMode->dmOrientation,
fg_orient_i_command, fg_orient_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_orientation],-1),pObj ))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// > PaperSize
if ( (pDevMode->dmFields & DM_PAPERSIZE) != 0) {
pObj = GetShortListStringObj(pDevMode->dmPaperSize,
fg_papersize_i_command, fg_papersize_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_papersize], -1), pObj))
return RET_ERROR;
// Remember a user size to get width and height even if not flagged
fUser = (pDevMode->dmPaperSize == DMPAPER_USER);
}
}
//--------------------------------------------------------------------------
// Append Paper Length and Width. They are only senseful for PaperSize
// equal "User". So, take the value if paper = user and the value is
// senseful, e.g. positivie and above 1mm (10)
if ( pDevMode->dmPaperLength > 10
&& (pDevMode->dmFields & DM_PAPERLENGTH || fUser)) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_paperlength],-1),
Tcl_NewDoubleObj(pDevMode->dmPaperLength/10.0)))
return RET_ERROR;
}
if ( pDevMode->dmPaperWidth > 10
&& (pDevMode->dmFields & DM_PAPERWIDTH || fUser)) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_paperwidth],-1),
Tcl_NewDoubleObj(pDevMode->dmPaperWidth/10.0)))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append Scale factor
if ( pDevMode->dmScale > 0 && (pDevMode->dmFields & DM_SCALE) != 0) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_scale],-1),
Tcl_NewDoubleObj(pDevMode->dmScale/100.0) ))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append copies
if ( pDevMode->dmCopies > 0 && (pDevMode->dmFields & DM_COPIES) != 0) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_copies],-1),
Tcl_NewIntObj(pDevMode->dmCopies) ))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append defaultsource
if ( (pDevMode->dmFields & DM_DEFAULTSOURCE) != 0) {
pObj = GetShortListStringObj(pDevMode->dmDefaultSource,
fg_default_source_i_command, fg_default_source_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_defaultsource],-1),
pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append printquality
if ( (pDevMode->dmFields & DM_PRINTQUALITY) != 0) {
if (pDevMode->dmPrintQuality > 0) {
// This is an X Dimension DPI Value
pObj = Tcl_NewIntObj( pDevMode->dmPrintQuality );
} else {
pObj = GetShortListStringObj(pDevMode->dmPrintQuality,
fg_print_quality_i_command, fg_print_quality_sub_cmds);
}
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_printquality],-1),
pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append Color
if ( (pDevMode->dmFields & DM_COLOR) != 0) {
pObj = GetShortListStringObj(pDevMode->dmColor,
fg_color_i_command, fg_color_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_color],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append Duplex
if ( (pDevMode->dmFields & DM_DUPLEX) != 0) {
pObj = GetShortListStringObj(pDevMode->dmDuplex,
fg_duplex_i_command, fg_duplex_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_duplex],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append YResolution
if ( pDevMode->dmYResolution > 0
&& (pDevMode->dmFields & DM_YRESOLUTION) != 0) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_yresolution],-1),
Tcl_NewIntObj(pDevMode->dmYResolution)))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append TTOption
if ( (pDevMode->dmFields & DM_TTOPTION) != 0) {
pObj = GetShortListStringObj(pDevMode->dmTTOption,
fg_tt_option_i_command, fg_tt_option_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_ttoption],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append Collate
if ( (pDevMode->dmFields & DM_COLLATE) != 0
&& ( pDevMode->dmCollate == DMCOLLATE_TRUE
|| pDevMode->dmCollate == DMCOLLATE_FALSE ) ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_collate],-1),
Tcl_NewBooleanObj(pDevMode->dmCollate == DMCOLLATE_TRUE)))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append FormName
if ( (pDevMode->dmFields & DM_FORMNAME) != 0) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_formname],-1),
GetWideStringObj(pDevMode->dmFormName, CCHFORMNAME)))
return RET_ERROR;
}
//--------------------------------------------------------------------------
// Append Nup
if ( (pDevMode->dmFields & DM_NUP) != 0) {
pObj = GetDWordListStringObj(pDevMode->dmNup,
fg_n_up_i_command, fg_n_up_sub_cmds);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_nup],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append ICMMethod
if ( (pDevMode->dmFields & DM_ICMMETHOD) != 0) {
pObj = GetDWordListStringObj(pDevMode->dmICMMethod,
fg_icm_method_i_command, fg_icm_method_sub_cmds);
if ( pObj == NULL && pDevMode->dmICMMethod >= 256)
pObj = Tcl_NewLongObj(pDevMode->dmICMMethod);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_icmmethod],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append ICMIntent
if ( (pDevMode->dmFields & DM_ICMINTENT) != 0) {
pObj = GetDWordListStringObj(pDevMode->dmICMIntent,
fg_icm_intent_i_command, fg_icm_intent_sub_cmds);
if ( pObj == NULL && pDevMode->dmICMIntent >= 256 )
pObj = Tcl_NewLongObj(pDevMode->dmICMIntent);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_icmintent],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append MediaType
if ( (pDevMode->dmFields & DM_MEDIATYPE) != 0) {
pObj = GetDWordListStringObj(pDevMode->dmMediaType,
fg_media_type_i_command, fg_media_type_sub_cmds);
if ( pObj == NULL && pDevMode->dmMediaType >= 256)
pObj = Tcl_NewLongObj(pDevMode->dmMediaType);
if ( pObj != NULL ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_mediatype],-1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append DitherType
if ((pDevMode->dmFields & DM_DITHERTYPE) != 0) {
pObj = GetDWordListStringObj(pDevMode->dmDitherType,
fg_dither_type_i_command, fg_dither_type_sub_cmds);
if (pObj == NULL && pDevMode->dmDitherType >= 256)
pObj = Tcl_NewLongObj(pDevMode->dmDitherType);
if ( pObj != NULL ) {
if (TCL_OK != Tcl_DictObjPut(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_dithertype], -1), pObj))
return RET_ERROR;
}
}
//--------------------------------------------------------------------------
// Append Driver private blob
if ( pDevMode->dmDriverExtra > 0 ) {
if ( TCL_OK != Tcl_DictObjPut( interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_driverextra],-1),
Tcl_NewByteArrayObj(((BYTE *) pDevMode) + (pDevMode->dmSize),
pDevMode->dmDriverExtra)))
return RET_ERROR;
}
//--------------------------------------------------------------------------
return RET_OK;
}
//------------------------------------------------------------------------------
// >>>>> DeviceDictToDevmode
//------------------------------------------------------------------------------
static char DeviceDictToDevmode(Tcl_Interp *interp, Tcl_Obj *pDeviceDict,
DEVMODE * pDevMode, int fDictOnlySameDriverVersion)
{
Tcl_Obj *pObj;
int IndexCur;
int IntCur;
double DoubleCur;
int fSameDriverVersionOrNotVerified = 1;
int fDriverVersionVerified = 0;
//--------------------------------------------------------------------------
// > Initially, there are no fields set
// pDevMode->dmFields = 0
//--------------------------------------------------------------------------
// Check Device Name
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_devicename],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
Tcl_Obj * pObjDevice;
int DeviceNameLengthDict, DeviceNameLengthDevice;
char * DeviceNameDict, * DeviceNameDevice;
pObjDevice = GetWideStringObj(pDevMode->dmDeviceName, CCHDEVICENAME);
DeviceNameDict = Tcl_GetStringFromObj(pObj, &DeviceNameLengthDict);
DeviceNameDevice = Tcl_GetStringFromObj(pObjDevice,
&DeviceNameLengthDevice);
if ( DeviceNameLengthDevice == DeviceNameLengthDict
&& 0 == memcmp (DeviceNameDict, DeviceNameDevice,
DeviceNameLengthDevice))
fDriverVersionVerified = 1;
else
fSameDriverVersionOrNotVerified = 0;
}
//--------------------------------------------------------------------------
// Check Driver Version
// Check if same printer name
if (fDriverVersionVerified) {
int VersionDict;
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_driverversion],-1), &pObj))
return RET_ERROR;
if (pObj == NULL) {
fDriverVersionVerified = 0;
} else {
if (TCL_OK != Tcl_GetIntFromObj(interp, pObj,&VersionDict))
return RET_ERROR;
if (VersionDict != pDevMode->dmDriverVersion ) {
fSameDriverVersionOrNotVerified = 0;
fDriverVersionVerified = 0;
}
}
}
//--------------------------------------------------------------------------
// > Orientation
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_orientation],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_orient_sub_cmds, fg_device_index[dli_orientation], TCL_EXACT,
&IndexCur))
return RET_ERROR;
pDevMode->dmOrientation = fg_orient_i_command[IndexCur];
pDevMode->dmFields |= DM_ORIENTATION;
}
//--------------------------------------------------------------------------
// > PaperSize
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_papersize],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_papersize_sub_cmds, fg_device_index[dli_papersize],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmPaperSize = fg_papersize_i_command[IndexCur];
pDevMode->dmFields |= DM_PAPERSIZE;
}
//--------------------------------------------------------------------------
// Append Paper Length and Width. They are only senseful for PaperSize
// equal "User".
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_paperlength],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetDoubleFromObj( interp, pObj, &DoubleCur))
return RET_ERROR;
pDevMode->dmPaperLength = (short)(floor(DoubleCur * 10+0.5));
pDevMode->dmFields |= DM_PAPERLENGTH;
}
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_paperwidth],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetDoubleFromObj( interp, pObj, &DoubleCur))
return RET_ERROR;
pDevMode->dmPaperWidth = (short)(floor(DoubleCur * 10+0.5));
pDevMode->dmFields |= DM_PAPERWIDTH;
}
//--------------------------------------------------------------------------
// > Get out here, if other driver version and this is checked.
// > The following settings may not fit to the changed driver.
if (!fSameDriverVersionOrNotVerified && fDictOnlySameDriverVersion)
return RET_OK;
//--------------------------------------------------------------------------
// Append Scale factor
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_scale],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetDoubleFromObj( interp, pObj, &DoubleCur))
return RET_ERROR;
pDevMode->dmScale = (short)(floor(DoubleCur * 100+0.5));
pDevMode->dmFields |= DM_SCALE;
}
//--------------------------------------------------------------------------
// Append copies
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_copies],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmCopies = (short)IntCur;
pDevMode->dmFields |= DM_COPIES;
}
//--------------------------------------------------------------------------
// Append defaultsource
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_defaultsource],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_default_source_sub_cmds, fg_device_index[dli_defaultsource],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmDefaultSource = fg_default_source_i_command[IndexCur];
pDevMode->dmFields |= DM_DEFAULTSOURCE;
}
//--------------------------------------------------------------------------
// Append printquality
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_printquality],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_print_quality_sub_cmds, fg_device_index[dli_printquality],
TCL_EXACT, &IndexCur))
{
// Not in list-> check for int
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmPrintQuality = (short)IntCur;
} else {
pDevMode->dmPrintQuality = fg_print_quality_i_command[IndexCur];
}
pDevMode->dmFields |= DM_PRINTQUALITY;
}
//--------------------------------------------------------------------------
// Append Color
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_color],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_color_sub_cmds, fg_device_index[dli_color],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmColor = fg_color_i_command[IndexCur];
pDevMode->dmFields |= DM_COLOR;
}
//--------------------------------------------------------------------------
// Append Duplex
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_duplex],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_duplex_sub_cmds, fg_device_index[dli_duplex],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmDuplex = fg_color_i_command[IndexCur];
pDevMode->dmFields |= DM_DUPLEX;
}
//--------------------------------------------------------------------------
// Append YResolution
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_yresolution],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmYResolution = (short)IntCur;
pDevMode->dmFields |= DM_YRESOLUTION;
}
//--------------------------------------------------------------------------
// Append TTOption
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_ttoption],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_tt_option_sub_cmds, fg_device_index[dli_ttoption],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmTTOption = fg_tt_option_i_command[IndexCur];
pDevMode->dmFields |= DM_TTOPTION;
}
//--------------------------------------------------------------------------
// Append Collate
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_collate],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetBooleanFromObj( interp, pObj, &IntCur))
return RET_ERROR;
if (IntCur)
pDevMode->dmCollate = DMCOLLATE_TRUE;
else
pDevMode->dmCollate = DMCOLLATE_FALSE;
pDevMode->dmFields |= DM_COLLATE;
}
//--------------------------------------------------------------------------
// Append FormName
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_formname],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
char * StrCur;
int LengthCur;
Tcl_DString Recoded;
// Recode to UTF-16
Tcl_DStringInit(&Recoded);
StrCur = Tcl_GetStringFromObj(pObj, &LengthCur);
Tcl_WinUtfToTChar(StrCur,LengthCur,&Recoded);
// Pad to right length
while (Tcl_DStringLength(&Recoded) < sizeof(WCHAR) * CCHFORMNAME)
Tcl_DStringAppend(&Recoded, "\0\0", 2);
// Truncate overflow bytes
Tcl_DStringSetLength(&Recoded, sizeof(WCHAR) * CCHFORMNAME);
memcpy(pDevMode->dmFormName, Tcl_DStringValue(&Recoded),
sizeof(WCHAR) * CCHFORMNAME);
pDevMode->dmFields |= DM_COLLATE;
}
//--------------------------------------------------------------------------
// Append Nup
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_nup],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_n_up_sub_cmds, fg_device_index[dli_nup],
TCL_EXACT, &IndexCur))
return RET_ERROR;
pDevMode->dmNup = fg_tt_option_i_command[IndexCur];
pDevMode->dmFields |= DM_NUP;
}
//--------------------------------------------------------------------------
// Append ICMMethod
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_icmmethod],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_icm_method_sub_cmds, fg_device_index[dli_icmmethod],
TCL_EXACT, &IndexCur))
{
// Not in list-> check for int
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmICMMethod = (DWORD)IntCur;
} else {
pDevMode->dmICMMethod = fg_icm_method_i_command[IndexCur];
}
pDevMode->dmFields |= DM_ICMMETHOD;
}
//--------------------------------------------------------------------------
// Append ICMIntent
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_icmintent],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_icm_intent_sub_cmds, fg_device_index[dli_icmintent],
TCL_EXACT, &IndexCur))
{
// Not in list-> check for int
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmICMIntent = (DWORD)IntCur;
} else {
pDevMode->dmICMIntent = fg_icm_intent_i_command[IndexCur];
}
pDevMode->dmFields |= DM_ICMINTENT;
}
//--------------------------------------------------------------------------
// Append MediaType
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_mediatype],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj( interp, pObj,
fg_media_type_sub_cmds, fg_device_index[dli_mediatype],
TCL_EXACT, &IndexCur))
{
// Not in list-> check for int
if (TCL_OK != Tcl_GetIntFromObj( interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmMediaType = (DWORD)IntCur;
} else {
pDevMode->dmMediaType = fg_media_type_i_command[IndexCur];
}
pDevMode->dmFields |= DM_MEDIATYPE;
}
//--------------------------------------------------------------------------
// Append DitherType
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_dithertype], -1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
if (TCL_OK != Tcl_GetIndexFromObj(interp, pObj,
fg_dither_type_sub_cmds, fg_device_index[dli_dithertype],
TCL_EXACT, &IndexCur))
{
// Not in list-> check for int
if (TCL_OK != Tcl_GetIntFromObj(interp, pObj, &IntCur))
return RET_ERROR;
pDevMode->dmDitherType = (DWORD)IntCur;
}
else {
pDevMode->dmDitherType = fg_dither_type_i_command[IndexCur];
}
pDevMode->dmFields |= DM_DITHERTYPE;
}
//--------------------------------------------------------------------------
// Append Driver private blob
// > Get out, if other driver version
if (!fDriverVersionVerified)
return RET_OK;
if (TCL_OK != Tcl_DictObjGet(interp, pDeviceDict,
Tcl_NewStringObj(fg_device_index[dli_driverextra],-1), &pObj))
return RET_ERROR;
if (pObj != NULL) {
unsigned char *pByteCur;
int LengthCur;
pByteCur = Tcl_GetByteArrayFromObj(pObj,&LengthCur);
// Only take the driver extra data, if:
// - blob has right size
// - it is from same driver version
// - it is from same generic device name
if (LengthCur == pDevMode->dmDriverExtra) {
memcpy(((BYTE *) pDevMode) + (pDevMode->dmSize), pByteCur,
LengthCur);
}
}
//--------------------------------------------------------------------------
return RET_OK;
}
//------------------------------------------------------------------------------
// >>>>> PrintPrinterSetup
//------------------------------------------------------------------------------
// Show the page setup dialogue box and return the users selection as tcl
// variables.
static char PrintPrinterSetup( Tcl_Interp *interp, TCHAR *pPrinter,
Tcl_Obj * pDeviceDict)
{
char Res;
DEVMODE *pDevMode;
//--------------------------------------------------------------------------
PrintReset( 1 );
//--------------------------------------------------------------------------
Res = CreateDevMode( interp, pPrinter, pDeviceDict, 1 , 1);
if ( RET_OK != Res )
return Res;
//--------------------------------------------------------------------------
if ( fg_pdlg.hDevMode == NULL )
{
return RET_ERROR_PRINTER_IO;
}
//--------------------------------------------------------------------------
pDevMode = GlobalLock( fg_pdlg.hDevMode );
if ( NULL == pDevMode )
return RET_ERROR_MEMORY;
//--------------------------------------------------------------------------
// > Orientation and paper size
if ( Res == RET_OK )
{
Tcl_Obj * pDeviceDictOut;
pDeviceDictOut = Tcl_NewObj();
Tcl_IncrRefCount(pDeviceDictOut);
Res = DevmodeToDeviceDict( interp, pDevMode, pDeviceDictOut);
if ( Res == RET_OK ) {
Tcl_SetObjResult( interp, pDeviceDictOut );
}
Tcl_DecrRefCount(pDeviceDictOut);
}
//--------------------------------------------------------------------------
GlobalUnlock( fg_pdlg.hDevMode );
//--------------------------------------------------------------------------
return Res;
}
//------------------------------------------------------------------------------
// >>>>> CreateDevMode
//------------------------------------------------------------------------------
// Create a DevMode structure for the given settings
// The devmode structure is put in a moveable memory object.
// The handle is placed in fg_pdlg.hDevMode.
static char CreateDevMode( Tcl_Interp *interp,
TCHAR * pPrinter, Tcl_Obj * pDeviceDict, int fShowPropertySheet,
int fDictOnlySameDriverVersion)
{
HANDLE hPrinter;
DEVMODE* lpDevMode;
LONG Size;
DWORD fMode;
char fDevNamesLocked;
char Res;
//--------------------------------------------------------------------------
Res = RET_OK;
//--------------------------------------------------------------------------
// > If no printer given, use last or default printer
//--------------------------------------------------------------------------
if ( pPrinter == NULL || pPrinter[0] == '\0' )
{
if ( fg_pdlg.hDevNames == NULL )
{
Res = LoadDefaultPrinter( );
if ( Res != RET_OK )
return Res;
}
pPrinter = ReturnLockedDeviceName( fg_pdlg.hDevNames );
fDevNamesLocked = 1;
} else {
fDevNamesLocked = 0;
}
//--------------------------------------------------------------------------
// > Get Printer handle
if ( FALSE == OpenPrinter( pPrinter, &hPrinter, NULL) )
{
hPrinter = NULL;
Res = RET_ERROR_PRINTER_IO;
}
//--------------------------------------------------------------------------
// > Get DevMode structure size
if (Res == RET_OK )
{
Size = DocumentProperties( NULL, hPrinter, pPrinter, NULL, NULL, 0 );
if ( Size < 0 )
Res = RET_ERROR_PRINTER_IO;
}
//--------------------------------------------------------------------------
// > Adjust or get new memory
lpDevMode = NULL;
if (Res == RET_OK )
{
if ( fg_pdlg.hDevMode != NULL )
fg_pdlg.hDevMode = GlobalReAlloc( fg_pdlg.hDevMode, Size, GMEM_ZEROINIT);
else
fg_pdlg.hDevMode = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, Size);
lpDevMode = GlobalLock( fg_pdlg.hDevMode );
if ( fg_pdlg.hDevMode == NULL || lpDevMode == NULL)
Res = RET_ERROR_MEMORY;
}
//--------------------------------------------------------------------------
// > Initialize if new
if ( Res == RET_OK && lpDevMode->dmSize == 0 ) {
// > Get default values
if ( IDOK != DocumentProperties(
NULL,
hPrinter,
pPrinter,
lpDevMode,
NULL,
DM_OUT_BUFFER ) )
Res = RET_ERROR_PRINTER_IO;
}
//--------------------------------------------------------------------------
// > Set values
if (Res == RET_OK && NULL != pDeviceDict)
Res = DeviceDictToDevmode( interp, pDeviceDict, lpDevMode,
fDictOnlySameDriverVersion );
//--------------------------------------------------------------------------
if (Res == RET_OK )
{
//----------------------------------------------------------------------
// > Modify present and eventually show property dialogue
fMode = DM_IN_BUFFER | DM_OUT_BUFFER;
if ( fShowPropertySheet )
fMode |= DM_IN_PROMPT;
Size = DocumentProperties(
NULL,
hPrinter,
pPrinter,
lpDevMode,
lpDevMode,
fMode );
if ( Size < 0 )
Res = RET_ERROR_PRINTER_IO;
}
//--------------------------------------------------------------------------
if ( fDevNamesLocked )
GlobalUnlock( fg_pdlg.hDevNames );
//--------------------------------------------------------------------------
if ( hPrinter != NULL )
ClosePrinter( hPrinter );
//--------------------------------------------------------------------------
if ( lpDevMode != NULL )
GlobalUnlock( fg_pdlg.hDevMode );
//--------------------------------------------------------------------------
if ( Res != RET_OK )
{
GlobalFree( fg_pdlg.hDevMode );
fg_pdlg.hDevMode = NULL;
}
//--------------------------------------------------------------------------
// > User may press the cancel button when interactive
if ( Res == RET_OK && fShowPropertySheet && Size == IDCANCEL )
return RET_ERROR_USER;
//--------------------------------------------------------------------------
return Res;
}
//------------------------------------------------------------------------------
// > PrintReset
//------------------------------------------------------------------------------
// Free any resource which might be opened by a print command.
// Initialise the fg_pdlg structure.
static char PrintReset( char fPreserveDeviceData )
{
int i;
//--------------------------------------------------------------------------
// >> Free members of the fg_pdlg structure
//--------------------------------------------------------------------------
if ( fg_f_pdlg_initialized )
{
if (fg_pdlg.hDC != NULL)
{
DeleteDC(fg_pdlg.hDC);
fg_pdlg.hDC = NULL;
}
if ( ! fPreserveDeviceData )
{
//------------------------------------------------------------------
// > Free any Device mode data
if ( fg_pdlg.hDevMode != NULL )
{
GlobalFree( fg_pdlg.hDevMode );
fg_pdlg.hDevMode = NULL;
}
//------------------------------------------------------------------
// > Free any Device Names data
if ( fg_pdlg.hDevNames != NULL )
{
GlobalFree( fg_pdlg.hDevNames );
fg_pdlg.hDevNames = NULL;
}
}
} else {
//----------------------------------------------------------------------
// > Initialise fg_pdlg structure
//----------------------------------------------------------------------
memset( &fg_pdlg, 0, sizeof( PRINTDLG ) );
fg_pdlg.lStructSize = sizeof( PRINTDLG );
fg_f_pdlg_initialized = TRUE;
}
return RET_OK;
}
//------------------------------------------------------------------------------
// >>>>> LoadDefaultPrinter
//------------------------------------------------------------------------------
// Load the default printer in the fg_pdlg structure.
static char LoadDefaultPrinter( )
{
PrintReset( 1 );
fg_pdlg.Flags = PD_RETURNDEFAULT ;
if ( PrintDlg( &fg_pdlg ) == FALSE)
return RET_ERROR_PRINTER_IO;
if ( fg_pdlg.hDevNames == NULL)
return RET_ERROR_PRINTER_IO;
return RET_OK;
}
//------------------------------------------------------------------------------
// >>>>> ListChoices
//------------------------------------------------------------------------------
static char ListChoices(Tcl_Interp *interp, const char *ppChoiceList[])
{
int Index;
Tcl_Obj *lResult;
//--------------------------------------------------------------------------
// > Initialise return list
lResult = Tcl_GetObjResult( interp );
//--------------------------------------------------------------------------
// Loop adding the printers to the list
for ( Index = 0; ppChoiceList[Index] != NULL; Index++)
{
Tcl_Obj *ChoiceText;
ChoiceText = Tcl_NewStringObj( ppChoiceList[Index], -1 );
if ( TCL_OK != Tcl_ListObjAppendElement( interp, lResult, ChoiceText))
{
// > Error already set in interp
return RET_ERROR;
}
}
return RET_OK;
}
//------------------------------------------------------------------------------
// >>>>> DeviceDictSpecGet
//------------------------------------------------------------------------------
static char DeviceDictSpecGet(Tcl_Interp *interp, char *KeyIn)
{
int IndexCur;
Tcl_Obj *lResult;
Tcl_Obj *pObj;
enum fg_device_dict_spec_type TypeCur;
int DivisionCur;
//--------------------------------------------------------------------------
// >> Search for the correct spec
for (IndexCur = 0; NULL != fg_device_index[IndexCur];IndexCur++) {
if ( 0 == strcmp(KeyIn,fg_device_index[IndexCur]) ) {
lResult = Tcl_GetObjResult( interp );
TypeCur = fg_device_dict_choices[IndexCur].Type;
pObj = Tcl_NewStringObj(fg_device_dict_spec_type_text[TypeCur],-1 );
if ( TCL_OK != Tcl_ListObjAppendElement( interp, lResult, pObj))
return RET_ERROR;
switch (TypeCur) {
case dds_list:
// list choice1 choice 2 ...
return ListChoices(interp,
fg_device_dict_choices[IndexCur].Choices);
case dds_listnum:
// listnum min max choice1 choice 2...
case dds_num:
// num min max
if ( TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewIntObj(
fg_device_dict_choices[IndexCur].Min))
|| TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewLongObj(
fg_dds_max_values[
fg_device_dict_choices[IndexCur].Division
])))
return RET_ERROR;
if (TypeCur == dds_listnum)
return ListChoices(interp,
fg_device_dict_choices[IndexCur].Choices);
break;
case dds_float:
// float min max digits
DivisionCur = fg_device_dict_choices[IndexCur].Division;
if ( TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewDoubleObj(
floor(0.5 + (double)
fg_device_dict_choices[IndexCur].Min
/ DivisionCur ) ) )
|| TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewDoubleObj(
floor(0.5 + 32767.0 / (double) DivisionCur )))
|| TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewIntObj( (int)log10(DivisionCur) ) ) )
return RET_ERROR;
break;
case dds_text:
// text "" min max
if ( TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewStringObj("",-1))
|| TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewIntObj(0))
|| TCL_OK != Tcl_ListObjAppendElement( interp, lResult,
Tcl_NewIntObj(
fg_device_dict_choices[IndexCur].Division ) ) )
return RET_ERROR;
break;
case dds_yn:
case dds_binary:
break;
}
return RET_OK;
}
}
return RET_ERROR_PARAMETER;
}