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/EnumPrinters.c?rev=74350&r1=74349&r2=74350&view=diff
==============================================================================
--- 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);
 }


Reply via email to