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; }