#include "procs.hxx" #pragma hdrstop /*++ Copyright (c) 1996 Microsoft Corporation All rights reserved Module Name: PrintWrp.c Abstract: Wide end to Win95 Ansi printing APIs Author: Felix Wong (t-felixw) Environment: Revision History: --*/ #include "dswarn.h" #include #include #include #include typedef struct _SPOOL *PSPOOL; typedef struct _NOTIFY *PNOTIFY; typedef struct _NOTIFY { PNOTIFY pNext; HANDLE hEvent; // event to trigger on notification DWORD fdwFlags; // flags to watch for DWORD fdwOptions; // PRINTER_NOTIFY_* DWORD dwReturn; // used by WPC when simulating FFPCN PSPOOL pSpool; } NOTIFY; typedef struct _SPOOL { DWORD signature; HANDLE hPrinter; HANDLE hFile; DWORD JobId; LPBYTE pBuffer; DWORD cbBuffer; DWORD Status; DWORD fdwFlags; DWORD cCacheWrite; DWORD cWritePrinters; DWORD cFlushBuffers; DWORD dwTickCount; DWORD dwCheckJobInterval; PNOTIFY pNotify; } SPOOL; #define SPOOL_STATUS_ANSI 0x00000004 #define MIN_DEVMODE_SIZEW 72 #define MIN_DEVMODE_SIZEA 40 #define NULL_TERMINATED 0 BOOL ConvertAnsiToUnicodeBuf( LPBYTE pAnsiBlob, LPBYTE pUnicodeBlob, DWORD dwAnsiSize, DWORD dwUnicodeSize, PDWORD pOffsets ); BOOL bValidDevModeW( const DEVMODEW *pDevModeW ) /*++ Routine Description: Check whether a devmode is valid to be RPC'd across to the spooler. Arguments: pDevMode - DevMode to check. Return Value: TRUE - Devmode can be RPC'd to spooler. FALSE - Invalid Devmode. --*/ { if( !pDevModeW ){ return FALSE; } if( pDevModeW->dmSize < MIN_DEVMODE_SIZEW ){ // // The only valid case is if pDevModeW is NULL. If it's // not NULL, then a bad devmode was passed in and the // app should fix it's code. // ASSERT( pDevModeW->dmSize >= MIN_DEVMODE_SIZEW ); return FALSE; } return TRUE; } LPSTR AllocateAnsiString( LPWSTR pPrinterName ) { LPSTR pAnsiString; if (!pPrinterName) return NULL; pAnsiString = (LPSTR)LocalAlloc(LPTR, wcslen(pPrinterName)*sizeof(CHAR) + sizeof(CHAR)); if (pAnsiString) UnicodeToAnsiString(pPrinterName, pAnsiString, NULL_TERMINATED); return pAnsiString; } LPSTR FreeAnsiString( LPSTR pAnsiString ) { if (!pAnsiString) return NULL; return (LPSTR)LocalFree(pAnsiString); } /***************************** Function Header ****************************** * AllocateAnsiDevMode * Allocate an ANSI version of the DEVMODE structure, and optionally * copy the contents of the ANSI version passed in. * * RETURNS: * Address of newly allocated structure, 0 if storage not available. * * HISTORY: * 09:23 on 10-Aug-92 -by- Lindsay Harris [lindsayh] * Made it usable. * * Originally "written" by DaveSn. * ***************************************************************************/ LPDEVMODEA AllocateAnsiDevMode( LPDEVMODEW pUNICODEDevMode ) { LPDEVMODEA pAnsiDevMode; LPBYTE p1, p2; DWORD dwSize; // // If the devmode is NULL, then return NULL -- KrishnaG // if ( !pUNICODEDevMode || !pUNICODEDevMode->dmSize ) { return NULL; } ASSERT( bValidDevModeW( pUNICODEDevMode )); // // Determine output structure size. This has two components: the // DEVMODEW structure size, plus any private data area. The latter // is only meaningful when a structure is passed in. // dwSize = pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra + sizeof(DEVMODEA) - sizeof(DEVMODEW); pAnsiDevMode = (LPDEVMODEA) LocalAlloc(LPTR, dwSize); if( !pAnsiDevMode ) { return NULL; /* This is bad news */ } // // Copy dmDeviceName which is a string // UnicodeToAnsiString(pUNICODEDevMode->dmDeviceName, (LPSTR)(pAnsiDevMode->dmDeviceName), ComputeMaxStrlenW(pUNICODEDevMode->dmDeviceName, sizeof pUNICODEDevMode->dmDeviceName)); // // Does the devmode we got have a dmFormName? (Windows 3.1 had // DevMode of size 40 and did not have dmFormName) // if ( (LPBYTE)pUNICODEDevMode + pUNICODEDevMode->dmSize > (LPBYTE) pUNICODEDevMode->dmFormName ) { // // Copy everything between dmDeviceName and dmFormName // p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName + sizeof(pUNICODEDevMode->dmDeviceName); p2 = (LPBYTE) pUNICODEDevMode->dmFormName; CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName + sizeof(pAnsiDevMode->dmDeviceName), p1, p2 - p1); // // Copy dmFormName which is a string // UnicodeToAnsiString(pUNICODEDevMode->dmFormName, (LPSTR)(pAnsiDevMode->dmFormName), ComputeMaxStrlenW(pUNICODEDevMode->dmFormName, sizeof pUNICODEDevMode->dmFormName)); // // Copy everything after dmFormName // p1 = (LPBYTE) pUNICODEDevMode->dmFormName + sizeof(pUNICODEDevMode->dmFormName); p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra; CopyMemory((LPBYTE) pAnsiDevMode->dmFormName + sizeof(pAnsiDevMode->dmFormName), p1, p2 - p1); pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize + sizeof(DEVMODEA) - sizeof(DEVMODEW); } else { // // Copy everything after dmDeviceName // p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName + sizeof(pUNICODEDevMode->dmDeviceName); p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra; CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName + sizeof(pAnsiDevMode->dmDeviceName), p1, p2-p1); pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize + sizeof(pAnsiDevMode->dmDeviceName) - sizeof(pUNICODEDevMode->dmDeviceName); } ASSERT(pAnsiDevMode->dmDriverExtra == pUNICODEDevMode->dmDriverExtra); return pAnsiDevMode; } /************************** Function Header ****************************** * CopyUnicodeDevModeFromAnsiDevMode * Converts the ANSI version of the DEVMODE to the UNICODE version. * * RETURNS: * Nothing. * * HISTORY: * 09:57 on 10-Aug-92 -by- Lindsay Harris [lindsayh] * This one actually works! * * Originally dreamed up by DaveSn. * **************************************************************************/ void CopyUnicodeDevModeFromAnsiDevMode( LPDEVMODEW pUNICODEDevMode, /* Filled in by us */ LPDEVMODEA pAnsiDevMode /* Source of data to fill above */ ) { LPBYTE p1, p2, pExtra; WORD dmSize, dmDriverExtra; // // NOTE: THE TWO INPUT STRUCTURES MAY BE THE SAME. // dmSize = pAnsiDevMode->dmSize; dmDriverExtra = pAnsiDevMode->dmDriverExtra; pExtra = (LPBYTE) pAnsiDevMode + pAnsiDevMode->dmSize; // // Copy dmDeviceName which is a string // AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmDeviceName), (pUNICODEDevMode->dmDeviceName), ComputeMaxStrlenA((LPSTR)(pAnsiDevMode->dmDeviceName), sizeof pUNICODEDevMode->dmDeviceName)); // // Does the devmode we got have a dmFormName? (Windows 3.1 had // DevMode of size 40 and did not have dmFormName) // if ( (LPBYTE)pAnsiDevMode + dmSize > (LPBYTE) pAnsiDevMode->dmFormName ) { // // Copy everything between dmDeviceName and dmFormName // p1 = (LPBYTE) pAnsiDevMode->dmDeviceName + sizeof(pAnsiDevMode->dmDeviceName); p2 = (LPBYTE) pAnsiDevMode->dmFormName; MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName + sizeof(pUNICODEDevMode->dmDeviceName), p1, p2 - p1); // // Copy dmFormName which is a string // AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmFormName), pUNICODEDevMode->dmFormName, ComputeMaxStrlenA((LPSTR)pAnsiDevMode->dmFormName, sizeof pUNICODEDevMode->dmFormName)); // // Copy everything after dmFormName // p1 = (LPBYTE) pAnsiDevMode->dmFormName + sizeof(pAnsiDevMode->dmFormName); p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra; MoveMemory((LPBYTE) pUNICODEDevMode->dmFormName + sizeof(pUNICODEDevMode->dmFormName), p1, p2 - p1); pUNICODEDevMode->dmSize = dmSize + sizeof(DEVMODEW) - sizeof(DEVMODEA); } else { // // Copy everything after dmDeviceName // p1 = (LPBYTE) pAnsiDevMode->dmDeviceName + sizeof(pAnsiDevMode->dmDeviceName); p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra; MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName + sizeof(pUNICODEDevMode->dmDeviceName), p1, p2 - p1); pUNICODEDevMode->dmSize = dmSize + sizeof(pUNICODEDevMode->dmDeviceName) - sizeof(pAnsiDevMode->dmDeviceName); } ASSERT(pUNICODEDevMode->dmDriverExtra == dmDriverExtra); return; } void ConvertAnsiToUnicodeStrings( LPBYTE pStructure, LPDWORD pOffsets ) { register DWORD i=0; LPSTR pAnsi; LPWSTR pUnicode; while (pOffsets[i] != -1) { pAnsi = *(LPSTR *)(pStructure+pOffsets[i]); if (pAnsi) { pUnicode = (LPWSTR)LocalAlloc( LPTR, strlen(pAnsi)*sizeof(WCHAR)+ sizeof(WCHAR)); if (pUnicode) { AnsiToUnicodeString(pAnsi, pUnicode, NULL_TERMINATED); *(LPWSTR *)(pStructure+pOffsets[i]) = pUnicode; LocalFree(pAnsi); } } i++; } } LPBYTE AllocateAnsiStructure( LPBYTE pUnicodeStructure, DWORD cbStruct, LPDWORD pOffsets ) { DWORD i, j; LPSTR *ppAnsiString; LPWSTR *ppUnicodeString; LPBYTE pAnsiStructure; if (!pUnicodeStructure) { return NULL; } pAnsiStructure = (LPBYTE)LocalAlloc(LPTR, cbStruct); if (pAnsiStructure) { memcpy(pAnsiStructure, pUnicodeStructure, cbStruct); for (i = 0 ; pOffsets[i] != -1 ; ++i) { ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[i]); ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[i]); *ppAnsiString = AllocateAnsiString(*ppUnicodeString); if (*ppUnicodeString && !*ppAnsiString) { for( j = 0 ; j < i ; ++j) { ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[j]); FreeAnsiString(*ppAnsiString); } LocalFree(pAnsiStructure); pAnsiStructure = NULL; break; } } } return pAnsiStructure; } void FreeAnsiStructure( LPBYTE pAnsiStructure, LPDWORD pOffsets ) { DWORD i=0; if ( pAnsiStructure == NULL ) { return; } while (pOffsets[i] != -1) { FreeAnsiString(*(LPSTR *)(pAnsiStructure+pOffsets[i])); i++; } LocalFree( pAnsiStructure ); } BOOL EnumJobsW( HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { DWORD i, cbStruct, *pOffsets; switch (Level) { case 1: pOffsets = JobInfo1StringsA; cbStruct = sizeof(JOB_INFO_1W); break; case 2: pOffsets = JobInfo2StringsA; cbStruct = sizeof(JOB_INFO_2W); break; case 3: return EnumJobsA( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (EnumJobsA(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned)) { i=*pcReturned; while (i--) { ConvertAnsiToUnicodeStrings(pJob, pOffsets); // // Convert the devmode in place for INFO_2. // if( Level == 2 ){ PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob; if( pJobInfo2->pDevMode ){ CopyUnicodeDevModeFromAnsiDevMode( (LPDEVMODEW)pJobInfo2->pDevMode, (LPDEVMODEA)pJobInfo2->pDevMode); } } pJob += cbStruct; } return TRUE; } else return FALSE; } BOOL GetPrinterW( HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; switch (Level) { //case STRESSINFOLEVEL: // pOffsets = PrinterInfoStressOffsetsA; // break; case 1: pOffsets = PrinterInfo1StringsA; break; case 2: pOffsets = PrinterInfo2StringsA; break; case 3: pOffsets = PrinterInfo3StringsA; break; case 4: pOffsets = PrinterInfo4StringsA; break; case 5: pOffsets = PrinterInfo5StringsA; break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (GetPrinterA(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) { if (pPrinter) { ConvertAnsiToUnicodeStrings(pPrinter, pOffsets); if ((Level == 2) && pPrinter) { PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *)pPrinter; if (pPrinterInfo2->pDevMode) CopyUnicodeDevModeFromAnsiDevMode( (LPDEVMODEW)pPrinterInfo2->pDevMode, (LPDEVMODEA)pPrinterInfo2->pDevMode); } } return TRUE; } return FALSE; } BOOL SetPrinterW( HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command ) { LPBYTE pAnsiStructure; /* Ansi version of input data */ DWORD cbStruct; /* Size of the output structure */ DWORD *pOffsets; /* -1 terminated list of addresses */ DWORD ReturnValue=FALSE; switch (Level) { case 0: // // This could be 2 cases. STRESSINFOLEVEL, or the real 0 level. // If Command is 0 then it is STRESSINFOLEVEL, else real 0 level // /* if ( !Command ) { pOffsets = PrinterInfoStressStringsA; cbStruct = sizeof( PRINTER_INFO_STRESSA ); } */ break; case 1: pOffsets = PrinterInfo1StringsA; cbStruct = sizeof( PRINTER_INFO_1W ); break; case 2: pOffsets = PrinterInfo2StringsA; cbStruct = sizeof( PRINTER_INFO_2W ); break; case 3: pOffsets = PrinterInfo3StringsA; cbStruct = sizeof( PRINTER_INFO_3); break; case 4: pOffsets = PrinterInfo4StringsA; cbStruct = sizeof( PRINTER_INFO_4W ); break; case 5: pOffsets = PrinterInfo5StringsA; cbStruct = sizeof( PRINTER_INFO_5W ); break; case 6: break; default: SetLastError( ERROR_INVALID_LEVEL ); return FALSE; } // // The structure needs to have its CONTENTS converted from // ANSI to Unicode. The above switch() statement filled in // the two important pieces of information needed to accomplish // this goal. First is the size of the structure, second is // a list of the offset within the structure to UNICODE // string pointers. The AllocateUnicodeStructure() call will // allocate a wide version of the structure, copy its contents // and convert the strings to Unicode as it goes. That leaves // us to deal with any other pieces needing conversion. // // // If Level == 0 and Command != 0 then pPrintert is a DWORD // if ( Level == 6 || (!Level && Command) ) { if ( Level == 6 || Command == PRINTER_CONTROL_SET_STATUS ) pAnsiStructure = pPrinter; else pAnsiStructure = NULL; } else { pAnsiStructure = AllocateAnsiStructure(pPrinter, cbStruct, pOffsets); if (pPrinter && !pAnsiStructure) return FALSE; } #define pPrinterInfo2A ((LPPRINTER_INFO_2A)pAnsiStructure) #define pPrinterInfo2W ((LPPRINTER_INFO_2W)pPrinter) // The Level 2 structure has a DEVMODE struct in it: convert now if ( Level == 2 && pAnsiStructure && pPrinterInfo2W->pDevMode ) { if( bValidDevModeW( pPrinterInfo2W->pDevMode )){ pPrinterInfo2A->pDevMode = AllocateAnsiDevMode( pPrinterInfo2W->pDevMode ); if( !pPrinterInfo2A->pDevMode) { FreeAnsiStructure(pAnsiStructure, pOffsets); return FALSE; } } } ReturnValue = SetPrinterA( hPrinter, Level, pAnsiStructure, Command ); // Free the DEVMODE we allocated (if we did!), then the // the Unicode structure and its contents. if (Level == 2 && pAnsiStructure && pPrinterInfo2A->pDevMode ) { LocalFree( pPrinterInfo2A->pDevMode ); } // // STRESS_INFO and Levels 1-5 // if ( Level != 6 && (Level || !Command) ) FreeAnsiStructure( pAnsiStructure, pOffsets ); #undef pPrinterInfo2A #undef pPrinterInfo2W return ReturnValue; } BOOL SetJobW( HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command ) { BOOL ReturnValue=FALSE; LPBYTE pAnsiStructure=NULL; LPDEVMODEA pDevModeA = NULL; DWORD cbStruct; DWORD *pOffsets; switch (Level) { case 0: break; case 1: pOffsets = JobInfo1StringsA; cbStruct = sizeof(JOB_INFO_1W); break; case 2: pOffsets = JobInfo2StringsA; cbStruct = sizeof(JOB_INFO_2W); break; case 3: return SetJobA( hPrinter, JobId, Level, pJob, Command ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (Level) { pAnsiStructure = AllocateAnsiStructure(pJob, cbStruct, pOffsets); if (pJob && !pAnsiStructure) return FALSE; } if ( Level == 2 && pAnsiStructure && pJob ) { if( bValidDevModeW( ((LPJOB_INFO_2W)pJob)->pDevMode )){ pDevModeA = AllocateAnsiDevMode(((LPJOB_INFO_2W)pJob)->pDevMode); if( !pDevModeA ){ ReturnValue = FALSE; goto Cleanup; } ((LPJOB_INFO_2A) pAnsiStructure)->pDevMode = pDevModeA; } } ReturnValue = SetJobA(hPrinter, JobId, Level, pAnsiStructure, Command); if ( pDevModeA ) { LocalFree(pDevModeA); } Cleanup: FreeAnsiStructure(pAnsiStructure, pOffsets); return ReturnValue; } BOOL GetJobW( HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; LPBYTE pJobA = NULL; DWORD cbNeededA = 0; DWORD cbBufA = 0; DWORD dwJobStructSizeW = 0; DWORD dwJobStructSizeA = 0; BOOL fRetval; switch (Level) { case 1: pOffsets = JobInfo1StringsA; dwJobStructSizeW = sizeof(JOB_INFO_1W); dwJobStructSizeA = sizeof(JOB_INFO_1A); break; case 2: pOffsets = JobInfo2StringsA; dwJobStructSizeW = sizeof(JOB_INFO_2W); dwJobStructSizeA = sizeof(JOB_INFO_2A); break; case 3: return GetJobA( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } // // GetJobA is broken. THis is a workaround here which will work // sometimes. The AV problem however goes away. // // Ramv bug fix: The user has passed in a certain amount of // unicode memory. This has to be appropriately translated into // equivalent ANSI memory. // // // The translation is to take the entire blob of memory and // subtract sizeof(JOB_INFO_2W) and then divide the remaining memory // into 2. // // we also have to contend with GetJobA's erroneous return values // when we pass in a buffer of sixe 0, it gives back wrong results // // // cbBufA = cbBuf > dwJobStructSizeW ? (cbBuf-dwJobStructSizeW)/sizeof(WCHAR) + dwJobStructSizeA : 64; pJobA = (LPBYTE)AllocADsMem( cbBufA); if (!pJobA){ goto error; } fRetval = GetJobA (hPrinter, JobId, Level, pJobA, cbBufA, &cbNeededA); if ( fRetval) { // // RamV bug fix. // The size that we get back is actually the size of // the ANSI array needed. We need our array to be larger for // unicode by an amount = (total lengths of all strings +1) // times the sizeof(WCHAR) // // // Looks like we have sufficient memory here for our operations // we need to copy the memory blob from Ansi to Unicode // // // Thanks to win95 returning erroneous values, we are forced // to fail this call even though it succeeded and send back // the cbNeededA value converted into the Unicode value // if (cbBuf == 0){ *pcbNeeded = 2*cbNeededA; // just being conservative here by // allocating a little more space than needed SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto error; } if (!ConvertAnsiToUnicodeBuf( pJobA, pJob, dwJobStructSizeA, dwJobStructSizeW, pOffsets)){ goto error; } // // Convert the devmode in place for INFO_2. // if( Level == 2 ){ PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob; if( pJobInfo2->pDevMode ){ CopyUnicodeDevModeFromAnsiDevMode( (LPDEVMODEW)pJobInfo2->pDevMode, (LPDEVMODEA)pJobInfo2->pDevMode); } } return TRUE; } else { // // RamV bug fix. // The size that we get back is actually the size of // the ANSI array needed. We need our array to be larger for // unicode by an amount = (total lengths of all strings +1) // times the sizeof(WCHAR) // if(cbNeededA) { // // we need to translate this into unicode terms // *pcbNeeded = dwJobStructSizeW + (cbBufA + cbNeededA - dwJobStructSizeA)*sizeof(WCHAR); } return FALSE; } error: if(pJobA) { FreeADsMem(pJobA); } return FALSE; } BOOL ConvertAnsiToUnicodeBuf( LPBYTE pAnsiBlob, LPBYTE pUnicodeBlob, DWORD dwAnsiSize, DWORD dwUnicodeSize, PDWORD pOffsets ) { DWORD i = 0; LPSTR pAnsi; LPBYTE pUnicode; LPBYTE pszString = pUnicodeBlob + dwUnicodeSize; LPBYTE pStringPos = NULL; memcpy(pUnicodeBlob, pAnsiBlob, dwAnsiSize); pUnicode = pszString; while (pOffsets[i] != -1) { pAnsi = *(LPSTR *)(pAnsiBlob + pOffsets[i]); if (!AnsiToUnicodeString((LPSTR)pAnsi, (LPWSTR)pUnicode, NULL_TERMINATED )){ return(FALSE); } pStringPos = pUnicodeBlob +pOffsets[i]; *((LPBYTE *)pStringPos) = pUnicode; pUnicode = pUnicode + (wcslen((LPWSTR)(pUnicode))+1)* sizeof(WCHAR); i++; } return(TRUE); } BOOL OpenPrinterW( LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault ) { BOOL ReturnValue = FALSE; LPSTR pAnsiPrinterName = NULL; PRINTER_DEFAULTSA AnsiDefaults={NULL, NULL, 0}; pAnsiPrinterName = AllocateAnsiString(pPrinterName); if (pPrinterName && !pAnsiPrinterName) goto Cleanup; if (pDefault) { AnsiDefaults.pDatatype = AllocateAnsiString(pDefault->pDatatype); if (pDefault->pDatatype && !AnsiDefaults.pDatatype) goto Cleanup; // // Milestones etc. 4.5 passes in a bogus devmode in pDefaults. // Be sure to validate here. // if( bValidDevModeW( pDefault->pDevMode )){ AnsiDefaults.pDevMode = AllocateAnsiDevMode( pDefault->pDevMode ); if( !AnsiDefaults.pDevMode ){ goto Cleanup; } } AnsiDefaults.DesiredAccess = pDefault->DesiredAccess; } ReturnValue = OpenPrinterA(pAnsiPrinterName, phPrinter, &AnsiDefaults); /* Ramv This code below causes AV. I have disabled it MattRim 1-10-00: Leaving this disabled. phPrinter is an opaque handle to an undocumented structure. Trying to manipulate it is a surefire way to cause AVs if a service pack/O.S. upgrade ever changes the implementation of this Win9x-internal structure. if (ReturnValue) { ((PSPOOL)*phPrinter)->Status |= SPOOL_STATUS_ANSI; } */ Cleanup: if (AnsiDefaults.pDevMode) LocalFree(AnsiDefaults.pDevMode); FreeAnsiString(AnsiDefaults.pDatatype); FreeAnsiString(pAnsiPrinterName); return ReturnValue; }