[PRINTING]
authorColin Finck <colin@reactos.org>
Fri, 5 Jun 2015 18:16:51 +0000 (18:16 +0000)
committerColin Finck <colin@reactos.org>
Fri, 5 Jun 2015 18:16:51 +0000 (18:16 +0000)
Add an include directory for all printing components containing definitions not found in the public headers.
For now, that's just PackStrings in spoolss.h.

[SPOOLSS_APITEST]
Use the new spoolss.h header.

[WINPRINT_APITEST]
Add an API-Test for the winprint Print Processor, so far for its EnumPrintProcessorDatatypesW function. Tests succeed in Windows Server 2003.
winspool.drv also provides functions that go into winprint.dll, but as these tests show, they behave slightly different in terms of error codes due to the involved RPC and routing.
Windows Server 2003 has winprint functions in localspl.dll, so you have to copy its localspl.dll to winprint.dll for testing.

[WINPRINT]
- Use PackStrings to simplify the code.
- Fix test failures.

svn path=/branches/colins-printing-for-freedom/; revision=68025

reactos/win32ss/printing/CMakeLists.txt
reactos/win32ss/printing/include/spoolss.h [new file with mode: 0644]
reactos/win32ss/printing/processors/winprint/CMakeLists.txt
reactos/win32ss/printing/processors/winprint/main.c
reactos/win32ss/printing/processors/winprint/precomp.h
rostests/apitests/CMakeLists.txt
rostests/apitests/spoolss/CMakeLists.txt
rostests/apitests/spoolss/PackStrings.c
rostests/apitests/winprint/CMakeLists.txt [new file with mode: 0644]
rostests/apitests/winprint/EnumPrintProcessorDatatypesW.c [new file with mode: 0644]
rostests/apitests/winprint/testlist.c [new file with mode: 0644]

index e7a2786..e91164d 100644 (file)
@@ -1,3 +1,5 @@
+include_directories(include)
+
 add_subdirectory(base)
 #add_subdirectory(drivers)
 add_subdirectory(monitors)
diff --git a/reactos/win32ss/printing/include/spoolss.h b/reactos/win32ss/printing/include/spoolss.h
new file mode 100644 (file)
index 0000000..ad8157d
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * PROJECT:     ReactOS Printing Include files
+ * LICENSE:     GNU LGPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Undocumented APIs of the Spooler Router "spoolss.dll"
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#ifndef _REACTOS_SPOOLSS_H
+#define _REACTOS_SPOOLSS_H
+
+PBYTE WINAPI
+PackStrings(PCWSTR* pSource, PBYTE pDest, PDWORD DestOffsets, PBYTE pEnd);
+
+#endif
index 1f422ec..199e7f9 100644 (file)
@@ -13,6 +13,6 @@ add_library(winprint SHARED
 
 set_module_type(winprint win32dll UNICODE)
 target_link_libraries(winprint wine)
-add_importlibs(winprint kernel32 msvcrt ntdll)
+add_importlibs(winprint spoolss msvcrt kernel32 ntdll)
 add_pch(winprint precomp.h SOURCE)
 add_cd_file(TARGET winprint DESTINATION reactos/system32/spool/prtprocs/w32x86 FOR all)
index 8c279a8..270065c 100644 (file)
@@ -48,18 +48,14 @@ PCWSTR pwszDatatypes[] = {
 BOOL WINAPI
 EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
-    DATATYPES_INFO_1W DatatypesInfo1;
     DWORD cbDatatype;
-    PBYTE pCurrentOutputDatatype;
-    PBYTE pCurrentOutputDatatypeInfo;
+    DWORD dwOffsets[_countof(pwszDatatypes)];
     PCWSTR* pCurrentDatatype;
+    PDWORD pCurrentOffset = dwOffsets;
 
     // Sanity checks
     if (Level != 1 || !pcbNeeded || !pcReturned)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
-    }
 
     // Count the required buffer size and the number of datatypes.
     *pcbNeeded = 0;
@@ -69,7 +65,12 @@ EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Lev
     {
         cbDatatype = (wcslen(*pCurrentDatatype) + 1) * sizeof(WCHAR);
         *pcbNeeded += sizeof(DATATYPES_INFO_1W) + cbDatatype;
+
+        // Also calculate the offset in the output buffer of the pointer to this datatype string.
+        *pCurrentOffset = *pcReturned * sizeof(DATATYPES_INFO_1W) + FIELD_OFFSET(DATATYPES_INFO_1W, pName);
+
         *pcReturned++;
+        pCurrentOffset++;
     }
 
     // Check if the supplied buffer is large enough.
@@ -79,25 +80,16 @@ EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Lev
         return FALSE;
     }
 
