[PATCH] localspl: Implement fpEnumPrinters
Detlef Riekenberg
wine.dev at web.de
Wed Apr 16 07:20:56 CDT 2008
---
dlls/localspl/Makefile.in | 2 +-
dlls/localspl/localspl_main.c | 642 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 642 insertions(+), 2 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 8efb7cb..3e2db29 100644
--- a/dlls/localspl/localspl_main.c
+++ b/dlls/localspl/localspl_main.c
@@ -56,6 +56,15 @@ typedef struct {
LPCWSTR versionsubdir;
} printenv_t;
+typedef struct {
+ LPBYTE ptr;
+ LPBYTE oldptr;
+ DWORD outlen;
+ DWORD needed;
+ DWORD len;
+ BOOL res;
+} output_data_t;
+
/* ############################### */
HINSTANCE LOCALSPL_hInstance = NULL;
@@ -63,11 +72,13 @@ 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 +99,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 +141,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 +249,537 @@ 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, output_data_t * out)
+{
+ /* 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->ptr && (out->outlen >= sizeof(DEVMODEW))) {
+ /* try best case: output buffer present and large enough */
+ value = out->ptr;
+ len = out->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", out->outlen, out->ptr, len, debugstr_w(pName));
+ value = heap_alloc(len);
+ if (!value) {
+ /* No Memory is bad */
+ out->len = 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->ptr) && (value != buffer)) 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->ptr && (out->outlen >= len)) {
+ memcpy(out->ptr, dmW, len);
+ }
+ HeapFree(GetProcessHeap(), 0, dmW);
+
+ /* ToDo: Update the DEVMODEA in the registry with the DEVMODEW */
+ }
+ }
+
+ if (res) {
+ TRACE("got %d with %s for %s (value %p, out->ptr %p, len %u)\n",
+ res, debugstr_w((LPWSTR) value), debugstr_w(pName), value, out->ptr, len);
+ }
+
+ if ((value != out->ptr) && (value != buffer)) heap_free(value); /* free the dynamic buffer */
+ if (!res) {
+ if (out->ptr && (len <= out->outlen)) {
+ out->oldptr = out->ptr;
+ out->outlen -= len;
+ out->ptr += len;
+ }
+ else
+ {
+ out->ptr = NULL;
+ out->outlen = 0;
+ out->res = FALSE;
+ }
+ out->needed += len;
+ out->len = 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, output_data_t * out)
+{
+ WCHAR buffer[MAX_PATH];
+ DWORD type;
+ DWORD len;
+ LONG res;
+ LPWSTR value;
+
+ if ((out->ptr) && (out->outlen >= sizeof(WCHAR))) {
+ /* try best case: output buffer present and large enough */
+ value = (LPWSTR) out->ptr;
+ len = out->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", out->outlen, out->ptr, len, debugstr_w(pName));
+ value = heap_alloc(len);
+ if (!value) {
+ /* No Memory is bad */
+ out->len = 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->ptr, len);
+ }
+
+ if ((value != (LPWSTR) out->ptr) && (value != buffer)) heap_free(value); /* free the dynamic buffer */
+ if (!res) {
+ if (out->ptr && (len <= out->outlen)) {
+ out->oldptr = out->ptr;
+ out->outlen -= len;
+ out->ptr += len;
+ }
+ else
+ {
+ out->ptr = NULL;
+ out->outlen = 0;
+ out->res = FALSE;
+ }
+ out->needed += len;
+ out->len = len;
+ }
+ return res == ERROR_SUCCESS;
+
+}
+
+/*****************************************************************************
+ * get_printerinfo1_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo1_from_reg(HKEY hentry, PRINTER_INFO_1W * pi, output_data_t * out)
+{
+ LPWSTR ptr;
+
+ /* Flags */
+ if (pi) pi->Flags = PRINTER_ENUM_ICON8;
+
+ /* pName */
+ if (get_string_from_reg(hentry, nameW, out)) {
+ ptr = (LPWSTR) out->ptr;
+ if (ptr) {
+ pi->pName = (LPWSTR) out->oldptr;
+ }
+
+ /* pDescription: "Name,Driver_Name," */
+ /* First part of the Description is the Name */
+ out->needed += out->len;
+ if (out->ptr && (out->outlen > out->len)) {
+ ptr = (LPWSTR) out->ptr;
+ lstrcpyW(ptr, pi->pName);
+ pi->pDescription = (LPWSTR) out->ptr;
+ out->outlen -= out->len;
+ ptr[out->len / sizeof(WCHAR)-1] = ','; /* replace termination with seperator */
+ out->ptr += out->len;
+ }
+ else
+ {
+ /* No space for the Name */
+ out->ptr = NULL;
+ out->outlen = 0;
+ out->res = FALSE;
+ }
+
+ /* Second Part of the Description is the Drivername */
+ if (get_string_from_reg(hentry, printer_driverW, out) && (out->len > sizeof(WCHAR))) {
+ ptr = (LPWSTR) out->oldptr;
+ /* reserve space for the second ',' */
+ out->needed += sizeof(WCHAR);
+ if (out->ptr && (out->outlen > sizeof(WCHAR))) {
+ out->outlen -= sizeof(WCHAR);
+ out->ptr += sizeof(WCHAR);
+ /* Append the second ',' */
+ ptr[out->len/sizeof(WCHAR)-1] = ',';
+ ptr[out->len/sizeof(WCHAR)] = '\0';
+ }
+ else
+ {
+ /* no Space for the second ',' */
+ out->ptr = NULL;
+ out->outlen = 0;
+ out->res = FALSE;
+ }
+ }
+ else
+ {
+ /* Without a Drivername, the Entry is invalid */
+ out->ptr = NULL;
+ out->outlen = 0;
+ out->res = FALSE;
+ }
+ }
+
+ /* pComment */
+ if (get_string_from_reg(hentry, descriptionW, out)) {
+ if (out->ptr) {
+ pi->pComment = (LPWSTR) out->oldptr;
+ }
+ }
+
+ if (pi && !out->res) ZeroMemory(pi, sizeof(PRINTER_INFO_1W));
+ return out->res;
+}
+
+/*****************************************************************************
+ * get_printerinfo2_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo2_from_reg(HKEY hentry, PRINTER_INFO_2W * pi, output_data_t * out)
+{
+
+ /* pServerName is NULL */
+
+ /* pPrinterName */
+ if (get_string_from_reg(hentry, nameW, out)) {
+ if (out->ptr) {
+ pi->pPrinterName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pShareName */
+ if (get_string_from_reg(hentry, share_nameW, out)) {
+ if (out->ptr) {
+ pi->pShareName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pPortName */
+ if (get_string_from_reg(hentry, portW, out)) {
+ if (out->ptr) {
+ pi->pPortName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pDriverName */
+ if (get_string_from_reg(hentry, printer_driverW, out)) {
+ if (out->ptr) {
+ pi->pDriverName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pComment */
+ if (get_string_from_reg(hentry, descriptionW, out)) {
+ if (out->ptr) {
+ pi->pComment = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pLocation */
+ if (get_string_from_reg(hentry, locationW, out)) {
+ if (out->ptr) {
+ pi->pLocation = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pDevMode */
+ /* FIXME: DevModePerUser / DevMode2 */
+ if (get_devmode_from_reg(hentry, default_devmodeW, out)) {
+ if (out->ptr) {
+ pi->pDevMode = (LPDEVMODEW) out->oldptr;
+ }
+ }
+ else
+ {
+ if (pi) FIXME("No DevMode found for printer %s\n", debugstr_w(pi->pPrinterName));
+ }
+
+ /* pSepFile */
+ if (get_string_from_reg(hentry, separator_fileW, out)) {
+ if (out->ptr) {
+ pi->pSepFile = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pPrintProcessor */
+ if (get_string_from_reg(hentry, print_processorW, out)) {
+ if (out->ptr) {
+ pi->pPrintProcessor = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pDatatype */
+ if (get_string_from_reg(hentry, datatypeW, out)) {
+ if (out->ptr) {
+ pi->pDatatype = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pParameters */
+ if (get_string_from_reg(hentry, parametersW, out)) {
+ if (out->ptr) {
+ pi->pParameters = (LPWSTR) out->oldptr;
+ }
+ }
+
+ if (pi && out->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 && !out->res) ZeroMemory(pi, sizeof(PRINTER_INFO_2W));
+ return out->res;
+
+}
+
+/*****************************************************************************
+ * get_printerinfo4_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo4_from_reg(HKEY hentry, PRINTER_INFO_4W * pi, output_data_t * out)
+{
+
+ /* pPrinterName */
+ if (get_string_from_reg(hentry, nameW, out)) {
+ if (out->ptr) {
+ pi->pPrinterName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pServerName is NULL */
+
+ if (pi && out->res) {
+ pi->Attributes = get_dword_from_reg(hentry, attributesW);
+ }
+
+ if (pi && !out->res) ZeroMemory(pi, sizeof(PRINTER_INFO_4W));
+ return out->res;
+}
+
+/*****************************************************************************
+ * get_printerinfo5_from_reg (INTERNAL)
+ *
+ */
+static BOOL get_printerinfo5_from_reg(HKEY hentry, PRINTER_INFO_5W * pi, output_data_t * out)
+{
+
+ /* pPrinterName */
+ if (get_string_from_reg(hentry, nameW, out)) {
+ if (out->ptr) {
+ pi->pPrinterName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ /* pPortName */
+ if (get_string_from_reg(hentry, portW, out)) {
+ if (out->ptr) {
+ pi->pPortName = (LPWSTR) out->oldptr;
+ }
+ }
+
+ if (pi && out->res) {
+ pi->Attributes = get_dword_from_reg(hentry, attributesW);
+ }
+
+ if (pi && !out->res) ZeroMemory(pi, sizeof(PRINTER_INFO_5W));
+ return out->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;
+ WCHAR buffer[MAX_PATH];
+ DWORD len;
+ DWORD index = 0;
+ DWORD needed = 0;
+ DWORD numentries = 0;
+ DWORD entrysize;
+ BOOL res;
+ output_data_t out;
+
+ entrysize = pi_sizeof[level];
+ len = entrysize * (*lpreturned); /* (*lpreturned) is 0, when we scan the registry */
+
+ out.ptr = (cbBuf >= len) ? &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;
+
+ out.outlen = cbBuf;
+ out.needed = 0;
+ out.res = TRUE;
+
+ if (pPrinters) ZeroMemory(pPrinters, entrysize);
+ switch (level) {
+ case 1:
+ res = get_printerinfo1_from_reg(hentry, (PRINTER_INFO_1W *) pPrinters, &out);
+ break;
+ case 2:
+ res = get_printerinfo2_from_reg(hentry, (PRINTER_INFO_2W *) pPrinters, &out);
+ break;
+
+ case 4:
+ res = get_printerinfo4_from_reg(hentry, (PRINTER_INFO_4W *) pPrinters, &out);
+ break;
+
+ case 5:
+ res = get_printerinfo5_from_reg(hentry, (PRINTER_INFO_5W *) pPrinters, &out);
+ break;
+
+ default:
+ res = FALSE;
+ }
+
+ /* we can't replace cbBuf with out.outlen here: it might be 0 for the last entry */
+ if (res && cbBuf && (cbBuf >= out.needed)) {
+ cbBuf -= out.needed;
+ if (pPrinters) pPrinters += entrysize;
+ }
+ else
+ {
+ pPrinters = NULL;
+ out.ptr = NULL;
+ cbBuf = 0;
+ }
+
+
+ numentries++;
+ needed += out.needed;
+ 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 +877,84 @@ 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
+ *
+ * BUGS
+ * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
+ * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
+ *
+ */
+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 +1221,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
--=-lk2m5v17uMom2JwZeKAn--
More information about the wine-patches
mailing list