Hi again. Ok I seem to finally have found that I need to be using WMI for monitoring the print queue and I have been playing with it for a while. I have a problem though and I keep going round and round in circles.
Basically I have a test form that I am using to start and stop my monitor class. Anyhow, I want to return the information that my print monitor is picking out when it detects a print event back to the original test form but am having problems. The method that extracts the information is triggered from my monitor method so any return values would be sent back to the monitor method which is not what I want. I suppose the above probably dosnt make much sense so heres the code which should clarify it a bit
Heres the methods in my monitor class:
Code:
public bool StartPrintMonitor()
{
// Initialise the remaining objects required for the watcher.
WqlEventQuery printQueueQuery;
ManagementScope printQueueScope = new ManagementScope("root\\cimv2");
try
{
// Check the watcher is not already running.
if (watcherStatus == false)
{
printQueueQuery = new WqlEventQuery();
printQueueQuery.EventClassName = "__InstanceOperationEvent";
printQueueQuery.Condition = @"TargetInstance ISA 'Win32_PrintJob'";
printQueueQuery.WithinInterval = new TimeSpan(0, 0, 10);
printQueueWatcher = new ManagementEventWatcher(printQueueScope, printQueueQuery);
printQueueWatcher.Start();
watcherStatus = true;
printQueueWatcher.EventArrived += new EventArrivedEventHandler(this.PrintEventDetectedHandler);
return processStatus = true;
}
else
{
return processStatus = false;
}
}
catch (Exception exptn)
{
MessageBox.Show("Error detected: " + exptn);
return processStatus = false;
}
}
public bool StopPrintMonitor()
{
if (watcherStatus == true)
{
printQueueWatcher.Stop();
watcherStatus = false;
return processStatus = true;
}
else
{
return processStatus = false;
}
}
public void PrintEventDetectedHandler(object sender, EventArrivedEventArgs e)
{
StringCollection printJobCollection = new StringCollection();
foreach (PropertyData printJobData in e.NewEvent.Properties)
{
string searchQuery = "SELECT * FROM Win32_PrintJob";
ManagementObjectSearcher searchPrintJobs = new ManagementObjectSearcher(searchQuery);
ManagementObjectCollection prntJobCollection = searchPrintJobs.Get();
foreach (ManagementObject prntJob in prntJobCollection)
{
// For each event, capture the relevant data and send it to be formatted and entered into the
// database.
// Grabs job name and job ID for the current print job.
// Job name is formatted as follows: [Printer Name], [Job ID] and so needs the the two fields
// to be separated.
String jobName = prntJob.Properties["Name"].Value.ToString();
char[] splitArr = new char[1];
splitArr[0] = Convert.ToChar(",");
string printerName = jobName.Split(splitArr)[0];
string printJobId = jobName.Split(splitArr)[1];
// Grabs the document name
string documentName = prntJob.Properties["Document"].Value.ToString();
// Grabs the current printer operation (Such as spooling, printing etc)
string printJobOperation = prntJob.Properties["JobStatus"].Value.ToString();
// Grabs the number of pages actually printed.
// TODO: Seems inacurate (answer is always 0) so needs checking
string printJobPagesPrinted = prntJob.Properties["PagesPrinted"].Value.ToString();
// Grabs the current status of the print job (errors etc)
string printStatus = prntJob.Properties["Status"].Value.ToString();
// Grabs the current status code of the print job.
// TODO: Seems to be the same status as JobStatus above. Look into and decide which to use.
string printStatusMask = prntJob.Properties["StatusMask"].Value.ToString();
MessageBox.Show(" Printername: " + printerName + "\nDocumentname: " + documentName + "\nJob ID: " + printJobId +
"\nCurrent printer operation: " + printJobOperation + "\nPages printed: " + printJobPagesPrinted +
"\nPrint status: " + printStatus + "\nPrint status code: " + printStatusMask);
}
}
}
and here is my test form:
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections.Specialized;
namespace TestPrintMonitor
{
public partial class Form1 : Form
{
PrinterDetail PrintMonitor = new PrinterDetail();
StringCollection printerNameCollection = new StringCollection();
StringCollection printerStatusCollection = new StringCollection();
bool watcherStatus;
public Form1()
{
InitializeComponent();
}
private void btnGetPrinterNames_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox1.Items.Add("Installed Printers:");
listBox2.Items.Add("Printer Status:");
printerNameCollection = PrintMonitor.GetInstalledPrinterName();
foreach (Object obj in printerNameCollection)
{
listBox1.Items.Add(obj);
}
printerStatusCollection = PrintMonitor.GetPrinterStatus();
foreach (Object obj in printerStatusCollection)
{
if (obj.ToString() == "False")
{
listBox2.Items.Add("Printer offline");
}
else
{
listBox2.Items.Add("Printer online");
}
}
}
private void btnStartPrintMonitor_Click(object sender, EventArgs e)
{
watcherStatus = PrintMonitor.StartPrintMonitor();
if (watcherStatus == true)
{
MessageBox.Show("Print monitor has started successfully.");
}
else
{
MessageBox.Show("Print monitor is already running.");
}
}
private void btnStopPrintMonitor_Click(object sender, EventArgs e)
{
watcherStatus = PrintMonitor.StopPrintMonitor();
if (watcherStatus == true)
{
MessageBox.Show("Print monitor has stopped successfully.");
}
else
{
MessageBox.Show("Print monitor is not running.");
}
}
}
}
The long and the short of it is I want to return the values from the PrintEventDetectedHandler back to the test form so I can show them on the form but I cant work out how to. Anyone got any pointers?