c# : How to Monitor Print job Using winspool_drv - c#

Recently I am making a system monitoring tool. For that I need a class to monitor print job.
Such as when a print started, is it successful or not, how many pages.
I know that I can do it using winspool.drv. But dont how. I've searched extensively but having no luck. Any code/suggestion could be very helpful.
Thanks.

Well I don't know about the winspool.drv, but you can use the WMI to get the status of the printer. Here is an example of the using Win32_Printer.
PrintDialog pd = new PrintDialog();
pd.ShowDialog();
PrintDoc.PrinterSettings = pd.PrinterSettings;
PrintDoc.PrintPage += new PrintPageEventHandler(PrintDoc_PrintPage);
PrintDoc.Print();
object status = Convert.ToUInt32(9999);
while ((uint)status != 0) // 0 being idle
{
ManagementObjectSearcher mos = new ManagementObjectSearcher("select * from Win32_Printer where Name='" + pd.PrinterSettings.PrinterName + "'");
foreach (ManagementObject service in mos.Get())
{
status = service.Properties["PrinterState"].Value;
Thread.Sleep(50);
}
}
If you don't use the PrintDialog object (to choose a printer) you can run the WMI query and it will return all the printers in the system.

Related

c# Print PDF with Adobe Reader and close

I didnt found a good (free) and simple Solution for printing PDFs (for e.g. from a "Hot"-Folder (FileSystemWatcher) on a Server) with Acrobat and close Acrobat Reader. So i wrote my own and i hope it will help someone.
(Yes, u can use a old free Foxit Reader Version, but we had too much trouble with it, sometimes stuck in Memory without printing)
The Point was, after printing, the file must be moved to a archive dir, but Adobe did not close. So i never knowed when its done, or wait 30+ Seconds and kill (not so fine if the Server needs longer and takes to much time).
Here my Solution, i run the Process and wait until one of the subprocesses of my Adobe Process shows the recent open Window.
Thanks to mtijn for his "Process Searcher" solution https://stackoverflow.com/a/7189381/480982
var prz = Process.Start("C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe", "/h /t \"" + YOURPDFFILE + "\" \"" + YOURPRINTER + "\"");
bool loop = true;
while (loop)
{
//u can use Thread.Sleep(x) too;
prz.WaitForExit(500);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ParentProcessId=" + prz.Id);
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
foreach (var item in collection)
{
UInt32 childProcessId = (UInt32)item["ProcessId"];
if ((int)childProcessId != Process.GetCurrentProcess().Id)
{
Process childProcess = Process.GetProcessById((int)childProcessId);
//If a File is open the Title begins with "Filename - Adobe ...", but after print/closing the recent window starts with "Adobe Acr..."
if(childProcess.MainWindowTitle.StartsWith("Adobe Acrobat"))
{
loop = false;
break;
}
}
}
}
}
//"Recent" Window found, lets kill the Process
prz.Kill();
// Now here u can move or Delete the pdf file

Unable to get system hard drive SerialNumber using Win32_DiskDrive

I'm using the following code to get my drive serial number. It's working fine with Windows 7, 8, 8.1, and 10 Professional, but I'm getting an error on Windows 10 Home.
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
foreach (ManagementObject wmi_HD in searcher.Get())
{
if (wmi_HD["SerialNumber"] == null)
hddId = null;
else
hddId = wmi_HD["SerialNumber"].ToString();
}
I'm getting
System.NullReferenceException : Object reference not set to an instance of an object.
Does anyone know why? What do I need to do to get the serial number in this case?
One more question: if I boot the OS from my pendrive, will this code work? How could I know that the OS is running from a pendrive or disk or any other resource?
When I go to the Device Manager, I see this:
I am adding this as an answer because it can save lot of time while debugging scenarios like System.NullReferenceException in WMI.
Windows+R (run command)
Type wbemtest
And connect to the machine for which you want to fetch information. Fire the query for Win32_DiskDrive and check the output for properties that you can fetch.
This is what I'm using on Windows 10 v1809:
using System;
using System.Management;
namespace GetSerialNo
{
class Program
{
static void Main(string[] args)
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
foreach (ManagementObject info in searcher.Get())
{
Console.WriteLine("DeviceID: " + info["DeviceID"].ToString());
Console.WriteLine("Model: " + "Model: " + info["Model"].ToString());
Console.WriteLine("Interface: " + "Interface: " + info["InterfaceType"].ToString());
Console.WriteLine("Serial#: " + "Serial#: " + info["SerialNumber"].ToString());
}
Console.ReadLine();
}
}
}
For details please see http://csharphelper.com/blog/2017/10/get-hard-drive-serial-number-c/
For the associated link Get Hard disk serial Number given by #ADreNaLiNe-DJ I wasn't able to find the required assembly reference for HardDrive hd = new HardDrive();

