Monitoring printer-spoolers using WMI

O

Olaf Rabbachin

Hi folks,

during printing, I'm constantly checking the printer-spooler to monitor
whether a document has showed up in a printer's spooler and - after it has
- whether the print-job has been finished.
I'm using the following code for that:

--- 8< ---
Imports System.Management

Public Class CPrinterQueue
Public Shared Function JobCount(ByVal strPrinterName As String) As Integer
Dim strQuery As String = "SELECT * FROM Win32_PrintJob " & _
"WHERE DriverName = '" & strPrinterName.Replace("'", "''") & "'"
Dim JobQuery As New ManagementObjectSearcher(strQuery)
Dim Jobs As ManagementObjectCollection = JobQuery.Get()

Try
Return Jobs.Count
Catch ex As Exception
Return -1
Finally
Jobs.Dispose()
JobQuery.Dispose()
End Try
End Function
end class
--- 8< ---

As long as I'm only using one printer, everything's fine. But after a set
of documents has been printed, a receipt will be printed to a different
printer. As soon as I use the above class/function with the second printer,
it will return a wrong number of jobs upon first call and the code will
just stop running (at "Return Jobs.Count") afterwards.
If I comment out one of the usages (that is, I'm only monitoring one
printer), everything will be fine.

Any pointers?

Thanks!

Cheers,
Olaf
 
S

Stephany Young

I'd be inclined to throw some Console.Writeline's into the JobCount method.

I suspect that you might be getting some collisions between you usages.
E.g., 2nd usage hitting the JobQuery.Get() before the first usage has
finished returning Jobs.Count.

Another point could be in the Finally clause. I have never fully understood
how one can do what you have done in the Try clause and disposed of the
source object in the Finally clause and still have the correct value
returned. Sure, I have never seen it fail yet, but I don't entirely trust it
(because I don't fully understand it).

I wonder what would happen if you assigned Jobs.Count to a local integer and
returned that instead.

Just because I'm paranoid, it doesn't mean they're not out to get me.
 
O

Olaf Rabbachin

Hi,

Stephany said:
I'd be inclined to throw some Console.Writeline's into the JobCount method.

I did that, but it didn't help.
I suspect that you might be getting some collisions between you usages.
E.g., 2nd usage hitting the JobQuery.Get() before the first usage has
finished returning Jobs.Count.

The class I quoted was the simplest I had. I also tried a couple of other
approaches, one i.e. simply having the calling thread sleep for half a
second. Doing so showed each WMI-thread was finished before the next one
was created.
Another point could be in the Finally clause. I have never fully understood
how one can do what you have done in the Try clause and disposed of the
source object in the Finally clause and still have the correct value
returned. Sure, I have never seen it fail yet, but I don't entirely trust it
(because I don't fully understand it).

That's because I'd like to make sure that all objects are disposed of when
exiting the function. How else could you achieve that if not in the
Finally-clause?
I wonder what would happen if you assigned Jobs.Count to a local integer and
returned that instead.

Tried that as well - no change.

Anyway, I found out something else - it seems to be really related to the
printer that I'm not receiving any spooler-related stuff - with some it'll
work and with others it won't. Is there different approaches for different
printers? I don't really see a difference there ... :-(

Cheers,
Olaf
 
O

Olaf Rabbachin

Hi,

Olaf said:
Anyway, I found out something else - it seems to be really related to the
printer that I'm not receiving any spooler-related stuff - with some it'll
work and with others it won't. Is there different approaches for different
printers? I don't really see a difference there ... :-(

geez, got it. I was dumb enough to think that the contents of <DriverName>
would always be the printer's name.
So much for trying things out and thinking they'd be right - I tried 4
printers and their <DriverName> always showed the printers' names, but the
one I experienced the problems with was one that had a non-standard driver
which was named differently. Nice that, while testing, I constantly
switched the printers being checked and thus ended up thinking that it was
a matter of two printers in a row being used.

Anyway - instead, I am now using the <Name> item (seems to include the same
information as the <Caption> and <Description> items). Too bad that
property isn't limited to the name (as would've been expected and which was
the reason why I chose to use <DriverName> in the first place) - it
contains a suffix in the form of ", [ID]" where [ID] is the job's ID (also
available via the <JobID>-item). I have no idea as to why it is being
appended - sure doesn't make a whole lot of sense (a bug maybe?).

I'm currently cutting off anything after the last "," which will leave me
with the printer's name.
Also I have to browse all jobs of all printers as the WMI-query doesn't
seem to know LIKE-statements as in regular SQL.

So, unless there's a way (I sure don't know one) to retrieve a printer's
driver-name by the printer's name I'll have to stick with that.

Cheers,
Olaf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top