[WINSPOOL] Implement DocumentPropertiesA including DEVMODE conversions (#2339)
authorDoug Lyons <douglyons@douglyons.com>
Tue, 25 Feb 2020 07:02:46 +0000 (01:02 -0600)
committerGitHub <noreply@github.com>
Tue, 25 Feb 2020 07:02:46 +0000 (08:02 +0100)
Co-authored-by: Doug Lyons <douglyons@douglyons.com>
Co-authored-by: Colin Finck <colin@reactos.org>
win32ss/printing/base/winspool/devmode.c
win32ss/printing/base/winspool/precomp.h
win32ss/printing/base/winspool/printers.c

index b75932a..c97f0e9 100644 (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);
+}
index cae8bd3..58eed62 100644 (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
index f661606..4180dfb 100644 (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)