Link to home
Start Free TrialLog in
Avatar of Shane Russell
Shane RussellFlag for United Kingdom of Great Britain and Northern Ireland

asked on

WMI, Printer c# 2005 express ?

ok Found this article on codeproject.com and this is the first time I have used c# and I dont see any download to the source code to a working example and am having a hard time trying to use wmi within any language in 2005 so if someone could help me get this example on code project working that would be great.

Preferably with a cancel button and a cancel all button so that I can cancel individual print jobs or all the print jobs in the printer's que for a remote machine.

Here is the code project article :

http://www.codeproject.com/csharp/prntjobcontrollerusingwmi.asp
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Step 1:  Here is a class that I use to enumerate Win32_PrintJobs:

using System;
using System.Management;

public class Win32_PrintJob
{

  public string DataType;
  public string Description;
  public string Document;
  public string DriverName;
  public DateTime ElapsedTime;
  public string HostPrintQueue;
  public DateTime InstallDate;
  public int JobId;
  public string JobStatus;
  public string Notify;
  public string Owner;
  public int PagesPrinted;
  public string Parameters;
  public string PrintProcessor;
  public int Priority;
  public int Size;
  public System.DateTime StartTime;
  public string Status;
  public int StatusMask;
  public DateTime TimeSubmitted;
  public int TotalPages;
  public DateTime UntilTime;

  public static Win32_PrintJob[] GetList()
  {
    string query = "Select * From Win32_PrintJob";

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    ManagementObjectCollection results = searcher.Get();

    Win32_PrintJob[] listPrintJobs = new Win32_PrintJob[results.Count - 1];

    int index = 0;
    foreach (ManagementObject entryCurrent in results)
    {
      Win32_PrintJob job = new Win32_PrintJob();

      job.DataType = (string)entryCurrent["DataType"];
      job.Description = (string)entryCurrent["Description"];
      job.Document = (string)entryCurrent["Document"];
      job.DriverName = (string)entryCurrent["DriverName"];
      job.ElapsedTime = ConvertFileTime((string)entryCurrent["ElapsedTime"]);
      job.HostPrintQueue = (string)entryCurrent["HostPrintQueue"];
      job.InstallDate = ConvertFileTime((string)entryCurrent["InstallDate"]);
      job.JobId = Convert.ToInt32(entryCurrent["JobId"]);
      job.JobStatus = (string)entryCurrent["JobStatus"];
      job.Notify = (string)entryCurrent["Notify"];
      job.Owner = (string)entryCurrent["Owner"];
      job.PagesPrinted = Convert.ToInt32(entryCurrent["PagesPrinted"]);
      job.Parameters = (string)entryCurrent["Parameters"];
      job.PrintProcessor = (string)entryCurrent["PrintProcessor"];
      job.Priority = Convert.ToInt32(entryCurrent["Priority"]);
      job.Size = Convert.ToInt32(entryCurrent["Size"]);
      job.StartTime = ConvertFileTime((string)entryCurrent["StartTime"]);
      job.Status = (string)entryCurrent["Status"];
      job.StatusMask = Convert.ToInt32(entryCurrent["StatusMask"]);
      job.TimeSubmitted = ConvertFileTime((string)entryCurrent["TimeSubmitted"]);
      job.TotalPages = Convert.ToInt32(entryCurrent["TotalPages"]);
      job.UntilTime = ConvertFileTime((string)entryCurrent["UntilTime"]);

      listPrintJobs[index] = job;

      index++;

    }
    return listPrintJobs;
  }

  private static DateTime ConvertFileTime(string time)
  {
    if (time != null)
    {
      const string FILE_TIME_MASK = "yyyyMMddHHmmss";
      time = time.Substring(0, time.IndexOf("."));
      return DateTime.ParseExact(time, FILE_TIME_MASK, null);
    }
    return DateTime.MinValue;
  }

}

Step 2:  Get a list of print jobs
 Call the static GetList and get back and array of Win32_PrintJob objects.

