[Printing] Fix ups and Implementations.
authorJames Tabor <james.tabor@reactos.org>
Tue, 4 Aug 2020 02:07:58 +0000 (21:07 -0500)
committerJames Tabor <james.tabor@reactos.org>
Tue, 4 Aug 2020 02:07:58 +0000 (21:07 -0500)
WinSpool : Implement missing API. Sync/Port from wine. Setting it to fast track for needed testing of the later GDI code. Leaving Fix-me debug prints on.
Local tree has WinSpool_winetest turned on. So no debug noise during normal ReactOS operation.

SpoolSS : Reordered header types. Have more Spl function to be added while SpoolSV is being coded to forward to LocalSpl.

Based on wine and old research from the GDI code.

26 files changed:
win32ss/printing/base/printui/printui.spec
win32ss/printing/base/spoolss/memory.c
win32ss/printing/base/spoolss/precomp.h
win32ss/printing/base/spoolsv/precomp.h
win32ss/printing/base/spoolsv/spoolfile.c
win32ss/printing/base/winspool/CMakeLists.txt
win32ss/printing/base/winspool/devmode.c
win32ss/printing/base/winspool/forms.c
win32ss/printing/base/winspool/jobs.c
win32ss/printing/base/winspool/main.c
win32ss/printing/base/winspool/monitors.c
win32ss/printing/base/winspool/ports.c
win32ss/printing/base/winspool/precomp.h
win32ss/printing/base/winspool/printerdata.c
win32ss/printing/base/winspool/printerdrivers.c
win32ss/printing/base/winspool/printers.c
win32ss/printing/base/winspool/printprocessors.c
win32ss/printing/base/winspool/printproviders.c
win32ss/printing/base/winspool/spoolfile.c [new file with mode: 0644]
win32ss/printing/base/winspool/utils.c
win32ss/printing/base/winspool/winspool.rc
win32ss/printing/base/winspool/winspool.spec
win32ss/printing/include/marshalling/forms.h [new file with mode: 0644]
win32ss/printing/include/marshalling/printerdrivers.h
win32ss/printing/include/spoolss.h
win32ss/printing/providers/localspl/spoolfile.c

index 2f2db27..e6ff2fd 100644 (file)
@@ -1,6 +1,6 @@
 @ stub ConnectToPrinterDlg
 @ stub ConnectToPrinterPropertyPage
-@ stub ConstructPrinterFriendlyName
+@ stdcall -stub ConstructPrinterFriendlyName(wstr wstr ptr)
 @ stub -private DllCanUnloadNow
 @ stub -private DllGetClassObject
 @ stub DocumentPropertiesWrap
index 2eeed65..d7f64d2 100644 (file)
@@ -111,6 +111,7 @@ DllAllocSplMem(DWORD dwBytes)
 BOOL WINAPI
 DllFreeSplMem(PVOID pMem)
 {
+    if ( !pMem ) return TRUE;
     return HeapFree(hProcessHeap, 0, pMem);
 }
 
@@ -128,7 +129,9 @@ DllFreeSplMem(PVOID pMem)
 BOOL WINAPI
 DllFreeSplStr(PWSTR pwszString)
 {
-    return HeapFree(hProcessHeap, 0, pwszString);
+    if ( pwszString )
+       return HeapFree(hProcessHeap, 0, pwszString);
+    return FALSE;
 }
 
 /**
index ee373e2..3a859aa 100644 (file)
@@ -52,12 +52,4 @@ SPOOLSS_PRINTER_HANDLE, *PSPOOLSS_PRINTER_HANDLE;
 extern HANDLE hProcessHeap;
 extern LIST_ENTRY PrintProviderList;
 
-// spoolfile.c
-typedef struct _FILE_INFO_1
-{
-    BOOL   bInheritHandle;
-    HANDLE hSpoolFileHandle;
-    DWORD  dwOptions;
-} FILE_INFO_1, *PFILE_INFO_1;
-
 #endif
index 79febdd..5ab518a 100644 (file)
@@ -28,27 +28,4 @@ WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);
 // rpcserver.c
 DWORD WINAPI LrpcThreadProc(LPVOID lpParameter);
 
-// spoolfile.c
-BOOL WINAPI
-SplGetSpoolFileInfo(
-    HANDLE hPrinter,
-    HANDLE hProcessHandle,
-    DWORD Level,
-    WINSPOOL_FILE_INFO_1 *pFileInfo,
-    DWORD dwSize,
-    DWORD* dwNeeded );
-
-BOOL WINAPI
-SplCommitSpoolData(
-    HANDLE hPrinter,
-    HANDLE hProcessHandle,
-    DWORD cbCommit,
-    DWORD Level,
-    WINSPOOL_FILE_INFO_1 *pFileInfo,
-    DWORD dwSize,
-    DWORD* dwNeeded );
-
-BOOL WINAPI
-SplCloseSpoolFileHandle( HANDLE hPrinter );
-
 #endif
index 67e8085..fee89ec 100644 (file)
@@ -19,7 +19,7 @@ _RpcGetSpoolFileInfo( WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_HANDLE hProcess
         return dwErrorCode;
     }
 
-    if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, pFileInfo, dwSize, dwNeeded ) )
+    if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, (FILE_INFO_1*)pFileInfo, dwSize, dwNeeded ) )
         dwErrorCode = GetLastError();
 
     RpcRevertToSelf();
@@ -38,7 +38,7 @@ _RpcCommitSpoolData( WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_HANDLE hProcessH
         return dwErrorCode;
     }
 
-    if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, pFileInfo, dwSize, dwNeeded ) )
+    if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, (FILE_INFO_1*)pFileInfo, dwSize, dwNeeded ) )
         dwErrorCode = GetLastError();
 
     RpcRevertToSelf();
@@ -61,7 +61,7 @@ _RpcGetSpoolFileInfo2( WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwProcessId, DWOR
     hProcessHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId );
 
 
-    if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, pFileInfoContainer->FileInfo.pFileInfo1, sizeof(WINSPOOL_FILE_INFO_1), &dwNeeded ) )
+    if (!SplGetSpoolFileInfo( hPrinter, hProcessHandle, Level, (FILE_INFO_1*)pFileInfoContainer->FileInfo.pFileInfo1, sizeof(FILE_INFO_1), &dwNeeded ) )
         dwErrorCode = GetLastError();
 
     if ( hProcessHandle )
@@ -88,7 +88,7 @@ _RpcCommitSpoolData2( WINSPOOL_PRINTER_HANDLE hPrinter, DWORD dwProcessId, DWORD
 
     hProcessHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId );
 
-    if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, pFileInfoContainer->FileInfo.pFileInfo1, sizeof(WINSPOOL_FILE_INFO_1), &dwNeeded ) )
+    if (!SplCommitSpoolData( hPrinter, hProcessHandle, cbCommit, Level, (FILE_INFO_1*)pFileInfoContainer->FileInfo.pFileInfo1, sizeof(FILE_INFO_1), &dwNeeded ) )
         dwErrorCode = GetLastError();
 
     if ( hProcessHandle )
index b557db8..a0a8388 100644 (file)
@@ -16,6 +16,7 @@ list(APPEND SOURCE
     printers.c
     printprocessors.c
     printproviders.c
+    spoolfile.c
     utils.c
     ${CMAKE_CURRENT_BINARY_DIR}/winspool_c.c)
 
@@ -31,6 +32,6 @@ add_library(winspool MODULE
 set_target_properties(winspool PROPERTIES SUFFIX ".drv")
 set_module_type(winspool win32dll UNICODE)
 target_link_libraries(winspool wine ${PSEH_LIB})
-add_importlibs(winspool advapi32 gdi32 rpcrt4 msvcrt kernel32 ntdll)
+add_importlibs(winspool advapi32 gdi32 user32 rpcrt4 msvcrt kernel32 ntdll)
 add_pch(winspool precomp.h "${PCH_SKIP_SOURCE}")
 add_cd_file(TARGET winspool DESTINATION reactos/system32 FOR all)
index c97f0e9..fd1a615 100644 (file)
@@ -234,7 +234,55 @@ Failure:
     return FALSE;
 }
 
-void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput)
+BOOL WINAPI
+IsValidDevmodeNoSizeW(PDEVMODEW pDevmode)
+{
+    PMINIMUM_SIZE_TABLE pTable = MinimumSizeW;
+    WORD wRequiredSize;
+
+    TRACE("IsValidDevmodeNoSizeW(%p)\n", pDevmode);
+
+    // Check if a Devmode was given at all.
+    if (!pDevmode)
+        goto Failure;
+
+    // If the structure has private members, the public structure must be 32-bit packed.
+    if (pDevmode->dmDriverExtra && pDevmode->dmSize % 4)
+        goto Failure;
+
+    // Now determine the minimum possible dmSize based on the given fields in dmFields.
+    wRequiredSize = FIELD_OFFSET(DEVMODEW, dmFields) + RTL_FIELD_SIZE(DEVMODEW, dmFields);
+
+    while (pTable->dwField)
+    {
+        if (pDevmode->dmFields & pTable->dwField)
+        {
+            wRequiredSize = pTable->wSize;
+            break;
+        }
+
+        pTable++;
+    }
+
+    // Verify that the value in dmSize is big enough for the used fields.
+    if (pDevmode->dmSize < wRequiredSize)
+        goto Failure;
+
+    // Check if dmDeviceName and (if used) dmFormName are null-terminated.
+    // Fix this if they aren't.
+    _FixStringW(pDevmode->dmDeviceName, sizeof(pDevmode->dmDeviceName));
+    if (pDevmode->dmFields & DM_FORMNAME)
+        _FixStringW(pDevmode->dmFormName, sizeof(pDevmode->dmFormName));
+
+    // Return success without setting the error code.
+    return TRUE;
+
+Failure:
+    SetLastError(ERROR_INVALID_DATA);
+    return FALSE;
+}
+
+void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW *pDevModeOutput)
 {
     // FIXME: This function should become ConvertAnsiDevModeToUnicodeDevmode when its parameters are known!
 
@@ -242,7 +290,7 @@ void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pD
     if (!pDevModeInput || !pDevModeOutput)
         return;
 
-    pDevModeOutput = GdiConvertToDevmodeW(pDevModeInput);
+    *pDevModeOutput = GdiConvertToDevmodeW(pDevModeInput);
 }
 
 // Internal counterpart to GdiConvertToDevmodeW from gdi32
@@ -304,11 +352,15 @@ _ConvertToDevmodeA(const DEVMODEW *dmW)
 
 void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput)
 {
+    PDEVMODEA pTmp;
+
     // 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);
+    pTmp = _ConvertToDevmodeA(pDevModeInput);
+    memcpy( pDevModeOutput, pTmp, pTmp->dmSize + pTmp->dmDriverExtra); // Copy into a Wide char (Larger) buffer.
+    HeapFree(hProcessHeap, 0, pTmp);
 }
index 50ce561..7d8a0e6 100644 (file)
  */
 
 #include "precomp.h"
+#include <marshalling/forms.h>
 
 BOOL WINAPI
 AddFormA(HANDLE hPrinter, DWORD Level, PBYTE pForm)
 {
+    FORM_INFO_2W   pfi2W;
+    PFORM_INFO_2A  pfi2A;
+    DWORD   len;
+    BOOL    res;
+
+    pfi2A = (PFORM_INFO_2A)pForm;
+
     TRACE("AddFormA(%p, %lu, %p)\n", hPrinter, Level, pForm);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ((Level < 1) || (Level > 2))
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    if (!pfi2A)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    ZeroMemory(&pfi2W, sizeof(FORM_INFO_2W));
+
+    if (pfi2A->pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, NULL, 0);
+        pfi2W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, pfi2W.pName, len);
+    }
+
+    pfi2W.Flags         = pfi2A->Flags;
+    pfi2W.Size          = pfi2A->Size;
+    pfi2W.ImageableArea = pfi2A->ImageableArea;
+
+    if (Level > 1)
+    {
+        if (pfi2A->pKeyword)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, NULL, 0);
+            pfi2W.pKeyword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, (LPWSTR)pfi2W.pKeyword, len);
+        }
+
+        if (pfi2A->pMuiDll)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, NULL, 0);
+            pfi2W.pMuiDll = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, (LPWSTR)pfi2W.pMuiDll, len);
+        }
+
+        if (pfi2A->pDisplayName)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, NULL, 0);
+            pfi2W.pDisplayName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, (LPWSTR)pfi2W.pDisplayName, len);
+        }
+        pfi2W.StringType   = pfi2A->StringType;
+        pfi2W.dwResourceId = pfi2A->dwResourceId;
+        pfi2W.wLangId      = pfi2A->wLangId;
+    }
+
+    res = AddFormW( hPrinter, Level, (PBYTE)&pfi2W );
+
+    if (pfi2W.pName) HeapFree(GetProcessHeap(), 0, pfi2W.pName);
+    if (pfi2W.pKeyword) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pKeyword);
+    if (pfi2W.pMuiDll) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pMuiDll);
+    if (pfi2W.pDisplayName) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pDisplayName);
+
+    return res;
 }
 
 BOOL WINAPI
 AddFormW(HANDLE hPrinter, DWORD Level, PBYTE pForm)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_FORM_CONTAINER FormInfoContainer;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("AddFormW(%p, %lu, %p)\n", hPrinter, Level, pForm);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        return FALSE;
+    }
+
+    if ((Level < 1) || (Level > 2))
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    FormInfoContainer.FormInfo.pFormInfo1 = (WINSPOOL_FORM_INFO_1*)pForm;
+    FormInfoContainer.Level = Level;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddForm(pHandle->hPrinter, &FormInfoContainer);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcAddForm failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 DeleteFormA(HANDLE hPrinter, PSTR pFormName)
 {
+    UNICODE_STRING FormNameW;
+    BOOL Ret;
+
     TRACE("DeleteFormA(%p, %s)\n", hPrinter, pFormName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    AsciiToUnicode(&FormNameW, pFormName);
+
+    Ret = DeleteFormW( hPrinter, FormNameW.Buffer );
+
+    RtlFreeUnicodeString(&FormNameW);
+
+    return Ret;
 }
 
 BOOL WINAPI
 DeleteFormW(HANDLE hPrinter, PWSTR pFormName)
 {
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("DeleteFormW(%p, %S)\n", hPrinter, pFormName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        return FALSE;
+    }
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeleteForm(pHandle->hPrinter, pFormName);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcDeleteForm failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 EnumFormsA(HANDLE hPrinter, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    DWORD dwErrorCode, i;
+    PFORM_INFO_2W pfi2w = (PFORM_INFO_2W)pForm;
+
     TRACE("EnumFormsA(%p, %lu, %p, %lu, %p, %p)\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
+
+    if ( EnumFormsW( hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned ) )
+    {
+        for ( i = 0; i < *pcReturned; i++ )
+        {
+            switch ( Level )
+            {
+                case 2:
+                    dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pKeyword);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pMuiDll);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w[i].pDisplayName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    // Fall through...
+                case 1:
+                    dwErrorCode = UnicodeToAnsiInPlace(pfi2w[i].pName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+            }
+        }
+        return TRUE;
+    }
+Cleanup:
     return FALSE;
 }
 
 BOOL WINAPI
 EnumFormsW(HANDLE hPrinter, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("EnumFormsW(%p, %lu, %p, %lu, %p, %p)\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        goto Cleanup;
+    }
+
+    if ((Level < 1) || (Level > 2))
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcEnumForms(pHandle->hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcEnumForms failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    if (dwErrorCode == ERROR_SUCCESS)
+    {
+        // Replace relative offset addresses in the output by absolute pointers.
+        ASSERT(Level >= 1 && Level <= 2);
+        MarshallUpStructuresArray(cbBuf, pForm, *pcReturned, pFormInfoMarshalling[Level]->pInfo, pFormInfoMarshalling[Level]->cbStructureSize, TRUE);
+    }
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 GetFormA(HANDLE hPrinter, PSTR pFormName, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded)
 {
+    DWORD dwErrorCode, len;
+    LPWSTR FormNameW = NULL;
+    FORM_INFO_2W* pfi2w = (FORM_INFO_2W*)pForm;
+
     TRACE("GetFormA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if (pFormName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pFormName, -1, NULL, 0);
+        FormNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pFormName, -1, FormNameW, len);
+    }
+
+    if ( GetFormW( hPrinter, FormNameW, Level, pForm, cbBuf, pcbNeeded ) )
+    {
+        switch ( Level )
+        {
+            case 2:
+                dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pKeyword);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pMuiDll);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace((LPWSTR)pfi2w->pDisplayName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+            // Fall through...
+            case 1:
+                dwErrorCode = UnicodeToAnsiInPlace(pfi2w->pName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                break;
+
+            default:
+                ERR("Level = %d, unsupported!\n", Level);
+                dwErrorCode = ERROR_INVALID_HANDLE;
+                SetLastError(dwErrorCode);
+                break;
+        }
+    }
+Cleanup:
+    if (FormNameW) HeapFree(GetProcessHeap(), 0, FormNameW);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 GetFormW(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm, DWORD cbBuf, PDWORD pcbNeeded)
 {
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("GetFormW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        goto Cleanup;
+    }
+
+    // Dismiss invalid levels already at this point.
+    if ((Level < 1) || (Level > 2))
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if (cbBuf && pForm)
+        ZeroMemory(pForm, cbBuf);
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcGetForm(pHandle->hPrinter, pFormName, Level, pForm, cbBuf, pcbNeeded);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcGetForm failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    if (dwErrorCode == ERROR_SUCCESS)
+    {
+        // Replace relative offset addresses in the output by absolute pointers.
+        ASSERT(Level >= 1 && Level <= 2);
+        MarshallUpStructure(cbBuf, pForm, pFormInfoMarshalling[Level]->pInfo, pFormInfoMarshalling[Level]->cbStructureSize, TRUE);
+    }
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 SetFormA(HANDLE hPrinter, PSTR pFormName, DWORD Level, PBYTE pForm)
 {
+    FORM_INFO_2W   pfi2W;
+    FORM_INFO_2A * pfi2A;
+    LPWSTR FormNameW = NULL;
+    DWORD len;
+    BOOL res;
+
+    pfi2A = (FORM_INFO_2A *) pForm;
+
     TRACE("SetFormA(%p, %s, %lu, %p)\n", hPrinter, pFormName, Level, pForm);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ((Level < 1) || (Level > 2))
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    if (!pfi2A)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if (pFormName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pFormName, -1, NULL, 0);
+        FormNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pFormName, -1, FormNameW, len);
+    }
+
+    ZeroMemory(&pfi2W, sizeof(FORM_INFO_2W));
+
+    if (pfi2A->pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, NULL, 0);
+        pfi2W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pfi2A->pName, -1, pfi2W.pName, len);
+    }
+
+    pfi2W.Flags         = pfi2A->Flags;
+    pfi2W.Size          = pfi2A->Size;
+    pfi2W.ImageableArea = pfi2A->ImageableArea;
+
+    if (Level > 1)
+    {
+        if (pfi2A->pKeyword)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, NULL, 0);
+            pfi2W.pKeyword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pKeyword, -1, (LPWSTR)pfi2W.pKeyword, len);
+        }
+
+        if (pfi2A->pMuiDll)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, NULL, 0);
+            pfi2W.pMuiDll = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pMuiDll, -1, (LPWSTR)pfi2W.pMuiDll, len);
+        }
+
+        if (pfi2A->pDisplayName)
+        {
+            len = MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, NULL, 0);
+            pfi2W.pDisplayName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, pfi2A->pDisplayName, -1, (LPWSTR)pfi2W.pDisplayName, len);
+        }
+        pfi2W.StringType   = pfi2A->StringType;
+        pfi2W.dwResourceId = pfi2A->dwResourceId;
+        pfi2W.wLangId      = pfi2A->wLangId;
+    }
+
+    res = SetFormW( hPrinter, FormNameW, Level, (PBYTE)&pfi2W );
+
+    if (FormNameW) HeapFree(GetProcessHeap(), 0, FormNameW);
+    if (pfi2W.pName) HeapFree(GetProcessHeap(), 0, pfi2W.pName);
+    if (pfi2W.pKeyword) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pKeyword);
+    if (pfi2W.pMuiDll) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pMuiDll);
+    if (pfi2W.pDisplayName) HeapFree(GetProcessHeap(), 0, (LPWSTR)pfi2W.pDisplayName);
+
+    return res;
 }
 
 BOOL WINAPI
 SetFormW(HANDLE hPrinter, PWSTR pFormName, DWORD Level, PBYTE pForm)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_FORM_CONTAINER FormInfoContainer;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("SetFormW(%p, %S, %lu, %p)\n", hPrinter, pFormName, Level, pForm);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        return FALSE;
