[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);
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
extern BOOL UnicodeToAnsiInPlace(PWSTR pwszField);
// devmode.c
extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput);
extern void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput);
#endif

View file

@ -205,9 +205,85 @@ DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG
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)