1
votes

I am able to get print job informations from Win32_PrintJob by using WMI and ManagementEventWatcher but I cannot seem to find the printer name. I also looked to this Win32_PrintJob documentation and the closest thing to printer name is DriverName property, but it is the printer driver name, not the printer name as displayed in the Control Panel's Devices and Printers.

So, as stated in the title, how can I get the printer name from print job from Win32_PrintJob?

This is my partial codes so far to get the print job:

public void PrintHelperInstance_OnPrintJobChange(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject objProps = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;

    string jobName = objProps["Document"].ToString();

    if (jobName == "Test Print Form")
    {
        if (!IsFoundPrintJob)
        {
            IsFoundPrintJob = true;
        }

        CurrentJobStatus = (string)objProps["JobStatus"];

        if (CurrentJobStatus != PreviousJobStatus)
        {
            uint jobId = (uint)objProps["JobId"];
            string jobPrinter = (string)objProps["DriverName"];
            string jobHost = (string)objProps["HostPrintQueue"];
            string jobStatus = (string)objProps["JobStatus"];

            PreviousJobStatus = CurrentJobStatus;
        }
    }
}
2

2 Answers

2
votes

You can use this code :

// produce wmi query object
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Printer");
// produce search object
ManagementObjectSearcher search = new ManagementObjectSearcher(query);
// retrieve result collection
ManagementObjectCollection result = search.Get();
// iterate through all printers 
foreach(ManagementObject obj in result)
{
    // now create your temp printer class
    Dictionary<string, object> printerObj = new Dictionary<string, object>();
    if(obj.GetPropertyValue("Local").ToString().Equals("true"))
    {
        printerObj.Add("isLocal", true);
        printerObj.Add("name", obj.GetPropertyValue("name").ToString());
    }
    else 
    {
        printerObj.Add("isLocal", false);
        printerObj.Add("serverName", obj.GetPropertyValue("ServerName").ToString());
        printerObj.Add("shareName", obj.GetPropertyValue("ShareName").ToString());
    }

    // create real printer object
    PrintServer srv = ((bool)printerObj["isLocal")) ? new LocalPrintServer() : new PrintServer((string)printerObj["serverName"]);
    PrintQueue queue = srv.GetPrintQueue(((bool)printerObj["isLocal")) ? (string)printerObj["name"] : (string)printerObj["shareName"];

    foreach(var job in queue.GetPrintJobInfoCollection())
    {
        // check job info and if it matches, return printer name;
    }
}
0
votes

Although I found the marked answer useful, there are some conventions that should be used:

  • Using that invokes Dispose
  • Contract requirement, to avoid passing nulls
  • A more efficient syntax for setting properties on new objects
  • The NameOf method, when possible, instead of using string

There are certain objects created that can be extended for your purposes:

Namespace PrintQueueTool
    Public Interface IPrintJob
        Property JobId As Integer
        Property JobName As String
        Property JobOwner As String
    End Interface
End Namespace
Imports System.Collections.ObjectModel

Namespace PrintQueueTool
    Public Interface IPrinter
        Property Id As String
        Property IsDefault As Boolean
        Property IsLocal As Boolean
        Property Name As String
        Property ServerName As String
        Property ShareName As String
        Property PrintJobs As ObservableCollection(Of IPrintJob)
    End Interface
End Namespace

With the above objects, the viewmodel loads the printers into its collection of Printer objects as follows:

        Private Sub GetPrinters()

            Dim objScope = New ManagementScope(ManagementPath.DefaultPath)
            objScope.Connect()

            Dim selectQuery As SelectQuery = New SelectQuery With {.QueryString = "Select * from win32_Printer"}
            Using searcher = New ManagementObjectSearcher(objScope, selectQuery)
                Using moCollection = searcher.Get()
                    PrinterCollection = New ObservableCollection(Of IPrinter)
                    For Each mo As ManagementObject In moCollection
                        Dim newPrinter = New Printer(mo)
                        PrinterCollection.Add(newPrinter)
                    Next mo
                End Using
            End Using
        End Sub

The printer object builds its own properties and queue from the ManagementObject it is passed

        Public Sub New(managementObject As System.Management.ManagementObject)
         Contracts.Contract.Requires(managementObject IsNot Nothing)
         Id = Guid.NewGuid().ToString()
            Name = managementObject(NameOf(Name))
            IsDefault = CBool(managementObject("Default"))
            IsLocal = CBool(managementObject("Local"))
            Using srv As PrintServer = If((CBool(managementObject("Local"))), New LocalPrintServer(), New PrintServer(CStr(managementObject("serverName"))))
                Using queue As PrintQueue = srv.GetPrintQueue(If((CBool(managementObject("Local"))), CStr(managementObject(NameOf(Name))), CStr(managementObject("shareName"))))
                    PrintJobs = New ObservableCollection(Of IPrintJob)
                    Using jobs = queue.GetPrintJobInfoCollection()
                        For Each job In jobs
                            Dim printJob = New PrintJob With
                            {
                                .JobId = job.JobIdentifier,
                                .JobName = job.JobName,
                                .JobOwner = job.Submitter
                            }
                        Next
                    End Using
                End Using
            End Using
        End Sub