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 PCWSTR 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, pPortInfoMarshalling[2]->pInfo, pPortInfoMarshalling[2]->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, pPortInfoMarshalling[2]->pInfo, pPortInfoMarshalling[2]->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, pPortInfoMarshalling[2]->pInfo, pPortInfoMarshalling[2]->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 } 119