[SPOOLSS]
authorColin Finck <colin@reactos.org>
Fri, 5 Jun 2015 15:52:39 +0000 (15:52 +0000)
committerColin Finck <colin@reactos.org>
Fri, 5 Jun 2015 15:52:39 +0000 (15:52 +0000)
In an attempt to simplify the code for further functions that return information structures, implement and document the undocumented PackStrings function.
Hints were taken from an XP DDK sample and own testing.

[SPOOLSS_APITEST]
Add some tests for PackStrings that succeed under Windows Server 2003.

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

reactos/win32ss/printing/base/spoolss/CMakeLists.txt
reactos/win32ss/printing/base/spoolss/spoolss.spec
reactos/win32ss/printing/base/spoolss/tools.c [new file with mode: 0644]
rostests/apitests/CMakeLists.txt
rostests/apitests/spoolss/CMakeLists.txt [new file with mode: 0644]
rostests/apitests/spoolss/PackStrings.c [new file with mode: 0644]
rostests/apitests/spoolss/testlist.c [new file with mode: 0644]

index 476cbed..fbf9895 100644 (file)
@@ -4,7 +4,8 @@ spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB)
 list(APPEND SOURCE
     context.c
     main.c
-    precomp.h)
+    precomp.h
+    tools.c)
 
 add_library(spoolss SHARED
     ${SOURCE}
index e2685d9..16e4b15 100644 (file)
 @ stub OpenPrinterExW
 @ stub OpenPrinterPortW
 @ stdcall OpenPrinterW(wstr ptr ptr)
-@ stub PackStrings
+@ stdcall PackStrings(ptr ptr ptr ptr)
 @ stub PartialReplyPrinterChangeNotification
 @ stub PlayGdiScriptOnPrinterIC
 @ stub PrinterHandleRundown
diff --git a/reactos/win32ss/printing/base/spoolss/tools.c b/reactos/win32ss/printing/base/spoolss/tools.c
new file mode 100644 (file)
index 0000000..1aab336
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * PROJECT:     ReactOS Spooler Router
+ * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Miscellaneous tool functions
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include "precomp.h"
+
+
+/**
+ * @name PackStrings
+ *
+ * Takes an array of Unicode strings and fills an output buffer with these strings at the end and pointers to each string at specific offsets.
+ * Useful helper for functions that copy an information structure including strings into a given buffer (like PRINTER_INFO_1).
+ *
+ * @param pSource
+ * The array of Unicode strings to copy. Needs to have at least as many elements as the DestOffsets array.
+ *
+ * @param pDest
+ * Pointer to the beginning of the output buffer.
+ * The caller is responsible for verifying that this buffer is large enough to hold all strings and pointers.
+ *
+ * @param DestOffsets
+ * Array of byte offsets in the output buffer. For each element of DestOffsets, the function will copy the address of the corresponding copied
+ * string of pSource to this location in the output buffer. If a string in pSource is NULL, the function will set the pointer address to NULL
+ * in the output buffer.
+ * Use macros like FIELD_OFFSET to calculate the offsets for this array.
+ * The last element of the array must have the value MAXDWORD to let the function detect the end of the array.
+ *
+ * @param pEnd
+ * Pointer to the end of the output buffer. That means the first element outside of the buffer given in pDest.
+ *
+ * @return
+ * Returns a pointer to the beginning of the strings in pDest.
+ * The strings are copied in reverse order, so this pointer will point to the last copied string of pSource.
+ */
+PBYTE WINAPI
+PackStrings(PCWSTR* pSource, PBYTE pDest, PDWORD DestOffsets, PBYTE pEnd)
+{
+    DWORD cbString;
+    ULONG_PTR StringAddress;
+
+    // Loop until we reach an element with offset set to MAXDWORD.
+    while (*DestOffsets != MAXDWORD)
+    {
+        StringAddress = 0;
+
+        if (*pSource)
+        {
+            // Determine the length of the source string.
+            cbString = (wcslen(*pSource) + 1) * sizeof(WCHAR);
+
+            // Copy it before the last string.
+            pEnd -= cbString;
+            StringAddress = (ULONG_PTR)pEnd;
+            CopyMemory(pEnd, *pSource, cbString);
+        }
+
+        // Copy the address of the copied string to the location given by the offset.
+        CopyMemory(&pDest[*DestOffsets], &StringAddress, sizeof(ULONG_PTR));
+
+        // Advance to the next source string and destination offset.
+        pSource++;
+        DestOffsets++;
+    }
+
+    // pEnd is now at the last string we copied. Return this value as a pointer to the beginning of all strings in the output buffer.
+    return pEnd;
+}
index 792a98d..f57068b 100644 (file)
@@ -17,6 +17,7 @@ add_subdirectory(powrprof)
 add_subdirectory(setupapi)
 add_subdirectory(shell32)
 add_subdirectory(psapi)
+add_subdirectory(spoolss)
 add_subdirectory(user32)
 if(NOT ARCH STREQUAL "amd64")
     add_subdirectory(w32kdll)
diff --git a/rostests/apitests/spoolss/CMakeLists.txt b/rostests/apitests/spoolss/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8ef98e1
--- /dev/null
@@ -0,0 +1,10 @@
+
+list(APPEND SOURCE
+    PackStrings.c
+    testlist.c)
+
+add_executable(spoolss_apitest ${SOURCE})
+target_link_libraries(spoolss_apitest wine ${PSEH_LIB})
+set_module_type(spoolss_apitest win32cui)
+add_importlibs(spoolss_apitest spoolss msvcrt kernel32 ntdll)
+add_cd_file(TARGET spoolss_apitest DESTINATION reactos/bin FOR all)
diff --git a/rostests/apitests/spoolss/PackStrings.c b/rostests/apitests/spoolss/PackStrings.c
new file mode 100644 (file)
index 0000000..28606f0
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * PROJECT:     ReactOS Spooler Router API Tests
+ * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
+ * PURPOSE:     Tests for PackStrings
+ * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ */
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+
+PBYTE WINAPI PackStrings(PCWSTR*, PBYTE, PDWORD, PBYTE);
+
+typedef struct _EXAMPLE_STRUCT
+{
+    PWSTR String1;
+    PWSTR String2;
+}
+EXAMPLE_STRUCT, *PEXAMPLE_STRUCT;
+
+START_TEST(PackStrings)
+{
+    PCWSTR Source1[] = { L"Test", L"String" };
+    PCWSTR Source2[] = { L"Test", NULL };
+
+    BYTE Buffer[50];
+    PBYTE pEnd;
+    PEXAMPLE_STRUCT pStruct = (PEXAMPLE_STRUCT)Buffer;
+    DWORD Offsets[] = {
+        FIELD_OFFSET(EXAMPLE_STRUCT, String1),
+        FIELD_OFFSET(EXAMPLE_STRUCT, String2),
+        MAXDWORD
+    };
+    
+    // Try a usual case with two strings. Verify that they are copied in reverse order.
+    pEnd = PackStrings(Source1, Buffer, Offsets, &Buffer[sizeof(Buffer)]);
+    ok(wcscmp(pStruct->String1, Source1[0]) == 0, "String1 and Source1[0] don't match!\n");
+    ok(wcscmp(pStruct->String2, Source1[1]) == 0, "String2 and Source1[1] don't match!\n");
+    ok(wcscmp((PWSTR)pEnd, Source1[1]) == 0, "pEnd and Source1[1] don't match!\n");
+
+    // Now verify that the corresponding pointer is set to NULL if a string is NULL.
+    pEnd = PackStrings(Source2, Buffer, Offsets, &Buffer[sizeof(Buffer)]);
+    ok(wcscmp(pStruct->String1, Source2[0]) == 0, "String1 and Source2[0] don't match!\n");
+    ok(!pStruct->String2, "String2 is %p!\n", pStruct->String2);
+    ok(wcscmp((PWSTR)pEnd, Source2[0]) == 0, "pEnd and Source2[0] don't match!\n");
+}
diff --git a/rostests/apitests/spoolss/testlist.c b/rostests/apitests/spoolss/testlist.c
new file mode 100644 (file)
index 0000000..0b10a39
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * PROJECT:     ReactOS Print Spooler Router 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>
+ */
+
+#define __ROS_LONG64__
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_PackStrings(void);
+
+const struct test winetest_testlist[] =
+{
+    { "PackStrings", func_PackStrings },
+
+    { 0, 0 }
+};