/*++ Copyright (c) 1990-1994 Microsoft Corporation All rights reserved Module Name: winspla.c Abstract: Ansi end to winspool.drv Author: Environment: User Mode -Win32 Revision History: amaxa July 2000 - Modified GetPrinterData(Ex)A and SetPrinterData(Ex)A to have the same behavior like the unicode functions. --*/ #include "precomp.h" #pragma hdrstop #include "client.h" #include "defprn.h" #include "winsprlp.h" typedef int (FAR WINAPI *INT_FARPROC)(); typedef struct { BOOL bOsVersionEx; union { OSVERSIONINFOW *pOsVersion; OSVERSIONINFOEXW *pOsVersionEx; } Unicode; union { OSVERSIONINFOA *pOsVersion; OSVERSIONINFOEXA *pOsVersionEx; } Ansi; } OSVERSIONWRAP; WCHAR *szCurDevMode = L"Printers\\DevModes2"; /* Make sure we have a prototype (in winspool.h): */ BOOL KickoffThread( LPWSTR pName, HWND hWnd, LPWSTR pPortName, INT_FARPROC pfn ); LPWSTR AllocateUnicodeStringWithSize( LPSTR pPrinterName, DWORD cbBytes // total number of bytes in input MULTI_SZ, incl. NULLs ); VOID ValidatePaperFields( LPCWSTR pUnicodeDeviceName, LPCWSTR pUnicodePort, LPDEVMODEW pDevModeIn ); #define NULL_TERMINATED 0 DWORD UnicodeToAnsi( IN LPBYTE pUnicode, IN DWORD cchUnicode, IN OUT LPBYTE pData, IN DWORD cbData, IN OUT DWORD *pcbCopied OPTIONAL ); /* AnsiToUnicodeString * * Parameters: * * pAnsi - A valid source ANSI string. * * pUnicode - A pointer to a buffer large enough to accommodate * the converted string. * * StringLength - The length of the source ANSI string. * If 0 (NULL_TERMINATED), the string is assumed to be * null-terminated. * * Return: * * The return value from MultiByteToWideChar, the number of * wide characters returned. * * * andrewbe, 11 Jan 1993 */ INT AnsiToUnicodeString( LPSTR pAnsi, LPWSTR pUnicode, DWORD StringLength ) { INT iReturn; if( StringLength == NULL_TERMINATED ) StringLength = strlen( pAnsi ); iReturn = MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, pAnsi, StringLength + 1, pUnicode, StringLength + 1 ); // // Ensure NULL termination. // pUnicode[StringLength] = 0; return iReturn; } /* UnicodeToAnsiString * * Parameters: * * pUnicode - A valid source Unicode string. * * pANSI - A pointer to a buffer large enough to accommodate * the converted string. * * StringLength - The length of the source Unicode string. * If 0 (NULL_TERMINATED), the string is assumed to be * null-terminated. * * * Notes: * With DBCS enabled, we will allocate twice the size of the * buffer including the null terminator to take care of double * byte character strings - KrishnaG * * pUnicode is truncated to StringLength characters. * * Return: * * The return value from WideCharToMultiByte, the number of * multi-byte characters returned. * * * andrewbe, 11 Jan 1993 */ INT UnicodeToAnsiString( LPWSTR pUnicode, LPSTR pAnsi, DWORD StringLength) { LPSTR pTempBuf = NULL; INT rc = 0; LPWSTR pAlignedUnicode = NULL; if ((ULONG_PTR)pUnicode != (((ULONG_PTR) (pUnicode) + (sizeof(WCHAR) - 1))&~(sizeof(WCHAR) - 1))) { // // Calculate the length of the unaligned string. // if(StringLength == NULL_TERMINATED) { for (StringLength = 0; !( ((LPSTR)pUnicode)[StringLength] == '\0' && ((LPSTR)pUnicode)[StringLength+1] == '\0' ); StringLength += 2) ; StringLength /= 2; } else { // // WideCharToMultiByte doesn't NULL terminate if we're copying // just part of the string, so terminate here. // ((LPSTR)(pUnicode + StringLength))[0] = '\0'; ((LPSTR)(pUnicode + StringLength))[1] = '\0'; } StringLength++; pAlignedUnicode = LocalAlloc(LPTR, StringLength * sizeof(WCHAR)); if (pAlignedUnicode) { memcpy(pAlignedUnicode, pUnicode, StringLength * sizeof(WCHAR)); } } else { pAlignedUnicode = pUnicode; if(StringLength == NULL_TERMINATED) { // // StringLength is just the // number of characters in the string // StringLength = wcslen(pAlignedUnicode); } // // WideCharToMultiByte doesn't NULL terminate if we're copying // just part of the string, so terminate here. // pAlignedUnicode[StringLength] = 0; StringLength++; } // // Unfortunately, WideCharToMultiByte doesn't do conversion in place, // so allocate a temporary buffer, which we can then copy: // if( pAnsi == (LPSTR)pAlignedUnicode ) { pTempBuf = LocalAlloc( LPTR, StringLength * 2 ); pAnsi = pTempBuf; } if( pAnsi && pAlignedUnicode ) { rc = WideCharToMultiByte( CP_THREAD_ACP, 0, pAlignedUnicode, StringLength, pAnsi, StringLength*2, NULL, NULL ); } // // If pTempBuf is non-null, we must copy the resulting string // so that it looks as if we did it in place: // if( pTempBuf ) { if( rc > 0 ) { pAnsi = (LPSTR)pAlignedUnicode; strcpy( pAnsi, pTempBuf ); } LocalFree( pTempBuf ); } if (pAlignedUnicode != pUnicode) { LocalFree(pAlignedUnicode); } return rc; } void ConvertUnicodeToAnsiStrings( LPBYTE pStructure, LPDWORD pOffsets ) { register DWORD i=0; LPWSTR pUnicode; LPSTR pAnsi; while (pOffsets[i] != -1) { pUnicode = *(LPWSTR *)(pStructure+pOffsets[i]); pAnsi = (LPSTR)pUnicode; if (pUnicode) { UnicodeToAnsiString(pUnicode, pAnsi, NULL_TERMINATED); } i++; } } LPWSTR AllocateUnicodeString( LPSTR pPrinterName ) { LPWSTR pUnicodeString; if (!pPrinterName) return NULL; pUnicodeString = LocalAlloc(LPTR, strlen(pPrinterName)*sizeof(WCHAR) + sizeof(WCHAR)); if (pUnicodeString) AnsiToUnicodeString(pPrinterName, pUnicodeString, NULL_TERMINATED); return pUnicodeString; } LPWSTR AllocateUnicodeStringWithSize( LPSTR pData, DWORD cbData ) { LPWSTR pUnicodeString = NULL; DWORD iReturn; if (pData && (pUnicodeString = LocalAlloc(LPTR, cbData*sizeof(WCHAR)))) { iReturn = MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, pData, cbData, pUnicodeString, cbData); if (iReturn != cbData) { LocalFree(pUnicodeString); pUnicodeString = NULL; } } return pUnicodeString; } LPWSTR FreeUnicodeString( LPWSTR pUnicodeString ) { if (!pUnicodeString) return NULL; return LocalFree(pUnicodeString); } LPBYTE AllocateUnicodeStructure( LPBYTE pAnsiStructure, DWORD cbStruct, LPDWORD pOffsets ) { DWORD i, j; LPWSTR *ppUnicodeString; LPSTR *ppAnsiString; LPBYTE pUnicodeStructure; if (!pAnsiStructure) { return NULL; } pUnicodeStructure = LocalAlloc(LPTR, cbStruct); if (pUnicodeStructure) { memcpy(pUnicodeStructure, pAnsiStructure, cbStruct); for (i = 0 ; pOffsets[i] != -1 ; ++i) { ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[i]); ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[i]); *ppUnicodeString = AllocateUnicodeString(*ppAnsiString); if (*ppAnsiString && !*ppUnicodeString) { for( j = 0 ; j < i ; ++j) { ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[j]); FreeUnicodeString(*ppUnicodeString); } LocalFree(pUnicodeStructure); pUnicodeStructure = NULL; break; } } } return pUnicodeStructure; } DWORD CopyOsVersionUnicodeToAnsi( IN OUT OSVERSIONWRAP Arg ) /*++ Routine Name: CopyOsVersionUnicodeToAnsi Routine Description: Copies the contents of the UNICODE structure OSVERSIONINFO(EX) into the ANSI structure. Arguments: An OSVERSIONWRAP structure Return Value: Win32 error core --*/ { DWORD dwError = ERROR_INVALID_PARAMETER; OSVERSIONINFOEXW *pIn = Arg.Unicode.pOsVersionEx; OSVERSIONINFOEXA *pOut = Arg.Ansi.pOsVersionEx; if (pIn && pOut) { dwError = ERROR_SUCCESS; pOut->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); pOut->dwMajorVersion = pIn->dwMajorVersion; pOut->dwMinorVersion = pIn->dwMinorVersion; pOut->dwBuildNumber = pIn->dwBuildNumber; pOut->dwPlatformId = pIn->dwPlatformId; // // Initialize the array of chars szCSDVersion to 0 so that we are consistent with // the return of the UNICODE versions of GetPrinterData(Ex). // memset(pOut->szCSDVersion, 0, COUNTOF(pOut->szCSDVersion)); UnicodeToAnsiString(pIn->szCSDVersion, pOut->szCSDVersion, NULL_TERMINATED); // // Copy the rest of the Ex structure // if (Arg.bOsVersionEx) { pOut->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); pOut->wServicePackMajor = pIn->wServicePackMajor; pOut->wServicePackMinor = pIn->wServicePackMinor; pOut->wSuiteMask = pIn->wSuiteMask; pOut->wProductType = pIn->wProductType; pOut->wReserved = pIn->wReserved; } } return dwError; } DWORD ComputeMaxStrlenW( LPWSTR pString, DWORD cchBufMax) /*++ Routine Description: Returns the length of the Unicode string, EXCLUDING the NULL. If the string (plus NULL) won't fit into the cchBufMax, then the string len is decreased. Arguments: Return Value: --*/ { DWORD cchLen; // // Include space for the NULL. // cchBufMax--; cchLen = wcslen(pString); if (cchLen > cchBufMax) return cchBufMax; return cchLen; } DWORD ComputeMaxStrlenA( LPSTR pString, DWORD cchBufMax) /*++ Routine Description: Returns the length of the Ansi string, EXCLUDING the NULL. If the string (plus NULL) won't fit into the cchBufMax, then the string len is decreased. Arguments: Return Value: --*/ { DWORD cchLen; // // Include space for the NULL. // cchBufMax--; cchLen = lstrlenA(pString); if (cchLen > cchBufMax) return cchBufMax; return cchLen; } /***************************** Function Header ****************************** * AllocateUnicodeDevMode * Allocate a UNICODE 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. * ***************************************************************************/ LPDEVMODEW AllocateUnicodeDevMode( LPDEVMODEA pANSIDevMode ) { LPDEVMODEW pUnicodeDevMode; LPBYTE p1, p2; DWORD dwSize; // // If the devmode is NULL, then return NULL -- KrishnaG // if ( !pANSIDevMode || !pANSIDevMode->dmSize ) { return NULL; } SPLASSERT( bValidDevModeA( pANSIDevMode )); // // 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 = pANSIDevMode->dmSize + pANSIDevMode->dmDriverExtra + sizeof(DEVMODEW) - sizeof(DEVMODEA); pUnicodeDevMode = (LPDEVMODEW) LocalAlloc(LPTR, dwSize); if( !pUnicodeDevMode ) { return NULL; /* This is bad news */ } // // Copy dmDeviceName which is a string // if (pANSIDevMode->dmDeviceName) { AnsiToUnicodeString(pANSIDevMode->dmDeviceName, pUnicodeDevMode->dmDeviceName, ComputeMaxStrlenA(pANSIDevMode->dmDeviceName, sizeof pANSIDevMode->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 + pANSIDevMode->dmSize > (LPBYTE) pANSIDevMode->dmFormName ) { // // Copy everything between dmDeviceName and dmFormName // p1 = (LPBYTE) pANSIDevMode->dmDeviceName + sizeof(pANSIDevMode->dmDeviceName); p2 = (LPBYTE) pANSIDevMode->dmFormName; CopyMemory((LPBYTE) pUnicodeDevMode->dmDeviceName + sizeof(pUnicodeDevMode->dmDeviceName), p1, p2 - p1); // // Copy dmFormName which is a string // if (pANSIDevMode->dmFormName) { AnsiToUnicodeString(pANSIDevMode->dmFormName, pUnicodeDevMode->dmFormName, ComputeMaxStrlenA(pANSIDevMode->dmFormName, sizeof pANSIDevMode->dmFormName)); } // // Copy everything after dmFormName // p1 = (LPBYTE) pANSIDevMode->dmFormName + sizeof(pANSIDevMode->dmFormName); p2 = (LPBYTE) pANSIDevMode + pANSIDevMode->dmSize + pANSIDevMode->dmDriverExtra; CopyMemory((LPBYTE) pUnicodeDevMode->dmFormName + sizeof(pUnicodeDevMode->dmFormName), p1, p2 - p1); pUnicodeDevMode->dmSize = pANSIDevMode->dmSize + sizeof(DEVMODEW) - sizeof(DEVMODEA); } else { // // Copy everything after dmDeviceName // p1 = (LPBYTE) pANSIDevMode->dmDeviceName + sizeof(pANSIDevMode->dmDeviceName); p2 = (LPBYTE) pANSIDevMode + pANSIDevMode->dmSize + pANSIDevMode->dmDriverExtra; CopyMemory((LPBYTE) pUnicodeDevMode->dmDeviceName + sizeof(pUnicodeDevMode->dmDeviceName), p1, p2-p1); pUnicodeDevMode->dmSize = pANSIDevMode->dmSize + sizeof(pUnicodeDevMode->dmDeviceName) - sizeof(pANSIDevMode->dmDeviceName); } SPLASSERT(pUnicodeDevMode->dmDriverExtra == pANSIDevMode->dmDriverExtra); return pUnicodeDevMode; } /************************** Function Header ****************************** * CopyAnsiDevModeFromUnicodeDevMode * Converts the UNICODE version of the DEVMODE to the ANSI version. * * RETURNS: * Nothing. * * HISTORY: * 09:57 on 10-Aug-92 -by- Lindsay Harris [lindsayh] * This one actually works! * * Originally dreamed up by DaveSn. * **************************************************************************/ void CopyAnsiDevModeFromUnicodeDevMode( LPDEVMODEA pANSIDevMode, /* Filled in by us */ LPDEVMODEW pUnicodeDevMode /* Source of data to fill above */ ) { LPBYTE p1, p2, pExtra; WORD dmSize, dmDriverExtra; // // NOTE: THE TWO INPUT STRUCTURES MAY BE THE SAME. // dmSize = pUnicodeDevMode->dmSize; dmDriverExtra = pUnicodeDevMode->dmDriverExtra; pExtra = (LPBYTE) pUnicodeDevMode + pUnicodeDevMode->dmSize; if (dmSize) { // // Copy dmDeviceName which is a string // UnicodeToAnsiString(pUnicodeDevMode->dmDeviceName, pANSIDevMode->dmDeviceName, ComputeMaxStrlenW(pUnicodeDevMode->dmDeviceName, sizeof pANSIDevMode->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 + dmSize > (LPBYTE) pUnicodeDevMode->dmFormName ) { // // Copy everything between dmDeviceName and dmFormName // p1 = (LPBYTE) pUnicodeDevMode->dmDeviceName + sizeof(pUnicodeDevMode->dmDeviceName); p2 = (LPBYTE) pUnicodeDevMode->dmFormName; MoveMemory((LPBYTE) pANSIDevMode->dmDeviceName + sizeof(pANSIDevMode->dmDeviceName), p1, p2 - p1); // // Copy dmFormName which is a string // UnicodeToAnsiString(pUnicodeDevMode->dmFormName, pANSIDevMode->dmFormName, ComputeMaxStrlenW(pUnicodeDevMode->dmFormName, sizeof pANSIDevMode->dmFormName)); // // Copy everything after dmFormName // p1 = (LPBYTE) pUnicodeDevMode->dmFormName + sizeof(pUnicodeDevMode->dmFormName); p2 = (LPBYTE) pUnicodeDevMode + dmSize + dmDriverExtra; MoveMemory((LPBYTE) pANSIDevMode->dmFormName + sizeof(pANSIDevMode->dmFormName), p1, p2 - p1); pANSIDevMode->dmSize = dmSize + sizeof(DEVMODEA) - sizeof(DEVMODEW); } else { // // Copy everything after dmDeviceName // p1 = (LPBYTE) pUnicodeDevMode->dmDeviceName + sizeof(pUnicodeDevMode->dmDeviceName); p2 = (LPBYTE) pUnicodeDevMode + dmSize + dmDriverExtra; MoveMemory((LPBYTE) pANSIDevMode->dmDeviceName + sizeof(pANSIDevMode->dmDeviceName), p1, p2 - p1); pANSIDevMode->dmSize = dmSize + sizeof(pANSIDevMode->dmDeviceName) - sizeof(pUnicodeDevMode->dmDeviceName); } SPLASSERT(pANSIDevMode->dmDriverExtra == dmDriverExtra); } return; } BOOL ConvertAnsiDevModeToUnicodeDevmode( PDEVMODEA pAnsiDevMode, PDEVMODEW pUnicodeDevMode, DWORD dwUnicodeDevModeSize, PDWORD pcbNeeded ) { PDEVMODEW pDevModeW = NULL; BOOL bRet = FALSE; if ( !pAnsiDevMode ) { SetLastError(ERROR_INVALID_PARAMETER); goto Cleanup; } SPLASSERT( bValidDevModeA( pAnsiDevMode )); pDevModeW = AllocateUnicodeDevMode(pAnsiDevMode); if ( !pDevModeW ) { goto Cleanup; } *pcbNeeded = pDevModeW->dmSize + pDevModeW->dmDriverExtra; if ( *pcbNeeded > dwUnicodeDevModeSize ) { SetLastError(ERROR_INSUFFICIENT_BUFFER); goto Cleanup; } CopyMemory((LPBYTE)pUnicodeDevMode, (LPBYTE)pDevModeW, *pcbNeeded); bRet = TRUE; Cleanup: if ( pDevModeW ) LocalFree(pDevModeW); return bRet; } BOOL ConvertUnicodeDevModeToAnsiDevmode( PDEVMODEW pUnicodeDevMode, PDEVMODEA pAnsiDevMode, DWORD dwAnsiDevModeSize, PDWORD pcbNeeded ) { LPBYTE pDevMode = NULL; BOOL bRet = FALSE; DWORD dwSize; if ( !pUnicodeDevMode ) { SetLastError(ERROR_INVALID_PARAMETER); goto Cleanup; } dwSize = pUnicodeDevMode->dmSize + pUnicodeDevMode->dmDriverExtra; pDevMode = LocalAlloc(LPTR, dwSize); if ( !pDevMode ) { goto Cleanup; } CopyMemory(pDevMode, (LPBYTE)pUnicodeDevMode, dwSize); CopyAnsiDevModeFromUnicodeDevMode((PDEVMODEA) pDevMode, (PDEVMODEW) pDevMode); *pcbNeeded = ((PDEVMODEA)pDevMode)->dmSize + ((PDEVMODEA)pDevMode)->dmDriverExtra; if ( *pcbNeeded > dwAnsiDevModeSize ) { SetLastError(ERROR_INSUFFICIENT_BUFFER); goto Cleanup; } CopyMemory((LPBYTE)pAnsiDevMode, pDevMode, *pcbNeeded); bRet = TRUE; Cleanup: if ( pDevMode ) LocalFree(pDevMode); return bRet; } void FreeUnicodeStructure( LPBYTE pUnicodeStructure, LPDWORD pOffsets ) { DWORD i=0; if ( pUnicodeStructure == NULL ) { return; } if (pOffsets) { while (pOffsets[i] != -1) { FreeUnicodeString(*(LPWSTR *)(pUnicodeStructure+pOffsets[i])); i++; } } LocalFree( pUnicodeStructure ); } BOOL EnumPrintersA( DWORD Flags, LPSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName; switch (Level) { case STRESSINFOLEVEL: pOffsets = PrinterInfoStressStrings; cbStruct = sizeof(PRINTER_INFO_STRESS); break; case 4: pOffsets = PrinterInfo4Strings; cbStruct = sizeof(PRINTER_INFO_4); break; case 1: pOffsets = PrinterInfo1Strings; cbStruct = sizeof(PRINTER_INFO_1); break; case 2: pOffsets = PrinterInfo2Strings; cbStruct = sizeof(PRINTER_INFO_2); break; case 5: pOffsets = PrinterInfo5Strings; cbStruct = sizeof(PRINTER_INFO_5); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(Name); if (Name && !pUnicodeName) return FALSE; ReturnValue = EnumPrintersW(Flags, pUnicodeName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); if (ReturnValue && pPrinterEnum) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pPrinterEnum, pOffsets); if ((Level == 2) && pPrinterEnum) { PRINTER_INFO_2 *pPrinterInfo2 = (PRINTER_INFO_2 *)pPrinterEnum; if (pPrinterInfo2->pDevMode) CopyAnsiDevModeFromUnicodeDevMode( (LPDEVMODEA)pPrinterInfo2->pDevMode, (LPDEVMODEW)pPrinterInfo2->pDevMode); } pPrinterEnum+=cbStruct; } } FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL OpenPrinterA( LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault ) { BOOL ReturnValue = FALSE; LPWSTR pUnicodePrinterName = NULL; PRINTER_DEFAULTSW UnicodeDefaults={NULL, NULL, 0}; pUnicodePrinterName = AllocateUnicodeString(pPrinterName); if (pPrinterName && !pUnicodePrinterName) goto Cleanup; if (pDefault) { UnicodeDefaults.pDatatype = AllocateUnicodeString(pDefault->pDatatype); if (pDefault->pDatatype && !UnicodeDefaults.pDatatype) goto Cleanup; // // Milestones etc. 4.5 passes in a bogus devmode in pDefaults. // Be sure to validate here. // if( bValidDevModeA( pDefault->pDevMode )){ UnicodeDefaults.pDevMode = AllocateUnicodeDevMode( pDefault->pDevMode ); if( !UnicodeDefaults.pDevMode ){ goto Cleanup; } } UnicodeDefaults.DesiredAccess = pDefault->DesiredAccess; } ReturnValue = OpenPrinterW(pUnicodePrinterName, phPrinter, &UnicodeDefaults); if (ReturnValue) { ((PSPOOL)*phPrinter)->Status |= SPOOL_STATUS_ANSI; } Cleanup: if (UnicodeDefaults.pDevMode) LocalFree(UnicodeDefaults.pDevMode); FreeUnicodeString(UnicodeDefaults.pDatatype); FreeUnicodeString(pUnicodePrinterName); return ReturnValue; } BOOL ResetPrinterA( HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault ) { BOOL ReturnValue = FALSE; PRINTER_DEFAULTSW UnicodeDefaults={NULL, NULL, 0}; if (pDefault) { if (pDefault->pDatatype == (LPSTR)-1) { UnicodeDefaults.pDatatype = (LPWSTR)-1; } else { UnicodeDefaults.pDatatype = AllocateUnicodeString(pDefault->pDatatype); if (pDefault->pDatatype && !UnicodeDefaults.pDatatype) return FALSE; } if (pDefault->pDevMode == (LPDEVMODEA)-1) { UnicodeDefaults.pDevMode = (LPDEVMODEW)-1; } else { if( bValidDevModeA( pDefault->pDevMode )){ UnicodeDefaults.pDevMode = AllocateUnicodeDevMode( pDefault->pDevMode ); if( !UnicodeDefaults.pDevMode ){ goto Cleanup; } } } } ReturnValue = ResetPrinterW(hPrinter, &UnicodeDefaults); if (UnicodeDefaults.pDevMode && (UnicodeDefaults.pDevMode != (LPDEVMODEW)-1)){ LocalFree(UnicodeDefaults.pDevMode); } Cleanup: if (UnicodeDefaults.pDatatype && (UnicodeDefaults.pDatatype != (LPWSTR)-1)) { FreeUnicodeString(UnicodeDefaults.pDatatype); } return ReturnValue; } BOOL SetJobA( HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command ) { BOOL ReturnValue=FALSE; LPBYTE pUnicodeStructure=NULL; LPDEVMODEW pDevModeW = NULL; DWORD cbStruct; DWORD *pOffsets; switch (Level) { case 0: break; case 1: pOffsets = JobInfo1Strings; cbStruct = sizeof(JOB_INFO_1); break; case 2: pOffsets = JobInfo2Strings; cbStruct = sizeof(JOB_INFO_2); break; case 3: return SetJobW( hPrinter, JobId, Level, pJob, Command ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (Level) { pUnicodeStructure = AllocateUnicodeStructure(pJob, cbStruct, pOffsets); if (pJob && !pUnicodeStructure) return FALSE; } if ( Level == 2 && pUnicodeStructure && pJob ) { if( bValidDevModeA( ((LPJOB_INFO_2A)pJob)->pDevMode )){ pDevModeW = AllocateUnicodeDevMode(((LPJOB_INFO_2A)pJob)->pDevMode); if( !pDevModeW ){ ReturnValue = FALSE; goto Cleanup; } ((LPJOB_INFO_2W) pUnicodeStructure)->pDevMode = pDevModeW; } } ReturnValue = SetJobW(hPrinter, JobId, Level, pUnicodeStructure, Command); if ( pDevModeW ) { LocalFree(pDevModeW); } Cleanup: FreeUnicodeStructure(pUnicodeStructure, pOffsets); return ReturnValue; } BOOL GetJobA( HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; switch (Level) { case 1: pOffsets = JobInfo1Strings; break; case 2: pOffsets = JobInfo2Strings; break; case 3: return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (GetJob(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded)) { ConvertUnicodeToAnsiStrings(pJob, pOffsets); // // Convert the devmode in place for INFO_2. // if( Level == 2 ){ PJOB_INFO_2A pJobInfo2 = (PJOB_INFO_2A)pJob; if( pJobInfo2->pDevMode ){ CopyAnsiDevModeFromUnicodeDevMode( (LPDEVMODEA)pJobInfo2->pDevMode, (LPDEVMODEW)pJobInfo2->pDevMode); } } return TRUE; } else return FALSE; } BOOL EnumJobsA( 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 = JobInfo1Strings; cbStruct = sizeof(JOB_INFO_1); break; case 2: pOffsets = JobInfo2Strings; cbStruct = sizeof(JOB_INFO_2); break; case 3: return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ); default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (EnumJobsW(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned)) { i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pJob, pOffsets); // // Convert the devmode in place for INFO_2. // if( Level == 2 ){ PJOB_INFO_2A pJobInfo2 = (PJOB_INFO_2A)pJob; if( pJobInfo2->pDevMode ){ CopyAnsiDevModeFromUnicodeDevMode( (LPDEVMODEA)pJobInfo2->pDevMode, (LPDEVMODEW)pJobInfo2->pDevMode); } } pJob += cbStruct; } return TRUE; } else return FALSE; } HANDLE AddPrinterA( LPSTR pName, DWORD Level, LPBYTE pPrinter ) { HANDLE hPrinter = NULL; LPBYTE pUnicodeStructure = NULL; LPDEVMODEW pDevModeW = NULL; LPWSTR pUnicodeName = NULL; DWORD cbStruct; DWORD *pOffsets; switch (Level) { case 2: pOffsets = PrinterInfo2Strings; cbStruct = sizeof(PRINTER_INFO_2); break; default: SetLastError(ERROR_INVALID_LEVEL); return NULL; } if (!pPrinter) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets); if (pPrinter && !pUnicodeStructure) goto Cleanup; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; if ( pUnicodeStructure ) { if( bValidDevModeA( ((LPPRINTER_INFO_2A)pPrinter)->pDevMode )){ pDevModeW = AllocateUnicodeDevMode( ((LPPRINTER_INFO_2A)pPrinter)->pDevMode); if( !pDevModeW ){ goto Cleanup; } } ((LPPRINTER_INFO_2W)pUnicodeStructure)->pDevMode = pDevModeW; hPrinter = AddPrinterW(pUnicodeName, Level, pUnicodeStructure); } Cleanup: FreeUnicodeString( pUnicodeName ); if ( pDevModeW ) { LocalFree(pDevModeW); } FreeUnicodeStructure( pUnicodeStructure, pOffsets ); return hPrinter; } BOOL AddPrinterConnectionA( LPSTR pName ) { BOOL rc; LPWSTR pUnicodeName; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) return FALSE; rc = AddPrinterConnectionW(pUnicodeName); FreeUnicodeString(pUnicodeName); return rc; } BOOL DeletePrinterConnectionA( LPSTR pName ) { BOOL rc; LPWSTR pUnicodeName; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) return FALSE; rc = DeletePrinterConnectionW(pUnicodeName); FreeUnicodeString(pUnicodeName); return rc; } BOOL SetPrinterA( HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command ) { LPBYTE pUnicodeStructure; /* Unicode version of input data */ DWORD cbStruct; /* Size of the output structure */ DWORD *pOffsets; /* -1 terminated list of addresses */ DWORD ReturnValue=FALSE; // // For APP compat. Win9x handled this // if (eProtectHandle(hPrinter, FALSE)) { return 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 = PrinterInfoStressStrings; cbStruct = sizeof( PRINTER_INFO_STRESS ); } break; case 1: pOffsets = PrinterInfo1Strings; cbStruct = sizeof( PRINTER_INFO_1 ); break; case 2: pOffsets = PrinterInfo2Strings; cbStruct = sizeof( PRINTER_INFO_2 ); break; case 3: pOffsets = PrinterInfo3Strings; cbStruct = sizeof( PRINTER_INFO_3 ); break; case 4: pOffsets = PrinterInfo4Strings; cbStruct = sizeof( PRINTER_INFO_4 ); break; case 5: pOffsets = PrinterInfo5Strings; cbStruct = sizeof( PRINTER_INFO_5 ); break; case 6: break; case 7: pOffsets = PrinterInfo7Strings; cbStruct = sizeof( PRINTER_INFO_7 ); break; case 8: pOffsets = PrinterInfo8Strings; cbStruct = sizeof( PRINTER_INFO_8 ); break; case 9: pOffsets = PrinterInfo9Strings; cbStruct = sizeof( PRINTER_INFO_9 ); break; default: SetLastError( ERROR_INVALID_LEVEL ); goto Done; } // // 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 pPrinter is a DWORD // if ( Level == 6 || (!Level && Command) ) { if ( Level == 6 || Command == PRINTER_CONTROL_SET_STATUS ) pUnicodeStructure = pPrinter; else pUnicodeStructure = NULL; } else { pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets); if (pPrinter && !pUnicodeStructure) { goto Done; } } #define pPrinterInfo2W ((LPPRINTER_INFO_2W)pUnicodeStructure) #define pPrinterInfo2A ((LPPRINTER_INFO_2A)pPrinter) // The Level 2 structure has a DEVMODE struct in it: convert now if ( Level == 2 && pPrinterInfo2A && pPrinterInfo2A->pDevMode ) { if( bValidDevModeA( pPrinterInfo2A->pDevMode )){ pPrinterInfo2W->pDevMode = AllocateUnicodeDevMode( pPrinterInfo2A->pDevMode ); if( !pPrinterInfo2W->pDevMode) { FreeUnicodeStructure(pUnicodeStructure, pOffsets); goto Done; } } } #define pPrinterInfo8W ((LPPRINTER_INFO_8W)pUnicodeStructure) #define pPrinterInfo8A ((LPPRINTER_INFO_8A)pPrinter) if (( Level == 8 || Level == 9 ) && pPrinterInfo8A && pPrinterInfo8A->pDevMode ) { if( bValidDevModeA( pPrinterInfo8A->pDevMode )){ pPrinterInfo8W->pDevMode = AllocateUnicodeDevMode( pPrinterInfo8A->pDevMode ); if( !pPrinterInfo8W->pDevMode) { FreeUnicodeStructure(pUnicodeStructure, pOffsets); goto Done; } } } ReturnValue = SetPrinterW( hPrinter, Level, pUnicodeStructure, Command ); // Free the DEVMODE we allocated (if we did!), then the // the Unicode structure and its contents. if (Level == 2 && pPrinterInfo2W && pPrinterInfo2W->pDevMode ) { LocalFree( pPrinterInfo2W->pDevMode ); } if ((Level == 8 || Level == 9) && pUnicodeStructure && pPrinterInfo8W->pDevMode ) { LocalFree( pPrinterInfo8W->pDevMode ); } // // STRESS_INFO and Levels 1-5 // if ( Level != 6 && (Level || !Command) ) FreeUnicodeStructure( pUnicodeStructure, pOffsets ); #undef pPrinterInfo2W #undef pPrinterInfo2A Done: vUnprotectHandle(hPrinter); return ReturnValue; } BOOL GetPrinterA( HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; switch (Level) { case STRESSINFOLEVEL: pOffsets = PrinterInfoStressOffsets; break; case 1: pOffsets = PrinterInfo1Strings; break; case 2: pOffsets = PrinterInfo2Strings; break; case 3: pOffsets = PrinterInfo3Strings; break; case 4: pOffsets = PrinterInfo4Strings; break; case 5: pOffsets = PrinterInfo5Strings; break; case 6: pOffsets = PrinterInfo6Strings; break; case 7: pOffsets = PrinterInfo7Strings; break; case 8: pOffsets = PrinterInfo8Strings; break; case 9: pOffsets = PrinterInfo9Strings; break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) { if (pPrinter) { ConvertUnicodeToAnsiStrings(pPrinter, pOffsets); if ((Level == 2) && pPrinter) { PRINTER_INFO_2 *pPrinterInfo2 = (PRINTER_INFO_2 *)pPrinter; if (pPrinterInfo2->pDevMode) CopyAnsiDevModeFromUnicodeDevMode( (LPDEVMODEA)pPrinterInfo2->pDevMode, (LPDEVMODEW)pPrinterInfo2->pDevMode); } if ((Level == 8 || Level == 9) && pPrinter) { PRINTER_INFO_8 *pPrinterInfo8 = (PRINTER_INFO_8 *)pPrinter; if (pPrinterInfo8->pDevMode) CopyAnsiDevModeFromUnicodeDevMode( (LPDEVMODEA)pPrinterInfo8->pDevMode, (LPDEVMODEW)pPrinterInfo8->pDevMode); } } return TRUE; } return FALSE; } // // Conversion in place // BOOL UnicodeToAnsiMultiSz( LPWSTR pUnicodeDependentFiles ) { LPWSTR pAlignedUnicodeStr = NULL; LPWSTR pUnicodeStr; DWORD StringLength, rc; DWORD Index; BOOL bReturn = FALSE; if (!(pUnicodeDependentFiles) || !*pUnicodeDependentFiles) { bReturn = TRUE; } else { if ((ULONG_PTR)pUnicodeDependentFiles != (((ULONG_PTR) (pUnicodeDependentFiles) + (sizeof(WCHAR) - 1))&~(sizeof(WCHAR) - 1))) { // // Calculate the length of the unaligned multisz string // for (StringLength = 0; !( ((LPSTR)pUnicodeDependentFiles)[StringLength] == '\0' && ((LPSTR)pUnicodeDependentFiles)[StringLength + 1] == '\0' && ((LPSTR)pUnicodeDependentFiles)[StringLength + 2] == '\0' && ((LPSTR)pUnicodeDependentFiles)[StringLength + 3] == '\0' ); StringLength += 2) ; StringLength /= 2; // // Include NULL terminator for last string and NULL terminator for MULTI SZ // StringLength +=2; } else { // // The string is WCHAR aligned. // pUnicodeStr = pUnicodeDependentFiles; while ( *pUnicodeStr ) { pUnicodeStr += wcslen(pUnicodeStr) + 1; } StringLength = (DWORD) (pUnicodeStr - pUnicodeDependentFiles + 1); } // // Since WideCharToMultiByte doesn't do in place conversion, // duplicate the pUnicodeDependentFiles regardless if it is aligned or not. // if (pAlignedUnicodeStr = LocalAlloc(LPTR, StringLength * sizeof(char) * 2)) { memcpy( pAlignedUnicodeStr, pUnicodeDependentFiles, StringLength * sizeof(char)* 2); rc = WideCharToMultiByte(CP_THREAD_ACP, 0, pAlignedUnicodeStr, StringLength, (LPSTR)pUnicodeDependentFiles, StringLength * 2, NULL, NULL ); LocalFree( pAlignedUnicodeStr ); bReturn = rc > 0; } } return bReturn; } BOOL AnsiToUnicodeMultiSz( LPSTR pAnsiDependentFiles, LPWSTR *pUnicodeDependentFiles ) { LPWSTR pUnicodeStr; LPSTR pAnsiStr; DWORD len, rc; if ( ! (pAnsiStr = pAnsiDependentFiles) || !*pAnsiStr ) { *pUnicodeDependentFiles = NULL; return TRUE; } while ( *pAnsiStr ) pAnsiStr += strlen(pAnsiStr) + 1; len = (DWORD) (pAnsiStr - pAnsiDependentFiles + 1); if ( !(*pUnicodeDependentFiles = LocalAlloc(LPTR, len * sizeof(WCHAR))) ) { return FALSE; } AnsiToUnicodeString(pAnsiDependentFiles, *pUnicodeDependentFiles, len-1); return TRUE; } BOOL AddPrinterDriverExA( LPSTR pName, DWORD Level, PBYTE pPrinter, DWORD dwFileCopyFlags ) { BOOL ReturnValue=FALSE; DWORD cbStruct; LPWSTR pUnicodeName = NULL; LPBYTE pUnicodeStructure = NULL; LPDWORD pOffsets; switch (Level) { case 2: pOffsets = DriverInfo2Strings; cbStruct = sizeof(DRIVER_INFO_2); break; case 3: pOffsets = DriverInfo3Strings; cbStruct = sizeof(DRIVER_INFO_3); break; case 4: pOffsets = DriverInfo4Strings; cbStruct = sizeof(DRIVER_INFO_4); break; case 6: pOffsets = DriverInfo6Strings; cbStruct = sizeof(DRIVER_INFO_6); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if (!pPrinter) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } pUnicodeStructure = AllocateUnicodeStructure(pPrinter, cbStruct, pOffsets); if (pPrinter && !pUnicodeStructure) goto Error; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Error; // // Handle dependent files which is upto \0\0 // if ( ( Level == 3 || Level == 4 || Level ==6 ) && !AnsiToUnicodeMultiSz( (LPSTR) ((PDRIVER_INFO_3A)pPrinter)->pDependentFiles, &(((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles)) ) { goto Error; } // // Handle pszzPreviousNames which is upto \0\0 // if ( ( Level == 4 || Level == 6 ) && !AnsiToUnicodeMultiSz( (LPSTR) ((PDRIVER_INFO_4A)pPrinter)->pszzPreviousNames, &(((PDRIVER_INFO_4W)pUnicodeStructure)->pszzPreviousNames)) ) { goto Error; } ReturnValue = AddPrinterDriverExW(pUnicodeName, Level, pUnicodeStructure,dwFileCopyFlags); if ( ( Level == 3 || Level == 4 || Level == 6) && ((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles ) { LocalFree(((PDRIVER_INFO_3W)pUnicodeStructure)->pDependentFiles); } if ( (Level == 4 || Level == 6 )&& (((PDRIVER_INFO_4)pUnicodeStructure)->pszzPreviousNames) ) LocalFree(((PDRIVER_INFO_4)pUnicodeStructure)->pszzPreviousNames); Error: FreeUnicodeStructure( pUnicodeStructure, pOffsets ); FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL AddPrinterDriverA( LPSTR pName, DWORD Level, PBYTE pPrinter ) { return AddPrinterDriverExA(pName, Level, pPrinter, APD_COPY_NEW_FILES); } BOOL EnumPrinterDriversA( LPSTR pName, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue=FALSE; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; switch (Level) { case 1: pOffsets = DriverInfo1Strings; cbStruct = sizeof(DRIVER_INFO_1); break; case 2: pOffsets = DriverInfo2Strings; cbStruct = sizeof(DRIVER_INFO_2); break; case 3: pOffsets = DriverInfo3Strings; cbStruct = sizeof(DRIVER_INFO_3); break; case 4: pOffsets = DriverInfo4Strings; cbStruct = sizeof(DRIVER_INFO_4); break; case 5: pOffsets = DriverInfo5Strings; cbStruct = sizeof(DRIVER_INFO_5); break; case 6: pOffsets = DriverInfo6Strings; cbStruct = sizeof(DRIVER_INFO_6); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; if (ReturnValue = EnumPrinterDriversW(pUnicodeName, pUnicodeEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned)) { if (pDriverInfo) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pDriverInfo, pOffsets); if ( ( Level == 3 || Level == 4 || Level == 6) && !UnicodeToAnsiMultiSz( ((PDRIVER_INFO_3) pDriverInfo)->pDependentFiles) ) ReturnValue = FALSE; if ( ( Level == 4 || Level == 6 ) && !UnicodeToAnsiMultiSz( ((PDRIVER_INFO_4) pDriverInfo)->pszzPreviousNames) ) ReturnValue = FALSE; pDriverInfo+=cbStruct; } } } Cleanup: FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL GetPrinterDriverA( HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; LPWSTR pUnicodeEnvironment = NULL; BOOL ReturnValue; switch (Level) { case 1: pOffsets = DriverInfo1Strings; break; case 2: pOffsets = DriverInfo2Strings; break; case 3: pOffsets = DriverInfo3Strings; break; case 4: pOffsets = DriverInfo4Strings; break; case 5: pOffsets = DriverInfo5Strings; break; case 6: pOffsets = DriverInfo6Strings; break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) return FALSE; if (ReturnValue = GetPrinterDriverW(hPrinter, pUnicodeEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded)) { if (pDriverInfo) { ConvertUnicodeToAnsiStrings(pDriverInfo, pOffsets); if ( ( Level == 3 || Level == 4 || Level == 6) && !UnicodeToAnsiMultiSz( ((PDRIVER_INFO_3)pDriverInfo)->pDependentFiles) ) { ReturnValue = FALSE; } if ( ( Level == 4 || Level == 6 ) && !UnicodeToAnsiMultiSz( ((PDRIVER_INFO_4)pDriverInfo)->pszzPreviousNames) ) { ReturnValue = FALSE; } } } // If called to get the size of buffer it will return the size of a W structure and strings // rather than the A version. also see enum // This cannot cause any harm since we are only allocating more memory than we need. FreeUnicodeString(pUnicodeEnvironment); return ReturnValue; } BOOL GetPrinterDriverDirectoryA( LPSTR pName, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded ) { DWORD *pOffsets; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodeName = NULL; LPWSTR pDriverDirectoryW = NULL; BOOL ReturnValue = FALSE; DWORD Offsets[]={0,(DWORD)-1}; switch (Level) { case 1: pOffsets = DriverInfo1Offsets; break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; if (ReturnValue = GetPrinterDriverDirectoryW(pUnicodeName, pUnicodeEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded)) { if (pDriverDirectory) { UnicodeToAnsiString((LPWSTR)pDriverDirectory, pDriverDirectory, NULL_TERMINATED); } } Cleanup: FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionNum ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodeDriverName = NULL; BOOL rc = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodeDriverName = AllocateUnicodeString(pDriverName); if (pDriverName && !pUnicodeDriverName) goto Cleanup; rc = DeletePrinterDriverExW(pUnicodeName, pUnicodeEnvironment, pUnicodeDriverName, dwDeleteFlag, dwVersionNum); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodeDriverName); return rc; } BOOL DeletePrinterDriverA( LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodeDriverName = NULL; BOOL rc = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodeDriverName = AllocateUnicodeString(pDriverName); if (pDriverName && !pUnicodeDriverName) goto Cleanup; rc = DeletePrinterDriverW(pUnicodeName, pUnicodeEnvironment, pUnicodeDriverName); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodeDriverName); return rc; } BOOL AddPerMachineConnectionA( LPCSTR pServer, LPCSTR pPrinterName, LPCSTR pPrintServer, LPCSTR pProvider ) { LPWSTR pUnicodeServer = NULL; LPWSTR pUnicodePrinterName = NULL; LPWSTR pUnicodePrintServer = NULL; LPWSTR pUnicodeProvider = NULL; BOOL rc = FALSE; pUnicodeServer = AllocateUnicodeString((LPSTR)pServer); if (pServer && !pUnicodeServer) goto Cleanup; pUnicodePrinterName = AllocateUnicodeString((LPSTR)pPrinterName); if (pPrinterName && !pUnicodePrinterName) goto Cleanup; pUnicodePrintServer = AllocateUnicodeString((LPSTR)pPrintServer); if (pPrintServer && !pUnicodePrintServer) goto Cleanup; pUnicodeProvider = AllocateUnicodeString((LPSTR)pProvider); if (pProvider && !pUnicodeProvider) goto Cleanup; rc = AddPerMachineConnectionW((LPCWSTR) pUnicodeServer, (LPCWSTR) pUnicodePrinterName, (LPCWSTR) pUnicodePrintServer, (LPCWSTR) pUnicodeProvider); Cleanup: FreeUnicodeString(pUnicodeServer); FreeUnicodeString(pUnicodePrinterName); FreeUnicodeString(pUnicodePrintServer); FreeUnicodeString(pUnicodeProvider); return rc; } BOOL DeletePerMachineConnectionA( LPCSTR pServer, LPCSTR pPrinterName ) { LPWSTR pUnicodeServer = NULL; LPWSTR pUnicodePrinterName = NULL; BOOL rc = FALSE; pUnicodeServer = AllocateUnicodeString((LPSTR)pServer); if (pServer && !pUnicodeServer) goto Cleanup; pUnicodePrinterName = AllocateUnicodeString((LPSTR)pPrinterName); if (pPrinterName && !pUnicodePrinterName) goto Cleanup; rc = DeletePerMachineConnectionW((LPCWSTR) pUnicodeServer, (LPCWSTR) pUnicodePrinterName); Cleanup: FreeUnicodeString(pUnicodeServer); FreeUnicodeString(pUnicodePrinterName); return rc; } BOOL EnumPerMachineConnectionsA( LPCSTR pServer, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue=FALSE; DWORD cbStruct,index; DWORD *pOffsets; LPWSTR pUnicodeServer = NULL; pOffsets = PrinterInfo4Strings; cbStruct = sizeof(PRINTER_INFO_4); pUnicodeServer = AllocateUnicodeString((LPSTR)pServer); if (pServer && !pUnicodeServer) goto Cleanup; ReturnValue = EnumPerMachineConnectionsW((LPCWSTR) pUnicodeServer, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); if (ReturnValue && pPrinterEnum) { index=*pcReturned; while (index--) { ConvertUnicodeToAnsiStrings(pPrinterEnum, pOffsets); pPrinterEnum+=cbStruct; } } Cleanup: FreeUnicodeString(pUnicodeServer); return ReturnValue; } BOOL AddPrintProcessorA( LPSTR pName, LPSTR pEnvironment, LPSTR pPathName, LPSTR pPrintProcessorName ) { BOOL ReturnValue=FALSE; LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodePathName = NULL; LPWSTR pUnicodePrintProcessorName = NULL; if (!pPathName || !*pPathName) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (!pPrintProcessorName || !*pPrintProcessorName) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodePathName = AllocateUnicodeString(pPathName); if (pPathName && !pUnicodePathName) goto Cleanup; pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName); if (pPrintProcessorName && !pUnicodePrintProcessorName) goto Cleanup; if (pUnicodePathName && pUnicodePrintProcessorName) { ReturnValue = AddPrintProcessorW(pUnicodeName, pUnicodeEnvironment, pUnicodePathName, pUnicodePrintProcessorName); } Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodePathName); FreeUnicodeString(pUnicodePrintProcessorName); return ReturnValue; } BOOL EnumPrintProcessorsA( LPSTR pName, LPSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue=FALSE; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; switch (Level) { case 1: pOffsets = PrintProcessorInfo1Strings; cbStruct = sizeof(PRINTPROCESSOR_INFO_1); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; if (ReturnValue = EnumPrintProcessorsW(pUnicodeName, pUnicodeEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned)) { if (pPrintProcessorInfo) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pPrintProcessorInfo, pOffsets); pPrintProcessorInfo+=cbStruct; } } } Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); return ReturnValue; } BOOL GetPrintProcessorDirectoryA( LPSTR pName, LPSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded ) { BOOL ReturnValue = FALSE; LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; ReturnValue = GetPrintProcessorDirectoryW(pUnicodeName, pUnicodeEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded); if (ReturnValue && pPrintProcessorInfo) { UnicodeToAnsiString((LPWSTR)pPrintProcessorInfo, (LPSTR)pPrintProcessorInfo, NULL_TERMINATED); } Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); return ReturnValue; } BOOL EnumPrintProcessorDatatypesA( LPSTR pName, LPSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatype, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue=FALSE; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName = NULL; LPWSTR pUnicodePrintProcessorName = NULL; switch (Level) { case 1: pOffsets = DatatypeInfo1Strings; cbStruct = sizeof(DATATYPES_INFO_1); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName); if (pPrintProcessorName && !pUnicodePrintProcessorName) goto Cleanup; if (ReturnValue = EnumPrintProcessorDatatypesW(pUnicodeName, pUnicodePrintProcessorName, Level, pDatatype, cbBuf, pcbNeeded, pcReturned)) { if (pDatatype) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pDatatype, pOffsets); pDatatype += cbStruct; } } } Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodePrintProcessorName); return ReturnValue; } DWORD StartDocPrinterA( HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo ) { BOOL ReturnValue = FALSE; LPBYTE pUnicodeStructure = NULL; DWORD cbStruct; // level 2 is supported on win95 and not on NT switch (Level) { case 1: cbStruct = sizeof(DOC_INFO_1A); break; case 3: cbStruct = sizeof(DOC_INFO_3A); break; default: // invalid level SetLastError(ERROR_INVALID_LEVEL); goto Cleanup; } pUnicodeStructure = AllocateUnicodeStructure(pDocInfo, cbStruct, DocInfo1Offsets); if (pDocInfo && !pUnicodeStructure) goto Cleanup; ReturnValue = StartDocPrinterW(hPrinter, Level, pUnicodeStructure); Cleanup: FreeUnicodeStructure(pUnicodeStructure, DocInfo1Offsets); return ReturnValue; } BOOL AddJobA( HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded ) { BOOL ReturnValue; if( Level == 2 || Level == 3 ){ SetLastError( ERROR_INVALID_LEVEL ); return FALSE; } if (ReturnValue = AddJobW(hPrinter, Level, pData, cbBuf, pcbNeeded)) ConvertUnicodeToAnsiStrings(pData, AddJobStrings); return ReturnValue; } DWORD GetPrinterDataA( HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded ) { DWORD ReturnValue = ERROR_SUCCESS; DWORD ReturnType = 0; LPWSTR pUnicodeValueName = NULL; pUnicodeValueName = AllocateUnicodeString(pValueName); // // pUnicodeValueName will be NULL if the caller passed NULL for pValueName. The // invalid situation is when pValueName is non NULL and pUnicodeValueName is NULL // if (pUnicodeValueName || !pValueName) { if (!pType) { pType = (PDWORD)&ReturnType; } if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSION)) { // // The caller wants OSVersion // OSVERSIONINFOW osw = {0}; ReturnValue = GetPrinterDataW(hPrinter, pUnicodeValueName, pType, (PBYTE)&osw, nSize >= sizeof(OSVERSIONINFOA) ? sizeof(osw) : nSize, pcbNeeded); if (ReturnValue == ERROR_SUCCESS && pData) { OSVERSIONWRAP wrap = {0}; wrap.bOsVersionEx = FALSE; wrap.Unicode.pOsVersion = &osw; wrap.Ansi.pOsVersion = (OSVERSIONINFOA *)pData; ReturnValue = CopyOsVersionUnicodeToAnsi(wrap); } // // Set correct number of bytes required/returned // if (pcbNeeded) { *pcbNeeded = sizeof(OSVERSIONINFOA); } } else if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSIONEX)) { // // The caller wants OSVersionEx // OSVERSIONINFOEXW osexw = {0}; ReturnValue = GetPrinterDataW(hPrinter, pUnicodeValueName, pType, (PBYTE)&osexw, nSize >= sizeof(OSVERSIONINFOEXA) ? sizeof(osexw) : nSize, pcbNeeded); if (ReturnValue == ERROR_SUCCESS && pData) { OSVERSIONWRAP wrap = {0}; wrap.bOsVersionEx = TRUE; wrap.Unicode.pOsVersionEx = &osexw; wrap.Ansi.pOsVersionEx = (OSVERSIONINFOEXA *)pData; ReturnValue = CopyOsVersionUnicodeToAnsi(wrap); } // // Set correct number of bytes required/returned // if (pcbNeeded) { *pcbNeeded = sizeof(OSVERSIONINFOEXA); } } else { ReturnValue = GetPrinterDataW(hPrinter, pUnicodeValueName, pType, pData, nSize, pcbNeeded); // // Special case string values // if ((ReturnValue == ERROR_MORE_DATA || ReturnValue == ERROR_SUCCESS) && (*pType == REG_MULTI_SZ || *pType == REG_SZ || *pType == REG_EXPAND_SZ)) { if (ReturnValue==ERROR_SUCCESS) { // // The buffer passed in by the caller was large enough. We only need to // convert from UNICODE to ANSI. It can happen that a UNICODE char will // be represented on 3 ansi chars, so we cannot assume that if a buffer // is large enough for a unicode string, it can also accomodate the converted // ansi string. // ReturnValue = UnicodeToAnsi(NULL, 0, pData, *pcbNeeded, pcbNeeded); } else { BYTE *pBuf = NULL; if (pBuf = LocalAlloc(LPTR, *pcbNeeded)) { if ((ReturnValue = GetPrinterDataW(hPrinter, pUnicodeValueName, pType, pBuf, *pcbNeeded, pcbNeeded)) == ERROR_SUCCESS) { ReturnValue = UnicodeToAnsi(pBuf, *pcbNeeded / sizeof(WCHAR), pData, nSize, pcbNeeded); } LocalFree(pBuf); } else { ReturnValue = GetLastError(); } } } } } FreeUnicodeString(pUnicodeValueName); return ReturnValue; } DWORD GetPrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded ) { DWORD ReturnValue = ERROR_SUCCESS; DWORD ReturnType = 0; LPWSTR pUnicodeValueName = NULL; LPWSTR pUnicodeKeyName = NULL; pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName); if (pValueName && !pUnicodeValueName) goto Cleanup; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; if (!pType) { pType = (PDWORD) &ReturnType; } if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSION)) { // // The caller wants OSVersion // OSVERSIONINFOW osw = {0}; ReturnValue = GetPrinterDataExW(hPrinter, (LPCWSTR)pUnicodeKeyName, (LPCWSTR)pUnicodeValueName, pType, (PBYTE)&osw, nSize >= sizeof(OSVERSIONINFOA) ? sizeof(osw) : nSize, pcbNeeded); if (ReturnValue == ERROR_SUCCESS && pData) { OSVERSIONWRAP wrap = {0}; wrap.bOsVersionEx = FALSE; wrap.Unicode.pOsVersion = &osw; wrap.Ansi.pOsVersion = (OSVERSIONINFOA *)pData; ReturnValue = CopyOsVersionUnicodeToAnsi(wrap); } // // Set correct number of bytes required/returned // if (pcbNeeded) { *pcbNeeded = sizeof(OSVERSIONINFOA); } } else if (pUnicodeValueName && !_wcsicmp(pUnicodeValueName, SPLREG_OS_VERSIONEX)) { // // The caller wants OSVersionEx // OSVERSIONINFOEXW osexw = {0}; ReturnValue = GetPrinterDataExW(hPrinter, (LPCWSTR)pUnicodeKeyName, (LPCWSTR)pUnicodeValueName, pType, (PBYTE)&osexw, nSize >= sizeof(OSVERSIONINFOEXA) ? sizeof(osexw) : nSize, pcbNeeded); if (ReturnValue == ERROR_SUCCESS && pData) { OSVERSIONWRAP wrap = {0}; wrap.bOsVersionEx = TRUE; wrap.Unicode.pOsVersionEx = &osexw; wrap.Ansi.pOsVersionEx = (OSVERSIONINFOEXA *)pData; ReturnValue = CopyOsVersionUnicodeToAnsi(wrap); } // // Set correct number of bytes required/returned // if (pcbNeeded) { *pcbNeeded = sizeof(OSVERSIONINFOEXA); } } else { ReturnValue = GetPrinterDataExW(hPrinter, (LPCWSTR)pUnicodeKeyName, (LPCWSTR)pUnicodeValueName, pType, pData, nSize, pcbNeeded); // // Special case string values // if ((ReturnValue == ERROR_MORE_DATA || ReturnValue == ERROR_SUCCESS) && (*pType == REG_MULTI_SZ || *pType == REG_SZ || *pType == REG_EXPAND_SZ)) { if (ReturnValue==ERROR_SUCCESS) { // // The buffer passed in by the caller was large enough. We only need to // convert from UNICODE to ANSI. It can happen that a UNICODE char will // be represented on 3 ansi chars, so we cannot assume that if a buffer // is large enough for a unicode string, it can also accomodate the converted // ansi string. // ReturnValue = UnicodeToAnsi(NULL, 0, pData, *pcbNeeded, pcbNeeded); } else { BYTE *pBuf = NULL; if (pBuf = LocalAlloc(LPTR, *pcbNeeded)) { if ((ReturnValue = GetPrinterDataExW(hPrinter, (LPCWSTR)pUnicodeKeyName, (LPCWSTR)pUnicodeValueName, pType, pBuf, *pcbNeeded, pcbNeeded)) == ERROR_SUCCESS) { ReturnValue = UnicodeToAnsi(pBuf, *pcbNeeded / sizeof(WCHAR), pData, nSize, pcbNeeded); } LocalFree(pBuf); } else { ReturnValue = GetLastError(); } } } } Cleanup: FreeUnicodeString(pUnicodeKeyName); FreeUnicodeString(pUnicodeValueName); return ReturnValue; } DWORD EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, // index of value to query LPSTR pValueName, // address of buffer for value string DWORD cbValueName, // size of pValueName LPDWORD pcbValueName, // address for size of value buffer LPDWORD pType, // address of buffer for type code LPBYTE pData, // address of buffer for value data DWORD cbData, // size of pData LPDWORD pcbData // address for size of data buffer ) { DWORD ReturnValue = 0; DWORD i; ReturnValue = EnumPrinterDataW(hPrinter, dwIndex, (LPWSTR) pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData); if (ReturnValue == ERROR_SUCCESS && (cbValueName || cbData)) { if (pData && pType && (*pType==REG_SZ || *pType==REG_MULTI_SZ || *pType==REG_EXPAND_SZ)) { // // For this API we will require a buffer size that can accomodate UNICODE strings // We do not want UnicodeToAnsi to update the number of bytes needed to store // the string converted to ansi. // UnicodeToAnsi(NULL, 0, pData, *pcbData, NULL); } UnicodeToAnsiString((LPWSTR) pValueName, (LPSTR) pValueName, NULL_TERMINATED); } return ReturnValue; } DWORD EnumPrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName, LPBYTE pEnumValues, DWORD cbEnumValues, LPDWORD pcbEnumValues, LPDWORD pnEnumValues ) { DWORD ReturnValue = 0; DWORD i; PPRINTER_ENUM_VALUES pEnumValue; LPWSTR pUnicodeKeyName = NULL; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; ReturnValue = EnumPrinterDataExW(hPrinter, (LPCWSTR) pUnicodeKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues); if (ReturnValue == ERROR_SUCCESS) { pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValues; for(i = 0 ; i < *pnEnumValues ; ++i, ++pEnumValue) { if (pEnumValue->cbValueName) { UnicodeToAnsiString((LPWSTR) pEnumValue->pValueName, (LPSTR) pEnumValue->pValueName, NULL_TERMINATED); } if (pEnumValue->pData && (pEnumValue->dwType == REG_SZ || pEnumValue->dwType == REG_MULTI_SZ || pEnumValue->dwType == REG_EXPAND_SZ)) { // // For this API we will require a buffer size that can accomodate UNICODE strings // We do not want UnicodeToAnsi to update the number of bytes needed to store // the string converted to ansi. // UnicodeToAnsi(NULL, 0, pEnumValue->pData, pEnumValue->cbData, NULL); } } } Cleanup: FreeUnicodeString(pUnicodeKeyName); return ReturnValue; } DWORD EnumPrinterKeyA( HANDLE hPrinter, LPCSTR pKeyName, LPSTR pSubkey, // address of buffer for value string DWORD cbSubkey, // size of pValueName LPDWORD pcbSubkey // address for size of value buffer ) { DWORD ReturnValue = 0; LPWSTR pUnicodeKeyName = NULL; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; ReturnValue = EnumPrinterKeyW( hPrinter, (LPCWSTR) pUnicodeKeyName, (LPWSTR) pSubkey, cbSubkey, pcbSubkey); if (ReturnValue == ERROR_SUCCESS && cbSubkey) { ReturnValue = UnicodeToAnsi(NULL, 0, pSubkey, *pcbSubkey, pcbSubkey); } else if (ReturnValue == ERROR_MORE_DATA) { BYTE *pBuf = NULL; if (pBuf = LocalAlloc(LPTR, *pcbSubkey)) { if ((ReturnValue = EnumPrinterKeyW(hPrinter, (LPCWSTR)pUnicodeKeyName, (LPWSTR)pBuf, *pcbSubkey, pcbSubkey)) == ERROR_SUCCESS) { ReturnValue = UnicodeToAnsi(pBuf, *pcbSubkey / sizeof(WCHAR), pSubkey, cbSubkey, pcbSubkey); } LocalFree(pBuf); } else { ReturnValue = GetLastError(); } } Cleanup: FreeUnicodeString(pUnicodeKeyName); return ReturnValue; } DWORD DeletePrinterDataA( HANDLE hPrinter, LPSTR pValueName ) { DWORD ReturnValue = 0; LPWSTR pUnicodeValueName = NULL; pUnicodeValueName = AllocateUnicodeString(pValueName); if (pValueName && !pUnicodeValueName) goto Cleanup; ReturnValue = DeletePrinterDataW(hPrinter, (LPWSTR) pUnicodeValueName); Cleanup: FreeUnicodeString(pUnicodeValueName); return ReturnValue; } DWORD DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName ) { DWORD ReturnValue = 0; LPWSTR pUnicodeKeyName = NULL; LPWSTR pUnicodeValueName = NULL; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName); if (pValueName && !pUnicodeValueName) goto Cleanup; ReturnValue = DeletePrinterDataExW(hPrinter, (LPCWSTR) pUnicodeKeyName, (LPCWSTR) pUnicodeValueName); Cleanup: FreeUnicodeString(pUnicodeKeyName); FreeUnicodeString(pUnicodeValueName); return ReturnValue; } DWORD DeletePrinterKeyA( HANDLE hPrinter, LPCSTR pKeyName ) { DWORD ReturnValue = 0; LPWSTR pUnicodeKeyName = NULL; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; ReturnValue = DeletePrinterKeyW(hPrinter, (LPCWSTR) pUnicodeKeyName); Cleanup: FreeUnicodeString(pUnicodeKeyName); return ReturnValue; } DWORD SetPrinterDataA( HANDLE hPrinter, LPSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData ) { DWORD ReturnValue = 0; LPWSTR pUnicodeValueName = NULL; LPWSTR pUnicodeData = NULL; DWORD cbDataString; DWORD i; pUnicodeValueName = AllocateUnicodeString(pValueName); if (pValueName && !pUnicodeValueName) goto Cleanup; if (Type == REG_SZ || Type == REG_EXPAND_SZ || Type == REG_MULTI_SZ) { // // No matter if reg_sz or multi_sz, we want to mimic the registry APIs // in behavior. This means we will not check strings for null termination. // We will set as many bytes as specified by cbData // pUnicodeData = AllocateUnicodeStringWithSize(pData, cbData); if (pUnicodeData) { cbData *= sizeof(WCHAR); ReturnValue = SetPrinterDataW(hPrinter, pUnicodeValueName, Type, (LPBYTE) pUnicodeData, cbData); FreeUnicodeString(pUnicodeData); } else { ReturnValue = ERROR_INVALID_PARAMETER; } } else { ReturnValue = SetPrinterDataW(hPrinter, pUnicodeValueName, Type, pData, cbData); } Cleanup: FreeUnicodeString(pUnicodeValueName); return ReturnValue; } DWORD SetPrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData ) { DWORD ReturnValue = 0; LPWSTR pUnicodeKeyName = NULL; LPWSTR pUnicodeValueName = NULL; LPWSTR pUnicodeData = NULL; DWORD cbDataString; DWORD i; pUnicodeKeyName = AllocateUnicodeString((LPSTR) pKeyName); if (pKeyName && !pUnicodeKeyName) goto Cleanup; pUnicodeValueName = AllocateUnicodeString((LPSTR) pValueName); if (pValueName && !pUnicodeValueName) goto Cleanup; if (Type == REG_SZ || Type == REG_EXPAND_SZ || Type == REG_MULTI_SZ) { // // No matter if reg_sz or multi_sz, we want to mimic the registry APIs // in behavior. This means we will not check strings for null termination. // We will set as many bytes as specified by cbData // pUnicodeData = AllocateUnicodeStringWithSize(pData, cbData); if (pUnicodeData) { cbData *= sizeof(WCHAR); ReturnValue = SetPrinterDataExW(hPrinter, (LPCWSTR) pUnicodeKeyName, (LPCWSTR) pUnicodeValueName, Type, (LPBYTE) pUnicodeData, cbData); FreeUnicodeString(pUnicodeData); } else { ReturnValue = ERROR_INVALID_PARAMETER; } } else { ReturnValue = SetPrinterDataExW(hPrinter, (LPCWSTR) pUnicodeKeyName, (LPCWSTR) pUnicodeValueName, Type, pData, cbData); } Cleanup: FreeUnicodeString(pUnicodeValueName); FreeUnicodeString(pUnicodeKeyName); return ReturnValue; } /**************************** Function Header ******************************* * DocumentPropertiesA * The ANSI version of the DocumentProperties function. Basically * converts the input parameters to UNICODE versions and calls * the DocumentPropertiesW function. * * CAVEATS: PRESUMES THAT IF pDevModeOutput IS SUPPLIED, IT HAS THE SIZE * OF THE UNICODE VERSION. THIS WILL USUALLY HAPPEN IF THE CALLER * FIRST CALLS TO FIND THE SIZE REQUIRED> * * RETURNS: * Somesort of LONG. * * HISTORY: * 10:12 on 11-Aug-92 -by- Lindsay Harris [lindsayh] * Changed to call DocumentPropertiesW * * Created by DaveSn * ****************************************************************************/ LONG DocumentPropertiesA( HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode ) { LPWSTR pUnicodeDeviceName = NULL; LPDEVMODEW pUnicodeDevModeInput = NULL; LPDEVMODEW pUnicodeDevModeOutput = NULL; LONG ReturnValue = -1; pUnicodeDeviceName = AllocateUnicodeString(pDeviceName); if (pDeviceName && !pUnicodeDeviceName) goto Cleanup; ReturnValue = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName, NULL, NULL, 0); if (ReturnValue > 0) { if (fMode) { if (pUnicodeDevModeOutput = LocalAlloc(LMEM_FIXED, ReturnValue)) { // // Only convert the input buffer if one is specified // and fMode indicates it's valid. WinNT 3.51 used // pDevModeInput regardless of DM_IN_BUFFER, but this // broke Borland Delphi for win95 + Corel Flow for win95. // if( pDevModeInput && ( fMode & DM_IN_BUFFER )){ // // If the devmode is invalid, then don't pass one in. // This fixes MS Imager32 (which passes dmSize == 0) and // Milestones etc. 4.5. // // Note: this assumes that pDevModeOutput is still the // correct size! // if( !bValidDevModeA( pDevModeInput )){ fMode &= ~DM_IN_BUFFER; } else { pUnicodeDevModeInput = AllocateUnicodeDevMode( pDevModeInput ); if( !pUnicodeDevModeInput ){ ReturnValue = -1; goto Cleanup; } } } ReturnValue = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName, pUnicodeDevModeOutput, pUnicodeDevModeInput, fMode ); // // The printer driver has filled in the DEVMODEW // structure - if one was passed in. Now convert it // back to a DEVMODEA structure. // if (pDevModeOutput && (ReturnValue == IDOK)) { CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput, pUnicodeDevModeOutput); } } else ReturnValue = -1; } else ReturnValue-=sizeof(DEVMODEW)-sizeof(DEVMODEA); } Cleanup: if (pUnicodeDevModeInput) LocalFree(pUnicodeDevModeInput); if (pUnicodeDevModeOutput) LocalFree(pUnicodeDevModeOutput); FreeUnicodeString(pUnicodeDeviceName); return ReturnValue; } BOOL WriteCurDevModeToRegistry( LPWSTR pPrinterName, LPDEVMODEW pDevMode ) { DWORD Status; HKEY hDevMode; SPLASSERT(pDevMode); Status = RegCreateKeyEx(HKEY_CURRENT_USER, szCurDevMode, 0, NULL, 0, KEY_WRITE, NULL, &hDevMode, NULL); if ( Status == ERROR_SUCCESS ) { Status = RegSetValueExW(hDevMode, pPrinterName, 0, REG_BINARY, (LPBYTE)pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra); RegCloseKey(hDevMode); } return Status == ERROR_SUCCESS; } BOOL DeleteCurDevModeFromRegistry( PWSTR pPrinterName ) { DWORD Status; HKEY hDevModeKey; Status = RegCreateKeyEx(HKEY_CURRENT_USER, szCurDevMode, 0, NULL, 0, KEY_WRITE, NULL, &hDevModeKey, NULL); if ( Status == ERROR_SUCCESS ) { Status = RegDeleteValue(hDevModeKey, pPrinterName); RegCloseKey(hDevModeKey); } return Status == ERROR_SUCCESS; } // MLAWRENC - This code now checks to see that the DEVMODE in the registry matches that of // the driver. If it does not, then 1. The driver has been migrated. 2. The user has been // using an incompatible driver. In this case, the per user DEVMODE settings are overwritten // with those obtained from the driver. LPDEVMODEW AllocateCurDevMode( HANDLE hPrinter, LPWSTR pDeviceName, LONG cbDevMode ) { LPDEVMODEW pRegDevMode = NULL; LPDEVMODEW pRealDevMode = NULL; LPDEVMODEW pRetDevMode = NULL; BOOL bUpdateReg = FALSE; HANDLE hKeyDevMode = INVALID_HANDLE_VALUE; DWORD dwStatus, dwType; LONG lDocStatus; dwStatus = RegCreateKeyEx( HKEY_CURRENT_USER, szCurDevMode, 0, NULL, 0, KEY_READ, NULL, &hKeyDevMode, NULL); if( dwStatus != ERROR_SUCCESS ) goto Cleanup; pRegDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED, cbDevMode); pRealDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED, cbDevMode); // This cbDevMode is obtained via a call to DocumentPropertiesW, thus it is // correct (unless race condition). if( pRegDevMode == NULL || pRealDevMode == NULL) goto Cleanup; lDocStatus = DocumentPropertiesW( NULL, hPrinter, pDeviceName, pRealDevMode, NULL, DM_COPY ); dwStatus = RegQueryValueExW(hKeyDevMode, pDeviceName, 0, &dwType, (LPBYTE)pRegDevMode, &cbDevMode); bUpdateReg = (dwStatus != ERROR_SUCCESS || dwType != REG_BINARY) && lDocStatus == IDOK; if (dwStatus == ERROR_SUCCESS && lDocStatus == IDOK && !bUpdateReg) { // Check to see that our DEVMODE structures are compatible bUpdateReg = pRealDevMode->dmSize != pRegDevMode->dmSize || pRealDevMode->dmDriverExtra != pRegDevMode->dmDriverExtra || pRealDevMode->dmSpecVersion != pRegDevMode->dmSpecVersion || pRealDevMode->dmDriverVersion != pRegDevMode->dmDriverVersion; if (!bUpdateReg) pRetDevMode = pRegDevMode; } if (bUpdateReg) { // The Registry is out of date, The read from the Document properties must have // succeded if (!WriteCurDevModeToRegistry(pDeviceName, pRealDevMode) ) goto Cleanup; else pRetDevMode = pRealDevMode; } Cleanup: if (pRegDevMode != pRetDevMode && pRegDevMode != NULL) LocalFree(pRegDevMode); if (pRealDevMode != pRetDevMode && pRealDevMode != NULL) LocalFree(pRealDevMode); if (hKeyDevMode != INVALID_HANDLE_VALUE) RegCloseKey( hKeyDevMode ); return pRetDevMode; } VOID MergeDevMode( LPDEVMODEW pDMOut, LPDEVMODEW pDMIn ) { // // Simply check each bit in the dmFields entry. If set, then copy // the input data to the output data. // if ( pDMIn->dmFields & DM_ORIENTATION ) { pDMOut->dmOrientation = pDMIn->dmOrientation; pDMOut->dmFields |= DM_ORIENTATION; } if( (pDMIn->dmFields & (DM_FORMNAME | DM_PAPERSIZE)) || (pDMIn->dmFields & (DM_PAPERLENGTH | DM_PAPERWIDTH)) == (DM_PAPERLENGTH | DM_PAPERWIDTH) ) { /* Value user fields, so use them. And delete ALL ours! */ pDMOut->dmFields &= ~(DM_FORMNAME | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH); if( pDMIn->dmFields & DM_PAPERSIZE ) { pDMOut->dmPaperSize = pDMIn->dmPaperSize; pDMOut->dmFields |= DM_PAPERSIZE; } if( pDMIn->dmFields & DM_PAPERLENGTH ) { pDMOut->dmPaperLength = pDMIn->dmPaperLength; pDMOut->dmFields |= DM_PAPERLENGTH; } if( pDMIn->dmFields & DM_PAPERWIDTH ) { pDMOut->dmPaperWidth = pDMIn->dmPaperWidth; pDMOut->dmFields |= DM_PAPERWIDTH; } if( pDMIn->dmFields & DM_FORMNAME ) { CopyMemory( pDMOut->dmFormName, pDMIn->dmFormName, sizeof( pDMOut->dmFormName ) ); pDMOut->dmFields |= DM_FORMNAME; } } if( pDMIn->dmFields & DM_SCALE ) { pDMOut->dmScale = pDMIn->dmScale; pDMOut->dmFields |= DM_SCALE; } if ( pDMIn->dmFields & DM_COPIES ) { pDMOut->dmCopies = pDMIn->dmCopies; pDMOut->dmFields |= DM_COPIES; } if ( pDMIn->dmFields & DM_DEFAULTSOURCE ) { pDMOut->dmDefaultSource = pDMIn->dmDefaultSource; pDMOut->dmFields |= DM_DEFAULTSOURCE; } if ( pDMIn->dmFields & DM_PRINTQUALITY ) { pDMOut->dmPrintQuality = pDMIn->dmPrintQuality; pDMOut->dmFields |= DM_PRINTQUALITY; } if ( pDMIn->dmFields & DM_COLOR ) { pDMOut->dmColor = pDMIn->dmColor; pDMOut->dmFields |= DM_COLOR; } if ( pDMIn->dmFields & DM_DUPLEX ) { pDMOut->dmDuplex = pDMIn->dmDuplex; pDMOut->dmFields |= DM_DUPLEX; } if ( pDMIn->dmFields & DM_YRESOLUTION ) { /* * Note that DM_YRESOLUTION implies there is data in dmPrintQuality. * This latter field is used to specify the desired X resolution, * which is only required for dot matrix printers. */ pDMOut->dmYResolution = pDMIn->dmYResolution; pDMOut->dmPrintQuality = pDMIn->dmPrintQuality; pDMOut->dmFields |= DM_YRESOLUTION; } if ( pDMIn->dmFields & DM_TTOPTION ) { pDMOut->dmTTOption = pDMIn->dmTTOption; pDMOut->dmFields |= DM_TTOPTION; } if ( pDMIn->dmFields & DM_COLLATE ) { pDMOut->dmCollate = pDMIn->dmCollate; pDMOut->dmFields |= DM_COLLATE; } if ( pDMIn->dmFields & DM_ICMMETHOD ) { pDMOut->dmICMMethod = pDMIn->dmICMMethod; pDMOut->dmFields |= DM_ICMMETHOD; } if ( pDMIn->dmFields & DM_ICMINTENT ) { pDMOut->dmICMIntent = pDMIn->dmICMIntent; pDMOut->dmFields |= DM_ICMINTENT; } if ( pDMIn->dmFields & DM_MEDIATYPE ) { pDMOut->dmMediaType = pDMIn->dmMediaType; pDMOut->dmFields |= DM_MEDIATYPE; } if ( pDMIn->dmFields & DM_DITHERTYPE ) { pDMOut->dmDitherType = pDMIn->dmDitherType; pDMOut->dmFields |= DM_DITHERTYPE; } } LONG ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput, LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile, DWORD fMode ) { HANDLE hPrinter = NULL; LONG cbDevMode; DWORD NewfMode; LPDEVMODEW pNewDevModeIn = NULL; LPDEVMODEW pNewDevModeOut = NULL, pTempDevMode = NULL; LONG ReturnValue = -1; PRINTER_DEFAULTSW PrinterDefaults={NULL, NULL, PRINTER_READ}; LPWSTR pUnicodeDeviceName; LPWSTR pUnicodePort; pUnicodeDeviceName = AllocateUnicodeString(pDeviceName); if (pDeviceName && !pUnicodeDeviceName) return ReturnValue; pUnicodePort = AllocateUnicodeString(pPort); if (pPort && !pUnicodePort) { FreeUnicodeString(pUnicodeDeviceName); return ReturnValue; } if (OpenPrinterW(pUnicodeDeviceName, &hPrinter, &PrinterDefaults)) { cbDevMode = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName, NULL, NULL, 0); if (!fMode || cbDevMode <= 0) { ClosePrinter(hPrinter); FreeUnicodeString(pUnicodeDeviceName); FreeUnicodeString(pUnicodePort); if (!fMode) cbDevMode -= sizeof(DEVMODEW) - sizeof(DEVMODEA); return cbDevMode; } pNewDevModeOut = (PDEVMODEW)LocalAlloc( LMEM_FIXED, cbDevMode ); if( !pNewDevModeOut ){ ClosePrinter(hPrinter); FreeUnicodeString(pUnicodeDeviceName); FreeUnicodeString(pUnicodePort); return -1; } // // If our flags specify an input DevMode, and we have // an input devmode, use it. // if(( fMode & DM_IN_BUFFER ) && pDevModeInput ){ // // App may specify one or two fields in dmFields and expect us // to merge it with the global 16-bit devmode // pNewDevModeIn = AllocateCurDevMode(hPrinter, pUnicodeDeviceName, cbDevMode); pTempDevMode = AllocateUnicodeDevMode(pDevModeInput); // // correct any bogus field settings for the papersize stuff // ValidatePaperFields(pUnicodeDeviceName, pUnicodePort, pTempDevMode); if ( !pNewDevModeIn || !pTempDevMode ) { if ( pNewDevModeIn ) LocalFree(pNewDevModeIn); if ( pTempDevMode ) LocalFree(pTempDevMode); ClosePrinter(hPrinter); FreeUnicodeString(pUnicodeDeviceName); FreeUnicodeString(pUnicodePort); return -1; } // // Some apps will just set the public fields they want to be changed // from global devmode, so we need to merge input devmode with global // devmode // MergeDevMode(pNewDevModeIn, pTempDevMode); // // Copy input devmode's private section if present else send the // the private section from global devmode // if ( pTempDevMode->dmDriverExtra && pTempDevMode->dmDriverExtra == pNewDevModeIn->dmDriverExtra ) { CopyMemory((LPBYTE)pNewDevModeIn + pNewDevModeIn->dmSize, (LPBYTE)pTempDevMode + pTempDevMode->dmSize, pTempDevMode->dmDriverExtra); } LocalFree(pTempDevMode); pTempDevMode = NULL; } else { // // Get the win16 global devmode. // pNewDevModeIn = AllocateCurDevMode( hPrinter, pUnicodeDeviceName, cbDevMode ); if (!pNewDevModeIn) { ClosePrinter(hPrinter); FreeUnicodeString(pUnicodeDeviceName); FreeUnicodeString(pUnicodePort); return -1; } fMode |= DM_IN_BUFFER; } NewfMode = fMode; // // If DM_UPDATE is set, turn on DM_COPY so that we can update // the win16 devmode. // if (fMode & DM_UPDATE) NewfMode |= DM_COPY; ReturnValue = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName, pNewDevModeOut, pNewDevModeIn, NewfMode); if ( ReturnValue == IDOK && (fMode & DM_UPDATE) ) { if ( WriteCurDevModeToRegistry(pUnicodeDeviceName, pNewDevModeOut) ) { SendNotifyMessageW(HWND_BROADCAST, WM_DEVMODECHANGE, 0, (LPARAM)pUnicodeDeviceName); } else { ReturnValue = -1; } } if (pNewDevModeIn) LocalFree(pNewDevModeIn); if ((ReturnValue == IDOK) && (fMode & DM_COPY) && pDevModeOutput) CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput, pNewDevModeOut); if (pNewDevModeOut) LocalFree(pNewDevModeOut); ClosePrinter(hPrinter); } FreeUnicodeString(pUnicodeDeviceName); FreeUnicodeString(pUnicodePort); return ReturnValue; } void DeviceMode( HWND hWnd, HANDLE hModule, LPSTR pDevice, LPSTR pPort ) { HANDLE hPrinter, hDevMode; DWORD cbDevMode; LPDEVMODEW pNewDevMode, pDevMode=NULL; PRINTER_DEFAULTSW PrinterDefaults={NULL, NULL, PRINTER_READ}; DWORD Status, Type, cb; LPWSTR pUnicodeDevice; pUnicodeDevice = AllocateUnicodeString(pDevice); if (pDevice && !pUnicodeDevice) return; if (OpenPrinterW(pUnicodeDevice, &hPrinter, &PrinterDefaults)) { Status = RegCreateKeyExW(HKEY_CURRENT_USER, szCurDevMode, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hDevMode, NULL); if (Status == ERROR_SUCCESS) { Status = RegQueryValueExW(hDevMode, pUnicodeDevice, 0, &Type, NULL, &cb); if (Status == ERROR_SUCCESS) { pDevMode = LocalAlloc(LMEM_FIXED, cb); if (pDevMode) { Status = RegQueryValueExW(hDevMode, pUnicodeDevice, 0, &Type, (LPBYTE)pDevMode, &cb); if (Status != ERROR_SUCCESS) { LocalFree(pDevMode); pDevMode = NULL; } } else { goto Cleanup; } } cbDevMode = DocumentPropertiesW(hWnd, hPrinter, pUnicodeDevice, NULL, pDevMode, 0); if (cbDevMode > 0) { if (pNewDevMode = (PDEVMODEW)LocalAlloc(LMEM_FIXED, cbDevMode)) { if (DocumentPropertiesW(hWnd, hPrinter, pUnicodeDevice, pNewDevMode, pDevMode, DM_COPY | DM_PROMPT | DM_MODIFY) == IDOK) { Status = RegSetValueExW(hDevMode, pUnicodeDevice, 0, REG_BINARY, (LPBYTE)pNewDevMode, pNewDevMode->dmSize + pNewDevMode->dmDriverExtra); if (Status == ERROR_SUCCESS) { // Whew, we made it, simply fall out } } LocalFree(pNewDevMode); } } if (pDevMode) LocalFree(pDevMode); RegCloseKey(hDevMode); } ClosePrinter(hPrinter); } Cleanup: FreeUnicodeString(pUnicodeDevice); return; } LONG AdvancedDocumentPropertiesA( HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput ) { LONG ReturnValue = FALSE; LPWSTR pUnicodeDeviceName = NULL; LPDEVMODEW pUnicodeDevModeInput = NULL; LPDEVMODEW pUnicodeDevModeOutput = NULL; LONG cbOutput = 0; pUnicodeDeviceName = AllocateUnicodeString(pDeviceName); if (pDeviceName && !pUnicodeDeviceName) goto Cleanup; if( bValidDevModeA( pDevModeInput )){ pUnicodeDevModeInput = AllocateUnicodeDevMode(pDevModeInput); if( !pUnicodeDevModeInput ){ goto Cleanup; } // // The output DevMode must be at least as big as the input // DevMode. // cbOutput = pDevModeInput->dmSize + pDevModeInput->dmDriverExtra + sizeof(DEVMODEW) - sizeof(DEVMODEA); } if( pDevModeOutput ){ if( !cbOutput ){ // // We don't know the output size of the devmode, so make // call DocumentPropertiesW to find out. // cbOutput = DocumentPropertiesW( hWnd, hPrinter, pUnicodeDeviceName, NULL, NULL, 0 ); if( cbOutput <= 0 ){ goto Cleanup; } } pUnicodeDevModeOutput = (PDEVMODEW)LocalAlloc( LPTR, cbOutput ); if( !pUnicodeDevModeOutput ){ goto Cleanup; } } ReturnValue = AdvancedDocumentPropertiesW(hWnd, hPrinter, pUnicodeDeviceName, pUnicodeDevModeOutput, pUnicodeDevModeInput ); if( pDevModeOutput && (ReturnValue > 0) ){ CopyAnsiDevModeFromUnicodeDevMode(pDevModeOutput, pUnicodeDevModeOutput); } if ( !pDevModeOutput && ReturnValue > 0 ) ReturnValue -= sizeof(DEVMODEW) - sizeof(DEVMODEA); Cleanup: if (pUnicodeDevModeOutput) LocalFree(pUnicodeDevModeOutput); if (pUnicodeDevModeInput) LocalFree(pUnicodeDevModeInput); FreeUnicodeString(pUnicodeDeviceName); return ReturnValue; } LONG AdvancedSetupDialog( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeInput, LPDEVMODEA pDevModeOutput ) { HANDLE hPrinter; LONG ReturnValue = -1; if (OpenPrinterA(pDevModeInput->dmDeviceName, &hPrinter, NULL)) { ReturnValue = AdvancedDocumentPropertiesA(hWnd, hPrinter, pDevModeInput->dmDeviceName, pDevModeOutput, pDevModeInput); ClosePrinter(hPrinter); } return ReturnValue; } BOOL AddFormA( HANDLE hPrinter, DWORD Level, LPBYTE pForm ) { BOOL ReturnValue; LPBYTE pUnicodeForm; pUnicodeForm = AllocateUnicodeStructure(pForm, sizeof(FORM_INFO_1A), FormInfo1Strings); if (pForm && !pUnicodeForm) return FALSE; ReturnValue = AddFormW(hPrinter, Level, pUnicodeForm); FreeUnicodeStructure(pUnicodeForm, FormInfo1Offsets); return ReturnValue; } BOOL DeleteFormA( HANDLE hPrinter, LPSTR pFormName ) { BOOL ReturnValue; LPWSTR pUnicodeFormName; pUnicodeFormName = AllocateUnicodeString(pFormName); if (pFormName && !pUnicodeFormName) return FALSE; ReturnValue = DeleteFormW(hPrinter, pUnicodeFormName); FreeUnicodeString(pUnicodeFormName); return ReturnValue; } BOOL GetFormA( HANDLE hPrinter, LPSTR pFormName, DWORD Level, LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded ) { BOOL ReturnValue; DWORD *pOffsets; LPWSTR pUnicodeFormName; switch (Level) { case 1: pOffsets = FormInfo1Strings; break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeFormName = AllocateUnicodeString(pFormName); if (pFormName && !pUnicodeFormName) return FALSE; ReturnValue = GetFormW(hPrinter, pUnicodeFormName, Level, pForm, cbBuf, pcbNeeded); if (ReturnValue && pForm) ConvertUnicodeToAnsiStrings(pForm, pOffsets); FreeUnicodeString(pUnicodeFormName); return ReturnValue; } BOOL SetFormA( HANDLE hPrinter, LPSTR pFormName, DWORD Level, LPBYTE pForm ) { BOOL ReturnValue = FALSE; LPWSTR pUnicodeFormName = NULL; LPBYTE pUnicodeForm = NULL; pUnicodeFormName = AllocateUnicodeString(pFormName); if (pFormName && !pUnicodeFormName) goto Cleanup; pUnicodeForm = AllocateUnicodeStructure(pForm, sizeof(FORM_INFO_1A), FormInfo1Strings); if (pForm && !pUnicodeForm) goto Cleanup; ReturnValue = SetFormW(hPrinter, pUnicodeFormName, Level, pUnicodeForm); Cleanup: FreeUnicodeString(pUnicodeFormName); FreeUnicodeStructure(pUnicodeForm, FormInfo1Offsets); return ReturnValue; } BOOL EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue; DWORD cbStruct; DWORD *pOffsets; switch (Level) { case 1: pOffsets = FormInfo1Strings; cbStruct = sizeof(FORM_INFO_1); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } ReturnValue = EnumFormsW(hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned); if (ReturnValue && pForm) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pForm, pOffsets); pForm+=cbStruct; } } return ReturnValue; } BOOL EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPort, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue = FALSE; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName = NULL; switch (Level) { case 1: pOffsets = PortInfo1Strings; cbStruct = sizeof(PORT_INFO_1); break; case 2: pOffsets = PortInfo2Strings; cbStruct = sizeof(PORT_INFO_2); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; ReturnValue = EnumPortsW(pUnicodeName, Level, pPort, cbBuf, pcbNeeded, pcReturned); if (ReturnValue && pPort) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pPort, pOffsets); pPort+=cbStruct; } } Cleanup: FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL EnumMonitorsA( LPSTR pName, DWORD Level, LPBYTE pMonitor, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { BOOL ReturnValue = FALSE; DWORD cbStruct; DWORD *pOffsets; LPWSTR pUnicodeName = NULL; switch (Level) { case 1: pOffsets = MonitorInfo1Strings; cbStruct = sizeof(MONITOR_INFO_1); break; case 2: pOffsets = MonitorInfo2Strings; cbStruct = sizeof(MONITOR_INFO_2); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; ReturnValue = EnumMonitorsW(pUnicodeName, Level, pMonitor, cbBuf, pcbNeeded, pcReturned); if (ReturnValue && pMonitor) { DWORD i=*pcReturned; while (i--) { ConvertUnicodeToAnsiStrings(pMonitor, pOffsets); pMonitor+=cbStruct; } } Cleanup: FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL AddPortA( LPSTR pName, HWND hWnd, LPSTR pMonitorName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeMonitorName = NULL; DWORD ReturnValue = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeMonitorName = AllocateUnicodeString(pMonitorName); if (pMonitorName && !pUnicodeMonitorName) goto Cleanup; ReturnValue = AddPortW( pUnicodeName, hWnd, pUnicodeMonitorName ); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeMonitorName); return ReturnValue; } BOOL ConfigurePortA( LPSTR pName, HWND hWnd, LPSTR pPortName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodePortName = NULL; DWORD ReturnValue = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodePortName = AllocateUnicodeString(pPortName); if (pPortName && !pUnicodePortName) goto Cleanup; ReturnValue = ConfigurePortW( pUnicodeName, hWnd, pUnicodePortName ); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodePortName); return ReturnValue; } BOOL DeletePortA( LPSTR pName, HWND hWnd, LPSTR pPortName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodePortName = NULL; DWORD ReturnValue = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodePortName = AllocateUnicodeString(pPortName); if (pPortName && !pUnicodePortName) goto Cleanup; ReturnValue = DeletePortW( pUnicodeName, hWnd, pUnicodePortName ); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodePortName); return ReturnValue; } DWORD PrinterMessageBoxA( HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType ) { DWORD ReturnValue=FALSE; LPWSTR pTextW = NULL; LPWSTR pCaptionW = NULL; pTextW = AllocateUnicodeString(pText); if (pText && !pTextW) goto Cleanup; pCaptionW = AllocateUnicodeString(pCaption); if (pCaption && !pCaptionW) goto Cleanup; ReturnValue = PrinterMessageBoxW(hPrinter, Error, hWnd, pTextW, pCaptionW, dwType); Cleanup: FreeUnicodeString(pTextW); FreeUnicodeString(pCaptionW); return ReturnValue; } int DeviceCapabilitiesA( LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, CONST DEVMODEA *pDevMode ) { LPWSTR pDeviceW = NULL; LPWSTR pPortW = NULL; LPWSTR pOutputW = NULL; LPWSTR pKeepW = NULL; LPDEVMODEW pDevModeW = NULL; DWORD c, Size; int cb = 0; int rc = GDI_ERROR; pDeviceW = AllocateUnicodeString((LPSTR)pDevice); if (pDevice && !pDeviceW) goto Cleanup; pPortW = AllocateUnicodeString((LPSTR)pPort); if (pPort && !pPortW) goto Cleanup; if( bValidDevModeA( pDevMode )){ pDevModeW = AllocateUnicodeDevMode((LPDEVMODEA)pDevMode); if( !pDevModeW ){ goto Cleanup; } } switch (fwCapability) { // These will require Unicode to Ansi conversion case DC_BINNAMES: case DC_FILEDEPENDENCIES: case DC_PAPERNAMES: case DC_PERSONALITY: case DC_MEDIAREADY: case DC_MEDIATYPENAMES: if (pOutput) { cb = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability, NULL, pDevModeW); if (cb >= 0) { switch (fwCapability) { case DC_BINNAMES: cb *= 48; break; case DC_PERSONALITY: cb *= 64; break; case DC_FILEDEPENDENCIES: case DC_PAPERNAMES: case DC_MEDIAREADY: case DC_MEDIATYPENAMES: cb *= 128; break; } pOutputW = pKeepW = LocalAlloc(LPTR, cb); if (pKeepW) { c = rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability, pOutputW, pDevModeW); switch (fwCapability) { case DC_BINNAMES: Size = 24; break; case DC_PERSONALITY: Size = 32; break; case DC_FILEDEPENDENCIES: case DC_PAPERNAMES: case DC_MEDIAREADY: case DC_MEDIATYPENAMES: Size = 64; break; } for (; c; c--) { UnicodeToAnsiString(pOutputW, pOutput, NULL_TERMINATED); pOutputW += Size; pOutput += Size; } LocalFree(pKeepW); } } } else { rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability, NULL, pDevModeW); } break; default: rc = DeviceCapabilitiesW(pDeviceW, pPortW, fwCapability, (LPWSTR)pOutput, pDevModeW); // // If the call to find size of public portion of devmode and // it was succesful adjust the size for UNICODE->ANSI conversion // if ( fwCapability == DC_SIZE && rc > 0 ) { rc -= sizeof(DEVMODEW) - sizeof(DEVMODEA); } } Cleanup: FreeUnicodeString(pDeviceW); FreeUnicodeString(pPortW); if (pDevModeW) LocalFree(pDevModeW); return rc; } BOOL AddMonitorA( LPSTR pName, DWORD Level, LPBYTE pMonitorInfo ) { BOOL ReturnValue=FALSE; DWORD cbStruct; LPWSTR pUnicodeName = NULL; LPBYTE pUnicodeStructure = NULL; LPDWORD pOffsets; switch (Level) { case 2: pOffsets = MonitorInfo2Strings; cbStruct = sizeof(MONITOR_INFO_2); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeStructure = AllocateUnicodeStructure(pMonitorInfo, cbStruct, pOffsets); if (pMonitorInfo && !pUnicodeStructure) goto Cleanup; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; if (pUnicodeStructure) { ReturnValue = AddMonitorW(pUnicodeName, Level, pUnicodeStructure); } Cleanup: FreeUnicodeStructure(pUnicodeStructure, pOffsets); FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL DeleteMonitorA( LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodeMonitorName = NULL; BOOL rc = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodeMonitorName = AllocateUnicodeString(pMonitorName); if (pMonitorName && !pUnicodeMonitorName) goto Cleanup; rc = DeleteMonitorW(pUnicodeName, pUnicodeEnvironment, pUnicodeMonitorName); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodeMonitorName); return rc; } BOOL DeletePrintProcessorA( LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodePrintProcessorName = NULL; BOOL rc = FALSE; if (!pPrintProcessorName || !*pPrintProcessorName) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodePrintProcessorName = AllocateUnicodeString(pPrintProcessorName); if (pPrintProcessorName && !pUnicodePrintProcessorName) goto Cleanup; rc = DeletePrintProcessorW(pUnicodeName, pUnicodeEnvironment, pUnicodePrintProcessorName); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodePrintProcessorName); return rc; } BOOL AddPrintProvidorA( LPSTR pName, DWORD Level, LPBYTE pProvidorInfo ) { BOOL ReturnValue=FALSE; DWORD cbStruct; LPWSTR pUnicodeName = NULL; LPBYTE pUnicodeStructure = NULL; LPDWORD pOffsets; if (!pProvidorInfo) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } switch (Level) { case 1: pOffsets = ProvidorInfo1Strings; cbStruct = sizeof(PROVIDOR_INFO_1); break; case 2: pOffsets = ProvidorInfo2Strings; cbStruct = sizeof(PROVIDOR_INFO_2); break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } pUnicodeStructure = AllocateUnicodeStructure(pProvidorInfo, cbStruct, pOffsets); if (!pProvidorInfo || !pUnicodeStructure) goto CleanUp; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto CleanUp; if ((Level == 2) && !AnsiToUnicodeMultiSz((LPSTR) ((PPROVIDOR_INFO_2A) pProvidorInfo)->pOrder, &(((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder))) { goto CleanUp; } if (pUnicodeStructure) { ReturnValue = AddPrintProvidorW(pUnicodeName, Level, pUnicodeStructure); } if ((Level == 2) && ((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder) { LocalFree(((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder); ((PPROVIDOR_INFO_2W) pUnicodeStructure)->pOrder = NULL; } CleanUp: FreeUnicodeStructure(pUnicodeStructure, pOffsets); FreeUnicodeString(pUnicodeName); return ReturnValue; } BOOL DeletePrintProvidorA( LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProvidorName ) { LPWSTR pUnicodeName = NULL; LPWSTR pUnicodeEnvironment = NULL; LPWSTR pUnicodePrintProvidorName = NULL; BOOL rc = FALSE; pUnicodeName = AllocateUnicodeString(pName); if (pName && !pUnicodeName) goto Cleanup; pUnicodeEnvironment = AllocateUnicodeString(pEnvironment); if (pEnvironment && !pUnicodeEnvironment) goto Cleanup; pUnicodePrintProvidorName = AllocateUnicodeString(pPrintProvidorName); if (pPrintProvidorName && !pUnicodePrintProvidorName) goto Cleanup; rc = DeletePrintProvidorW(pUnicodeName, pUnicodeEnvironment, pUnicodePrintProvidorName); Cleanup: FreeUnicodeString(pUnicodeName); FreeUnicodeString(pUnicodeEnvironment); FreeUnicodeString(pUnicodePrintProvidorName); return rc; } BOOL AddPortExA( IN LPSTR pName, OPTIONAL IN DWORD Level, IN LPBYTE pBuffer, IN LPSTR pMonitorName ) { PPORT_INFO_1A pPortInfo1; PPORT_INFO_FFA pPortInfoFF; LPWSTR pNameW = NULL; LPWSTR pMonitorNameW = NULL; LPWSTR pPortNameW = NULL; PORT_INFO_1W PortInfo1; PORT_INFO_FFW PortInfoFF; DWORD LastError = ERROR_SUCCESS; BOOL bReturnValue = FALSE; // // Initialize variables that will be freed in error cases. // pNameW = AllocateUnicodeString( pName); if (pName && !pNameW) { LastError = GetLastError(); goto Done; } pPortNameW = NULL; pMonitorNameW = AllocateUnicodeString( pMonitorName); if (pMonitorName && !pMonitorNameW) { LastError = GetLastError(); goto Done; } if( !pBuffer || !pMonitorName ){ LastError = ERROR_INVALID_PARAMETER; goto Done; } // // Catch out of memory conditions. // if( !pMonitorNameW || ( pName && !pNameW )){ LastError = GetLastError(); goto Done; } switch( Level ){ case (DWORD)-1: pPortInfoFF = (PPORT_INFO_FFA)pBuffer; if( !pPortInfoFF->pName || !pPortInfoFF->pName[0] ){ LastError = ERROR_INVALID_PARAMETER; goto Done; } pPortNameW = PortInfoFF.pName = AllocateUnicodeString( pPortInfoFF->pName); if( !pPortNameW ){ LastError = GetLastError(); goto Done; } PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData; PortInfoFF.pMonitorData = pPortInfoFF->pMonitorData; bReturnValue = AddPortExW( pNameW, Level, (LPBYTE)&PortInfoFF, pMonitorNameW ); if( !bReturnValue ){ LastError = GetLastError(); } break; case 1: pPortInfo1 = (PPORT_INFO_1A)pBuffer; if( !pPortInfo1->pName || !pPortInfo1->pName[0] ){ LastError = ERROR_INVALID_PARAMETER; goto Done; } pPortNameW = PortInfo1.pName = AllocateUnicodeString( pPortInfo1->pName); if( !pPortNameW ){ LastError = GetLastError(); goto Done; } bReturnValue = AddPortExW( pNameW, Level, (LPBYTE)&PortInfo1, pMonitorNameW ); if( !bReturnValue ){ LastError = GetLastError(); } break; default: LastError = ERROR_INVALID_LEVEL; break; } Done: FreeUnicodeString( pNameW ); FreeUnicodeString( pPortNameW ); FreeUnicodeString( pMonitorNameW ); if( !bReturnValue ){ SetLastError( LastError ); return FALSE; } return TRUE; } LPSTR StartDocDlgA( HANDLE hPrinter, DOCINFOA *pDocInfo ) { DOCINFOW DocInfoW; LPSTR lpszAnsiOutput = NULL; LPSTR lpszAnsiString = NULL; LPWSTR lpszUnicodeString = NULL; DWORD dwLen = 0; if (!pDocInfo) { DBGMSG(DBG_WARNING, ("StartDocDlgA: Null pDocInfo passed in\n")); return NULL; } memset(&DocInfoW, 0, sizeof(DOCINFOW)); if (pDocInfo->lpszDocName) { DocInfoW.lpszDocName = (LPCWSTR)AllocateUnicodeString ((LPSTR)pDocInfo->lpszDocName); if (pDocInfo->lpszDocName && !DocInfoW.lpszDocName) return NULL; } if (pDocInfo->lpszOutput) { DocInfoW.lpszOutput = (LPCWSTR)AllocateUnicodeString((LPSTR)pDocInfo->lpszOutput); if (pDocInfo->lpszOutput && !DocInfoW.lpszOutput) { FreeUnicodeString((LPWSTR) DocInfoW.lpszDocName); return NULL; } } lpszUnicodeString = StartDocDlgW(hPrinter, &DocInfoW); if (lpszUnicodeString == (LPWSTR)-1) { lpszAnsiString = (LPSTR)-1; } else if (lpszUnicodeString == (LPWSTR)-2) { lpszAnsiString = (LPSTR)-2; } else if (lpszUnicodeString){ dwLen = wcslen(lpszUnicodeString); if (lpszAnsiString = LocalAlloc(LPTR, dwLen+1)){ UnicodeToAnsiString(lpszUnicodeString, lpszAnsiString, dwLen); LocalFree(lpszUnicodeString); } else { DBGMSG(DBG_WARNING, ("StartDocDlgA: LocalAlloc failed returning NULL\n")); } } if (DocInfoW.lpszDocName ) { FreeUnicodeString((LPWSTR)DocInfoW.lpszDocName); } if (DocInfoW.lpszOutput) { // // we might have changed the DocInfoW.lpszOutput as well // for pooled printing; so reconstruct pDocInfo->lpszOutput // dwLen = wcslen(DocInfoW.lpszOutput); UnicodeToAnsiString((LPWSTR)DocInfoW.lpszOutput, (LPSTR)pDocInfo->lpszOutput, dwLen); FreeUnicodeString((LPWSTR)DocInfoW.lpszOutput); } return lpszAnsiString; } BOOL SetPortA( LPSTR pszName, LPSTR pszPortName, DWORD dwLevel, LPBYTE pPorts ) { LPBYTE pUnicodeStructure = NULL; DWORD cbStruct; PDWORD pOffsets = NULL; LPWSTR pszUnicodeName = NULL; LPWSTR pszUnicodePortName = NULL; BOOL bRet = FALSE; switch (dwLevel) { case 3: pOffsets = PortInfo3Offsets; cbStruct = sizeof(PORT_INFO_3); break; default: SetLastError( ERROR_INVALID_LEVEL ); return FALSE; } pszUnicodeName = AllocateUnicodeString(pszName); if (pszName && !pszUnicodeName) goto Cleanup; pszUnicodePortName = AllocateUnicodeString(pszPortName); if (pszPortName && !pszUnicodePortName) goto Cleanup; pUnicodeStructure = AllocateUnicodeStructure(pPorts, cbStruct, pOffsets); if (pPorts && !pUnicodeStructure) goto Cleanup; bRet = SetPortW(pszUnicodeName, pszUnicodePortName, dwLevel, pUnicodeStructure); Cleanup: FreeUnicodeStructure(pUnicodeStructure, pOffsets); FreeUnicodeString(pszUnicodePortName); FreeUnicodeString(pszUnicodeName); return bRet; } BOOL bValidDevModeA( const DEVMODEA *pDevModeA ) /*++ 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( !pDevModeA ){ return FALSE; } if( pDevModeA->dmSize < MIN_DEVMODE_SIZEA ){ // // The only valid case is if pDevModeA is NULL. If it's // not NULL, then a bad devmode was passed in and the // app should fix it's code. // SPLASSERT( pDevModeA->dmSize >= MIN_DEVMODE_SIZEA ); return FALSE; } return TRUE; } /******************************************************************** Ansi version entry points for the default printer api set. ********************************************************************/ BOOL GetDefaultPrinterA( IN LPSTR pszBuffer, IN LPDWORD pcchBuffer ) { BOOL bRetval = TRUE; LPWSTR pszUnicodeBuffer = NULL; LPDWORD pcchUnicodeBuffer = pcchBuffer; if( pszBuffer && pcchBuffer && *pcchBuffer ) { pszUnicodeBuffer = LocalAlloc( LMEM_FIXED, *pcchBuffer * sizeof( WCHAR ) ); bRetval = pszUnicodeBuffer ? TRUE : FALSE; } if( bRetval ) { bRetval = GetDefaultPrinterW( pszUnicodeBuffer, pcchUnicodeBuffer ); if( bRetval && pszUnicodeBuffer ) { bRetval = UnicodeToAnsiString( pszUnicodeBuffer, pszBuffer, 0 ) > 0; } } if( pszUnicodeBuffer ) { LocalFree( pszUnicodeBuffer ); } return bRetval; } BOOL SetDefaultPrinterA( IN LPCSTR pszPrinter ) { BOOL bRetval = TRUE; LPWSTR pszUnicode = NULL; if( pszPrinter ) { pszUnicode = AllocateUnicodeString( (PSTR) pszPrinter ); bRetval = pszUnicode ? TRUE : FALSE; } if( bRetval ) { bRetval = SetDefaultPrinterW( pszUnicode ); } if( pszUnicode ) { FreeUnicodeString( pszUnicode ); } return bRetval; } BOOL PublishPrinterA( HWND hwnd, PCSTR pszUNCName, PCSTR pszDN, PCSTR pszCN, PSTR *ppszDN, DWORD dwAction ) { PWSTR pszUnicodeUNCName = NULL; PWSTR pszUnicodeDN = NULL; PWSTR pszUnicodeCN = NULL; BOOL bRet = FALSE; pszUnicodeUNCName = AllocateUnicodeString((PSTR) pszUNCName); if (pszUNCName && !pszUnicodeUNCName) goto error; pszUnicodeDN = AllocateUnicodeString((PSTR) pszDN); if (pszDN && !pszUnicodeDN) goto error; pszUnicodeCN = AllocateUnicodeString((PSTR) pszCN); if (pszCN && !pszUnicodeCN) goto error; bRet = PublishPrinterW( hwnd, pszUnicodeUNCName, pszUnicodeDN, pszUnicodeCN, (PWSTR *) ppszDN, dwAction); if (ppszDN && *ppszDN) { if (!UnicodeToAnsiString((PWSTR) *ppszDN, *ppszDN, NULL_TERMINATED)) bRet = FALSE; } error: FreeUnicodeString(pszUnicodeUNCName); FreeUnicodeString(pszUnicodeDN); FreeUnicodeString(pszUnicodeCN); return bRet; } VOID ValidatePaperFields( LPCWSTR pUnicodeDeviceName, LPCWSTR pUnicodePort, LPDEVMODEW pDevModeIn ) { POINTS ptMinSize, ptMaxSize; if(!pUnicodeDeviceName || !pUnicodeDeviceName[0] || !pUnicodePort || !pUnicodePort[0] || !pDevModeIn) { return; } // // this logic was swiped from the MergeDevMode() code for the Win3.1 UNIDRV // // According to UNIDRV, dmPaperSize must be set to DMPAPER_USER if custom // paper sizes are going to be taken seriously. if((pDevModeIn->dmPaperSize == DMPAPER_USER) && (pDevModeIn->dmFields & DM_PAPERWIDTH) && (pDevModeIn->dmFields & DM_PAPERLENGTH)) { pDevModeIn->dmFields |= (DM_PAPERLENGTH | DM_PAPERLENGTH); // get the minimum size this printer supports if(DeviceCapabilitiesW(pUnicodeDeviceName, pUnicodePort, DC_MINEXTENT, (PWSTR) &ptMinSize, NULL) == -1) { return; // => no changes } if(DeviceCapabilitiesW(pUnicodeDeviceName, pUnicodePort, DC_MAXEXTENT, (PWSTR) &ptMaxSize, NULL) == -1) { return; // => no changes } // force the custom paper size to fit the machine's capabilities if(pDevModeIn->dmPaperWidth < ptMinSize.x) pDevModeIn->dmPaperWidth = ptMinSize.x; else if(pDevModeIn->dmPaperWidth > ptMaxSize.x) pDevModeIn->dmPaperWidth = ptMaxSize.x; if(pDevModeIn->dmPaperLength < ptMinSize.y) pDevModeIn->dmPaperLength = ptMinSize.y; else if(pDevModeIn->dmPaperLength > ptMaxSize.y) pDevModeIn->dmPaperLength = ptMaxSize.y; } // else if they don't have it right, turn these guys off so they don't // get merged into the default devmode later. else { pDevModeIn->dmFields &= ~(DM_PAPERLENGTH | DM_PAPERWIDTH); pDevModeIn->dmPaperWidth = 0; pDevModeIn->dmPaperLength = 0; } } DWORD UnicodeToAnsi( IN LPBYTE pUnicode, IN DWORD cchUnicode, IN OUT LPBYTE pData, IN DWORD cbData, IN OUT DWORD *pcbCopied OPTIONAL ) /*++ Routine Name: UnicodeToAnsi Routine Description: Converts the content of a buffer from unicode to ansi. There is no assumption about NULL terminator. If pUnicode is not NULL, then it must be WCHAR aligned and cchUnicode indicates the number of WCHARs in the buffer that will be converted to ansi. If pUnicode is NULL, then the function converts in place the contents of pData from Unicode to Ansi. Arguments: pUnicode - buffer aligned to WCHAR that contains a unicode string cchUnicode - number of WCHARs in pUnicode buffer pData - buffer that will hold the converted string cbData - sizeo in bytes of the buffer pDa pcbCopied - number of bytes copied to pData or needed to accomodate the converted string Return Value: None. --*/ { DWORD cReturn = cbData; DWORD cbCopied = 0; DWORD Error = ERROR_INVALID_PARAMETER; // // If the size of both input buffer is 0, then we do not do anything and return success. // Otherwise, the caller must give us either valid pData or a valid pUnicode that is // WCHAR aligned // if (!cbData && !cchUnicode) { Error = ERROR_SUCCESS; } else if (pData || pUnicode && !((ULONG_PTR)pUnicode % sizeof(WCHAR))) { LPWSTR pAligned = (LPWSTR)pUnicode; Error = ERROR_SUCCESS; if (!pAligned) { // // We convert contents of pData from unicode to ansi // if (pAligned = LocalAlloc(LPTR, cbData)) { memcpy(pAligned, pData, cbData); cchUnicode = cbData / sizeof(WCHAR); } else { Error = GetLastError(); } } // // Convert data to ansi or find out how many bytes are // necessary to accomodate the string // if (Error == ERROR_SUCCESS) { cbCopied = WideCharToMultiByte(CP_THREAD_ACP, 0, pAligned, cchUnicode, pData, cbData, NULL, NULL); // // WideCharToMultiByte tells us how many bytes we need // if (!cbCopied) { Error = ERROR_MORE_DATA; cbCopied = WideCharToMultiByte(CP_THREAD_ACP, 0, pAligned, cchUnicode, pData, 0, NULL, NULL); } else if (!cbData) { Error = ERROR_MORE_DATA; } if (pAligned != (LPWSTR)pUnicode) { LocalFree(pAligned); } } } if (pcbCopied) { *pcbCopied = cbCopied; } return Error; }