-    // Put the datatype strings right after the last DATATYPES_INFO_1W structure.
-    pCurrentOutputDatatypeInfo = pDatatypes;
-    pCurrentOutputDatatype = pDatatypes + *pcReturned * sizeof(DATATYPES_INFO_1W);
-
-    // Copy over all datatypes.
-    for (pCurrentDatatype = pwszDatatypes; *pCurrentDatatype; pCurrentDatatype++)
+    // Check if a buffer was supplied at all.
+    if (!pDatatypes)
     {
-        // Copy the datatype string into the output buffer.
-        cbDatatype = (wcslen(*pCurrentDatatype) + 1) * sizeof(WCHAR);
-        CopyMemory(pCurrentOutputDatatype, *pCurrentDatatype, cbDatatype);
-
-        // Fill and copy the DATATYPES_INFO_1W structure belonging to this datatype.
-        DatatypesInfo1.pName = (PWSTR)pCurrentOutputDatatype;
-        CopyMemory(pCurrentOutputDatatypeInfo, &DatatypesInfo1, sizeof(DATATYPES_INFO_1W));
-        
-        // Advance to the next DATATYPES_INFO_1W location and string location in the output buffer.
-        pCurrentOutputDatatype += cbDatatype;
-        pCurrentOutputDatatypeInfo += sizeof(DATATYPES_INFO_1W);
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
     }
 
+    // Copy over all datatypes.
+    *pCurrentOffset = MAXDWORD;
+    PackStrings(pwszDatatypes, pDatatypes, dwOffsets, &pDatatypes[*pcbNeeded]);
+
     return TRUE;
 }
index 7dce148..9ae0ecb 100644 (file)
@@ -9,6 +9,7 @@
 #define _PRECOMP_H
 
 #define WIN32_NO_STATUS
+#include <stdlib.h>
 #include <windef.h>
 #include <winbase.h>
 #include <wingdi.h>
@@ -16,6 +17,8 @@
 #include <winspool.h>
 #include <winsplp.h>
 
+#include <spoolss.h>
+
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(winprint);
 
index f57068b..f608c27 100644 (file)
@@ -25,5 +25,6 @@ if(NOT ARCH STREQUAL "amd64")
 endif()
 add_subdirectory(winhttp)
 add_subdirectory(wininet)
+add_subdirectory(winprint)
 add_subdirectory(winspool)
 add_subdirectory(ws2_32)
index 8ef98e1..8550695 100644 (file)
@@ -1,4 +1,6 @@
 
+include_directories(${REACTOS_SOURCE_DIR}/win32ss/printing/include)
+
 list(APPEND SOURCE
     PackStrings.c
     testlist.c)
index 28606f0..8f7c1a7 100644 (file)
@@ -10,8 +10,7 @@
 #define WIN32_NO_STATUS
 #include <windef.h>
 #include <winbase.h>
