Determining Printer Behavior with WMI and Visual Studio 2012
Introduction
Imagine this scenario: Your program's duty is to print a lot of reports and charts, and relies heavily on printers. Now, imagine further that your program cannot determine whether or not a printer is working or is having some kind of paper jam. This scenario can be quite embarrassing for you or your company whenever this situation arises and you have not compensated for that.
This article will explain how to use WMI with VB.NET and C# to determine local and remote printer activity.
WMI
If you have missed my previous article entitled "Getting Hard disk Information with WMI and Visual Studio 2012" in which I have explained WMI thoroughly, you could also have a look at this article about WMI.
Design
Start a new project in either VB.NET or C# and name it On_Off_Printer.
We don't need to add any control to our form. The reason for this is that we will create a user control, which will host all our needed objects (which we will create during run time), and the form will host the user control. So, all we need to do is to add a User Control to our project by clicking Project->Add User Control... Give it a name of MonitorPrinters
Code
MonitorPrinters
Let's get the show on the road! I thought it best to start with our User Control, as it will expose the necessary properties for our form to use. First, let us add the necessary Namespaces:
VB.NET
Imports System Imports System.Management 'Working With WMI Imports System.Drawing Imports System.Windows.Forms Imports System.IO 'Working With Files Imports On_Off_Printer_VB.frmPrinter
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Management; //Working With WMI using System.IO; //Working With Files using On_Off_Printer_C;
Remember to add a Project Reference to System.Management as well! Now, let us create the variables:
VB.NET
'Dynamically Create Labels & Buttons For Our Control
Private Label1 As New Label
Private lblPrinter As New Label 'Printer Name
Private Label2 As New Label
Private lblPrinterStatus As New Label 'Printer Status
Private Label3 As New Label
Private lblPrinterError As New Label 'Error
Private btnProperties As New Button
Private tmrCheck As Timer
Private intTime As System.Int32
C#
//Dynamically Create Labels & Buttons For Our Control
private Label Label1 = new Label();
private Label lblPrinter = new Label(); //Printer Name
private Label Label2 = new Label();
private Label lblPrinterStatus = new Label(); //Printer Status
private Label Label3 = new Label();
private Label lblPrinterError = new Label(); //Error
private Button btnProperties = new Button();
private Timer tmrCheck = new Timer();
private Int32 intTime;
Quite obviously this code creates the necessary objects. We need to go to the MonitorPrinter's Designer Code and add the following:
VB.NET
Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
'
'MonitorPrinters
'
Me.SuspendLayout()
With Label1
.Width = 60
.Text = "Printer"
.Top = 5
.Left = 10
.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
.AutoSize = True
End With
Me.Controls.Add(Label1)
With lblPrinter
.Width = 200
.Top = 5
.Left = Me.Label1.Left + Me.Label1.Width + 5
.TextAlign = System.Drawing.ContentAlignment.MiddleLeft
End With
Me.Controls.Add(lblPrinter)
With Label2
.Width = 60
.Text = "Status"
.Top = 5
.Left = Me.lblPrinter.Left + Me.lblPrinter.Width + 5
.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
.AutoSize = True
End With
Me.Controls.Add(Label2)
With lblPrinterStatus
.Text = ""
.Width = 120
.Top = 5
.Left = Me.Label2.Left + Me.Label2.Width + 5
.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
End With
Me.Controls.Add(lblPrinterStatus)
With Label3
.Width = 60
.Text = "Error"
.Top = 5
.Left = Me.lblPrinterStatus.Left + Me.lblPrinterStatus.Width + 5
.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
.AutoSize = True
End With
Me.Controls.Add(Label3)
With lblPrinterError
.Text = ""
.Width = 120
.Top = 5
.Left = Me.Label3.Left + Me.Label3.Width + 5
.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
End With
Me.Controls.Add(lblPrinterError)
With btnProperties
.Text = "Print Properties"
.Top = 5
.Left = lblPrinterError.Left + lblPrinterError.Width + 10
End With
Me.Controls.Add(btnProperties)
AddHandler Me.btnProperties.Click, AddressOf btnPropertiesClick
Me.ClientSize = New System.Drawing.Size(btnProperties.Left + btnProperties.Width + 10, btnProperties.Top + btnProperties.Height + 5)
tmrCheck = New System.Windows.Forms.Timer
tmrCheck.Interval = 5000
AddHandler tmrCheck.Tick, AddressOf tmrCheckTick
Me.ResumeLayout()
End Sub
C#
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Label1.Width = 60;
Label1.Text = "Printer";
Label1.Top = 5;
Label1.Left = 10;
Label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Label1.AutoSize = true;
this.Controls.Add(Label1);
lblPrinter.Width = 200;
lblPrinter.Top = 5;
lblPrinter.Left = this.Label1.Left + this.Label1.Width + 5;
lblPrinter.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.Controls.Add(lblPrinter);
Label2.Width = 60;
Label2.Text = "Status";
Label2.Top = 5;
Label2.Left = this.lblPrinter.Left + this.lblPrinter.Width + 5;
Label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Label2.AutoSize = true;
this.Controls.Add(Label2);
lblPrinterStatus.Text = "";
lblPrinterStatus.Width = 120;
lblPrinterStatus.Top = 5;
lblPrinterStatus.Left = this.Label2.Left + this.Label2.Width + 5;
lblPrinterStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.Controls.Add(lblPrinterStatus);
Label3.Width = 60;
Label3.Text = "Error";
Label3.Top = 5;
Label3.Left = this.lblPrinterStatus.Left + this.lblPrinterStatus.Width + 5;
Label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Label3.AutoSize = true;
this.Controls.Add(Label3);
lblPrinterError.Text = "";
lblPrinterError.Width = 120;
lblPrinterError.Top = 5;
lblPrinterError.Left = this.Label3.Left + this.Label3.Width + 5;
lblPrinterError.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.Controls.Add(lblPrinterError);
btnProperties.Text = "Print Properties";
btnProperties.Top = 5;
btnProperties.Left = lblPrinterError.Left + lblPrinterError.Width + 10;
this.Controls.Add(btnProperties);
btnProperties.Click += new System.EventHandler( this.btnPropertiesClick );
this.ClientSize = new System.Drawing.Size(btnProperties.Left + btnProperties.Width + 10, btnProperties.Top + btnProperties.Height + 5);
tmrCheck = new System.Windows.Forms.Timer(this.components);
tmrCheck.Interval = 5000;
tmrCheck.Enabled = true;
tmrCheck.Tick += new System.EventHandler(this.tmrCheckTick);
this.components.Add(tmrCheck);
this.ResumeLayout();
}
With the above code, we simply give each of our objects some properties in order to work with them, and in order for them to display correctly. Remember, we are creating these objects on the fly. This was just simpler to do. I guess it is a force of habit. You could obviously have put all these objects on your design window - the choice is ultimately yours.
Let us now initialize our User Control class:
VB.NET
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal strPrinterName As System.String)
MyBase.New()
Me.InitializeComponent()
PrinterNameProp = strPrinterName 'Printer name
End Sub
Public Sub New(ByVal strPrinterName As System.String, ByVal intCheckInTime As Integer)
MyBase.New()
Me.InitializeComponent()
CheckTimeProp = intCheckInTime 'Interval
PrinterNameProp = strPrinterName 'Printer name
End Sub
C#
public MonitorPrinters() : base()
{
this.InitializeComponent();
}
public MonitorPrinters(String strPrinterName) : base()
{
this.InitializeComponent();
PrinterNameProp = strPrinterName; //Printer Name
}
public MonitorPrinters(String strPrinterName, int intCheckInTime) : base()
{
// Must be called for initialization
this.InitializeComponent();
CheckTimeProp = intCheckInTime; //Interval
PrinterNameProp = strPrinterName; //Printer Name
}
Now we can call this class three different ways:
- Normally, i.e. Without any outside input via parameters.
- We could supply a printer name for which to obtain the settings.
- We could supply the printer name, as well as a interval time. This means that we could check every interval whether or not there is a change in the printer's behavior.
Now we need to add the Class properties that will be exposed for use with our form:
VB.NET
'Printer Name Property
Public Property PrinterNameProp As String
Get
Return lblPrinter.Text
End Get
Set(ByVal value As String)
lblPrinter.Text = value
tmrCheck.Start()
GetPrinterStatus()
End Set
End Property
'Printer Status Property
Public ReadOnly Property PrinterStatusProp As String
Get
Return lblPrinterStatus.Text
End Get
End Property
'Error Property
Public ReadOnly Property PrinterErrorProp As String
Get
Return lblPrinterError.Text
End Get
End Property
'Interval Property
Public Property CheckTimeProp As Int32
Get
Return tmrCheck.Interval
End Get
Set(ByVal value As Int32)
tmrCheck.Interval = value
End Set
End Property
C#
//Printer Name Property
public String PrinterNameProp
{
get
{
return lblPrinter.Text;
}
set
{
lblPrinter.Text = value;
tmrCheck.Start();
GetPrinterStatus();
}
}
//Printer Status Property
public String PrinterStatusProp
{
get
{
return lblPrinterStatus.Text;
}
}
//Error Property
public String PrinterErrorProp
{
get
{
return lblPrinterError.Text;
}
}
//Interval Property
public Int32 CheckTimeProp
{
get
{
return tmrCheck.Interval;
}
set
{
tmrCheck.Interval = value;
}
}
Right, the easy stuff is now out of the way; we can now start with the more complicated code - the code where we make use of WMI. The first procedure we will tackle is the GetPrinterStatus procedure. It looks like:
VB.NET
Public Sub GetPrinterStatus()
Dim moObj As ManagementObject 'Our Object to work with WMI
Dim mosQuery As ManagementObjectSearcher 'Retrieves a collection of management objects based on a specified query
Dim mocColl As ManagementObjectCollection 'Represents different collections of management objects retrieved through WMI
mosQuery = New ManagementObjectSearcher("Select * from Win32_Printer") 'Execute Query to Retreive Printers
mocColl = mosQuery.Get 'Get All Info
'Search Each Printer's Properties
For Each moObj In mocColl
If moObj.Properties("Name").Value = lblPrinter.Text Then 'If We Have A Match
lblPrinterStatus.Text = moObj.Properties("Status").Value 'Get Printer Status
lblPrinterError.Text = [Enum].GetName(GetType(DetectedErrorState), moObj.Properties("DetectedErrorState").Value) 'Get Error State
End If
Next
'Dispose of All WMI Objects
mosQuery.Dispose()
mocColl.Dispose()
moObj.Dispose()
End Sub
C#
public void GetPrinterStatus()
{
ManagementObjectSearcher mosQuery = default(ManagementObjectSearcher); //Retrieves a collection of management objects based on a specified query
ManagementObjectCollection mocColl = default(ManagementObjectCollection); //Represents different collections of management objects retrieved through WMI
mosQuery = new ManagementObjectSearcher("Select * from Win32_Printer"); //Execute Query to Retreive Printers
mocColl = mosQuery.Get(); //Get All Info
//Search Each Printer's Properties
foreach (ManagementObject _mo in mocColl) //Our Object to work with WMI
{
PropertyDataCollection moProperties = _mo.Properties;
if (moProperties["Name"].Value.ToString() == lblPrinter.Text) //If We Have A Match
{
lblPrinterStatus.Text = moProperties["Status"].Value.ToString(); //Get Printer Status
lblPrinterError.Text = Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.DetectedErrorState), moProperties["DetectedErrorState"].Value); //Get Error State
}
}
//Dispose of All WMI Objects
mosQuery.Dispose();
mocColl.Dispose();
}
Hello! You still there? OK, good, glad to see that you haven't run away after this piece of code! Here, we created all the WMI objects. We made use of the mosQuery object to search for all the printers installed on the computer (local as well as remote), then we looped through the mocColl object to obtain each printer's properties. These properties include the printer's name and status, as well as any error reported.
This information is actually just the tip of the iceberg. With our next procedure we will dive deeper into each printer's settings. These settings include the number of pages to print at a time, what print driver is actually used etc. Let us create the ShowPrinterProperties procedure now:
VB.NET
Public Sub ShowPrinterProperties(ByRef moObj As Management.ManagementObject)
Dim pdcProperties As PropertyDataCollection = moObj.Properties
Dim pdProperty As PropertyData
Dim strPath As String = Application.StartupPath & "\Printer" & lblPrinter.Text.Replace("\", " ") & ".txt"
Dim swPropertyWriter As StreamWriter = File.CreateText(strPath)
swPropertyWriter.WriteLine(moObj("Name"))
'Write Each Printer's Properties to A Seperate File
For Each pdProperty In pdcProperties
If pdProperty.Value Is Nothing Then
swPropertyWriter.WriteLine("")
Else
Select Case pdProperty.Name
Case "Availablility"
swPropertyWriter.WriteLine("Availabilty Properties : ")
swPropertyWriter.WriteLine([Enum].GetName(GetType(PrinterAvailability), pdProperty.Value))
Case "PrinterStatus"
swPropertyWriter.WriteLine("Printer Status Properties : ")
swPropertyWriter.WriteLine([Enum].GetName(GetType(PrinterStatus2), pdProperty.Value))
Case "ExtendedPrinterStatus"
swPropertyWriter.WriteLine("Extended Printer Status Properties :")
swPropertyWriter.WriteLine([Enum].GetName(GetType(ExtendedPrinterStatus), pdProperty.Value))
Case "PrinterStatusInfo"
swPropertyWriter.WriteLine("Printer Status Info Properties : ")
swPropertyWriter.WriteLine([Enum].GetName(GetType(PrinterStatus1), pdProperty.Value))
Case "PrinterState"
swPropertyWriter.WriteLine("Printer State Properties :")
swPropertyWriter.WriteLine([Enum].GetName(GetType(PrinterState), pdProperty.Value))
Case "DetectedErrorState"
swPropertyWriter.WriteLine("Detected Error State Properties :")
swPropertyWriter.WriteLine([Enum].GetName(GetType(DetectedErrorState), pdProperty.Value))
Case "ExtendedDetectedErrorState"
swPropertyWriter.WriteLine("Extended Detected Error State Properties :")
swPropertyWriter.WriteLine([Enum].GetName(GetType(ExtendedDetectedErrorState), pdProperty.Value))
Case Else
swPropertyWriter.WriteLine("Other Properties :")
swPropertyWriter.WriteLine(Convert.ToString(pdProperty.Value))
End Select
End If
Next
swPropertyWriter.Close()
End Sub
C#
public void ShowPrinterProperties(ref ManagementObject moObj)
{
PropertyDataCollection pdcProperties = moObj.Properties;
string strPath = Application.StartupPath + "\\Printer" + lblPrinter.Text.Replace("\\", " ") + ".txt";
StreamWriter swPropertyWriter = File.CreateText(strPath);
swPropertyWriter.WriteLine(moObj["Name"]);
//Write Each Printer's Properties to A Seperate File
foreach (PropertyData moProperty in pdcProperties)
{
if (moProperty.Value == null)
{
swPropertyWriter.WriteLine("");
}
else
{
switch (moProperty.Name)
{
case "Availablility":
swPropertyWriter.WriteLine("Availabilty Properties : ");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.PrinterAvailability), moProperty.Value));
break;
case "PrinterStatus":
swPropertyWriter.WriteLine("Printer Status Properties : ");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.PrinterStatus2), moProperty.Value));
break;
case "ExtendedPrinterStatus":
swPropertyWriter.WriteLine("Extended Printer Status Properties :");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.ExtendedPrinterStatus), moProperty.Value));
break;
case "PrinterStatusInfo":
swPropertyWriter.WriteLine("Printer Status Info Properties :");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.PrinterStatus1), moProperty.Value));
break;
case "PrinterState":
swPropertyWriter.WriteLine("Printer State Properties :");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.PrinterState), moProperty.Value));
break;
case "DetectedErrorState":
swPropertyWriter.WriteLine("Detected Error State Properties :");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.DetectedErrorState), moProperty.Value));
break;
case "ExtendedDetectedErrorState":
swPropertyWriter.WriteLine("Extended Detected Error State Properties :");
swPropertyWriter.WriteLine(Enum.GetName(typeof(On_Off_Printer_C.frmPrinter.ExtendedDetectedErrorState), moProperty.Value));
break;
default:
swPropertyWriter.WriteLine("Other Properties :");
swPropertyWriter.WriteLine(Convert.ToString(moProperty.Value));
break;
}
}
}
}
As mentioned, we delve a bit deeper into each printer's settings. We actually have a look through seven enumerations (which we will create in our Form ) and determine each enumeration's value or setting. We then print each printer's settings out onto a separate file for each associated printer. For more information on the Enums we are referring to here, have a look here.
All that is needed inside this class is the calls to the above procedures we created. Let us add the last events for MonitorPrinter now:
VB.NET
Private Sub tmrCheckTick(ByVal sender As System.Object, ByVal e As System.EventArgs)
GetPrinterStatus()
End Sub
Private Sub btnPropertiesClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim moObj As ManagementObject
Dim mosQuery As ManagementObjectSearcher
Dim mocColl As ManagementObjectCollection
mosQuery = New ManagementObjectSearcher("Select * from Win32_Printer")
mocColl = mosQuery.Get
'Get All Printer Properties
For Each moObj In mocColl
If moObj.Properties("Name").Value = lblPrinter.Text Then
ShowPrinterProperties(moObj)
End If
Next
mosQuery.Dispose()
mocColl.Dispose()
moObj.Dispose()
End Sub
C#
private void tmrCheckTick(System.Object sender, System.EventArgs e)
{
GetPrinterStatus();
}
private void btnPropertiesClick(System.Object sender, System.EventArgs e)
{
ManagementObject moObj = default(ManagementObject);
ManagementObjectSearcher mosQuery = default(ManagementObjectSearcher);
ManagementObjectCollection mocColl = default(ManagementObjectCollection);
mosQuery = new System.Management.ManagementObjectSearcher("Select * from Win32_Printer");
mocColl = mosQuery.Get();
//Get All Printer Properties
foreach ( ManagementObject _mo in mocColl)
{
if (_mo["Name"].ToString() == lblPrinter.Text)
{
moObj = _mo;
ShowPrinterProperties(ref moObj);
}
}
mosQuery.Dispose();
mocColl.Dispose();
}
}
We call the GetPrinterStatus sub every five seconds via our Timer. In the Button's event we simply ensure that we are dealing with the correct printer each time, and then call the sub for printing our extended printer settings. You may be wondering now where do I create the Enums? What else is left?
Well, let us move our focus to our form.
frmPrinters
The User Control is now set up nicely. It will list all the printers on the system along with each printer's status and extended properties. Obviously, we need a host for our User Control, and this host is our form. Because we deal with an unknown amount of printers, we will need to make an array of user controls for the amount of printers we have. We also need to include our Win32_Printer class enums here, or else we will not be able to obtain our extended properties as shown above. Add the following Namespace to your form's code:
VB.NET
Imports System.Management 'Working with WMI. Reference System.Management as well
C#
using System.Management; //Working with WMI. Reference System.Management as well
Add the necessary enumerations:
VB.NET
Public Enum PrinterAvailability As Integer 'PrinterAvailability WMI Settings
Other = 1
Unknown = 2
Running = 3
Warning = 4
InTest = 5
NotApplicable = 6
PowerOff = 7
OffLine = 8
OffDuty = 9
Degraded = 10
NotInstalled = 11
InstallError = 12
PowerSaveUnknown = 13
PowerSaveLowPower = 14
PowerSaveStandBy = 15
PowerCycle = 16
PowerSaveWarning = 17
End Enum
Public Enum DetectedErrorState As Integer 'Detected ErrorState WMI Settings
Unknown = 1
Other = 2
NoError = 3
LowPaper = 4
NoPaper = 5
LowToner = 6
NoToner = 7
DoorOpen = 8
Jammed = 9
Offline = 10
ServiceRequested = 11
OutputBinFull = 12
End Enum
Public Enum ExtendedDetectedErrorState As Integer 'Extended ErrorState WMI Settings
Unknown = 0
Other = 1
NoError = 2
LowPaper = 3
NoPaper = 4
LowToner = 5
NoToner = 6
DoorOpen = 7
Jam = 8
ServiceRequested = 9
OutputBinFull = 10
PaperProblem = 11
CannotPrintPage = 12
UserInterventionRequired = 13
OutOfMemory = 14
ServerUnknown = 15
End Enum
Public Enum PrinterState As Integer 'Printer State WMI Settings
Unknown = 0
Paused = 1
PrintError = 2
PendingDeletion = 3
PaperJam = 4
PaperOut = 5
ManualFeed = 6
PaperProblem = 7
Offline = 8
IoActive = 9
Busy = 10
Printing = 11
OutputBinFull = 12
NotAvailable = 13
Waiting = 14
Processing = 15
Initialization = 16
WarmingUp = 17
TonerLow = 18
NoToner = 19
PagePunt = 20
UserInterventionRequired = 21
OutOfMemory = 22
DoorOpen = 23
ServerUnknown = 24
PowerSave = 25
End Enum
Public Enum PrinterStatus1 As Integer 'Printer Status WMI Settings
Other = 1
Unknown = 2
Enabled = 3
Disabled = 4
NotApplicable = 5
End Enum
Public Enum PrinterStatus2 As Integer
Other = 1
Unknown = 2
Idle = 3
Printing = 4
WarmUp = 5
StoppedPrinting = 6
OffLine = 7
End Enum
Public Enum ExtendedPrinterStatus As Integer 'Printer Status WMI Settings
Other = 1
Unknown = 2
Idle = 3
Printing = 4
WarmUp = 5
StoppedPrinting = 6
Offline = 7
Paused = 8
GeneralError = 9
Busy = 10
NotAvailable = 11
Waiting = 12
Processing = 13
Initialization = 14
PowerSave = 15
PendingDeletion = 16
IoActive = 17
ManualFeed = 18
End Enum
C#
public enum PrinterAvailability : int //PrinterAvailability WMI Settings
{
Other = 1,
Unknown = 2,
Running = 3,
Warning = 4,
InTest = 5,
NotApplicable = 6,
PowerOff = 7,
OffLine = 8,
OffDuty = 9,
Degraded = 10,
NotInstalled = 11,
InstallError = 12,
PowerSaveUnknown = 13,
PowerSaveLowPower = 14,
PowerSaveStandBy = 15,
PowerCycle = 16,
PowerSaveWarning = 17
}
public enum DetectedErrorState : int //Detected ErrorState WMI Settings
{
Unknown = 1,
Other = 2,
NoError = 3,
LowPaper = 4,
NoPaper = 5,
LowToner = 6,
NoToner = 7,
DoorOpen = 8,
Jammed = 9,
Offline = 10,
ServiceRequested = 11,
OutputBinFull = 12
}
public enum ExtendedDetectedErrorState : int //Extended ErrorState WMI Settings
{
Unknown = 0,
Other = 1,
NoError = 2,
LowPaper = 3,
NoPaper = 4,
LowToner = 5,
NoToner = 6,
DoorOpen = 7,
Jam = 8,
ServiceRequested = 9,
OutputBinFull = 10,
PaperProblem = 11,
CannotPrintPage = 12,
UserInterventionRequired = 13,
OutOfMemory = 14,
ServerUnknown = 15
}
public enum PrinterState : int //Printer State WMI Settings
{
Unknown = 0,
Paused = 1,
PrintError = 2,
PendingDeletion = 3,
PaperJam = 4,
PaperOut = 5,
ManualFeed = 6,
PaperProblem = 7,
Offline = 8,
IoActive = 9,
Busy = 10,
Printing = 11,
OutputBinFull = 12,
NotAvailable = 13,
Waiting = 14,
Processing = 15,
Initialization = 16,
WarmingUp = 17,
TonerLow = 18,
NoToner = 19,
PagePunt = 20,
UserInterventionRequired = 21,
OutOfMemory = 22,
DoorOpen = 23,
ServerUnknown = 24,
PowerSave = 25
}
public enum PrinterStatus1 : int //Printer Status WMI Settings
{
Other = 1,
Unknown = 2,
Enabled = 3,
Disabled = 4,
NotApplicable = 5
}
public enum PrinterStatus2 : int
{
Other = 1,
Unknown = 2,
Idle = 3,
Printing = 4,
WarmUp = 5,
StoppedPrinting = 6,
OffLine = 7
}
public enum ExtendedPrinterStatus : int //Printer Status WMI Settings
{
Other = 1,
Unknown = 2,
Idle = 3,
Printing = 4,
WarmUp = 5,
StoppedPrinting = 6,
Offline = 7,
Paused = 8,
GeneralError = 9,
Busy = 10,
NotAvailable = 11,
Waiting = 12,
Processing = 13,
Initialization = 14,
PowerSave = 15,
PendingDeletion = 16,
IoActive = 17,
ManualFeed = 18
}
For more information on these enums, please refer to the Win32_Printer Class link above.
Let us now create the User Control array:
VB.NET
Private ucPrinters() As MonitorPrinters 'UserControl To Show Printer Values
C#
private MonitorPrinters[] ucPrinters; //UserControl To Show Printer Values
Finally, let us add the Form_Load event to get the party started:
VB.NET
Private Sub Form_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim mocColl As Management.ManagementObjectCollection 'Represents different collections of management objects retrieved through WMI
Dim mosQuery As Management.ManagementObjectSearcher 'Retrieves a collection of management objects based on a specified query
Dim moObj As Management.ManagementObject 'Our Object to work with WMI
Dim msScope As Management.ManagementScope 'Represents a scope (namespace) for management operations.
Dim ucPrinters() As MonitorPrinters 'Create UserControl Array
Dim iYPos As Integer = 15 'Vertical Pos of Controls
Dim iXPos As Integer = 15 'Horizontal Pos of Controls
Dim iInterval As Integer = 5000 'Printer Checking Interval
msScope = New ManagementScope("\root\cimv2") 'We Want To Search Our Local Machine
msScope.Connect() 'Connect to Local Machine
mosQuery = New Management.ManagementObjectSearcher("Select * from Win32_Printer") 'Execute Query to Retreive Printers
mocColl = mosQuery.Get 'Get All Info
For Each moObj In mocColl 'Loop Through WMI Collection
If ucPrinters Is Nothing Then 'If No Printers
ReDim ucPrinters(0)
ucPrinters(0) = New MonitorPrinters(moObj.Properties("Name").Value, iInterval)
Else 'If Printers
ReDim Preserve ucPrinters(ucPrinters.Length) 'Resize to Amount of Printers Installed
ucPrinters(ucPrinters.Length - 1) = New MonitorPrinters(moObj.Properties("Name").Value, iInterval) 'Send Printer Name to UserControl
End If
With ucPrinters(ucPrinters.Length - 1) 'Set Location of Each UserControl
.Top = iYPos
.Left = iXPos
End With
Me.Controls.Add(ucPrinters(ucPrinters.Length - 1)) 'Add UserControl to Form
iYPos = iYPos + ucPrinters(ucPrinters.Length - 1).Height + 5
Next
'Resize Form
Me.ClientSize = New System.Drawing.Size(ucPrinters(0).Width + 10, ucPrinters(ucPrinters.Length - 1).Top + ucPrinters(ucPrinters.Length - 1).Height + 5)
End Sub
C#
private void frmPrinter_Load(object sender, EventArgs e)
{
ManagementObjectCollection mocColl = default(ManagementObjectCollection); //Represents different collections of management objects retrieved through WMI
ManagementObjectSearcher mosQuery = default(ManagementObjectSearcher); //Retrieves a collection of management objects based on a specified query
ManagementScope msScope = default(ManagementScope); //Represents a scope (namespace) for management operations.
MonitorPrinters[] ucPrinters = null; //Create UserControl Array
int iYPos = 15; //Vertical Pos of Controls
int iHorPos = 15; //Horizontal Pos of Controls
int iInterval = 5000; //Printer Checking Interval
msScope = new ManagementScope("\\root\\cimv2"); //We Want To Search Our Local Machine
msScope.Connect(); //Connect to Local Machine
mosQuery = new ManagementObjectSearcher("Select * from Win32_Printer"); //Execute Query to Retreive Printers
mocColl = mosQuery.Get(); //Get All Info
foreach (ManagementObject moObj in mocColl) //Loop Through WMI Collection
{
PropertyDataCollection properties = moObj.Properties; //Store Properties
if (ucPrinters == null || ucPrinters.Length == 0) //If No Printer Exists
{
Array.Resize(ref ucPrinters, 1);
ucPrinters[0] = new MonitorPrinters(properties["Name"].Value.ToString(), iInterval);
}
else //If Printers
{
Array.Resize(ref ucPrinters, ucPrinters.Length + 1); //resize to Amount of Printers
ucPrinters[ucPrinters.Length - 1] = new MonitorPrinters(properties["Name"].Value.ToString(), iInterval); //Send Names to UserControl
}
//Set Location of Each UserCOntrol
ucPrinters[ucPrinters.Length - 1].Top = iYPos;
ucPrinters[ucPrinters.Length - 1].Left = iHorPos;
this.Controls.Add(ucPrinters[ucPrinters.Length - 1]); //Add UserControl to Form
iYPos = iYPos + ucPrinters[ucPrinters.Length - 1].Height + 5;
}
//Resize Form
this.ClientSize = new Size(ucPrinters[0].Width + 10, ucPrinters[ucPrinters.Length - 1].Top + ucPrinters[ucPrinters.Length - 1].Height + 5);
}
}
What happens above is we query our WMI objects again and create the MonitorPrinters control for each associated printer. The rest of the code concentrates on spacing the controls correctly.
If you were to run your project now, you would see a screen listing of all your installed printers. Once you click the Print button, you will be able to determine which printer is possibly at fault. I am including the projects in zipped format below, just in case...
Conclusion
Phew! That was some work indeed! Thank you for reading my article. I hope it gives you much joy and helps you out with a lot of printer problems in the future. Until next time, Cheers!