+    }
+
+    FormInfoContainer.FormInfo.pFormInfo1 = (WINSPOOL_FORM_INFO_1*)pForm;
+    FormInfoContainer.Level = Level;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcSetForm(pHandle->hPrinter, pFormName, &FormInfoContainer);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
index e3cea65..7cc17d4 100644 (file)
 BOOL WINAPI
 AddJobA(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
 {
-    TRACE("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
-    return FALSE;
+    BOOL ret;
+
+    FIXME("AddJobA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
+
+    if (Level != 1)
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    ret = AddJobW(hPrinter, Level, pData, cbBuf, pcbNeeded);
+
+    if (ret)
+    {
+        DWORD dwErrorCode;
+        ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)pData;
+        dwErrorCode = UnicodeToAnsiInPlace(addjobW->Path);
+        if (dwErrorCode != ERROR_SUCCESS)
+        {
+           ret = FALSE;
+        }
+    }
+    return ret;
 }
 
 BOOL WINAPI
@@ -22,7 +43,7 @@ AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded
     DWORD dwErrorCode;
     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
 
-    TRACE("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
+    FIXME("AddJobW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
 
     if (!pHandle)
     {
@@ -46,6 +67,8 @@ AddJobW(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded
     {
         // Replace relative offset addresses in the output by absolute pointers.
         MarshallUpStructure(cbBuf, pData, AddJobInfo1Marshalling.pInfo, AddJobInfo1Marshalling.cbStructureSize, TRUE);
+        pHandle->bJob = TRUE;
+        FIXME("Notify Tray Icon\n");
     }
 
 Cleanup:
@@ -56,8 +79,118 @@ Cleanup:
 BOOL WINAPI
 EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    DWORD dwErrorCode, i;
+    JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob;
+    JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob;
+    JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob;
+
     TRACE("EnumJobsA(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
+
+    if ( Level == 3 )
+        return EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned );
+
+    if ( EnumJobsW( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned ) )
+    {
+        switch ( Level )
+        {
+            case 1:
+            {
+                for ( i = 0; i < *pcReturned; i++ )
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pPrinterName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pMachineName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pUserName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDocument);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pDatatype);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji1w[i].pStatus);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+            }
+                break;
+
+            case 2:
+            {
+                for ( i = 0; i < *pcReturned; i++ )
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrinterName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pMachineName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pUserName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDocument);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pNotifyName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pDatatype);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pPrintProcessor);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pParameters);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pji2w[i].pStatus);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    if ( pji2w[i].pDevMode )
+                    {
+                        RosConvertUnicodeDevModeToAnsiDevmode( pji2w[i].pDevMode, pji2a[i].pDevMode );
+                    }
+                }
+            }
+                break;
+        }
+        return TRUE;
+    }
+Cleanup:
     return FALSE;
 }
 
@@ -105,8 +238,108 @@ Cleanup:
 BOOL WINAPI
 GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD pcbNeeded)
 {
-    TRACE("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
+    DWORD dwErrorCode;
+    JOB_INFO_1W* pji1w = (JOB_INFO_1W*)pJob;
+    JOB_INFO_2A* pji2a = (JOB_INFO_2A*)pJob;
+    JOB_INFO_2W* pji2w = (JOB_INFO_2W*)pJob;
+
+    FIXME("GetJobA(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+
+    if ( Level == 3 )
+        return GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded );
+
+    if ( GetJobW( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded ) )
+    {
+        switch ( Level )
+        {
+            case 1:
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pPrinterName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pMachineName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pUserName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDocument);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pDatatype);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji1w->pStatus);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                break;
+
+            case 2:
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrinterName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pMachineName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pUserName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDocument);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pNotifyName);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pDatatype);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pPrintProcessor);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pParameters);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                dwErrorCode = UnicodeToAnsiInPlace(pji2w->pStatus);
+                if (dwErrorCode != ERROR_SUCCESS)
+                {
+                    goto Cleanup;
+                }
+                if ( pji2w->pDevMode )
+                {
+                    RosConvertUnicodeDevModeToAnsiDevmode( pji2w->pDevMode, pji2a->pDevMode );
+                }
+                break;
+        }
+        return TRUE;
+    }
+Cleanup:
     return FALSE;
 }
 
@@ -116,7 +349,7 @@ GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWO
     DWORD dwErrorCode;
     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
 
-    TRACE("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+    FIXME("GetJobW(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
 
     if (!pHandle)
     {
@@ -174,6 +407,9 @@ ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
     }
     RpcEndExcept;
 
+    if ( dwErrorCode == ERROR_SUCCESS )
+        pHandle->bJob = FALSE;
+
 Cleanup:
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
@@ -182,9 +418,100 @@ Cleanup:
 BOOL WINAPI
 SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
 {
+    BOOL ret;
+    LPBYTE JobW;
+    UNICODE_STRING usBuffer;
+
     TRACE("SetJobA(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
+       are all ignored by SetJob, so we don't bother copying them */
+    switch(Level)
+    {
+    case 0:
+        JobW = NULL;
+        break;
+    case 1:
+      {
+        JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
+        ZeroMemory( info1W, sizeof(JOB_INFO_1W) );
+        JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJobInfo;
+
+        JobW = (LPBYTE)info1W;
+        info1W->pUserName = AsciiToUnicode(&usBuffer, info1A->pUserName);
+        info1W->pDocument = AsciiToUnicode(&usBuffer, info1A->pDocument);
+        info1W->pDatatype = AsciiToUnicode(&usBuffer, info1A->pDatatype);
+        info1W->pStatus = AsciiToUnicode(&usBuffer, info1A->pStatus);
+        info1W->Status = info1A->Status;
+        info1W->Priority = info1A->Priority;
+        info1W->Position = info1A->Position;
+        info1W->PagesPrinted = info1A->PagesPrinted;
+        break;
+      }
+    case 2:
+      {
+        JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
+        ZeroMemory( info2W, sizeof(JOB_INFO_2W) );
+        JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJobInfo;
+
+        JobW = (LPBYTE)info2W;
+        info2W->pUserName = AsciiToUnicode(&usBuffer, info2A->pUserName);
+        info2W->pDocument = AsciiToUnicode(&usBuffer, info2A->pDocument);
+        info2W->pNotifyName = AsciiToUnicode(&usBuffer, info2A->pNotifyName);
+        info2W->pDatatype = AsciiToUnicode(&usBuffer, info2A->pDatatype);
+        info2W->pPrintProcessor = AsciiToUnicode(&usBuffer, info2A->pPrintProcessor);
+        info2W->pParameters = AsciiToUnicode(&usBuffer, info2A->pParameters);
+        info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
+        info2W->pStatus = AsciiToUnicode(&usBuffer, info2A->pStatus);
+        info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
+        info2W->Status = info2A->Status;
+        info2W->Priority = info2A->Priority;
+        info2W->Position = info2A->Position;
+        info2W->StartTime = info2A->StartTime;
+        info2W->UntilTime = info2A->UntilTime;
+        info2W->PagesPrinted = info2A->PagesPrinted;
+        break;
+      }
+    case 3:
+        JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
+        memcpy(JobW, pJobInfo, sizeof(JOB_INFO_3));
+        break;
+    default:
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
+
+    switch(Level)
+    {
+    case 1:
+      {
+        JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
+        HeapFree(GetProcessHeap(), 0, info1W->pUserName);
+        HeapFree(GetProcessHeap(), 0, info1W->pDocument);
+        HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
+        HeapFree(GetProcessHeap(), 0, info1W->pStatus);
+        break;
+      }
+    case 2:
+      {
+        JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
+        HeapFree(GetProcessHeap(), 0, info2W->pUserName);
+        HeapFree(GetProcessHeap(), 0, info2W->pDocument);
+        HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
+        HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
+        HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
+        HeapFree(GetProcessHeap(), 0, info2W->pParameters);
+        HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
+        HeapFree(GetProcessHeap(), 0, info2W->pStatus);
+        break;
+      }
+    }
+    HeapFree(GetProcessHeap(), 0, JobW);
+
+    return ret;
 }
 
 BOOL WINAPI
index c4f6f77..d9c66eb 100644 (file)
@@ -9,7 +9,8 @@
 
 // Global Variables
 HANDLE hProcessHeap;
-
+HINSTANCE hinstWinSpool = NULL;
+CRITICAL_SECTION rtlCritSec;
 
 handle_t __RPC_USER
 WINSPOOL_HANDLE_bind(WINSPOOL_HANDLE wszName)
@@ -79,6 +80,12 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             hProcessHeap = GetProcessHeap();
+            hinstWinSpool = hinstDLL;
+            InitializeCriticalSection(&rtlCritSec);
+            break;
+
+        case DLL_PROCESS_DETACH:
+            DeleteCriticalSection(&rtlCritSec);
             break;
     }
 
index 18c6fd1..720d353 100644 (file)
 BOOL WINAPI
 AddMonitorA(PSTR pName, DWORD Level, PBYTE pMonitors)
 {
-    TRACE("AddMonitorA(%s, %lu, %p)\n", pName, Level, pMonitors);
-    UNIMPLEMENTED;
-    return FALSE;
+    LPWSTR  nameW = NULL;
+    INT     len;
+    BOOL    res;
+    LPMONITOR_INFO_2A mi2a;
+    MONITOR_INFO_2W mi2w;
+
+    mi2a = (LPMONITOR_INFO_2A) pMonitors;
+    TRACE("AddMonitorA(%s, %d, %p) :  %s %s %s\n", debugstr_a(pName), Level, pMonitors,
+          debugstr_a(mi2a ? mi2a->pName : NULL),
+          debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
+          debugstr_a(mi2a ? mi2a->pDLLName : NULL));
+
+    if  (Level != 2)
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
+    if (mi2a == NULL)
+    {
+        return FALSE;
+    }
+
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
+    if (mi2a->pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
+        mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
+    }
+    if (mi2a->pEnvironment)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
+        mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
+    }
+    if (mi2a->pDLLName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
+        mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
+    }
+
+    res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
+
+    HeapFree(GetProcessHeap(), 0, mi2w.pName);
+    HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
+    HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
+    HeapFree(GetProcessHeap(), 0, nameW);
+
+    return (res);
 }
 
 BOOL WINAPI
 AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_MONITOR_CONTAINER MonitorInfoContainer;
     TRACE("AddMonitorW(%S, %lu, %p)\n", pName, Level, pMonitors);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if (Level != 2)
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    MonitorInfoContainer.MonitorInfo.pMonitorInfo2 = (WINSPOOL_MONITOR_INFO_2*)pMonitors;
+    MonitorInfoContainer.Level = Level;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddMonitor(pName, &MonitorInfoContainer);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcAddMonitor failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 DeleteMonitorA(PSTR pName, PSTR pEnvironment, PSTR pMonitorName)
 {
+    LPWSTR  nameW = NULL;
+    LPWSTR  EnvironmentW = NULL;
+    LPWSTR  MonitorNameW = NULL;
+    BOOL    res;
+    INT     len;
+
     TRACE("DeleteMonitorA(%s, %s, %s)\n", pName, pEnvironment, pMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if (pName) {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    if (pEnvironment) {
+        len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
+        EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
+    }
+    if (pMonitorName) {
+        len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
+        MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
+    }
+
+    res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
+
+    HeapFree(GetProcessHeap(), 0, MonitorNameW);
+    HeapFree(GetProcessHeap(), 0, EnvironmentW);
+    HeapFree(GetProcessHeap(), 0, nameW);
+
+    return (res);
 }
 
 BOOL WINAPI
 DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
 {
+    DWORD dwErrorCode;
+
     TRACE("DeleteMonitorW(%S, %S, %S)\n", pName, pEnvironment, pMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeleteMonitor(pName, pEnvironment, pMonitorName);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcDeleteMonitor failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+
 }
 
 BOOL WINAPI
 EnumMonitorsA(PSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
-    TRACE("EnumMonitorsA(%s, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+    BOOL    res;
+    LPBYTE  bufferW = NULL;
+    LPWSTR  nameW = NULL;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    INT     len;
+
+    FIXME("EnumMonitorsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
+
+    if ( Level < 1 || Level > 2 )
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError( ERROR_INVALID_LEVEL );
+        return FALSE;
+    }
+
+    /* convert servername to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+    /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
+    needed = cbBuf * sizeof(WCHAR);
+    if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
+    res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
+
+    if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        if (pcbNeeded) needed = *pcbNeeded;
+        /* HeapReAlloc return NULL, when bufferW was NULL */
+        bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
+                              HeapAlloc(GetProcessHeap(), 0, needed);
+
+        /* Try again with the large Buffer */
+        res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
+    }
+    numentries = pcReturned ? *pcReturned : 0;
+    needed = 0;
+    /*
+       W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
+       We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
+     */
+    if (res)
+    {
+        /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
+        DWORD   entrysize = 0;
+        DWORD   index;
+        LPSTR   ptr;
+        LPMONITOR_INFO_2W mi2w;
+        LPMONITOR_INFO_2A mi2a;
+
+        /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
+        entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
+
+        /* First pass: calculate the size for all Entries */
+        mi2w = (LPMONITOR_INFO_2W) bufferW;
+        mi2a = (LPMONITOR_INFO_2A) pMonitors;
+        index = 0;
+        while (index < numentries)
+        {
+            index++;
+            needed += entrysize;    /* MONITOR_INFO_?A */
+            TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
+
+            needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
+                                            NULL, 0, NULL, NULL);
+            if (Level > 1)
+            {
+                needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
+                                                NULL, 0, NULL, NULL);
+                needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
+                                                NULL, 0, NULL, NULL);
+            }
+            /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
+            mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
+            mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
+        }
+
+        /* check for errors and quit on failure */
+        if (cbBuf < needed)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            res = FALSE;
+            goto emA_cleanup;
+        }
+        len = entrysize * numentries;       /* room for all MONITOR_INFO_?A */
+        ptr = (LPSTR) &pMonitors[len];      /* room for strings */
+        cbBuf -= len ;                      /* free Bytes in the user-Buffer */
+        mi2w = (LPMONITOR_INFO_2W) bufferW;
+        mi2a = (LPMONITOR_INFO_2A) pMonitors;
+        index = 0;
+        /* Second Pass: Fill the User Buffer (if we have one) */
+        while ((index < numentries) && pMonitors)
+        {
+            index++;
+            TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
+            mi2a->pName = ptr;
+            len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
+                                            ptr, cbBuf , NULL, NULL);
+            ptr += len;
+            cbBuf -= len;
+            if (Level > 1)
+            {
+                mi2a->pEnvironment = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
+
+                mi2a->pDLLName = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
+            }
+            /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
+            mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
+            mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
+        }
+    }
+emA_cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = (res) ? numentries : 0;
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, bufferW);
+
+    FIXME("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries);
+
+    return (res);
+
 }
 
 BOOL WINAPI
@@ -53,7 +310,14 @@ EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcb
 {
     DWORD dwErrorCode;
 
-    TRACE("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
+    FIXME("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
+
+    if ( Level < 1 || Level > 2 )
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError( ERROR_INVALID_LEVEL );
+        return FALSE;
+    }
 
     // Do the RPC call
     RpcTryExcept
@@ -63,7 +327,7 @@ EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcb
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
     {
         dwErrorCode = RpcExceptionCode();
-        ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode);
+        ERR("_RpcEnumMonitors failed with exception code %lu!\n", dwErrorCode);
     }
     RpcEndExcept;
 
index f243567..80854ab 100644 (file)
 #include "precomp.h"
 #include <marshalling/ports.h>
 
+typedef struct _PORTTHREADINFO
+{
+  LPWSTR pName;
+  HWND hWnd;
+  LPWSTR pPortName;
+  FARPROC fpFunction;
+  DWORD dwErrorCode;
+  HANDLE hEvent;
+} PORTTHREADINFO, *PPORTTHREADINFO;
+
+VOID WINAPI
+IntPortThread( PPORTTHREADINFO pPortThreadInfo )
+{
+    // Do the RPC call
+    RpcTryExcept
+    {
+        pPortThreadInfo->dwErrorCode = (*pPortThreadInfo->fpFunction)( pPortThreadInfo->pName, pPortThreadInfo->hWnd, pPortThreadInfo->pPortName);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        pPortThreadInfo->dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    SetEvent( pPortThreadInfo->hEvent );
+}
+
+//
+// Start a thread to wait on a printer port.
+//
 BOOL WINAPI
-AddPortA(PSTR pName, HWND hWnd, PSTR pMonitorName)
+StartPortThread( LPWSTR pName, HWND hWnd, LPWSTR pPortName, FARPROC fpFunction )
 {
-    TRACE("AddPortA(%s, %p, %s)\n", pName, hWnd, pMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+    PORTTHREADINFO PortThreadInfo;
+    HANDLE htHandle;
+    MSG Msg;
+    DWORD tid;
+
+    if ( hWnd ) EnableWindow( hWnd, FALSE );
+
+    PortThreadInfo.pName = pName;
+    PortThreadInfo.hWnd = hWnd;
+    PortThreadInfo.pPortName = pPortName;
+    PortThreadInfo.fpFunction = fpFunction;
+    PortThreadInfo.dwErrorCode = ERROR_SUCCESS;
+    PortThreadInfo.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
+
+    htHandle = CreateThread( NULL,
+                             32*1024,
+                            (LPTHREAD_START_ROUTINE)IntPortThread,
+                            &PortThreadInfo,
+                             0,
+                            &tid );
+
+    CloseHandle( htHandle );
+
+    while ( MsgWaitForMultipleObjects( 1, &PortThreadInfo.hEvent, FALSE, INFINITE, QS_SENDMESSAGE|QS_ALLEVENTS ) == 1 )
+    {
+        while ( PeekMessageW( &Msg, NULL, 0, 0, PM_REMOVE ) )
+        {
+            TranslateMessage( &Msg );
+            DispatchMessageW( &Msg );
+        }
+    }
+
+    CloseHandle( PortThreadInfo.hEvent );
+
+    if ( hWnd )
+    {
+        EnableWindow(hWnd, TRUE);
+        SetForegroundWindow(hWnd);
+        SetFocus(hWnd);
+    }
+
+    SetLastError(PortThreadInfo.dwErrorCode);
+    return (PortThreadInfo.dwErrorCode == ERROR_SUCCESS);
 }
 
+
 BOOL WINAPI
-AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName)
+AddPortA(PSTR pName, HWND hWnd, PSTR pMonitorName)
 {
-    TRACE("AddPortExA(%s, %lu, %p, %s)\n", pName, Level, lpBuffer, lpMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+    LPWSTR  nameW = NULL;
+    LPWSTR  monitorW = NULL;
+    DWORD   len;
+    BOOL    res;
+
+    TRACE("AddPortA(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
+
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    if (pMonitorName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
+        monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
+    }
+
+    res = AddPortW(nameW, hWnd, monitorW);
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, monitorW);
+
+    return res;
 }
 
 BOOL WINAPI
 AddPortExW(PWSTR pName, DWORD Level, PBYTE lpBuffer, PWSTR lpMonitorName)
 {
-    TRACE("AddPortExA(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+    DWORD dwErrorCode;
+    WINSPOOL_PORT_CONTAINER PortInfoContainer;
+    WINSPOOL_PORT_VAR_CONTAINER PortVarContainer;
+    WINSPOOL_PORT_INFO_FF *pPortInfoFF;
+
+    TRACE("AddPortExW(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName);
+
+    switch (Level)
+    {
+        case 1:
+           // FIXME!!!! Only Level 1 is supported? See note in wine winspool test info.c : line 575.
+           PortInfoContainer.PortInfo.pPortInfo1 = (WINSPOOL_PORT_INFO_1*)lpBuffer;
+           PortInfoContainer.Level = Level;
+           PortVarContainer.cbMonitorData = 0;
+           PortVarContainer.pMonitorData = NULL;
+           break;
+
+        case 0xFFFFFFFF:
+           pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer;
+           PortInfoContainer.PortInfo.pPortInfoFF = pPortInfoFF;
+           PortInfoContainer.Level = Level;
+           PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData;
+           PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData;
+           break;
+
+        default:
+           ERR("Level = %d, unsupported!\n", Level);
+           SetLastError(ERROR_INVALID_LEVEL);
+           return FALSE;
+    }
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddPortEx(pName, &PortInfoContainer, &PortVarContainer, lpMonitorName);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName)
+{
+    PORT_INFO_1W   pi1W;
+    PORT_INFO_1A * pi1A;
+    LPWSTR  nameW = NULL;
+    LPWSTR  monitorW = NULL;
+    DWORD   len;
+    BOOL    res = FALSE;
+    WINSPOOL_PORT_INFO_FF *pPortInfoFF, PortInfoFF;
+
+    pi1A = (PORT_INFO_1A *)lpBuffer;
+    pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer;
+
+    TRACE("AddPortExA(%s, %d, %p, %s): %s\n", debugstr_a(pName), Level, lpBuffer, debugstr_a(lpMonitorName), debugstr_a(pi1A ? pi1A->pName : NULL));
+
+    if ( !lpBuffer || !lpMonitorName )
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    if (lpMonitorName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, NULL, 0);
+        monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, monitorW, len);
+    }
+
+    pi1W.pName = NULL;
+    ZeroMemory( &PortInfoFF, sizeof(WINSPOOL_PORT_INFO_FF));
+
+    switch ( Level )
+    {
+        case 1:
+            if ( pi1A->pName )
+            {
+                len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0);
+                pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len);
+            }
+            break;
+
+        case 0xFFFFFFFF:
+            //
+            // Remember the calling parameter is Ansi.
+            //
+            if ( !pPortInfoFF->pPortName || !(PCHAR)pPortInfoFF->pPortName )
+            {
+                SetLastError(ERROR_INVALID_PARAMETER);
+                goto Cleanup;
+            }
+
+            len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, NULL, 0);
+            PortInfoFF.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, (LPWSTR)PortInfoFF.pPortName, len);
+
+            PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData;
+            PortInfoFF.pMonitorData  = pPortInfoFF->pMonitorData;
+            break;
+
+        default:
+            ERR("Level = %d, unsupported!\n", Level);
+            SetLastError(ERROR_INVALID_LEVEL);
+            goto Cleanup;
+    }
+
+    res = AddPortExW( nameW, Level,  Level == 1 ? (PBYTE)&pi1W : (PBYTE)&PortInfoFF, monitorW );
+
+Cleanup:
+    if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
+    if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW);
+    if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName);
+    if (PortInfoFF.pPortName) HeapFree(GetProcessHeap(), 0, PortInfoFF.pPortName);
+
+    return res;
 }
 
 BOOL WINAPI
 AddPortW(PWSTR pName, HWND hWnd, PWSTR pMonitorName)
 {
     TRACE("AddPortW(%S, %p, %S)\n", pName, hWnd, pMonitorName);
-    UNIMPLEMENTED;
-    return FALSE;
+    return StartPortThread(pName, hWnd, pMonitorName, (FARPROC)_RpcAddPort);
 }
 
 BOOL WINAPI
 ConfigurePortA(PSTR pName, HWND hWnd, PSTR pPortName)
 {
-    TRACE("ConfigurePortA(%s, %p, %s)\n", pName, hWnd, pPortName);
-    UNIMPLEMENTED;
-    return FALSE;
+    LPWSTR  nameW = NULL;
+    LPWSTR  portW = NULL;
+    INT     len;
+    DWORD   res;
+
+    TRACE("ConfigurePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
+
+    /* convert servername to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    /* convert portname to unicode */
+    if (pPortName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
+        portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
+    }
+
+    res = ConfigurePortW(nameW, hWnd, portW);
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, portW);
+
+    return res;
 }
 
 BOOL WINAPI
 ConfigurePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
 {
     TRACE("ConfigurePortW(%S, %p, %S)\n", pName, hWnd, pPortName);
-    UNIMPLEMENTED;
-    return FALSE;
+    return StartPortThread(pName, hWnd, pPortName, (FARPROC)_RpcConfigurePort);
 }
 
 BOOL WINAPI
 DeletePortA(PSTR pName, HWND hWnd, PSTR pPortName)
 {
-    TRACE("DeletePortA(%s, %p, %s)\n", pName, hWnd, pPortName);
-    UNIMPLEMENTED;
-    return FALSE;
+    LPWSTR  nameW = NULL;
+    LPWSTR  portW = NULL;
+    INT     len;
+    DWORD   res;
+
+    TRACE("DeletePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
+
+    /* convert servername to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    /* convert portname to unicode */
+    if (pPortName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
+        portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
+    }
+
+    res = DeletePortW(nameW, hWnd, portW);
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, portW);
+
+    return res;
 }
 
 BOOL WINAPI
 DeletePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
 {
     TRACE("DeletePortW(%S, %p, %S)\n", pName, hWnd, pPortName);
-    UNIMPLEMENTED;
-    return FALSE;
+    return StartPortThread(pName, hWnd, pPortName, (FARPROC)_RpcDeletePort);
 }
 
 BOOL WINAPI
 EnumPortsA(PSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
-    TRACE("EnumPortsA(%s, %lu, %p, %lu, %p, %p)\n", pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+    BOOL    res;
+    LPBYTE  bufferW = NULL;
+    LPWSTR  nameW = NULL;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    INT     len;
+
+    TRACE("EnumPortsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts, cbBuf, pcbNeeded, pcReturned);
+
+    /* convert servername to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+    /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
+    needed = cbBuf * sizeof(WCHAR);
+    if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
+    res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
+
+    if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        if (pcbNeeded) needed = *pcbNeeded;
+        /* HeapReAlloc return NULL, when bufferW was NULL */
+        bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
+                              HeapAlloc(GetProcessHeap(), 0, needed);
+
+        /* Try again with the large Buffer */
+        res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
+    }
+    needed = pcbNeeded ? *pcbNeeded : 0;
+    numentries = pcReturned ? *pcReturned : 0;
+
+    /*
+       W2k require the buffersize from EnumPortsW also for EnumPortsA.
+       We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
+     */
+    if (res)
+    {
+        /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
+        DWORD   entrysize = 0;
+        DWORD   index;
+        LPSTR   ptr;
+        LPPORT_INFO_2W pi2w;
+        LPPORT_INFO_2A pi2a;
+
+        needed = 0;
+        entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
+
+        /* First pass: calculate the size for all Entries */
+        pi2w = (LPPORT_INFO_2W) bufferW;
+        pi2a = (LPPORT_INFO_2A) pPorts;
+        index = 0;
+        while (index < numentries)
+        {
+            index++;
+            needed += entrysize;    /* PORT_INFO_?A */
+            TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
+
+            needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
+                                            NULL, 0, NULL, NULL);
+            if (Level > 1)
+            {
+                needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
+                                                NULL, 0, NULL, NULL);
+                needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
+                                                NULL, 0, NULL, NULL);
+            }
+            /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
+            pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
+            pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
+        }
+
+        /* check for errors and quit on failure */
+        if (cbBuf < needed)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            res = FALSE;
+            goto cleanup;
+        }
+        len = entrysize * numentries;       /* room for all PORT_INFO_?A */
+        ptr = (LPSTR) &pPorts[len];         /* room for strings */
+        cbBuf -= len ;                      /* free Bytes in the user-Buffer */
+        pi2w = (LPPORT_INFO_2W) bufferW;
+        pi2a = (LPPORT_INFO_2A) pPorts;
+        index = 0;
+        /* Second Pass: Fill the User Buffer (if we have one) */
+        while ((index < numentries) && pPorts)
+        {
+            index++;
+            TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
+            pi2a->pPortName = ptr;
+            len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
+                                            ptr, cbBuf , NULL, NULL);
+            ptr += len;
+            cbBuf -= len;
+            if (Level > 1)
+            {
+                pi2a->pMonitorName = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
+
+                pi2a->pDescription = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
+
+                pi2a->fPortType = pi2w->fPortType;
+                pi2a->Reserved = 0; /* documented: "must be zero" */
+
+            }
+            /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
+            pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
+            pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
+        }
+    }
+
+cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = (res) ? numentries : 0;
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, bufferW);
+
+    TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
+            (res), GetLastError(), needed, (res)? numentries : 0, numentries);
+
+    return (res);
 }
 
 BOOL WINAPI
