[WINSPOOL] Implement DocumentPropertiesA including DEVMODE conversions (#2339)

Co-authored-by: Doug Lyons <douglyons@douglyons.com>
Co-authored-by: Colin Finck <colin@reactos.org>
This commit is contained in:
Doug Lyons 2020-02-25 01:02:46 -06:00 committed by GitHub
parent 1e60116563
commit 3077c0e43e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 2 deletions

View file

@ -233,3 +233,82 @@ Failure:
SetLastError(ERROR_INVALID_DATA); SetLastError(ERROR_INVALID_DATA);
return FALSE; 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);
}

View file

@ -44,4 +44,9 @@ extern HANDLE hProcessHeap;
// utils.c // utils.c
extern BOOL UnicodeToAnsiInPlace(PWSTR pwszField); extern BOOL UnicodeToAnsiInPlace(PWSTR pwszField);
// devmode.c
extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput);
extern void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput);
#endif #endif

View file

@ -205,9 +205,85 @@ DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG
LONG WINAPI LONG WINAPI
DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode) 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); 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) static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)