How to list all printers on network computer

As shown below in the picture, when I tried to retrieve all printers, I got only 2 printers.
Is there a way to return all printers using either PowerShell WMI or C#(so that I can translate it in powershell)?
I have tried System.Drawing.Printing.PrinterSettings.InstalledPrinters (refer to how to get the list of all printers in computer - C# Winform) but also displays only 2 entries.
Simply,
via System.Drawing.Printing
foreach (String printer in PrinterSettings.InstalledPrinters)
{
Console.WriteLine(printer.ToString()+Environment.NewLine);
}
via WMI
public static void AvailablePrinters()
{
oManagementScope = new ManagementScope(ManagementPath.DefaultPath);
oManagementScope.Connect();
SelectQuery oSelectQuery = new SelectQuery();
oSelectQuery.QueryString = #"SELECT Name FROM Win32_Printer";
ManagementObjectSearcher oObjectSearcher =
new ManagementObjectSearcher(oManagementScope, #oSelectQuery);
ManagementObjectCollection oObjectCollection = oObjectSearcher.Get();
foreach (ManagementObject oItem in oObjectCollection)
{
Console.WriteLine("Name : " + oItem["Name"].ToString()+ Environment.NewLine);
}
}
via PowerShell
Get-WMIObject -class Win32_Printer -computer $printserver | Select Name,DriverName,PortName
For more information, please check this article & WMI Printer Class

Get local printer list to change printer IP and default printer

How am I able do find all local printers of the machine where the program is running with a user that doesn't have admin rights. I need to remap the printer IP and set the printer as default. My idea is to use impersonation to do this but I don't know where to find the printer and if it is a good solution to use impersonation.
Thanks for any help!
I don't think you will have any luck with this. Impersonation will not work here and just throw a exception. You can try this by making a impersonation and try to open Environment.Domain it should give you a exception.
You can try something like this without impersonation:
ManagementScope mscope = new ManagementScope(#"\root\CIMV2", options);
mscope.Connect();
System.Management.ObjectQuery oQuery = new ObjectQuery("Select * from Win32_TCPIPPrinterPort");
System.Management.ManagementObjectSearcher searcher = new ManagementObjectSearcher(mscope, oQuery);
ManagementObjectCollection moCollection = searcher.Get();
foreach (ManagementObject mo in moCollection)
{
string name = mo["Name"].ToString();
if (name.Equals(this.portName))
{
System.Threading.Thread.Sleep(10000);
mo["HostAddress"] = this.printerIP;
mo.Put();
Console.WriteLine("Adjusted Printer Port to new IP address " + this.printerIP);
return true;
}
}

How can I remove a printer from the .Net print dialog?

I am working on a Winforms application that allows users to print a few different Reporting Services reports. Unfortunately, if the user tries to print to PDF using the Adobe PDF printer, it crashes. We haven't been able to solve this issue, so as a work around we want remove the ability for users to print to the Adobe PDF printer.
Is there any way to programmatically remove the Adobe PDF printer from the list of printers in the print dialog?
Call this with the printer name before calling PrintDialog().... I think this will solve your issue
public bool RemovePrinter(string printerName)
{
ManagementScope scope = new ManagementScope(ManagementPath.DefaultPath);
scope.Connect();
SelectQuery query = new SelectQuery("select * from Win32_Printer");
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection printers = search.Get();
foreach (ManagementObject printer in printers)
{
string printerName = printer["Name"].ToString().ToLower();
if (printerName.Equals(printerName.ToLower()))
{
printer.Delete();
break;
}
}
return true;
}
The answer from manish gave me what I needed. In my case, I had a virtual printer driver that was being created by a library, and it left orphans like Printer (1), Printer (2), etc. I wanted to delete all of those, so I used a variant of the WMI code above.
using System.Management;
//...
var scope = new ManagementScope(ManagementPath.DefaultPath);
scope.Connect();
var query = new SelectQuery($#"select * from Win32_Printer where Name like '{PrinterDeviceName}%'");
foreach (var o in new ManagementObjectSearcher(scope, query).Get())
((ManagementObject) o).Delete();
You need a reference to System.Management.

Categories

Resources