@@ -113,15 +512,84 @@ EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded
 BOOL WINAPI
 SetPortA(PSTR pName, PSTR pPortName, DWORD dwLevel, PBYTE pPortInfo)
 {
+    LPWSTR NameW = NULL;
+    LPWSTR PortNameW = NULL;
+    PORT_INFO_3W  pi3W;
+    PORT_INFO_3A *pi3A;
+    DWORD len;
+    BOOL res;
+
     TRACE("SetPortA(%s, %s, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ( dwLevel != 3 )
+    {
+        ERR("Level = %d, unsupported!\n", dwLevel);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        NameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, NameW, len);
+    }
+
+    if (pPortName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
+        PortNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pPortName, -1, PortNameW, len);
+    }
+
+    if (pi3A->pszStatus)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, NULL, 0);
+        pi3W.pszStatus = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, pi3W.pszStatus, len);
+    }
+
+    pi3W.dwStatus   = pi3A->dwStatus;
+    pi3W.dwSeverity = pi3A->dwSeverity;
+
+    res = SetPortW( NameW, PortNameW, dwLevel, (PBYTE)&pi3W );
+
+    if (NameW) HeapFree(GetProcessHeap(), 0, NameW);
+    if (PortNameW) HeapFree(GetProcessHeap(), 0, PortNameW);
+    if (pi3W.pszStatus) HeapFree(GetProcessHeap(), 0, pi3W.pszStatus);
+
+    return res;
 }
 
 BOOL WINAPI
 SetPortW(PWSTR pName, PWSTR pPortName, DWORD dwLevel, PBYTE pPortInfo)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_PORT_CONTAINER PortInfoContainer;
+
     TRACE("SetPortW(%S, %S, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ( dwLevel != 3 )
+    {
+        ERR("Level = %d, unsupported!\n", dwLevel);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    PortInfoContainer.PortInfo.pPortInfo3 = (WINSPOOL_PORT_INFO_3*)pPortInfo;
+    PortInfoContainer.Level = dwLevel;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcSetPort(pName, pPortName, &PortInfoContainer);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
index e5a857b..05eb850 100644 (file)
 #define WIN32_NO_STATUS
 #include <windef.h>
 #include <winbase.h>
+#include <winuser.h>
 #include <wingdi.h>
 #include <winreg.h>
 #include <winspool.h>
 #include <winspool_c.h>
+#include <winsplp.h>
 #include <winddiui.h>
 #include <ndk/rtlfuncs.h>
 #include <strsafe.h>
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
 
+#define SPOOLER_HANDLE_SIG 'gg'
+
 // Structures
 /*
- * Describes a handle returned by OpenPrinterW.
+ * Describes a handle returned by AddPrinterW or OpenPrinterW.
  */
 typedef struct _SPOOLER_HANDLE
 {
+    DWORD_PTR Sig;
     BOOL bStartedDoc : 1;
+    BOOL bJob : 1;
+    BOOL bAnsi : 1;
+    BOOL bDocEvent : 1;
+    BOOL bTrayIcon : 1;
+    BOOL bNoColorProfile : 1;
+    BOOL bShared : 1;
+    BOOL bClosed : 1;
     DWORD dwJobID;
     HANDLE hPrinter;
     HANDLE hSPLFile;
+    DWORD cCount;
+    HANDLE hSpoolFileHandle;
+    DWORD dwOptions;
 }
 SPOOLER_HANDLE, *PSPOOLER_HANDLE;
 
 // main.c
 extern HANDLE hProcessHeap;
+extern CRITICAL_SECTION rtlCritSec;
 
 // utils.c
 DWORD UnicodeToAnsiInPlace(PWSTR pwszField);
+DWORD UnicodeToAnsiZZInPlace(PWSTR pwszzField);
+SECURITY_DESCRIPTOR * get_sd( SECURITY_DESCRIPTOR *sd, DWORD *size );
+LONG WINAPI IntProtectHandle(HANDLE,BOOL);
+BOOL WINAPI IntUnprotectHandle(HANDLE);
 
 // devmode.c
-extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW pDevModeOutput);
+extern void RosConvertAnsiDevModeToUnicodeDevmode(PDEVMODEA pDevModeInput, PDEVMODEW *pDevModeOutput);
 
 extern void RosConvertUnicodeDevModeToAnsiDevmode(PDEVMODEW pDevModeInput, PDEVMODEA pDevModeOutput);
 
+// RC
+
+#define IDS_CAPTION       10
+#define IDS_FILE_EXISTS   11
+#define IDS_CANNOT_OPEN   12
+#define FILENAME_DIALOG  100
+#define EDITBOX 201
+
+//
+// [MS-EMF] 2.2.27 UniversalFontId Object
+//
+typedef struct _UNIVERSAL_FONT_ID
+{
+    ULONG CheckSum;
+    ULONG Index;
+} UNIVERSAL_FONT_ID, *PUNIVERSAL_FONT_ID;
+
+BOOL WINAPI IsValidDevmodeNoSizeW(PDEVMODEW pDevmode);
+
+/* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
+   if passed a NULL string. This returns NULLs to the result.
+*/
+static inline PWSTR AsciiToUnicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
+{
+    if ( (src) )
+    {
+        RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
+        return usBufferPtr->Buffer;
+    }
+    usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
+    return NULL;
+}
+
 #endif
index aefa944..7e574e9 100644 (file)
@@ -7,6 +7,22 @@
 
 #include "precomp.h"
 
+LONG WINAPI
+AdvancedSetupDialog(HWND hWnd, INT Unknown, PDEVMODEA pDevModeInput, PDEVMODEA pDevModeOutput)
+{
+   HANDLE hPrinter;
+   LONG Ret = -1;
+
+    TRACE("AdvancedSetupDialog(%p, %d, %p, %p)\n", hWnd, Unknown, pDevModeOutput, pDevModeInput);
+
+    if ( OpenPrinterA( (LPSTR)pDevModeInput->dmDeviceName, &hPrinter, NULL ) )
+    {
+        Ret = AdvancedDocumentPropertiesA( hWnd, hPrinter, (PSTR)pDevModeInput->dmDeviceName, pDevModeOutput, pDevModeInput );
+        ClosePrinter(hPrinter);
+    }
+    return Ret;
+}
+
 LONG WINAPI
 AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, PSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
 {
@@ -26,17 +42,57 @@ AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVM
 DWORD WINAPI
 DeletePrinterDataA(HANDLE hPrinter, PSTR pValueName)
 {
+    LPWSTR  valuenameW = NULL;
+    INT     len;
+    DWORD   res;
+
     TRACE("DeletePrinterDataA(%p, %s)\n", hPrinter, pValueName);
-    UNIMPLEMENTED;
-    return ERROR_NOT_SUPPORTED;
+
+    if (pValueName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0);
+        valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len);
+    }
+
+    res = DeletePrinterDataW( hPrinter, valuenameW );
+
+    HeapFree(GetProcessHeap(), 0, valuenameW);
+
+    return res;
+
 }
 
 DWORD WINAPI
 DeletePrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PCSTR pValueName)
 {
+    LPWSTR  keynameW = NULL;
+    LPWSTR  valuenameW = NULL;
+    INT     len;
+    DWORD   res;
+
     TRACE("DeletePrinterDataExA(%p, %s, %s)\n", hPrinter, pKeyName, pValueName);
-    UNIMPLEMENTED;
-    return ERROR_NOT_SUPPORTED;
+
+    if (pKeyName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0);
+        keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len);
+    }
+
+    if (pValueName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pValueName, -1, NULL, 0);
+        valuenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pValueName, -1, valuenameW, len);
+    }
+
+    res = DeletePrinterDataExW( hPrinter, keynameW, valuenameW );
+
+    HeapFree(GetProcessHeap(), 0, keynameW);
+    HeapFree(GetProcessHeap(), 0, valuenameW);
+
+    return res;
 }
 
 DWORD WINAPI
@@ -58,9 +114,24 @@ DeletePrinterDataW(HANDLE hPrinter, PWSTR pValueName)
 DWORD WINAPI
 DeletePrinterKeyA(HANDLE hPrinter, PCSTR pKeyName)
 {
+    LPWSTR  keynameW = NULL;
+    INT     len;
+    DWORD   res;
+
     TRACE("DeletePrinterKeyA(%p, %s)\n", hPrinter, pKeyName);
-    UNIMPLEMENTED;
-    return ERROR_NOT_SUPPORTED;
+
+    if (pKeyName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, NULL, 0);
+        keynameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, keynameW, len);
+    }
+
+    res = DeletePrinterKeyW( hPrinter, keynameW );
+
+    HeapFree(GetProcessHeap(), 0, keynameW);
+
+    return res;
 }
 
 DWORD WINAPI
@@ -82,9 +153,142 @@ EnumPrinterDataA(HANDLE hPrinter, DWORD dwIndex, PSTR pValueName, DWORD cbValueN
 DWORD WINAPI
 EnumPrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
 {
+    INT            len;
+    LPWSTR  pKeyNameW;
+    DWORD   ret, dwIndex, dwBufSize;
+    HANDLE  hHeap;
+    LPSTR   pBuffer;
+
     TRACE("EnumPrinterDataExA(%p, %s, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
-    UNIMPLEMENTED;
-    return ERROR_NOT_SUPPORTED;
+
+    if (pKeyName == NULL || *pKeyName == 0)
+       return ERROR_INVALID_PARAMETER;
+
+    len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
+    if (len == 0)
+    {
+       ret = GetLastError ();
+       ERR ("MultiByteToWideChar failed with code %i\n", ret);
+       return ret;
+    }
+
+    hHeap = GetProcessHeap ();
+    if (hHeap == NULL)
+    {
+       ERR ("GetProcessHeap failed\n");
+       return ERROR_OUTOFMEMORY;
+    }
+
+    pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
+    if (pKeyNameW == NULL)
+    {
+       ERR ("Failed to allocate %i bytes from process heap\n",
+             (LONG)(len * sizeof (WCHAR)));
+       return ERROR_OUTOFMEMORY;
+    }
+
+    if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
+    {
+       ret = GetLastError ();
+       ERR ("MultiByteToWideChar failed with code %i\n", ret);
+       if (HeapFree (hHeap, 0, pKeyNameW) == 0)
+           WARN ("HeapFree failed with code %i\n", GetLastError ());
+       return ret;
+    }
+
+    ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
+
+    if (ret != ERROR_SUCCESS)
+    {
+       if (HeapFree (hHeap, 0, pKeyNameW) == 0)
+           WARN ("HeapFree failed with code %i\n", GetLastError ());
+       TRACE ("EnumPrinterDataExW returned %i\n", ret);
+       return ret;
+    }
+
+    if (HeapFree (hHeap, 0, pKeyNameW) == 0)
+    {
+       ret = GetLastError ();
+       ERR ("HeapFree failed with code %i\n", ret);
+       return ret;
+    }
+
+    if (*pnEnumValues == 0)    /* empty key */
+       return ERROR_SUCCESS;
+
+    dwBufSize = 0;
+    for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
+    {
+       PPRINTER_ENUM_VALUESW ppev =
+               &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
+
+       if (dwBufSize < ppev->cbValueName)
+           dwBufSize = ppev->cbValueName;
+
+       if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
+               ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
+           dwBufSize = ppev->cbData;
+    }
+
+    TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
+
+    pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
+    if (pBuffer == NULL)
+    {
+       ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
+       return ERROR_OUTOFMEMORY;
+    }
+
+    for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
+    {
+       PPRINTER_ENUM_VALUESW ppev =
+               &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
+
+       len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
+               ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
+               NULL);
+       if (len == 0)
+       {
+           ret = GetLastError ();
+           ERR ("WideCharToMultiByte failed with code %i\n", ret);
+           if (HeapFree (hHeap, 0, pBuffer) == 0)
+               WARN ("HeapFree failed with code %i\n", GetLastError ());
+           return ret;
+       }
+
+       memcpy (ppev->pValueName, pBuffer, len);
+
+       TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
+
+       if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
+               ppev->dwType != REG_MULTI_SZ)
+           continue;
+
+       len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
+               ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
+       if (len == 0)
+       {
+           ret = GetLastError ();
+           ERR ("WideCharToMultiByte failed with code %i\n", ret);
+           if (HeapFree (hHeap, 0, pBuffer) == 0)
+               WARN ("HeapFree failed with code %i\n", GetLastError ());
+           return ret;
+       }
+
+       memcpy (ppev->pData, pBuffer, len);
+
+       TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
+       TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
+    }
+
+    if (HeapFree (hHeap, 0, pBuffer) == 0)
+    {
+       ret = GetLastError ();
+       ERR ("HeapFree failed with code %i\n", ret);
+       return ret;
+    }
+
+    return ERROR_SUCCESS;
 }
 
 DWORD WINAPI
index 07ba18c..a30b611 100644 (file)
  */
 
 #include "precomp.h"
