Author: cfinck
Date: Mon Apr 17 13:40:51 2017
New Revision: 74350
URL:
http://svn.reactos.org/svn/reactos?rev=74350&view=rev
Log:
[WINSPOOL]
Added tests for some more basic and newly discovered corner cases of EnumPrintersW.
Modified:
trunk/rostests/apitests/winspool/EnumPrinters.c
Modified: trunk/rostests/apitests/winspool/EnumPrinters.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/winspool/EnumPri…
==============================================================================
--- trunk/rostests/apitests/winspool/EnumPrinters.c [iso-8859-1] (original)
+++ trunk/rostests/apitests/winspool/EnumPrinters.c [iso-8859-1] Mon Apr 17 13:40:51 2017
@@ -19,10 +19,23 @@
BYTE ZeroBuffer[50] = { 0 };
DWORD cbNeeded;
DWORD cbTemp;
+ DWORD cchComputerName;
DWORD dwReturned;
+ PPRINTER_INFO_1W pPrinterInfo1;
PVOID pMem;
- DWORD i;
- DWORD dwValidLevels[] = { 0, 1, 2, 4, 5 };
+ DWORD Level;
+ WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 2 + 1];
+
+ wszComputerName[0] = L'\\';
+ wszComputerName[1] = L'\\';
+ cchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
+ if (!GetComputerNameW(&wszComputerName[2], &cchComputerName))
+ {
+ skip("GetComputerNameW failed with error %lu!\n", GetLastError());
+ return;
+ }
+
+ cchComputerName += 2;
// Verify that EnumPrintersW returns success and zeroes all input variables even
though no flag has been specified.
memset(TempBuffer, 0xDE, sizeof(TempBuffer));
@@ -53,54 +66,160 @@
ok(cbNeeded == 0xDEADBEEF, "cbNeeded is %lu!\n", cbNeeded);
ok(dwReturned == 0xDEADBEEF, "dwReturned is %lu!\n", dwReturned);
- // Try for all valid levels. Level 0 is valid here and returns the
PRINTER_INFO_STRESS structure (documented in MS-RPRN).
- for (i = 0; i < sizeof(dwValidLevels) / sizeof(DWORD); i++)
+ // Try for all levels. Level 0 is valid here and returns the PRINTER_INFO_STRESS
structure (documented in MS-RPRN).
+ for (Level = 0; Level <= 5; Level++)
{
+ if (Level == 3)
+ continue;
+
// Try with no valid arguments at all.
SetLastError(0xDEADBEEF);
- ok(!EnumPrintersW(0, NULL, dwValidLevels[i], NULL, 0, NULL, NULL),
"EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
- ok(GetLastError() == RPC_X_NULL_REF_POINTER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
+ ok(!EnumPrintersW(0, NULL, Level, NULL, 0, NULL, NULL), "EnumPrintersW
returns TRUE for Level %lu!\n", Level);
+ ok(GetLastError() == RPC_X_NULL_REF_POINTER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), Level);
// It has to succeed if we supply the required pointers and query no
information.
SetLastError(0xDEADBEEF);
- ok(EnumPrintersW(0, NULL, dwValidLevels[i], NULL, 0, &cbNeeded,
&dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), dwValidLevels[i]);
- ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
dwValidLevels[i]);
- ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
dwValidLevels[i]);
+ ok(EnumPrintersW(0, NULL, Level, NULL, 0, &cbNeeded, &dwReturned),
"EnumPrintersW returns FALSE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
Level);
// This constant is from Windows 9x/ME times and mustn't work anymore.
SetLastError(0xDEADBEEF);
- ok(EnumPrintersW(PRINTER_ENUM_DEFAULT, NULL, dwValidLevels[i], NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), dwValidLevels[i]);
- ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
dwValidLevels[i]);
- ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
dwValidLevels[i]);
+ ok(EnumPrintersW(PRINTER_ENUM_DEFAULT, NULL, Level, NULL, 0, &cbNeeded,
&dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
Level);
// Now things get interesting. Let's query the buffer size for information
about the local printers.
SetLastError(0xDEADBEEF);
- ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
- ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n",
dwValidLevels[i]);
- ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
dwValidLevels[i]);
-
- // Same error has to occur with no buffer, but a size < 4 (AlignRpcPtr comes
into play here).
- SetLastError(0xDEADBEEF);
- ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 1,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
- ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n",
dwValidLevels[i]);
- ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
dwValidLevels[i]);
-
- // Now provide the demanded size, but no buffer.
- SetLastError(0xDEADBEEF);
- ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, cbNeeded,
&cbTemp, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
- ok(cbTemp == 0, "cbTemp is %lu for Level %lu!\n", cbTemp,
dwValidLevels[i]);
- ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
dwValidLevels[i]);
-
- // Finally use the function as intended and aim for success!
- pMem = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
- SetLastError(0xDEADBEEF);
- ok(EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], pMem, cbNeeded,
&cbTemp, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n",
dwValidLevels[i]);
- ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), dwValidLevels[i]);
- HeapFree(GetProcessHeap(), 0, pMem);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, 0, &cbNeeded,
&dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error
%lu for Level %lu!\n", GetLastError(), Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned,
Level);
+
+ // There need to be installed local printers for the next steps.
+ if (cbNeeded > 0)
+ {
+ // Same error has to occur with no buffer, but a size < 4 (AlignRpcPtr
comes into play here).
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, 1, &cbNeeded,
&dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // Now provide the demanded size, but no buffer.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, NULL, cbNeeded,
&cbTemp, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
Level);
+ ok(GetLastError() == ERROR_INVALID_USER_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbTemp == 0, "cbTemp is %lu for Level %lu!\n", cbTemp, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // Finally use the function as intended and aim for success!
+ // After that, cbTemp contains the needed buffer size without the computer
name prepended.
+ pMem = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ SetLastError(0xDEADBEEF);
+ ok(EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, Level, pMem, cbNeeded,
&cbTemp, &dwReturned), "EnumPrintersW returns FALSE for Level %lu!\n",
Level);
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu for
Level %lu!\n", GetLastError(), Level);
+ HeapFree(GetProcessHeap(), 0, pMem);
+
+ if (Level != 4)
+ {
+ // Show that the Name parameter is checked when PRINTER_ENUM_NAME is also
specified.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, L"LOREM
IPSUM", Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns
TRUE for Level %lu!\n", Level);
+ ok(GetLastError() != ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW
returns error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+ }
+
+ // Show that the structure is returned with its known size again when
PRINTER_ENUM_NAME is specified and Name
+ // is the (case-insensitively compared) name of the Local Print Provider.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, L"wInDoWs NT
Local Print Providor", Level, NULL, 0, &cbNeeded, &dwReturned),
"EnumPrintersW returns TRUE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == cbTemp, "cbNeeded is %lu, reference size is %lu for Level
%lu!\n", cbNeeded, cbTemp, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // Now we specify the correct "\\COMPUTERNAME" for Name.
+ // The returned structure should have some strings prepended with the
Computer Name and thus require a larger buffer.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, wszComputerName,
Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for
Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded > cbTemp, "cbNeeded is %lu, reference size is %lu for
Level %lu!\n", cbNeeded, cbTemp, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ if (Level != 4)
+ {
+ // This won't work when there is a trailing backslash (i.e.
"\\COMPUTERNAME\").
+ wszComputerName[cchComputerName++] = L'\\';
+ wszComputerName[cchComputerName] = 0;
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME,
wszComputerName, Level, NULL, 0, &cbNeeded, &dwReturned), "EnumPrintersW
returns TRUE for Level %lu!\n", Level);
+ ok(GetLastError() == ERROR_INVALID_NAME, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == 0, "cbNeeded is %lu for Level %lu!\n", cbNeeded,
Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+ wszComputerName[--cchComputerName] = 0;
+ }
+
+ // Now it gets funky. There are also cases where EnumPrintersW takes the Name
parameter into account,
+ // although PRINTER_ENUM_NAME is not given.
+ // A bogus Name without two backslashes is ignored.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, L"LOREM IPSUM", Level, NULL,
0, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level
%lu!\n", Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == cbTemp, "cbNeeded is %lu, reference size is %lu for Level
%lu!\n", cbNeeded, cbTemp, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // Specifying "\\COMPUTERNAME" again prepends it to some strings.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded > cbTemp, "cbNeeded is %lu, reference size is %lu for
Level %lu!\n", cbNeeded, cbTemp, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // Specifying "\\COMPUTERNAME\" also verifies the Computer Name,
but doesn't prepend it.
+ // This logic is crazy, and different to PRINTER_ENUM_NAME...
+ wszComputerName[cchComputerName++] = L'\\';
+ wszComputerName[cchComputerName] = 0;
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == cbTemp, "cbNeeded is %lu for Level %lu!\n",
cbNeeded, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+
+ // I can even put an additional bogus character after the trailing backslash,
doesn't change anything.
+ wszComputerName[cchComputerName++] = L'a';
+ wszComputerName[cchComputerName] = 0;
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, wszComputerName, Level, NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n",
Level);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns
error %lu for Level %lu!\n", GetLastError(), Level);
+ ok(cbNeeded == cbTemp, "cbNeeded is %lu for Level %lu!\n",
cbNeeded, Level);
+ ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n",
dwReturned, Level);
+ cchComputerName -= 2;
+ wszComputerName[cchComputerName] = 0;
+ }
+ else
+ {
+ skip("cbNeeded is 0 on Level %lu, skipping additional tests!\n",
Level);
+ }
}
+
+ // Using EnumPrintersW with PRINTER_ENUM_NAME, Level 1 and no Name must return
information about the Print Providers.
+ // First record must always be the Local Print Provider.
+ SetLastError(0xDEADBEEF);
+ ok(!EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, NULL, 0,
&cbNeeded, &dwReturned), "EnumPrintersW returns TRUE!\n");
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error
%lu!\n", GetLastError());
+ ok(cbNeeded > 0, "cbNeeded is 0!\n");
+ ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
+ SetLastError(0xDEADBEEF);
+ pPrinterInfo1 = (PPRINTER_INFO_1W)HeapAlloc(GetProcessHeap(), 0, cbNeeded);
+ ok(EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1,
(PBYTE)pPrinterInfo1, cbNeeded, &cbTemp, &dwReturned), "EnumPrintersW returns
FALSE!\n");
+ ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu!\n",
GetLastError());
+ ok(cbTemp == cbNeeded, "cbTemp is %lu, cbNeeded is %lu!\n", cbTemp,
cbNeeded);
+ ok(dwReturned > 0, "dwReturned is %lu!\n", dwReturned);
+ ok(!wcscmp(pPrinterInfo1->pName, L"Windows NT Local Print Providor"),
"pPrinterInfo1->pName is %S!\n", pPrinterInfo1->pName);
+ ok(!wcscmp(pPrinterInfo1->pComment, L"Locally connected Printers"),
"pPrinterInfo1->pComment is %S!\n", pPrinterInfo1->pComment);
+ ok(!wcscmp(pPrinterInfo1->pDescription, L"Windows NT Local Printers"),
"pPrinterInfo1->pDescription is %S!\n", pPrinterInfo1->pDescription);
+ HeapFree(GetProcessHeap(), 0, pPrinterInfo1);
}