[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