?
Solved

Spooler job number and filenames

Posted on 2003-03-06
6
Medium Priority
?
591 Views
Last Modified: 2011-09-20
I can easily retrieve the job jumber of a spooled job, but how do I get the complete pathnames to the .SPL and .SHD files?

I'm hoping that the answer isn't to look for leading-zero-filled-jobnumber.spl/shd in the default and device-specific spool directories - that's a pain!

...Bill
0
Comment
Question by:billious
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
6 Comments
 
LVL 7

Expert Comment

by:Motaz
ID: 8078424
If I understand you correctly you need to search in a directory for files that you didn't know thier names:

var
  Rec: TSearchRec;
begin
  ListBox1.Clear;
  if FindFirst('c:\Spool\*.*', faAnyFile, Rec) = 0 then
  repeat
    ListBox1.Items.Add(Rec.Name);
  until FindNext(Rec) <> 0;
  FindClose(Rec);
end;

Motaz
0
 
LVL 1

Expert Comment

by:DjamD
ID: 8078803
Here's an implementation of GetPrintJobs Unit :
--------------------------------------------------------
unit GetPrintJobs;

interface

uses
  Windows, Sysutils, Winspool, Printers, classes;

function PrintJobsNumber(PrinterName : PChar):Integer;
function PrintJobsList(PrinterName : PChar):TStringList;

implementation

function GetCurrentPrinterHandle(PrinterName : PChar): THandle;
var
  Device, Driver, Port: array[0..255] of Char;
  hDeviceMode: THandle;
begin
  Printer.PrinterIndex := Printer.Printers.IndexOf(PrinterName);
  Printer.GetPrinter(Device, Driver, Port, hDeviceMode);
  if not OpenPrinter(@Device, Result, nil) then
    RaiseLastWin32Error;
end;

function SavePChar(p: PChar): PChar;
const
  error: PChar = 'Nil';
begin
  if not Assigned(p) then
    Result := error
  else
    Result := p;
end;

function PrintJobsNumber(PrinterName : PChar):Integer;
type
  TJobs  = array [0..1000] of JOB_INFO_1;
  PJobs = ^TJobs;
var
  hPrinter: THandle;
  bytesNeeded, numJobs: Cardinal;
  pJ: PJobs;
begin
  hPrinter := GetCurrentPrinterHandle(PrinterName);
  try
    EnumJobs(hPrinter, 0, 1000, 1, nil, 0, bytesNeeded,
      numJobs);
    pJ := AllocMem(bytesNeeded);

    if not EnumJobs(hPrinter, 0, 1000, 1, pJ, bytesNeeded,
      bytesNeeded, numJobs) then
      RaiseLastWin32Error;

    Result := numJobs;
  finally
    ClosePrinter(hPrinter);
  end;
end;

function PrintJobsList(PrinterName : PChar):TStringList;
type
  TJobs  = array [0..1000] of JOB_INFO_1;
  PJobs = ^TJobs;
var
  hPrinter: THandle;
  bytesNeeded, numJobs, i: Cardinal;
  pJ: PJobs;
begin
  hPrinter := GetCurrentPrinterHandle(PrinterName);
  try
    EnumJobs(hPrinter, 0, 1000, 1, nil, 0, bytesNeeded,
      numJobs);
    pJ := AllocMem(bytesNeeded);

    if not EnumJobs(hPrinter, 0, 1000, 1, pJ, bytesNeeded,
      bytesNeeded, numJobs) then
      RaiseLastWin32Error;

    Result.Clear;

    if numJobs <> 0 then
    begin
      Result.Clear;
     
      for i := 0 to Pred(numJobs) do
        Result.Add(Format('Printer %s, Job %s, Status (%d): %s',
          [SavePChar(pJ^[i].pPrinterName), SavePChar(pJ^[i].pDocument),
          pJ^[i].Status, SavePChar(pJ^[i].pStatus)]));
    end;
  finally
    ClosePrinter(hPrinter);
  end;
end;

end.

--------------------------------------------------------
By giving the Printer name to the function it returns the number of jobs that are scheduled.

If it's equal to zero it means that your print jobs are ended.

Hope this helps,
Cordially

DjamD
0
 