Step 3:  Get this from a remote machine
  To follow.

Bob
WMI requires that you add a "Reference" to your project before it will work.

This is typically done from the Solution Explorer (usually in the upper right-hand corner of the Visual Studio's IDE.  Right click on the "References" item and select "Add Reference".  A dialog box will appear... scroll about 3/4 of the way down, and select "System.Management".
Avatar of Shane Russell

ASKER

TheLearnedOne :

I need this in rich dummy terms with regards to where to put all this code as well as how to cancel individual jobs and or cancel all the print jobs.

graye :

I have already added the system management reference and that didnt help any as I still got errors as I have no clue where to copy and paste that code to because whenever I copy and paste the code that is given in that example from code project it just flags up errors.

Any chance you could get the example in the code project working and uploaded to some webspace in a zip file ( Because if the reply regarding connecting to a remote machine on code project is correct here :

//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();

co.Username = textUserID.Text;
co.Password = textPassword.Text;

//Point to machine
System.Management.ManagementScope ms = new System.Management.
ManagementScope("\\\\" + stringHostName + "\\root\\cimv2", co);

Then connecting to a remote machine shouldn't be an issue ( As long as I know how to cancel invidual jobs as well as all the jobs ( obviously in 2 seperate buttons ) Then I will be fine.

Thanks for the help
Step 4:  Cancel individual jobs.
The Win32_Printer class has CancelAllJobs.  The Win32_PrintJob has a Pause and a Resume method.  Neither of these will do what you need.   To cancel the print job, you need to just delete the management object.

job.Document.Delete();

External reference:
A simple approach for controlling print jobs using WMI
http://www.codeproject.com/csharp/prntjobcontrollerusingwmi.asp

Bob

so remind me, where does all the code go ? Do I need to create a new class to put your public class into or can I just copy and paste that into the same code window as the rest of the code or what steps do I need to take exactly ?
Step 5:  Implementation

1) Add a new class, called Win32_PrintJob, and paste the code from the class definition

2) The Win32_PrintJob.GetList returns an array of Win32_PrintJob elements, which contain the properties for each of the print job objects

3) Add a new property to the class:

   public ManagementObject PrintJob;

4) Add this line to GetList:

 job.PrintJob = entryCurrent;

5) Add a method to Win32_PrintJob:

   public static DeleteJob()
  {
      PrintJob.InvokeMethod("Delete", null);
  }

6) Add your code to set the management scope for the remote machine

7) Get all the print jobs:

  Win32_PrintJob[] list = Win32_PrintJob.GetList();

8) Cancel the job that you need

HTH
Bob
ok here is my code so far :

'-------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System;
using System.Management;

namespace PrintJob
{
    class Win32_PrintJob
    {
  public ManagementObject PrintJob;
  public string DataType;
  public string Description;
  public string Document;
  public string DriverName;
  public DateTime ElapsedTime;
  public string HostPrintQueue;
  public DateTime InstallDate;
  public int JobId;
  public string JobStatus;
  public string Notify;
  public string Owner;
  public int PagesPrinted;
  public string Parameters;
  public string PrintProcessor;
  public int Priority;
  public int Size;
  public System.DateTime StartTime;
  public string Status;
  public int StatusMask;
  public DateTime TimeSubmitted;
  public int TotalPages;
  public DateTime UntilTime;