-
-PBYTE WINAPI PackStrings(PCWSTR*, PBYTE, PDWORD, PBYTE);
+#include <spoolss.h>
 
 typedef struct _EXAMPLE_STRUCT
 {
diff --git a/rostests/apitests/winprint/CMakeLists.txt b/rostests/apitests/winprint/CMakeLists.txt
new file mode 100644 (file)
index 0000000..68fa7d9
--- /dev/null
@@ -0,0 +1,10 @@
+
+list(APPEND SOURCE
+    EnumPrintProcessorDatatypesW.c
+    testlist.c)
+
+add_executable(winprint_apitest ${SOURCE})
+target_link_libraries(winprint_apitest wine ${PSEH_LIB})
+set_module_type(winprint_apitest win32cui)
+add_importlibs(winprint_apitest winprint msvcrt kernel32 ntdll)
+add_cd_file(TARGET winprint_apitest DESTINATION reactos/bin FOR all)
diff --git a/rostests/apitests/winprint/EnumPrintProcessorDatatypesW.c b/rostests/apitests/winprint/EnumPrintProcessorDatatypesW.c
new file mode 100644 (file)
index 0000000..551bfb9
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * PROJECT:     ReactOS Standard Print Processor API Tests
+ * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Tests for EnumPrintProcessorDatatypesW
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winspool.h>
+
+START_TEST(EnumPrintProcessorDatatypesW)
+{
+    DWORD cbNeeded;
+    DWORD cbTemp;
+    DWORD dwReturned;
+    PDATATYPES_INFO_1W pDatatypesInfo1;
+
+    // Try with an invalid level. The error needs to be set by winspool, but not by the Print Processor.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 0, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+    // Now try with valid level, but no pcbNeeded and no pcReturned. The error needs to be set by RPC.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, NULL, NULL), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+
+    // Now try with pcbNeeded and pcReturned, but give no Print Processor. Show that winprint actually ignores the given Print Processor.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    ok(cbNeeded > 0, "cbNeeded is 0!\n");
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // Same error has to occur when looking for an invalid Print Processor.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, L"invalid", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    ok(cbNeeded > 0, "cbNeeded is 0!\n");
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // Now get the required buffer size by supplying all information. This needs to fail with ERROR_INSUFFICIENT_BUFFER.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    ok(cbNeeded > 0, "cbNeeded is 0!\n");
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // Same error has to occur with a size to small.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, 1, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu!\n", GetLastError());
+    ok(cbNeeded > 0, "cbNeeded is 0!\n");
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // Now provide the demanded size, but no buffer. Show that winprint returns a different error than the same function in winspool.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    ok(cbTemp == cbNeeded, "cbTemp is %lu!\n", cbTemp);
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // This also has to fail the same way when no Print Processor was given at all.
+    SetLastError(0xDEADBEEF);
+    ok(!EnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, cbNeeded, &cbTemp, &dwReturned), "EnumPrintProcessorDatatypesW returns TRUE!\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    ok(cbTemp == cbNeeded, "cbTemp is %lu!\n", cbTemp);
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+    // Finally use the function as intended and aim for success! Show that winprint doesn't modify the error code at all.
+    pDatatypesInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+    SetLastError(0xDEADBEEF);
+    ok(EnumPrintProcessorDatatypesW(NULL, L"winprint", 1, (PBYTE)pDatatypesInfo1, cbNeeded, &cbNeeded, &dwReturned), "EnumPrintProcessorDatatypesW returns FALSE!\n");
+    ok(GetLastError() == 0xDEADBEEF, "EnumPrintProcessorDatatypesW returns error %lu!\n", GetLastError());
+    HeapFree(GetProcessHeap(), 0, pDatatypesInfo1);
+}
diff --git a/rostests/apitests/winprint/testlist.c b/rostests/apitests/winprint/testlist.c
new file mode 100644 (file)
index 0000000..1ad91ab
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * PROJECT:     ReactOS Standard Print Processor API Tests
+ * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Test list
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+/*
+ * These tests are developed and tested against the Windows Server 2003 counterpart of winprint.
+ * While ReactOS implements the Standard Print Processor in a separate module winprint.dll,
+ * Windows Server 2003 puts it into the Local Print Spooler localspl.dll.
+ *
+ * To test against Windows, simply run these tests under Windows Server 2003, but copy its
+ * localspl.dll to winprint.dll in advance.
+ *
+ * winspool.drv also provides functions that go into winprint.dll, but as these tests show,
+ * they behave slightly different in terms of error codes due to the involved RPC and routing.
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_EnumPrintProcessorDatatypesW(void);
+
+const struct test winetest_testlist[] =
+{
+    { "EnumPrintProcessorDatatypesW", func_EnumPrintProcessorDatatypesW },
+
+    { 0, 0 }
+};