I have multiple printers which contain a "Rotate 180 degree" checkbox like below:
Here's another one ("Nee" means "no"):
Is there a way to programmatically set this value, and change PrintTicket
? If not, how can I get the current value of it? For my software I need to know if this is set or not and if it's set it needs to be changed, if possible. For my software it would be the best if I don't have to open the printdialog, it's a piece of software where users can print directly without clicking any buttons, so setting or getting it programmatically is what I'm looking for.
I've been searching around using ManagementObjectSearcher
and in the normal PrintDocument.DefaultPageSettings
property but couldn't find anything!
If this option isn't set, I automatically want to set it temporarily for the users (otherwise it prints upside down with my particular printers). I've been messing around trying to set it for the users but I can't figure out how to get it to work. I've been looking at the DEVMODE
struct and tried to implement it but it also doesn't have a "rotate 180 degrees option" or anything similar.
NOTE: I'M NOT TRYING TO SET LANDSCAPE MODE. That's pretty easy and something different.
I tried doing the following:
pdialog.PrintQueue.CurrentJobSettings.CurrentPrintTicket.PageOrientation = PageOrientation.ReversePortrait;
However, this only inverts the page orientation and not the content (the content needs to be rotated as well).
If I rotate the visual that I'm printing, the margins aren't right anymore so that doesn't work either! Hope someone can help.
Thanks in advance.
EDIT
I used Hans' method to figure out which value to change. Note that his method would apply for any type of printer! The devmode
changes the value of the PrintDialog
. This took me hours and hours to solve so for whoever I can help, here's my code and I'm glad to share or help! First I was trying to change DefaultPrintTicket
from a new PrintServer()
which didn't work, but UserPrintTicket
seemed to be the right one where you can actually see the value change in WindowsControl Panel if you don't switch back to the original one. *However*, this only seemed to work on just my pc (which was necessary), on a virtual machine for example the
magic` value was already different. This was rather practice than real-life usage.
var pdialog = new PrintDialog();
pdialog.PrintQueue = new PrintQueue(new LocalPrintServer(), _printername, PrintSystemDesiredAccess.AdministratePrinter); // this will be your printer. any of these: new PrintServer().GetPrintQueues()
pdialog.PrintTicket.PageMediaSize = size;
pdialog.PrintTicket.CopyCount = _amount;
if (CheckPrinterDriverName(_printername))
{
int magic = 361;
var defaulttckt = pdialog.PrintQueue.UserPrintTicket;
pdialog.PrintQueue.UserPrintTicket = PrinterModifier.ChangeDevMode(pdialog, magic, vis);
pdialog.PrintQueue.Commit();
pdialog.PrintVisual(vis, "Label");
//Set back old settings so it's not permanently changed
pdialog.PrintQueue.UserPrintTicket = defaulttckt;
pdialog.PrintQueue.Commit();
}
...
class PrinterModifier
{
public static PrintTicket ChangeDevMode(PrintDialog pdialog, int prpty, DrawingVisual vis)
{
var queue = pdialog.PrintQueue;
var cvt = new PrintTicketConverter(queue.Name, PrintTicketConverter.MaxPrintSchemaVersion);
// Display dialog, don't make changes
var devmode1 = cvt.ConvertPrintTicketToDevMode(pdialog.PrintTicket, BaseDevModeType.UserDefault);
// Consistency check
var dmSize = BitConverter.ToInt16(devmode1, 68);
var dmDriverExtra = BitConverter.ToInt16(devmode1, 70);
if (devmode1[361] == 0)
{
devmode1[361] = 1;
}
return cvt.ConvertDevModeToPrintTicket(devmode1, PrintTicketScope.PageScope);
}
}
The value in the printdialog changes, but it still prints wrong. The changes don't apply. Any help is welcome!
(Start button) => Control Panel => Hardware and Sound => Devices and Printers. Right-click your Brother machine icon and select Printer properties. NOTE: If you see the Change Properties button at the bottom left of the dialog box, click the Change Properties button before changing the settings.
It probably helps to realize how unusual this property is. Funny true story as introduction about Pete Conrad, an astronaut recruited by NASA for the Gemini space program. Having no real idea how long term space flight affects humans, the doctors exposed them to basically anything they could think of. Often very intrusive and uncomfortable tests. Conrad rebelled and failed one psychological test. The doc handed him a blank card and asked "What do you see?" He instantly shoved it back and remarked "It is upside down".
This printer is unusual, always something to worry about. Perhaps designed to operate on a production line that includes some kind of automated paper binding operation. Printer drivers can arbitrarily add properties to customize their behavior, this is one such property. The property sheet you are looking at is equally non-standard, it comes from the printer driver.
To understand how you can change this setting, you first need to understand the DEVMODE structure. About the ugliest structure used in the winapi. It is a variable size struct, the declaration you see in the MSDN page only covers the standard properties. A printer driver can arbitrarily extend it, the dmDriverExtra
field keeps track of how many extra bytes were added. The dmSize
field reports the size of the non-variable part of the struct, it is 220 on Windows version 6 (Vista and up). Something you need to check.
Winforms exposes the DEVMODE directly with the PrinterSettings.GetHdevmode() method. WPF abstracts it away through the PrintTicket class. You have to use the PrintTicketConverter class to convert from a PrintTicket to a DEVMODE and back.
What you need to reverse-engineer is the exact field in the private driver data that stores this setting. Only the printer manufacturer knows this detail, they are not going to answer your phone call. Some sample code to help you discover and verify that field, just try it out in a do-nothing WPF app in the MainWindow constructor:
using System.Printing; // Add reference to System.Printing
using System.Printing.Interop; // Add reference to ReachFramework
using System.Diagnostics;
....
public MainWindow() {
InitializeComponent();
// Assume default printer
var queue = new LocalPrintServer().DefaultPrintQueue;
var cvt = new PrintTicketConverter(queue.Name, PrintTicketConverter.MaxPrintSchemaVersion);
// Display dialog, don't make changes
var dlg = new PrintDialog();
dlg.ShowDialog();
var devmode1 = cvt.ConvertPrintTicketToDevMode(dlg.PrintTicket, BaseDevModeType.UserDefault);
// Consistency check
var dmSize = BitConverter.ToInt16(devmode1, 68);
var dmDriverExtra = BitConverter.ToInt16(devmode1, 70);
Debug.Assert(dmSize == 220);
Debug.Assert(dmDriverExtra > 0);
Debug.Assert(dmSize + dmDriverExtra == devmode1.Length);
// Display dialog again, do make the change
dlg.ShowDialog();
var devmode2 = cvt.ConvertPrintTicketToDevMode(dlg.PrintTicket, BaseDevModeType.UserDefault);
var len = Math.Min(devmode1.Length, devmode2.Length);
for (int ix = 0; ix < len; ++ix) {
if (devmode1[ix] != devmode2[ix]) {
Debug.Print("Change at {0} from {1} to {2}", ix, devmode1[ix], devmode2[ix]);
}
}
// Tinker with the DEVMODE...
var magic = dmSize + 0; // Change this
Debug.Assert(magic < dmSize + dmDriverExtra);
devmode1[magic] = devmode2[magic];
dlg.PrintTicket = cvt.ConvertDevModeToPrintTicket(devmode1);
// Verify that the setting changed!
dlg.ShowDialog();
}
}
Beware that you might see many bytes change. Most likely guess is that you'd be looking for one that changes from 0 to 1. The Debug > Windows > Memory > Memory1 window can be useful to filter out noise produced by strings, put "devmode2" in the Address field.
The expected outcome is that you now know how to customize the PrintTicket. Beware that it is highly specific to that printer and can change with a driver update. So you may well consider to do this the most logical way, rotating the visual to be printed with the LayoutTransform property.
try This. "LandscapeAngle" will return the orientation set in the print dialog control.
PrintDialog.PrinterSettings.LandscapeAngle
Ref: https://msdn.microsoft.com/en-us/library/system.drawing.printing.printersettings(v=vs.110).aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With