• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 624
  • Last Modified:

Spooler job number and filenames

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
billious
Asked:
billious
1 Solution
 
MotazCommented:
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
 
DjamDCommented:
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
 
DjamDCommented:
Oops,
i forgot to mention that i was talking about the PrintJobsNumber function.

Cordially,
DjamD
0
[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

 
billiousAuthor Commented:
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
 
billiousAuthor Commented:
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
 
SpideyModCommented:
PAQ'd and points refunded.

SpideyMod
Community Support Moderator @Experts Exchange
0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now