Comments
Its always necessary keep your teeth clean
Posted by grorbQuonge on 05/01/2013 03:56pmA tooth (plural teeth) is a mignonne, calcified, whitish order found in the jaws (or mouths) of many vertebrates and occupied to defeat down food. Some animals, particularly carnivores, also exercise teeth for the purpose hunting or in place of defensive purposes. The roots of teeth are covered sooner than gums. Teeth are not made of bone, but to a certain extent of multiple tissues of varying density and hardness. The general structure of teeth is alike resemble across the vertebrates, although there is considerable variation in their form and position. The teeth of mammals get deep roots, and this figure is also rest in some fish, and in crocodilians. In most teleost fish, how, the teeth are partial to to the outer surface of the bone, while in lizards they are attached to the inner side of the jaw alongside a man side. In cartilaginous fish, such as sharks, the teeth are joined by rough ligaments to the hoops of cartilage that type the jaw.
ReplyIts always necessary keep your teeth clean
Posted by tamrinnalon on 04/28/2013 02:18amA tooth (plural teeth) is a cheap, calcified, whitish order start in the jaws (or mouths) of various vertebrates and habituated to to sever down food. Some animals, explicitly carnivores, also exercise teeth in behalf of hunting or owing defensive purposes. The roots of teeth are covered by means of gums. Teeth are not made of bone, but degree of multiple tissues of varying density and hardness. The general systematize of teeth is nearly the same across the vertebrates, although there is considerable modulation in their form and position. The teeth of mammals drink serious roots, and this design is also found in some fish, and in crocodilians. In most teleost fish, manner, the teeth are partial to to the outer surface of the bone, while in lizards they are fastened to the inner come up of the jaw by a man side. In cartilaginous fish, such as sharks, the teeth are unavailable by means of cold ligaments to the hoops of cartilage that construct the jaw.
Reply