[winspool 1/6] Revise EnumPrinterDriversW to fix the incorrect handling of 'all'. EnumPrinterDriversA is similarly fixed by using EnumPrinterDriversW.

Jeremy White jwhite at codeweavers.com
Tue Dec 1 10:46:07 CST 2009


---
 dlls/winspool.drv/info.c       |  169 +++++++++++++++++++++++-----------------
 dlls/winspool.drv/tests/info.c |    2 -
 2 files changed, 96 insertions(+), 75 deletions(-)

diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index aa6f305..313514f 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -4838,45 +4838,22 @@ BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
  */
 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
                                         DWORD Level, LPBYTE pDriverInfo,
+                                        DWORD driver_index,
                                         DWORD cbBuf, LPDWORD pcbNeeded,
-                                        LPDWORD pcReturned, BOOL unicode)
+                                        LPDWORD pcFound, DWORD data_offset)
 
 {   HKEY  hkeyDrivers;
-    DWORD i, needed, number = 0, size = 0;
-    WCHAR DriverNameW[255];
-    PBYTE ptr;
+    DWORD i, size = 0;
     const printenv_t * env;
 
-    TRACE("%s,%s,%d,%p,%d,%d\n",
+    TRACE("%s,%s,%d,%p,%d,%d,%d\n",
           debugstr_w(pName), debugstr_w(pEnvironment),
-          Level, pDriverInfo, cbBuf, unicode);
-
-    /* check for local drivers */
-    if((pName) && (pName[0])) {
-        FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
-        SetLastError(ERROR_ACCESS_DENIED);
-        return FALSE;
-    }
+          Level, pDriverInfo, driver_index, cbBuf, data_offset);
 
     env = validate_envW(pEnvironment);
     if (!env) return FALSE;     /* SetLastError() is in validate_envW */
 
-    /* check input parameter */
-    if ((Level < 1) || (Level == 7) || (Level > 8)) {
-        SetLastError(ERROR_INVALID_LEVEL);
-        return FALSE;
-    }
-
-    if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
-        SetLastError(RPC_X_NULL_REF_POINTER);
-        return FALSE;
-    }
-
-    /* initialize return values */
-    if(pDriverInfo)
-        memset( pDriverInfo, 0, cbBuf);
-    *pcbNeeded  = 0;
-    *pcReturned = 0;
+    *pcFound = 0;
 
     hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
     if(!hkeyDrivers) {
@@ -4884,39 +4861,49 @@ static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
         return FALSE;
     }
 
-    if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
+    if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
                         NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
         RegCloseKey(hkeyDrivers);
         ERR("Can't query Drivers key\n");
         return FALSE;
     }
-    TRACE("Found %d Drivers\n", number);
+    TRACE("Found %d Drivers\n", *pcFound);
 
     /* get size of single struct
      * unicode and ascii structure have the same size
      */
     size = di_sizeof[Level];
 
-    /* calculate required buffer size */
-    *pcbNeeded = size * number;
+    if (data_offset == 0)
+        data_offset = size * (*pcFound);
+    *pcbNeeded = data_offset;
+
+    for( i = 0; i < *pcFound; i++) {
+        WCHAR DriverNameW[255];
+        PBYTE table_ptr = NULL;
+        PBYTE data_ptr = NULL;
+        DWORD needed = 0;
 
-    for( i = 0,  ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
-         i < number;
-         i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
         if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
                        != ERROR_SUCCESS) {
             ERR("Can't enum key number %d\n", i);
             RegCloseKey(hkeyDrivers);
             return FALSE;
         }
+
+        if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
+            table_ptr = pDriverInfo + (driver_index + i) * size;
+        if (pDriverInfo && *pcbNeeded <= cbBuf)
+            data_ptr = pDriverInfo + *pcbNeeded;
+
         if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
-                         env, Level, ptr,
-                         (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
+                         env, Level, table_ptr, data_ptr,
                          (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
-                         &needed, unicode)) {
+                         &needed, TRUE)) {
             RegCloseKey(hkeyDrivers);
             return FALSE;
         }
+
         *pcbNeeded += needed;
     }
 
@@ -4927,7 +4914,6 @@ static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
         return FALSE;
     }
 
-    *pcReturned = number;
     return TRUE;
 }
 
@@ -4941,30 +4927,78 @@ BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
                                 LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
     static const WCHAR allW[] = {'a','l','l',0};
+    BOOL ret;
+    DWORD found;
+
+    if ((pcbNeeded == NULL) || (pcReturned == NULL))
+    {
+        SetLastError(RPC_X_NULL_REF_POINTER);
+        return FALSE;
+    }
+
+    /* check for local drivers */
+    if((pName) && (pName[0])) {
+        FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
+        SetLastError(ERROR_ACCESS_DENIED);
+        return FALSE;
+    }
+
+    /* check input parameter */
+    if ((Level < 1) || (Level == 7) || (Level > 8)) {
+        SetLastError(ERROR_INVALID_LEVEL);
+        return FALSE;
+    }
 
