[PRINTING] Implement the undocumented MarshallDownStructure, MarshallDownStructuresAr...
[reactos.git] / modules / rostests / apitests / spoolss / MarshallDownStructuresArray.c
1 /*
2 * PROJECT: ReactOS Spooler Router API Tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Tests for MarshallDownStructuresArray
5 * COPYRIGHT: Copyright 2018 Colin Finck (colin@reactos.org)
6 */
7
8 #include <apitest.h>
9
10 #define WIN32_NO_STATUS
11 #include <windef.h>
12 #include <winbase.h>
13 #include <wingdi.h>
14 #include <winspool.h>
15 #include <ndk/rtlfuncs.h>
16
17 #include <spoolss.h>
18 #include <marshalling/marshalling.h>
19 #include <marshalling/ports.h>
20
21 START_TEST(MarshallDownStructuresArray)
22 {
23 const DWORD cElements = 2;
24 const DWORD dwPortInfo2Offsets[] = {
25 FIELD_OFFSET(PORT_INFO_2W, pPortName),
26 FIELD_OFFSET(PORT_INFO_2W, pMonitorName),
27 FIELD_OFFSET(PORT_INFO_2W, pDescription),
28 MAXDWORD
29 };
30
31 PPORT_INFO_2W pPortInfo2;
32 PPORT_INFO_2W pPortInfo2Copy;
33 PPORT_INFO_2W pPortInfo2Test;
34 PBYTE pPortInfoEnd;
35 PWSTR pwszStrings[] = { L"PortName", L"MonitorName", L"Description" };
36 DWORD cbPortInfo2Size = cElements * (sizeof(PORT_INFO_2W) + (wcslen(pwszStrings[0]) + 1 + wcslen(pwszStrings[1]) + 1 + wcslen(pwszStrings[2]) + 1) * sizeof(WCHAR));
37 DWORD fPortType = 1337;
38 DWORD Reserved = 42;
39
40 // Setting cElements to zero should yield success.
41 SetLastError(0xDEADBEEF);
42 ok(MarshallDownStructuresArray(NULL, 0, NULL, 0, FALSE), "MarshallDownStructuresArray returns FALSE!\n");
43 ok(GetLastError() == 0xDEADBEEF, "GetLastError returns %lu!\n", GetLastError());
44
45 // Setting cElements non-zero should fail with ERROR_INVALID_PARAMETER.
46 SetLastError(0xDEADBEEF);
47 ok(!MarshallDownStructuresArray(NULL, 1, NULL, 0, FALSE), "MarshallDownStructuresArray returns TRUE!\n");
48 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError returns %lu!\n", GetLastError());
49
50 // This is triggered by both pStructuresArray and pInfo.
51 SetLastError(0xDEADBEEF);
52 ok(!MarshallDownStructuresArray((PVOID)0xDEADDEAD, 1, NULL, 0, FALSE), "MarshallDownStructuresArray returns TRUE!\n");
53 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError returns %lu!\n", GetLastError());
54
55 SetLastError(0xDEADBEEF);
56 ok(!MarshallDownStructuresArray(NULL, 1, (const MARSHALLING_INFO*)0xDEADDEAD, 0, FALSE), "MarshallDownStructuresArray returns TRUE!\n");
57 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError returns %lu!\n", GetLastError());
58
59 // Now create two PORT_INFO_2W structures.
60 pPortInfo2 = (PPORT_INFO_2W)HeapAlloc(GetProcessHeap(), 0, cbPortInfo2Size);
61 pPortInfoEnd = (PBYTE)pPortInfo2 + cbPortInfo2Size;
62
63 (&pPortInfo2[0])->fPortType = fPortType;
64 (&pPortInfo2[0])->Reserved = Reserved;
65 pPortInfoEnd = PackStrings(pwszStrings, (PBYTE)(&pPortInfo2[0]), dwPortInfo2Offsets, pPortInfoEnd);
66
67 (&pPortInfo2[1])->fPortType = fPortType + 1;
68 (&pPortInfo2[1])->Reserved = Reserved + 1;
69 pPortInfoEnd = PackStrings(pwszStrings, (PBYTE)(&pPortInfo2[1]), dwPortInfo2Offsets, pPortInfoEnd);
70
71 // Create a backup.
72 pPortInfo2Copy = (PPORT_INFO_2W)HeapAlloc(GetProcessHeap(), 0, cbPortInfo2Size);
73 CopyMemory(pPortInfo2Copy, pPortInfo2, cbPortInfo2Size);
74
75 // Marshall them down.
76 SetLastError(0xDEADBEEF);
77 ok(MarshallDownStructuresArray(pPortInfo2, cElements, PortInfo2Marshalling.pInfo, PortInfo2Marshalling.cbStructureSize, TRUE), "MarshallDownStructuresArray returns FALSE!\n");
78 ok(GetLastError() == 0xDEADBEEF, "GetLastError returns %lu!\n", GetLastError());
79
80 // DWORD values should be unchanged.
81 ok((&pPortInfo2[0])->fPortType == fPortType, "fPortType is %lu!\n", (&pPortInfo2[0])->fPortType);
82 ok((&pPortInfo2[0])->Reserved == Reserved, "Reserved is %lu!\n", (&pPortInfo2[0])->Reserved);
83 ok((&pPortInfo2[1])->fPortType == fPortType + 1, "fPortType is %lu!\n", (&pPortInfo2[1])->fPortType);
84 ok((&pPortInfo2[1])->Reserved == Reserved + 1, "Reserved is %lu!\n", (&pPortInfo2[1])->Reserved);
85
86 // Pointers should now contain relative offsets.
87 ok((ULONG_PTR)(&pPortInfo2[0])->pPortName == ((ULONG_PTR)(&pPortInfo2Copy[0])->pPortName - (ULONG_PTR)(&pPortInfo2[0])), "pPortName is %p!\n", (&pPortInfo2[0])->pPortName);
88 ok((ULONG_PTR)(&pPortInfo2[0])->pMonitorName == ((ULONG_PTR)(&pPortInfo2Copy[0])->pMonitorName - (ULONG_PTR)(&pPortInfo2[0])), "pMonitorName is %p!\n", (&pPortInfo2[0])->pMonitorName);
89 ok((ULONG_PTR)(&pPortInfo2[0])->pDescription == ((ULONG_PTR)(&pPortInfo2Copy[0])->pDescription - (ULONG_PTR)(&pPortInfo2[0])), "pDescription is %p!\n", (&pPortInfo2[0])->pDescription);
90 ok((ULONG_PTR)(&pPortInfo2[1])->pPortName == ((ULONG_PTR)(&pPortInfo2Copy[1])->pPortName - (ULONG_PTR)(&pPortInfo2[1])), "pPortName is %p!\n", (&pPortInfo2[1])->pPortName);
91 ok((ULONG_PTR)(&pPortInfo2[1])->pMonitorName == ((ULONG_PTR)(&pPortInfo2Copy[1])->pMonitorName - (ULONG_PTR)(&pPortInfo2[1])), "pMonitorName is %p!\n", (&pPortInfo2[1])->pMonitorName);
92 ok((ULONG_PTR)(&pPortInfo2[1])->pDescription == ((ULONG_PTR)(&pPortInfo2Copy[1])->pDescription - (ULONG_PTR)(&pPortInfo2[1])), "pDescription is %p!\n", (&pPortInfo2[1])->pDescription);
93
94 // Marshall them up again.
95 // We need a backup of the marshalled down array to experiment with MarshallUpStructuresArray.
96 pPortInfo2Test = (PPORT_INFO_2W)HeapAlloc(GetProcessHeap(), 0, cbPortInfo2Size);
97 CopyMemory(pPortInfo2Test, pPortInfo2, cbPortInfo2Size);
98
99 // Due to the implementation of PackStrings, (&pPortInfo2[0])->pPortName contains the highest offset.
100 // Show that MarshallUpStructuresArray checks the offsets and bails out with ERROR_INVALID_DATA if cbSize <= highest offset.
101 SetLastError(0xDEADBEEF);
102 ok(!MarshallUpStructuresArray((DWORD)(&pPortInfo2[0])->pPortName, pPortInfo2Test, cElements, PortInfo2Marshalling.pInfo, PortInfo2Marshalling.cbStructureSize, TRUE), "MarshallUpStructuresArray returns TRUE!\n");
103 ok(GetLastError() == ERROR_INVALID_DATA, "GetLastError returns %lu!\n", GetLastError());
104
105 // It works with cbSize > highest offset.
106 // In real world cases, we would use cbPortInfo2Size for cbSize.
107 SetLastError(0xDEADBEEF);
108 ok(MarshallUpStructuresArray((DWORD)(&pPortInfo2[0])->pPortName + 1, pPortInfo2, cElements, PortInfo2Marshalling.pInfo, PortInfo2Marshalling.cbStructureSize, TRUE), "MarshallUpStructuresArray returns FALSE!\n");
109 ok(GetLastError() == 0xDEADBEEF, "GetLastError returns %lu!\n", GetLastError());
110
111 // pPortInfo2 should now be identical to the copy again.
112 ok(RtlEqualMemory(pPortInfo2, pPortInfo2Copy, cbPortInfo2Size), "pPortInfo2 and pPortInfo2Copy are not equal after marshalling down and up!\n");
113
114 // Free all memory.
115 HeapFree(GetProcessHeap(), 0, pPortInfo2);
116 HeapFree(GetProcessHeap(), 0, pPortInfo2Copy);
117 HeapFree(GetProcessHeap(), 0, pPortInfo2Test);
118 }