The following information is provided as is, and the authors take no responsibility for the correctness.

Windows Spooler Tips and Tricks

Administrators Secret Lunchbox

Try executing “rundll32 printui.dll,PrintUIEntry /?“, and you will discover all sorts of tasty managment functions.

Spooler Stress Testing

Microsoft has included some nifty spooler stress test tools in their Windows Server System Reference Architecture (WSSRA).

The complete WSSRA including the tools can be download here: http://go.microsoft.com/fwlink/?LinkId=32645&clcid=0x409

  • Print Services Testing
    Instructions on the actual processes of testing the print services in WSSRA configurations. First, details of the test methodology are discussed, followed by an explanation of the associated test tools used specifically in this service. Then, test case specifications are listed and results are presented and discussed.

Maximum Private DEVMODE size?

On Windows 2000 the only upper limit in theory is due to the dmDriverExtra field (short) in public devmode. But in practice, there are legacy applications that assumed their own “big enough” devmode size. From our testing experience, we recommend the full DEVMODE size to be no more than 10K.

Windows 98 has a 2K limit.

Our testing showed that some legacy apps will crash if the full
DEVMODE size is over 12K. That's why we recommended the 10K size
(For Windows NT/2000/XP...).
//Printer Drivers -- Ask the Experts Online, November 2002 

PRINTER_INFO_2 results in ERROR_ACCESS_DENIED

When specifying Level 2 for GetPrinter, you might always receive an ERROR_ACCESS_DENIED, even if you provided PRINTER_ACCESS_ADMINISTER, READ_CONTROL or ACCESS_SYSTEM_SECURITY in the access mask used for OpenPrinter.

To sucessfully call GetPrinter for level 2, you should:

  1. Specify PRINTER_ALL_ACCESS for the ACCESS_MASK member of the PRINTER_DEFAULTS structure used with OpenPrinter.
  2. The pcbNeeded parameter should be zero initialized when calling GetPrinter with cbBuf specified as zero. This will provide you with the correct buffersize needed.

Determining the State of a Physical Printer

The status of printers and print jobs are updated by the Win32 Spooler during the despool of a print job. At all other times, when that printer is not despooling and reports no state information, the printer is considered to be ready and idle.

There is one fundamental premise that must be true to determine the 
state of a physical printer: the Spooler must be attempting to send 
a print job to the physical printer. This is the only time the state
of the printer is reported by the port monitor. 

For information on how to get status informations se the Microsoft Knowledge Base article Q160129.

Using ReadPrinter for BIDI communication

Just read in a post from Jeffrey Tan that BIDI communication with the printer is actually possible.

I always thought that this was impossible, as Windows restrics the read access to any ports to language monitors only.

But now it turns out, you can work around this, by creating a dummy job, and then opening a handle to that job with OpenPrinter. You ofcourse still need the port monitor to support bidi.

#define BUFSIZE 256

BOOL TestReadPrinterWithJob(LPSTR szPrinterName)
{
  HANDLE hPrinter = NULL;
  HANDLE hPrinterJob = NULL;
  DWORD dwBytesRead;
  LPVOID lpBytes = NULL;
  DOC_INFO_1 dc;
  DWORD jobid;
  TCHAR jobStr[100];
  // Open a handle to the printer.
  if (!OpenPrinter(szPrinterName, &hPrinter, NULL))
  {
    PrintError(GetLastError(), "OpenPrinter");
    return FALSE;
  }
  // We can't read from a printer handle, but we can read from
  // a printer job handle, So the trick is to create a Job using
  // StartDocPrinter, then open a handle to the printer job...
  ZeroMemory(&dc, sizeof(DOC_INFO_1));
  dc.pDocName="Dummy job";
  jobid = StartDocPrinter(hPrinter,1,(LPSTR)&dc); // start a Doc 
  if (jobid == 0)
  {
    ClosePrinter(hPrinter);
    PrintError(GetLastError(), "OpenPrinter");
    return FALSE;
  }
  // Open handle to the printer job...
  wsprintf(jobStr, "%s,Job %i", szPrinterName, jobid);
  if (!OpenPrinter(jobStr, &hPrinterJob, NULL))
  {
    ClosePrinter(hPrinter);
    PrintError(GetLastError(), "OpenPrinter Job");
    return FALSE;
  }
  // Allocate a buffer to read printer data into...
  lpBytes = (LPVOID)malloc(BUFSIZE);
  if (!lpBytes)
  {
    PrintError(GetLastError(), "malloc");
    ClosePrinter(hPrinter);
    ClosePrinter(hPrinterJob);
    return FALSE;
  }
  // Try ReadPrinter...
  SetLastError(0);
  if (!ReadPrinter(hPrinterJob, lpBytes, BUFSIZE, &dwBytesRead))
  {
    PrintError(GetLastError(), "ReadPrinter");
    ClosePrinter(hPrinter);
    ClosePrinter(hPrinterJob);
    if (lpBytes)
      free(lpBytes);
    return FALSE;
  }
  else
  {
    printf("%i bytes successfully read by ReadPrinter (%i attempted)\n",
    dwBytesRead, BUFSIZE);
  }
  // Clean up...
  ClosePrinter(hPrinterJob);
  EndDocPrinter(hPrinter); // end the doc 
  ClosePrinter(hPrinter);
  if (lpBytes)
    free(lpBytes);
  return TRUE;
}

void PrintError( DWORD dwError, LPCSTR lpString )
{
  #define MAX_MSG_BUF_SIZE 512
  char *msgBuf;
  DWORD cMsgLen;
  cMsgLen = FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, 
    NULL, dwError, MAKELANGID(0, SUBLANG_ENGLISH_US), 
    (LPTSTR) &msgBuf, MAX_MSG_BUF_SIZE, NULL);
  printf( "%s Error [%d]:: %s\n", lpString, dwError, msgBuf );
  LocalFree( msgBuf );
  #undef MAX_MSG_BUF_SIZE
}

 
winspool/tips_and_tricks.txt · Last modified: 2010/05/07 14:21 by 192.168.11.1
 

All text is available under the terms of the GNU Free Documentation License (see Copyrights for details). Disclaimers

Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki