[PATCH 4/6] winspool: Move CUPS printer enumeration to cups.c.

Huw Davies huw at codeweavers.com
Tue Oct 26 05:18:10 CDT 2021


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/winspool.drv/cups.c   | 117 +++++++++++++++++++++++++++++
 dlls/winspool.drv/info.c   | 148 +++++++++++++------------------------
 dlls/winspool.drv/wspool.h |  16 ++++
 3 files changed, 185 insertions(+), 96 deletions(-)

diff --git a/dlls/winspool.drv/cups.c b/dlls/winspool.drv/cups.c
index 207c95c568a..7aeb68d4f8d 100644
--- a/dlls/winspool.drv/cups.c
+++ b/dlls/winspool.drv/cups.c
@@ -41,11 +41,22 @@
 #include "winspool.h"
 #include "ddk/winsplp.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 
 #include "wspool.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
 
+/* Temporary helpers until switch to unixlib */
+#include "winnls.h"
+#include "wine/heap.h"
+#define malloc( sz ) heap_alloc( sz )
+#define free( ptr ) heap_free( ptr )
+static DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen )
+{
+    return MultiByteToWideChar( CP_UNIXCP, 0, src, srclen, dst, dstlen );
+}
+
 #ifdef SONAME_LIBCUPS
 
 void *libcups_handle = NULL;
@@ -99,3 +110,109 @@ NTSTATUS unix_process_attach( void *arg )
     return STATUS_NOT_SUPPORTED;
 #endif /* SONAME_LIBCUPS */
 }
+
+#ifdef SONAME_LIBCUPS
+static WCHAR *cups_get_optionW( const char *opt_name, int num_options, cups_option_t *options )
+{
+    const char *value;
+    WCHAR *ret;
+    int len;
+
+    value = pcupsGetOption( opt_name, num_options, options );
+    if (!value) return NULL;
+
+    len = strlen( value ) + 1;
+    ret = malloc( len * sizeof(WCHAR) );
+    if (ret) ntdll_umbstowcs( value, len, ret, len );
+
+    return ret;
+}
+
+static cups_ptype_t cups_get_printer_type( const cups_dest_t *dest )
+{
+    const char *value;
+    cups_ptype_t ret;
+    char *end;
+
+    value = pcupsGetOption( "printer-type", dest->num_options, dest->options );
+    if (!value) return 0;
+    ret = (cups_ptype_t)strtoul( value, &end, 10 );
+    if (*end) ret = 0;
+    return ret;
+}
+
+static BOOL cups_is_scanner( cups_dest_t *dest )
+{
+    return cups_get_printer_type( dest ) & 0x2000000 /* CUPS_PRINTER_SCANNER */;
+}
+#endif /* SONAME_LIBCUPS */
+
+NTSTATUS unix_enum_printers( void *args )
+{
+    struct enum_printers_params *params = args;
+#ifdef SONAME_LIBCUPS
+    unsigned int num, i, name_len, comment_len, location_len, needed;
+    WCHAR *comment, *location, *ptr;
+    struct printer_info *info;
+    cups_dest_t *dests;
+
+    params->num = 0;
+    if (!pcupsGetDests) return STATUS_NOT_SUPPORTED;
+
+    num = pcupsGetDests( &dests );
+
+    for (i = 0; i < num; i++)
+    {
+        if (cups_is_scanner( dests + i ))
+        {
+            TRACE( "Printer %d: %s - skipping scanner\n", i, debugstr_a( dests[i].name ) );
+            continue;
+        }
+        TRACE( "Printer %d: %s\n", i, debugstr_a( dests[i].name ) );
+        params->num++;
+    }
+
+    needed = sizeof( *info ) * params->num;
+    info = params->printers;
+    ptr = (WCHAR *)(info + params->num);
+
+    for (i = 0; i < num; i++)
+    {
+        if (cups_is_scanner( dests + i )) continue;
+
+        comment = cups_get_optionW( "printer-info", dests[i].num_options, dests[i].options );
+        location = cups_get_optionW( "printer-location", dests[i].num_options, dests[i].options );
+
+        name_len = strlen( dests[i].name ) + 1;
+        comment_len = comment ? strlenW( comment ) + 1 : 0;
+        location_len = location ? strlenW( location ) + 1 : 0;
+        needed += (name_len + comment_len + location_len) * sizeof(WCHAR);
+
+        if (needed <= params->size)
+        {
+            info->name = ptr;
+            ntdll_umbstowcs( dests[i].name, name_len, info->name, name_len );
+            info->comment = comment ? ptr + name_len : NULL;
+            memcpy( info->comment, comment, comment_len * sizeof(WCHAR) );
+            info->location = location ? ptr + name_len + comment_len : NULL;
+            memcpy( info->location, location, location_len * sizeof(WCHAR) );
+            info->is_default = dests[i].is_default;
+            info++;
+            ptr += name_len + comment_len + location_len;
+        }
+        free( comment );
+        free( location );
+    }
+    pcupsFreeDests( num, dests );
+
+    if (needed > params->size)
+    {
+        params->size = needed;
+        return STATUS_BUFFER_OVERFLOW;
+    }
+    return STATUS_SUCCESS;
+#else
+    params->num = 0;
+    return STATUS_NOT_SUPPORTED;
+#endif /* SONAME_LIBCUPS */
+}
diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 9d2af8cec94..a3fcb32641a 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -107,6 +107,8 @@
 #define NONAMELESSSTRUCT
 #define NONAMELESSUNION
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
@@ -917,7 +919,6 @@ extern void *libcups_handle;
     DO_FUNC(cupsAddOption); \
     DO_FUNC(cupsFreeDests); \
     DO_FUNC(cupsFreeOptions); \
-    DO_FUNC(cupsGetDests); \
     DO_FUNC(cupsGetOption); \
     DO_FUNC(cupsParseOptions); \
     DO_FUNC(cupsPrintFile)
@@ -981,137 +982,96 @@ static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
 
     return http_status == HTTP_OK;
 }
+#endif
 
-static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
-{
-    const char *value;
-    WCHAR *ret;
-    int len;
-
-    value = pcupsGetOption( name, num_options, options );
-    if (!value) return NULL;
-
-    len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
-    ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
-    if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
-
-    return ret;
-}
-
-static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
+static BOOL init_unix_printers( void )
 {
-    WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
-    cups_ptype_t ret = 0;
+    WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
+    struct enum_printers_params enum_params;
+    HKEY printer_key, printers_key;
+    HANDLE added_printer;
+    PRINTER_INFO_2W pi2;
+    NTSTATUS status;
+    int i;
 
-    if (type && *type)
+    if (RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers_key ) != ERROR_SUCCESS)
     {
-        ret = (cups_ptype_t)strtoulW( type, &end, 10 );
-        if (*end) ret = 0;
-    }
-    HeapFree( GetProcessHeap(), 0, type );
-    return ret;
-}
-
-static BOOL CUPS_LoadPrinters(void)
-{
-    int	                  i, nrofdests;
-    BOOL                  hadprinter = FALSE, haddefault = FALSE;
-    cups_dest_t          *dests;
-    PRINTER_INFO_2W       pi2;
-    WCHAR *port, *ppd_dir = NULL;
-    HKEY hkeyPrinter, hkeyPrinters;
-    WCHAR   nameW[MAX_PATH];
-    HANDLE  added_printer;
-    cups_ptype_t printer_type;
-
-    if (!libcups_handle) return FALSE;
-
-    if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
-       ERROR_SUCCESS) {
-        ERR("Can't create Printers key\n");
-	return FALSE;
+        ERR( "Can't create Printers key\n" );
+        return FALSE;
     }
 
