[PATCH] localspl: Implement fpEnumPrinters

Detlef Riekenberg wine.dev at web.de
Sun Mar 9 18:00:05 CDT 2008


---
 dlls/localspl/Makefile.in     |    2 +-
 dlls/localspl/localspl_main.c |  779 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 778 insertions(+), 3 deletions(-)

diff --git a/dlls/localspl/Makefile.in b/dlls/localspl/Makefile.in
index c3691e8..d6a468c 100644
--- a/dlls/localspl/Makefile.in
+++ b/dlls/localspl/Makefile.in
@@ -3,7 +3,7 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = localspl.dll
-IMPORTS   = spoolss user32 advapi32 kernel32
+IMPORTS   = spoolss user32 advapi32 kernel32 gdi32
 
 C_SRCS = \
 	localmon.c \
diff --git a/dlls/localspl/localspl_main.c b/dlls/localspl/localspl_main.c
index 77fb730..fcc132f 100644
--- a/dlls/localspl/localspl_main.c
+++ b/dlls/localspl/localspl_main.c
@@ -62,12 +62,14 @@ HINSTANCE LOCALSPL_hInstance = NULL;
 
 static const PRINTPROVIDOR * pp = NULL;
 
-
+static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
 static const WCHAR backslashW[] = {'\\',0};
 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
+static const WCHAR default_priorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
+
 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
@@ -88,7 +90,21 @@ static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
 static const WCHAR portW[] = {'P','o','r','t',0};
 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
+static const WCHAR printer_driverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
+static const WCHAR printers_connectionsW[] = {'P','r','i','n','t','e','r','s','\\',
+                                              'C','o','n','n','e','c','t','i','o','n','s',0};
+static const WCHAR print_printersW[] = { 'S','y','s','t','e','m','\\',
+                                  'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+                                  'c','o','n','t','r','o','l','\\',
+                                  'P','r','i','n','t','\\','P','r','i','n','t','e','r','s',0};
+static const WCHAR print_processorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
+static const WCHAR priorityW[] = {'P','r','i','o','r','i','t','y',0};
+static const WCHAR separator_fileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
+static const WCHAR share_nameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
+static const WCHAR starttimeW[] = {'S','t','a','r','t','T','i','m','e',0};
+static const WCHAR statusW[] = {'S','t','a','t','u','s',0};
+static const WCHAR untiltimeW[] = {'U','n','t','i','l','T','i','m','e',0};
 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
 
 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
@@ -116,6 +132,12 @@ static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_
                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
                                   0, sizeof(DRIVER_INFO_8W)};
 
