![]() |
![]() |
|
![]() |
Win32 API and Printers Changing Printer Attributes © 2002 Rick Kelly www.crooit.com Preface Libraries and forms (Paradox 9) presented are available as a download here. Paradox 8 is not supported although Paradox 7-32 surprisingly works. After downloading into the folder of your choice, make that folder :WORK: and run the included form for a demonstration. You'll need to run the form before opening it in design mode as it references table :PRIV:__PJobs that is created in the form's INIT event. (If running Paradox 10, or if the table doesn't get created properly, you should first run the BldSpool.ssl script prior to running the form.) Introduction Previous articles in this series:
As printers have differing capabilities, each driver communicates which portion of the Windows common feature set it supports through the use of bit level flags. These bit level flags and printer settings are stored in a structure called the DEVMODE. Each printer driver typically references a large amount of device-independent and device-dependent information in DEVMODE that we don’t know or care about. When we make modifications to fields in the device-independent part of DEVMODE, it may also effect changes in the device-dependent portion and we will need to take additional steps to ensure we have a consistent DEVMODE structure before the printer update. In the first article of this series, we covered retrieval of printer attributes which were returned in a Paradox Record Type structure of custom type W32PrinterInfo. We are adding an additional field of LongInt Type called FieldsCanChange to W32PrinterInfo which contains bit level flags for which DEVMODE fields the print driver supports changes. These bit level flags are mapped into the following custom Paradox Record Type by the W32CanSetPrinterFields method: Type ; ; Printer attributes that can be changed - driver specific ; W32SetPrinterFields = record Orientation Logical PaperSize Logical PaperLength Logical PaperWidth Logical Scale Logical Copies Logical DefaultPaperSource Logical PrintQuality Logical Color Logical Duplex Logical YResolution Logical TTOption Logical Collate Logical FormName Logical endRecord endType Const ; ; Printer attributes that can be changed ; cnOrientation = 1 cnPaperSize = 2 cnPaperLength = 4 cnPaperWidth = 8 cnScale = 16 cnCopies = 256 cnDefaultPaperSource = 512 cnPrintQuality = 1024 cnColor = 2048 cnDuplex = 4096 cnYResolution = 8192 cnTTOption = 16384 cnCollate = 32768 cnFormName = 65536 endConst method W32CanSetPrinterFields(liFields LongInt) W32SetPrinterFields var spf W32SetPrinterFields endVar ; ; Return Available Fields for printer ; switch case liFields.bitAnd(cnOrientation) = cnOrientation : spf.Orientation = True otherwise : spf.Orientation = False endSwitch switch case liFields.bitAnd(cnPaperSize) = cnPaperSize : spf.PaperSize = True otherwise : spf.PaperSize = False endSwitch switch case liFields.bitAnd(cnPaperLength) = cnPaperLength : spf.PaperLength = True otherwise : spf.PaperLength = False endSwitch switch case liFields.bitAnd(cnPaperWidth) = cnPaperWidth : spf.PaperWidth = True otherwise : spf.PaperWidth = False endSwitch switch case liFields.bitAnd(cnScale) = cnScale : spf.Scale = True otherwise : spf.Scale = False endSwitch switch case liFields.bitAnd(cnCopies) = cnCopies : spf.Copies = True otherwise : spf.Copies = False endSwitch switch case liFields.bitAnd(cnOrientation) = cnOrientation : spf.Orientation = True otherwise : spf.Orientation = False endSwitch switch case liFields.bitAnd(cnDefaultPaperSource) = cnDefaultPaperSource : spf.DefaultPaperSource = True otherwise : spf.DefaultPaperSource = False endSwitch switch case liFields.bitAnd(cnPrintQuality) = cnPrintQuality : spf.PrintQuality = True otherwise : spf.PrintQuality = False endSwitch switch case liFields.bitAnd(cnColor) = cnColor : spf.Color = True otherwise : spf.Color = False endSwitch switch case liFields.bitAnd(cnDuplex) = cnDuplex : spf.Duplex = True otherwise : spf.Duplex = False endSwitch switch case liFields.bitAnd(cnYResolution) = cnYResolution : spf.YResolution = True otherwise : spf.YResolution = False endSwitch switch case liFields.bitAnd(cnTTOption) = cnTTOption : spf.TTOption = True otherwise : spf.TTOption = False endSwitch switch case liFields.bitAnd(cnCollate) = cnCollate : spf.Collate = True otherwise : spf.Collate = False endSwitch switch case liFields.bitAnd(cnFormName) = cnFormName : spf.FormName = True otherwise : spf.FormName = False endSwitch return spf endMethod Referenced Win32 APIs Other referenced Win32 API's have been covered in earlier articles. Newly introduced methods are: DocumentProperties( hWnd cLong, hPrn cLong, pDeviceName cPtr, pDevModeOutput cLong, pDevModeInput cLong, fMode cLong) cLong [stdcall "DocumentPropertiesA"]hWnd - Window Handle - always 0 for our use hPrn - Handle to the printer pDeviceName - Printer Name pDevModeOutput - Pointer to update/merged/retrieved DEVMODE pDevModeInput - Pointer to input DEVMODE fMode - Flags indicating operation to perform Updating Printer We use the following Paradox DynArray of AnyType to hold what fields to change and their respective new values. Type W32SetPrinter = DynArray[] AnyType ; ; Index Name Type ; --------------------------- ; ; Comment String ; Location String ; SeparatorPage String ; Orientation SmallInt ; PaperSize SmallInt ; PaperLength SmallInt ; PaperWidth SmallInt ; Scale SmallInt ; Copies SmallInt ; DefaultPaperSource SmallInt ; PrintQuality SmallInt ; Color SmallInt ; Duplex SmallInt ; YResolution SmallInt ; TTOption SmallInt ; Collate SmallInt ; FormName String ; DefaultPriority SmallInt ; Priority SmallInt ; StartTime LongInt ; UntilTime LongInt ; endTypeRefer to the first article of this series for an explanation of each field and valid values. Constants we will be referring to: Const ; ; Administrative Access ; cnPrinterAccessAdminister = 4 cnPrinterAccessUse = 8 cnPrinterStandardRights = 983040 ;0x000F0000 ; ; Printer attributes that can be changed ; cnOrientation = 1 cnPaperSize = 2 cnPaperLength = 4 cnPaperWidth = 8 cnScale = 16 cnCopies = 256 cnDefaultPaperSource = 512 cnPrintQuality = 1024 cnColor = 2048 cnDuplex = 4096 cnYResolution = 8192 cnTTOption = 16384 cnCollate = 32768 cnFormName = 65536 ; ; DocumentProperties Options ; cnDMOutBuffer = 2 cnDMInBuffer = 8 endConstCommon procedures referenced are: Proc cmGetPrinterInfo(var stPrinter String, var liPrinterHandle LongInt, var liMemoryStructure LongInt) Logical var liReturn LongInt liSizeNeeded LongInt liSizeUsed LongInt liDevMode LongInt loReturn Logical endVar ; ; Get admin access handle to the printer ; liPrinterHandle = 0 liMemoryStructure = 0 liDevMode = 0 loReturn = False switch case cmOpenPrinterAdmin(stPrinter,liPrinterHandle) = False : otherwise : ; ; First call is to get buffer size needed ; liSizeNeeded = 0 liSizeUsed = 0 liReturn = GetPrinter( liPrinterHandle, 2, 0, 0, liSizeNeeded) ; ; Allocate memory for Printer Info Structure Level 2 ; liMemoryStructure = GlobalAlloc(fromHex("0x40"),liSizeNeeded) ; ; Get Printer Info Structure ; liReturn = GetPrinter( liPrinterHandle, 2, liMemoryStructure, liSizeNeeded, liSizeUsed) ; ; Check if GetPrinter returned a DEVMODE structure pointer ; switch case liReturn = 1 : MoveFromMemory(liDevMode,liMemoryStructure + 28,4) switch ; ; DEVMODE structure missing - attempt to ; get one ; case liDevMode = 0 : loReturn = cmGetDeviceMode( stPrinter, liPrinterHandle, liDevMode) otherwise : loReturn = True endSwitch endSwitch switch case loReturn = False : liReturn = GlobalFree(liMemoryStructure) liMemoryStructure = 0 liReturn = ClosePrinter(liPrinterHandle) liPrinterHandle = 0 switch case liDevMode <> 0 : liReturn = GlobalFree(liDevMode) endSwitch endSwitch endSwitch return loReturn endProc Proc cmGetDeviceMode(var stPrinter String, var liPrinterHandle LongInt, var liDevMode LongInt) Logical var liSizeNeeded LongInt liReturn LongInt loReturn Logical endVar liDevMode = 0 loReturn = False liSizeNeeded = DocumentProperties( 0, liPrinterHandle, stPrinter, 0, 0, 0) switch case liSizeNeeded > 0 : ; ; Allocate memory for DEVMODE structure ; liDevMode = GlobalAlloc(fromHex("0x40"),liSizeNeeded) ; ; Retrieve DEVMODE structure from driver ; liReturn = DocumentProperties( 0, liPrinterHandle, stPrinter, liDevMode, 0, cnDMOutBuffer) loReturn = (liReturn = 1) endSwitch return loReturn endProc Proc cmOpenPrinterAdmin(var stPrinter String, var liPrinterHandle LongInt) Logical ; ; Open printer for administrative access ; var liReturn LongInt liAny LongInt liDefaultStructure LongInt endVar ; ; Build a printer defaults structure ; ; liDataType LongInt (address pointer) ; liDeviceMode LongInt (address pointer) ; liDesiredAccess LongInt ; liDefaultStructure = GlobalAlloc(fromHex("0x40"),12) liAny = 0 MoveToMemory(liDefaultStructure,liAny,4) MoveToMemory(liDefaultStructure + 4,liAny,4) liAny = cnPrinterAccessAdminister + cnPrinterAccessUse + cnPrinterStandardRights MoveToMemory(liDefaultStructure + 8,liAny,4) ; ; Get a handle to the printer ; liPrinterHandle = 0 liReturn = OpenPrinter(stPrinter,liPrinterHandle,liDefaultStructure) GlobalFree(liDefaultStructure) return liPrinterHandle <> 0 endProc Proc cmCopyStringToMemory(stAny String) LongInt var liPointer LongInt liSize LongInt endVar ; ; If string is not blank, allocate memory and copy it ; liPointer = 0 switch case stAny.size() > 0 : liSize = stAny.size() + 1 liPointer = GlobalAlloc(fromHex("0x40"),liSize) MoveToMemory(liPointer,stAny,liSize) endSwitch return liPointer endProcOur basic outline to updating printer attributes is:
method SetPrinterInfo(stPrinter String, var dyPrinterAttributes W32SetPrinter) Logical var loReturn Logical liPrinterHandle LongInt liReturn LongInt liMemoryStructure LongInt liDevMode LongInt liAny LongInt liFields LongInt arMemory Array[] LongInt siAny SmallInt stAny String liSupportedFields LongInt endVar liFields = 0 loReturn = False arMemory.empty() ; ; Open printer ; switch case cmGetPrinterInfo( stPrinter, liPrinterHandle, liMemoryStructure) = False : otherwise : ; ; Update Printer Info Structure Level 2 and/or associated DEVMODE ; liAny = 0 liSupportedFields = 0 ; ; Do not attempt to set security descriptor ; MoveToMemory(liMemoryStructure + 48,liAny,4) ; ; Get pointer to DevMode structure ; MoveFromMemory(liDevMode,liMemoryStructure + 28,4) ; ; Get flags for driver field change support ; MoveFromMemory(liSupportedFields,liDevMode + 40,4) ; ; Update Comment ; switch case dyPrinterAttributes.contains("Comment") = False : otherwise : liAny = cmCopyStringToMemory( dyPrinterAttributes["Comment"]) MoveToMemory(liMemoryStructure + 20,liAny,4) arMemory.grow(1) arMemory[arMemory.size()] = liAny endSwitch ; ; Update Location ; switch case dyPrinterAttributes.contains("Location") = False : otherwise : liAny = cmCopyStringToMemory( dyPrinterAttributes["Location"]) MoveToMemory(liMemoryStructure + 24,liAny,4) arMemory.grow(1) arMemory[arMemory.size()] = liAny endSwitch ; ; Update Separator Page ; switch case dyPrinterAttributes.contains("SeparatorPage") = False : otherwise : liAny = cmCopyStringToMemory( dyPrinterAttributes["SeparatorPage"]) MoveToMemory(liMemoryStructure + 32,liAny,4) arMemory.grow(1) arMemory[arMemory.size()] = liAny endSwitch ; ; Update Default Priority ; switch case dyPrinterAttributes.contains("DefaultPriority") = False : otherwise : try liAny = dyPrinterAttributes["DefaultPriority"] MoveToMemory(liMemoryStructure + 60,liAny,4) onFail errorClear() msgStop(stPrinter,"Invalid Default Priority=" + strval(dyPrinterAttributes["DefaultPriority"])) endTry endSwitch ; ; Update Priority ; switch case dyPrinterAttributes.contains("Priority") = False : otherwise : try liAny = dyPrinterAttributes["Priority"] MoveToMemory(liMemoryStructure + 56,liAny,4) onFail errorClear() msgStop(stPrinter,"Invalid Priority=" + strval(dyPrinterAttributes["Priority"])) endTry endSwitch ; ; Update Start Time ; switch case dyPrinterAttributes.contains("StartTime") = False : otherwise : try liAny = dyPrinterAttributes["StartTime"] MoveToMemory(liMemoryStructure + 64,liAny,4) onFail errorClear() msgStop(stPrinter,"Invalid Start Time=" + strval(dyPrinterAttributes["StartTime"])) endTry endSwitch ; ; Update Until Time ; switch case dyPrinterAttributes.contains("UntilTime") = False : otherwise : try liAny = dyPrinterAttributes["UntilTime"] MoveToMemory(liMemoryStructure + 68,liAny,4) onFail errorClear() msgStop(stPrinter,"Invalid Until Time=" + strval(dyPrinterAttributes["UntilTime"])) endTry endSwitch ; ; Update orientation ; switch case dyPrinterAttributes.contains("Orientation") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnOrientation) = cnOrientation : try siAny = dyPrinterAttributes["Orientation"] liFields = liFields + cnOrientation MoveToMemory(liDevMode + 44,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Orientation=" + strval(dyPrinterAttributes["Orientation"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Orientation changes") endSwitch ; ; Update Paper Size ; switch case dyPrinterAttributes.contains("PaperSize") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnPaperSize) = cnPaperSize : try siAny = dyPrinterAttributes["PaperSize"] liFields = liFields + cnPaperSize MoveToMemory(liDevMode + 46,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Paper Size=" + strval(dyPrinterAttributes["PaperSize"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Paper Size changes") endSwitch ; ; Update Paper Length ; switch case dyPrinterAttributes.contains("PaperLength") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnPaperLength) = cnPaperLength : try siAny = dyPrinterAttributes["PaperLength"] liFields = liFields + cnPaperLength MoveToMemory(liDevMode + 48,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Paper Length=" + strval(dyPrinterAttributes["PaperLength"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Paper Length changes") endSwitch ; ; Update Paper Width ; switch case dyPrinterAttributes.contains("PaperWidth") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnPaperWidth) = cnPaperWidth : try siAny = dyPrinterAttributes["PaperWidth"] liFields = liFields + cnPaperWidth MoveToMemory(liDevMode + 50,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Paper Width=" + strval(dyPrinterAttributes["PaperWidth"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Paper Width changes") endSwitch ; ; Update Scale ; switch case dyPrinterAttributes.contains("Scale") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnScale) = cnScale : try siAny = dyPrinterAttributes["Scale"] liFields = liFields + cnScale MoveToMemory(liDevMode + 52,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Scale=" + strval(dyPrinterAttributes["Scale"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Scale changes") endSwitch ; ; Update copies ; switch case dyPrinterAttributes.contains("Copies") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnCopies) = cnCopies : try siAny = dyPrinterAttributes["Copies"] liFields = liFields + cnCopies MoveToMemory(liDevMode + 54,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Copies=" + strval(dyPrinterAttributes["Copies"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Copies changes") endSwitch ; ; Update Default Paper Source ; switch case dyPrinterAttributes.contains("DefaultPaperSource") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnDefaultPaperSource) = cnDefaultPaperSource : try siAny = dyPrinterAttributes["DefaultPaperSource"] liFields = liFields + cnDefaultPaperSource MoveToMemory(liDevMode + 56,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Default Paper Source=" + strval(dyPrinterAttributes["DefaultPaperSource"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Default Paper Source changes") endSwitch ; ; Update Print Quality ; switch case dyPrinterAttributes.contains("PrintQuality") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnPrintQuality) = cnPrintQuality : try siAny = dyPrinterAttributes["PrintQuality"] liFields = liFields + cnPrintQuality MoveToMemory(liDevMode + 58,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Print Quality=" + strval(dyPrinterAttributes["PrintQuality"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Print Quality changes") endSwitch ; ; Update Color ; switch case dyPrinterAttributes.contains("Color") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnColor) = cnColor : try siAny = dyPrinterAttributes["Color"] liFields = liFields + cnColor MoveToMemory(liDevMode + 60,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Color=" + strval(dyPrinterAttributes["Color"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Color changes") endSwitch ; ; Update Duplex ; switch case dyPrinterAttributes.contains("Duplex") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnDuplex) = cnDuplex : try siAny = dyPrinterAttributes["Duplex"] liFields = liFields + cnDuplex MoveToMemory(liDevMode + 62,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Duplex=" + strval(dyPrinterAttributes["Duplex"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Duplex changes") endSwitch ; ; Update YResolution ; switch case dyPrinterAttributes.contains("YResolution") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnYResolution) = cnYResolution : try siAny = dyPrinterAttributes["YResolution"] liFields = liFields + cnYResolution MoveToMemory(liDevMode + 64,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid YResolution=" + strval(dyPrinterAttributes["YResolution"])) endTry otherwise : msgStop(stPrinter,"Driver does not support YResolution changes") endSwitch ; ; Update TTOption ; switch case dyPrinterAttributes.contains("TTOption") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnTTOption) = cnTTOption : try siAny = dyPrinterAttributes["TTOption"] liFields = liFields + cnTTOption MoveToMemory(liDevMode + 66,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid TTOption=" + strval(dyPrinterAttributes["TTOption"])) endTry otherwise : msgStop(stPrinter,"Driver does not support TTOption changes") endSwitch ; ; Update Collate ; switch case dyPrinterAttributes.contains("Collate") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnCollate) = cnCollate : try siAny = dyPrinterAttributes["Collate"] liFields = liFields + cnCollate MoveToMemory(liDevMode + 68,siAny,2) onFail errorClear() msgStop(stPrinter,"Invalid Collate=" + strval(dyPrinterAttributes["Collate"])) endTry otherwise : msgStop(stPrinter,"Driver does not support Collate changes") endSwitch ; ; Update Form Name ; switch case dyPrinterAttributes.contains("FormName") = False : ; ; Does driver support this change? ; case liSupportedFields.bitAnd(cnFormName) = cnFormName : ; ; Form Name size limit is 32 bytes ; switch case dyPrinterAttributes["FormName"].size() > 31 : stAny = dyPrinterAttributes["FormName"].substr(1,31) otherwise : stAny = dyPrinterAttributes["FormName"] endSwitch liAny = stAny.size() + 1 MoveToMemory(liDevMode + 70,stAny,liAny) liFields = liFields + cnFormName otherwise : msgStop(stPrinter,"Driver does not support Form Name changes") endSwitch ; ; Ensure that driver dependent portion of DEVMODE is updated ; liReturn = DocumentProperties( 0, liPrinterHandle, stPrinter, liDevMode, liDevMode, cnDMInBuffer + cnDMOutBuffer) switch case liReturn = 1 : ; ; Update printer attributes - if liReturn <> 1 ; the driver doesn't support or is unable to ; make the changes ; liReturn = SetPrinter( liPrinterHandle, 2, liMemoryStructure, 0) switch case liReturn = 1 : ; ; Send out alert to all running applications ; that a system value has been updated ; liReturn = SendDevModeMessage( cnBroadcast, cnSettingChange, 0, stPrinter, cnTimeOutNormal, 1000, 0) loReturn = True endSwitch endSwitch ; ; Release Memory ; liReturn = GlobalFree(liMemoryStructure) liReturn = GlobalFree(liDevMode) ; ; Release printer handle ; liReturn = ClosePrinter(liPrinterHandle) endSwitch ; ; Release any miscellaneous memory ; switch case arMemory.size() > 0 : for siAny from 1 to arMemory.size() liAny = arMemory[siAny] liReturn = GlobalFree(liAny) endFor endSwitch return loReturn endMethod Conclusion We now have methods that support updating Windows printer attributes. (Hint: Look at the underlying OPAL in the provided libraries and the form and see what else you can discover and learn about<g>) Next: I tink T-T-T-T-T-T-T-T-That's all folks! Discussion of this article |
![]() Feedback | Paradox Day | Who Uses Paradox | I Use Paradox | Downloads ![]() |
|
![]() The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation. Paradox is a registered trademark of Corel Corporation. ![]() |
|
![]() Modified: 15 May 2003 Terms of Use / Legal Disclaimer ![]() |
![]() Copyright © 2001- 2003 Paradox Community. All rights reserved. Company and product names are trademarks or registered trademarks of their respective companies. Authors hold the copyrights to their own works. Please contact the author of any article for details. ![]() |
![]() |
|