Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RawPrint utility eventually deteriorates to ICM data corruption and spooler hangup

6 views
Skip to first unread message

Thomas Alkire

unread,
Dec 17, 2002, 5:20:52 PM12/17/02
to
Hi,
The following code works fine for some time like up to a week or two but
eventually deteriorates where it causes a spool32 error on a non-network
situation or a spoolsv error on a network situation. Before it deteriorates
where the spooler actually hangs, the ICM data seems to be corrupted
because some of the colors in the DOS application (which drives this
WinConsoleApp utility) get corrupted. It seems to take a while for this
problem to show up. I've had this fail on both Win98SE and on Server 2000
os's. My EnumPrinters statement originally called for PRINTER_ENUM_LOCAL
(which I've corrected ) but I can't see how that would corrupt the
PrinterInformation since I'm just getting a PrinterName with it.

John Hornick, you are probably my best hope to know if there is something
wrong here that would cause a DEVMODE problem or some other subtle problem
that builds up over time.

regards,
thomas

// Program flow:
// Console program where format = <ProgName> <FileName> <PortCode> where
PortCode is
// decoded with a switch-case statement to get the PortName ie "LPT2:".
// Next Main calls GetPrinterFromPort ( LPTSTR szPortName )
// Using the PortName an EnumPrinters is used to get the PrinterName
connected to
// the decoded PortName.
// Next Main calls ReadFileWithAlloc( LPTSTR szFileName, LPDWORD pdwSize,
LPBYTE *ppBytes )
// to get the file read into an allocated buffer pBytes.
// Next Main calls RawDataToPrinter( LPTSTR PrinterName, LPBYTE lpData,
DWORD dwCount )
// to get that buffer printed to the PrinterName. After using OpenPrinter
and GetPrinter to
// get the printer handle it starts a print job and send that buffer lpData
to the printer.


#include <Windows.h>
#include <StdIO.h>
#include <memory.h>
#include <winspool.h>

void GetPrinterFromPort ( LPTSTR );

LPTSTR PrinterName ;
LPTSTR ParmFileName ;
LPTSTR szFileName ;
char *cPort = "LPT1"; // set default value
int iParm = 1; // set default value

// **********************************************************************
// PrintError - uses printf() to display error code information
//
// Params:
// dwError - the error code, usually from GetLastError()
// lpString - some caller-defined text to print with the error info
//
// Returns: void
// **********************************************************************
void PrintError( DWORD dwError, LPCTSTR lpString )
{
#define MAX_MSG_BUF_SIZE 512
TCHAR *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( TEXT("%s Error [%d]:: %s\n"), lpString, dwError, msgBuf );
LocalFree( msgBuf );
#undef MAX_MSG_BUF_SIZE
}// end PrintError


// **********************************************************************
// ReadFileWithAlloc - allocates memory for and reads contents of a file
//
// Params:
// szFileName - NULL terminated string specifying file name
// pdwSize - address of variable to receive file bytes size
// ppBytes - address of pointer which will be allocated and contain
file bytes
//
// Returns: TRUE for success, FALSE for failure.
//
// Notes: Caller is responsible for freeing the memory using GlobalFree()
//
// **********************************************************************
BOOL ReadFileWithAlloc( LPTSTR szFileName, LPDWORD pdwSize, LPBYTE
*ppBytes )
{
HANDLE hFile;
DWORD dwBytes;
BOOL bSuccess = FALSE;

// Validate pointer parameters
if( ( pdwSize == NULL ) || ( ppBytes == NULL ) )
return FALSE;

// Open the file for reading
hFile = CreateFile( szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );

if( hFile == INVALID_HANDLE_VALUE ) {
PrintError( GetLastError(), TEXT("CreateFile()") );
return FALSE;
} //endif

// How big is the file?
*pdwSize = GetFileSize( hFile, NULL );

// check if size is correct
if( *pdwSize == (DWORD)-1 )
PrintError( GetLastError(), TEXT("GetFileSize()") );
else {
// Allocate the memory
*ppBytes = (LPBYTE)GlobalAlloc( GPTR, *pdwSize );

// check if allocating memory failed
if( *ppBytes == NULL )
PrintError( GetLastError(), TEXT("Failed to allocate memory\n") );

else {
// Read the file into the newly allocated memory
bSuccess = ReadFile( hFile, *ppBytes, *pdwSize, &dwBytes, NULL );
if( ! bSuccess )
PrintError( GetLastError(), TEXT("ReadFile()") );

}
}
// Clean up
CloseHandle( hFile );
return bSuccess;
}// End ReadFileWithAlloc


