diff --git a/win32ss/printing/base/winspool/CMakeLists.txt b/win32ss/printing/base/winspool/CMakeLists.txt index 9081819..34c3026 100644 --- a/win32ss/printing/base/winspool/CMakeLists.txt +++ b/win32ss/printing/base/winspool/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCE printers.c printprocessors.c printproviders.c + utils.c ${CMAKE_CURRENT_BINARY_DIR}/winspool_c.c) add_library(winspool MODULE diff --git a/win32ss/printing/base/winspool/devmode.c b/win32ss/printing/base/winspool/devmode.c index b75932a..c97f0e9 100644 --- a/win32ss/printing/base/winspool/devmode.c +++ b/win32ss/printing/base/winspool/devmode.c @@ -233,3 +233,82 @@ Failure: SetLastError(ERROR_INVALID_DATA); return FALSE; } + +void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput) +{ + // FIXME: This function should become ConvertAnsiDevModeToUnicodeDevmode when its parameters are known! + + // Check if a pDevModeInput and pDevModeOutput are both not NULL. + if (!pDevModeInput || !pDevModeOutput) + return; + + pDevModeOutput = GdiConvertToDevmodeW(pDevModeInput); +} + +// Internal counterpart to GdiConvertToDevmodeW from gdi32 +static __inline DEVMODEA* +_ConvertToDevmodeA(const DEVMODEW *dmW) +{ + DEVMODEA *dmA; + WORD dmA_size, dmW_size; + size_t BytesToCopy; + + dmW_size = dmW->dmSize; + + /* this is the minimal dmSize that XP accepts */ + if (dmW_size < FIELD_OFFSET(DEVMODEW, dmFields)) + return NULL; + + // Guard against callers that set dmSize incorrectly. + if (dmW_size > sizeof(DEVMODEW)) + dmW_size = sizeof(DEVMODEW); + + // dmA_size must become dmW_size without the additional 1 byte per character for each Unicode string (dmDeviceName and dmFormName). + dmA_size = dmW_size - CCHDEVICENAME; + if (dmW_size >= FIELD_OFFSET(DEVMODEW, dmFormName) + CCHFORMNAME * sizeof(WCHAR)) + dmA_size -= CCHFORMNAME; + + // Allocate the required bytes, that is dmSize for the ANSI DEVMODEA structure plus any extra bytes requested through dmDriverExtra. + dmA = HeapAlloc(GetProcessHeap(), 0, dmA_size + dmW->dmDriverExtra); + if (!dmA) return NULL; + + // Every valid DEVMODEW has a dmDeviceName, which we convert to ANSI here. + WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL); + + // Copy everything up to dmFormName or the remaining dmW_size, whatever is smaller. + BytesToCopy = min(FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion), dmW_size - CCHDEVICENAME * sizeof(WCHAR)); + memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion, BytesToCopy); + + // Handle dmFormName if the input DEVMODEW is large enough to contain one. + if (dmW_size >= FIELD_OFFSET(DEVMODEW, dmFormName) + CCHFORMNAME * sizeof(WCHAR)) + { + if (dmW->dmFields & DM_FORMNAME) + WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL); + else + dmA->dmFormName[0] = 0; + + // Copy the remaining fields. + if (dmW_size > FIELD_OFFSET(DEVMODEW, dmLogPixels)) + memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW_size - FIELD_OFFSET(DEVMODEW, dmLogPixels)); + } + + // Append dmDriverExtra if required. + if (dmW->dmDriverExtra) + memcpy((char *)dmA + dmA_size, (const char *)dmW + dmW_size, dmW->dmDriverExtra); + + // Set the corrected dmSize and we are done. + dmA->dmSize = dmA_size; + + return dmA; +} + +void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput) +{ + // FIXME: This function should become ConvertUnicodeDevModeToAnsiDevmode when its parameters are known! + + // Check if a pDevModeInput and pDevModeOutput are both not NULL. + if (!pDevModeInput || !pDevModeOutput) + return; + + pDevModeOutput = _ConvertToDevmodeA(pDevModeInput); +} diff --git a/win32ss/printing/base/winspool/precomp.h b/win32ss/printing/base/winspool/precomp.h index cbfaac9..58eed62 100644 --- a/win32ss/printing/base/winspool/precomp.h +++ b/win32ss/printing/base/winspool/precomp.h @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include @@ -39,4 +41,12 @@ SPOOLER_HANDLE, *PSPOOLER_HANDLE; // main.c extern HANDLE hProcessHeap; +// utils.c +extern BOOL UnicodeToAnsiInPlace(PWSTR pwszField); + +// devmode.c +extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput); + +extern void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput); + #endif diff --git a/win32ss/printing/base/winspool/printers.c b/win32ss/printing/base/winspool/printers.c index 28bce50..4180dfb 100644 --- a/win32ss/printing/base/winspool/printers.c +++ b/win32ss/printing/base/winspool/printers.c @@ -8,6 +8,7 @@ #include "precomp.h" #include #include +#include // Local Constants @@ -193,12 +194,96 @@ DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pO return 0; } +INT WINAPI +DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut) +{ + TRACE("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut); + UNIMPLEMENTED; + return DOCUMENTEVENT_UNSUPPORTED; +} + LONG WINAPI DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode) { + PWSTR pwszDeviceName = NULL; + PDEVMODEW pdmwInput = NULL; + PDEVMODEW pdmwOutput = NULL; + BOOL bReturnValue = -1; + DWORD cch; + TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); - UNIMPLEMENTED; - return -1; + + if (pDeviceName) + { + // Convert pName to a Unicode string pwszDeviceName. + cch = strlen(pDeviceName); + + pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszDeviceName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1); + } + + if (pDevModeInput) + { + // Create working buffer for input to DocumentPropertiesW. + pdmwInput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); + if (!pdmwInput) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, pdmwInput); + } + + if (pDevModeOutput) + { + // Create working buffer for output from DocumentPropertiesW. + pdmwOutput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); + if (!pdmwOutput) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + } + + bReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode); + TRACE("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue); + + if (pwszDeviceName) + { + HeapFree(hProcessHeap, 0, pwszDeviceName); + } + + if (bReturnValue < 0) + { + TRACE("DocumentPropertiesW failed!\n"); + goto Cleanup; + } + + if (pdmwOutput) + { + RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput); + } + +Cleanup: + if(pwszDeviceName) + HeapFree(hProcessHeap, 0, pwszDeviceName); + + if (pdmwInput) + HeapFree(hProcessHeap, 0, pdmwInput); + + if (pdmwOutput) + HeapFree(hProcessHeap, 0, pdmwOutput); + + return bReturnValue; } static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) @@ -386,8 +471,451 @@ Cleanup: BOOL WINAPI EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { + BOOL bReturnValue = FALSE; + DWORD cch; + PWSTR pwszName = NULL; + PSTR pszPrinterName = NULL; + PSTR pszServerName = NULL; + PSTR pszDescription = NULL; + PSTR pszName = NULL; + PSTR pszComment = NULL; + PSTR pszShareName = NULL; + PSTR pszPortName = NULL; + PSTR pszDriverName = NULL; + PSTR pszLocation = NULL; + PSTR pszSepFile = NULL; + PSTR pszPrintProcessor = NULL; + PSTR pszDatatype = NULL; + PSTR pszParameters = NULL; + DWORD i; + PPRINTER_INFO_1W ppi1w = NULL; + PPRINTER_INFO_1A ppi1a = NULL; + PPRINTER_INFO_2W ppi2w = NULL; + PPRINTER_INFO_2A ppi2a = NULL; + PPRINTER_INFO_4W ppi4w = NULL; + PPRINTER_INFO_4A ppi4a = NULL; + PPRINTER_INFO_5W ppi5w = NULL; + PPRINTER_INFO_5A ppi5a = NULL; + TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); - return FALSE; + + // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable. + if (Level != 1 && Level != 2 && Level != 4 && Level != 5) + { + SetLastError(ERROR_INVALID_LEVEL); + ERR("Invalid Level!\n"); + goto Cleanup; + } + + if (Name) + { + // Convert pName to a Unicode string pwszName. + cch = strlen(Name); + + pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1); + } + + /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */ + bReturnValue = EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); + HeapFree(hProcessHeap, 0, pwszName); + + TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned, bReturnValue, GetLastError()); + + /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */ + /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */ + /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */ + + /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */ + ppi1w = (PPRINTER_INFO_1W)pPrinterEnum; + ppi2w = (PPRINTER_INFO_2W)pPrinterEnum; + ppi4w = (PPRINTER_INFO_4W)pPrinterEnum; + ppi5w = (PPRINTER_INFO_5W)pPrinterEnum; + /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */ + ppi1a = (PPRINTER_INFO_1A)pPrinterEnum; + ppi2a = (PPRINTER_INFO_2A)pPrinterEnum; + ppi4a = (PPRINTER_INFO_4A)pPrinterEnum; + ppi5a = (PPRINTER_INFO_5A)pPrinterEnum; + + for (i = 0; i < *pcReturned; i++) + { + switch (Level) + { + case 1: + { + if (ppi1w[i].pDescription) + { + // Convert Unicode pDescription to a ANSI string pszDescription. + cch = wcslen(ppi1w[i].pDescription); + + pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDescription) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription); + + HeapFree(hProcessHeap, 0, pszDescription); + } + + if (ppi1w[i].pName) + { + // Convert Unicode pName to a ANSI string pszName. + cch = wcslen(ppi1w[i].pName); + + pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a[i].pName, cch + 1, pszName); + + HeapFree(hProcessHeap, 0, pszName); + } + + if (ppi1w[i].pComment) + { + // Convert Unicode pComment to a ANSI string pszComment. + cch = wcslen(ppi1w[i].pComment); + + pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszComment) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment); + + HeapFree(hProcessHeap, 0, pszComment); + } + break; + } + + + case 2: + { + if (ppi2w[i].pServerName) + { + // Convert Unicode pServerName to a ANSI string pszServerName. + cch = wcslen(ppi2w[i].pServerName); + + pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName); + + HeapFree(hProcessHeap, 0, pszServerName); + } + + if (ppi2w[i].pPrinterName) + { + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi2w[i].pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi2w[i].pShareName) + { + // Convert Unicode pShareName to a ANSI string pszShareName. + cch = wcslen(ppi2w[i].pShareName); + + pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszShareName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName); + + HeapFree(hProcessHeap, 0, pszShareName); + } + + if (ppi2w[i].pPortName) + { + // Convert Unicode pPortName to a ANSI string pszPortName. + cch = wcslen(ppi2w[i].pPortName); + + pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPortName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName); + + HeapFree(hProcessHeap, 0, pszPortName); + } + + if (ppi2w[i].pDriverName) + { + // Convert Unicode pDriverName to a ANSI string pszDriverName. + cch = wcslen(ppi2w[i].pDriverName); + + pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDriverName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName); + + HeapFree(hProcessHeap, 0, pszDriverName); + } + + if (ppi2w[i].pComment) + { + // Convert Unicode pComment to a ANSI string pszComment. + cch = wcslen(ppi2w[i].pComment); + + pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszComment) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment); + + HeapFree(hProcessHeap, 0, pszComment); + } + + if (ppi2w[i].pLocation) + { + // Convert Unicode pLocation to a ANSI string pszLocation. + cch = wcslen(ppi2w[i].pLocation); + + pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszLocation) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation); + + HeapFree(hProcessHeap, 0, pszLocation); + } + + + if (ppi2w[i].pSepFile) + { + // Convert Unicode pSepFile to a ANSI string pszSepFile. + cch = wcslen(ppi2w[i].pSepFile); + + pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszSepFile) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile); + + HeapFree(hProcessHeap, 0, pszSepFile); + } + + if (ppi2w[i].pPrintProcessor) + { + // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. + cch = wcslen(ppi2w[i].pPrintProcessor); + + pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrintProcessor) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor); + + HeapFree(hProcessHeap, 0, pszPrintProcessor); + } + + + if (ppi2w[i].pDatatype) + { + // Convert Unicode pDatatype to a ANSI string pszDatatype. + cch = wcslen(ppi2w[i].pDatatype); + + pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDatatype) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype); + + HeapFree(hProcessHeap, 0, pszDatatype); + } + + if (ppi2w[i].pParameters) + { + // Convert Unicode pParameters to a ANSI string pszParameters. + cch = wcslen(ppi2w[i].pParameters); + + pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszParameters) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters); + + HeapFree(hProcessHeap, 0, pszParameters); + } + break; + + } + + case 4: + { + if (ppi4w[i].pPrinterName) + { + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi4w[i].pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi4w[i].pServerName) + { + // Convert Unicode pServerName to a ANSI string pszServerName. + cch = wcslen(ppi4w[i].pServerName); + + pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); + StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName); + + HeapFree(hProcessHeap, 0, pszServerName); + } + break; + } + + case 5: + { + if (ppi5w[i].pPrinterName) + { + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi5w[i].pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi5w[i].pPortName) + { + // Convert Unicode pPortName to a ANSI string pszPortName. + cch = wcslen(ppi5w[i].pPortName); + + pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPortName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); + StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName); + + HeapFree(hProcessHeap, 0, pszPortName); + } + break; + } + + } // switch + } // for + +Cleanup: + + return bReturnValue; } BOOL WINAPI @@ -579,15 +1107,690 @@ Cleanup: BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) { + PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter; + PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter; + PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; + PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; + PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter; + PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter; + PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter; + PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter; + PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; + PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; + DWORD cch; + BOOL bReturnValue = FALSE; + TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); - return FALSE; + + // Check for invalid levels here for early error return. Should be 1-9. + if (Level < 1 || Level > 9) + { + SetLastError(ERROR_INVALID_LEVEL); + ERR("Invalid Level!\n"); + goto Cleanup; + } + + bReturnValue = GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded); + + if (!bReturnValue) + { + TRACE("GetPrinterW failed!\n"); + goto Cleanup; + } + + switch (Level) + { + case 1: + { + if (ppi1w->pDescription) + { + PSTR pszDescription; + + // Convert Unicode pDescription to a ANSI string pszDescription. + cch = wcslen(ppi1w->pDescription); + + pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDescription) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription); + + HeapFree(hProcessHeap, 0, pszDescription); + } + + if (ppi1w->pName) + { + PSTR pszName; + + // Convert Unicode pName to a ANSI string pszName. + cch = wcslen(ppi1w->pName); + + pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a->pName, cch + 1, pszName); + + HeapFree(hProcessHeap, 0, pszName); + } + + if (ppi1w->pComment) + { + PSTR pszComment; + + // Convert Unicode pComment to a ANSI string pszComment. + cch = wcslen(ppi1w->pComment); + + pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszComment) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL); + StringCchCopyA(ppi1a->pComment, cch + 1, pszComment); + + HeapFree(hProcessHeap, 0, pszComment); + } + break; + } + + case 2: + { + if (ppi2w->pServerName) + { + PSTR pszServerName; + + // Convert Unicode pServerName to a ANSI string pszServerName. + cch = wcslen(ppi2w->pServerName); + + pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName); + + HeapFree(hProcessHeap, 0, pszServerName); + } + + if (ppi2w->pPrinterName) + { + PSTR pszPrinterName; + + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi2w->pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi2w->pShareName) + { + PSTR pszShareName; + + // Convert Unicode pShareName to a ANSI string pszShareName. + cch = wcslen(ppi2w->pShareName); + + pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszShareName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName); + + HeapFree(hProcessHeap, 0, pszShareName); + } + + if (ppi2w->pPortName) + { + PSTR pszPortName; + + // Convert Unicode pPortName to a ANSI string pszPortName. + cch = wcslen(ppi2w->pPortName); + + pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPortName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName); + + HeapFree(hProcessHeap, 0, pszPortName); + } + + if (ppi2w->pDriverName) + { + PSTR pszDriverName; + + // Convert Unicode pDriverName to a ANSI string pszDriverName. + cch = wcslen(ppi2w->pDriverName); + + pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDriverName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName); + + HeapFree(hProcessHeap, 0, pszDriverName); + } + + if (ppi2w->pComment) + { + PSTR pszComment; + + // Convert Unicode pComment to a ANSI string pszComment. + cch = wcslen(ppi2w->pComment); + + pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszComment) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pComment, cch + 1, pszComment); + + HeapFree(hProcessHeap, 0, pszComment); + } + + if (ppi2w->pLocation) + { + PSTR pszLocation; + + // Convert Unicode pLocation to a ANSI string pszLocation. + cch = wcslen(ppi2w->pLocation); + + pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszLocation) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation); + + HeapFree(hProcessHeap, 0, pszLocation); + } + + if (ppi2w->pSepFile) + { + PSTR pszSepFile; + + // Convert Unicode pSepFile to a ANSI string pszSepFile. + cch = wcslen(ppi2w->pSepFile); + + pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszSepFile) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile); + + HeapFree(hProcessHeap, 0, pszSepFile); + } + + if (ppi2w->pPrintProcessor) + { + PSTR pszPrintProcessor; + + // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. + cch = wcslen(ppi2w->pPrintProcessor); + + pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrintProcessor) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor); + + HeapFree(hProcessHeap, 0, pszPrintProcessor); + } + + if (ppi2w->pDatatype) + { + PSTR pszDatatype; + + // Convert Unicode pDatatype to a ANSI string pszDatatype. + cch = wcslen(ppi2w->pDatatype); + + pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszDatatype) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype); + + HeapFree(hProcessHeap, 0, pszDatatype); + } + + if (ppi2w->pParameters) + { + PSTR pszParameters; + + // Convert Unicode pParameters to a ANSI string pszParameters. + cch = wcslen(ppi2w->pParameters); + + pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszParameters) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL); + StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters); + + HeapFree(hProcessHeap, 0, pszParameters); + } + break; + } + + case 4: + { + if (ppi4w->pPrinterName) + { + PSTR pszPrinterName; + + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi4w->pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi4w->pServerName) + { + PSTR pszServerName; + + // Convert Unicode pServerName to a ANSI string pszServerName. + cch = wcslen(ppi4w->pServerName); + + pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszServerName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); + StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName); + + HeapFree(hProcessHeap, 0, pszServerName); + } + break; + } + + case 5: + { + if (ppi5w->pPrinterName) + { + PSTR pszPrinterName; + + // Convert Unicode pPrinterName to a ANSI string pszPrinterName. + cch = wcslen(ppi5w->pPrinterName); + + pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPrinterName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); + StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName); + + HeapFree(hProcessHeap, 0, pszPrinterName); + } + + if (ppi5w->pPortName) + { + PSTR pszPortName; + + // Convert Unicode pPortName to a ANSI string pszPortName. + cch = wcslen(ppi5w->pPortName); + + pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszPortName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); + StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName); + + HeapFree(hProcessHeap, 0, pszPortName); + } + break; + } + + case 7: + { + if (ppi7w->pszObjectGUID) + { + PSTR pszaObjectGUID; + + // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID. + cch = wcslen(ppi7w->pszObjectGUID); + + pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszaObjectGUID) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Cleanup; + } + + WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL); + StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID); + + HeapFree(hProcessHeap, 0, pszaObjectGUID); + } + break; + } + } // switch + +Cleanup: + return bReturnValue; } BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) -{ +{ + /* + * We are mapping multiple different pointers to the same pDriverInfo pointer here so that + * we can use the same incoming pointer for different Levels + */ + PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; + PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo; + PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo; + PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo; + PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo; + PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo; + + BOOL bReturnValue = FALSE; + DWORD cch; + PWSTR pwszEnvironment = NULL; + TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); - return FALSE; + + // Check for invalid levels here for early error return. Should be 1-6. + if (Level < 1 || Level > 6) + { + SetLastError(ERROR_INVALID_LEVEL); + ERR("Invalid Level!\n"); + goto Exit; + } + + if (pEnvironment) + { + // Convert pEnvironment to a Unicode string pwszEnvironment. + cch = strlen(pEnvironment); + + pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); + if (!pwszEnvironment) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + goto Exit; + } + + MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); + } + + bReturnValue = GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); + TRACE("*pcbNeeded is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcbNeeded, bReturnValue, GetLastError()); + + if (pwszEnvironment) + { + HeapFree(hProcessHeap, 0, pwszEnvironment); + } + + if (!bReturnValue) + { + TRACE("GetPrinterDriverW failed!\n"); + goto Exit; + } + + // Do Unicode to ANSI conversions for strings based on Level + switch (Level) + { + case 1: + { + if (!UnicodeToAnsiInPlace(pdi1w->pName)) + goto Exit; + + break; + } + + case 2: + { + if (!UnicodeToAnsiInPlace(pdi2w->pName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi2w->pEnvironment)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi2w->pDriverPath)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi2w->pDataFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi2w->pConfigFile)) + goto Exit; + + break; + } + + case 3: + { + if (!UnicodeToAnsiInPlace(pdi3w->pName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pEnvironment)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pDriverPath)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pDataFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pConfigFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pHelpFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pDependentFiles)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pMonitorName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi3w->pDefaultDataType)) + goto Exit; + + break; + } + + case 4: + { + if (!UnicodeToAnsiInPlace(pdi4w->pName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pEnvironment)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pDriverPath)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pDataFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pConfigFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pHelpFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pDependentFiles)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pMonitorName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pDefaultDataType)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames)) + goto Exit; + + break; + } + + case 5: + { + if (!UnicodeToAnsiInPlace(pdi5w->pName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi5w->pEnvironment)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi5w->pDriverPath)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi5w->pDataFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi5w->pConfigFile)) + goto Exit; + + break; + } + + case 6: + { + if (!UnicodeToAnsiInPlace(pdi6w->pName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pEnvironment)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pDriverPath)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pDataFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pConfigFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pHelpFile)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pDependentFiles)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pMonitorName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pDefaultDataType)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pszMfgName)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pszOEMUrl)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pszHardwareID)) + goto Exit; + + if (!UnicodeToAnsiInPlace(pdi6w->pszProvider)) + goto Exit; + } + } + + bReturnValue = TRUE; + +Exit: + + return bReturnValue; } BOOL WINAPI @@ -623,14 +1826,14 @@ GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDri RpcExcept(EXCEPTION_EXECUTE_HANDLER) { dwErrorCode = RpcExceptionCode(); - ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); + ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode); } RpcEndExcept; if (dwErrorCode == ERROR_SUCCESS) { // Replace relative offset addresses in the output by absolute pointers. - ASSERT(Level <= 3); + ASSERT(Level <= 5); MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); } @@ -1026,6 +2229,14 @@ SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) return FALSE; } +BOOL WINAPI +SplDriverUnloadComplete(LPWSTR pDriverFile) +{ + TRACE("DriverUnloadComplete(%S)\n", pDriverFile); + UNIMPLEMENTED; + return TRUE; // return true for now. +} + DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) { diff --git a/win32ss/printing/base/winspool/utils.c b/win32ss/printing/base/winspool/utils.c new file mode 100644 index 0000000..ae190ed --- /dev/null +++ b/win32ss/printing/base/winspool/utils.c @@ -0,0 +1,55 @@ +/* +* PROJECT: ReactOS Spooler API +* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) +* PURPOSE: Utility Functions related to Print Processors +* COPYRIGHT: Copyright 2020 Doug Lyons (douglyons@douglyons.com) +*/ + +#include "precomp.h" + +BOOL UnicodeToAnsiInPlace(PWSTR pwszField) +{ + /* + * This converts an incoming Unicode string to an ANSI string. + * It returns FALSE on failure, otherwise it returns TRUE. + * It is only useful for "in-place" conversions where the ANSI string goes + * back into the same place where the Unicode string came into this function. + * It seems that many of the functions involving printing can use this. + */ + + PSTR pszTemp; + DWORD cch; + + /* + * Map the incoming Unicode pwszField string to an ANSI one here so that we can do + * in-place conversion. We read the Unicode input and then we write back the ANSI + * conversion into the same buffer for use with our GetPrinterDriverA function + */ + PSTR pszField = (PSTR)pwszField; + + if (!pwszField) + { + return TRUE; + } + + cch = wcslen(pwszField); + if (cch == 0) + { + return TRUE; + } + + pszTemp = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); + if (!pszField) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + ERR("HeapAlloc failed!\n"); + return FALSE; // indicates a failure to be handled by caller + } + + WideCharToMultiByte(CP_ACP, 0, pwszField, -1, pszTemp, cch + 1, NULL, NULL); + StringCchCopyA(pszField, cch + 1, pszTemp); + + HeapFree(hProcessHeap, 0, pszTemp); + + return TRUE; +} diff --git a/win32ss/gdi/gdi32/misc/misc.c b/win32ss/gdi/gdi32/misc/misc.c index b31db63..04be375 100644 --- a/win32ss/gdi/gdi32/misc/misc.c +++ b/win32ss/gdi/gdi32/misc/misc.c @@ -962,6 +962,7 @@ bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unkno /* * @implemented + * Synchronized with WINE dlls/gdi32/driver.c */ DEVMODEW * WINAPI @@ -986,15 +987,19 @@ GdiConvertToDevmodeW(const DEVMODEA *dmA) dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra); if (!dmW) return NULL; - MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, CCHDEVICENAME, - dmW->dmDeviceName, CCHDEVICENAME); + MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, -1, + dmW->dmDeviceName, CCHDEVICENAME); /* copy slightly more, to avoid long computations */ memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME); if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME) { - MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME, - dmW->dmFormName, CCHFORMNAME); + if (dmA->dmFields & DM_FORMNAME) + MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, -1, + dmW->dmFormName, CCHFORMNAME); + else + dmW->dmFormName[0] = 0; + if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels)) memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels)); } diff --git a/win32ss/printing/base/spoolsv/printerdrivers.c b/win32ss/printing/base/spoolsv/printerdrivers.c index a1f4586..ae85f84 100644 --- a/win32ss/printing/base/spoolsv/printerdrivers.c +++ b/win32ss/printing/base/spoolsv/printerdrivers.c @@ -49,6 +49,8 @@ _RpcGetPrinterDriver(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pEnvironment, DWOR DWORD dwErrorCode; PBYTE pDriverAligned; + ERR("_RpcGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriver, cbBuf, pcbNeeded); + dwErrorCode = RpcImpersonateClient(NULL); if (dwErrorCode != ERROR_SUCCESS) { @@ -61,7 +63,7 @@ _RpcGetPrinterDriver(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pEnvironment, DWOR if (GetPrinterDriverW(hPrinter, pEnvironment, Level, pDriverAligned, cbBuf, pcbNeeded)) { // Replace relative offset addresses in the output by absolute pointers. - ASSERT(Level >= 1 && Level <= 3); + ASSERT(Level >= 1 && Level <= 5); MarshallDownStructure(pDriverAligned, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); } else diff --git a/win32ss/printing/base/winspool/winspool.spec b/win32ss/printing/base/winspool/winspool.spec index 7c2888b..318a2df 100644 --- a/win32ss/printing/base/winspool/winspool.spec +++ b/win32ss/printing/base/winspool/winspool.spec @@ -74,7 +74,7 @@ 173 stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr) 174 stub DeviceMode 175 stub DevicePropertySheets -176 stub DocumentEvent +176 stdcall DocumentEvent(ptr ptr long long ptr long ptr) 177 stdcall DocumentPropertiesA(ptr ptr ptr ptr ptr long) 178 stdcall DocumentPropertiesW(ptr ptr ptr ptr ptr long) 179 stub DocumentPropertySheets @@ -186,7 +186,7 @@ 285 stdcall SetPrinterDataExW(ptr wstr wstr long ptr long) 286 stdcall SetPrinterDataW(ptr wstr long ptr long) 287 stdcall SetPrinterW(ptr long ptr long) -288 stub SplDriverUnloadComplete +288 stdcall SplDriverUnloadComplete(ptr) 289 stub SpoolerDevQueryPrintW 290 stdcall SpoolerInit() 291 stub SpoolerPrinterEvent diff --git a/win32ss/printing/include/marshalling/printerdrivers.h b/win32ss/printing/include/marshalling/printerdrivers.h index 49951bd..ffaf50f 100644 --- a/win32ss/printing/include/marshalling/printerdrivers.h +++ b/win32ss/printing/include/marshalling/printerdrivers.h @@ -41,6 +41,34 @@ static const MARSHALLING PrinterDriver3Marshalling = { } }; +static const MARSHALLING PrinterDriver4Marshalling = { + sizeof(DRIVER_INFO_4W), + { + { FIELD_OFFSET(DRIVER_INFO_4W, pName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_4W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_4W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pConfigFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_4W, pHelpFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING PrinterDriver5Marshalling = { + sizeof(DRIVER_INFO_5W), + { + { FIELD_OFFSET(DRIVER_INFO_5W, pName), RTL_FIELD_SIZE(DRIVER_INFO_5W, pName), RTL_FIELD_SIZE(DRIVER_INFO_5W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_5W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_5W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_5W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_5W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_5W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_5W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_5W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_5W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_5W, pConfigFile), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; static const MARSHALLING* pPrinterDriverMarshalling[] = { @@ -48,4 +76,6 @@ static const MARSHALLING* pPrinterDriverMarshalling[] = { &PrinterDriver1Marshalling, &PrinterDriver2Marshalling, &PrinterDriver3Marshalling, + &PrinterDriver4Marshalling, + &PrinterDriver5Marshalling, }; diff --git a/win32ss/printing/providers/localspl/printerdrivers.c b/win32ss/printing/providers/localspl/printerdrivers.c index 5bb5b3d..351667c 100644 --- a/win32ss/printing/providers/localspl/printerdrivers.c +++ b/win32ss/printing/providers/localspl/printerdrivers.c @@ -7,7 +7,6 @@ #include "precomp.h" - // Local Constants static DWORD dwDriverInfo1Offsets[] = { FIELD_OFFSET(DRIVER_INFO_1W, pName), @@ -36,6 +35,29 @@ static DWORD dwDriverInfo3Offsets[] = { MAXDWORD }; +static DWORD dwDriverInfo4Offsets[] = { + FIELD_OFFSET(DRIVER_INFO_4W, pName), + FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment), + FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath), + FIELD_OFFSET(DRIVER_INFO_4W, pDataFile), + FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile), + FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile), + FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles), + FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName), + FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType), + FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), + MAXDWORD +}; + +static DWORD dwDriverInfo5Offsets[] = { + FIELD_OFFSET(DRIVER_INFO_5W, pName), + FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment), + FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath), + FIELD_OFFSET(DRIVER_INFO_5W, pDataFile), + FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile), + MAXDWORD +}; + static void ToMultiSz(LPWSTR pString) { @@ -118,7 +140,7 @@ _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppD pwszStrings[1] = wszCurrentEnvironment; // pEnvironment pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile - pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile + pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile pwszStrings[5] = L""; // pHelpFile pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator! pwszStrings[7] = NULL; // pMonitorName @@ -148,6 +170,87 @@ _LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppD (*ppDriverInfo)++; } +static void +_LocalGetPrinterDriverLevel4(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_4W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded) +{ + DWORD n; + PCWSTR pwszStrings[10]; + + /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */ + pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName + pwszStrings[1] = wszCurrentEnvironment; // pEnvironment + pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath + pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile + pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile + pwszStrings[5] = L""; // pHelpFile + pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator! + pwszStrings[7] = NULL; // pMonitorName + pwszStrings[8] = NULL; // pDefaultDataType + pwszStrings[9] = NULL; // pszzPreviousNames + + // Calculate the string lengths. + if (!ppDriverInfo) + { + for (n = 0; n < _countof(pwszStrings); ++n) + { + if (pwszStrings[n]) + { + *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR); + } + } + + *pcbNeeded += sizeof(DRIVER_INFO_4W); + return; + } + + (*ppDriverInfo)->cVersion = 3; + + // Finally copy the structure and advance to the next one in the output buffer. + *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo4Offsets, *ppDriverInfoEnd); + ToMultiSz((*ppDriverInfo)->pDependentFiles); + (*ppDriverInfo)++; +} + +static void +_LocalGetPrinterDriverLevel5(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_5W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded) +{ + DWORD n; + PCWSTR pwszStrings[5]; + + /* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */ + pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName + pwszStrings[1] = wszCurrentEnvironment; // pEnvironment + pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath UniDrv.dll + pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile.ppd + pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile UniDrvUI.dll + + // Calculate the string lengths. + if (!ppDriverInfo) + { + for (n = 0; n < _countof(pwszStrings); ++n) + { + if (pwszStrings[n]) + { + *pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR); + } + } + + *pcbNeeded += sizeof(DRIVER_INFO_5W); + return; + } + + (*ppDriverInfo)->cVersion = 3; + // Driver attributes, like UMPD/KMPD. + (*ppDriverInfo)->dwDriverAttributes = 0; // UMPD/KMPD, So where are they? + // Number of times the configuration file for this driver has been upgraded or downgraded since the last spooler restart. + (*ppDriverInfo)->dwConfigVersion = 1; + // Number of times the driver file for this driver has been upgraded or downgraded since the last spooler restart. + (*ppDriverInfo)->dwDriverVersion = 1; + + // Finally copy the structure and advance to the next one in the output buffer. + *ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo5Offsets, *ppDriverInfoEnd); + (*ppDriverInfo)++; +} BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) { @@ -168,8 +271,8 @@ BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Le pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; - // Only support 3 levels for now - if (Level > 3) + // Only support 5 levels for now + if (Level > 5) { // The caller supplied an invalid level. dwErrorCode = ERROR_INVALID_LEVEL; @@ -185,6 +288,10 @@ BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Le _LocalGetPrinterDriverLevel2(pPrinterHandle, NULL, NULL, pcbNeeded); else if (Level == 3) _LocalGetPrinterDriverLevel3(pPrinterHandle, NULL, NULL, pcbNeeded); + else if (Level == 4) + _LocalGetPrinterDriverLevel4(pPrinterHandle, NULL, NULL, pcbNeeded); + else if (Level == 5) + _LocalGetPrinterDriverLevel5(pPrinterHandle, NULL, NULL, pcbNeeded); // Check if the supplied buffer is large enough. if (cbBuf < *pcbNeeded) @@ -202,6 +309,10 @@ BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Le _LocalGetPrinterDriverLevel2(pPrinterHandle, (PDRIVER_INFO_2W*)&pDriverInfo, &pEnd, NULL); else if (Level == 3) _LocalGetPrinterDriverLevel3(pPrinterHandle, (PDRIVER_INFO_3W*)&pDriverInfo, &pEnd, NULL); + else if (Level == 4) + _LocalGetPrinterDriverLevel4(pPrinterHandle, (PDRIVER_INFO_4W*)&pDriverInfo, &pEnd, NULL); + else if (Level == 5) + _LocalGetPrinterDriverLevel5(pPrinterHandle, (PDRIVER_INFO_5W*)&pDriverInfo, &pEnd, NULL); dwErrorCode = ERROR_SUCCESS;