I have a service which prints. Up until now the service has been printing using the WPF System.Windows.Controls.PrintDialog.PrintDocument method however due to various issues (performance, windows update bugs, 32 bit service on 64bit system issues etc) I am converting to use the traditional System.Drawing.Printing.PrintDocument method.
As this is running as a service I want this to always print using the default printer preferences (which include things like media settings and print speed for industrial label printer such as the Intermec/Honewell PM43)
Previously I had done this using PrintDialog.PrintTicket = PrintQueue.DefaultPrintTicket.Clone
However I cannot find the equivalent method in System.Drawing.Printing.PrintDocument and the service is not picking up the default printer preferences as set in the printer properties (specifically Print Speed in this case)
So what is the equivalent of PrintDialog.PrintTicket = PrintQueue.DefaultPrintTicket.Clone in System.Drawing.Printing.PrintDocument?
The following question helped me find an answer
Can't change DEVMODE of a printer
//Get the registry key containing the printer settings
var regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Print\\Printers\\" + PrinterName);
if (regKey != null)
{
//Get the value of the default printer preferences
var defaultDevMode = (byte[])regKey.GetValue("Default DevMode");
//Create a handle and populate
var pDevMode = Marshal.AllocHGlobal(defaultDevMode.Length);
Marshal.Copy(defaultDevMode, 0, pDevMode, defaultDevMode.Length);
//Set the printer preferences
pd.PrinterSettings.SetHdevmode(pDevMode);
//Clean up
Marshal.FreeHGlobal(pDevMode);
}
Related
I am currently working with some OMR software that will take and scan sheets from a scanner, and then write their information to a text file. For getting available local scanners, I am using WIA; to get these scanners, I would use some bit of code like
public List<ScannerInfo> GetWiaDevices()
{
WIA.DeviceManager mgr = new WIA.DeviceManager();
List<ScannerInfo> retVal = new List<ScannerInfo>();
foreach (WIA.DeviceInfo info in mgr.DeviceInfos)
{
if (info.Type == WIA.WiaDeviceType.ScannerDeviceType)
{
foreach (WIA.Property p in info.Properties)
{
if (p.Name == "Name")
retVal.Add(new ScannerInfo(((WIA.IProperty)p).get_Value().ToString(), info.DeviceID));
}
}
}
return retVal;
}
Now, I am working with something that is technically a printer (and that Windows reads as a printer) -- the Konica Minolta Bizhub 282, I believe. Unfortunately, if (info.Type == WIA.WiaDeviceType.ScannerDeviceType) doesn't recognize printers with built in scanners as scanners, so when I run this code checking for local scanners, the printer doesn't show up.
Is there a way to make printers with built-in scanners show up on the list, and furthermore, to make them usable as scanners in C#? Thanks for your time!
It doesn't look like this printer has a scanner that will show up as a twain or WIA source.
There certainly are no drivers on the Minolta site for it (only PCLx and PostScript Print Drivers).
The way this scanner works is to use a SMB network share setup by your IT admin. The printer will dump scanned documents there after it is configured properly.
You can read about it here .
If I somehow missed something.. (I don't think I did), ALL of the manuals for that printer are here
I have created a watcher to connect to BarcodeScanner using Windows.Devices.PointOfService
var watcher = DeviceInformation.CreateWatcher(BarcodeScanner.GetDeviceSelector());
var id = "";
watcher.Added += async (sender, information) =>
{
id = information.Id;
var barcodeScanner = await BarcodeScanner.FromIdAsync(id);
...
}
information parameter contains all data releted to my barcodeScanner, but when i try to get it with FromIdAsync is always null.
Those are data contained into information
- information {Windows.Devices.Enumeration.DeviceInformation} Windows.Devices.Enumeration.DeviceInformation
EnclosureLocation null Windows.Devices.Enumeration.EnclosureLocation
Id "\\\\?\\HID#VID_0536&PID_02E1&MI_01#c&d907bf5&0&0000#{c243ffbd-3afc-45e9-b3d3-2ba18bc7ebc5}\\POSBarcodeScanner" string
IsDefault false bool
IsEnabled true bool
Kind DeviceInterface Windows.Devices.Enumeration.DeviceInformationKind
Name "3800G" string
+ Pairing {Windows.Devices.Enumeration.DeviceInformationPairing} Windows.Devices.Enumeration.DeviceInformationPairing
+ Properties {System.__ComObject} System.Collections.Generic.IReadOnlyDictionary<string, object> {System.__ComObject}
+ Native View 0x1d148140 <Information not available, no symbols loaded for Windows.Devices.Enumeration.dll> IUnknown *
This device is listed as enabled to be accessed with POS.
Where I'm wrong? I have tried also to create the watcher behind a button click, but nothigs change.
If the model name of the scanner you are using is "3800G" as in the question code, it may not be supported by Windows.Devices.PointOfService.
A list of supported models is below.
Supported Point of Service Peripherals
If you want to use it with Windows.Devices.PointOfService, please change it to the model described in this.
In Addition:
Unified POS standard and Windows® Embedded for Point of Service are OPOS/POS for.NET/JavaPOS API. It is not Windows.Devices.PointOfService API.
That model is not listed on Honeywell's site.
And, sales agencies in Japan may be displayed as sales ended. Probably it is an old model. It is better to switch to a new model.
For example, the USB HID Bar code scanner mode setting is described on page 21 of the detailed manual of 1900 series.
If this mode setting description is not in the 3800G manual, you can not use Windows.Devices.PointOfService API on 3800G.
If you can set it, you will be able to use it if you install a device driver corresponding to this mode.
#Luigi Saggese,
You must first put this scanner into USB HID Barcode Scanner Mode. Please see Page 1-3 of the Honeywell 3800g Users Guide for the programming code to put the scanner into this mode.
Once the scanner is in this mode, you should see a POS Barcode Scanner node in Windows Device Manager. The specific scanner will show up in Device Manager as POS HID Barcode Scanner since it is using an in-box class driver which supports the USB HID POS Scanner protocol. At this point it should work with your Watcher.
Terry Warwick, Microsoft
I have writen some simple C# Tool that Prints PDFs with the Help of SpirePDF
In the Tool i can select The Printer and its PaperTray
I have 2 Printers here and they are working fine with my code (The correct tray is used)
On an other machine with other Printers, it doesnt work, the correct Printer is choosen, but the PaperTray is alway the same (Manual Feed), no matter which Tray i choose.
printDocument.PrinterSettings.PrinterName = PrinterSettings.InstalledPrinters[MyPrinterConfiguration.GetPrinterIndex(#"invoice_print")];
printDocument.DefaultPageSettings.PaperSource = printDocument.PrinterSettings.PaperSources[MyPrinterConfiguration.GetPrinterTrayIndex(#"invoice_print")];
MyPrinterConfiguration is an Dictionary that hold the indexes of the Trays and Printer on the System.
Are there any other methods to set the PaperSource for this Document?
My Printers are from Samsung and Brother
the others from HP and Brother (both are not working) so it seem not to be a driver Problem.
I have found a solution:
Setting the PaperSource in self-created PrinterSettings seems not to work for some Printers, but when i make a Printdialog, let the User choose the Settings (PaperSource, PaperType and so on) and take theese settings (unchanged) to apply them on the PrintDocument, then it works for all my testet printers.
I think PrinterSettings from PrintDialog have other or more characteristics than i can set programaticly.
if (printDialog.ShowDialog() == DialogResult.OK) {
gpsMyPrintSettings.SetSettingsForType( "badge", (PrinterSettings) printDialog.PrinterSettings.Clone() );
}
printDocument.PrinterSettings = gpsMyPrintSettings.GetSettingsForDocumentType( "badge" );
printDocument.Print();
I have made a small c# winforms program which among other stuff, prints barcodes. On some client machines where it operates, some other software for printing barcodes overrides my settings for printing the barcode and it resizes just the barcode.
If I change the code just for that machine, it either repositions the image (makes it smaller as well), or stretches it so wide that it cuts off one third of it. Currently I am only using the printing settings to set the margins to 0 and set the paper mode to landscape in the print dialog, and the image size is fixed in the printing process(I used constants). Below is the code for when the user clicks the print button, and also two constants defined outside of it.
const int barcodeX = 570;
const int barcodeY = 135;
private void Print_Click(object sender, EventArgs e)
{
DocPrint.DocumentName = "Document";
elements = 0;
PrintDialog.Document = DocumentDrucker;
DocPrint.DefaultPageSettings.Landscape = true;
DocPrint.DefaultPageSettings.Margins.Top = 0;
DocPrint.DefaultPageSettings.Margins.Left = 0;
DocPrint.DefaultPageSettings.Margins.Right = 0;
DocPrint.DefaultPageSettings.Margins.Bottom = 0;
//DocumentDrucker.OriginAtMargins = false;
if (PrintDialog.ShowDialog() == DialogResult.OK)
DocPrint.Print();
}
Also the lines to encode and print the barcode in the printing process. The barcodePoint is where the barcode is positioned, on the paper.
b.Encode(TYPE.CODE128A, "SBD" + currentItem.Text.Substring(0, 3) + currentItem.Text.Substring(4), Color.Black, Color.Transparent, barcodeX, barcodeY);
graphic.DrawImage(b.EncodedImage, barcodePoint);
The program runs fine under any other circumstances, so I have identified the problem, I just do not know how to go around the other software's settings. I have already reinstalled the drivers for the printer (no success), as well logged in as a different user on the same computer, and that made my program work. So it has something to do with the software installed on it, I just don't know what.
At first I thought it was a problem with the drivers and the OS, but I tried it on other computers and it worked fine as well. The problem persists just on the computers with the software.
Is there any way to make my program force it's printing settings for the barcode image, since the software installed on the machines always uses it's own settings? Or to make sure that the settings in my code will not be changed?
Uninstalling the software is not an option, as it is used for other processes.
EDIT: I have run the program from both my user logon (no software) and the target machine user (both on the same machine). The settings were identical in both cases, the only thing different was that on the target machine, the software was installed. What are some ways to make sure that my settings are enforced, instead of an X program overwriting them?
I am working on some code that monitors the printer queue and then uses the event information to collect some specifics about the job, including # pages, orientation, whether or not it was color and how many copies were requested.
I catch the events using the code from Merrion Computing (which is now open source); which handles the interop.
In the case of Color, it is supposed to be stored in JOB_INFO_2.pDeviceMode.dmColor; however no matter how I submit the job (color or black and white using the printer properties printing from several apps, including word and adobe) it always indicates color. I debugged through that code directly, and the interop appears to be correct, so then I used the JobId from the event to query the print system via .NET with the code (below); and it contains exactly the same settings for copies and color.
int iJobId = e.PrintJob.JobId;
LocalPrintServer printServer = new LocalPrintServer();
PrintQueueCollection queueCollection = printServer.GetPrintQueues();
foreach (PrintQueue queue in queueCollection)
{
queue.Refresh();
if(queue.FullName.Equals(e.PrintJob.PrinterName,StringComparison.OrdinalIgnoreCase))
{
int? iPageCount;
PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
foreach(PrintSystemJobInfo job in jobs)
{
job.Refresh();
if(job.JobIdentifier==iJobId)
{
iPageCount = job.NumberOfPages;
}
}
//-- Found the Printer...
int? iCopyCount=queue.CurrentJobSettings.CurrentPrintTicket.CopyCount;
PageOrientation? eOrientation = queue.CurrentJobSettings.CurrentPrintTicket.PageOrientation;
OutputColor? eColor = queue.CurrentJobSettings.CurrentPrintTicket.OutputColor;
Debug.WriteLine("queue=" + queue.FullName + ", Copies=" + iCopyCount.Value + ",Color=" + eColor.ToString() + ", pagecount=" + "unk" /*iPageCount.Value*/ + ", Orientation=", eOrientation.ToString());
Debug.WriteLine("---");
}
}
Has anyone seen a reliable way to retrieve the number of copies and page count (preferably using .NET) for a specific printer job?
I
I did find this post describing the same type of problem, but there wasn't a resolution there.
Determine current print job color using C#
It should also be noted that the WMI Code from the above article also returns color.
I went in an enabled the eventlog for printing (http://www.papercut.com/kb/Main/LogPrintJobsInEventViewer). Looking at the details of the print event; the color setting is as expected "2", which indicates grayscale.
It is pretty clear that the windows subsystem is receiving the requested setting; however I have been unsuccessful to retrieve the value using WMI, System.Printing's namespace, or the interop from Merrion's print monitoring library where the values all indicate that the job is color with the correct number of pages and copies.
Is it possible to grab the spool file generated for this print to check that it is setting the dmColor setting itself?
The setting you are getting from the event log, 2, corresponds to DMCOLOR_COLOR not DMCOLOR_MONOCHROME so it seems the colour setting in the log thinks it is colour too.
It may be that the printer driver is being a bit sneaky in submitting the job as colour when it creates it but then sending a "set device settings" message in the spool that changes it to monochrome? If so there should be an SPT_DEVMODE record in the spool file.
Check this article for a spool file reader: http://www.codeproject.com/Articles/10586/EMF-Printer-Spool-File-Viewer
You need to refresh your jog until the flag IsSpooling becomes false.
for (int i = 0; i < jobs.Count(); i++)
{
try
{
int timeOut = 20000;
var jobInfo = jobs.ElementAt(i);
while (jobInfo.IsSpooling && timeOut > 0)
{
Thread.Sleep(100);
timeOut-=100;
jobInfo.Refresh();
} var pages = Math.Max(jobInfo.NumberOfPages,jobInfo.NumberOfPagesPrinted);
}
}