+#include <marshalling/printerdrivers.h>
+extern const WCHAR wszCurrentEnvironment[];
+
+static int multi_sz_lenA(const char *str)
+{
+    const char *ptr = str;
+    if(!str) return 0;
+    do
+    {
+        ptr += lstrlenA(ptr) + 1;
+    } while(*ptr);
+
+    return ptr - str + 1;
+}
+
+static int multi_sz_lenW(const WCHAR *str)
+{
+    const WCHAR *ptr = str;
+    if (!str) return 0;
+    do
+    {
+        ptr += lstrlenW(ptr) + 1;
+    } while (*ptr);
+
+    return (ptr - str + 1);
+}
 
 BOOL WINAPI
 AddPrinterDriverA(PSTR pName, DWORD Level, PBYTE pDriverInfo)
 {
     TRACE("AddPrinterDriverA(%s, %lu, %p)\n", pName, Level, pDriverInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+    return AddPrinterDriverExA(pName, Level, pDriverInfo, APD_COPY_NEW_FILES);
 }
 
 BOOL WINAPI
 AddPrinterDriverExA(PSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags)
 {
-    TRACE("AddPrinterDriverExA(%s, %lu, %p, %lu)\n", pName, Level, pDriverInfo, dwFileCopyFlags);
-    UNIMPLEMENTED;
-    return FALSE;
+    PDRIVER_INFO_8A  pdiA;
+    DRIVER_INFO_8W   diW;
+    LPWSTR  nameW = NULL;
+    DWORD   lenA;
+    DWORD   len;
+    BOOL    res = FALSE;
+
+    TRACE("AddPrinterDriverExA(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
+
+    pdiA = (DRIVER_INFO_8A *) pDriverInfo;
+    ZeroMemory(&diW, sizeof(diW));
+
+    if (Level < 2 || Level == 5 || Level == 7 || Level > 8)
+    {
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    if (pdiA == NULL)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* convert servername to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    /* common fields */
+    diW.cVersion = pdiA->cVersion;
+
+    if (pdiA->pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, NULL, 0);
+        diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pName, -1, diW.pName, len);
+    }
+
+    if (pdiA->pEnvironment)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, NULL, 0);
+        diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pEnvironment, -1, diW.pEnvironment, len);
+    }
+
+    if (pdiA->pDriverPath)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, NULL, 0);
+        diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pDriverPath, -1, diW.pDriverPath, len);
+    }
+
+    if (pdiA->pDataFile)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, NULL, 0);
+        diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pDataFile, -1, diW.pDataFile, len);
+    }
+
+    if (pdiA->pConfigFile)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, NULL, 0);
+        diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pConfigFile, -1, diW.pConfigFile, len);
+    }
+
+    if ((Level > 2) && pdiA->pHelpFile)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, NULL, 0);
+        diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pHelpFile, -1, diW.pHelpFile, len);
+    }
+
+    if ((Level > 2) && pdiA->pDependentFiles)
+    {
+        lenA = multi_sz_lenA(pdiA->pDependentFiles);
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, NULL, 0);
+        diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pDependentFiles, lenA, diW.pDependentFiles, len);
+    }
+
+    if ((Level > 2) && pdiA->pMonitorName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, NULL, 0);
+        diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pMonitorName, -1, diW.pMonitorName, len);
+    }
+
+    if ((Level > 2) && pdiA->pDefaultDataType)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, NULL, 0);
+        diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pDefaultDataType, -1, diW.pDefaultDataType, len);
+    }
+
+    if ((Level > 3) && pdiA->pszzPreviousNames)
+    {
+        lenA = multi_sz_lenA(pdiA->pszzPreviousNames);
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, NULL, 0);
+        diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
+    }
+
+    if (Level > 5)
+    {
+        diW.ftDriverDate = pdiA->ftDriverDate;
+        diW.dwlDriverVersion = pdiA->dwlDriverVersion;
+    }
+
+    if ((Level > 5) && pdiA->pszMfgName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, NULL, 0);
+        diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszMfgName, -1, diW.pszMfgName, len);
+    }
+
+    if ((Level > 5) && pdiA->pszOEMUrl)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, NULL, 0);
+        diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszOEMUrl, -1, diW.pszOEMUrl, len);
+    }
+
+    if ((Level > 5) && pdiA->pszHardwareID)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, NULL, 0);
+        diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszHardwareID, -1, diW.pszHardwareID, len);
+    }
+
+    if ((Level > 5) && pdiA->pszProvider)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, NULL, 0);
+        diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszProvider, -1, diW.pszProvider, len);
+    }
+
+    if ((Level > 7) && pdiA->pszPrintProcessor)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, NULL, 0);
+        diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
+    }
+
+    if ((Level > 7) && pdiA->pszVendorSetup)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, NULL, 0);
+        diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszVendorSetup, -1, diW.pszVendorSetup, len);
+    }
+
+    if ((Level > 7) && pdiA->pszzColorProfiles)
+    {
+        lenA = multi_sz_lenA(pdiA->pszzColorProfiles);
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, NULL, 0);
+        diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
+    }
+
+    if ((Level > 7) && pdiA->pszInfPath)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, NULL, 0);
+        diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszInfPath, -1, diW.pszInfPath, len);
+    }
+
+    if ((Level > 7) && pdiA->pszzCoreDriverDependencies)
+    {
+        lenA = multi_sz_lenA(pdiA->pszzCoreDriverDependencies);
+        len = MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, NULL, 0);
+        diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pdiA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
+    }
+
+    if (Level > 7)
+    {
+        diW.dwPrinterDriverAttributes = pdiA->dwPrinterDriverAttributes;
+        diW.ftMinInboxDriverVerDate = pdiA->ftMinInboxDriverVerDate;
+        diW.dwlMinInboxDriverVerVersion = pdiA->dwlMinInboxDriverVerVersion;
+    }
+
+    res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
+
+    TRACE("got %u with %u\n", res, GetLastError());
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, diW.pName);
+    HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
+    HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
+    HeapFree(GetProcessHeap(), 0, diW.pDataFile);
+    HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
+    HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
+    HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
+    HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
+    HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
+    HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
+    HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
+    HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
+    HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
+    HeapFree(GetProcessHeap(), 0, diW.pszProvider);
+    HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
+    HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
+    HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
+    HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
+    HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
+
+    TRACE("=> %u with %u\n", res, GetLastError());
+    return res;
 }
 
 BOOL WINAPI
 AddPrinterDriverExW(PWSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_DRIVER_INFO_8 * pdi = NULL;
+    WINSPOOL_DRIVER_CONTAINER pDriverContainer;
+
     TRACE("AddPrinterDriverExW(%S, %lu, %p, %lu)\n", pName, Level, pDriverInfo, dwFileCopyFlags);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    pDriverContainer.Level = Level;
+
+    switch (Level)
+    {
+        case 8:
+        {
+            PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo;
+            pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_8));
+
+            pdi->pPrintProcessor   = pdi8w->pszPrintProcessor;
+            pdi->pVendorSetup      = pdi8w->pszVendorSetup;
+
+            pdi->pszzColorProfiles = pdi8w->pszzColorProfiles;
+            pdi->cchColorProfiles = 0;
+            if ( pdi8w->pszzColorProfiles && *pdi8w->pszzColorProfiles )
+            {
+                pdi->cchColorProfiles = multi_sz_lenW( pdi8w->pszzColorProfiles );
+            }
+
+            pdi->pInfPath = pdi8w->pszInfPath;
+
+            pdi->pszzCoreDriverDependencies = pdi8w->pszzCoreDriverDependencies;
+            pdi->cchCoreDependencies = 0;
+            if ( pdi8w->pszzCoreDriverDependencies && *pdi8w->pszzCoreDriverDependencies )
+            {
+                pdi->cchCoreDependencies = multi_sz_lenW( pdi8w->pszzCoreDriverDependencies );
+            }
+
+            pdi->ftMinInboxDriverVerDate     = pdi8w->ftMinInboxDriverVerDate;
+            pdi->dwlMinInboxDriverVerVersion = pdi8w->dwlMinInboxDriverVerVersion;
+        }
+        case 6:
+        {
+            PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo;
+            if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_6));
+
+            pdi->pMfgName         = pdi6w->pszMfgName;
+            pdi->pOEMUrl          = pdi6w->pszOEMUrl;
+            pdi->pHardwareID      = pdi6w->pszHardwareID;
+            pdi->pProvider        = pdi6w->pszProvider;
+            pdi->ftDriverDate     = pdi6w->ftDriverDate;
+            pdi->dwlDriverVersion = pdi6w->dwlDriverVersion;
+        }
+        case 4:
+        {
+
+            PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo;
+            if ( pdi == NULL )  pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_4));
+
+            pdi->pszzPreviousNames = pdi4w->pszzPreviousNames;
+            pdi->cchPreviousNames  = 0;
+            if ( pdi4w->pDependentFiles && *pdi4w->pDependentFiles )
+            {
+               pdi->cchPreviousNames = multi_sz_lenW( pdi4w->pDependentFiles );
+            }
+        }
+        case 3:
+        {
+            PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo;
+            if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_3));
+
+            pdi->pHelpFile        = pdi3w->pHelpFile;
+            pdi->pDependentFiles  = pdi3w->pDependentFiles;
+            pdi->pMonitorName     = pdi3w->pMonitorName;
+            pdi->pDefaultDataType = pdi3w->pDefaultDataType;
+
+            pdi->pDependentFiles = pdi3w->pDependentFiles;
+            pdi->cchDependentFiles = 0;
+            if ( pdi3w->pDependentFiles && *pdi3w->pDependentFiles )
+            {
+                pdi->cchDependentFiles = multi_sz_lenW( pdi3w->pDependentFiles );
+            }
+        }
+        case 2:
+        {
+            PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo;
+            if ( pdi == NULL ) pdi = HeapAlloc(hProcessHeap, 0, sizeof(WINSPOOL_DRIVER_INFO_2));
+
+            pdi->pName = pdi2w->pName;
+
+            pdi->pEnvironment = pdi2w->pEnvironment;
+            if ( !pdi2w->pEnvironment || !*pdi2w->pEnvironment )
+            {
+                pdi2w->pEnvironment = (PWSTR)wszCurrentEnvironment;
+            }
+
+            pdi->pDriverPath = pdi2w->pDriverPath;
+            pdi->pDataFile   = pdi2w->pDataFile;
+            pdi->pConfigFile = pdi2w->pConfigFile;
+        }
+            break;
+
+        default:
+            SetLastError(ERROR_INVALID_LEVEL);
+            return FALSE;
+    }
+
+    pDriverContainer.DriverInfo.Level8 = pdi;
+
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddPrinterDriverEx( pName, &pDriverContainer, dwFileCopyFlags );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcAddPrinterDriverEx failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    if ( pdi ) HeapFree( GetProcessHeap(), 0, pdi );
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 AddPrinterDriverW(PWSTR pName, DWORD Level, PBYTE pDriverInfo)
 {
     TRACE("AddPrinterDriverW(%S, %lu, %p)\n", pName, Level, pDriverInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+    return AddPrinterDriverExW(pName, Level, pDriverInfo, APD_COPY_NEW_FILES);
 }
 
 BOOL WINAPI
 DeletePrinterDriverA(PSTR pName, PSTR pEnvironment, PSTR pDriverName)
 {
     TRACE("DeletePrinterDriverA(%s, %s, %s)\n", pName, pEnvironment, pDriverName);
-    UNIMPLEMENTED;
-    return FALSE;
+    return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
 }
 
 BOOL WINAPI
 DeletePrinterDriverExA(PSTR pName, PSTR pEnvironment, PSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
 {
+    UNICODE_STRING NameW, EnvW, DriverW;
+    BOOL ret;
+
     TRACE("DeletePrinterDriverExA(%s, %s, %s, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    AsciiToUnicode(&NameW, pName);
+    AsciiToUnicode(&EnvW, pEnvironment);
+    AsciiToUnicode(&DriverW, pDriverName);
+
+    ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
+
+    RtlFreeUnicodeString(&DriverW);
+    RtlFreeUnicodeString(&EnvW);
+    RtlFreeUnicodeString(&NameW);
+
+    return ret;
 }
 
 BOOL WINAPI
 DeletePrinterDriverExW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
 {
+    DWORD dwErrorCode;
+
     TRACE("DeletePrinterDriverExW(%S, %S, %S, %lu, %lu)\n", pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ( !pDriverName || !*pDriverName )
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if ( !pEnvironment || !*pEnvironment )
+    {
+        pEnvironment = (PWSTR)wszCurrentEnvironment;
+    }
+
+    // Do the RPC call.
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeletePrinterDriverEx(pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcDeletePrinterDriverEx failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+
 }
 
 BOOL WINAPI
 DeletePrinterDriverW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName)
 {
     TRACE("DeletePrinterDriverW(%S, %S, %S)\n", pName, pEnvironment, pDriverName);
-    UNIMPLEMENTED;
-    return FALSE;
+    return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
 }
 
 BOOL WINAPI
 EnumPrinterDriversA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    BOOL ret;
+    DWORD dwErrorCode, i;
+    UNICODE_STRING pNameW, pEnvironmentW;
+    PWSTR pwstrNameW, pwstrEnvironmentW;
+    PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo;
+    PDRIVER_INFO_8W pdi8w = (PDRIVER_INFO_8W)pDriverInfo;
+
     TRACE("EnumPrinterDriversA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    pwstrNameW = AsciiToUnicode(&pNameW, pName);
+    pwstrEnvironmentW = AsciiToUnicode(&pEnvironmentW, pEnvironment);
+
+    ret = EnumPrinterDriversW( pwstrNameW, pwstrEnvironmentW, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned );
+
+    if (ret)
+    {
+        for ( i = 0; i < *pcReturned; i++ )
+        {
+            switch (Level)
+            {
+                case 1:
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi1w[i].pName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    break;
+                }
+                case 8:
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszPrintProcessor);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszVendorSetup);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzColorProfiles);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszInfPath);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                    dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzCoreDriverDependencies);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+                case 6:
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszMfgName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszOEMUrl);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszHardwareID);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pszProvider);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+                case 4:
+                {
+                    dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pszzPreviousNames);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+                case 3:
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pHelpFile);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w[i].pDependentFiles);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pMonitorName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDefaultDataType);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+                case 2:
+                case 5:
+                {
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pName);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pEnvironment);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDriverPath);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pDataFile);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+
+                    dwErrorCode = UnicodeToAnsiInPlace(pdi8w[i].pConfigFile);
+                    if (dwErrorCode != ERROR_SUCCESS)
+                    {
+                        goto Cleanup;
+                    }
+                }
+            }
+        }
+    }
+Cleanup:
+    RtlFreeUnicodeString(&pNameW);
+    RtlFreeUnicodeString(&pEnvironmentW);
+
+    return ret;
 }
 
 BOOL WINAPI
 EnumPrinterDriversW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
+    DWORD dwErrorCode;
+
     TRACE("EnumPrinterDriversW(%S, %S, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Dismiss invalid levels already at this point.
+    if (Level > 8 || Level == 7 || Level < 1)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if ( !pEnvironment || !*pEnvironment )
+    {
+        pEnvironment = (PWSTR)wszCurrentEnvironment;
+    }
+
+    if (cbBuf && pDriverInfo)
+        ZeroMemory(pDriverInfo, cbBuf);
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcEnumPrinterDrivers( pName, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, pcReturned );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcEnumPrinterDrivers failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    if (dwErrorCode == ERROR_SUCCESS)
+    {
+        // Replace relative offset addresses in the output by absolute pointers.
+        ASSERT(Level <= 6 || Level == 8);
+        MarshallUpStructuresArray(cbBuf, pDriverInfo, *pcReturned, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
+    }
+
+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_8W pdi8w = (PDRIVER_INFO_8W)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 & 8.
+    if (Level <  1 || Level == 7 || Level > 8)
+    {
+        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 8:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszPrintProcessor);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszVendorSetup);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzColorProfiles);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszInfPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+            dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzCoreDriverDependencies);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+        case 6:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszMfgName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszOEMUrl);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszHardwareID);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pszProvider);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+        case 4:
+        {
+            dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pszzPreviousNames);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+        case 3:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pHelpFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiZZInPlace(pdi8w->pDependentFiles);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pMonitorName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDefaultDataType);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+        case 2:
+        case 5:
+        {
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pName);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pEnvironment);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDriverPath);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pDataFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+
+            dwErrorCode = UnicodeToAnsiInPlace(pdi8w->pConfigFile);
+            if (dwErrorCode != ERROR_SUCCESS)
+            {
+                goto Cleanup;
+            }
+        }
+    }
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    if (pwszEnvironment)
+    {
+        HeapFree(hProcessHeap, 0, pwszEnvironment);
+    }
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
+{
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+    TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        goto Cleanup;
+    }
+
+    // Dismiss invalid levels already at this point.
+    if (Level > 8 || Level == 7 || Level < 1)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if ( !pEnvironment || !*pEnvironment )
+    {
+        pEnvironment = (PWSTR)wszCurrentEnvironment;
+    }
+
+    if (cbBuf && pDriverInfo)
+        ZeroMemory(pDriverInfo, cbBuf);
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        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 <= 6 || Level == 8);
+        MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
+    }
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 GetPrinterDriverDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
 {
-    TRACE("GetPrinterDriverDirectoryA(%s, %s, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
-    return FALSE;
+    UNICODE_STRING nameW, environmentW;
+    BOOL ret;
+    DWORD pcbNeededW;
+    INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
+    WCHAR *driverDirectoryW = NULL;
+
+    TRACE("GetPrinterDriverDirectoryA(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
+
+    if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
+
+    if (pName)
+    {
+        RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
+    }
+    else
+    {
+        nameW.Buffer = NULL;
+    }
+    if (pEnvironment)
+    {
+        RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
+    }
+    else
+    {
+        environmentW.Buffer = NULL;
+    }
+
+    ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level, (LPBYTE)driverDirectoryW, len, &pcbNeededW );
+
+    if (ret)
+    {
+        DWORD needed =  WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1, (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
+
+        if ( pcbNeeded )
+            *pcbNeeded = needed;
+
+        ret = needed <= cbBuf;
+    }
+    else
+    {
+        if (pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
+    }
+
+    TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
+
+    HeapFree( GetProcessHeap(), 0, driverDirectoryW );
+    RtlFreeUnicodeString(&environmentW);
+    RtlFreeUnicodeString(&nameW);
+
+    return ret;
 }
 
 BOOL WINAPI
 GetPrinterDriverDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
 {
+    DWORD dwErrorCode;
+
     TRACE("GetPrinterDriverDirectoryW(%S, %S, %lu, %p, %lu, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ( !pEnvironment || !*pEnvironment )
+    {
+        pEnvironment = (PWSTR)wszCurrentEnvironment;
+    }
+
+    // Do the RPC call.
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcGetPrinterDriverDirectory(pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcGetPrinterDriverDirectory failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
index 249d412..12c299a 100644 (file)
@@ -7,9 +7,53 @@
 
 #include "precomp.h"
 #include <marshalling/printers.h>
-#include <marshalling/printerdrivers.h>
+//#include <marshalling/printerdrivers.h>
 #include <strsafe.h>
 
+extern HINSTANCE hinstWinSpool;
+//
+// See winddiui.h, ReactOS version is limited.
+// Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL.
+//
+typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW);
+static DEVICECAPABILITIES fpDeviceCapabilities;
+
+typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
+static DEVICEPROPERTYSHEETS fpDevicePropertySheets;
+typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
+static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets;
+
+typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD);
+static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW;
+
+typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*);
+static  QUERYCOLORPROFILE fpQueryColorProfile;
+
+typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM);
+static SPOOLERPRINTEREVENT fpPrinterEvent;
+
+typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*);
+static DEVQUERYPRINT fpDevQueryPrint;
+
+typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO);
+static DEVQUERYPRINTEX fpDevQueryPrintEx;
+
+//
+//  PrintUI.dll
+//
+LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size );
+typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD);
+static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName;
+
+//
+//  CompstUI User Data
+//
+typedef struct _COMPUI_USERDATA
+{
+  HMODULE hModule;
+  LPWSTR pszPrinterName;
+} COMPUI_USERDATA, *PCOMPUI_USERDATA;
+
 // Local Constants
 
 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
@@ -110,25 +154,257 @@ _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
 BOOL WINAPI
 AbortPrinter(HANDLE hPrinter)
 {
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("AbortPrinter(%p)\n", hPrinter);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        goto Cleanup;
+    }
+
+    pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE;
+
+    if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob )
+    {
+        // Close any open file handle.
+        CloseHandle( pHandle->hSPLFile );
+        pHandle->hSPLFile = INVALID_HANDLE_VALUE;
+
+        SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE );
+
+        return ScheduleJob( hPrinter, pHandle->dwJobID );
+    }
+
+    // Do the RPC call.
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 HANDLE WINAPI
 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
 {
-    TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter);
-    UNIMPLEMENTED;
-    return NULL;
+    UNICODE_STRING pNameW, usBuffer;
+    PWSTR pwstrNameW;
+    PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter;
+    PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter;
+    HANDLE ret = NULL;
+    PWSTR pwszPrinterName = NULL;
+    PWSTR pwszServerName = NULL;
+    PWSTR pwszShareName = NULL;
+    PWSTR pwszPortName = NULL;
+    PWSTR pwszDriverName = NULL;
+    PWSTR pwszComment = NULL;
+    PWSTR pwszLocation = NULL;
+    PWSTR pwszSepFile = NULL;
+    PWSTR pwszPrintProcessor = NULL;
+    PWSTR pwszDatatype = NULL;
+    PWSTR pwszParameters = NULL;
+    PDEVMODEW pdmw = NULL;
+
+    TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
+
+    if(Level != 2)
+    {
+        ERR("Level = %d, unsupported!\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+        return NULL;
+    }
+
+    pwstrNameW = AsciiToUnicode(&pNameW,pName);
+
+    if (ppi2a->pShareName)
+    {
+        pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
+        if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
+    }
+    if (ppi2a->pPortName)
+    {
+        pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
+        if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
+    }
+    if (ppi2a->pDriverName)
+    {
+        pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
+        if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
+    }
+    if (ppi2a->pComment)
+    {
+        pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
+        if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
+    }
+    if (ppi2a->pLocation)
+    {
+        pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
+        if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
+    }
+    if (ppi2a->pSepFile)
+    {
+        pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
+        if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
+    }
+    if (ppi2a->pServerName)
+    {
+        pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
+        if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
+    }
+    if (ppi2a->pDatatype)
+    {
+        pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
+        if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
+    }
+    if (ppi2a->pParameters)
+    {
+        pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
+        if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
+    }
+    if ( ppi2a->pDevMode )
+    {
+        RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
+        ppi2w->pDevMode = pdmw;
+    }
+    if (ppi2a->pServerName)
+    {
+        pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
+        if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
+    }
+    if (ppi2a->pPrinterName)
+    {
+        pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
+        if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
+    }
+
+    ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w);
+
+Cleanup:
+    if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
+    if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
+    if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
+    if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
+    if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
+    if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
+    if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
+    if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
+    if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
+    if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
+    if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
+    if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
+
+    RtlFreeUnicodeString(&pNameW);
+    return ret;
 }
 
 HANDLE WINAPI
 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_PRINTER_CONTAINER PrinterContainer;
