https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3077c0e43e08bc98f8017…
commit 3077c0e43e08bc98f801718a86d354adc269a963
Author: Doug Lyons <douglyons(a)douglyons.com>
AuthorDate: Tue Feb 25 01:02:46 2020 -0600
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Feb 25 08:02:46 2020 +0100
[WINSPOOL] Implement DocumentPropertiesA including DEVMODE conversions (#2339)
Co-authored-by: Doug Lyons <douglyons(a)douglyons.com>
Co-authored-by: Colin Finck <colin(a)reactos.org>
---
win32ss/printing/base/winspool/devmode.c | 79 ++++++++++++++++++++++++++++++
win32ss/printing/base/winspool/precomp.h | 5 ++
win32ss/printing/base/winspool/printers.c | 80 ++++++++++++++++++++++++++++++-
3 files changed, 162 insertions(+), 2 deletions(-)
diff --git a/win32ss/printing/base/winspool/devmode.c
b/win32ss/printing/base/winspool/devmode.c
index b75932a313f..c97f0e9ff58 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 cae8bd320e8..58eed626d02 100644
--- a/win32ss/printing/base/winspool/precomp.h
+++ b/win32ss/printing/base/winspool/precomp.h
@@ -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
diff --git a/win32ss/printing/base/winspool/printers.c
b/win32ss/printing/base/winspool/printers.c
index f6616068442..4180dfb3d1c 100644
--- a/win32ss/printing/base/winspool/printers.c
+++ b/win32ss/printing/base/winspool/printers.c
@@ -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)