-    nrofdests = pcupsGetDests(&dests);
-    TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
-    for (i=0;i<nrofdests;i++) {
-        MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
-        printer_type = get_cups_printer_type( dests + i );
-
-        TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
+    enum_params.size = 10000;
+    enum_params.printers = NULL;
+    do
+    {
+        enum_params.size *= 2;
+        heap_free( enum_params.printers );
+        enum_params.printers = heap_alloc( enum_params.size );
+        status = UNIX_CALL( enum_printers, &enum_params );
+    } while (status == STATUS_BUFFER_OVERFLOW);
+    if (status) goto end;
 
-        if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
-        {
-            TRACE( "skipping scanner-only device\n" );
-            continue;
-        }
+    TRACE( "Found %d CUPS %s:\n", enum_params.num, (enum_params.num == 1) ? "printer" : "printers" );
+    for (i = 0; i < enum_params.num; i++)
+    {
+        struct printer_info *printer = enum_params.printers + i;
 
-        if (RegOpenKeyW( hkeyPrinters, nameW, &hkeyPrinter ) == ERROR_SUCCESS)
+        if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == ERROR_SUCCESS)
         {
-            DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
+            DWORD status = get_dword_from_reg( printer_key, StatusW );
             /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
                and continue */
             TRACE("Printer already exists\n");
-            RegDeleteValueW(hkeyPrinter, May_Delete_Value);
+            RegDeleteValueW( printer_key, May_Delete_Value );
             /* flag that the PPD file should be checked for an update */
-            set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
-            RegCloseKey(hkeyPrinter);
+            set_reg_DWORD( printer_key, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
+            RegCloseKey( printer_key );
         }
         else
         {
             if (!ppd_dir && !(ppd_dir = get_ppd_dir())) break;
-            if (!add_printer_driver( nameW, ppd_dir )) continue;
+            if (!add_printer_driver( printer->name, ppd_dir )) continue;
 
-            port = heap_alloc( sizeof(CUPS_Port) + lstrlenW( nameW ) * sizeof(WCHAR) );
+            port = heap_alloc( sizeof(CUPS_Port) + lstrlenW( printer->name ) * sizeof(WCHAR) );
             lstrcpyW( port, CUPS_Port );
-            lstrcatW( port, nameW );
+            lstrcatW( port, printer->name );
 
-            memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
-            pi2.pPrinterName    = nameW;
+            memset( &pi2, 0, sizeof(PRINTER_INFO_2W) );
+            pi2.pPrinterName    = printer->name;
             pi2.pDatatype       = rawW;
             pi2.pPrintProcessor = WinPrintW;
-            pi2.pDriverName     = nameW;
-            pi2.pComment        = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
-            pi2.pLocation       = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
+            pi2.pDriverName     = printer->name;
+            pi2.pComment        = printer->comment;
+            pi2.pLocation       = printer->location;
             pi2.pPortName       = port;
             pi2.pParameters     = emptyStringW;
             pi2.pShareName      = emptyStringW;
             pi2.pSepFile        = emptyStringW;
 
-            added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
+            added_printer = AddPrinterW( NULL, 2, (BYTE *)&pi2 );
             if (added_printer) ClosePrinter( added_printer );
             else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
-                ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
+                ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w( printer->name ), GetLastError() );
 
             heap_free( port );
-            HeapFree( GetProcessHeap(), 0, pi2.pComment );
-            HeapFree( GetProcessHeap(), 0, pi2.pLocation );
-        }
-
-        hadprinter = TRUE;
-        if (dests[i].is_default) {
-            SetDefaultPrinterW(nameW);
-            haddefault = TRUE;
         }
+        if (printer->is_default) default_printer = printer->name;
     }
 
+    if (!default_printer && enum_params.num) default_printer = enum_params.printers[0].name;
+    if (default_printer) SetDefaultPrinterW( default_printer );
+
     if (ppd_dir)
     {
         RemoveDirectoryW( ppd_dir );
-        HeapFree( GetProcessHeap(), 0, ppd_dir );
+        heap_free( ppd_dir );
     }
-
-    if (hadprinter && !haddefault) {
-        MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
-        SetDefaultPrinterW(nameW);
-    }
-    pcupsFreeDests(nrofdests, dests);
-    RegCloseKey(hkeyPrinters);
+end:
+    heap_free( enum_params.printers );
+    RegCloseKey( printers_key );
     return TRUE;
 }
 
-#endif
-
 static void set_ppd_overrides( HANDLE printer )
 {
     WCHAR *wstr = NULL;
@@ -1493,11 +1453,7 @@ void WINSPOOL_LoadSystemPrinters(void)
     }
 
     old_printer_check( FALSE );
-
-#ifdef SONAME_LIBCUPS
-    CUPS_LoadPrinters();
-#endif
-
+    init_unix_printers();
     old_printer_check( TRUE );
 
     ReleaseMutex( init_mutex );
diff --git a/dlls/winspool.drv/wspool.h b/dlls/winspool.drv/wspool.h
index bca4a5ea02d..5a1f1038995 100644
--- a/dlls/winspool.drv/wspool.h
+++ b/dlls/winspool.drv/wspool.h
@@ -37,6 +37,22 @@ extern void WINSPOOL_LoadSystemPrinters(void) DECLSPEC_HIDDEN;
 #define FILENAME_DIALOG  100
 #define EDITBOX 201
 
+struct printer_info
+{
+    WCHAR *name;
+    WCHAR *comment;
+    WCHAR *location;
+    BOOL is_default;
+};
+
+struct enum_printers_params
+{
+    struct printer_info *printers;
+    unsigned int size;
+    unsigned int num;
+};
+
 #define UNIX_CALL( func, params ) unix_ ## func( params )
 
 NTSTATUS unix_process_attach( void * ) DECLSPEC_HIDDEN;
+NTSTATUS unix_enum_printers( void * ) DECLSPEC_HIDDEN;
-- 
2.23.0




More information about the wine-devel mailing list