+static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
+                                     sizeof(PRINTER_INFO_3),  sizeof(PRINTER_INFO_4W),
+                                     sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
+                                     sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
+                                     sizeof(PRINTER_INFO_9W)};
+
 /******************************************************************
  *  apd_copyfile [internal]
  *
@@ -218,6 +240,666 @@ static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
     return 0;
 }
 
+/*****************************************************************************
+ * get_devmode_type (INTERNAL)
+ *
+ * RETURNS
+ *  Failure: 0
+ *  Success: sizeof(DEVMODEW) for UNICODE, sizeof(DEVMODEA) for ANSI
+ *
+ */
+static DWORD get_devmode_type(LPBYTE ptr, DWORD len)
+{
+    LPDEVMODEW dmW = (LPDEVMODEW) ptr;
+    LPDEVMODEA dmA = (LPDEVMODEA) ptr;
+
+    TRACE("expect %d+%d (%d) or %d+%d (%d) for %p (have %d): %s\n", 
+            dmW->dmSize, dmW->dmDriverExtra, dmW->dmSize + dmW->dmDriverExtra,
+            dmA->dmSize, dmA->dmDriverExtra, dmA->dmSize + dmA->dmDriverExtra, 
+            ptr, len, debugstr_a((LPSTR) ptr));
+
+    if ((len >= sizeof(DEVMODEW)) &&
+        (dmW->dmSize + dmW->dmDriverExtra == len) &&
+        (ptr[1] == '\0'))
+    {
+        return sizeof(DEVMODEW);   /* UNICODE */
+    }
+
+    if ((len >= sizeof(DEVMODEA)) &&
+        (dmA->dmSize + dmA->dmDriverExtra == len))
+    {
+        return sizeof(DEVMODEA);   /* ANSI */
+    }    
+
+    WARN("expected %d+%d (%d) or %d+%d (%d) for %p (have %d): %s\n", 
+            dmW->dmSize, dmW->dmDriverExtra, dmW->dmSize + dmW->dmDriverExtra,
+            dmA->dmSize, dmA->dmDriverExtra, dmA->dmSize + dmA->dmDriverExtra, 
+            ptr, len, debugstr_a((LPSTR) ptr));
+
+    return 0;   /* unknown */
+
+}
+
+/*****************************************************************************
+ * get_devmode_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_devmode_from_reg(HKEY hentry, LPCWSTR pName, LPBYTE out, DWORD outlen, LPDWORD needed)
+{
+    /* avoid dynamic buffer most times: extra space for private data of wineps.drv */
+    BYTE  buffer[sizeof(DEVMODEW) + 32 ];
+    DWORD type = 0;
+    DWORD len;
+    LONG  res;
+    LPBYTE value;
+
+    if ((out) && (outlen >= sizeof(DEVMODEW))) {
+        /* try best case: output buffer present and large enough */
+        value = out;
+        len = outlen;
+    }
+    else
+    {
+        value = buffer;
+        len = sizeof(buffer);
+    }
+
+    value[0] = '\0';
+    res = RegQueryValueExW(hentry, pName, NULL, &type, value, &len);
+    if (res == ERROR_MORE_DATA) {
+        TRACE("%u byte at %p to small: need %u byte for %s\n", outlen, out, len, debugstr_w(pName));
+        value = heap_alloc(len);
+        if (!value) {
+            /* No Memory is bad */
+            *needed = 0;
+            return FALSE;
+        }
+        value[0] = '\0';
+        res = RegQueryValueExW(hentry, pName, NULL, &type, value, &len);
+    }
+
+    if (!res) {
+        DWORD dm_type;
+        dm_type = get_devmode_type(value, len);
+        if (dm_type == sizeof(DEVMODEA)) {
+            LPDEVMODEW dmW;
+
+            /* Convert the DEVMODE in the Registry from A to W */
+            dmW = GdiConvertToDevmodeW((LPDEVMODEA) value);
+            if (!dmW) {
+                ERR("failed to convert DEVMODEA to DEVMODEW: %u\n", GetLastError()); 
+                if (value != out) heap_free(value); /* free the dynamic buffer */
+                return FALSE;
+            }
+
+            /* return the converted devmodeA, until we support devmodeW everywhere */
+            len = dmW->dmSize + dmW->dmDriverExtra;
+            if (out && (outlen >= len)) {
+                memcpy(out, dmW, len);
+            }
+            HeapFree(GetProcessHeap(), 0, dmW);
+
+#if 0
+            /* Update the registry */
+            res = RegSetValueExW(hentry, pName, 0, REG_BINARY, (LPBYTE) dmW, dmW->dmSize + dmW->dmDriverExtra);
+            HeapFree(GetProcessHeap(), 0, dmW);
+
+            if (value != out) heap_free(value); /* free the dynamic buffer */
+
+            /* read again from the registry. used only once for a Printer */ 
+            return get_devmode_from_reg(hentry, pName, out, outlen, needed);
+#endif
+        }
+    }
+
+    if (res) {
+        TRACE("got %d with %s for %s (value %p, out %p, len %u)\n", 
+              res, debugstr_w((LPWSTR) value), debugstr_w(pName), value, out, len);
+    }
+
+    if (value != out) heap_free(value); /* free the dynamic buffer */
+    if (!res) *needed = len;
+    return res == ERROR_SUCCESS;
+}
+
+/*****************************************************************************
+ * get_dword_from_reg (INTERNAL)
+ *
+ */
+static DWORD get_dword_from_reg(HKEY hentry, LPCWSTR pName)
+{
+    DWORD   value = 0;  /* initialize to avoid a false compiler warning */
+    DWORD   type;
+    DWORD   len = sizeof(DWORD);
+    LONG    res;
+
+    res = RegQueryValueExW(hentry, pName, NULL, &type, (LPBYTE) value, &len);
+    if ((!res) && (type == REG_DWORD) && (len == sizeof(DWORD))) return value;
+
+    TRACE("got %d with type %u and len %u for %s\n", res, type, len, debugstr_w(pName));
+    return 0;
+}
+
+/*****************************************************************************
+ * get_string_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_string_from_reg(HKEY hentry, LPCWSTR pName, LPWSTR out, DWORD outlen, LPDWORD needed)
+{
+    WCHAR   buffer[MAX_PATH];
+    DWORD   type;
+    DWORD   len;
+    LONG    res;
+    LPWSTR  value;
+
+    if ((out) && (outlen >= sizeof(WCHAR))) {
+        /* try best case: output buffer present and large enough */
+        value = out;
+        len = outlen;
+    }
+    else
+    {
+        value = buffer;
+        len = sizeof(buffer);
+    }
+
+    value[0] = '\0';
+    res = RegQueryValueExW(hentry, pName, NULL, &type, (LPBYTE) value, &len);
+    if (res == ERROR_MORE_DATA) {
+        TRACE("%u byte at %p to small: need %u byte for %s\n", outlen, out, len, debugstr_w(pName));
+        value = heap_alloc(len);
+        if (!value) {
+            /* No Memory is bad */
+            *needed = 0;
+            return FALSE;
+        }
+        value[0] = '\0';
+        res = RegQueryValueExW(hentry, pName, NULL, &type, (LPBYTE) value, &len);
+    }
+
+    if (res) {
+        TRACE("got %d with %s for %s at %p,%p (len: %u)\n", res, 
+                            debugstr_w(value), debugstr_w(pName), value, out, len);
+    }
+
+    if (value != out) heap_free(value); /* free the dynamic buffer */
+    if (!res) *needed = len;
+    return res == ERROR_SUCCESS;
+
+}
+
+/*****************************************************************************
+ * get_printerinfo1_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo1_from_reg(HKEY hentry, PRINTER_INFO_1W * pi, 
+                                      LPWSTR ptr, DWORD cbBuf, LPDWORD needed)
+{
+
+    DWORD len = 0;
+    BOOL res = FALSE;
+
+    /* Flags */
+    if (pi) pi->Flags = PRINTER_ENUM_ICON8;
+    
+    /* pName */
+    if (get_string_from_reg(hentry, nameW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+            res = TRUE;
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+        }
+        *needed += len;
+
+        /* pDescription: "Name,Driver_Name," */
+        *needed += len;
+        if (ptr && (len <= cbBuf)) {
+            lstrcpyW(ptr, pi->pName);
+            pi->pDescription = ptr;
+            cbBuf -= len;
+            ptr[len/sizeof(WCHAR)-1] = ',';     /* seperator */
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+
+        /* Append the Drivername */
+        if (get_string_from_reg(hentry, printer_driverW, ptr, cbBuf, &len)) {
+            len += (sizeof(WCHAR));   /* reserve space for the second ',' */
+            if (res && ptr && (len <= cbBuf)) {
+                cbBuf -= len;
+                ptr[len/sizeof(WCHAR)-2] = ',';
+                ptr[len/sizeof(WCHAR)-1] = '\0';
+                ptr += (len / sizeof(WCHAR));
+            }
+            else
+            {
+                ptr = NULL;
+                cbBuf = 0;
+                res = FALSE;
+            }
+            *needed += len;
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+    }
+
+    /* pComment */
+    if (get_string_from_reg(hentry, descriptionW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pComment = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    if (pi && !res) ZeroMemory(pi, sizeof(PRINTER_INFO_1W));
+    return res;
+}
+
+/*****************************************************************************
+ * get_printerinfo2_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo2_from_reg(HKEY hentry, PRINTER_INFO_2W * pi, 
+                                      LPWSTR ptr, DWORD cbBuf, LPDWORD needed)
+{
+    DWORD len = 0;
+    BOOL res = FALSE;
+
+    /* pServerName is NULL */
+    
+    /* pPrinterName */
+    if (get_string_from_reg(hentry, nameW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPrinterName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+            res = TRUE;
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+        }
+        *needed += len;
+    }
+
+    /* pShareName */
+    if (get_string_from_reg(hentry, share_nameW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pShareName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pPortName */
+    if (get_string_from_reg(hentry, portW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPortName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pDriverName */
+    if (get_string_from_reg(hentry, printer_driverW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pDriverName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pComment */
+    if (get_string_from_reg(hentry, descriptionW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pComment = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pLocation */
+    if (get_string_from_reg(hentry, locationW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pLocation = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pDevMode */
+    /* FIXME: DevModePerUser / DevMode2 */
+    if (get_devmode_from_reg(hentry, default_devmodeW, (LPBYTE) ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pDevMode = (LPDEVMODEW) ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+    else
+    {
+        if (pi) FIXME("No DevMode found for printer %s\n", debugstr_w(pi->pPrinterName));
+    }
+
+    /* pSepFile */
+    if (get_string_from_reg(hentry, separator_fileW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pSepFile = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pPrintProcessor */
+    if (get_string_from_reg(hentry, print_processorW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPrintProcessor = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pDatatype */
+    if (get_string_from_reg(hentry, datatypeW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pDatatype = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    /* pParameters */
+    if (get_string_from_reg(hentry, parametersW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pParameters = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    if (pi && res) {
+        pi->Attributes = get_dword_from_reg(hentry, attributesW);
+        pi->Priority = get_dword_from_reg(hentry, priorityW);
+        pi->DefaultPriority = get_dword_from_reg(hentry, default_priorityW);
+        pi->StartTime = get_dword_from_reg(hentry, starttimeW);
+        pi->UntilTime = get_dword_from_reg(hentry, untiltimeW);
+        pi->Status = get_dword_from_reg(hentry, statusW);
+    }
+
+    if (pi && !res) ZeroMemory(pi, sizeof(PRINTER_INFO_2W));
+    return res;
+}
+
+/*****************************************************************************
+ * get_printerinfo4_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo4_from_reg(HKEY hentry, PRINTER_INFO_4W * pi, 
+                                      LPWSTR ptr, DWORD cbBuf, LPDWORD needed)
+{
+
+    DWORD len = 0;
+    BOOL res = FALSE;
+    
+    /* pPrinterName */
+    if (get_string_from_reg(hentry, nameW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPrinterName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+            res = TRUE;
+
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+        }
+        *needed += len;
+    }
+
+    /* pServerName is NULL */
+
+    if (pi && res) {
+        pi->Attributes = get_dword_from_reg(hentry, attributesW);
+    }
+
+    if (pi && !res) ZeroMemory(pi, sizeof(PRINTER_INFO_4W));
+    return res;
+}
+
+/*****************************************************************************
+ * get_printerinfo5_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo5_from_reg(HKEY hentry, PRINTER_INFO_5W * pi, 
+                                      LPWSTR ptr, DWORD cbBuf, LPDWORD needed)
+{
+
+    DWORD len = 0;
+    BOOL res = FALSE;
+    
+    /* pPrinterName */
+    if (get_string_from_reg(hentry, nameW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPrinterName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+            res = TRUE;
+
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+        }
+        *needed += len;
+    }
+
+    /* pPortName */
+    if (get_string_from_reg(hentry, portW, ptr, cbBuf, &len)) {
+        if (ptr && (len <= cbBuf)) {
+            pi->pPortName = ptr;
+            cbBuf -= len;
+            ptr += (len / sizeof(WCHAR));
+        }
+        else
+        {
+            ptr = NULL;
+            cbBuf = 0;
+            res = FALSE;
+        }
+        *needed += len;
+    }
+
+    if (pi && res) {
+        pi->Attributes = get_dword_from_reg(hentry, attributesW);
+    }
+
+    if (pi && !res) ZeroMemory(pi, sizeof(PRINTER_INFO_5W));
+    return res;
+
+}
+/*****************************************************************************
+ * enumerate the local printers (INTERNAL)
+ *
+ * returns the needed size (in bytes) for pPrinters
+ * and  *lpreturned is set to number of entries returned in pPrinters
+ *
+ */
+static DWORD get_printers_from_reg(HKEY hroot, DWORD flags, DWORD level, 
+                                    LPBYTE pPrinters, DWORD cbBuf, LPDWORD lpreturned)
+{
+    HKEY    hentry = NULL;
+    LPWSTR  ptr;
+    WCHAR   buffer[MAX_PATH];
+    DWORD   len;
+    DWORD   index = 0;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    DWORD   entrysize;
+    BOOL    res;
+
+    entrysize = pi_sizeof[level];
+
+    len = entrysize * (*lpreturned); /* (*lpreturned) is 0, when we scan the registry */
+
+    ptr = (cbBuf >= len) ? (LPWSTR) &pPrinters[len] : NULL;
+    cbBuf = (cbBuf >= len) ? cbBuf - len : 0;
+
+    len = sizeof(buffer) / sizeof(buffer[0]);
+    buffer[0] = '\0';
+
+    /* Scan all Printer-Registry-Keys */
+    while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
+        if (RegOpenKeyW(hroot, buffer, &hentry) == ERROR_SUCCESS) {
+
+            TRACE("#%u: %s\n", index, debugstr_w(buffer));
+            needed += entrysize;
+            len = 0;
+            if (pPrinters) ZeroMemory(pPrinters, entrysize);
+            switch (level) {
+                case 1:
+                    res = get_printerinfo1_from_reg(hentry, (PRINTER_INFO_1W *) pPrinters, ptr, cbBuf, &len);
+                    break;
+                case 2:
+                    res = get_printerinfo2_from_reg(hentry, (PRINTER_INFO_2W *) pPrinters, ptr, cbBuf, &len);
+                    break;
+
+                case 4:
+                    res = get_printerinfo4_from_reg(hentry, (PRINTER_INFO_4W *) pPrinters, ptr, cbBuf, &len);
+                    break;
+
+                case 5:
+                    res = get_printerinfo5_from_reg(hentry, (PRINTER_INFO_5W *) pPrinters, ptr, cbBuf, &len);
+                    break;
+
+                default:
+                    res = FALSE;
+            }
+
+            if (res && cbBuf && (cbBuf >= len)) {
+                    cbBuf -= len;
+                    if (pPrinters) pPrinters += entrysize;
+                    if (ptr) ptr += len / sizeof(WCHAR);
+            }
+            else
+            {
+                pPrinters = NULL;
+                ptr = NULL;
+                cbBuf = 0;
+            }
+
+
+            numentries++;
+            needed += len;
+            RegCloseKey(hentry);
+        }
+        index++;
+
+        len = sizeof(buffer) / sizeof(buffer[0]);
+        buffer[0] = '\0';
+    }
+
+    *lpreturned = numentries;
+    TRACE("has %u byte left in cbBuf, we used %u for %u entries\n", cbBuf, needed, numentries);
+    return needed;
+}
+
 /******************************************************************
  * Return the number of bytes for an multi_sz string.
  * The result includes all \0s
@@ -315,6 +997,99 @@ static HKEY open_driver_reg(LPCWSTR pEnvironment)
     return retval;
 }
 
+
+/******************************************************************
+ * fpEnumPrinters  [exported through PRINTPROVIDOR]
+ *
+ * Enumerates the available printers, printservers and print providers
+ * selected by depending on the specified flags, name and level.
+ *
+ * PARAMS
+ *  flags      [I] select Types of Objects to enumerate
+ *  pName      [I] Name of Objects to enumerate 
+ *  level      [I] level of the requested PRINTER_INFO structure
+ *  pPrinters  [O] PTR to Buffer that receives the Result
+ *  cbBuf      [I] Size of Buffer at pPrinters
+ *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPrinters
+ *  pcReturned [O] PTR to DWORD that receives the number of objects in pPrinters
+ *
+ * RETURNS
+ *  Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
+ *  Success: TRUE and pPrinters filled
+ *
+ *  level == 1:
+ *      Returns an array of PRINTER_INFO_1 structures in the pPrinters buffer.
+ *
+ *  level == 2:
+ *      Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
+ *      Returns an array of PRINTER_INFO_2 structures in the pPrinters buffer.
+ *      According to MSDN, an OpenPrinter should be performed on every remote printer.
+ *
+ *  level == 4 (WinNT only):
+ *      Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
+ *      Returns an array of PRINTER_INFO_4 structures in the pPrinters buffer.
+ *      Fast: Only the registry is queried to retrieve printer names
+ *      (no connection to the driver is made.)
+ *
+ *  level == 5:
+ *      Returns an array of PRINTER_INFO_5 structures in the pPrinters buffer.
+ *      Fast: Only the registry is queried to retrieve printer names
+ *      (no connection to the driver is made.)
+ *
+ */
+static BOOL WINAPI fpEnumPrinters(DWORD flags, LPWSTR pName, DWORD level,
+                LPBYTE pPrinters, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+{
+    HKEY    hroot;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    BOOL    res = FALSE;
+    LONG    lres;
+    
+    TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n\n", flags, debugstr_w(pName), level,
+                pPrinters, cbBuf, pcbNeeded, pcReturned);
+
+    if (flags & PRINTER_ENUM_CONNECTIONS) {
+        lres = RegOpenKeyW(HKEY_CURRENT_USER, printers_connectionsW, &hroot);
+        if (lres == ERROR_SUCCESS) {
+            FIXME("PRINTER_ENUM_CONNECTIONS not implemented\n");
+            RegCloseKey(hroot);
+            hroot = NULL;
+        }
+        flags &= ~PRINTER_ENUM_CONNECTIONS;
+    }
+
+    /* FIXME: (flags & PRINTER_ENUM_NAME) && (pName == NULL) enumerates Printprovidor */
+    if ((flags & PRINTER_ENUM_LOCAL) || ((flags & PRINTER_ENUM_NAME) && (pName == NULL))) {
+        lres = RegCreateKeyW(HKEY_LOCAL_MACHINE, print_printersW, &hroot);
+        if (lres == ERROR_SUCCESS) {
+            needed = get_printers_from_reg(hroot, flags, level, NULL, 0, &numentries); 
+            if ((cbBuf >= needed) && pPrinters) {
+                *pcbNeeded = get_printers_from_reg(hroot, flags, level, pPrinters, cbBuf, &numentries); 
+                *pcReturned = numentries;
+                RegCloseKey(hroot);
+                TRACE("=> TRUE with %u (%u byte for %u entries)\n", GetLastError(), needed, numentries);
+                return TRUE;
+            }               
+            RegCloseKey(hroot);
+            hroot = NULL;
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        }
+        else
+            SetLastError(lres);
+    }
+    else
+    {
+        if (flags) FIXME("not implemented for flags 0x%x\n", flags);
+    }
+
+    TRACE("=> %u with %u (%u byte for %u entries)\n", res, GetLastError(), needed, numentries);
+
+    *pcReturned = (res) ? numentries : 0;
+    *pcbNeeded = needed;
+    return res;
+}
+
 /*****************************************************************************
  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
  *
@@ -581,7 +1356,7 @@ static const PRINTPROVIDOR * get_backend(void)
         NULL,   /* fpDeletePrinter */
         NULL,   /* fpSetPrinter */
         NULL,   /* fpGetPrinter */
-        NULL,   /* fpEnumPrinters */
+        fpEnumPrinters,
         NULL,   /* fpAddPrinterDriver */
         NULL,   /* fpEnumPrinterDrivers */
         NULL,   /* fpGetPrinterDriver */
-- 
1.5.3.6


--=-7WRxrXx4bRbuFv8Yg2x3--




More information about the wine-patches mailing list