+    WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
+    WINSPOOL_SECURITY_CONTAINER SecurityContainer;
+    SECURITY_DESCRIPTOR *sd = NULL;
+    DWORD size;
+    HANDLE hPrinter = NULL, hHandle = NULL;
+    PSPOOLER_HANDLE pHandle = NULL;
+
     TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
-    UNIMPLEMENTED;
-    return NULL;
+
+    DevModeContainer.cbBuf = 0;
+    DevModeContainer.pDevMode = NULL;
+
+    SecurityContainer.cbBuf = 0;
+    SecurityContainer.pSecurity = NULL;
+
+    if ( Level != 2 )
+    {
+        FIXME( "Unsupported level %d\n", Level );
+        SetLastError( ERROR_INVALID_LEVEL );
+        return hHandle;
+    }
+    else
+    {
+        PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
+        if ( pi2w )
+        {
+            if ( pi2w->pDevMode )
+            {
+                if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
+                {
+                    DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
+                    DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
+                }
+            }
+
+            if ( pi2w->pSecurityDescriptor )
+            {
+                sd = get_sd( pi2w->pSecurityDescriptor, &size );
+                if ( sd )
+                {
+                    SecurityContainer.cbBuf = size;
+                    SecurityContainer.pSecurity = (PBYTE)sd;
+                }
+            }
+        }
+        else
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return hHandle;
+        }
+    }
+
+    PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
+    PrinterContainer.Level = Level;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    if (hPrinter)
+    {
+        // Create a new SPOOLER_HANDLE structure.
+        pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
+        if (!pHandle)
+        {
+            dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+            ERR("HeapAlloc failed!\n");
+            _RpcDeletePrinter(hPrinter);
+            _RpcClosePrinter(hPrinter);
+            goto Cleanup;
+        }
+
+        pHandle->Sig = SPOOLER_HANDLE_SIG;
+        pHandle->hPrinter = hPrinter;
+        pHandle->hSPLFile = INVALID_HANDLE_VALUE;
+        pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
+        hHandle = (HANDLE)pHandle;
+    }
+
+Cleanup:
+    if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
+
+    SetLastError(dwErrorCode);
+    return hHandle;
 }
 
 BOOL WINAPI
@@ -140,7 +416,7 @@ ClosePrinter(HANDLE hPrinter)
     TRACE("ClosePrinter(%p)\n", hPrinter);
 
     // Sanity checks.
-    if (!pHandle)
+    if ( IntProtectHandle( hPrinter, TRUE ) )
     {
         dwErrorCode = ERROR_INVALID_HANDLE;
         goto Cleanup;
@@ -162,6 +438,8 @@ ClosePrinter(HANDLE hPrinter)
     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
         CloseHandle(pHandle->hSPLFile);
 
+    pHandle->Sig = -1;
+
     // Free the memory for the handle.
     HeapFree(hProcessHeap, 0, pHandle);
 
@@ -173,25 +451,207 @@ Cleanup:
 BOOL WINAPI
 DeletePrinter(HANDLE hPrinter)
 {
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
     TRACE("DeletePrinter(%p)\n", hPrinter);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    // Sanity checks.
+    if (!pHandle)
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+        goto Cleanup;
+    }
+
+    // Do the RPC call.
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+//
+// Based on GDI32:printdrv.c:IntGetPrinterDriver.
+//
+HMODULE
+WINAPI
+LoadPrinterDriver( HANDLE hspool )
+{
+    INT iTries = 0;
+    DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings.
+    PDRIVER_INFO_5W pdi = NULL;
+    HMODULE hLibrary = NULL;
+
+    do
+    {
+        ++iTries;
+
+        pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size);
+
+        if ( !pdi )
+            break;
+
+        if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) )
+        {
+            TRACE("Level 5 Size %d\n",Size);
+
+            // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll!
+
+            hLibrary = LoadLibrary(pdi->pConfigFile);
+
+            FIXME("IGPD : Get Printer Driver %S\n",pdi->pConfigFile);
+
+            RtlFreeHeap( GetProcessHeap(), 0, pdi);
+            return hLibrary;
+        }
+
+        if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
+            ++iTries;
+
+        RtlFreeHeap( GetProcessHeap(), 0, pdi);
+     }
+     while ( iTries < 2 );
+     ERR("No Printer Driver Error %d\n",GetLastError());
+     return NULL;
 }
 
 DWORD WINAPI
 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
 {
-    TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
-    UNIMPLEMENTED;
-    return 0;
+    PWSTR pwszDeviceName = NULL;
+    PDEVMODEW pdmwInput = NULL;
+    BOOL bReturnValue = GDI_ERROR;
+    DWORD cch;
+
+    FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
+
+    if (pDevice)
+    {
+        // Convert pName to a Unicode string pwszDeviceName.
+        cch = strlen(pDevice);
+
+        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, pDevice, -1, pwszDeviceName, cch + 1);
+    }
+
+    if (pDevMode)
+    {
+        RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput);
+    }
+
+    // pPort is ignored so no need to pass it.
+    bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput );
+
+Cleanup:
+    if(pwszDeviceName)
+        HeapFree(hProcessHeap, 0, pwszDeviceName);
+
+    if (pdmwInput)
+        HeapFree(hProcessHeap, 0, pdmwInput);
+
+    return bReturnValue;
 }
 
 DWORD WINAPI
 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
 {
-    TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
-    UNIMPLEMENTED;
-    return 0;
+    HANDLE hPrinter;
+    HMODULE hLibrary;
+    DWORD iDevCap = GDI_ERROR;
+
+    FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
+
+    if ( pDevMode )
+    {
+        if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) )
+        {
+            ERR("DeviceCapabilitiesW : Devode Invalid");
+            return -1;
+        }
+    }
+
+    if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) )
+    {
+        hLibrary = LoadPrinterDriver( hPrinter );
+
+        if ( hLibrary )
+        {
+            fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" );
+
+            if ( fpDeviceCapabilities )
+            {
+                iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode );
+            }
+
+            FreeLibrary(hLibrary);
+        }
+
+        ClosePrinter( hPrinter );
+    }
+
+    return iDevCap;
+}
+
+BOOL
+WINAPI
+DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID)
+{
+    HMODULE hLibrary;
+    BOOL Ret = FALSE;
+
+    hLibrary = LoadPrinterDriver( hPrinter );
+
+    if ( hLibrary )
+    {
+        fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" );
+
+        if ( fpDevQueryPrint )
+        {
+            Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID );
+        }
+
+        FreeLibrary(hLibrary);
+    }
+    return Ret;
+}
+
+BOOL WINAPI
+DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo )
+{
+    HMODULE hLibrary;
+    BOOL Ret = FALSE;
+
+    hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter );
+
+    if ( hLibrary )
+    {
+        fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" );
+
+        if ( fpDevQueryPrintEx )
+        {
+            Ret = fpDevQueryPrintEx( pDQPInfo );
+        }
+
+        FreeLibrary(hLibrary);
+    }
+    return Ret;
 }
 
 INT WINAPI
@@ -211,7 +671,7 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe
     BOOL bReturnValue = -1;
     DWORD cch;
 
-    TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
+    FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
 
     if (pDeviceName)
     {
@@ -232,30 +692,32 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe
     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);
+        RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput);
     }
 
     if (pDevModeOutput)
     {
         // Create working buffer for output from DocumentPropertiesW.
-        pdmwOutput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW));
-        if (!pdmwOutput)
+
+        // Do it RIGHT! Get the F...ing Size!
+        LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 );
+
+        if ( Size < 0 )
         {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            ERR("HeapAlloc failed!\n");
+            goto Cleanup;
+        }
+
+        pdmwOutput = HeapAlloc(hProcessHeap, 0, Size);
+        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);
+    FIXME("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue);
 
     if (pwszDeviceName)
     {
@@ -264,7 +726,7 @@ DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDe
 
     if (bReturnValue < 0)
     {
-        TRACE("DocumentPropertiesW failed!\n");
+        FIXME("DocumentPropertiesW failed!\n");
         goto Cleanup;
     }
 
@@ -286,7 +748,7 @@ Cleanup:
     return bReturnValue;
 }
 
-static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
+PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
 {
     PRINTER_INFO_9W *pi9 = NULL;
     DWORD needed = 0;
@@ -307,65 +769,470 @@ static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
     return NULL;
 }
 
-LONG WINAPI
-DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
+BOOL
+FASTCALL
+CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter )
 {
-    HANDLE hUseHandle = NULL;
-    PRINTER_INFO_9W *pi9 = NULL;
-    LONG Result = -1, Length;
+    PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) );
 
-    TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
-    if (hPrinter)
+    *puserdata = (ULONG_PTR)pcui_ud;
+    FIXME("CreateUIUserData\n");
+    if ( pcui_ud )
     {
-        hUseHandle = hPrinter;
+        pcui_ud->hModule = LoadPrinterDriver( hPrinter );
+
+        if ( !pcui_ud->hModule )
+        {
+            DllFreeSplMem( pcui_ud );
+            *puserdata = 0;
+        }
     }
-    else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
+    return *puserdata != 0;
+}
+
+VOID
+FASTCALL
+DestroyUIUserData( ULONG_PTR *puserdata )
+{
+    PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata;
+    FIXME("DestroyUIUserData\n");
+    if ( pcui_ud )
     {
-        ERR("No handle, and no usable printer name passed in\n");
-        return -1;
+        if ( pcui_ud->hModule )
+        {
+            FreeLibrary( pcui_ud->hModule );
+            pcui_ud->hModule = NULL;
+        }
+
+        if ( pcui_ud->pszPrinterName )
+        {
+            DllFreeSplMem( pcui_ud->pszPrinterName );
+            pcui_ud->pszPrinterName = NULL;
+        }
+
+        DllFreeSplMem( pcui_ud );
+        *puserdata = 0;
+    }
+}
+
+BOOL
+FASTCALL
+IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr )
+{
+    PRINTER_INFO_2W *pi2 = NULL;
+    DWORD needed = 0;
+    BOOL res;
+
+    if (!(pdphdr->fMode & DM_OUT_BUFFER) ||
+         pdphdr->fMode & DM_NOPERMISSION || // Do not allow the user to modify properties on the displayed property sheet pages.
+        !pdphdr->pdmOut )
+    {
+        return FALSE;
+    }
+
+    res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed);
+    if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        pi2 = HeapAlloc(hProcessHeap, 0, needed);
+        res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed);
+    }
+
+    if (res)
+    {
+        FIXME("IFUDMN : Get Printer Name %S\n",pi2->pPrinterName);
+        StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName );
+        pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0;
+    }
+    else
+    {
+        ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError());
+    }
+    HeapFree(hProcessHeap, 0, pi2);
+    return res;
+}
+
+LONG
+WINAPI
+CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName )
+{
+    LONG Result = 0;
+    DWORD Size = 0;
+    HMODULE hLibrary = NULL;
+
+    hLibrary = LoadLibraryA( "printui.dll" );
+
+    if ( hLibrary )
+    {
+        fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" );
+
+        if ( fpConstructPrinterFriendlyName )
+        {
+             if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) )
+             {
+                 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
+                 {
+                     PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) );
+
+                     pcui_ud->pszPrinterName = pwstr;
+
+                     if ( pwstr )
+                         Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size );
+                 }
+             }
+        }
+        FreeLibrary( hLibrary );
+    }
+
+    if ( !Result )
+    {
+        DllFreeSplMem( pcui_ud->pszPrinterName );
+        pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName );
     }
 
-    pi9 = get_devmodeW(hUseHandle);
+    return Result;
+}
+
+//
+// Tested with XP CompstUI as a callback and works. Fails perfectly.
+//
+LONG
+WINAPI
+DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
+{
+    LONG Result = -1;
+    PDOCUMENTPROPERTYHEADER pdphdr;
+
+    FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
 
-    if (pi9)
+    // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL,
+    // this function should return the size, in bytes, of the printer's DEVMODEW structure.
+    if ( !pCPSUIInfo && lparam )
     {
-        Length = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
-        // See wineps.drv PSDRV_ExtDeviceMode
-        if (fMode)
+        pdphdr = (PDOCUMENTPROPERTYHEADER)lparam;
+
+        if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) &&
+            !(pdphdr->fMode & DM_PROMPT) )
         {
-            Result = 1; /* IDOK */
+            HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter );
 
-            if (fMode & DM_IN_BUFFER)
+            if ( hLibrary )
             {
-                FIXME("Merge pDevModeInput with pi9, write back to driver!\n");
-                // See wineps.drv PSDRV_MergeDevmodes
-            }
+                fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" );
+
+                if ( fpDocumentPropertySheets )
+                {
+                    Result = fpDocumentPropertySheets( pCPSUIInfo, lparam );
+                }
+                else
+                {
+                    //
+                    // ReactOS backup!!! Currently no supporting UI driver.
+                    //
+                    PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter );
+                    if ( pi9 )
+                    {
+                        Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
+                        FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result);
+                        HeapFree(hProcessHeap, 0, pi9);
+                    }
+                }
+
+                FreeLibrary(hLibrary);
 
-            if (fMode & DM_IN_PROMPT)
+                if ( Result > 0 )
+                {
+                    IntFixUpDevModeNames( pdphdr );
+                }
+
+                return Result;
+            }
+            else
             {
-                FIXME("Show property sheet!\n");
-                Result = 2; /* IDCANCEL */
+                SetLastError(ERROR_INVALID_HANDLE);
             }
+        }
+        else
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+        }
+        return Result;
+    }
+
+    Result = 0;
+
+    if ( pCPSUIInfo )
+    {
+        PSETRESULT_INFO psri;
+        PPROPSHEETUI_INFO_HEADER ppsuiihdr;
+        PCOMPUI_USERDATA pcui_ud;
+        pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit;
 
-            if (fMode & (DM_OUT_BUFFER | DM_OUT_DEFAULT))
+        if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) )
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return Result;
+        }
+
+        switch ( pCPSUIInfo->Reason )
+        {
+            case PROPSHEETUI_REASON_INIT:
             {
-                if (pDevModeOutput)
+                FIXME("DocPS : PROPSHEETUI_REASON_INIT\n");
+                if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
+                {
+                    pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
+
+                    fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" );
+
+                    if ( fpDocumentPropertySheets )
+                    {
+                        pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
+                                                     CPSFUNC_SET_FUSION_CONTEXT,
+                                                     -3,  // What type of handle is this?
+                                                     0 ); // Not used, must be zero.
+
+                        Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
+                                                              CPSFUNC_ADD_PFNPROPSHEETUIW,
+                                                             (LPARAM)fpDocumentPropertySheets,
+                                                              pCPSUIInfo->lParamInit );
+                        break;
+                    }
+                    FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n");
+                    DestroyUIUserData( &pCPSUIInfo->UserData );
+                }
+            }
+                break;
+
+            case PROPSHEETUI_REASON_GET_INFO_HEADER:
+                FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
+
+                ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
+
+                pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
+
+                CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
+
+                ppsuiihdr->Flags  = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
+                ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
+                ppsuiihdr->hInst  = hinstWinSpool;
+                ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
+
+                Result = CPSUI_OK;
+                break;
+
+            case PROPSHEETUI_REASON_DESTROY:
+                FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n");
+                DestroyUIUserData( &pCPSUIInfo->UserData );
+                Result = CPSUI_OK;
+                break;
+
+            case PROPSHEETUI_REASON_SET_RESULT:
+                FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n");
+
+                psri = (PSETRESULT_INFO)lparam;
+
+                pCPSUIInfo->Result = psri->Result;
+                if ( pCPSUIInfo->Result > 0 )
                 {
-                    memcpy(pDevModeOutput, pi9->pDevMode, pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra);
+                    IntFixUpDevModeNames( pdphdr );
                 }
-                else
+                Result = CPSUI_OK;
+                break;
+        }
+    }
+    return Result;
+}
+
+LONG
+WINAPI
+DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
+{
+    LONG Result = 0;
+    PDEVICEPROPERTYHEADER pdphdr;
+
+    FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
+
+    if ( pCPSUIInfo )
+    {
+        PSETRESULT_INFO psri;
+        PPROPSHEETUI_INFO_HEADER ppsuiihdr;
+        PCOMPUI_USERDATA pcui_ud;
+        pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit;
+
+        if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) )
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return Result;
+        }
+
+        switch ( pCPSUIInfo->Reason )
+        {
+            case PROPSHEETUI_REASON_INIT:
+            {
+                FIXME("DevPS : PROPSHEETUI_REASON_INIT\n");
+                if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
                 {
-                    ERR("No pDevModeOutput\n");
-                    Result = -1;
+                    pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
+
+                    fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" );
+
+                    if ( fpDevicePropertySheets )
+                    {
+                        pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
+                                                     CPSFUNC_SET_FUSION_CONTEXT,
+                                                     -3,  // What type of handle is this?
+                                                     0 ); // Not used, must be zero.
+
+                        Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
+                                                              CPSFUNC_ADD_PFNPROPSHEETUIW,
+                                                             (LPARAM)fpDevicePropertySheets,
+                                                              pCPSUIInfo->lParamInit );
+                        break;
+                    }
+                    FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n");
+                    DestroyUIUserData( &pCPSUIInfo->UserData );
                 }
             }
+                break;
+
+            case PROPSHEETUI_REASON_GET_INFO_HEADER:
+                FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
+
+                ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
+
+                pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
+
+                CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
+
+                ppsuiihdr->Flags  = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
+                ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
+                ppsuiihdr->hInst  = hinstWinSpool;
+                ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
+
+                Result = CPSUI_OK;
+                break;
+
+            case PROPSHEETUI_REASON_DESTROY:
+                FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n");
+                DestroyUIUserData( &pCPSUIInfo->UserData );
+                Result = CPSUI_OK;
+                break;
+
+            case PROPSHEETUI_REASON_SET_RESULT:
+                FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n");
+                psri = (PSETRESULT_INFO)lparam;
+                pCPSUIInfo->Result = psri->Result;
+                Result = CPSUI_OK;
+                break;
         }
-        else
+    }
+    return Result;
+}
+
+LONG
+WINAPI
+CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
+{
+    HMODULE hLibrary = NULL;
+    LONG Ret = ERR_CPSUI_GETLASTERROR;
+
+    FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
+
+    if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) )
+    {
+        fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW");
+
+        if ( fpCommonPropertySheetUIW )
+        {
+            Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult );
+        }
+
+        FreeLibrary(hLibrary);
+    }
+    return Ret;
+}
+
+LONG WINAPI
+DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
+{
+    HANDLE hUseHandle = NULL;
+    DOCUMENTPROPERTYHEADER docprophdr;
+    LONG Result = IDOK;
+
+    FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
+
+    if (hPrinter)
+    {
+        hUseHandle = hPrinter;
+    }
+    else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
+    {
+        ERR("No handle, and no usable printer name passed in\n");
+        return -1;
+    }
+
+    if ( !(fMode & DM_IN_BUFFER ) ||
+         ( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) )
+    {
+        pDevModeInput = NULL;
+        fMode &= ~DM_IN_BUFFER;
+    }
+
+    docprophdr.cbSize         = sizeof(DOCUMENTPROPERTYHEADER);
+    docprophdr.Reserved       = 0;
+    docprophdr.hPrinter       = hUseHandle;
+    docprophdr.pszPrinterName = pDeviceName;
+    docprophdr.cbOut          = 0;
+
+    if ( pDevModeOutput )
+    {
+        docprophdr.pdmIn  = NULL;
+        docprophdr.pdmOut = NULL;
+        docprophdr.fMode  = 0;
+        FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput);
+        docprophdr.cbOut  = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
+    }
+
+    docprophdr.pdmIn  = pDevModeInput;
+    docprophdr.pdmOut = pDevModeOutput;
+    docprophdr.fMode  = fMode;
+
+    if ( fMode & DM_IN_PROMPT )
+    {
+        Result = CPSUI_CANCEL;
+
+        //
+        // Now call the Property Sheet for Print > Properties.
+        //
+        if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 )
         {
-            Result = Length;
+            FIXME("CallCommonPropertySheetUI return error\n");
+            Result = ERR_CPSUI_GETLASTERROR;
         }
+        else
+            Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
+        FIXME("CallCommonPropertySheetUI returned\n");
+    }
+    else
+    {
+        FIXME("DPW : CallDocumentPropertySheets\n");
+        Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
+    }
 
-        HeapFree(hProcessHeap, 0, pi9);
+    if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED )
+    {
+        if ( pDevModeOutput )
+        {
+            if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) )
+            {
+                ERR("DPW : Improper pDevModeOutput size.\n");
+                Result = -1;
+            }
+        }
+        else
+        {
+            ERR("No pDevModeOutput\n");
+        }
     }
 
     if (hUseHandle && !hPrinter)
@@ -373,6 +1240,56 @@ DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pD
     return Result;
 }
 
