[WINSPOOL] GetPrinterDriverA(): Refactor failure handling (#2832)
[reactos.git] / win32ss / printing / base / winspool / printers.c
index 3d02914..249d412 100644 (file)
@@ -8,6 +8,7 @@
 #include "precomp.h"
 #include <marshalling/printers.h>
 #include <marshalling/printerdrivers.h>
+#include <strsafe.h>
 
 // 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,459 @@ Cleanup:
 BOOL WINAPI
 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    DWORD dwErrorCode;
+    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)
+    {
+        dwErrorCode = 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)
+        {
+            dwErrorCode = 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 */
+    if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned))
+    {
+        dwErrorCode = GetLastError();
+        goto Cleanup;
+    }
+
+    /* 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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)
+                    {
+                        dwErrorCode = 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
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    if (pwszName)
+    {
+        HeapFree(hProcessHeap, 0, pwszName);
+    }
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
@@ -397,201 +933,1004 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
 
     TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
 
-    // Dismiss invalid levels already at this point.
-    if (Level == 3 || Level > 5)
-    {
-        dwErrorCode = ERROR_INVALID_LEVEL;
-        goto Cleanup;
-    }
+    // Dismiss invalid levels already at this point.
+    if (Level == 3 || Level > 5)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if (cbBuf && pPrinterEnum)
+        ZeroMemory(pPrinterEnum, cbBuf);
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    if (dwErrorCode == ERROR_SUCCESS)
+    {
+        // Replace relative offset addresses in the output by absolute pointers.
+        ASSERT(Level <= 9);
+        MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
+    }
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
+{
+    TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
+    UNIMPLEMENTED;
+    return FALSE;
+}
+
+BOOL WINAPI
+GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
+{
+    DWORD dwErrorCode;
+    PWSTR pwszBuffer = NULL;
+
+    TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
+
+    // Sanity check.
+    if (!pcchBuffer)
+    {
+        dwErrorCode = ERROR_INVALID_PARAMETER;
+        goto Cleanup;
+    }
+
+    // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
+    if (pszBuffer && *pcchBuffer)
+    {
+        pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
+        if (!pwszBuffer)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("HeapAlloc failed!\n");
+            goto Cleanup;
+        }
+    }
+
+    if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
+    {
+        dwErrorCode = GetLastError();
+        goto Cleanup;
+    }
+
+    // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
+    WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    if (pwszBuffer)
+        HeapFree(hProcessHeap, 0, pwszBuffer);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
+{
+    DWORD cbNeeded;
+    DWORD cchInputBuffer;
+    DWORD dwErrorCode;
+    HKEY hWindowsKey = NULL;
+    PWSTR pwszDevice = NULL;
+    PWSTR pwszComma;
+
+    TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
+
+    // Sanity check.
+    if (!pcchBuffer)
+    {
+        dwErrorCode = ERROR_INVALID_PARAMETER;
+        goto Cleanup;
+    }
+
+    cchInputBuffer = *pcchBuffer;
+
+    // Open the registry key where the default printer for the current user is stored.
+    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Determine the size of the required buffer.
+    dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Allocate it.
+    pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
+    if (!pwszDevice)
+    {
+        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+        ERR("HeapAlloc failed!\n");
+        goto Cleanup;
+    }
+
+    // Now get the actual value.
+    dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // We get a string "<Printer Name>,winspool,<Port>:".
+    // Extract the printer name from it.
+    pwszComma = wcschr(pwszDevice, L',');
+    if (!pwszComma)
+    {
+        ERR("Found no or invalid default printer: %S!\n", pwszDevice);
+        dwErrorCode = ERROR_INVALID_NAME;
+        goto Cleanup;
+    }
+
+    // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
+    *pcchBuffer = pwszComma - pwszDevice + 1;
+
+    // Check if the supplied buffer is large enough.
+    if (cchInputBuffer < *pcchBuffer)
+    {
+        dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+        goto Cleanup;
+    }
+
+    // Copy the default printer.
+    *pwszComma = 0;
+    CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    if (hWindowsKey)
+        RegCloseKey(hWindowsKey);
+
+    if (pwszDevice)
+        HeapFree(hProcessHeap, 0, pwszDevice);
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+    DWORD dwErrorCode;
+    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;
+
+    TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
+
+    // Check for invalid levels here for early error return. Should be 1-9.
+    if (Level <  1 || Level > 9)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        ERR("Invalid Level!\n");
+        goto Cleanup;
+    }
+
+    if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded))
+    {
+        dwErrorCode = GetLastError();
+        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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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)
+                {
+                    dwErrorCode = 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
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+{   
+    DWORD dwErrorCode;
+    /*
+     * 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;
+
+    DWORD cch;
+    PWSTR pwszEnvironment = NULL;
+
+    TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
+
+    // Check for invalid levels here for early error return. Should be 1-6.
+    if (Level <  1 || Level > 6)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        ERR("Invalid Level!\n");
+        goto Cleanup;
+    }
+
+    if (pEnvironment)
+    {
+        // Convert pEnvironment to a Unicode string pwszEnvironment.
+        cch = strlen(pEnvironment);
+
+        pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+        if (!pwszEnvironment)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("HeapAlloc failed!\n");
+            goto Cleanup;
+        }
+
+        MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1);
+    }
+
+    if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded))
+    {
+        dwErrorCode = GetLastError();
+        goto Cleanup;
+    }
+
+    // Do Unicode to ANSI conversions for strings based on Level
+    switch (Level)
+    {
+        case 1:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            break;
+        }
+
+        case 2:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            break;
+        }
+
+        case 3:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pHelpFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDependentFiles);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pMonitorName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDefaultDataType);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            break;
+        }
+
+        case 4:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    if (cbBuf && pPrinterEnum)
-        ZeroMemory(pPrinterEnum, cbBuf);
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Do the RPC call
-    RpcTryExcept
-    {
-        dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
-    }
-    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
-    {
-        dwErrorCode = RpcExceptionCode();
-        ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
-    }
-    RpcEndExcept;
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    if (dwErrorCode == ERROR_SUCCESS)
-    {
-        // Replace relative offset addresses in the output by absolute pointers.
-        ASSERT(Level <= 9);
-        MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-Cleanup:
-    SetLastError(dwErrorCode);
-    return (dwErrorCode == ERROR_SUCCESS);
-}
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pHelpFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-BOOL WINAPI
-FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
-{
-    TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
-    UNIMPLEMENTED;
-    return FALSE;
-}
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDependentFiles);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-BOOL WINAPI
-GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
-{
-    DWORD dwErrorCode;
-    PWSTR pwszBuffer = NULL;
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pMonitorName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDefaultDataType);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
+            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Sanity check.
-    if (!pcchBuffer)
-    {
-        dwErrorCode = ERROR_INVALID_PARAMETER;
-        goto Cleanup;
-    }
+            break;
+        }
 
-    // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
-    if (pszBuffer && *pcchBuffer)
-    {
-        pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
-        if (!pwszBuffer)
+        case 5:
         {
-            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
-            ERR("HeapAlloc failed!\n");
-            goto Cleanup;
-        }
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
-    {
-        dwErrorCode = GetLastError();
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
-    WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
+            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    dwErrorCode = ERROR_SUCCESS;
+            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-Cleanup:
-    if (pwszBuffer)
-        HeapFree(hProcessHeap, 0, pwszBuffer);
+            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    SetLastError(dwErrorCode);
-    return (dwErrorCode == ERROR_SUCCESS);
-}
+            break;
+        }
 
-BOOL WINAPI
-GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
-{
-    DWORD cbNeeded;
-    DWORD cchInputBuffer;
-    DWORD dwErrorCode;
-    HKEY hWindowsKey = NULL;
-    PWSTR pwszDevice = NULL;
-    PWSTR pwszComma;
+        case 6:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Sanity check.
-    if (!pcchBuffer)
-    {
-        dwErrorCode = ERROR_INVALID_PARAMETER;
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    cchInputBuffer = *pcchBuffer;
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Open the registry key where the default printer for the current user is stored.
-    dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
-    if (dwErrorCode != ERROR_SUCCESS)
-    {
-        ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Determine the size of the required buffer.
-    dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
-    if (dwErrorCode != ERROR_SUCCESS)
-    {
-        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pHelpFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Allocate it.
-    pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
-    if (!pwszDevice)
-    {
-        dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
-        ERR("HeapAlloc failed!\n");
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDependentFiles);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Now get the actual value.
-    dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
-    if (dwErrorCode != ERROR_SUCCESS)
-    {
-        ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pMonitorName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDefaultDataType);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // We get a string "<Printer Name>,winspool,<Port>:".
-    // Extract the printer name from it.
-    pwszComma = wcschr(pwszDevice, L',');
-    if (!pwszComma)
-    {
-        ERR("Found no or invalid default printer: %S!\n", pwszDevice);
-        dwErrorCode = ERROR_INVALID_NAME;
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
-    *pcchBuffer = pwszComma - pwszDevice + 1;
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszMfgName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Check if the supplied buffer is large enough.
-    if (cchInputBuffer < *pcchBuffer)
-    {
-        dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
-        goto Cleanup;
-    }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszOEMUrl);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
 
-    // Copy the default printer.
-    *pwszComma = 0;
-    CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszHardwareID);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszProvider);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+    }
 
     dwErrorCode = ERROR_SUCCESS;
 
 Cleanup:
-    if (hWindowsKey)
-        RegCloseKey(hWindowsKey);
-
-    if (pwszDevice)
-        HeapFree(hProcessHeap, 0, pwszDevice);
+    if (pwszEnvironment)
+    {
+        HeapFree(hProcessHeap, 0, pwszEnvironment);
+    }
 
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
 }
 
-BOOL WINAPI
-GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
-{
-    TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
-    if(pcbNeeded) *pcbNeeded = 0;
-    return FALSE;
-}
-
-BOOL WINAPI
-GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
-{
-    TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
-    if(pcbNeeded) *pcbNeeded = 0;
-    return FALSE;
-}
-
 BOOL WINAPI
 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
 {
@@ -625,14 +1964,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);
     }
 
@@ -1028,6 +2367,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)
 {