+    if(pDriverInfo && cbBuf > 0)
+        memset( pDriverInfo, 0, cbBuf);
+
+    /* Exception:  pull all printers */
     if (pEnvironment && !strcmpW(pEnvironment, allW))
     {
-        BOOL ret;
-        DWORD i, needed, returned, bufsize = cbBuf;
+        DWORD i, needed, bufsize = cbBuf;
+        DWORD total_needed = 0;
+        DWORD total_found = 0;
+        DWORD data_offset;
 
+        /* Precompute the overall total; we need this to know
+           where pointers end and data begins (i.e. data_offset) */
         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
         {
-            needed = returned = 0;
+            needed = found = 0;
             ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
-                                              pDriverInfo, bufsize, &needed, &returned, TRUE);
+                                              NULL, 0, 0, &needed, &found, 0);
+            if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
+            total_needed += needed;
+            total_found += found;
+        }
+
+        data_offset = di_sizeof[Level] * total_found;
+
+        *pcReturned = 0;
+        *pcbNeeded = 0;
+        total_found = 0;
+        for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
+        {
+            needed = found = 0;
+            ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
+                                              pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
             if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
             else if (ret)
-            {
-                bufsize -= needed;
-                if (pDriverInfo) pDriverInfo += needed;
-                if (pcReturned) *pcReturned += returned;
-            }
-            if (pcbNeeded) *pcbNeeded += needed;
+                *pcReturned += found;
+            *pcbNeeded = needed;
+            data_offset = needed;
+            total_found += found;
         }
         return ret;
     }
-    return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
-                                       cbBuf, pcbNeeded, pcReturned, TRUE);
+
+    /* Normal behavior */
+    ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
+                                       0, cbBuf, pcbNeeded, &found, 0);
+    if (ret)
+        *pcReturned = found;
+
+    return ret;
 }
 
 /*****************************************************************************
@@ -4979,32 +5013,21 @@ BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
     BOOL ret;
     UNICODE_STRING pNameW, pEnvironmentW;
     PWSTR pwstrNameW, pwstrEnvironmentW;
+    LPBYTE buf = NULL;
+
+    if (cbBuf)
+        buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
 
     pwstrNameW = asciitounicode(&pNameW, pName);
     pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
 
-    if (pEnvironment && !strcmp(pEnvironment, "all"))
-    {
-        DWORD i, needed, returned, bufsize = cbBuf;
+    ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
+                                buf, cbBuf, pcbNeeded, pcReturned);
+    if (ret)
+        convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
+
+    HeapFree(GetProcessHeap(), 0, buf);
 
-        for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
-        {
-            needed = returned = 0;
-            ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
-                                              pDriverInfo, bufsize, &needed, &returned, FALSE);
-            if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
-            else if (ret)
-            {
-                bufsize -= needed;
-                if (pDriverInfo) pDriverInfo += needed;
-                if (pcReturned) *pcReturned += returned;
-            }
-            if (pcbNeeded) *pcbNeeded += needed;
-        }
-    }
-    else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
-                                           Level, pDriverInfo, cbBuf, pcbNeeded,
-                                           pcReturned, FALSE);
     RtlFreeUnicodeString(&pNameW);
     RtlFreeUnicodeString(&pEnvironmentW);
 
diff --git a/dlls/winspool.drv/tests/info.c b/dlls/winspool.drv/tests/info.c
index 7d2631f..ef726f4 100644
--- a/dlls/winspool.drv/tests/info.c
+++ b/dlls/winspool.drv/tests/info.c
@@ -1161,7 +1161,6 @@ static void test_EnumPrinterDrivers(void)
             DWORD double_needed;
             DWORD double_returned;
             pEnumPrinterDriversW(NULL, NULL, level, NULL, 0, &double_needed, &double_returned);
-            todo_wine
             ok(double_needed == cbBuf, "level %d: EnumPrinterDriversA returned different size %d than EnumPrinterDriversW (%d)\n", level, cbBuf, double_needed);
         }
 
@@ -1248,7 +1247,6 @@ static void test_EnumPrinterDrivers(void)
     if (res && pcReturned > 0)
     {
         DRIVER_INFO_1 *di_1 = (DRIVER_INFO_1 *)buffer;
-        todo_wine
         ok((LPBYTE) di_1->pName == NULL || (LPBYTE) di_1->pName < buffer ||
             (LPBYTE) di_1->pName >= (LPBYTE)(di_1 + pcReturned),
             "Driver Information not in sequence; pName %p, top of data %p\n",



More information about the wine-patches mailing list