+BOOL
+WINAPI
+PrinterProperties( HWND hWnd, HANDLE hPrinter )
+{
+    PRINTER_INFO_2W *pi2 = NULL;
+    DWORD needed = 0;
+    LONG Ret, Result = 0;
+    BOOL res;
+    DEVICEPROPERTYHEADER devprophdr;
+
+    FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter);
+
+    devprophdr.cbSize         = sizeof(DEVICEPROPERTYHEADER);
+    devprophdr.Flags          = DPS_NOPERMISSION;
+    devprophdr.hPrinter       = hPrinter;
+    devprophdr.pszPrinterName = NULL;
+
+    res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
+    if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        pi2 = HeapAlloc(hProcessHeap, 0, needed);
+        res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
+    }
+
+    //
+    // Above can fail, still process w/o printer name.
+    //
+    if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName;
+
+    needed = 1;
+
+    if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) )
+    {
+        devprophdr.Flags &= ~DPS_NOPERMISSION;
+    }
+
+    Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result );
+
+    res = (Ret >= 0);
+
+    if (!res)
+    {
+        FIXME("PrinterProperties fail ICPSUI\n");
+    }
+
+    if (pi2) HeapFree(hProcessHeap, 0, pi2);
+
+    return res;
+}
+
 BOOL WINAPI
 EndDocPrinter(HANDLE hPrinter)
 {
@@ -421,7 +1338,7 @@ EndDocPrinter(HANDLE hPrinter)
     }
 
     // A new document can now be started again.
-    pHandle->bStartedDoc = FALSE;
+    pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE;
 
 Cleanup:
     SetLastError(dwErrorCode);
@@ -823,8 +1740,11 @@ EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbB
 
                     HeapFree(hProcessHeap, 0, pszParameters);
                 }
+                if ( ppi2w[i].pDevMode )
+                {
+                    RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode );
+                }
                 break;
-
             }
 
             case 4:
@@ -1089,7 +2009,7 @@ GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
     *pcchBuffer = pwszComma - pwszDevice + 1;
 
     // Check if the supplied buffer is large enough.
-    if (cchInputBuffer < *pcchBuffer)
+    if ( !pszBuffer || cchInputBuffer < *pcchBuffer)
     {
         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
         goto Cleanup;
@@ -1126,6 +2046,8 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD
     PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
     PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
     PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
+    PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
+    PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
     DWORD cch;
 
     TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
@@ -1445,6 +2367,10 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD
 
                 HeapFree(hProcessHeap, 0, pszParameters);
             }
+            if ( ppi2w->pDevMode )
+            {
+                RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode );
+            }
             break;
         }
 
@@ -1562,8 +2488,12 @@ GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD
 
                 HeapFree(hProcessHeap, 0, pszaObjectGUID);
             }
-            break;
         }
+            break;
+        case 8:
+        case 9:
+            RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode);
+            break;
     }       // switch
 
     dwErrorCode = ERROR_SUCCESS;
@@ -1574,431 +2504,24 @@ Cleanup:
 }
 
 BOOL WINAPI
-GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
-{   
+GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, 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;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
 
-    TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
+    TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
 
-    // Check for invalid levels here for early error return. Should be 1-6.
-    if (Level <  1 || Level > 6)
+    // Sanity checks.
+    if (!pHandle)
     {
-        dwErrorCode = ERROR_INVALID_LEVEL;
-        ERR("Invalid Level!\n");
+        dwErrorCode = ERROR_INVALID_HANDLE;
         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))
+    // Dismiss invalid levels already at this point.
+    if (Level > 9)
     {
-        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;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDriverPath);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDataFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pConfigFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pHelpFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDependentFiles);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pMonitorName);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDefaultDataType);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            break;
-        }
-
-        case 5:
-        {
-            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pName);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pEnvironment);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDriverPath);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDataFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pConfigFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            break;
-        }
-
-        case 6:
-        {
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pName);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pEnvironment);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDriverPath);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDataFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pConfigFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pHelpFile);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDependentFiles);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pMonitorName);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDefaultDataType);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszMfgName);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszOEMUrl);
-            if (dwErrorCode != ERROR_SUCCESS)
-            {
-                goto Cleanup;
-            }
-
-            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 (pwszEnvironment)
-    {
-        HeapFree(hProcessHeap, 0, pwszEnvironment);
-    }
-
-    SetLastError(dwErrorCode);
-    return (dwErrorCode == ERROR_SUCCESS);
-}
-
-BOOL WINAPI
-GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
-{
-    DWORD dwErrorCode;
-    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
-
-    TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
-
-    // Sanity checks.
-    if (!pHandle)
-    {
-        dwErrorCode = ERROR_INVALID_HANDLE;
-        goto Cleanup;
-    }
-
-    // Dismiss invalid levels already at this point.
-    if (Level > 8 || Level < 1)
-    {
-        dwErrorCode = ERROR_INVALID_LEVEL;
-        goto Cleanup;
-    }
-
-    if (cbBuf && pDriverInfo)
-        ZeroMemory(pDriverInfo, cbBuf);
-
-    // Do the RPC call
-    RpcTryExcept
-    {
-        dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
-    }
-    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
-    {
-        dwErrorCode = RpcExceptionCode();
-        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 <= 5);
-        MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE);
-    }
-
-Cleanup:
-    SetLastError(dwErrorCode);
-    return (dwErrorCode == ERROR_SUCCESS);
-}
-
-BOOL WINAPI
-GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
-{
-    DWORD dwErrorCode;
-    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
-
-    TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
-
-    // Sanity checks.
-    if (!pHandle)
-    {
-        dwErrorCode = ERROR_INVALID_HANDLE;
-        goto Cleanup;
-    }
-
-    // Dismiss invalid levels already at this point.
-    if (Level > 9)
-    {
-        dwErrorCode = ERROR_INVALID_LEVEL;
+        dwErrorCode = ERROR_INVALID_LEVEL;
         goto Cleanup;
     }
 
@@ -2081,6 +2604,12 @@ OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefaul
 
     bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
 
+    if ( bReturnValue )
+    {
+        PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter;
+        pHandle->bAnsi = TRUE;
+    }
+
 Cleanup:
     if (wDefault.pDatatype)
         HeapFree(hProcessHeap, 0, wDefault.pDatatype);
@@ -2145,16 +2674,188 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau
             goto Cleanup;
         }
 
+        pHandle->Sig = SPOOLER_HANDLE_SIG;
         pHandle->hPrinter = hPrinter;
         pHandle->hSPLFile = INVALID_HANDLE_VALUE;
+        pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
+
+        // Return it as phPrinter.
+        *phPrinter = (HANDLE)pHandle;
+    }
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
+
+//
+// Dead API.
+//
+DWORD WINAPI
+PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType)
+{
+    return 50;
+}
+
+DWORD WINAPI
+PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
+{
+    return 50;
+}
+
+BOOL WINAPI
+QueryColorProfile(
+  HANDLE    hPrinter,
+  PDEVMODEW pdevmode,
+  ULONG     ulQueryMode,
+  VOID      *pvProfileData,
+  ULONG     *pcbProfileData,
+  FLONG     *pflProfileData )
+{
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+    BOOL Ret = FALSE;
+    HMODULE hLibrary;
+
+    FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData);
+
+    if ( pHandle->bNoColorProfile )
+    {
+        Ret = (BOOL)SP_ERROR;
+    }
+    else
+    {
+
+        if ( pdevmode )
+        {
+            if (!IsValidDevmodeNoSizeW( pdevmode ) )
+            {
+                ERR("DeviceCapabilitiesW : Devode Invalid");
+                return FALSE;
+            }
+        }
+
+        hLibrary = LoadPrinterDriver( hPrinter );
+
+        if ( hLibrary )
+        {
+            fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" );
+
+            if ( fpQueryColorProfile )
+            {
+                Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData );
+            }
+            else
+            {
+                pHandle->bNoColorProfile = TRUE;
+                Ret = (BOOL)SP_ERROR;
+            }
+
+            FreeLibrary(hLibrary);
+        }
+    }
+    return Ret;
+}
+
+// Note from GDI32:printdrv.c
+//
+//  QuerySpoolMode :
+//    BOOL return TRUE if successful.
+//    dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?.
+//    dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18.
+//
+
+#define QSM_DOWNLOADINGFONTS 0x0001
+
+/*
+   Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file"
+
+   Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in
+   v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8:
+
+    Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure.
+    Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
+    Choose your datatype based on the presence or absence of the flag:
+        If the flag is set, use XPS_PASS.
+        If the flag isn't set, use RAW.
+ */
+
+#define QSM_XPS_PASS         0x0002 // Guessing. PRINTER_DRIVER_XPS?
+
+BOOL WINAPI
+QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion )
+{
+    PRINTER_INFO_2W *pi2 = NULL;
+    DWORD needed = 0;
+    BOOL res;
+
+    FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion);
+
+    res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
+    if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        pi2 = HeapAlloc(hProcessHeap, 0, needed);
+        res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
+    }
+
+    if ( res )
+    {
+        *dwVersion = 0x10000;
+        *downloadFontsFlags = 0;
+
+        if ( pi2->pServerName )
+        {
+            *downloadFontsFlags |= QSM_DOWNLOADINGFONTS;
+        }
+    }
+//
+//  Guessing,,,
+//  To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag,
+//          to set *downloadFontsFlags |= QSM_XPS_PASS;
+//
+//  Vista+ looks for QSM_XPS_PASS to be set in GDI32.
+//
+    HeapFree(hProcessHeap, 0, pi2);
+    return res;
+}
+
+//
+// This requires IC support.
+//
+DWORD WINAPI
+QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs )
+{
+    HANDLE hIC;
+    DWORD Result = -1, cOut, cIn = 0;
+    PBYTE pOut;
+
+    FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs);
+
+    hIC = CreatePrinterIC( hPrinter, NULL );
+    if ( hIC )
+    {
+        cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size.
+
+        pOut = HeapAlloc( hProcessHeap, 0, cOut );
+        if ( pOut )
+        {
+            if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) )
+            {
+                cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object.
+
+                Result = cIn; // Return the required size.
 
-        // Return it as phPrinter.
-        *phPrinter = (HANDLE)pHandle;
+                if( NumberOfUFIs < cIn )
+                {
+                    cIn = NumberOfUFIs;
+                }
+                //     Copy whole object back to GDI32, exclude first DWORD part.
+                memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) );
+            }
+            HeapFree( hProcessHeap, 0, pOut );
+        }
+        DeletePrinterIC( hIC );
     }
-
-Cleanup:
-    SetLastError(dwErrorCode);
-    return (dwErrorCode == ERROR_SUCCESS);
+    return Result;
 }
 
 BOOL WINAPI
@@ -2192,9 +2893,41 @@ Cleanup:
 BOOL WINAPI
 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
 {
+    BOOL ret;
+    UNICODE_STRING pNameW;
+    PDEVMODEW pdmw = NULL;
+    PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault;
+
     TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ( pDefault->pDatatype == (LPSTR)-1 )
+    {
+        pdw->pDatatype = (LPWSTR)-1;
+    }
+    else
+    {
+        pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype );
+    }
+    if ( pDefault->pDevMode == (LPDEVMODEA)-1)
+    {
+        pdw->pDevMode = (LPDEVMODEW)-1;
+    }
+    else
+    {
+        if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) )
+        {
+            RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw );
+            pdw->pDevMode = pdmw;
+        }
+    }
+
+    ret = ResetPrinterW( hPrinter, pdw );
+
+    if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
+
+    RtlFreeUnicodeString( &pNameW );
+
+    return ret;
 }
 
 BOOL WINAPI
@@ -2354,17 +3087,323 @@ Cleanup:
 BOOL WINAPI
 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
 {
-    TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
-    UNIMPLEMENTED;
-    return FALSE;
+    BOOL Ret = FALSE;
+    UNICODE_STRING usBuffer;
+    PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter;
+    PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter;
+    PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
+    PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
+    PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
+    PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
+    PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
+    PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
+    PWSTR pwszPrinterName = NULL;
+    PWSTR pwszServerName = NULL;
+    PWSTR pwszShareName = NULL;
+    PWSTR pwszPortName = NULL;
+    PWSTR pwszDriverName = NULL;
+    PWSTR pwszComment = NULL;
+    PWSTR pwszLocation = NULL;
+    PWSTR pwszSepFile = NULL;
+    PWSTR pwszPrintProcessor = NULL;
+    PWSTR pwszDatatype = NULL;
+    PWSTR pwszParameters = NULL;
+    PDEVMODEW pdmw = NULL;
+
+    FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
+
+    switch ( Level )
+    {
+        case 0:
+            if ( Command == 0 )
+            {
+                if (ppisa->pPrinterName)
+                {
+                    pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName);
+                    if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup;
+                }
+                if (ppisa->pServerName)
+                {
+                    pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName);
+                    if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup;
+                }
+            }
+            if ( Command == PRINTER_CONTROL_SET_STATUS )
+            {
+                // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
+                PRINTER_INFO_6 pi6;
+                pi6.dwStatus = (DWORD)pPrinter;
+                pPrinter = (LPBYTE)&pi6;
+                Level = 6;
+                Command = 0;
+            }
+            break;
+        case 2:
+            {
+                if (ppi2a->pShareName)
+                {
+                    pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
+                    if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
+                }
+                if (ppi2a->pPortName)
+                {
+                    pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
+                    if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
+                }
+                if (ppi2a->pDriverName)
+                {
+                    pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
+                    if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
+                }
+                if (ppi2a->pComment)
+                {
+                    pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
+                    if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
+                }
+                if (ppi2a->pLocation)
+                {
+                    pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
+                    if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
+                }
+                if (ppi2a->pSepFile)
+                {
+                    pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
+                    if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
+                }
+                if (ppi2a->pServerName)
+                {
+                    pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
+                    if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
+                }
+                if (ppi2a->pDatatype)
+                {
+                    pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
+                    if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
+                }
+                if (ppi2a->pParameters)
+                {
+                    pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
+                    if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
+                }
+
+                if ( ppi2a->pDevMode )
+                {
+                    RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
+                    ppi2w->pDevMode = pdmw;
+                }
+            }
+        //
+        //  These two strings are relitive and common to these three Levels.
+        //  Fall through...
+        //
+        case 4:
+        case 5:
+            {
+                if (ppi2a->pServerName) // 4 & 5 : pPrinterName.
+                {
+                    pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
+                    if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
+                }
+                if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName.
+                {
+                    pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
+                    if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
+                }
+            }
+            break;
+        case 3:
+        case 6:
+            break;
+        case 7:
+            {
+                if (ppi7a->pszObjectGUID)
+                {
+                    pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID);
+                    if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup;
+                }
+            }
+            break;
+
+        case 8:
+        /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
+        /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
+        /* fall through */
+        case 9:
+            {
+                RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw );
+                ppi9w->pDevMode = pdmw;
+            }
+            break;
+
+        default:
+            FIXME( "Unsupported level %d\n", Level);
+            SetLastError( ERROR_INVALID_LEVEL );
+    }
+
+    Ret = SetPrinterW( hPrinter, Level, pPrinter, Command );
+
+Cleanup:
+    if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
+    if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
+    if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
+    if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
+    if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
+    if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
+    if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
+    if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
+    if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
+    if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
+    if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
+    if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
+    return Ret;
 }
 
 BOOL WINAPI
 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
 {
-    TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
-    UNIMPLEMENTED;
-    return FALSE;
+    DWORD dwErrorCode;
+    WINSPOOL_PRINTER_CONTAINER PrinterContainer;
+    WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
+    WINSPOOL_SECURITY_CONTAINER SecurityContainer;
+    SECURITY_DESCRIPTOR *sd = NULL;
+    DWORD size;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+    FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
+
+    // Sanity checks
+    if (!pHandle)
+        return ERROR_INVALID_HANDLE;
+
+    DevModeContainer.cbBuf = 0;
+    DevModeContainer.pDevMode = NULL;
+
+    SecurityContainer.cbBuf = 0;
+    SecurityContainer.pSecurity = NULL;
+
+    switch ( Level )
+    {
+        case 0:
+            if ( Command == PRINTER_CONTROL_SET_STATUS )
+            {
+                // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
+                PRINTER_INFO_6 pi6;
+                pi6.dwStatus = (DWORD)pPrinter;
+                pPrinter = (LPBYTE)&pi6;
+                Level = 6;
+                Command = 0;
+            }
+            break;
+        case 2:
+            {
+                PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
+                if ( pi2w )
+                {
+                    if ( pi2w->pDevMode )
+                    {
+                         if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
+                         {
+                             DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
+                             DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
+                         }
+                    }
+
+                    if ( pi2w->pSecurityDescriptor )
+                    {
+                        sd = get_sd( pi2w->pSecurityDescriptor, &size );
+                        if ( sd )
+                        {
+                            SecurityContainer.cbBuf = size;
+                            SecurityContainer.pSecurity = (PBYTE)sd;
+                        }
+                    }
+                }
+                else
+                {
+                    SetLastError(ERROR_INVALID_PARAMETER);
+                    return FALSE;
+                }
+            }
+            break;
+        case 3:
+            {
+                PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter;
+                if ( pi3 )
+                {
+                    if ( pi3->pSecurityDescriptor )
+                    {
+                        sd = get_sd( pi3->pSecurityDescriptor, &size );
+                        if ( sd )
+                        {
+                            SecurityContainer.cbBuf = size;
+                            SecurityContainer.pSecurity = (PBYTE)sd;
+                        }
+                    }
+                }
+                else
+                {
+                    SetLastError(ERROR_INVALID_PARAMETER);
+                    return FALSE;
+                }
+            }
+            break;
+
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+            if ( pPrinter == NULL )
+            {
+                SetLastError(ERROR_INVALID_PARAMETER);
+                return FALSE;
+            }
+            break;
+
+        case 8:
+        /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
+        /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
+        /* fall through */
+        case 9:
+            {
+                PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter;
+                if ( pi9w )
+                {
+                    if ( pi9w->pDevMode )
+                    {
+                         if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) )
+                         {
+                             DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra;
+                             DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode;
+                         }
+                    }
+                }
+            }
+            break;
+
+        default:
+            FIXME( "Unsupported level %d\n", Level );
+            SetLastError( ERROR_INVALID_LEVEL );
+            return FALSE;
+    }
+
+    PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
+    PrinterContainer.Level = Level;
+
+    // Do the RPC call
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+    }
+    RpcEndExcept;
+
+    if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
@@ -2374,6 +3413,219 @@ SplDriverUnloadComplete(LPWSTR pDriverFile)
     UNIMPLEMENTED;
     return TRUE; // return true for now.
 }
+BOOL WINAPI
+
+SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam )
+{
+    HMODULE hLibrary;
+    HANDLE hPrinter;
+    BOOL Ret = FALSE;
+
+    if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) )
+    {
+        hLibrary = LoadPrinterDriver( hPrinter );
+
+        if ( hLibrary )
+        {
+            fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" );
+
+            if ( fpPrinterEvent )
+            {
+                Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam );
+            }
+
+            FreeLibrary(hLibrary);
+        }
+
+        ClosePrinter( hPrinter );
+    }
+
+    return Ret;
+}
+
+INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    LPWSTR filename;
+
+    switch(msg)
+    {
+    case WM_INITDIALOG:
+        SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
+        return TRUE;
+
+    case WM_COMMAND:
+        if(HIWORD(wparam) == BN_CLICKED)
+        {
+            if(LOWORD(wparam) == IDOK)
+            {
+                HANDLE hf;
+                DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
+                LPWSTR *output;
+
+                filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+                GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
+
+                if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
+                {
+                    WCHAR caption[200], message[200];
+                    int mb_ret;
+
+                    LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
+                    LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message));
+                    mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
+                    if(mb_ret == IDCANCEL)
+                    {
+                        HeapFree(GetProcessHeap(), 0, filename);
+                        return TRUE;
+                    }
+                }
+                hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+                if(hf == INVALID_HANDLE_VALUE)
+                {
+                    WCHAR caption[200], message[200];
+
+                    LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
+                    LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message));
+                    MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
+                    HeapFree(GetProcessHeap(), 0, filename);
+                    return TRUE;
+                }
+                CloseHandle(hf);
+                DeleteFileW(filename);
+                output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
+                *output = filename;
+                EndDialog(hwnd, IDOK);
+                return TRUE;
+            }
+            if(LOWORD(wparam) == IDCANCEL)
+            {
+                EndDialog(hwnd, IDCANCEL);
+                return TRUE;
+            }
+        }
+        return FALSE;
+    }
+    return FALSE;
+}
+
+static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
+
+LPWSTR WINAPI
+StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
+{
+    LPWSTR ret = NULL;
+    DWORD len, attr, retDlg;
+
+    FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc);
+
+    if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */
+    {
+        PRINTER_INFO_5W *pi5;
+        GetPrinterW(hPrinter, 5, NULL, 0, &len);
+        if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            return NULL;
+        pi5 = HeapAlloc(GetProcessHeap(), 0, len);
+        GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
+        if (!pi5->pPortName || wcsicmp(pi5->pPortName, FILE_Port))
+        {
+            HeapFree(GetProcessHeap(), 0, pi5);
+            return NULL;
+        }
+        HeapFree(GetProcessHeap(), 0, pi5);
+    }
+
+    if (doc->lpszOutput == NULL || !wcsicmp(doc->lpszOutput, FILE_Port))
+    {
+        LPWSTR name;
+
+        retDlg = DialogBoxParamW( hinstWinSpool,
+                                  MAKEINTRESOURCEW(FILENAME_DIALOG),
+                                  GetForegroundWindow(),
+                                  file_dlg_proc,
+                                 (LPARAM)&name );
+
+        if ( retDlg == IDOK )
+        {
+            if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
+            {
+                HeapFree(GetProcessHeap(), 0, name);
+                return NULL;
+            }
+            ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+            GetFullPathNameW(name, len, ret, NULL);
+            HeapFree(GetProcessHeap(), 0, name);
+        }
+        else if ( retDlg == 0 ) // FALSE, some type of error occurred.
+        {
+            ret = (LPWSTR)SP_ERROR;
+        }
+        else if ( retDlg == IDCANCEL )
+        {
+            SetLastError( ERROR_CANCELLED );
+            ret = (LPWSTR)SP_APPABORT;
+        }
+        return ret;
+    }
+
+    if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
+        return NULL;
+
+    ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
+
+    attr = GetFileAttributesW(ret);
+    if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
+    {
+        HeapFree(GetProcessHeap(), 0, ret);
+        ret = NULL;
+    }
+    return ret;
+}
+
+LPSTR WINAPI
+StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
+{
+    UNICODE_STRING usBuffer;
+    DOCINFOW docW = { 0 };
+    LPWSTR retW;
+    LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
+    LPSTR ret = NULL;
+
+    docW.cbSize = sizeof(docW);
+    if (doc->lpszDocName)
+    {
+        docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName);
+        if (!(docW.lpszDocName = docnameW)) goto failed;
+    }
+    if (doc->lpszOutput)
+    {
+        outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput);
+        if (!(docW.lpszOutput = outputW)) goto failed;
+    }
+    if (doc->lpszDatatype)
+    {
+        datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype);
+        if (!(docW.lpszDatatype = datatypeW)) goto failed;
+    }
+    docW.fwType = doc->fwType;
+
+    retW = StartDocDlgW(hPrinter, &docW);
+
+    if (retW)
+    {
+        DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
+        ret = HeapAlloc(GetProcessHeap(), 0, len);
+        WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
+        HeapFree(GetProcessHeap(), 0, retW);
+    }
+
+failed:
+    if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW);
+    if (outputW) HeapFree(GetProcessHeap(), 0, outputW);
+    if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW);
+
+    return ret;
+}
 
 DWORD WINAPI
 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