  public static Win32_PrintJob[] GetList()
  {
    string query = "Select * From Win32_PrintJob";

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    ManagementObjectCollection results = searcher.Get();

    Win32_PrintJob[] listPrintJobs = new Win32_PrintJob[results.Count - 1];

    int index = 0;
    foreach (ManagementObject entryCurrent in results)
    {
      Win32_PrintJob job = new Win32_PrintJob();

      job.PrintJob = entryCurrent;
      job.DataType = (string)entryCurrent["DataType"];
      job.Description = (string)entryCurrent["Description"];
      job.Document = (string)entryCurrent["Document"];
      job.DriverName = (string)entryCurrent["DriverName"];
      job.ElapsedTime = ConvertFileTime((string)entryCurrent["ElapsedTime"]);
      job.HostPrintQueue = (string)entryCurrent["HostPrintQueue"];
      job.InstallDate = ConvertFileTime((string)entryCurrent["InstallDate"]);
      job.JobId = Convert.ToInt32(entryCurrent["JobId"]);
      job.JobStatus = (string)entryCurrent["JobStatus"];
      job.Notify = (string)entryCurrent["Notify"];
      job.Owner = (string)entryCurrent["Owner"];
      job.PagesPrinted = Convert.ToInt32(entryCurrent["PagesPrinted"]);
      job.Parameters = (string)entryCurrent["Parameters"];
      job.PrintProcessor = (string)entryCurrent["PrintProcessor"];
      job.Priority = Convert.ToInt32(entryCurrent["Priority"]);
      job.Size = Convert.ToInt32(entryCurrent["Size"]);
      job.StartTime = ConvertFileTime((string)entryCurrent["StartTime"]);
      job.Status = (string)entryCurrent["Status"];
      job.StatusMask = Convert.ToInt32(entryCurrent["StatusMask"]);
      job.TimeSubmitted = ConvertFileTime((string)entryCurrent["TimeSubmitted"]);
      job.TotalPages = Convert.ToInt32(entryCurrent["TotalPages"]);
      job.UntilTime = ConvertFileTime((string)entryCurrent["UntilTime"]);

      listPrintJobs[index] = job;

      index++;

    }
    return listPrintJobs;
  }

  private static DateTime ConvertFileTime(string time)
  {
    if (time != null)
    {
      const string FILE_TIME_MASK = "yyyyMMddHHmmss";
      time = time.Substring(0, time.IndexOf("."));
      return DateTime.ParseExact(time, FILE_TIME_MASK, null);
    }
    return DateTime.MinValue;
  }

}

}

'---------------------------

Im not sure where to put the code for step 5 or 7 and how do I link this class to the actual user form so that I can see this working ?
Do you have a main GUI form?

Bob
Yes I clicked in the toolbar on insert and selected add windows form and it inserted a form.
Just looking at the coding side with regards to connecting to the remote machine ( I dont understand where to put the following code )

//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();

co.Username = textUserID.Text;
co.Password = textPassword.Text;

//Point to machine
System.Management.ManagementScope ms = new System.Management.
ManagementScope("\\\\" + stringHostName + "\\root\\cimv2", co);


Does it go in place of this code :


    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    ManagementObjectCollection results = searcher.Get();
1)  Add the scope to the searcher:

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
    searcher.Scope = ms;

2) Add a list box to display the print job descriptions

3) Add a button to delete the job

4) Get a reference to the right Win32_PrintJob object, and call the DeleteJob method.

Bob
ok uploaded it to here :

http://www.badongo.com/file/1049914

Not sure how Im supposed to add a button to a delete job and the other steps just went over my head :-S
1 --> I can leave for now and just do it for the local machine and can work on the remote machine part later on.

2 --> Done that already when I added the form as I added a button called cmdPrinter with the caption set to Printer ( which in c sharp is called text obviously )

3 --> Im assuming you mean just adding a button to the form ( Cos thats all Ive done ) and not sure what else to do or what to put in the button or w/e

4 --> How can I tell If I have the right reference to the Win32_PrintJob object and how can I call the DeleteJob Method as that is what I was stuck on ( remember steps 5 and 7 ) with regards to not knowing where to put the code for that.

When I know where to put the code for that then I am assuming its just a case of doing a

Call FunctionName()

Inside of the button ?
you still there or did you give up ?
Man, do you think I live next to my computer, or am I allowed to have a life away from it?  

1) If you have an array of objects and a 1-to-1 correspondence with a ListBox, you can get the SelectedIndex, and get the right object from the array