// **********************************************************************
// RawDataToPrinter - sends binary data directly to a printer
//
// Params:
// szPrinterName - NULL terminated string specifying printer name
// lpData - Pointer to raw data bytes
// dwCount - Length of lpData in bytes
//
// Returns: TRUE for success, FALSE for failure.
//
// **********************************************************************
BOOL RawDataToPrinter( LPTSTR PrinterName, LPBYTE lpData, DWORD dwCount )
{
HANDLE hPrinter;
DOC_INFO_1 DocInfo; // required for NT/2000/XP; and works with 95/98/Me
DWORD dwJob;
DWORD dwBytesWritten;

// Need a handle to the printer.
if( ! OpenPrinter( PrinterName, &hPrinter, NULL ) ) {
PrintError( GetLastError(), TEXT("OpenPrinter") );
return FALSE;
}

// Fill in the structure with info about this "document."
DocInfo.pDocName = TEXT(szFileName);
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = TEXT("RAW");

// Inform the spooler the document is beginning.
if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 ) {
PrintError( GetLastError(), TEXT("StartDocPrinter") );
ClosePrinter( hPrinter );
return FALSE;
}

// Informs the spooler that a page is about to be printed on the specified
printed
if( ! StartPagePrinter( hPrinter ) ) {
PrintError( GetLastError(), TEXT("StartPagePrinter") );
EndDocPrinter( hPrinter );
ClosePrinter( hPrinter );
return FALSE;
}

// Send the data to the printer.
if( ! WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten ) ) {
PrintError( GetLastError(), TEXT("WritePrinter") );
EndPagePrinter( hPrinter );
EndDocPrinter( hPrinter );
ClosePrinter( hPrinter );
return FALSE;
}

// End the page.
if( ! EndPagePrinter( hPrinter ) ) {
PrintError( GetLastError(), TEXT("EndPagePrinter") );
EndDocPrinter( hPrinter );
ClosePrinter( hPrinter );
return FALSE;
}

// Inform the spooler that the document is ending.
if( ! EndDocPrinter( hPrinter ) ) {
PrintError( GetLastError(), TEXT("EndDocPrinter") );
ClosePrinter( hPrinter );
return FALSE;
}
// Tidy up the printer handle.
ClosePrinter( hPrinter );

// Check to see if correct number of bytes were written.
if( dwBytesWritten != dwCount ) {
printf( TEXT("Wrote %d bytes instead of requested %d bytes.\n"),
dwBytesWritten, dwCount );
return FALSE;
}
return TRUE;
}// End RawDataToPrinter


