From ecd7f83ffb4c6a915d5a7d3d77a61f1880c33ec1 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Fri, 5 Jun 2015 15:52:39 +0000 Subject: [PATCH] [SPOOLSS] 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 --- .../printing/base/spoolss/CMakeLists.txt | 3 +- .../printing/base/spoolss/spoolss.spec | 2 +- reactos/win32ss/printing/base/spoolss/tools.c | 70 +++++++++++++++++++ rostests/apitests/CMakeLists.txt | 1 + rostests/apitests/spoolss/CMakeLists.txt | 10 +++ rostests/apitests/spoolss/PackStrings.c | 48 +++++++++++++ rostests/apitests/spoolss/testlist.c | 20 ++++++ 7 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 reactos/win32ss/printing/base/spoolss/tools.c create mode 100644 rostests/apitests/spoolss/CMakeLists.txt create mode 100644 rostests/apitests/spoolss/PackStrings.c create mode 100644 rostests/apitests/spoolss/testlist.c diff --git a/reactos/win32ss/printing/base/spoolss/CMakeLists.txt b/reactos/win32ss/printing/base/spoolss/CMakeLists.txt index 476cbed5ed7..fbf989587a2 100644 --- a/reactos/win32ss/printing/base/spoolss/CMakeLists.txt +++ b/reactos/win32ss/printing/base/spoolss/CMakeLists.txt @@ -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} diff --git a/reactos/win32ss/printing/base/spoolss/spoolss.spec b/reactos/win32ss/printing/base/spoolss/spoolss.spec index e2685d9920f..16e4b153499 100644 --- a/reactos/win32ss/printing/base/spoolss/spoolss.spec +++ b/reactos/win32ss/printing/base/spoolss/spoolss.spec @@ -106,7 +106,7 @@ @ 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 index 00000000000..1aab33612f4 --- /dev/null +++ b/reactos/win32ss/printing/base/spoolss/tools.c @@ -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 + */ + +#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; +} diff --git a/rostests/apitests/CMakeLists.txt b/rostests/apitests/CMakeLists.txt index 792a98d319f..f57068b7905 100644 --- a/rostests/apitests/CMakeLists.txt +++ b/rostests/apitests/CMakeLists.txt @@ -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 index 00000000000..8ef98e1eb90 --- /dev/null +++ b/rostests/apitests/spoolss/CMakeLists.txt @@ -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 index 00000000000..28606f059e0 --- /dev/null +++ b/rostests/apitests/spoolss/PackStrings.c @@ -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 + */ + +#include + +#define WIN32_NO_STATUS +#include +#include + +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 index 00000000000..0b10a39b51e --- /dev/null +++ b/rostests/apitests/spoolss/testlist.c @@ -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 + */ + +#define __ROS_LONG64__ + +#define STANDALONE +#include + +extern void func_PackStrings(void); + +const struct test winetest_testlist[] = +{ + { "PackStrings", func_PackStrings }, + + { 0, 0 } +};