@@ -2396,6 +3648,7 @@ StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
 
     if (Level != 1)
     {
+        ERR("Level = %d, unsupported!\n", Level);
         dwErrorCode = ERROR_INVALID_LEVEL;
         goto Cleanup;
     }
@@ -2493,6 +3746,7 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
 
     if (Level != 1)
     {
+        ERR("Level = %d, unsupported!\n", Level);
         dwErrorCode = ERROR_INVALID_LEVEL;
         goto Cleanup;
     }
@@ -2546,6 +3800,10 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
     {
         pHandle->bStartedDoc = TRUE;
         dwReturnValue = pHandle->dwJobID;
+        if ( !pHandle->bTrayIcon )
+        {
+            FIXME("Notify Tray Icon\n");
+        }
     }
 
 Cleanup:
index 9283eeb..d40d81e 100644 (file)
 BOOL WINAPI
 AddPrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPathName, PSTR pPrintProcessorName)
 {
+    UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
+    BOOL Ret;
+
     TRACE("AddPrintProcessorA(%s, %s, %s, %s)\n", pName, pEnvironment, pPathName, pPrintProcessorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    AsciiToUnicode(&NameW, pName);
+    AsciiToUnicode(&EnvW, pEnvironment);
+    AsciiToUnicode(&PathW, pPathName);
+    AsciiToUnicode(&ProcessorW, pPrintProcessorName);
+
+    Ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
+
+    RtlFreeUnicodeString(&ProcessorW);
+    RtlFreeUnicodeString(&PathW);
+    RtlFreeUnicodeString(&EnvW);
+    RtlFreeUnicodeString(&NameW);
+
+    return Ret;
 }
 
 BOOL WINAPI
 AddPrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPathName, PWSTR pPrintProcessorName)
 {
+    DWORD dwErrorCode;
+
     TRACE("AddPrintProcessorW(%S, %S, %S, %S)\n", pName, pEnvironment, pPathName, pPrintProcessorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddPrintProcessor( pName, pEnvironment, pPathName, pPrintProcessorName );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcPrintProcessor failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 DeletePrintProcessorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProcessorName)
 {
+    UNICODE_STRING NameW, EnvW, ProcessorW;
+    BOOL Ret;
+
     TRACE("DeletePrintProcessorA(%s, %s, %s)\n", pName, pEnvironment, pPrintProcessorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    AsciiToUnicode(&NameW, pName);
+    AsciiToUnicode(&EnvW, pEnvironment);
+    AsciiToUnicode(&ProcessorW, pPrintProcessorName);
+
+    Ret = DeletePrintProcessorW(NameW.Buffer, EnvW.Buffer, ProcessorW.Buffer);
+
+    RtlFreeUnicodeString(&ProcessorW);
+    RtlFreeUnicodeString(&EnvW);
+    RtlFreeUnicodeString(&NameW);
+
+    return Ret;
 }
 
 BOOL WINAPI
 DeletePrintProcessorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProcessorName)
 {
+    DWORD dwErrorCode;
+
     TRACE("DeletePrintProcessorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProcessorName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeletePrintProcessor( pName, pEnvironment, pPrintProcessorName );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcDeletePrintProcessor failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
@@ -89,9 +145,115 @@ Cleanup:
 BOOL WINAPI
 EnumPrintProcessorsA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pPrintProcessorInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
-    TRACE("EnumPrintProcessorsA(%s, %s, %lu, %p, %lu, %p, %p)\n", pName, pEnvironment, Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
-    UNIMPLEMENTED;
-    return FALSE;
+    BOOL    res;
+    LPBYTE  bufferW = NULL;
+    LPWSTR  nameW = NULL;
+    LPWSTR  envW = NULL;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    INT     len;
+
+    TRACE("EnumPrintProcessorsA(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment), Level, pPrintProcessorInfo, cbBuf, pcbNeeded, pcReturned);
+
+    /* convert names to unicode */
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+    if (pEnvironment)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
+        envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
+    }
+
+    /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
+    needed = cbBuf * sizeof(WCHAR);
+    if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
+    res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
+
+    if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+    {
+        if (pcbNeeded) needed = *pcbNeeded;
+        /* HeapReAlloc return NULL, when bufferW was NULL */
+        bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
+                              HeapAlloc(GetProcessHeap(), 0, needed);
+
+        /* Try again with the large Buffer */
+        res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
+    }
+    numentries = pcReturned ? *pcReturned : 0;
+    needed = 0;
+
+    if (res)
+    {
+        /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
+        DWORD   index;
+        LPSTR   ptr;
+        PPRINTPROCESSOR_INFO_1W ppiw;
+        PPRINTPROCESSOR_INFO_1A ppia;
+
+        /* First pass: calculate the size for all Entries */
+        ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
+        ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo;
+        index = 0;
+        while (index < numentries)
+        {
+            index++;
+            needed += sizeof(PRINTPROCESSOR_INFO_1A);
+            TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
+
+            needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
+                                            NULL, 0, NULL, NULL);
+
+            ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
+            ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
+        }
+
+        /* check for errors and quit on failure */
+        if (cbBuf < needed)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            res = FALSE;
+            goto epp_cleanup;
+        }
+
+        len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
+        ptr = (LPSTR) &pPrintProcessorInfo[len];        /* start of strings */
+        cbBuf -= len ;                      /* free Bytes in the user-Buffer */
+        ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
+        ppia = (PPRINTPROCESSOR_INFO_1A) pPrintProcessorInfo;
+        index = 0;
+        /* Second Pass: Fill the User Buffer (if we have one) */
+        while ((index < numentries) && pPrintProcessorInfo)
+        {
+            index++;
+            TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
+            ppia->pName = ptr;
+            len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
+                                            ptr, cbBuf , NULL, NULL);
+            ptr += len;
+            cbBuf -= len;
+
+            ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
+            ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
+
+        }
+    }
+epp_cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = (res) ? numentries : 0;
+
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, envW);
+    HeapFree(GetProcessHeap(), 0, bufferW);
+
+    TRACE("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries);
+
+    return (res);
+
 }
 
 BOOL WINAPI
index 58efb89..ffeb533 100644 (file)
 BOOL WINAPI
 AddPrintProvidorA(PSTR pName, DWORD Level, PBYTE pProviderInfo)
 {
+    LPWSTR nameW = NULL;
+    PROVIDOR_INFO_1W pi1W;
+    PROVIDOR_INFO_2W pi2W;
+    DWORD len;
+    BOOL res;
+    PBYTE pPI = NULL;
+
     TRACE("AddPrintProvidorA(%s, %lu, %p)\n", pName, Level, pProviderInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    ZeroMemory(&pi1W, sizeof(PROVIDOR_INFO_1W));
+    pi2W.pOrder = NULL;
+
+    switch (Level)
+    {
+        case 1:
+        {
+            PROVIDOR_INFO_1A *pi1A = (PROVIDOR_INFO_1A*)pProviderInfo;
+            if (pi1A->pName)
+            {
+                len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0);
+                pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len);
+            }
+            if (pi1A->pEnvironment)
+            {
+                len = MultiByteToWideChar(CP_ACP, 0, pi1A->pEnvironment, -1, NULL, 0);
+                pi1W.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, pi1A->pEnvironment, -1, pi1W.pEnvironment, len);
+            }
+            if (pi1A->pDLLName)
+            {
+                len = MultiByteToWideChar(CP_ACP, 0, pi1A->pDLLName, -1, NULL, 0);
+                pi1W.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, pi1A->pDLLName, -1, pi1W.pDLLName, len);
+            }
+            pPI = (PBYTE)&pi1W;
+        }
+            break;
+
+        case 2:
+        {
+            PROVIDOR_INFO_2A *pi2A = (PROVIDOR_INFO_2A*)pProviderInfo;
+            if (pi2A->pOrder)
+            {
+                len = MultiByteToWideChar(CP_ACP, 0, pi2A->pOrder, -1, NULL, 0);
+                pi2W.pOrder = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                MultiByteToWideChar(CP_ACP, 0, pi2A->pOrder, -1, pi2W.pOrder, len);
+            }
+            pPI = (PBYTE)&pi2W;
+        }
+            break;
+
+        default:
+            SetLastError(ERROR_INVALID_LEVEL);
+            return FALSE;
+    }
+
+    if (pName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
+    }
+
+    res = AddPrintProvidorW( nameW, Level, pPI );
+
+    if (pName) HeapFree(GetProcessHeap(), 0, nameW);
+    if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName);
+    if (pi1W.pEnvironment) HeapFree(GetProcessHeap(), 0, pi1W.pEnvironment);
+    if (pi1W.pDLLName) HeapFree(GetProcessHeap(), 0, pi1W.pDLLName);
+    if (pi2W.pOrder) HeapFree(GetProcessHeap(), 0, pi2W.pOrder);
+
+    return res;
 }
 
 BOOL WINAPI
 AddPrintProvidorW(PWSTR pName, DWORD Level, PBYTE pProviderInfo)
 {
+    DWORD dwErrorCode;
+    WINSPOOL_PROVIDOR_CONTAINER ProvidorContainer;
+
     TRACE("AddPrintProvidorW(%S, %lu, %p)\n", pName, Level, pProviderInfo);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    if ((Level < 1) || (Level > 2))
+    {
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
+
+    ProvidorContainer.ProvidorInfo.pProvidorInfo1 = (WINSPOOL_PROVIDOR_INFO_1*)pProviderInfo;
+    ProvidorContainer.Level = Level;
+
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcAddPrintProvidor( pName, &ProvidorContainer );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 DeletePrintProvidorA(PSTR pName, PSTR pEnvironment, PSTR pPrintProviderName)
 {
+    UNICODE_STRING NameW, EnvW, ProviderW;
+    BOOL Ret;
+
     TRACE("DeletePrintProvidorW(%s, %s, %s)\n", pName, pEnvironment, pPrintProviderName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    AsciiToUnicode(&NameW, pName);
+    AsciiToUnicode(&EnvW, pEnvironment);
+    AsciiToUnicode(&ProviderW, pPrintProviderName);
+
+    Ret = DeletePrintProvidorW(NameW.Buffer, EnvW.Buffer, ProviderW.Buffer);
+
+    RtlFreeUnicodeString(&ProviderW);
+    RtlFreeUnicodeString(&EnvW);
+    RtlFreeUnicodeString(&NameW);
+
+    return Ret;
 }
 
 BOOL WINAPI
 DeletePrintProvidorW(PWSTR pName, PWSTR pEnvironment, PWSTR pPrintProviderName)
 {
+    DWORD dwErrorCode;
+
     TRACE("DeletePrintProvidorW(%S, %S, %S)\n", pName, pEnvironment, pPrintProviderName);
-    UNIMPLEMENTED;
-    return FALSE;
+
+    RpcTryExcept
+    {
+        dwErrorCode = _RpcDeletePrintProvidor( pName, pEnvironment, pPrintProviderName );
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwErrorCode = RpcExceptionCode();
+        ERR("_RpcEnumPorts failed with exception code %lu!\n", dwErrorCode);
+    }
+    RpcEndExcept;
+
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
diff --git a/win32ss/printing/base/winspool/spoolfile.c b/win32ss/printing/base/winspool/spoolfile.c
new file mode 100644 (file)
index 0000000..d40e090
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * PROJECT:     ReactOS Spooler API
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Functions related to Spool Files and printing
+ * COPYRIGHT:   Copyright 1998-2020 ReactOS
+ */
+
+#include "precomp.h"
+
+
+HANDLE WINAPI
+GetSpoolFileHandle( HANDLE hPrinter )
+{
+    DWORD dwErrorCode, cpid;
+    WINSPOOL_FILE_INFO_CONTAINER FileInfoContainer;
+    WINSPOOL_FILE_INFO_1 wsplfi;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+    HANDLE hHandle = NULL;
+
+    FIXME("GetSpoolFileHandle(%p)\n", hPrinter);
+
+    if ( IntProtectHandle( hPrinter, FALSE ) )
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+    }
+    else
+    {
+        if ( pHandle->hSpoolFileHandle != INVALID_HANDLE_VALUE )
+        {
+              hHandle = pHandle->hSpoolFileHandle;
+        }
+        else
+        {
+            cpid = GetCurrentProcessId();
+
+            FileInfoContainer.Level = 1;
+            FileInfoContainer.FileInfo.pFileInfo1 = &wsplfi;
+
+            // Do the RPC call.
+            RpcTryExcept
+            {
+                dwErrorCode = _RpcGetSpoolFileInfo2( &pHandle->hPrinter, cpid, 1, &FileInfoContainer );
+            }
+            RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+            {
+                dwErrorCode = RpcExceptionCode();
+                ERR("_RpcGetSpoolFileInfo failed with exception code %lu!\n", dwErrorCode);
+            }
+            RpcEndExcept;
+
+            if (dwErrorCode == ERROR_SUCCESS)
+            {
+                pHandle->hSpoolFileHandle = wsplfi.hSpoolFileHandle;
+                pHandle->dwOptions        = wsplfi.dwOptions;
+                hHandle                   = pHandle->hSpoolFileHandle;
+            }
+        }
+        IntUnprotectHandle(pHandle);
+    }
+    SetLastError(dwErrorCode);
+    return hHandle;
+}
+
+HANDLE WINAPI
+CommitSpoolData( HANDLE hPrinter, HANDLE hSpoolFile, DWORD cbCommit )
+{
+    DWORD dwErrorCode, cpid;
+    WINSPOOL_FILE_INFO_CONTAINER FileInfoContainer;
+    WINSPOOL_FILE_INFO_1 wsplfi;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+    HANDLE hHandle = INVALID_HANDLE_VALUE;
+
+    FIXME("CommitSpoolData(%p, %p, %d)\n", hPrinter,hSpoolFile,cbCommit);
+
+    if ( IntProtectHandle( hPrinter, FALSE ) )
+    {
+        return hHandle;
+    }
+
+    if ( pHandle->hSpoolFileHandle == INVALID_HANDLE_VALUE || pHandle->hSpoolFileHandle != hSpoolFile )
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+    }
+    else
+    {
+        cpid = GetCurrentProcessId();
+
+        FileInfoContainer.Level = 1;
+        FileInfoContainer.FileInfo.pFileInfo1 = &wsplfi;
+
+        // Do the RPC call.
+        RpcTryExcept
+        {
+            dwErrorCode = _RpcCommitSpoolData2( &pHandle->hPrinter, cpid, cbCommit, 1, &FileInfoContainer );
+        }
+        RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+        {
+            dwErrorCode = RpcExceptionCode();
+            ERR("_RpcCommitSpoolData failed with exception code %lu!\n", dwErrorCode);
+        }
+        RpcEndExcept;
+
+        if (dwErrorCode == ERROR_SUCCESS)
+        {
+            if ( wsplfi.hSpoolFileHandle != INVALID_HANDLE_VALUE )
+            {
+                CloseHandle( pHandle->hSpoolFileHandle );
+                pHandle->hSpoolFileHandle = wsplfi.hSpoolFileHandle;
+            }
+            hHandle = pHandle->hSpoolFileHandle;
+        }
+        IntUnprotectHandle(pHandle);
+    }
+    SetLastError(dwErrorCode);
+    return hHandle;
+}
+
+BOOL WINAPI
+CloseSpoolFileHandle( HANDLE hPrinter, HANDLE hSpoolFile )
+{
+    DWORD dwErrorCode;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+    FIXME("CloseSpoolFileHandle(%p, %p)\n", hPrinter,hSpoolFile);
+
+    if ( IntProtectHandle( hPrinter, FALSE ) )
+    {
+        return FALSE;
+    }
+    if ( pHandle->hSpoolFileHandle == hSpoolFile )
+    {
+        CloseHandle( pHandle->hSpoolFileHandle );
+        pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
+
+        // Do the RPC call.
+        RpcTryExcept
+        {
+            dwErrorCode = _RpcCloseSpoolFileHandle( &pHandle->hPrinter );
+        }
+        RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+        {
+            dwErrorCode = RpcExceptionCode();
+            ERR("_RpcloseSpoolFileHandle failed with exception code %lu!\n", dwErrorCode);
+        }
+        RpcEndExcept;
+    }
+    else
+    {
+        dwErrorCode = ERROR_INVALID_HANDLE;
+    }
+    IntUnprotectHandle(pHandle);
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
+}
index f16cd95..8dae057 100644 (file)
@@ -52,3 +52,281 @@ DWORD UnicodeToAnsiInPlace(PWSTR pwszField)
 
     return ERROR_SUCCESS;
 }
+
+static int multi_sz_lenW(const WCHAR *str)
+{
+    const WCHAR *ptr = str;
+    if (!str) return 0;
+    do
+    {
+        ptr += lstrlenW(ptr) + 1;
+    } while (*ptr);
+
+    return (ptr - str + 1);// * sizeof(WCHAR); wine does this.
+}
+
+DWORD UnicodeToAnsiZZInPlace(PWSTR pwszzField)
+{
+    PSTR pszTemp;
+    INT len, lenW;
+    PSTR pszField = (PSTR)pwszzField;
+
+    lenW = multi_sz_lenW(pwszzField);
+    if (lenW == 0)
+    {
+        return ERROR_SUCCESS;
+    }
+
+    len = WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, NULL, 0, NULL, NULL);
+
+    pszTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+
+    WideCharToMultiByte(CP_ACP, 0, pwszzField, lenW, pszTemp, len, NULL, NULL);
+
+    StringCchCopyA(pszField, len, pszTemp);
+
+    HeapFree(hProcessHeap, 0, pszTemp);
+
+    return ERROR_SUCCESS;
+}
+
+//
+//  Implement and simplify later.
+//
+LONG WINAPI
+IntProtectHandle( HANDLE hSpooler, BOOL Close )
+{
+    BOOL Bad = TRUE;
+    LONG Ret;
+    PSPOOLER_HANDLE pHandle;
+
+    EnterCriticalSection(&rtlCritSec);
+
+    _SEH2_TRY
+    {
+        pHandle = (PSPOOLER_HANDLE)hSpooler;
+        if ( pHandle && pHandle->Sig == SPOOLER_HANDLE_SIG )
+        {
+            Bad = FALSE; // Not bad.
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+    }
+    _SEH2_END;
+
+    Ret = Bad; // Set return Level to 1 if we are BAD.
+
+    if ( Bad )
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        ERR("IPH : Printer Handle failed!\n");
+    }
+    else
+    {
+        if ( Close )
+        {
+            if ( pHandle->bShared || pHandle->cCount != 0 )
+            {
+                pHandle->bShared = TRUE;
+                Ret = 2; // Return a high level and we are shared.
+                FIXME("IPH Close : We are shared\n");
+            }
+            else
+            {
+                pHandle->bClosed = TRUE;
+                FIXME("IPH Close : closing.\n");
+            }
+        }
+    }
+
+    if ( !Ret ) // Need to be Level 0.
+    {
+        pHandle->cCount++;
+        FIXME("IPH : Count %d\n",pHandle->cCount);
+    }
+
+    LeaveCriticalSection(&rtlCritSec);
+
+    // Return Level:
+    // 2 : Close and/or shared
+    // 1 : Failed Handle
+    // 0 : In use.
+    return Ret; 
+}
+//
+// This one too.
+//
+BOOL WINAPI
+IntUnprotectHandle( HANDLE hSpooler )
+{
+    BOOL Ret = FALSE;
+    PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hSpooler;
+    EnterCriticalSection(&rtlCritSec);
+    if ( pHandle->bShared && --pHandle->cCount == 0 )
+    {
+        pHandle->bClosed = TRUE;
+        pHandle->bShared = FALSE;
+        Ret = TRUE;
+    }
+    LeaveCriticalSection(&rtlCritSec);
+    FIXME("IUH : Count %d\n",pHandle->cCount);
+    if ( Ret )
+    {
+//        ClosePrinterWorker( pHandle );
+    }
+    return Ret;
+}
+
+/**
+ * @name AllocSplStr
+ *
+ * Allocates memory for a Unicode string and copies the input string into it.
+ * Equivalent of wcsdup, but the returned buffer is allocated from the spooler heap and must be freed with DllFreeSplStr.
+ *
+ * @param pwszInput
+ * The input string to copy
+ *
+ * @return
+ * Pointer to the copied string or NULL if no memory could be allocated.
+ */
+PWSTR WINAPI
+AllocSplStr(PCWSTR pwszInput)
+{
+    DWORD cbInput;
+    PWSTR pwszOutput;
+
+    // Sanity check
+    if (!pwszInput)
+        return NULL;
+
+    // Get the length of the input string.
+    cbInput = (wcslen(pwszInput) + 1) * sizeof(WCHAR);
+
+    // Allocate it. We don't use DllAllocSplMem here, because it unnecessarily zeroes the memory.
+    pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
+    if (!pwszOutput)
+    {
+        ERR("HeapAlloc failed!\n");
+        return NULL;
+    }
+
+    // Copy the string and return it.
+    CopyMemory(pwszOutput, pwszInput, cbInput);
+    return pwszOutput;
+}
+
+/**
+ * @name DllAllocSplMem
+ *
+ * Allocate a block of zeroed memory.
+ * Windows allocates from a separate spooler heap here while we just use the process heap.
+ *
+ * @param dwBytes
+ * Number of bytes to allocate.
+ *
+ * @return
+ * A pointer to the allocated memory or NULL in case of an error.
+ * You have to free this memory using DllFreeSplMem.
+ */
+PVOID WINAPI
+DllAllocSplMem(DWORD dwBytes)
+{
+    return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwBytes);
+}
+
+/**
+ * @name DllFreeSplMem
+ *
+ * Frees the memory allocated with DllAllocSplMem.
+ *
+ * @param pMem
+ * Pointer to the allocated memory.
+ *
+ * @return
+ * TRUE in case of success, FALSE otherwise.
+ */
+BOOL WINAPI
+DllFreeSplMem(PVOID pMem)
+{
+    if ( !pMem ) return TRUE;
+    return HeapFree(hProcessHeap, 0, pMem);
+}
+
+/**
+ * @name DllFreeSplStr
+ *
+ * Frees the string allocated with AllocSplStr.
+ *
+ * @param pwszString
+ * Pointer to the allocated string.
+ *
+ * @return
+ * TRUE in case of success, FALSE otherwise.
+ */
+BOOL WINAPI
+DllFreeSplStr(PWSTR pwszString)
+{
+    if ( pwszString )
+       return HeapFree(hProcessHeap, 0, pwszString);
+    return FALSE;
+}
+
+SECURITY_DESCRIPTOR * get_sd( SECURITY_DESCRIPTOR *sd, DWORD *size )
+{
+    PSID sid_group, sid_owner;
+    ACL *sacl, *dacl;
+    BOOL bSet = FALSE, bSetd = FALSE, bSets = FALSE;
+    PSECURITY_DESCRIPTOR absolute_sd, retsd;
+
+    if ( !IsValidSecurityDescriptor( sd ) )
+    {
+        return NULL;
+    }
+
+    InitializeSecurityDescriptor( &absolute_sd, SECURITY_DESCRIPTOR_REVISION );
+
+    if ( !GetSecurityDescriptorOwner( sd, &sid_owner, &bSet ) )
+    {
+        return NULL;
+    }
+
+    SetSecurityDescriptorOwner( &absolute_sd, sid_owner, bSet );
+
+    if ( !GetSecurityDescriptorGroup( sd, &sid_group, &bSet ) )
+    {
+        return NULL;
+    }
+
+    SetSecurityDescriptorGroup( &absolute_sd, sid_group, bSet );
+
+    if ( !GetSecurityDescriptorDacl( sd, &bSetd, &dacl, &bSet ) )
+    {
+        return NULL;
+    }
+
+    SetSecurityDescriptorDacl( &absolute_sd, bSetd, dacl, bSet );
+
+    if ( !GetSecurityDescriptorSacl( sd, &bSets, &sacl, &bSet ) )
+    {
+        return(NULL);
+    }
+
+    SetSecurityDescriptorSacl( &absolute_sd, bSets, sacl, bSet );
+
+    *size = GetSecurityDescriptorLength( &absolute_sd );
+
+    retsd = HeapAlloc( GetProcessHeap(), 0, *size );
+
+    if ( retsd )
+    {
+        if ( !MakeSelfRelativeSD( &absolute_sd, retsd, size ) )
+        {
+            HeapFree( GetProcessHeap(), 0, retsd );
+            retsd = NULL;
+        }
+    }
+
+    return retsd;
+}
+
index c7b2a80..e7db2a1 100644 (file)
@@ -1,5 +1,35 @@
+
+#include "precomp.h"
+
 #define REACTOS_VERSION_DLL
 #define REACTOS_STR_FILE_DESCRIPTION  "ReactOS Spooler API"
 #define REACTOS_STR_INTERNAL_NAME     "winspool"
 #define REACTOS_STR_ORIGINAL_FILENAME "winspool.drv"
 #include <reactos/version.rc>