// **********************************************************************
// main - entry point for this console application
//
// Params:
// argc - count of command line arguments
// argv - array of NULL terminated command line arguments
//
// Returns: 0 for success, non-zero for failure.
//
// Command line: c:\>RawPrint FileName PortCode
// sends raw data file to printer using spooler APIs
// written oct 2002 TBA
// argv[1]= file
// argv[2]= portcode
// **********************************************************************
int main( int argc, char* argv[] )
{
LPBYTE pBytes = NULL;
DWORD dwSize = 0;
szFileName = argv[1];


printf( TEXT("PrnForms.exe \nCopyright 2002 by Voyager 10.\n\n\n") );


if( argc != 3 )

return printf( TEXT("Syntax: %s <FileName> <PortCode>\n"), argv[0] );

if (strlen(argv[2]) < 2)
{
iParm = atoi(argv[2]); // convert 2nd parm to integer
switch (iParm) // decode the integer to a portname
{
case 1 :
cPort = "LPT1:";
break;
case 2 :
cPort = "LPT2:";
break;
case 3 :
cPort = "COM1:";
break;
case 4 :
cPort = "COM2:";
break;
case 5 :
cPort = "COM3:";
break;
case 6 :
cPort = "COM4:";
break;
case 7 :
cPort = "EPUSB1:";
break;
}


//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//
// Call this routine to get the PrinterName on the desired port
// and pass value to PrinterName
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
GetPrinterFromPort ( cPort );

}
else
{
PrinterName = argv[2];
}

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//
// Reading file and error handling routines
//
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
// ============Feedback msg to user about filename and printername
=====================
// file
printer
printf( TEXT("Attempting to send file [%s] to printer [%s].\n"), argv[1],
PrinterName );

// ============Read the File into pBytes =====================
// fileName, FileSize, pointerToFileName
if( ! ReadFileWithAlloc( szFileName,
&dwSize,
&pBytes ) )
return printf( TEXT("Failed to allocate memory for and read file
[%s].\n"), ParmFileName );

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//
// Start the printing routines
//
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&


// ============Print the RAW DATA=====================
// PrinterName, pointerToFileName, FileSize
if( ! RawDataToPrinter( PrinterName, pBytes, dwSize ) )
printf( TEXT("Failed to send data to printer.\n") );
else
printf( TEXT("Data sent to printer.\n") );

// release memory used in RawDataToPrinter
GlobalFree( (HGLOBAL)pBytes );

return 0;
}// end main

//code from SelectPrintFromSuppliedPortName.cpp
#include <windows.h>
#include <iostream.h>
#include <process.h>
#include <winspool.h>
#include <stdio.h>
extern LPTSTR PrinterName ;

//********************************************************
// SelectPrinter
// Get a list of printers and match it from supplied port
//********************************************************
void GetPrinterFromPort ( LPTSTR szPortName )
{
DWORD dwSizeNeeded;
DWORD dwNumItems;
DWORD dwItem;
LPPRINTER_INFO_2 lpInfo = NULL;
char mybuff[] = "n";

// Get buffer size
EnumPrinters ( PRINTER_ENUM_NAME, NULL, 2, NULL, 0, &dwSizeNeeded,
&dwNumItems );

// allocate memory
lpInfo = (LPPRINTER_INFO_2)HeapAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY,
dwSizeNeeded );
if ( lpInfo == NULL )
{
cout << "Not enough memory\n" ;
} //endif

// Calling EnumPrinters to poll for connected Local printers
if ( EnumPrinters (
PRINTER_ENUM_NAME, // what to enumerate (in)- local will enum local
printers
NULL, // printer name (in)- NULL ->get all printers
2, // level (in)- 2 will work for 9x,me -NT?
(LPBYTE)lpInfo, // buffer (out)-memory for this allocated above
dwSizeNeeded, // size of buffer (in)
&dwSizeNeeded, // returns size (out)
&dwNumItems // return num. items (out)
) == 0 ) {
// failed !!!!!
cout << "EnumPrinters() Failed with error: \n" << GetLastError() ;
} //endif

//*********************************************
// get the dwItem for the matching portname
//*********************************************
printf( " portcode passed is %s \n", szPortName );

for ( dwItem = 0; dwItem < dwNumItems; dwItem++ ){
printf( "Item=[%d] Printername=[%s] Portname=[%s]\n",
dwItem, lpInfo[dwItem].pPrinterName, lpInfo[dwItem].pPortName );
if ( strcmp(lpInfo[dwItem].pPortName , szPortName)==0 ) {
printf( "\n\nMatched on item=[%d] printername=[%s] Portname=[%s]\n",
dwItem, lpInfo[dwItem].pPrinterName ,lpInfo[dwItem].pPortName);
PrinterName = lpInfo[dwItem].pPrinterName;
// strcpy(PrinterName , lpInfo[dwItem].pPrinterName);
printf( "\n\nPrinterName=[%s]\n", PrinterName);
break;
} // endif
} // next

// free memory
HeapFree ( GetProcessHeap (), 0, lpInfo );

} // end of GetPrinterFromPort


John Hornick [MS]

unread,
Dec 18, 2002, 10:30:04 AM12/18/02
to
Hi,

> The following code works fine for some time like up to a week or two but
> eventually deteriorates where it causes a spool32 error on a non-network
> situation or a spoolsv error on a network situation. Before it
deteriorates
> where the spooler actually hangs, the ICM data seems to be corrupted
> because some of the colors in the DOS application (which drives this
> WinConsoleApp utility) get corrupted. It seems to take a while for this
> problem to show up. I've had this fail on both Win98SE and on Server 2000
> os's. My EnumPrinters statement originally called for PRINTER_ENUM_LOCAL
> (which I've corrected ) but I can't see how that would corrupt the
> PrinterInformation since I'm just getting a PrinterName with it.
>
> John Hornick, you are probably my best hope to know if there is something
> wrong here that would cause a DEVMODE problem or some other subtle problem
> that builds up over time.

<code snipped>


That's a lot of code. Have you run it under BoundsChecker to see if it
is leaking? Otherwise, you could use the Application Verifier to look
for heap-related problems. See http://support.microsoft.com/?id=286568

Thanks,
- John
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
Visit http://www.microsoft.com/security for current information on security.

0 new messages