2) Adding a button to a form is a fairly basic operation, and I hope that you are not asking me how to do that.

3) This isn't Visual Basic, so leave off the Call, and just use the function name:

   Win32_PrintJob job = jobList[this.ListBox1.SelectedIndex];
   job.DeleteJob();

Bob
I wasnt trying to say you live next to your computer or anything like that just before you were replying swiftly and then all of a sudden no reply. Sorry about that.

Just about to head off to work so I will give this a try this afternoon when I get back :)

I mis read what you said earlier but hopefully I can get this to work later on.
Is there any chance yourself or someone else could put it all together for me because I have left out the job.deletejob() and just tried to do it for the local machine and now I am even getting errors on this chunk of code

private static DateTime ConvertFileTime(string time)
  {
    if (time != null)
    {
      const string FILE_TIME_MASK = "yyyyMMddHHmmss";
      time = time.Substring(0, time.IndexOf("."));
      return DateTime.ParseExact(time, FILE_TIME_MASK, null);
    }
    return DateTime.MinValue;
  }

It said something about it not being compatable with the gregorian calendar or something about a string or something along those lines.

As per my question this is the first time I have used c# and I am just getting frustrated trying to add in all these niggly little bits left right and centre when I have absolutly no clue where I am supposed to put them exactly.

Is it asking too much for an example that is something like :

put this code into a class called Win32_PrintJob

'whatever the code is

Call it like so from a command button in a form like so :

' code to add the print jobs into a list view and have either a button or a context menu which when the job or jobs are selected you either click cancel all or cancel job to cancel a print job or all of the print jobs.
You are making me work very hard for my money--oh, wait, I do this for free*BIG GRIN*

Bob
How would you do this in VB6?

Bob
I wouldn't I was gonna do this in vb 2005 express. I just wanted to give it a go in c# as I have never used c# before.

Any chance you could get an example working for the local machine or at least add in the relevant parts of code into the class and then just give me the code I need to enumerate a listview which would be called from a button or in the form somewhere so that it just fills the list view with the print jobs.

Other then that I have another question open in the vb.net TA so if neither of the above is feasable then possibly help me with the cancelling the print jobs in vb.net 2005 express because I am further ahead with using vb.net with regards to at least having a listview that returns the print jobs in all the printers ( which I can alter to specific printers by using the where clause ie where name = 'printername'

I mean at the end of the day I just want a utility that will allow me to select a printer and either cancel a print job or purge all the print jobs for that printer.
I only asked about VB6, because I see where you are involved in that, and I wanted to give you a jumping off point, since C# is not significantly different.  I was kinda hopin' that I wouldn't have to do the whole thing for you as I am working on my own problems.  Teach someone to fish, and all that ;)

Bob
I've used wmi in vbscript and vb 6 but I havent done classes so that is where I am struggling at least afaik.

To be honest I would be happy just to see this class working and enumerating the print jobs into a listbox at this point.

@ Teach someone to fish, and all that ;)

Are you sure you didn't trip over the fishing line cos I can feel a hook through my finger lol
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Its not letting me logon to that ee stuff site, saying my logon credentials are wrong ( which I know isnt true ). email me it ( email is in profile - the yahoo one )
that example partialy works but when I click on delete print job it duplicates the other print job and then i click on delete on the duplicated print job and I get an array out of bounds error ( As I have 2 printers installed ) and it is saying that the printer que is for \\nameofmachine ( which is fair enough ) but it doesnt display which printer it is going to ie \\machinename\\printername

anway im off out and if you cant help me with being too busy or w/e thats fine and I will award you points as you have been helpful
1) I don't have 2 printers to debug this one

2) The Owner property might be a link to the machine, but I am not sure

Bob
I just installed some fake printers as I want to be able to do this for multiple printers ( If you would prefer I will ask about the bugs in a seperate question )
Nah, we can deal with here.  I will try to add some printers, and print to them.

Bob
much appriecated :) thx !! :)
You need to clear the ListView items collection.

Bob