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
> 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.