LVL 1

Expert Comment

by:DjamD
ID: 8078816
Oops,
i forgot to mention that i was talking about the PrintJobsNumber function.

Cordially,
DjamD
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 7

Author Comment

by:billious
ID: 8079558
Thanks guys - but unfortunately not what I need.

In gory detail, the scenario is this:

I have a group of users who employ an application which automatically produces reports.

They only need a small proportion of the reports produced, but don't know which they need until some hours after the report has been created.

Naturally, they don't want to have a mountain of waste paper to sort through, for obvious reasons.

To cure this, I set their system to print to a dummy printer which is permanently set to being PAUSED. I then added an application which searched for significant strings in the .SPL file, and allows them to
print their selections to a real printer. Any print files more than a few days old are purged.

The users now want to move to NT and 32-bit versions of their application (over which I have no control).

I have found that in the registry, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers
has an entry DefaultSpooldirectory which acts as the destination for the spooled files, and have changed this to a big, fast drive for no reason other than I could.

For each printer, under HKEY...\Printers\Printername, there is a "Spooldirectory" entry, which acts as the spool destination directory for the individual printer - if set to "", use the default.

The 16-bit version of the software happily places the print jobs in the appropriate directory, as directed by the ...\Printername Spooldirectory, defaulting to ...\Printers Defaultdirectory if not set.

The 32-bit version will only place it in ...\Printers Defaultdirectory.

I've experimented with this a little, and I've found that a Delphi application also appears to ignore the "Spooldirectory" entry. I don't know whether this is a Borland bug, or a Windows bug or a Microsoft rethink.

The machine also gets used for office work, so I can't assume that all of the .SPL files in "DefaultSpooldirectory" are of interest to my application.

What I need is to have a reliable way of locating the precise path name to the .SPL file - without constructing the pathname by making assumptions such as the directory in which the file resides or the structure of its name. I can't find what appears to be an API call to do so, the nearest I can get is the job number returned in job_info_1 (or 2.)

I'm trying to make the application robust so that if Uncle Bill, over his Croissants and Orange Juice in the morning suddenly decides to allow a print job to be created just anywhere, and the spooler just gets notified of the job's presence and takes care of it, I don't have to change my application.

Similarly, if Bill and Dale, over a lunch of vegetable soup and croutons, decide that the best way to torture me is to fix their various systems to work as designed (as I am sure they have done in the past) then the files might start turning up in the logical directory.

I don't want to assume that the filename will be of the format 5digits.SPL (where the 5 digits are the zero-filled job number returned from EnumJobs) because if Uncle Bill, over a bedtime repast of cocoa with crackers and Wensleydale cheese decides that 100,000 spool entries is far too few and he needs to add another digit or two, or express the number in hex, or he can make a few more million by recycling the random filename generator he used for tempfiles, then I'll have to revamp the program again.

 
So it would seem that a simple API call to return the full pathname of a job on the spoolqueue is the answer. Personally, I'd have included it in the job_info_n structure, but Uncle Bill was in a bit of a mood that day, and didn't ask me. I fear this API doesn't exist.

...Bill
0
 
LVL 7

Author Comment

by:billious
ID: 8128830
Looks like no-one's got any more ideas - would have been easy for someone who's been there before!

I ended up building a Tstringlist of appropriate directories (Spooldirectory & Defaultspooldirectory items) and building the filename by taking the job number, padding it to length 5 with leading zeroes, adding '.SPL' to the end.

I can find the file by then looking for the filename so constructed in each of the directories in the Tstringlist.

It's not very satisfactory for the reasons I rambled on about before - but it'll have to do!

I'll ask that this question be closed because of the lack of a satisfactory solution, but I'll post a "points for" q in appreciation of your efforts.

Thanks

....Bill
0
 

Accepted Solution

by:
SpideyMod earned 0 total points
ID: 8129764
PAQ'd and points refunded.

SpideyMod
Community Support Moderator @Experts Exchange
0

Featured Post

Enroll in August's Course of the Month

August's CompTIA IT Fundamentals course includes 19 hours of basic computer principle modules and prepares you for the certification exam. It's free for Premium Members, Team Accounts, and Qualified Experts!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question