+
+#pragma makedep po
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+    IDS_CAPTION "Local Port"
+    IDS_FILE_EXISTS "The output file already exists. Click OK to overwrite."
+    IDS_CANNOT_OPEN "Unable to create the output file."
+}
+
+FILENAME_DIALOG DIALOG 6, 18, 245, 47
+STYLE DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFONT | DS_SETFOREGROUND | WS_POPUPWINDOW | WS_VISIBLE | WS_CAPTION
+CAPTION "Print to File"
+FONT 8, "MS Shell Dlg"
+BEGIN
+    LTEXT "&Output File Name:", -1, 7, 13, 194, 13, WS_VISIBLE
+    EDITTEXT EDITBOX, 6, 28, 174, 12, WS_VISIBLE | ES_AUTOHSCROLL
+    DEFPUSHBUTTON "OK", IDOK, 199, 10, 40, 14, WS_VISIBLE
+    PUSHBUTTON "Cancel", IDCANCEL, 199, 27, 40, 14, WS_VISIBLE
+END
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+/* @makedep: generic.ppd */
+/*1 PPDFILE generic.ppd*/
index 419354d..e459f5a 100644 (file)
@@ -5,7 +5,7 @@
 104 stub PerfClose
 105 stub PerfCollect
 106 stub PerfOpen
-107 stub ADVANCEDSETUPDIALOG
+107 stdcall ADVANCEDSETUPDIALOG(ptr long ptr ptr) AdvancedSetupDialog
 108 stdcall AbortPrinter(ptr)
 109 stdcall AddFormA(ptr long ptr)
 110 stdcall AddFormW(ptr long ptr)
 130 stdcall AddPrinterW(wstr long ptr)
 131 stdcall AdvancedDocumentPropertiesA(ptr ptr str ptr ptr)
 132 stdcall AdvancedDocumentPropertiesW(ptr ptr wstr ptr ptr)
-133 stub AdvancedSetupDialog
+133 stdcall AdvancedSetupDialog(ptr long ptr ptr)
 134 stdcall ClosePrinter(ptr)
-135 stub CloseSpoolFileHandle
-136 stub CommitSpoolData
+135 stdcall CloseSpoolFileHandle(ptr ptr)
+136 stdcall CommitSpoolData(ptr ptr long)
 137 stdcall ConfigurePortA(str ptr str)
 138 stdcall ConfigurePortW(wstr ptr wstr)
 139 stub ConnectToPrinterDlg
 140 stub ConvertAnsiDevModeToUnicodeDevmode
 141 stub ConvertUnicodeDevModeToAnsiDevmode
-142 stub CreatePrinterIC
-143 stub DEVICECAPABILITIES
-144 stub DEVICEMODE
+142 stdcall -stub CreatePrinterIC(ptr ptr)
+143 stdcall DEVICECAPABILITIES(str str long ptr ptr) DeviceCapabilitiesA
+144 stdcall DEVICEMODE(ptr ptr str ptr) DeviceMode
 145 stdcall DeleteFormA(ptr str)
 146 stdcall DeleteFormW(ptr wstr)
 147 stdcall DeleteMonitorA(str str str)
 163 stdcall DeletePrinterDriverExA(str str str long long)
 164 stdcall DeletePrinterDriverExW(wstr wstr wstr long long)
 165 stdcall DeletePrinterDriverW(wstr wstr wstr)
-166 stub DeletePrinterIC
+166 stdcall -stub DeletePrinterIC(ptr)
 167 stdcall DeletePrinterKeyA(ptr str)
 168 stdcall DeletePrinterKeyW(ptr wstr)
-169 stub DevQueryPrint
-170 stub DevQueryPrintEx
-171 stub DeviceCapabilities
+169 stdcall DevQueryPrint(ptr ptr ptr)
+170 stdcall DevQueryPrintEx(ptr)
+171 stdcall DeviceCapabilities(str str long ptr ptr) DeviceCapabilitiesA
 172 stdcall DeviceCapabilitiesA(str str long ptr ptr)
 173 stdcall DeviceCapabilitiesW(wstr wstr long ptr ptr)
-174 stub DeviceMode
-175 stub DevicePropertySheets
+174 stdcall -stub DeviceMode(ptr ptr str ptr)
+175 stdcall DevicePropertySheets(ptr long)
 176 stdcall DocumentEvent(ptr ptr long long ptr long ptr)
-177 stdcall DocumentPropertiesA(ptr ptr ptr ptr ptr long)
-178 stdcall DocumentPropertiesW(ptr ptr ptr ptr ptr long)
-179 stub DocumentPropertySheets
-180 stub EXTDEVICEMODE
+177 stdcall DocumentPropertiesA(ptr ptr str ptr ptr long)
+178 stdcall DocumentPropertiesW(ptr ptr wstr ptr ptr long)
+179 stdcall DocumentPropertySheets(ptr long)
+180 stdcall EXTDEVICEMODE(ptr ptr ptr str str ptr str long) ExtDeviceMode
 181 stdcall EndDocPrinter(ptr)
 182 stdcall EndPagePrinter(ptr)
 183 stdcall EnumFormsA(ptr long ptr long ptr ptr)
 209 stub -noname DeletePerMachineConnectionW
 210 stub -noname EnumPerMachineConnectionsA
 211 stub -noname EnumPerMachineConnectionsW
-212 stub -noname LoadPrinterDriver
+212 stdcall -noname LoadPrinterDriver(ptr)
 213 stub -noname RefCntLoadDriver
 214 stub -noname RefCntUnloadDriver
 215 stub -noname ForceUnloadDriver
 216 stub -noname PublishPrinterA
 217 stub -noname PublishPrinterW
-218 stub -noname CallCommonPropertySheetUI
+218 stdcall -noname CallCommonPropertySheetUI(ptr ptr long ptr)
 219 stub -noname PrintUIQueueCreate
 220 stub -noname PrintUIPrinterPropPages
 221 stub -noname PrintUIDocumentDefaults
 233 stdcall EnumPrinterKeyW(ptr wstr wstr long ptr)
 234 stdcall EnumPrintersA(long ptr long ptr long ptr ptr)
 235 stdcall EnumPrintersW(long ptr long ptr long ptr ptr)
-236 stub ExtDeviceMode
+236 stdcall -stub ExtDeviceMode(ptr ptr ptr str str ptr str long)
 237 stub FindClosePrinterChangeNotification
 238 stub FindFirstPrinterChangeNotification
 239 stub FindNextPrinterChangeNotification
 255 stdcall GetPrinterDriverDirectoryW(wstr wstr long ptr long ptr)
 256 stdcall GetPrinterDriverW(ptr wstr long ptr long ptr)
 257 stdcall GetPrinterW(ptr long ptr long ptr)
-258 stub GetSpoolFileHandle
+258 stdcall GetSpoolFileHandle(ptr)
 259 stdcall IsValidDevmodeA(ptr long)
 260 stdcall IsValidDevmodeW(ptr long)
 261 stdcall OpenPrinterA(str ptr ptr)
 262 stdcall OpenPrinterW(wstr ptr ptr)
-263 stub PlayGdiScriptOnPrinterIC
-264 stub PrinterMessageBoxA
-265 stub PrinterMessageBoxW
-266 stub PrinterProperties
-267 stub QueryColorProfile
-268 stub QueryRemoteFonts
-269 stub QuerySpoolMode
+263 stdcall -stub PlayGdiScriptOnPrinterIC(ptr ptr long ptr long long)
+264 stdcall PrinterMessageBoxA(ptr long ptr str str long)
+265 stdcall PrinterMessageBoxW(ptr long ptr wstr wstr long)
+266 stdcall PrinterProperties(ptr ptr)
+267 stdcall QueryColorProfile(ptr ptr long ptr ptr ptr)
+268 stdcall QueryRemoteFonts(ptr ptr long)
+269 stdcall QuerySpoolMode(ptr ptr ptr)
 270 stdcall ReadPrinter(ptr ptr long ptr)
 271 stdcall ResetPrinterA(ptr ptr)
 272 stdcall ResetPrinterW(ptr ptr)
 288 stdcall SplDriverUnloadComplete(ptr)
 289 stub SpoolerDevQueryPrintW
 290 stdcall SpoolerInit()
-291 stub SpoolerPrinterEvent
-292 stub StartDocDlgA
-293 stub StartDocDlgW
+291 stdcall SpoolerPrinterEvent(wstr long long long)
+292 stdcall StartDocDlgA(ptr ptr)
+293 stdcall StartDocDlgW(ptr ptr)
 294 stdcall StartDocPrinterA(ptr long ptr)
 295 stdcall StartDocPrinterW(ptr long ptr)
 296 stdcall StartPagePrinter(ptr)
diff --git a/win32ss/printing/include/marshalling/forms.h b/win32ss/printing/include/marshalling/forms.h
new file mode 100644 (file)
index 0000000..90af259
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * PROJECT:     ReactOS Printing Stack Marshalling Functions
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Marshalling definitions for FORM_INFO_*
+ * COPYRIGHT:   Copyright 1998-2020 ReactOS
+ */
+
+static const MARSHALLING FormInfo1Marshalling = {
+    sizeof(FORM_INFO_1W),
+    {
+        { FIELD_OFFSET(FORM_INFO_1W, pName), RTL_FIELD_SIZE(FORM_INFO_1W, pName), RTL_FIELD_SIZE(FORM_INFO_1W, pName), TRUE },
+        { MAXDWORD, 0, 0, FALSE }
+    }
+};
+
+static const MARSHALLING FormInfo2Marshalling = {
+    sizeof(FORM_INFO_2W),
+    {
+        { FIELD_OFFSET(FORM_INFO_2W, pName), RTL_FIELD_SIZE(FORM_INFO_2W, pName), RTL_FIELD_SIZE(FORM_INFO_2W, pName), TRUE },
+        { FIELD_OFFSET(FORM_INFO_2W, pKeyword), RTL_FIELD_SIZE(FORM_INFO_2W, pKeyword), RTL_FIELD_SIZE(FORM_INFO_2W, pKeyword), TRUE },
+        { FIELD_OFFSET(FORM_INFO_2W, pMuiDll), RTL_FIELD_SIZE(FORM_INFO_2W, pMuiDll), RTL_FIELD_SIZE(FORM_INFO_2W, pMuiDll), TRUE },
+        { FIELD_OFFSET(FORM_INFO_2W, pDisplayName), RTL_FIELD_SIZE(FORM_INFO_2W, pDisplayName), RTL_FIELD_SIZE(FORM_INFO_2W, pDisplayName), FALSE },
+        { MAXDWORD, 0, 0, FALSE }
+    }
+};
+
+static const MARSHALLING* pFormInfoMarshalling[] = {
+    NULL,
+    &FormInfo1Marshalling,
+    &FormInfo2Marshalling
+};
index ffaf50f..d46c774 100644 (file)
@@ -53,7 +53,7 @@ static const MARSHALLING PrinterDriver4Marshalling = {
         { FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDependentFiles), TRUE },
         { FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_4W, pMonitorName), TRUE },
         { FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE },
-        { FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pDefaultDataType), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_4W, pszzPreviousNames), TRUE },
         { MAXDWORD, 0, 0, FALSE }
     }
 };
@@ -70,6 +70,52 @@ static const MARSHALLING PrinterDriver5Marshalling = {
     }
 };
 
+static const MARSHALLING PrinterDriver6Marshalling = {
+    sizeof(DRIVER_INFO_6W),
+    {
+        { FIELD_OFFSET(DRIVER_INFO_6W, pName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_6W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_6W, pEnvironment), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDriverPath), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDataFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pConfigFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_6W, pHelpFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDependentFiles), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pMonitorName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_6W, pDefaultDataType), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszzPreviousNames), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszMfgName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszOEMUrl), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszHardwareID), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_6W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_6W, pszProvider), TRUE },
+        { MAXDWORD, 0, 0, FALSE }
+    }
+};
+
+static const MARSHALLING PrinterDriver8Marshalling = {
+    sizeof(DRIVER_INFO_8W),
+    {
+        { FIELD_OFFSET(DRIVER_INFO_8W, pName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_8W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_8W, pEnvironment), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDriverPath), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDataFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pConfigFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_8W, pHelpFile), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDependentFiles), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pMonitorName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_8W, pDefaultDataType), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzPreviousNames), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzPreviousNames), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszMfgName), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszMfgName), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszOEMUrl), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszOEMUrl), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszHardwareID), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszHardwareID), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszProvider), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszProvider), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszPrintProcessor), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszPrintProcessor), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszPrintProcessor), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszVendorSetup), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszVendorSetup), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszVendorSetup), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszzColorProfiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzColorProfiles), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzColorProfiles), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszInfPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszInfPath), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszInfPath), TRUE },
+        { FIELD_OFFSET(DRIVER_INFO_8W, pszzCoreDriverDependencies), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzCoreDriverDependencies), RTL_FIELD_SIZE(DRIVER_INFO_8W, pszzCoreDriverDependencies), TRUE },
+        { MAXDWORD, 0, 0, FALSE }
+    }
+};
 
 static const MARSHALLING* pPrinterDriverMarshalling[] = {
     NULL,
@@ -78,4 +124,6 @@ static const MARSHALLING* pPrinterDriverMarshalling[] = {
     &PrinterDriver3Marshalling,
     &PrinterDriver4Marshalling,
     &PrinterDriver5Marshalling,
+    &PrinterDriver6Marshalling,
+    &PrinterDriver8Marshalling,
 };
index a16cca4..51de840 100644 (file)
@@ -57,6 +57,13 @@ typedef struct _PRINTER_INFO_STRESS
 }
 PRINTER_INFO_STRESS, *PPRINTER_INFO_STRESS;
 
+typedef struct _FILE_INFO_1
+{
+    BOOL   bInheritHandle;
+    HANDLE hSpoolFileHandle;
+    DWORD  dwOptions;
+} FILE_INFO_1, *PFILE_INFO_1;
+
 PVOID WINAPI AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer);
 PWSTR WINAPI AllocSplStr(PCWSTR pwszInput);
 PVOID WINAPI DllAllocSplMem(DWORD dwBytes);
@@ -69,5 +76,8 @@ BOOL WINAPI ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput);
 BOOL WINAPI SplInitializeWinSpoolDrv(PVOID* pTable);
 BOOL WINAPI SpoolerInit(VOID);
 PDWORD WINAPI UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded);
+BOOL WINAPI SplGetSpoolFileInfo(HANDLE hPrinter,HANDLE hProcessHandle,DWORD Level,FILE_INFO_1 *pFileInfo,DWORD dwSize,DWORD* dwNeeded );
+BOOL WINAPI SplCommitSpoolData(HANDLE hPrinter,HANDLE hProcessHandle,DWORD cbCommit,DWORD Level,FILE_INFO_1 *pFileInfo,DWORD dwSize,DWORD* dwNeeded);
+BOOL WINAPI SplCloseSpoolFileHandle( HANDLE hPrinter );
 
 #endif
index c919aea..e6981b0 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Local Spooler
  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
  * PURPOSE:     Functions related to Spool Files and printing
- * COPYRIGHT:   Copyright 1998-2020 ReactOS)
+ * COPYRIGHT:   Copyright 1998-2020 ReactOS
  */
 
 #include "precomp.h"