[PRINTING] Implement the undocumented MarshallDownStructure, MarshallDownStructuresArray, MarshallUpStructure, and MarshallUpStructuresArray to the extent I need and could find out through black-box testing.

PDBs reveal that these functions are also used in winspool.drv, but not imported from spoolss.dll to retain the client/server architecture.
As winspool.drv highly benefits from the MarshallUp* functions, I put them in a source file shared between spoolss.dll and winspool.drv.

The added API Tests cover my testing and all implemented features.
One more item done from https://reactos.org/wiki/Printing !
This commit is contained in:
Colin Finck 2018-01-17 10:13:25 +01:00
parent 2ae756a4e5
commit f3ea8225cb
15 changed files with 445 additions and 55 deletions

View file

@ -0,0 +1,212 @@
/*
* PROJECT: ReactOS Printing Stack Marshalling Functions
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Marshalling functions
* COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
*/
/**
* @name MarshallDownStructure
*
* Prepare a structure for marshalling/serialization by replacing absolute pointer addresses in its fields by relative offsets.
*
* @param pStructure
* Pointer to the structure to operate on.
*
* @param pInfo
* Array of MARSHALLING_INFO elements containing information about the fields of the structure as well as how to modify them.
* See the documentation on MARSHALLING_INFO for more information.
* You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
*
* @param cbStructureSize
* Size in bytes of the structure.
* This parameter is unused in my implementation.
*
* @param bSomeBoolean
* Unknown boolean value, set to TRUE.
*
* @return
* TRUE if the structure was successfully adjusted, FALSE otherwise.
*/
BOOL WINAPI
MarshallDownStructure(PVOID pStructure, const MARSHALLING_INFO* pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
{
// Sanity checks
if (!pStructure || !pInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Loop until we reach an element with offset set to MAXDWORD.
while (pInfo->dwOffset != MAXDWORD)
{
PULONG_PTR pCurrentField = (PULONG_PTR)((PBYTE)pStructure + pInfo->dwOffset);
if (pInfo->bAdjustAddress && *pCurrentField)
{
// Make a relative offset out of the absolute pointer address.
*pCurrentField -= (ULONG_PTR)pStructure;
}
// Advance to the next field description.
pInfo++;
}
return TRUE;
}
/**
* @name MarshallDownStructuresArray
*
* Prepare an array of structures for marshalling/serialization by replacing absolute pointer addresses in its fields by relative offsets.
*
* @param pStructuresArray
* Pointer to the array of structures to operate on.
*
* @param cElements
* Number of array elements.
*
* @param pInfo
* Array of MARSHALLING_INFO elements containing information about the fields of the structure as well as how to modify them.
* See the documentation on MARSHALLING_INFO for more information.
* You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
*
* @param cbStructureSize
* Size in bytes of each structure array element.
*
* @param bSomeBoolean
* Unknown boolean value, set to TRUE.
*
* @return
* TRUE if the array was successfully adjusted, FALSE otherwise.
*/
BOOL WINAPI
MarshallDownStructuresArray(PVOID pStructuresArray, DWORD cElements, const MARSHALLING_INFO* pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
{
PBYTE pCurrentElement = pStructuresArray;
// Call MarshallDownStructure on all array elements given by cElements of cbStructureSize.
while (cElements--)
{
if (!MarshallDownStructure(pCurrentElement, pInfo, cbStructureSize, bSomeBoolean))
return FALSE;
// Advance to the next array element.
pCurrentElement += cbStructureSize;
}
return TRUE;
}
/**
* @name MarshallUpStructure
*
* Unmarshall/deserialize a structure previuosly marshalled by MarshallDownStructure by replacing relative offsets in its fields
* by absolute pointer addresses again.
*
* @param cbSize
* Size in bytes of the memory allocated for both the structure and its data.
* The function will check if all relative offsets are within the bounds given by this size.
*
* @param pStructure
* Pointer to the structure to operate on.
*
* @param pInfo
* Array of MARSHALLING_INFO elements containing information about the fields of the structure as well as how to modify them.
* See the documentation on MARSHALLING_INFO for more information.
* You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
*
* @param cbStructureSize
* Size in bytes of the structure.
* This parameter is unused in my implementation.
*
* @param bSomeBoolean
* Unknown boolean value, set to TRUE.
*
* @return
* TRUE if the structure was successfully adjusted, FALSE otherwise.
*/
BOOL WINAPI
MarshallUpStructure(DWORD cbSize, PVOID pStructure, const MARSHALLING_INFO* pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
{
// Sanity checks
if (!pStructure || !pInfo)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Loop until we reach an element with offset set to MAXDWORD.
while (pInfo->dwOffset != MAXDWORD)
{
PULONG_PTR pCurrentField = (PULONG_PTR)((PBYTE)pStructure + pInfo->dwOffset);
if (pInfo->bAdjustAddress && *pCurrentField)
{
// Verify that the offset in the current field is within the bounds given by cbSize.
if (cbSize <= *pCurrentField)
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
// Make an absolute pointer address out of the relative offset.
*pCurrentField += (ULONG_PTR)pStructure;
}
// Advance to the next field description.
pInfo++;
}
return TRUE;
}
/**
* @name MarshallUpStructuresArray
*
* Unmarshall/deserialize an array of structures previuosly marshalled by MarshallDownStructuresArray by replacing relative offsets
* in its fields by absolute pointer addresses again.
*
* @param cbSize
* Size in bytes of the memory allocated for the entire structure array and its data.
* The function will check if all relative offsets are within the bounds given by this size.
*
* @param pStructuresArray
* Pointer to the array of structures to operate on.
*
* @param cElements
* Number of array elements.
*
* @param pInfo
* Array of MARSHALLING_INFO elements containing information about the fields of the structure as well as how to modify them.
* See the documentation on MARSHALLING_INFO for more information.
* You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
*
* @param cbStructureSize
* Size in bytes of each structure array element.
*
* @param bSomeBoolean
* Unknown boolean value, set to TRUE.
*
* @return
* TRUE if the array was successfully adjusted, FALSE otherwise.
*/
BOOL WINAPI
MarshallUpStructuresArray(DWORD cbSize, PVOID pStructuresArray, DWORD cElements, const MARSHALLING_INFO* pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
{
PBYTE pCurrentElement = pStructuresArray;
// Call MarshallUpStructure on all array elements given by cElements of cbStructureSize.
while (cElements--)
{
if (!MarshallUpStructure(cbSize, pCurrentElement, pInfo, cbStructureSize, bSomeBoolean))
return FALSE;
// Advance to the next array element.
pCurrentElement += cbStructureSize;
}
return TRUE;
}

View file

@ -2,6 +2,7 @@
spec2def(spoolss.dll spoolss.spec ADD_IMPORTLIB)
list(APPEND SOURCE
../marshalling.c
context.c
jobs.c
main.c

View file

@ -18,6 +18,7 @@
#include <ndk/rtlfuncs.h>
#include <spoolss.h>
#include <marshalling/marshalling.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(spoolss);

View file

@ -97,9 +97,9 @@
@ stub LoadDriverWithVersion
@ stub LogWmiTraceEvent
@ stdcall MarshallDownStructure(ptr ptr long long)
@ stub MarshallDownStructuresArray
@ stub MarshallUpStructure
@ stub MarshallUpStructuresArray
@ stdcall MarshallDownStructuresArray(ptr long ptr long long)
@ stdcall MarshallUpStructure(long ptr ptr long long)
@ stdcall MarshallUpStructuresArray(long ptr long ptr long long)
@ stub MIDL_user_allocate1
@ stub MIDL_user_free1
@ stub OldGetPrinterDriverW

View file

@ -8,56 +8,6 @@
#include "precomp.h"
/**
* @name MarshallDownStructure
*
* Prepare a structure for marshalling/serialization by replacing absolute pointer addresses in its fields by relative offsets.
*
* @param pStructure
* Pointer to the structure to operate on.
*
* @param pParameters
* Array of MARSHALL_DOWN_INFO elements containing information about the fields of the structure as well as how to modify them.
* See the documentation on MARSHALL_DOWN_INFO for more information.
* You have to indicate the end of the array by setting the dwOffset field to MAXDWORD.
*
* @param cbStructureSize
* Apparently, this is the size in bytes of the structure given through pStructure under Windows.
* This parameter is unused in my implementation.
*
* @param bSomeBoolean
* Unknown boolean value
*
* @return
* TRUE if the structure was successfully adjusted, FALSE otherwise.
*/
BOOL WINAPI
MarshallDownStructure(PVOID pStructure, PMARSHALL_DOWN_INFO pParameters, DWORD cbStructureSize, BOOL bSomeBoolean)
{
// Sanity checks
if (!pStructure || !pParameters)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Loop until we reach an element with offset set to MAXDWORD.
while (pParameters->dwOffset != MAXDWORD)
{
if (pParameters->bAdjustAddress)
{
// Apply the byte offset on pStructure. There must be a pointer at this position, whose address we're adjusting
// by subtracting the address of pStructure from it.
*((PULONG_PTR)((PBYTE)pStructure + pParameters->dwOffset)) -= (ULONG_PTR)pStructure;
}
// Advance to the next element description.
pParameters++;
}
return TRUE;
}
/**
* @name PackStrings
*

View file

@ -17,8 +17,10 @@
#include <winspool.h>
#include <winsplp.h>
#include <winspool_s.h>
#include <ndk/rtlfuncs.h>
#include <spoolss.h>
#include <marshalling/marshalling.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);

View file

@ -4,6 +4,7 @@ add_rpc_files(client ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/winspool.idl)
spec2def(winspool.drv winspool.spec ADD_IMPORTLIB)
list(APPEND SOURCE
../marshalling.c
devmode.c
forms.c
jobs.c

View file

@ -15,8 +15,10 @@
#include <winreg.h>
#include <winspool.h>
#include <winspool_c.h>
#include <ndk/rtlfuncs.h>
#include <spoolss.h>
#include <marshalling/marshalling.h>
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(winspool);