blob: 5057c0da69fd7a837b7bdbb277a24bba209bd4fd [file] [log] [blame]
Vincent Béron9a624912002-05-31 23:06:46 +00001/*
Huw D M Daviese39b6761999-05-17 16:20:51 +00002 * WINSPOOL functions
Vincent Béron9a624912002-05-31 23:06:46 +00003 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00004 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
Huw D M Davies7aaabc32000-05-25 23:02:46 +00006 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00008 * Copyright 2001 Marcus Meissner
Detlef Riekenbergae91e972008-02-26 23:09:55 +01009 * Copyright 2005-2008 Detlef Riekenberg
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000010 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Huw D M Daviese39b6761999-05-17 16:20:51 +000024 */
25
Marcus Meissnerab8b7db2001-04-27 18:02:46 +000026#include "config.h"
Marcus Meissnerf061f762002-11-12 02:22:24 +000027#include "wine/port.h"
Marcus Meissnerab8b7db2001-04-27 18:02:46 +000028
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000029#include <stdarg.h>
Alexandre Julliard49556bc2000-11-29 18:38:24 +000030#include <stdio.h>
Huw D M Daviese39b6761999-05-17 16:20:51 +000031#include <stdlib.h>
32#include <string.h>
33#include <ctype.h>
Huw D M Davies7aaabc32000-05-25 23:02:46 +000034#include <stddef.h>
Francois Gougetd867a772005-07-22 09:04:08 +000035#ifdef HAVE_UNISTD_H
36# include <unistd.h>
37#endif
Huw Davies0a4681f2005-07-20 17:48:53 +000038#include <signal.h>
Marcus Meissnerf061f762002-11-12 02:22:24 +000039#ifdef HAVE_CUPS_CUPS_H
Marcus Meissnerab8b7db2001-04-27 18:02:46 +000040# include <cups/cups.h>
41#endif
Dimitrie O. Paun297f3d82003-01-07 20:36:20 +000042
43#define NONAMELESSUNION
44#define NONAMELESSSTRUCT
45#include "wine/library.h"
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000046#include "windef.h"
Huw D M Daviese39b6761999-05-17 16:20:51 +000047#include "winbase.h"
Huw Davies686a9f92003-05-19 23:19:21 +000048#include "winuser.h"
Huw D M Daviese39b6761999-05-17 16:20:51 +000049#include "winerror.h"
50#include "winreg.h"
Francois Gouget3efacb02003-01-07 23:09:22 +000051#include "wingdi.h"
52#include "winspool.h"
Stefan Leichterfacaee42003-01-03 03:04:46 +000053#include "winternl.h"
Alexandre Julliard83f52d12000-09-26 22:20:14 +000054#include "wine/windef16.h"
Alexandre Julliardc7e7df82000-08-14 14:41:19 +000055#include "wine/unicode.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000056#include "wine/debug.h"
Huw Davies344090f2005-07-06 15:44:15 +000057#include "wine/list.h"
Huw D M Davies7aaabc32000-05-25 23:02:46 +000058#include "winnls.h"
Huw D M Daviese39b6761999-05-17 16:20:51 +000059
Detlef Riekenberg1e177382006-09-02 22:50:32 +020060#include "ddk/winsplp.h"
Huw Daviese502d4d2005-07-12 17:01:44 +000061#include "wspool.h"
62
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000063WINE_DEFAULT_DEBUG_CHANNEL(winspool);
Huw D M Daviese39b6761999-05-17 16:20:51 +000064
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +020065/* ############################### */
66
67static CRITICAL_SECTION monitor_handles_cs;
68static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
69{
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
73};
74static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
75
76
Huw Daviesdf9c4342005-07-05 11:00:09 +000077static CRITICAL_SECTION printer_handles_cs;
78static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
79{
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
Alexandre Julliard20a1a202005-09-09 10:19:44 +000082 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
Huw Daviesdf9c4342005-07-05 11:00:09 +000083};
84static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
85
Detlef Riekenberg1e177382006-09-02 22:50:32 +020086/* ############################### */
87
88typedef struct {
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +020089 struct list entry;
Detlef Riekenberg1e177382006-09-02 22:50:32 +020090 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97} monitor_t;
98
Huw Daviesdf9c4342005-07-05 11:00:09 +000099typedef struct {
Huw Davies6fd3c472005-07-08 14:19:18 +0000100 DWORD job_id;
101 HANDLE hf;
102} started_doc_t;
103
104typedef struct {
Huw Davies344090f2005-07-06 15:44:15 +0000105 struct list jobs;
Huw Davies48a52d02005-07-19 19:12:13 +0000106 LONG ref;
Robert Lunnonc22716f2005-10-24 15:03:02 +0000107} jobqueue_t;
Huw Davies48a52d02005-07-19 19:12:13 +0000108
109typedef struct {
110 LPWSTR name;
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +0100111 LPWSTR printername;
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +0100112 monitor_t *pm;
Detlef Riekenberg72b126b2007-01-05 01:09:46 +0100113 HANDLE hXcv;
Robert Lunnonc22716f2005-10-24 15:03:02 +0000114 jobqueue_t *queue;
Huw Davies6fd3c472005-07-08 14:19:18 +0000115 started_doc_t *doc;
Huw Daviesdf9c4342005-07-05 11:00:09 +0000116} opened_printer_t;
117
Huw Davies344090f2005-07-06 15:44:15 +0000118typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
Huw Davies1ed9bac2005-07-13 14:14:37 +0000122 WCHAR *document_title;
Huw Davies344090f2005-07-06 15:44:15 +0000123} job_t;
124
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100125
126typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +0200129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100132} printenv_t;
133
134/* ############################### */
135
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200136static struct list monitor_handles = LIST_INIT( monitor_handles );
Detlef Riekenberga7481a92006-11-28 20:04:08 +0100137static monitor_t * pm_localport;
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200138
Huw Daviesdf9c4342005-07-05 11:00:09 +0000139static opened_printer_t **printer_handles;
Detlef Riekenbergd244a552007-11-04 17:57:54 +0100140static UINT nb_printer_handles;
Kevin Koltzau7d8e3772005-09-29 13:34:34 +0000141static LONG next_job_id = 1;
Huw D M Daviese39b6761999-05-17 16:20:51 +0000142
Patrik Stridvall57e57842002-02-02 18:42:11 +0000143static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
Alexandre Julliard49556bc2000-11-29 18:38:24 +0000144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
Patrik Stridvall57e57842002-02-02 18:42:11 +0000146static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
Alexandre Julliard49556bc2000-11-29 18:38:24 +0000147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
150
Dimitrie O. Paund4193bb2005-03-29 13:10:35 +0000151static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +0200156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
Huw D M Daviese39b6761999-05-17 16:20:51 +0000157
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200158static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
Detlef Riekenberg1e2b9b72006-09-18 07:57:41 +0200162 'M','o','n','i','t','o','r','s','\\',0};
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200163
Detlef Riekenberg351106f2006-05-12 16:14:59 +0200164static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
169
Dmitry Timoshkov18049002006-11-29 18:04:13 +0800170static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200171
Huw Davies3d0b22b2005-03-31 10:06:46 +0000172static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
177
178static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
183
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +0100184static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
189
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200190static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
195
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000196static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100197static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
Detlef Riekenberg36a65152007-07-26 22:54:14 +0200201static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
202static const WCHAR Version0_SubdirW[] = {'\\','0',0};
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +0200203static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
204static const WCHAR Version3_SubdirW[] = {'\\','3',0};
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100205
206static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +0200207static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
Huw D M Davies7aaabc32000-05-25 23:02:46 +0000208
Detlef Riekenberg4b531542007-07-26 23:05:27 +0200209static const WCHAR backslashW[] = {'\\',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000210static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
Huw D M Davies7aaabc32000-05-25 23:02:46 +0000211 'i','o','n',' ','F','i','l','e',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000212static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
213static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200214static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
215static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000216static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200218static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000219static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
220static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200221static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000222static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
Detlef Riekenberge576b092007-01-11 13:10:37 +0100223static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000224static const WCHAR NameW[] = {'N','a','m','e',0};
Detlef Riekenbergae91e972008-02-26 23:09:55 +0100225static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200226static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000227static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
228static const WCHAR PortW[] = {'P','o','r','t',0};
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +0100229static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200230static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200234static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +0200235static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000237static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
Detlef Riekenberg29444b42007-08-15 23:30:59 +0200238static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000239static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
Stefan Leichter03210d42004-03-07 03:46:54 +0000240static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000241static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
Stefan Leichter03210d42004-03-07 03:46:54 +0000242static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243static const WCHAR emptyStringW[] = {0};
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +0100244static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000246
247static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
Huw D M Davies7aaabc32000-05-25 23:02:46 +0000248
Huw Daviesc108d802005-07-10 17:39:01 +0000249static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251static const WCHAR LPR_Port[] = {'L','P','R',':',0};
252
Huw Davies183fcb52005-07-15 09:55:23 +0000253static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
255
Detlef Riekenberga2daf752007-07-26 23:14:55 +0200256static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
Francois Gouget0c31ca32007-01-17 17:18:54 +0100260
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +0100261
262static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
263 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
264 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
265 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
266 sizeof(PRINTER_INFO_9W)};
267
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100268/******************************************************************
269 * validate the user-supplied printing-environment [internal]
270 *
271 * PARAMS
272 * env [I] PTR to Environment-String or NULL
273 *
274 * RETURNS
275 * Failure: NULL
276 * Success: PTR to printenv_t
277 *
278 * NOTES
Detlef Riekenberg366f4522006-02-01 12:32:10 +0100279 * An empty string is handled the same way as NULL.
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100280 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
281 *
282 */
283
284static const printenv_t * validate_envW(LPCWSTR env)
285{
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +0200286 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
287 3, Version3_RegPathW, Version3_SubdirW};
288 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
Detlef Riekenberg36a65152007-07-26 22:54:14 +0200289 0, Version0_RegPathW, Version0_SubdirW};
290
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100291 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
292
293 const printenv_t *result = NULL;
294 unsigned int i;
295
296 TRACE("testing %s\n", debugstr_w(env));
Detlef Riekenberg366f4522006-02-01 12:32:10 +0100297 if (env && env[0])
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +0100298 {
299 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
300 {
301 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
302 {
303 result = all_printenv[i];
304 break;
305 }
306 }
307
308 if (result == NULL) {
309 FIXME("unsupported Environment: %s\n", debugstr_w(env));
310 SetLastError(ERROR_INVALID_ENVIRONMENT);
311 }
312 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
313 }
314 else
315 {
316 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
317 }
318 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
319
320 return result;
321}
322
323
Duane Clark0987ae02003-02-12 01:19:25 +0000324/* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
325 if passed a NULL string. This returns NULLs to the result.
326*/
327static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
328{
329 if ( (src) )
330 {
331 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
332 return usBufferPtr->Buffer;
333 }
334 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
335 return NULL;
336}
337
Huw Davies183fcb52005-07-15 09:55:23 +0000338static LPWSTR strdupW(LPCWSTR p)
Huw Davies1ed9bac2005-07-13 14:14:37 +0000339{
340 LPWSTR ret;
341 DWORD len;
342
343 if(!p) return NULL;
344 len = (strlenW(p) + 1) * sizeof(WCHAR);
345 ret = HeapAlloc(GetProcessHeap(), 0, len);
346 memcpy(ret, p, len);
347 return ret;
348}
349
Alexandre Julliard27319982006-11-17 15:29:40 +0100350static LPSTR strdupWtoA( LPCWSTR str )
351{
352 LPSTR ret;
353 INT len;
354
355 if (!str) return NULL;
356 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
357 ret = HeapAlloc( GetProcessHeap(), 0, len );
358 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
359 return ret;
360}
361
Detlef Riekenberg29444b42007-08-15 23:30:59 +0200362/******************************************************************
Detlef Riekenberg29444b42007-08-15 23:30:59 +0200363 * Return the number of bytes for an multi_sz string.
364 * The result includes all \0s
365 * (specifically the extra \0, that is needed as multi_sz terminator).
366 */
Detlef Riekenberg6ec7c2d2008-02-08 00:41:24 +0100367#if 0
Detlef Riekenberg29444b42007-08-15 23:30:59 +0200368static int multi_sz_lenW(const WCHAR *str)
369{
370 const WCHAR *ptr = str;
371 if(!str) return 0;
372 do
373 {
374 ptr += lstrlenW(ptr) + 1;
375 } while(*ptr);
376
377 return (ptr - str + 1) * sizeof(WCHAR);
378}
Detlef Riekenberg6ec7c2d2008-02-08 00:41:24 +0100379#endif
Detlef Riekenberg29444b42007-08-15 23:30:59 +0200380/* ################################ */
381
Huw Davies1ad05ac2006-11-07 17:16:29 +0000382static int multi_sz_lenA(const char *str)
383{
384 const char *ptr = str;
385 if(!str) return 0;
386 do
387 {
388 ptr += lstrlenA(ptr) + 1;
389 } while(*ptr);
390
391 return ptr - str + 1;
392}
393
Vincent Béron9a624912002-05-31 23:06:46 +0000394static void
Vitaly Lipatovc9d78fc2007-02-18 13:51:09 +0300395WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
Marcus Meissner6d3e81b2001-05-18 20:57:36 +0000396 char qbuf[200];
397
398 /* If forcing, or no profile string entry for device yet, set the entry
399 *
400 * The always change entry if not WINEPS yet is discussable.
401 */
402 if (force ||
403 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
404 !strcmp(qbuf,"*") ||
Alexandre Julliardb3e9c442005-05-06 20:04:27 +0000405 !strstr(qbuf,"WINEPS.DRV")
Marcus Meissner6d3e81b2001-05-18 20:57:36 +0000406 ) {
Alexandre Julliardb3e9c442005-05-06 20:04:27 +0000407 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000408 HKEY hkey;
Marcus Meissner6d3e81b2001-05-18 20:57:36 +0000409
Alexandre Julliardb3e9c442005-05-06 20:04:27 +0000410 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
Marcus Meissner6d3e81b2001-05-18 20:57:36 +0000411 WriteProfileStringA("windows","device",buf);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000412 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
Mike McCormackbc4a5762005-08-03 11:03:44 +0000413 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000414 RegCloseKey(hkey);
415 }
Marcus Meissner6d3e81b2001-05-18 20:57:36 +0000416 HeapFree(GetProcessHeap(),0,buf);
417 }
418}
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000419
Vitaly Lipatovc9d78fc2007-02-18 13:51:09 +0300420static BOOL add_printer_driver(const char *name)
Huw Daviesd510bdc2006-11-07 17:19:06 +0000421{
422 DRIVER_INFO_3A di3a;
423
Detlef Riekenberg85061252007-08-22 20:24:35 +0200424 static char driver_9x[] = "wineps16.drv",
425 driver_nt[] = "wineps.drv",
426 env_9x[] = "Windows 4.0",
427 env_nt[] = "Windows NT x86",
428 data_file[] = "generic.ppd",
Huw Daviesd510bdc2006-11-07 17:19:06 +0000429 default_data_type[] = "RAW";
430
Detlef Riekenberg85061252007-08-22 20:24:35 +0200431 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
432 di3a.cVersion = 3;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000433 di3a.pName = (char *)name;
Detlef Riekenberg85061252007-08-22 20:24:35 +0200434 di3a.pEnvironment = env_nt;
435 di3a.pDriverPath = driver_nt;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000436 di3a.pDataFile = data_file;
Detlef Riekenberg85061252007-08-22 20:24:35 +0200437 di3a.pConfigFile = driver_nt;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000438 di3a.pDefaultDataType = default_data_type;
439
Detlef Riekenbergd6d02392007-11-05 22:48:07 +0100440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
Huw Daviesd510bdc2006-11-07 17:19:06 +0000442 {
Detlef Riekenberg85061252007-08-22 20:24:35 +0200443 di3a.cVersion = 0;
444 di3a.pEnvironment = env_9x;
445 di3a.pDriverPath = driver_9x;
446 di3a.pConfigFile = driver_9x;
Detlef Riekenbergd6d02392007-11-05 22:48:07 +0100447 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
448 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
Detlef Riekenberg85061252007-08-22 20:24:35 +0200449 {
450 return TRUE;
451 }
Huw Daviesd510bdc2006-11-07 17:19:06 +0000452 }
Detlef Riekenbergd6d02392007-11-05 22:48:07 +0100453 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
454 debugstr_a(di3a.pEnvironment), GetLastError());
Detlef Riekenberg85061252007-08-22 20:24:35 +0200455 return FALSE;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000456}
457
Alexandre Julliard702d3552007-07-02 17:30:44 +0200458#ifdef SONAME_LIBCUPS
Huw Davies18116de2005-07-11 13:21:48 +0000459static typeof(cupsGetDests) *pcupsGetDests;
460static typeof(cupsGetPPD) *pcupsGetPPD;
461static typeof(cupsPrintFile) *pcupsPrintFile;
462static void *cupshandle;
463
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000464static BOOL CUPS_LoadPrinters(void)
465{
Huw Davies6694ce92003-06-23 19:52:55 +0000466 int i, nrofdests;
Pedro Araujo Chaves Jrffbd30d2007-07-04 20:22:15 -0300467 BOOL hadprinter = FALSE, haddefault = FALSE;
Huw Davies6694ce92003-06-23 19:52:55 +0000468 cups_dest_t *dests;
469 PRINTER_INFO_2A pinfo2a;
Duane Clark45abf7c2003-02-12 21:27:27 +0000470 char *port,*devline;
Huw Davies3d0b22b2005-03-31 10:06:46 +0000471 HKEY hkeyPrinter, hkeyPrinters, hkey;
Detlef Riekenbergf976fc82007-07-30 19:41:03 +0200472 char loaderror[256];
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000473
Detlef Riekenbergf976fc82007-07-30 19:41:03 +0200474 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
475 if (!cupshandle) {
476 TRACE("%s\n", loaderror);
477 return FALSE;
478 }
479 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
Marcus Meissnerf061f762002-11-12 02:22:24 +0000480
481#define DYNCUPS(x) \
482 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
483 if (!p##x) return FALSE;
484
Marcus Meissnerf061f762002-11-12 02:22:24 +0000485 DYNCUPS(cupsGetPPD);
Huw Davies6694ce92003-06-23 19:52:55 +0000486 DYNCUPS(cupsGetDests);
Huw Davies18116de2005-07-11 13:21:48 +0000487 DYNCUPS(cupsPrintFile);
Marcus Meissnerf061f762002-11-12 02:22:24 +0000488#undef DYNCUPS
489
Detlef Riekenberg358ce062006-05-21 14:35:29 +0200490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000493 return FALSE;
494 }
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000495
Huw Davies6694ce92003-06-23 19:52:55 +0000496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000498 for (i=0;i<nrofdests;i++) {
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
Mike McCormackbc4a5762005-08-03 11:03:44 +0000507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000508 RegCloseKey(hkey);
509 }
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200510
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 RegCloseKey(hkey);
516 }
517
518 HeapFree(GetProcessHeap(), 0, devline);
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000519
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 and continue */
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
527 } else {
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
535
Huw Daviesd510bdc2006-11-07 17:19:06 +0000536 add_printer_driver(dests[i].name);
537
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000538 memset(&pinfo2a,0,sizeof(pinfo2a));
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000542 pinfo2a.pDriverName = dests[i].name;
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000549
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000553 }
554 }
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000555 HeapFree(GetProcessHeap(),0,port);
Huw Davies6694ce92003-06-23 19:52:55 +0000556
557 hadprinter = TRUE;
Pedro Araujo Chaves Jrffbd30d2007-07-04 20:22:15 -0300558 if (dests[i].is_default) {
Huw Davies6694ce92003-06-23 19:52:55 +0000559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
Pedro Araujo Chaves Jrffbd30d2007-07-04 20:22:15 -0300560 haddefault = TRUE;
561 }
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000562 }
Pedro Araujo Chaves Jrffbd30d2007-07-04 20:22:15 -0300563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
Huw Davies4b0fc2e2003-11-05 00:36:47 +0000565 RegCloseKey(hkeyPrinters);
Marcus Meissner0c630122001-05-09 17:10:41 +0000566 return hadprinter;
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000567}
568#endif
569
Marcus Meissner0c630122001-05-09 17:10:41 +0000570static BOOL
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100571PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
Marcus Meissner0c630122001-05-09 17:10:41 +0000572 PRINTER_INFO_2A pinfo2a;
Huw Daviese459f7a2003-11-11 00:42:35 +0000573 char *e,*s,*name,*prettyname,*devname;
574 BOOL ret = FALSE, set_default = FALSE;
Lionel Debroux87b33cc2007-12-14 14:56:57 +0100575 char *port = NULL, *devline,*env_default;
Huw Davies3d0b22b2005-03-31 10:06:46 +0000576 HKEY hkeyPrinter, hkeyPrinters, hkey;
Marcus Meissner0c630122001-05-09 17:10:41 +0000577
Bill Medlanddff78ed2002-05-17 00:10:15 +0000578 while (isspace(*pent)) pent++;
Marcus Meissner0c630122001-05-09 17:10:41 +0000579 s = strchr(pent,':');
Huw Daviese459f7a2003-11-11 00:42:35 +0000580 if(s) *s='\0';
581 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
582 strcpy(name,pent);
583 if(s) {
584 *s=':';
585 pent = s;
586 } else
587 pent = "";
588
589 TRACE("name=%s entry=%s\n",name, pent);
590
591 if(ispunct(*name)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
593 goto end;
594 }
595
596 if(strstr(pent,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
598 goto end;
599 }
Marcus Meissner0c630122001-05-09 17:10:41 +0000600
601 /* Determine whether this is a postscript printer. */
602
Huw Daviese459f7a2003-11-11 00:42:35 +0000603 ret = TRUE;
604 env_default = getenv("PRINTER");
Marcus Meissner0c630122001-05-09 17:10:41 +0000605 prettyname = name;
606 /* Get longest name, usually the one at the right for later display. */
Huw Daviese459f7a2003-11-11 00:42:35 +0000607 while((s=strchr(prettyname,'|'))) {
608 *s = '\0';
609 e = s;
610 while(isspace(*--e)) *e = '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname));
612 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
613 for(prettyname = s+1; isspace(*prettyname); prettyname++)
614 ;
615 }
616 e = prettyname + strlen(prettyname);
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
Marcus Meissner0c630122001-05-09 17:10:41 +0000620
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname = prettyname;
624 if (strlen(devname)>=CCHDEVICENAME-1)
625 devname = name;
Huw Daviese459f7a2003-11-11 00:42:35 +0000626 if (strlen(devname)>=CCHDEVICENAME-1) {
627 ret = FALSE;
628 goto end;
629 }
Marcus Meissner0c630122001-05-09 17:10:41 +0000630
Marcus Meissner0c630122001-05-09 17:10:41 +0000631 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
632 sprintf(port,"LPR:%s",name);
Marcus Meissner0c630122001-05-09 17:10:41 +0000633
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
636 sprintf(devline, "WINEPS.DRV,%s", port);
637 WriteProfileStringA("devices", devname, devline);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000638 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
Mike McCormackbc4a5762005-08-03 11:03:44 +0000639 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
Huw Davies3d0b22b2005-03-31 10:06:46 +0000640 RegCloseKey(hkey);
641 }
Detlef Riekenberg473717f2008-05-06 20:26:05 +0200642
643 lstrcatA(devline, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname, devline);
645 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
646 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
647 RegCloseKey(hkey);
648 }
649
Marcus Meissner0c630122001-05-09 17:10:41 +0000650 HeapFree(GetProcessHeap(),0,devline);
Huw Daviese459f7a2003-11-11 00:42:35 +0000651
Detlef Riekenberg358ce062006-05-21 14:35:29 +0200652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw Daviese459f7a2003-11-11 00:42:35 +0000653 ERROR_SUCCESS) {
654 ERR("Can't create Printers key\n");
655 ret = FALSE;
656 goto end;
Marcus Meissner0c630122001-05-09 17:10:41 +0000657 }
Huw Daviese459f7a2003-11-11 00:42:35 +0000658 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
660 and continue */
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
663 RegCloseKey(hkeyPrinter);
664 } else {
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100665 static CHAR data_type[] = "RAW",
666 print_proc[] = "WinPrint",
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100667 comment[] = "WINEPS Printer using LPR",
668 params[] = "<parameters?>",
669 share_name[] = "<share name?>",
670 sep_file[] = "<sep file?>";
671
Huw Daviesd510bdc2006-11-07 17:19:06 +0000672 add_printer_driver(devname);
673
Huw Daviese459f7a2003-11-11 00:42:35 +0000674 memset(&pinfo2a,0,sizeof(pinfo2a));
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100675 pinfo2a.pPrinterName = devname;
676 pinfo2a.pDatatype = data_type;
677 pinfo2a.pPrintProcessor = print_proc;
Huw Daviesd510bdc2006-11-07 17:19:06 +0000678 pinfo2a.pDriverName = devname;
Andrew Talbot02c04ea2006-08-19 14:22:39 +0100679 pinfo2a.pComment = comment;
680 pinfo2a.pLocation = prettyname;
681 pinfo2a.pPortName = port;
682 pinfo2a.pParameters = params;
683 pinfo2a.pShareName = share_name;
684 pinfo2a.pSepFile = sep_file;
Huw Daviese459f7a2003-11-11 00:42:35 +0000685
686 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200688 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
Huw Daviese459f7a2003-11-11 00:42:35 +0000689 }
690 }
691 RegCloseKey(hkeyPrinters);
692
693 if (isfirst || set_default)
694 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
695
Huw Daviese459f7a2003-11-11 00:42:35 +0000696 end:
Lionel Debroux87b33cc2007-12-14 14:56:57 +0100697 HeapFree(GetProcessHeap(), 0, port);
Huw Daviese459f7a2003-11-11 00:42:35 +0000698 HeapFree(GetProcessHeap(), 0, name);
699 return ret;
Marcus Meissner0c630122001-05-09 17:10:41 +0000700}
701
702static BOOL
703PRINTCAP_LoadPrinters(void) {
Huw Daviese459f7a2003-11-11 00:42:35 +0000704 BOOL hadprinter = FALSE;
Marcus Meissner0c630122001-05-09 17:10:41 +0000705 char buf[200];
706 FILE *f;
Huw Daviese459f7a2003-11-11 00:42:35 +0000707 char *pent = NULL;
708 BOOL had_bash = FALSE;
Marcus Meissner0c630122001-05-09 17:10:41 +0000709
710 f = fopen("/etc/printcap","r");
711 if (!f)
712 return FALSE;
713
Huw Daviese459f7a2003-11-11 00:42:35 +0000714 while(fgets(buf,sizeof(buf),f)) {
715 char *start, *end;
Marcus Meissner0c630122001-05-09 17:10:41 +0000716
Huw Daviese459f7a2003-11-11 00:42:35 +0000717 end=strchr(buf,'\n');
718 if (end) *end='\0';
719
720 start = buf;
721 while(isspace(*start)) start++;
722 if(*start == '#' || *start == '\0')
723 continue;
Marcus Meissner0c630122001-05-09 17:10:41 +0000724
Huw Daviese459f7a2003-11-11 00:42:35 +0000725 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
728 pent = NULL;
729 }
730
731 if (end && *--end == '\\') {
732 *end = '\0';
733 had_bash = TRUE;
734 } else
735 had_bash = FALSE;
736
737 if (pent) {
738 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
739 strcat(pent,start);
740 } else {
741 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
742 strcpy(pent,start);
743 }
744
745 }
746 if(pent) {
747 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
748 HeapFree(GetProcessHeap(),0,pent);
Marcus Meissner0c630122001-05-09 17:10:41 +0000749 }
750 fclose(f);
751 return hadprinter;
752}
753
Alexandre Julliard4d626b02003-11-11 20:38:51 +0000754static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
Gerard Patel14c94292001-10-28 21:16:38 +0000755{
Huw Davies6694ce92003-06-23 19:52:55 +0000756 if (value)
Eric Pouech0a258962004-11-30 21:38:57 +0000757 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
Huw Davies1ad05ac2006-11-07 17:16:29 +0000758 (lstrlenW(value) + 1) * sizeof(WCHAR));
Huw Davies6694ce92003-06-23 19:52:55 +0000759 else
760 return ERROR_FILE_NOT_FOUND;
Gerard Patel14c94292001-10-28 21:16:38 +0000761}
762
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200763/*****************************************************************************
Francois Gouget0c31ca32007-01-17 17:18:54 +0100764 * enumerate the local monitors (INTERNAL)
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200765 *
766 * returns the needed size (in bytes) for pMonitors
767 * and *lpreturned is set to number of entries returned in pMonitors
768 *
769 */
770static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
771{
772 HKEY hroot = NULL;
773 HKEY hentry = NULL;
774 LPWSTR ptr;
775 LPMONITOR_INFO_2W mi;
776 WCHAR buffer[MAX_PATH];
777 WCHAR dllname[MAX_PATH];
778 DWORD dllsize;
779 DWORD len;
780 DWORD index = 0;
781 DWORD needed = 0;
782 DWORD numentries;
783 DWORD entrysize;
784
785 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
786
787 numentries = *lpreturned; /* this is 0, when we scan the registry */
788 len = entrysize * numentries;
789 ptr = (LPWSTR) &pMonitors[len];
790
791 numentries = 0;
Rob Shearman35be5e12008-02-21 16:44:48 +0000792 len = sizeof(buffer)/sizeof(buffer[0]);
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200793 buffer[0] = '\0';
794
795 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
796 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
797 /* Scan all Monitor-Registry-Keys */
798 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200799 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
Rob Shearmanee8dd6a2008-02-21 16:44:42 +0000800 dllsize = sizeof(dllname);
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200801 dllname[0] = '\0';
802
803 /* The Monitor must have a Driver-DLL */
804 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
805 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
806 /* We found a valid DLL for this Monitor. */
807 TRACE("using Driver: %s\n", debugstr_w(dllname));
808 }
809 RegCloseKey(hentry);
810 }
811
812 /* Windows returns only Port-Monitors here, but to simplify our code,
813 we do no filtering for Language-Monitors */
814 if (dllname[0]) {
815 numentries++;
816 needed += entrysize;
817 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
818 if (level > 1) {
819 /* we install and return only monitors for "Windows NT x86" */
820 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
821 needed += dllsize;
822 }
823
824 /* required size is calculated. Now fill the user-buffer */
825 if (pMonitors && (cbBuf >= needed)){
826 mi = (LPMONITOR_INFO_2W) pMonitors;
827 pMonitors += entrysize;
828
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200829 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200830 mi->pName = ptr;
831 lstrcpyW(ptr, buffer); /* Name of the Monitor */
832 ptr += (len+1); /* len is lstrlenW(monitorname) */
833 if (level > 1) {
834 mi->pEnvironment = ptr;
835 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
836 ptr += (lstrlenW(envname_x86W)+1);
837
838 mi->pDLLName = ptr;
839 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
840 ptr += (dllsize / sizeof(WCHAR));
841 }
842 }
843 }
844 index++;
Rob Shearman18d89192008-02-25 09:01:29 +0000845 len = sizeof(buffer)/sizeof(buffer[0]);
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200846 buffer[0] = '\0';
847 }
848 RegCloseKey(hroot);
849 }
850 *lpreturned = numentries;
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200851 TRACE("need %d byte for %d entries\n", needed, numentries);
Detlef Riekenberg4b008052006-03-31 14:30:10 +0200852 return needed;
853}
Marcus Meissnerab8b7db2001-04-27 18:02:46 +0000854
Huw D M Daviese39b6761999-05-17 16:20:51 +0000855/******************************************************************
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200856 * monitor_unload [internal]
857 *
858 * release a printmonitor and unload it from memory, when needed
859 *
860 */
861static void monitor_unload(monitor_t * pm)
862{
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +0100863 if (pm == NULL) return;
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200864 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200865
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200866 EnterCriticalSection(&monitor_handles_cs);
867
868 if (pm->refcount) pm->refcount--;
869
870 if (pm->refcount == 0) {
871 list_remove(&pm->entry);
872 FreeLibrary(pm->hdll);
873 HeapFree(GetProcessHeap(), 0, pm->name);
874 HeapFree(GetProcessHeap(), 0, pm->dllname);
875 HeapFree(GetProcessHeap(), 0, pm);
876 }
877 LeaveCriticalSection(&monitor_handles_cs);
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200878}
879
880/******************************************************************
Detlef Riekenberg412acde2006-11-04 00:27:16 +0100881 * monitor_unloadall [internal]
882 *
883 * release all printmonitors and unload them from memory, when needed
884 */
885
886static void monitor_unloadall(void)
887{
888 monitor_t * pm;
889 monitor_t * next;
890
891 EnterCriticalSection(&monitor_handles_cs);
892 /* iterate through the list, with safety against removal */
893 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
894 {
895 monitor_unload(pm);
896 }
897 LeaveCriticalSection(&monitor_handles_cs);
898}
899
900/******************************************************************
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200901 * monitor_load [internal]
902 *
903 * load a printmonitor, get the dllname from the registry, when needed
904 * initialize the monitor and dump found function-pointers
905 *
906 * On failure, SetLastError() is called and NULL is returned
907 */
908
Dmitry Timoshkov18049002006-11-29 18:04:13 +0800909static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200910{
911 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
912 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
913 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
914 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
915 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
916
917 monitor_t * pm = NULL;
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200918 monitor_t * cursor;
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200919 LPWSTR regroot = NULL;
920 LPWSTR driver = dllname;
921
922 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
923 /* Is the Monitor already loaded? */
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200924 EnterCriticalSection(&monitor_handles_cs);
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200925
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +0100926 if (name) {
927 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
928 {
929 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
930 pm = cursor;
931 break;
932 }
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200933 }
934 }
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200935
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200936 if (pm == NULL) {
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200937 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
938 if (pm == NULL) goto cleanup;
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +0200939 list_add_tail(&monitor_handles, &pm->entry);
940 }
941 pm->refcount++;
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200942
943 if (pm->name == NULL) {
944 /* Load the monitor */
945 LPMONITOREX pmonitorEx;
946 DWORD len;
947
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +0100948 if (name) {
949 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
950 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
951 }
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200952
953 if (regroot) {
954 lstrcpyW(regroot, MonitorsW);
955 lstrcatW(regroot, name);
956 /* Get the Driver from the Registry */
Detlef Riekenberg0bd336a2006-11-04 00:26:20 +0100957 if (driver == NULL) {
958 HKEY hroot;
959 DWORD namesize;
960 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
961 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
962 &namesize) == ERROR_SUCCESS) {
963 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
964 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
965 }
966 RegCloseKey(hroot);
967 }
968 }
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200969 }
970
971 pm->name = strdupW(name);
972 pm->dllname = strdupW(driver);
973
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +0100974 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200975 monitor_unload(pm);
976 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
977 pm = NULL;
978 goto cleanup;
979 }
980
981 pm->hdll = LoadLibraryW(driver);
Hans Leidekker61faa6b2006-10-13 11:51:23 +0200982 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
Detlef Riekenberg1e177382006-09-02 22:50:32 +0200983
984 if (pm->hdll == NULL) {
985 monitor_unload(pm);
986 SetLastError(ERROR_MOD_NOT_FOUND);
987 pm = NULL;
988 goto cleanup;
989 }
990
991 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
992 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
993 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
994 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
995 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
996
997
998 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
999 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1000 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1001 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1002 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1003
1004 if (pInitializePrintMonitorUI != NULL) {
1005 pm->monitorUI = pInitializePrintMonitorUI();
1006 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1007 if (pm->monitorUI) {
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02001008 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1009 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001010
1011 }
1012 }
1013
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +01001014 if (pInitializePrintMonitor && regroot) {
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001015 pmonitorEx = pInitializePrintMonitor(regroot);
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +01001016 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1017 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001018
1019 if (pmonitorEx) {
1020 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1021 pm->monitor = &(pmonitorEx->Monitor);
1022 }
1023 }
1024
1025 if (pm->monitor) {
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02001026 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001027
1028 }
1029
Detlef Riekenberg9bdd9002007-01-11 13:05:16 +01001030 if (!pm->monitor && regroot) {
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001031 if (pInitializePrintMonitor2 != NULL) {
1032 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1033 }
1034 if (pInitializeMonitorEx != NULL) {
1035 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1036 }
1037 if (pInitializeMonitor != NULL) {
1038 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1039 }
1040 }
1041 if (!pm->monitor && !pm->monitorUI) {
1042 monitor_unload(pm);
1043 SetLastError(ERROR_PROC_NOT_FOUND);
1044 pm = NULL;
1045 }
1046 }
1047cleanup:
Detlef Riekenberga7481a92006-11-28 20:04:08 +01001048 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1049 pm->refcount++;
1050 pm_localport = pm;
1051 }
Detlef Riekenbergec1c7cc2006-09-02 22:55:25 +02001052 LeaveCriticalSection(&monitor_handles_cs);
Detlef Riekenberg1e177382006-09-02 22:50:32 +02001053 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1054 HeapFree(GetProcessHeap(), 0, regroot);
1055 TRACE("=> %p\n", pm);
1056 return pm;
1057}
1058
1059/******************************************************************
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001060 * monitor_loadall [internal]
1061 *
1062 * Load all registered monitors
1063 *
1064 */
1065static DWORD monitor_loadall(void)
1066{
1067 monitor_t * pm;
1068 DWORD registered = 0;
1069 DWORD loaded = 0;
1070 HKEY hmonitors;
1071 WCHAR buffer[MAX_PATH];
1072 DWORD id = 0;
1073
1074 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1075 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1076 NULL, NULL, NULL, NULL, NULL);
1077
1078 TRACE("%d monitors registered\n", registered);
1079
1080 EnterCriticalSection(&monitor_handles_cs);
1081 while (id < registered) {
1082 buffer[0] = '\0';
1083 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1084 pm = monitor_load(buffer, NULL);
1085 if (pm) loaded++;
1086 id++;
1087 }
1088 LeaveCriticalSection(&monitor_handles_cs);
1089 RegCloseKey(hmonitors);
1090 }
1091 TRACE("%d monitors loaded\n", loaded);
1092 return loaded;
1093}
1094
1095/******************************************************************
Detlef Riekenberge576b092007-01-11 13:10:37 +01001096 * monitor_loadui [internal]
1097 *
1098 * load the userinterface-dll for a given portmonitor
1099 *
1100 * On failure, NULL is returned
1101 */
1102
1103static monitor_t * monitor_loadui(monitor_t * pm)
1104{
1105 monitor_t * pui = NULL;
1106 LPWSTR buffer[MAX_PATH];
1107 HANDLE hXcv;
1108 DWORD len;
1109 DWORD res;
1110
1111 if (pm == NULL) return NULL;
1112 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1113
1114 /* Try the Portmonitor first; works for many monitors */
1115 if (pm->monitorUI) {
1116 EnterCriticalSection(&monitor_handles_cs);
1117 pm->refcount++;
1118 LeaveCriticalSection(&monitor_handles_cs);
1119 return pm;
1120 }
1121
1122 /* query the userinterface-dllname from the Portmonitor */
1123 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1124 /* building (",XcvMonitor %s",pm->name) not needed yet */
1125 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1126 TRACE("got %u with %p\n", res, hXcv);
1127 if (res) {
1128 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1129 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1130 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1131 pm->monitor->pfnXcvClosePort(hXcv);
1132 }
1133 }
1134 return pui;
1135}
1136
1137
1138/******************************************************************
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01001139 * monitor_load_by_port [internal]
1140 *
1141 * load a printmonitor for a given port
1142 *
1143 * On failure, NULL is returned
1144 */
1145
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001146static monitor_t * monitor_load_by_port(LPCWSTR portname)
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01001147{
1148 HKEY hroot;
1149 HKEY hport;
1150 LPWSTR buffer;
1151 monitor_t * pm = NULL;
1152 DWORD registered = 0;
1153 DWORD id = 0;
1154 DWORD len;
1155
1156 TRACE("(%s)\n", debugstr_w(portname));
1157
1158 /* Try the Local Monitor first */
1159 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1160 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1161 /* found the portname */
1162 RegCloseKey(hroot);
1163 return monitor_load(LocalPortW, NULL);
1164 }
1165 RegCloseKey(hroot);
1166 }
1167
1168 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1169 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1170 if (buffer == NULL) return NULL;
1171
1172 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1173 EnterCriticalSection(&monitor_handles_cs);
1174 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1175
1176 while ((pm == NULL) && (id < registered)) {
1177 buffer[0] = '\0';
1178 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1179 TRACE("testing %s\n", debugstr_w(buffer));
1180 len = lstrlenW(buffer);
1181 lstrcatW(buffer, bs_Ports_bsW);
1182 lstrcatW(buffer, portname);
1183 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1184 RegCloseKey(hport);
1185 buffer[len] = '\0'; /* use only the Monitor-Name */
1186 pm = monitor_load(buffer, NULL);
1187 }
1188 id++;
1189 }
1190 LeaveCriticalSection(&monitor_handles_cs);
1191 RegCloseKey(hroot);
1192 }
1193 HeapFree(GetProcessHeap(), 0, buffer);
1194 return pm;
1195}
1196
1197/******************************************************************
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001198 * enumerate the local Ports from all loaded monitors (internal)
1199 *
1200 * returns the needed size (in bytes) for pPorts
1201 * and *lpreturned is set to number of entries returned in pPorts
1202 *
1203 */
1204static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1205{
1206 monitor_t * pm;
1207 LPWSTR ptr;
1208 LPPORT_INFO_2W cache;
1209 LPPORT_INFO_2W out;
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001210 LPBYTE pi_buffer = NULL;
1211 DWORD pi_allocated = 0;
1212 DWORD pi_needed;
1213 DWORD pi_index;
1214 DWORD pi_returned;
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001215 DWORD res;
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001216 DWORD outindex = 0;
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001217 DWORD needed;
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001218 DWORD numentries;
1219 DWORD entrysize;
1220
1221
1222 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1223 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1224
1225 numentries = *lpreturned; /* this is 0, when we scan the registry */
1226 needed = entrysize * numentries;
1227 ptr = (LPWSTR) &pPorts[needed];
1228
1229 numentries = 0;
1230 needed = 0;
1231
1232 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1233 {
1234 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001235 pi_needed = 0;
1236 pi_returned = 0;
1237 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1238 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1239 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1240 HeapFree(GetProcessHeap(), 0, pi_buffer);
1241 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1242 pi_allocated = (pi_buffer) ? pi_needed : 0;
1243 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001244 }
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001245 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1246 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001247
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001248 numentries += pi_returned;
1249 needed += pi_needed;
1250
1251 /* fill the output-buffer (pPorts), if we have one */
1252 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1253 pi_index = 0;
1254 while (pi_returned > pi_index) {
1255 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001256 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1257 out->pPortName = ptr;
1258 lstrcpyW(ptr, cache->pPortName);
1259 ptr += (lstrlenW(ptr)+1);
1260 if (level > 1) {
1261 out->pMonitorName = ptr;
1262 lstrcpyW(ptr, cache->pMonitorName);
1263 ptr += (lstrlenW(ptr)+1);
1264
1265 out->pDescription = ptr;
1266 lstrcpyW(ptr, cache->pDescription);
1267 ptr += (lstrlenW(ptr)+1);
1268 out->fPortType = cache->fPortType;
1269 out->Reserved = cache->Reserved;
1270 }
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001271 pi_index++;
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001272 outindex++;
1273 }
1274 }
1275 }
1276 }
Detlef Riekenberg4cd9d532007-03-29 17:38:16 +02001277 /* the temporary portinfo-buffer is no longer needed */
1278 HeapFree(GetProcessHeap(), 0, pi_buffer);
Detlef Riekenberg412acde2006-11-04 00:27:16 +01001279
1280 *lpreturned = numentries;
1281 TRACE("need %d byte for %d entries\n", needed, numentries);
1282 return needed;
1283}
1284
1285/******************************************************************
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001286 * get_servername_from_name (internal)
1287 *
1288 * for an external server, a copy of the serverpart from the full name is returned
1289 *
1290 */
1291static LPWSTR get_servername_from_name(LPCWSTR name)
1292{
1293 LPWSTR server;
1294 LPWSTR ptr;
1295 WCHAR buffer[MAX_PATH];
1296 DWORD len;
1297
1298 if (name == NULL) return NULL;
1299 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1300
1301 server = strdupW(&name[2]); /* skip over both backslash */
1302 if (server == NULL) return NULL;
1303
1304 /* strip '\' and the printername */
1305 ptr = strchrW(server, '\\');
1306 if (ptr) ptr[0] = '\0';
1307
1308 TRACE("found %s\n", debugstr_w(server));
1309
1310 len = sizeof(buffer)/sizeof(buffer[0]);
1311 if (GetComputerNameW(buffer, &len)) {
1312 if (lstrcmpW(buffer, server) == 0) {
1313 /* The requested Servername is our computername */
1314 HeapFree(GetProcessHeap(), 0, server);
1315 return NULL;
1316 }
1317 }
1318 return server;
1319}
1320
1321/******************************************************************
1322 * get_basename_from_name (internal)
1323 *
1324 * skip over the serverpart from the full name
1325 *
1326 */
1327static LPCWSTR get_basename_from_name(LPCWSTR name)
1328{
1329 if (name == NULL) return NULL;
1330 if ((name[0] == '\\') && (name[1] == '\\')) {
1331 /* skip over the servername and search for the following '\' */
1332 name = strchrW(&name[2], '\\');
1333 if ((name) && (name[1])) {
Francois Gougetb0bde6b2007-01-18 11:35:50 +01001334 /* found a separator ('\') followed by a name:
1335 skip over the separator and return the rest */
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001336 name++;
1337 }
1338 else
1339 {
1340 /* no basename present (we found only a servername) */
1341 return NULL;
1342 }
1343 }
1344 return name;
1345}
1346
1347/******************************************************************
Huw Daviesdf9c4342005-07-05 11:00:09 +00001348 * get_opened_printer_entry
Huw D M Daviese39b6761999-05-17 16:20:51 +00001349 * Get the first place empty in the opened printer table
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001350 *
1351 * ToDo:
1352 * - pDefault is ignored
Huw D M Daviese39b6761999-05-17 16:20:51 +00001353 */
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001354static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
Huw D M Daviese39b6761999-05-17 16:20:51 +00001355{
Kevin Koltzau7d8e3772005-09-29 13:34:34 +00001356 UINT_PTR handle = nb_printer_handles, i;
Robert Lunnonc22716f2005-10-24 15:03:02 +00001357 jobqueue_t *queue = NULL;
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001358 opened_printer_t *printer = NULL;
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001359 LPWSTR servername;
1360 LPCWSTR printername;
1361 HKEY hkeyPrinters;
1362 HKEY hkeyPrinter;
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001363 DWORD len;
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001364
1365 servername = get_servername_from_name(name);
1366 if (servername) {
1367 FIXME("server %s not supported\n", debugstr_w(servername));
1368 HeapFree(GetProcessHeap(), 0, servername);
1369 SetLastError(ERROR_INVALID_PRINTER_NAME);
1370 return NULL;
1371 }
1372
1373 printername = get_basename_from_name(name);
1374 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1375
1376 /* an empty printername is invalid */
1377 if (printername && (!printername[0])) {
1378 SetLastError(ERROR_INVALID_PARAMETER);
1379 return NULL;
1380 }
Thuy Nguyen6374cd21999-08-15 16:34:22 +00001381
Huw Daviesdf9c4342005-07-05 11:00:09 +00001382 EnterCriticalSection(&printer_handles_cs);
Alexandre Julliarde1635e92001-02-28 05:26:08 +00001383
Huw Davies48a52d02005-07-19 19:12:13 +00001384 for (i = 0; i < nb_printer_handles; i++)
1385 {
1386 if (!printer_handles[i])
1387 {
1388 if(handle == nb_printer_handles)
1389 handle = i;
1390 }
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001391 else
1392 {
1393 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1394 queue = printer_handles[i]->queue;
1395 }
Huw Davies48a52d02005-07-19 19:12:13 +00001396 }
Huw Daviesdf9c4342005-07-05 11:00:09 +00001397
1398 if (handle >= nb_printer_handles)
Thuy Nguyen6374cd21999-08-15 16:34:22 +00001399 {
Huw Daviesdf9c4342005-07-05 11:00:09 +00001400 opened_printer_t **new_array;
1401 if (printer_handles)
1402 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1403 (nb_printer_handles + 16) * sizeof(*new_array) );
Huw Davies344090f2005-07-06 15:44:15 +00001404 else
Huw Daviesdf9c4342005-07-05 11:00:09 +00001405 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1406 (nb_printer_handles + 16) * sizeof(*new_array) );
Oleg Prokhorovcf8b84c2003-10-15 21:01:05 +00001407
Huw Daviesdf9c4342005-07-05 11:00:09 +00001408 if (!new_array)
1409 {
1410 handle = 0;
1411 goto end;
1412 }
1413 printer_handles = new_array;
1414 nb_printer_handles += 16;
Thuy Nguyen6374cd21999-08-15 16:34:22 +00001415 }
1416
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001417 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
Thuy Nguyen6374cd21999-08-15 16:34:22 +00001418 {
Huw Daviesdf9c4342005-07-05 11:00:09 +00001419 handle = 0;
1420 goto end;
Thuy Nguyen6374cd21999-08-15 16:34:22 +00001421 }
Huw Daviesdf9c4342005-07-05 11:00:09 +00001422
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001423
1424 /* clone the base name. This is NULL for the printserver */
1425 printer->printername = strdupW(printername);
1426
1427 /* clone the full name */
1428 printer->name = strdupW(name);
1429 if (name && (!printer->name)) {
1430 handle = 0;
1431 goto end;
1432 }
1433
1434 if (printername) {
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001435 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1436 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1437 /* OpenPrinter(",XcvMonitor " detected */
1438 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1439 printer->pm = monitor_load(&printername[len], NULL);
1440 if (printer->pm == NULL) {
Detlef Riekenbergfc780342007-04-30 10:37:58 +02001441 SetLastError(ERROR_UNKNOWN_PORT);
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001442 handle = 0;
1443 goto end;
1444 }
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001445 }
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001446 else
1447 {
1448 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1449 if (strncmpW( printername, XcvPortW, len) == 0) {
1450 /* OpenPrinter(",XcvPort " detected */
1451 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1452 printer->pm = monitor_load_by_port(&printername[len]);
1453 if (printer->pm == NULL) {
Detlef Riekenbergfc780342007-04-30 10:37:58 +02001454 SetLastError(ERROR_UNKNOWN_PORT);
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001455 handle = 0;
1456 goto end;
1457 }
1458 }
1459 }
1460
1461 if (printer->pm) {
Detlef Riekenberg72b126b2007-01-05 01:09:46 +01001462 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
Detlef Riekenberg6b7c4822007-04-30 10:41:02 +02001463 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1464 pDefault ? pDefault->DesiredAccess : 0,
1465 &printer->hXcv);
Detlef Riekenberg72b126b2007-01-05 01:09:46 +01001466 }
1467 if (printer->hXcv == NULL) {
1468 SetLastError(ERROR_INVALID_PARAMETER);
1469 handle = 0;
1470 goto end;
1471 }
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001472 }
1473 else
1474 {
1475 /* Does the Printer exist? */
1476 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1477 ERR("Can't create Printers key\n");
1478 handle = 0;
1479 goto end;
1480 }
1481 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
Francois Gouget42c41142007-01-18 11:37:51 +01001482 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001483 RegCloseKey(hkeyPrinters);
1484 SetLastError(ERROR_INVALID_PRINTER_NAME);
1485 handle = 0;
1486 goto end;
1487 }
1488 RegCloseKey(hkeyPrinter);
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001489 RegCloseKey(hkeyPrinters);
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001490 }
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001491 }
1492 else
1493 {
1494 TRACE("using the local printserver\n");
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001495 }
1496
Huw Davies48a52d02005-07-19 19:12:13 +00001497 if(queue)
1498 printer->queue = queue;
1499 else
1500 {
1501 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001502 if (!printer->queue) {
1503 handle = 0;
1504 goto end;
1505 }
Huw Davies48a52d02005-07-19 19:12:13 +00001506 list_init(&printer->queue->jobs);
1507 printer->queue->ref = 0;
1508 }
1509 InterlockedIncrement(&printer->queue->ref);
Huw Daviesdf9c4342005-07-05 11:00:09 +00001510
Huw Davies344090f2005-07-06 15:44:15 +00001511 printer_handles[handle] = printer;
Huw Daviesdf9c4342005-07-05 11:00:09 +00001512 handle++;
1513end:
1514 LeaveCriticalSection(&printer_handles_cs);
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001515 if (!handle && printer) {
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001516 /* Something failed: Free all resources */
Detlef Riekenberg72b126b2007-01-05 01:09:46 +01001517 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01001518 monitor_unload(printer->pm);
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01001519 HeapFree(GetProcessHeap(), 0, printer->printername);
Detlef Riekenberg351106f2006-05-12 16:14:59 +02001520 HeapFree(GetProcessHeap(), 0, printer->name);
1521 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1522 HeapFree(GetProcessHeap(), 0, printer);
1523 }
Huw Daviesdf9c4342005-07-05 11:00:09 +00001524
1525 return (HANDLE)handle;
Huw D M Daviese39b6761999-05-17 16:20:51 +00001526}
1527
1528/******************************************************************
Huw Daviesdf9c4342005-07-05 11:00:09 +00001529 * get_opened_printer
Huw D M Daviese39b6761999-05-17 16:20:51 +00001530 * Get the pointer to the opened printer referred by the handle
1531 */
Huw Daviesdf9c4342005-07-05 11:00:09 +00001532static opened_printer_t *get_opened_printer(HANDLE hprn)
Huw D M Daviese39b6761999-05-17 16:20:51 +00001533{
Kevin Koltzau7d8e3772005-09-29 13:34:34 +00001534 UINT_PTR idx = (UINT_PTR)hprn;
Huw Daviesdf9c4342005-07-05 11:00:09 +00001535 opened_printer_t *ret = NULL;
1536
1537 EnterCriticalSection(&printer_handles_cs);
1538
Detlef Riekenbergd244a552007-11-04 17:57:54 +01001539 if ((idx > 0) && (idx <= nb_printer_handles)) {
1540 ret = printer_handles[idx - 1];
1541 }
Huw Daviesdf9c4342005-07-05 11:00:09 +00001542 LeaveCriticalSection(&printer_handles_cs);
1543 return ret;
1544}
1545
1546/******************************************************************
1547 * get_opened_printer_name
1548 * Get the pointer to the opened printer name referred by the handle
1549 */
1550static LPCWSTR get_opened_printer_name(HANDLE hprn)
1551{
1552 opened_printer_t *printer = get_opened_printer(hprn);
1553 if(!printer) return NULL;
1554 return printer->name;
Huw D M Daviese39b6761999-05-17 16:20:51 +00001555}
1556
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001557/******************************************************************
1558 * WINSPOOL_GetOpenedPrinterRegKey
1559 *
1560 */
1561static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1562{
Huw Daviesdf9c4342005-07-05 11:00:09 +00001563 LPCWSTR name = get_opened_printer_name(hPrinter);
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001564 DWORD ret;
1565 HKEY hkeyPrinters;
1566
Alexandre Julliarde1635e92001-02-28 05:26:08 +00001567 if(!name) return ERROR_INVALID_HANDLE;
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001568
Detlef Riekenberg358ce062006-05-21 14:35:29 +02001569 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001570 ERROR_SUCCESS)
1571 return ret;
1572
Alexandre Julliarde1635e92001-02-28 05:26:08 +00001573 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1574 {
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001575 ERR("Can't find opened printer %s in registry\n",
Huw Daviesdf9c4342005-07-05 11:00:09 +00001576 debugstr_w(name));
1577 RegCloseKey(hkeyPrinters);
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00001578 return ERROR_INVALID_PRINTER_NAME; /* ? */
1579 }
1580 RegCloseKey(hkeyPrinters);
1581 return ERROR_SUCCESS;
1582}
1583
Francois Gouget0c31ca32007-01-17 17:18:54 +01001584void WINSPOOL_LoadSystemPrinters(void)
1585{
1586 HKEY hkey, hkeyPrinters;
1587 HANDLE hprn;
1588 DWORD needed, num, i;
1589 WCHAR PrinterName[256];
1590 BOOL done = FALSE;
1591
1592 /* This ensures that all printer entries have a valid Name value. If causes
1593 problems later if they don't. If one is found to be missed we create one
1594 and set it equal to the name of the key */
1595 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1596 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1597 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1598 for(i = 0; i < num; i++) {
Vitaly Lipatov914e78a2007-12-01 19:43:37 +03001599 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
Francois Gouget0c31ca32007-01-17 17:18:54 +01001600 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1601 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1602 set_reg_szW(hkey, NameW, PrinterName);
1603 }
1604 RegCloseKey(hkey);
1605 }
1606 }
1607 }
1608 }
1609 RegCloseKey(hkeyPrinters);
1610 }
1611
1612 /* We want to avoid calling AddPrinter on printers as much as
1613 possible, because on cups printers this will (eventually) lead
1614 to a call to cupsGetPPD which takes forever, even with non-cups
1615 printers AddPrinter takes a while. So we'll tag all printers that
1616 were automatically added last time around, if they still exist
1617 we'll leave them be otherwise we'll delete them. */
1618 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1619 if(needed) {
1620 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1621 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1622 for(i = 0; i < num; i++) {
1623 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1624 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1625 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1626 DWORD dw = 1;
1627 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1628 RegCloseKey(hkey);
1629 }
1630 ClosePrinter(hprn);
1631 }
1632 }
1633 }
1634 }
1635 HeapFree(GetProcessHeap(), 0, pi);
1636 }
1637
1638
Alexandre Julliard702d3552007-07-02 17:30:44 +02001639#ifdef SONAME_LIBCUPS
Francois Gouget0c31ca32007-01-17 17:18:54 +01001640 done = CUPS_LoadPrinters();
1641#endif
1642
Huw Davies37b671c2007-01-30 21:27:11 +00001643 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1644 PRINTCAP_LoadPrinters();
Francois Gouget0c31ca32007-01-17 17:18:54 +01001645
Francois Gougetb2bc7122007-09-27 18:57:51 +02001646 /* Now enumerate the list again and delete any printers that are still tagged */
Francois Gouget0c31ca32007-01-17 17:18:54 +01001647 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1648 if(needed) {
1649 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1650 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1651 for(i = 0; i < num; i++) {
1652 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1653 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1654 BOOL delete_driver = FALSE;
1655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1656 DWORD dw, type, size = sizeof(dw);
1657 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1658 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1659 DeletePrinter(hprn);
1660 delete_driver = TRUE;
1661 }
1662 RegCloseKey(hkey);
1663 }
1664 ClosePrinter(hprn);
1665 if(delete_driver)
1666 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1667 }
1668 }
1669 }
1670 }
1671 HeapFree(GetProcessHeap(), 0, pi);
1672 }
1673
1674 return;
1675
1676}
1677
Huw Davies1ed9bac2005-07-13 14:14:37 +00001678/******************************************************************
1679 * get_job
1680 *
1681 * Get the pointer to the specified job.
1682 * Should hold the printer_handles_cs before calling.
1683 */
1684static job_t *get_job(HANDLE hprn, DWORD JobId)
1685{
1686 opened_printer_t *printer = get_opened_printer(hprn);
1687 job_t *job;
1688
1689 if(!printer) return NULL;
Huw Davies48a52d02005-07-19 19:12:13 +00001690 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
Huw Davies1ed9bac2005-07-13 14:14:37 +00001691 {
1692 if(job->job_id == JobId)
1693 return job;
1694 }
1695 return NULL;
1696}
1697
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001698/***********************************************************
1699 * DEVMODEcpyAtoW
1700 */
1701static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1702{
1703 BOOL Formname;
Eric Pouech0a258962004-11-30 21:38:57 +00001704 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001705 DWORD size;
1706
1707 Formname = (dmA->dmSize > off_formname);
1708 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
Mike McCormack516a5772005-08-19 10:04:03 +00001709 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1710 dmW->dmDeviceName, CCHDEVICENAME);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001711 if(!Formname) {
1712 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1713 dmA->dmSize - CCHDEVICENAME);
1714 } else {
1715 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1716 off_formname - CCHDEVICENAME);
Mike McCormack516a5772005-08-19 10:04:03 +00001717 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1718 dmW->dmFormName, CCHFORMNAME);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001719 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1720 (off_formname + CCHFORMNAME));
1721 }
1722 dmW->dmSize = size;
Eric Pouech0a258962004-11-30 21:38:57 +00001723 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001724 dmA->dmDriverExtra);
1725 return dmW;
1726}
1727
1728/***********************************************************
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001729 * DEVMODEdupWtoA
1730 * Creates an ansi copy of supplied devmode
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001731 */
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001732static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001733{
1734 LPDEVMODEA dmA;
1735 DWORD size;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001736
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001737 if (!dmW) return NULL;
1738 size = dmW->dmSize - CCHDEVICENAME -
1739 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1740
1741 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1742 if (!dmA) return NULL;
1743
Mike McCormack516a5772005-08-19 10:04:03 +00001744 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1745 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001746
1747 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1748 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1749 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001750 }
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001751 else
1752 {
1753 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1754 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1755 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1756 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1757
1758 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1759 }
1760
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001761 dmA->dmSize = size;
Detlef Riekenberg741fa212008-03-09 00:38:49 +01001762 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001763 return dmA;
1764}
1765
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +01001766/******************************************************************
1767 * convert_printerinfo_W_to_A [internal]
1768 *
1769 */
1770static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1771 DWORD level, DWORD outlen, DWORD numentries)
1772{
1773 DWORD id = 0;
1774 LPSTR ptr;
1775 INT len;
1776
1777 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1778
1779 len = pi_sizeof[level] * numentries;
1780 ptr = (LPSTR) out + len;
1781 outlen -= len;
1782
1783 /* copy the numbers of all PRINTER_INFO_* first */
1784 memcpy(out, pPrintersW, len);
1785
1786 while (id < numentries) {
1787 switch (level) {
1788 case 1:
1789 {
1790 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1791 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1792
1793 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1794 if (piW->pDescription) {
1795 piA->pDescription = ptr;
1796 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1797 ptr, outlen, NULL, NULL);
1798 ptr += len;
1799 outlen -= len;
1800 }
1801 if (piW->pName) {
1802 piA->pName = ptr;
1803 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1804 ptr, outlen, NULL, NULL);
1805 ptr += len;
1806 outlen -= len;
1807 }
1808 if (piW->pComment) {
1809 piA->pComment = ptr;
1810 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1811 ptr, outlen, NULL, NULL);
1812 ptr += len;
1813 outlen -= len;
1814 }
1815 break;
1816 }
1817
1818 case 2:
1819 {
1820 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1821 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1822 LPDEVMODEA dmA;
1823
1824 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1825 if (piW->pServerName) {
1826 piA->pServerName = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1828 ptr, outlen, NULL, NULL);
1829 ptr += len;
1830 outlen -= len;
1831 }
1832 if (piW->pPrinterName) {
1833 piA->pPrinterName = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1835 ptr, outlen, NULL, NULL);
1836 ptr += len;
1837 outlen -= len;
1838 }
1839 if (piW->pShareName) {
1840 piA->pShareName = ptr;
1841 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1842 ptr, outlen, NULL, NULL);
1843 ptr += len;
1844 outlen -= len;
1845 }
1846 if (piW->pPortName) {
1847 piA->pPortName = ptr;
1848 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1849 ptr, outlen, NULL, NULL);
1850 ptr += len;
1851 outlen -= len;
1852 }
1853 if (piW->pDriverName) {
1854 piA->pDriverName = ptr;
1855 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1856 ptr, outlen, NULL, NULL);
1857 ptr += len;
1858 outlen -= len;
1859 }
1860 if (piW->pComment) {
1861 piA->pComment = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1863 ptr, outlen, NULL, NULL);
1864 ptr += len;
1865 outlen -= len;
1866 }
1867 if (piW->pLocation) {
1868 piA->pLocation = ptr;
1869 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1870 ptr, outlen, NULL, NULL);
1871 ptr += len;
1872 outlen -= len;
1873 }
1874
1875 dmA = DEVMODEdupWtoA(piW->pDevMode);
1876 if (dmA) {
1877 /* align DEVMODEA to a DWORD boundary */
1878 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1879 ptr += len;
1880 outlen -= len;
1881
1882 piA->pDevMode = (LPDEVMODEA) ptr;
1883 len = dmA->dmSize + dmA->dmDriverExtra;
1884 memcpy(ptr, dmA, len);
1885 HeapFree(GetProcessHeap(), 0, dmA);
1886
1887 ptr += len;
1888 outlen -= len;
1889 }
1890
1891 if (piW->pSepFile) {
1892 piA->pSepFile = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1894 ptr, outlen, NULL, NULL);
1895 ptr += len;
1896 outlen -= len;
1897 }
1898 if (piW->pPrintProcessor) {
1899 piA->pPrintProcessor = ptr;
1900 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1901 ptr, outlen, NULL, NULL);
1902 ptr += len;
1903 outlen -= len;
1904 }
1905 if (piW->pDatatype) {
1906 piA->pDatatype = ptr;
1907 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1908 ptr, outlen, NULL, NULL);
1909 ptr += len;
1910 outlen -= len;
1911 }
1912 if (piW->pParameters) {
1913 piA->pParameters = ptr;
1914 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1915 ptr, outlen, NULL, NULL);
1916 ptr += len;
1917 outlen -= len;
1918 }
1919 if (piW->pSecurityDescriptor) {
1920 piA->pSecurityDescriptor = NULL;
1921 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1922 }
1923 break;
1924 }
1925
1926 case 4:
1927 {
1928 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1929 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1930
1931 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1932
1933 if (piW->pPrinterName) {
1934 piA->pPrinterName = ptr;
1935 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1936 ptr, outlen, NULL, NULL);
1937 ptr += len;
1938 outlen -= len;
1939 }
1940 if (piW->pServerName) {
1941 piA->pServerName = ptr;
1942 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1943 ptr, outlen, NULL, NULL);
1944 ptr += len;
1945 outlen -= len;
1946 }
1947 break;
1948 }
1949
1950 case 5:
1951 {
1952 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1953 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1954
1955 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1956
1957 if (piW->pPrinterName) {
1958 piA->pPrinterName = ptr;
1959 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1960 ptr, outlen, NULL, NULL);
1961 ptr += len;
1962 outlen -= len;
1963 }
1964 if (piW->pPortName) {
1965 piA->pPortName = ptr;
1966 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1967 ptr, outlen, NULL, NULL);
1968 ptr += len;
1969 outlen -= len;
1970 }
1971 break;
1972 }
1973
1974 default:
1975 FIXME("for level %u\n", level);
1976 }
1977 pPrintersW += pi_sizeof[level];
1978 out += pi_sizeof[level];
1979 id++;
1980 }
1981}
1982
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001983/***********************************************************
1984 * PRINTER_INFO_2AtoW
1985 * Creates a unicode copy of PRINTER_INFO_2A on heap
1986 */
1987static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1988{
1989 LPPRINTER_INFO_2W piW;
Matthew Davison60009b92003-01-23 23:07:38 +00001990 UNICODE_STRING usBuffer;
1991
Huw D M Davies7aaabc32000-05-25 23:02:46 +00001992 if(!piA) return NULL;
1993 piW = HeapAlloc(heap, 0, sizeof(*piW));
1994 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
Matthew Davison60009b92003-01-23 23:07:38 +00001995
Duane Clark0987ae02003-02-12 01:19:25 +00001996 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1997 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1998 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1999 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
2000 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
2001 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
2002 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
Alexandre Julliardc2320db2003-08-12 23:46:34 +00002003 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
Duane Clark0987ae02003-02-12 01:19:25 +00002004 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
2005 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
2006 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
2007 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002008 return piW;
2009}
2010
2011/***********************************************************
2012 * FREE_PRINTER_INFO_2W
2013 * Free PRINTER_INFO_2W and all strings
2014 */
2015static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
2016{
2017 if(!piW) return;
2018
2019 HeapFree(heap,0,piW->pServerName);
2020 HeapFree(heap,0,piW->pPrinterName);
2021 HeapFree(heap,0,piW->pShareName);
2022 HeapFree(heap,0,piW->pPortName);
2023 HeapFree(heap,0,piW->pDriverName);
2024 HeapFree(heap,0,piW->pComment);
2025 HeapFree(heap,0,piW->pLocation);
2026 HeapFree(heap,0,piW->pDevMode);
2027 HeapFree(heap,0,piW->pSepFile);
2028 HeapFree(heap,0,piW->pPrintProcessor);
2029 HeapFree(heap,0,piW->pDatatype);
2030 HeapFree(heap,0,piW->pParameters);
2031 HeapFree(heap,0,piW);
2032 return;
2033}
2034
Huw D M Daviese39b6761999-05-17 16:20:51 +00002035/******************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002036 * DeviceCapabilities [WINSPOOL.@]
2037 * DeviceCapabilitiesA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002038 *
2039 */
Andreas Mohr2caee712000-07-16 15:44:22 +00002040INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
Huw D M Daviese39b6761999-05-17 16:20:51 +00002041 LPSTR pOutput, LPDEVMODEA lpdm)
2042{
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00002043 INT ret;
Alexandre Julliard49556bc2000-11-29 18:38:24 +00002044
2045 if (!GDI_CallDeviceCapabilities16)
2046 {
2047 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2048 (LPCSTR)104 );
2049 if (!GDI_CallDeviceCapabilities16) return -1;
2050 }
Andreas Mohr2caee712000-07-16 15:44:22 +00002051 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002052
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00002053 /* If DC_PAPERSIZE map POINT16s to POINTs */
2054 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2055 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
Alexandre Julliardf6168db2000-12-13 20:03:53 +00002056 POINT *pt = (POINT *)pOutput;
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00002057 INT i;
2058 memcpy(tmp, pOutput, ret * sizeof(POINT16));
Alexandre Julliardf6168db2000-12-13 20:03:53 +00002059 for(i = 0; i < ret; i++, pt++)
2060 {
2061 pt->x = tmp[i].x;
2062 pt->y = tmp[i].y;
2063 }
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00002064 HeapFree( GetProcessHeap(), 0, tmp );
2065 }
2066 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002067}
2068
2069
2070/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002071 * DeviceCapabilitiesW [WINSPOOL.@]
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002072 *
2073 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2074 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00002075 */
2076INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2077 WORD fwCapability, LPWSTR pOutput,
2078 const DEVMODEW *pDevMode)
2079{
Detlef Riekenberg741fa212008-03-09 00:38:49 +01002080 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
Alexandre Julliard27319982006-11-17 15:29:40 +01002081 LPSTR pDeviceA = strdupWtoA(pDevice);
2082 LPSTR pPortA = strdupWtoA(pPort);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002083 INT ret;
2084
2085 if(pOutput && (fwCapability == DC_BINNAMES ||
2086 fwCapability == DC_FILEDEPENDENCIES ||
2087 fwCapability == DC_PAPERNAMES)) {
2088 /* These need A -> W translation */
2089 INT size = 0, i;
2090 LPSTR pOutputA;
2091 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2092 dmA);
2093 if(ret == -1)
2094 return ret;
2095 switch(fwCapability) {
2096 case DC_BINNAMES:
2097 size = 24;
2098 break;
2099 case DC_PAPERNAMES:
2100 case DC_FILEDEPENDENCIES:
2101 size = 64;
2102 break;
2103 }
2104 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2105 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2106 dmA);
2107 for(i = 0; i < ret; i++)
2108 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2109 pOutput + (i * size), size);
2110 HeapFree(GetProcessHeap(), 0, pOutputA);
2111 } else {
2112 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2113 (LPSTR)pOutput, dmA);
2114 }
2115 HeapFree(GetProcessHeap(),0,pPortA);
2116 HeapFree(GetProcessHeap(),0,pDeviceA);
2117 HeapFree(GetProcessHeap(),0,dmA);
2118 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002119}
2120
2121/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002122 * DocumentPropertiesA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002123 *
Dmitry Timoshkov3a910c72003-08-12 20:42:18 +00002124 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
Huw D M Daviese39b6761999-05-17 16:20:51 +00002125 */
2126LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2127 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2128 LPDEVMODEA pDevModeInput,DWORD fMode )
2129{
Huw D M Daviese39b6761999-05-17 16:20:51 +00002130 LPSTR lpName = pDeviceName;
Andrew Talbot8c56ffd2006-08-16 21:00:14 +01002131 static CHAR port[] = "LPT1:";
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002132 LONG ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002133
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002134 TRACE("(%p,%p,%s,%p,%p,%d)\n",
Huw D M Daviese39b6761999-05-17 16:20:51 +00002135 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2136 );
2137
2138 if(!pDeviceName) {
Huw Daviesdf9c4342005-07-05 11:00:09 +00002139 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00002140 if(!lpNameW) {
2141 ERR("no name from hPrinter?\n");
Huw Daviesdf9c4342005-07-05 11:00:09 +00002142 SetLastError(ERROR_INVALID_HANDLE);
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00002143 return -1;
2144 }
Alexandre Julliard27319982006-11-17 15:29:40 +01002145 lpName = strdupWtoA(lpNameW);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002146 }
2147
Alexandre Julliard49556bc2000-11-29 18:38:24 +00002148 if (!GDI_CallExtDeviceMode16)
2149 {
2150 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2151 (LPCSTR)102 );
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00002152 if (!GDI_CallExtDeviceMode16) {
2153 ERR("No CallExtDeviceMode16?\n");
2154 return -1;
2155 }
Alexandre Julliard49556bc2000-11-29 18:38:24 +00002156 }
Andrew Talbot8c56ffd2006-08-16 21:00:14 +01002157 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002158 pDevModeInput, NULL, fMode);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002159
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002160 if(!pDeviceName)
2161 HeapFree(GetProcessHeap(),0,lpName);
2162 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002163}
2164
2165
2166/*****************************************************************************
Patrik Stridvall8b216b32001-06-19 18:20:47 +00002167 * DocumentPropertiesW (WINSPOOL.@)
Dmitry Timoshkov3a910c72003-08-12 20:42:18 +00002168 *
2169 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
Huw D M Daviese39b6761999-05-17 16:20:51 +00002170 */
2171LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002172 LPWSTR pDeviceName,
2173 LPDEVMODEW pDevModeOutput,
2174 LPDEVMODEW pDevModeInput, DWORD fMode)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002175{
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002176
Alexandre Julliard27319982006-11-17 15:29:40 +01002177 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
Detlef Riekenberg741fa212008-03-09 00:38:49 +01002178 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002179 LPDEVMODEA pDevModeOutputA = NULL;
2180 LONG ret;
2181
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002182 TRACE("(%p,%p,%s,%p,%p,%d)\n",
Huw D M Daviese39b6761999-05-17 16:20:51 +00002183 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2184 fMode);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002185 if(pDevModeOutput) {
2186 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2187 if(ret < 0) return ret;
2188 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2189 }
2190 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2191 pDevModeInputA, fMode);
2192 if(pDevModeOutput) {
2193 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2194 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2195 }
2196 if(fMode == 0 && ret > 0)
2197 ret += (CCHDEVICENAME + CCHFORMNAME);
2198 HeapFree(GetProcessHeap(),0,pDevModeInputA);
Vincent Béron9a624912002-05-31 23:06:46 +00002199 HeapFree(GetProcessHeap(),0,pDeviceNameA);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002200 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002201}
2202
Huw D M Daviese39b6761999-05-17 16:20:51 +00002203/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002204 * OpenPrinterA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002205 *
Detlef Riekenbergdd6aa8c2005-12-12 12:10:13 +01002206 * See OpenPrinterW.
2207 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00002208 */
2209BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002210 LPPRINTER_DEFAULTSA pDefault)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002211{
Matthew Davison60009b92003-01-23 23:07:38 +00002212 UNICODE_STRING lpPrinterNameW;
2213 UNICODE_STRING usBuffer;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002214 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
Duane Clark0987ae02003-02-12 01:19:25 +00002215 PWSTR pwstrPrinterNameW;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002216 BOOL ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002217
Duane Clark0987ae02003-02-12 01:19:25 +00002218 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
Matthew Davison60009b92003-01-23 23:07:38 +00002219
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002220 if(pDefault) {
Duane Clark0987ae02003-02-12 01:19:25 +00002221 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
Alexandre Julliardc2320db2003-08-12 23:46:34 +00002222 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002223 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2224 pDefaultW = &DefaultW;
2225 }
Duane Clark0987ae02003-02-12 01:19:25 +00002226 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002227 if(pDefault) {
Matthew Davison60009b92003-01-23 23:07:38 +00002228 RtlFreeUnicodeString(&usBuffer);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002229 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2230 }
Matthew Davison60009b92003-01-23 23:07:38 +00002231 RtlFreeUnicodeString(&lpPrinterNameW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002232 return ret;
2233}
2234
2235/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002236 * OpenPrinterW [WINSPOOL.@]
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002237 *
Detlef Riekenbergdd6aa8c2005-12-12 12:10:13 +01002238 * Open a Printer / Printserver or a Printer-Object
2239 *
2240 * PARAMS
2241 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2242 * phPrinter [O] The resulting Handle is stored here
2243 * pDefault [I] PTR to Default Printer Settings or NULL
2244 *
2245 * RETURNS
2246 * Success: TRUE
2247 * Failure: FALSE
2248 *
2249 * NOTES
2250 * lpPrinterName is one of:
2251 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2252 *| Printer: "PrinterName"
2253 *| Printer-Object: "PrinterName,Job xxx"
2254 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2255 *| XcvPort: "Servername,XcvPort PortName"
2256 *
2257 * BUGS
Detlef Riekenbergdd6aa8c2005-12-12 12:10:13 +01002258 *| Printer-Object not supported
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002259 *| pDefaults is ignored
Detlef Riekenbergdd6aa8c2005-12-12 12:10:13 +01002260 *
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002261 */
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002262BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002263{
Huw D M Daviese39b6761999-05-17 16:20:51 +00002264
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002265 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2266 if (pDefault) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002267 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002268 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
Ulrich Czekalla6a80c8a2000-02-25 21:38:17 +00002269 }
2270
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002271 if(!phPrinter) {
2272 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2273 SetLastError(ERROR_INVALID_PARAMETER);
2274 return FALSE;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002275 }
2276
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002277 /* Get the unique handle of the printer or Printserver */
2278 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
Francois Gouget42c41142007-01-18 11:37:51 +01002279 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
Detlef Riekenberg351106f2006-05-12 16:14:59 +02002280 return (*phPrinter != 0);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002281}
2282
Huw D M Daviese39b6761999-05-17 16:20:51 +00002283/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002284 * AddMonitorA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002285 *
Detlef Riekenberga5219472005-12-06 11:33:52 +01002286 * See AddMonitorW.
2287 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00002288 */
Huw D M Davies685fa2d1999-09-04 14:30:33 +00002289BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002290{
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002291 LPWSTR nameW = NULL;
2292 INT len;
2293 BOOL res;
2294 LPMONITOR_INFO_2A mi2a;
2295 MONITOR_INFO_2W mi2w;
2296
2297 mi2a = (LPMONITOR_INFO_2A) pMonitors;
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002298 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002299 mi2a ? debugstr_a(mi2a->pName) : NULL,
2300 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2301 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2302
2303 if (Level != 2) {
2304 SetLastError(ERROR_INVALID_LEVEL);
2305 return FALSE;
2306 }
2307
2308 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2309 if (mi2a == NULL) {
2310 return FALSE;
2311 }
2312
2313 if (pName) {
2314 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2315 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2317 }
2318
2319 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2320 if (mi2a->pName) {
2321 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2322 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2323 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2324 }
2325 if (mi2a->pEnvironment) {
2326 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2327 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2329 }
2330 if (mi2a->pDLLName) {
2331 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2332 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2333 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2334 }
2335
2336 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2337
2338 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2339 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2340 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2341
2342 HeapFree(GetProcessHeap(), 0, nameW);
2343 return (res);
Hans Leidekker8facd462005-01-03 20:24:39 +00002344}
2345
2346/******************************************************************************
2347 * AddMonitorW [WINSPOOL.@]
Detlef Riekenberga5219472005-12-06 11:33:52 +01002348 *
2349 * Install a Printmonitor
2350 *
2351 * PARAMS
2352 * pName [I] Servername or NULL (local Computer)
2353 * Level [I] Structure-Level (Must be 2)
2354 * pMonitors [I] PTR to MONITOR_INFO_2
2355 *
2356 * RETURNS
2357 * Success: TRUE
2358 * Failure: FALSE
2359 *
2360 * NOTES
2361 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2362 *
Hans Leidekker8facd462005-01-03 20:24:39 +00002363 */
2364BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2365{
Detlef Riekenberg1e177382006-09-02 22:50:32 +02002366 monitor_t * pm = NULL;
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002367 LPMONITOR_INFO_2W mi2w;
2368 HKEY hroot = NULL;
2369 HKEY hentry = NULL;
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002370 DWORD disposition;
2371 BOOL res = FALSE;
2372
2373 mi2w = (LPMONITOR_INFO_2W) pMonitors;
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002374 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002375 mi2w ? debugstr_w(mi2w->pName) : NULL,
2376 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2377 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2378
2379 if (Level != 2) {
2380 SetLastError(ERROR_INVALID_LEVEL);
2381 return FALSE;
2382 }
2383
2384 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2385 if (mi2w == NULL) {
2386 return FALSE;
2387 }
2388
2389 if (pName && (pName[0])) {
2390 FIXME("for server %s not implemented\n", debugstr_w(pName));
2391 SetLastError(ERROR_ACCESS_DENIED);
2392 return FALSE;
2393 }
2394
2395
2396 if (!mi2w->pName || (! mi2w->pName[0])) {
Francois Gougetf7c24f32006-05-12 00:32:31 +02002397 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002398 SetLastError(ERROR_INVALID_PARAMETER);
2399 return FALSE;
2400 }
2401 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2402 WARN("Environment %s requested (we support only %s)\n",
2403 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2404 SetLastError(ERROR_INVALID_ENVIRONMENT);
2405 return FALSE;
2406 }
2407
2408 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
Francois Gougetf7c24f32006-05-12 00:32:31 +02002409 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002410 SetLastError(ERROR_INVALID_PARAMETER);
2411 return FALSE;
2412 }
2413
Detlef Riekenberg1e177382006-09-02 22:50:32 +02002414 /* Load and initialize the monitor. SetLastError() is called on failure */
2415 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002416 return FALSE;
2417 }
Detlef Riekenberg1e177382006-09-02 22:50:32 +02002418 monitor_unload(pm);
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002419
2420 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2421 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2422 return FALSE;
2423 }
2424
Detlef Riekenberg698a8a02006-06-16 10:01:31 +02002425 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2426 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2427 &disposition) == ERROR_SUCCESS) {
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002428
Detlef Riekenberg698a8a02006-06-16 10:01:31 +02002429 /* Some installers set options for the port before calling AddMonitor.
2430 We query the "Driver" entry to verify that the monitor is installed,
2431 before we return an error.
2432 When a user installs two print monitors at the same time with the
2433 same name but with a different driver DLL and a task switch comes
2434 between RegQueryValueExW and RegSetValueExW, a race condition
2435 is possible but silently ignored. */
2436
2437 DWORD namesize = 0;
2438
2439 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2440 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2441 &namesize) == ERROR_SUCCESS)) {
Detlef Riekenberged1161f2006-04-11 20:42:18 +02002442 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2443 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2444 9x: ERROR_ALREADY_EXISTS (183) */
2445 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2446 }
2447 else
2448 {
2449 INT len;
2450 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2451 res = (RegSetValueExW(hentry, DriverW, 0,
2452 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2453 }
2454 RegCloseKey(hentry);
2455 }
2456
2457 RegCloseKey(hroot);
2458 return (res);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002459}
2460
2461/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002462 * DeletePrinterDriverA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002463 *
2464 */
Huw Daviesd4fb1c32006-11-07 11:57:39 +00002465BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002466{
Huw Daviesd4fb1c32006-11-07 11:57:39 +00002467 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002468}
2469
Hans Leidekker8facd462005-01-03 20:24:39 +00002470/******************************************************************
2471 * DeletePrinterDriverW [WINSPOOL.@]
2472 *
2473 */
Huw Daviesd4fb1c32006-11-07 11:57:39 +00002474BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
Hans Leidekker8facd462005-01-03 20:24:39 +00002475{
Huw Daviesd4fb1c32006-11-07 11:57:39 +00002476 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
Hans Leidekker8facd462005-01-03 20:24:39 +00002477}
Huw D M Daviese39b6761999-05-17 16:20:51 +00002478
2479/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002480 * DeleteMonitorA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002481 *
Detlef Riekenberga5219472005-12-06 11:33:52 +01002482 * See DeleteMonitorW.
2483 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00002484 */
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002485BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002486{
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002487 LPWSTR nameW = NULL;
2488 LPWSTR EnvironmentW = NULL;
2489 LPWSTR MonitorNameW = NULL;
2490 BOOL res;
2491 INT len;
2492
2493 if (pName) {
2494 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2495 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2496 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2497 }
2498
2499 if (pEnvironment) {
2500 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2501 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2502 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2503 }
2504 if (pMonitorName) {
2505 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2506 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2507 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2508 }
2509
2510 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2511
2512 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2513 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2514 HeapFree(GetProcessHeap(), 0, nameW);
2515 return (res);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002516}
2517
Hans Leidekker8facd462005-01-03 20:24:39 +00002518/******************************************************************
2519 * DeleteMonitorW [WINSPOOL.@]
2520 *
Detlef Riekenberga5219472005-12-06 11:33:52 +01002521 * Delete a specific Printmonitor from a Printing-Environment
2522 *
2523 * PARAMS
2524 * pName [I] Servername or NULL (local Computer)
2525 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2526 * pMonitorName [I] Name of the Monitor, that should be deleted
2527 *
2528 * RETURNS
2529 * Success: TRUE
2530 * Failure: FALSE
2531 *
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002532 * NOTES
2533 * pEnvironment is ignored in Windows for the local Computer.
Detlef Riekenberga5219472005-12-06 11:33:52 +01002534 *
Hans Leidekker8facd462005-01-03 20:24:39 +00002535 */
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002536
2537BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
Hans Leidekker8facd462005-01-03 20:24:39 +00002538{
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002539 HKEY hroot = NULL;
2540
2541 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2542 debugstr_w(pMonitorName));
2543
2544 if (pName && (pName[0])) {
2545 FIXME("for server %s not implemented\n", debugstr_w(pName));
2546 SetLastError(ERROR_ACCESS_DENIED);
2547 return FALSE;
2548 }
2549
2550 /* pEnvironment is ignored in Windows for the local Computer */
2551
2552 if (!pMonitorName || !pMonitorName[0]) {
2553 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2554 SetLastError(ERROR_INVALID_PARAMETER);
2555 return FALSE;
2556 }
2557
2558 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2559 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2560 return FALSE;
2561 }
2562
Stefan Leichter06b64a12007-06-05 18:47:17 +02002563 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002564 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2565 RegCloseKey(hroot);
2566 return TRUE;
2567 }
2568
Francois Gougetb0bde6b2007-01-18 11:35:50 +01002569 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
Detlef Riekenberg3b383082006-04-16 02:56:27 +02002570 RegCloseKey(hroot);
2571
2572 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2573 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2574 return (FALSE);
Hans Leidekker8facd462005-01-03 20:24:39 +00002575}
Huw D M Daviese39b6761999-05-17 16:20:51 +00002576
2577/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002578 * DeletePortA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002579 *
Detlef Riekenberg1395d142005-12-06 10:57:01 +01002580 * See DeletePortW.
2581 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00002582 */
Detlef Riekenbergbcfa90e2006-11-28 00:47:08 +01002583BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002584{
Detlef Riekenbergbcfa90e2006-11-28 00:47:08 +01002585 LPWSTR nameW = NULL;
2586 LPWSTR portW = NULL;
2587 INT len;
2588 DWORD res;
2589
2590 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2591
2592 /* convert servername to unicode */
2593 if (pName) {
2594 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2595 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2596 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2597 }
2598
2599 /* convert portname to unicode */
2600 if (pPortName) {
2601 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2602 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2604 }
2605
2606 res = DeletePortW(nameW, hWnd, portW);
2607 HeapFree(GetProcessHeap(), 0, nameW);
2608 HeapFree(GetProcessHeap(), 0, portW);
2609 return res;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002610}
2611
Hans Leidekker8facd462005-01-03 20:24:39 +00002612/******************************************************************
2613 * DeletePortW [WINSPOOL.@]
2614 *
Detlef Riekenberg1395d142005-12-06 10:57:01 +01002615 * Delete a specific Port
2616 *
2617 * PARAMS
2618 * pName [I] Servername or NULL (local Computer)
2619 * hWnd [I] Handle to parent Window for the Dialog-Box
2620 * pPortName [I] Name of the Port, that should be deleted
2621 *
2622 * RETURNS
2623 * Success: TRUE
2624 * Failure: FALSE
2625 *
Hans Leidekker8facd462005-01-03 20:24:39 +00002626 */
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002627BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
Hans Leidekker8facd462005-01-03 20:24:39 +00002628{
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002629 monitor_t * pm;
Detlef Riekenberg917b0ee2007-01-15 05:37:20 +01002630 monitor_t * pui;
2631 DWORD res;
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002632
2633 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2634
2635 if (pName && pName[0]) {
2636 SetLastError(ERROR_INVALID_PARAMETER);
2637 return FALSE;
2638 }
2639
2640 if (!pPortName) {
2641 SetLastError(RPC_X_NULL_REF_POINTER);
2642 return FALSE;
2643 }
2644
2645 /* an empty Portname is Invalid */
Detlef Riekenberg917b0ee2007-01-15 05:37:20 +01002646 if (!pPortName[0]) {
2647 SetLastError(ERROR_NOT_SUPPORTED);
2648 return FALSE;
2649 }
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002650
2651 pm = monitor_load_by_port(pPortName);
Detlef Riekenberg917b0ee2007-01-15 05:37:20 +01002652 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2653 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2654 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2655 TRACE("got %d with %u\n", res, GetLastError());
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002656 }
Detlef Riekenberg917b0ee2007-01-15 05:37:20 +01002657 else
2658 {
2659 pui = monitor_loadui(pm);
2660 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2661 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2662 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2663 TRACE("got %d with %u\n", res, GetLastError());
2664 }
2665 else
2666 {
2667 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2668 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2669
2670 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2671 SetLastError(ERROR_NOT_SUPPORTED);
2672 res = FALSE;
2673 }
2674 monitor_unload(pui);
2675 }
Detlef Riekenbergc587d1a2006-11-28 00:46:28 +01002676 monitor_unload(pm);
2677
Detlef Riekenberg917b0ee2007-01-15 05:37:20 +01002678 TRACE("returning %d with %u\n", res, GetLastError());
2679 return res;
Hans Leidekker8facd462005-01-03 20:24:39 +00002680}
2681
Huw D M Daviese39b6761999-05-17 16:20:51 +00002682/******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002683 * SetPrinterW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002684 */
Detlef Riekenbergb7a62e52006-05-12 14:53:17 +02002685BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2686{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002687 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00002688 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2689 return FALSE;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002690}
2691
2692/******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002693 * WritePrinter [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002694 */
Huw Davies6fd3c472005-07-08 14:19:18 +00002695BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2696{
2697 opened_printer_t *printer;
2698 BOOL ret = FALSE;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002699
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002700 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
Huw Davies6fd3c472005-07-08 14:19:18 +00002701
2702 EnterCriticalSection(&printer_handles_cs);
2703 printer = get_opened_printer(hPrinter);
2704 if(!printer)
2705 {
2706 SetLastError(ERROR_INVALID_HANDLE);
2707 goto end;
2708 }
2709
2710 if(!printer->doc)
2711 {
2712 SetLastError(ERROR_SPL_NO_STARTDOC);
2713 goto end;
2714 }
2715
2716 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2717end:
2718 LeaveCriticalSection(&printer_handles_cs);
2719 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002720}
2721
2722/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002723 * AddFormA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002724 */
2725BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2726{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002727 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002728 return 1;
2729}
2730
2731/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002732 * AddFormW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002733 */
2734BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2735{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002736 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
Huw D M Daviese39b6761999-05-17 16:20:51 +00002737 return 1;
2738}
2739
2740/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002741 * AddJobA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002742 */
Huw Davies344090f2005-07-06 15:44:15 +00002743BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002744{
Huw Davies344090f2005-07-06 15:44:15 +00002745 BOOL ret;
2746 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2747 DWORD needed;
2748
2749 if(Level != 1) {
2750 SetLastError(ERROR_INVALID_LEVEL);
2751 return FALSE;
2752 }
2753
2754 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2755
2756 if(ret) {
2757 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2758 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2759 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2760 if(*pcbNeeded > cbBuf) {
2761 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2762 ret = FALSE;
2763 } else {
2764 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2765 addjobA->JobId = addjobW->JobId;
2766 addjobA->Path = (char *)(addjobA + 1);
2767 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2768 }
2769 }
2770 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002771}
2772
2773/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00002774 * AddJobW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00002775 */
Huw Davies344090f2005-07-06 15:44:15 +00002776BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
Huw D M Daviese39b6761999-05-17 16:20:51 +00002777{
Huw Davies344090f2005-07-06 15:44:15 +00002778 opened_printer_t *printer;
2779 job_t *job;
2780 BOOL ret = FALSE;
2781 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2782 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2783 WCHAR path[MAX_PATH], filename[MAX_PATH];
2784 DWORD len;
2785 ADDJOB_INFO_1W *addjob;
2786
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002787 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
Huw Davies344090f2005-07-06 15:44:15 +00002788
2789 EnterCriticalSection(&printer_handles_cs);
2790
2791 printer = get_opened_printer(hPrinter);
2792
2793 if(!printer) {
2794 SetLastError(ERROR_INVALID_HANDLE);
2795 goto end;
2796 }
2797
2798 if(Level != 1) {
2799 SetLastError(ERROR_INVALID_LEVEL);
2800 goto end;
2801 }
2802
2803 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2804 if(!job)
2805 goto end;
2806
2807 job->job_id = InterlockedIncrement(&next_job_id);
2808
2809 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2810 if(path[len - 1] != '\\')
2811 path[len++] = '\\';
2812 memcpy(path + len, spool_path, sizeof(spool_path));
2813 sprintfW(filename, fmtW, path, job->job_id);
2814
2815 len = strlenW(filename);
2816 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2817 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
Huw Davies183fcb52005-07-15 09:55:23 +00002818 job->document_title = strdupW(default_doc_title);
Huw Davies48a52d02005-07-19 19:12:13 +00002819 list_add_tail(&printer->queue->jobs, &job->entry);
Huw Davies344090f2005-07-06 15:44:15 +00002820
2821 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2822 if(*pcbNeeded <= cbBuf) {
2823 addjob = (ADDJOB_INFO_1W*)pData;
2824 addjob->JobId = job->job_id;
2825 addjob->Path = (WCHAR *)(addjob + 1);
2826 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2827 ret = TRUE;
2828 } else
2829 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2830
2831end:
2832 LeaveCriticalSection(&printer_handles_cs);
2833 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00002834}
2835
2836/*****************************************************************************
Uwe Bonnes1d603872003-04-27 20:35:08 +00002837 * GetPrintProcessorDirectoryA [WINSPOOL.@]
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002838 *
2839 * Return the PATH for the Print-Processors
2840 *
2841 * See GetPrintProcessorDirectoryW.
2842 *
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002843 *
Uwe Bonnes1d603872003-04-27 20:35:08 +00002844 */
Alexandre Julliard402b79a2003-11-27 00:59:36 +00002845BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
Uwe Bonnes1d603872003-04-27 20:35:08 +00002846 DWORD level, LPBYTE Info,
Detlef Riekenberg94543cb2006-06-09 13:06:41 +02002847 DWORD cbBuf, LPDWORD pcbNeeded)
Uwe Bonnes1d603872003-04-27 20:35:08 +00002848{
Detlef Riekenberg94543cb2006-06-09 13:06:41 +02002849 LPWSTR serverW = NULL;
2850 LPWSTR envW = NULL;
2851 BOOL ret;
2852 INT len;
2853
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
Detlef Riekenberg94543cb2006-06-09 13:06:41 +02002855 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2856
2857
2858 if (server) {
2859 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2860 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2861 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2862 }
2863
2864 if (env) {
2865 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2866 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2867 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2868 }
2869
2870 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2871 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2872 */
2873 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2874 cbBuf, pcbNeeded);
2875
2876 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2877 cbBuf, NULL, NULL) > 0;
2878
2879
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002880 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
Detlef Riekenberg94543cb2006-06-09 13:06:41 +02002881 HeapFree(GetProcessHeap(), 0, envW);
2882 HeapFree(GetProcessHeap(), 0, serverW);
2883 return ret;
Hans Leidekker8facd462005-01-03 20:24:39 +00002884}
2885
2886/*****************************************************************************
2887 * GetPrintProcessorDirectoryW [WINSPOOL.@]
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002888 *
2889 * Return the PATH for the Print-Processors
2890 *
2891 * PARAMS
2892 * server [I] Servername (NT only) or NULL (local Computer)
2893 * env [I] Printing-Environment (see below) or NULL (Default)
2894 * level [I] Structure-Level (must be 1)
2895 * Info [O] PTR to Buffer that receives the Result
2896 * cbBuf [I] Size of Buffer at "Info"
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002897 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002898 * required for the Buffer at "Info"
2899 *
2900 * RETURNS
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002901 * Success: TRUE and in pcbNeeded the Bytes used in Info
2902 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002903 * if cbBuf is too small
2904 *
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002905 * Native Values returned in Info on Success:
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002906 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2907 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2908 *| win9x(Windows 4.0): "%winsysdir%"
2909 *
2910 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2911 *
2912 * BUGS
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002913 * Only NULL or "" is supported for server
Detlef Riekenbergaff1b332006-05-27 00:30:58 +02002914 *
Hans Leidekker8facd462005-01-03 20:24:39 +00002915 */
2916BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2917 DWORD level, LPBYTE Info,
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002918 DWORD cbBuf, LPDWORD pcbNeeded)
Hans Leidekker8facd462005-01-03 20:24:39 +00002919{
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002920 DWORD needed;
2921 const printenv_t * env_t;
2922
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002923 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002924 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2925
2926 if(server != NULL && server[0]) {
2927 FIXME("server not supported: %s\n", debugstr_w(server));
2928 SetLastError(ERROR_INVALID_PARAMETER);
2929 return FALSE;
2930 }
2931
2932 env_t = validate_envW(env);
2933 if(!env_t) return FALSE; /* environment invalid or unsupported */
2934
2935 if(level != 1) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002936 WARN("(Level: %d) is ignored in win9x\n", level);
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002937 SetLastError(ERROR_INVALID_LEVEL);
2938 return FALSE;
2939 }
2940
2941 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2942 needed = GetSystemDirectoryW(NULL, 0);
2943 /* add the Size for the Subdirectories */
2944 needed += lstrlenW(spoolprtprocsW);
2945 needed += lstrlenW(env_t->subdir);
2946 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2947
2948 if(pcbNeeded) *pcbNeeded = needed;
Hans Leidekker61faa6b2006-10-13 11:51:23 +02002949 TRACE ("required: 0x%x/%d\n", needed, needed);
Detlef Riekenbergf0a62dd2006-05-28 21:56:52 +02002950 if (needed > cbBuf) {
2951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2952 return FALSE;
2953 }
2954 if(pcbNeeded == NULL) {
2955 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2956 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2957 SetLastError(RPC_X_NULL_REF_POINTER);
2958 return FALSE;
2959 }
2960 if(Info == NULL) {
2961 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2962 SetLastError(RPC_X_NULL_REF_POINTER);
2963 return FALSE;
2964 }
2965
2966 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2967 /* add the Subdirectories */
2968 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2969 lstrcatW((LPWSTR) Info, env_t->subdir);
2970 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2971 return TRUE;
Uwe Bonnes1d603872003-04-27 20:35:08 +00002972}
2973
2974/*****************************************************************************
Stefan Leichterca1661c2000-11-06 05:26:00 +00002975 * WINSPOOL_OpenDriverReg [internal]
2976 *
2977 * opens the registry for the printer drivers depending on the given input
2978 * variable pEnvironment
2979 *
2980 * RETURNS:
2981 * the opened hkey on success
Vincent Béron9a624912002-05-31 23:06:46 +00002982 * NULL on error
Stefan Leichterca1661c2000-11-06 05:26:00 +00002983 */
Vitaly Lipatovc9d78fc2007-02-18 13:51:09 +03002984static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
Dimitrie O. Paund4193bb2005-03-29 13:10:35 +00002985{
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +02002986 HKEY retval = NULL;
2987 LPWSTR buffer;
2988 const printenv_t * env;
Stefan Leichterca1661c2000-11-06 05:26:00 +00002989
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +02002990 TRACE("(%s, %d)\n",
2991 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
Stefan Leichterca1661c2000-11-06 05:26:00 +00002992
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +02002993 if (!pEnvironment || unicode) {
2994 /* pEnvironment was NULL or an Unicode-String: use it direct */
2995 env = validate_envW(pEnvironment);
Stefan Leichterca1661c2000-11-06 05:26:00 +00002996 }
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +02002997 else
2998 {
2999 /* pEnvironment was an ANSI-String: convert to unicode first */
3000 LPWSTR buffer;
3001 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
3002 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3003 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
3004 env = validate_envW(buffer);
3005 HeapFree(GetProcessHeap(), 0, buffer);
3006 }
3007 if (!env) return NULL;
Stefan Leichterca1661c2000-11-06 05:26:00 +00003008
Detlef Riekenberg6c233ef2006-05-11 23:59:17 +02003009 buffer = HeapAlloc( GetProcessHeap(), 0,
3010 (strlenW(DriversW) + strlenW(env->envname) +
3011 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3012 if(buffer) {
3013 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3014 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3015 HeapFree(GetProcessHeap(), 0, buffer);
3016 }
Stefan Leichterca1661c2000-11-06 05:26:00 +00003017 return retval;
3018}
3019
3020/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003021 * AddPrinterW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003022 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003023HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
Huw D M Daviese39b6761999-05-17 16:20:51 +00003024{
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003025 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3026 LPDEVMODEA dmA;
3027 LPDEVMODEW dmW;
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003028 HANDLE retval;
3029 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003030 LONG size;
Andrew Talbot54d578b2007-02-27 23:06:30 +00003031 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
3032 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
3033 priorityW[] = {'P','r','i','o','r','i','t','y',0},
3034 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
3035 statusW[] = {'S','t','a','t','u','s',0},
3036 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003037
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003038 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
Vincent Béron9a624912002-05-31 23:06:46 +00003039
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003040 if(pName != NULL) {
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00003041 ERR("pName = %s - unsupported\n", debugstr_w(pName));
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003042 SetLastError(ERROR_INVALID_PARAMETER);
3043 return 0;
3044 }
3045 if(Level != 2) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003046 ERR("Level = %d, unsupported!\n", Level);
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003047 SetLastError(ERROR_INVALID_LEVEL);
3048 return 0;
3049 }
3050 if(!pPrinter) {
3051 SetLastError(ERROR_INVALID_PARAMETER);
3052 return 0;
3053 }
Detlef Riekenberg358ce062006-05-21 14:35:29 +02003054 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003055 ERROR_SUCCESS) {
3056 ERR("Can't create Printers key\n");
3057 return 0;
3058 }
Marcus Meissner0c630122001-05-09 17:10:41 +00003059 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
Andrew Talbot54d578b2007-02-27 23:06:30 +00003060 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
Marcus Meissner0c630122001-05-09 17:10:41 +00003061 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3062 RegCloseKey(hkeyPrinter);
3063 RegCloseKey(hkeyPrinters);
3064 return 0;
3065 }
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003066 RegCloseKey(hkeyPrinter);
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003067 }
Stefan Leichterca1661c2000-11-06 05:26:00 +00003068 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
3069 if(!hkeyDrivers) {
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003070 ERR("Can't create Drivers key\n");
3071 RegCloseKey(hkeyPrinters);
3072 return 0;
3073 }
Vincent Béron9a624912002-05-31 23:06:46 +00003074 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003075 ERROR_SUCCESS) {
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003076 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003077 RegCloseKey(hkeyPrinters);
3078 RegCloseKey(hkeyDrivers);
3079 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3080 return 0;
3081 }
3082 RegCloseKey(hkeyDriver);
3083 RegCloseKey(hkeyDrivers);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003084
3085 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00003086 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003087 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3088 RegCloseKey(hkeyPrinters);
3089 return 0;
3090 }
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003091
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003092 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003093 ERROR_SUCCESS) {
Marcus Meissnerab8b7db2001-04-27 18:02:46 +00003094 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003095 SetLastError(ERROR_INVALID_PRINTER_NAME);
3096 RegCloseKey(hkeyPrinters);
3097 return 0;
3098 }
Andrew Talbot54d578b2007-02-27 23:06:30 +00003099 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003100 (LPBYTE)&pi->Attributes, sizeof(DWORD));
Gerard Patel14c94292001-10-28 21:16:38 +00003101 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
Marcus Meissner0c630122001-05-09 17:10:41 +00003102
3103 /* See if we can load the driver. We may need the devmode structure anyway
3104 *
3105 * FIXME:
3106 * Note that DocumentPropertiesW will briefly try to open the printer we
3107 * just create to find a DEVMODEA struct (it will use the WINEPS default
3108 * one in case it is not there, so we are ok).
3109 */
Alexandre Julliard613ead72002-10-04 00:27:10 +00003110 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
Huw Davies6694ce92003-06-23 19:52:55 +00003111
Marcus Meissner0c630122001-05-09 17:10:41 +00003112 if(size < 0) {
Francois Gouget42c41142007-01-18 11:37:51 +01003113 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
Marcus Meissner0c630122001-05-09 17:10:41 +00003114 size = sizeof(DEVMODEW);
3115 }
3116 if(pi->pDevMode)
3117 dmW = pi->pDevMode;
Michael Stefaniuc5f62da12007-04-25 00:57:55 +02003118 else
Huw Davies6694ce92003-06-23 19:52:55 +00003119 {
Michael Stefaniuc5f62da12007-04-25 00:57:55 +02003120 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
Huw Davies7afe18e2006-06-15 11:36:00 +01003121 dmW->dmSize = size;
3122 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
Huw Davies6694ce92003-06-23 19:52:55 +00003123 {
Francois Gouget42c41142007-01-18 11:37:51 +01003124 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
Huw Davies6694ce92003-06-23 19:52:55 +00003125 HeapFree(GetProcessHeap(),0,dmW);
3126 dmW=NULL;
Huw Davies7afe18e2006-06-15 11:36:00 +01003127 }
Huw Davies6694ce92003-06-23 19:52:55 +00003128 else
3129 {
Huw Davies7afe18e2006-06-15 11:36:00 +01003130 /* set devmode to printer name */
3131 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
Huw Davies6694ce92003-06-23 19:52:55 +00003132 }
Marcus Meissner0c630122001-05-09 17:10:41 +00003133 }
3134
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003135 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3136 and we support these drivers. NT writes DEVMODEW so somehow
3137 we'll need to distinguish between these when we support NT
3138 drivers */
Huw Davies6694ce92003-06-23 19:52:55 +00003139 if (dmW)
3140 {
Detlef Riekenberg741fa212008-03-09 00:38:49 +01003141 dmA = DEVMODEdupWtoA(dmW);
Andrew Talbot54d578b2007-02-27 23:06:30 +00003142 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
Huw Davies6694ce92003-06-23 19:52:55 +00003143 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3144 HeapFree(GetProcessHeap(), 0, dmA);
3145 if(!pi->pDevMode)
3146 HeapFree(GetProcessHeap(), 0, dmW);
3147 }
Gerard Patel14c94292001-10-28 21:16:38 +00003148 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3149 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3150 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3151 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3152
3153 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3154 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3155 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
Andrew Talbot54d578b2007-02-27 23:06:30 +00003156 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3157 (LPBYTE)&pi->Priority, sizeof(DWORD));
Gerard Patel14c94292001-10-28 21:16:38 +00003158 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3159 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
Andrew Talbot54d578b2007-02-27 23:06:30 +00003160 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3161 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3162 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3163 (LPBYTE)&pi->Status, sizeof(DWORD));
3164 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3165 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003166
3167 RegCloseKey(hkeyPrinter);
3168 RegCloseKey(hkeyPrinters);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003169 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00003170 ERR("OpenPrinter failing\n");
3171 return 0;
3172 }
3173 return retval;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003174}
3175
3176/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003177 * AddPrinterA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003178 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003179HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
Huw D M Daviese39b6761999-05-17 16:20:51 +00003180{
Matthew Davison60009b92003-01-23 23:07:38 +00003181 UNICODE_STRING pNameW;
Duane Clark0987ae02003-02-12 01:19:25 +00003182 PWSTR pwstrNameW;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003183 PRINTER_INFO_2W *piW;
3184 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3185 HANDLE ret;
3186
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003187 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003188 if(Level != 2) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003189 ERR("Level = %d, unsupported!\n", Level);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003190 SetLastError(ERROR_INVALID_LEVEL);
3191 return 0;
3192 }
Duane Clark0987ae02003-02-12 01:19:25 +00003193 pwstrNameW = asciitounicode(&pNameW,pName);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003194 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3195
Duane Clark0987ae02003-02-12 01:19:25 +00003196 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003197
3198 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
Matthew Davison60009b92003-01-23 23:07:38 +00003199 RtlFreeUnicodeString(&pNameW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003200 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003201}
3202
3203
3204/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003205 * ClosePrinter [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003206 */
3207BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3208{
Kevin Koltzau7d8e3772005-09-29 13:34:34 +00003209 UINT_PTR i = (UINT_PTR)hPrinter;
Huw Daviesdf9c4342005-07-05 11:00:09 +00003210 opened_printer_t *printer = NULL;
Huw Davies344090f2005-07-06 15:44:15 +00003211 BOOL ret = FALSE;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003212
Detlef Riekenberg619621d2007-01-15 05:38:22 +01003213 TRACE("(%p)\n", hPrinter);
Thuy Nguyen6374cd21999-08-15 16:34:22 +00003214
Huw Daviesdf9c4342005-07-05 11:00:09 +00003215 EnterCriticalSection(&printer_handles_cs);
3216
3217 if ((i > 0) && (i <= nb_printer_handles))
Huw Daviesdf9c4342005-07-05 11:00:09 +00003218 printer = printer_handles[i - 1];
Huw Daviesdf9c4342005-07-05 11:00:09 +00003219
Detlef Riekenberg619621d2007-01-15 05:38:22 +01003220
Huw Daviesdf9c4342005-07-05 11:00:09 +00003221 if(printer)
3222 {
Huw Davies344090f2005-07-06 15:44:15 +00003223 struct list *cursor, *cursor2;
Huw Davies6fd3c472005-07-08 14:19:18 +00003224
Detlef Riekenberg619621d2007-01-15 05:38:22 +01003225 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3226 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3227 printer->hXcv, debugstr_w(printer->name), printer->doc );
3228
Huw Davies6fd3c472005-07-08 14:19:18 +00003229 if(printer->doc)
3230 EndDocPrinter(hPrinter);
3231
Huw Davies48a52d02005-07-19 19:12:13 +00003232 if(InterlockedDecrement(&printer->queue->ref) == 0)
Huw Davies344090f2005-07-06 15:44:15 +00003233 {
Huw Davies48a52d02005-07-19 19:12:13 +00003234 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3235 {
3236 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3237 ScheduleJob(hPrinter, job->job_id);
3238 }
3239 HeapFree(GetProcessHeap(), 0, printer->queue);
Huw Davies344090f2005-07-06 15:44:15 +00003240 }
Detlef Riekenberg72b126b2007-01-05 01:09:46 +01003241 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
Detlef Riekenbergf85b02b2007-01-05 01:09:13 +01003242 monitor_unload(printer->pm);
Detlef Riekenberg58d1e2f2007-01-05 01:09:02 +01003243 HeapFree(GetProcessHeap(), 0, printer->printername);
Huw Daviesdf9c4342005-07-05 11:00:09 +00003244 HeapFree(GetProcessHeap(), 0, printer->name);
3245 HeapFree(GetProcessHeap(), 0, printer);
Huw Davies344090f2005-07-06 15:44:15 +00003246 printer_handles[i - 1] = NULL;
3247 ret = TRUE;
Huw Daviesdf9c4342005-07-05 11:00:09 +00003248 }
Huw Davies344090f2005-07-06 15:44:15 +00003249 LeaveCriticalSection(&printer_handles_cs);
3250 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003251}
3252
3253/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003254 * DeleteFormA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003255 */
3256BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3257{
Michael Stefaniucea335dd2002-10-22 00:47:33 +00003258 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003259 return 1;
3260}
3261
3262/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003263 * DeleteFormW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003264 */
3265BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3266{
Michael Stefaniucea335dd2002-10-22 00:47:33 +00003267 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
Huw D M Daviese39b6761999-05-17 16:20:51 +00003268 return 1;
3269}
3270
3271/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003272 * DeletePrinter [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003273 */
3274BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3275{
Huw Daviesdf9c4342005-07-05 11:00:09 +00003276 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
Huw Davies3d0b22b2005-03-31 10:06:46 +00003277 HKEY hkeyPrinters, hkey;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003278
Huw Daviesdf9c4342005-07-05 11:00:09 +00003279 if(!lpNameW) {
3280 SetLastError(ERROR_INVALID_HANDLE);
3281 return FALSE;
3282 }
Detlef Riekenberg358ce062006-05-21 14:35:29 +02003283 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
Stefan Leichter06b64a12007-06-05 18:47:17 +02003284 RegDeleteTreeW(hkeyPrinters, lpNameW);
Huw Davies4b0fc2e2003-11-05 00:36:47 +00003285 RegCloseKey(hkeyPrinters);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003286 }
Huw Davies4b0fc2e2003-11-05 00:36:47 +00003287 WriteProfileStringW(devicesW, lpNameW, NULL);
Detlef Riekenberg473717f2008-05-06 20:26:05 +02003288 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3289
Huw Davies3d0b22b2005-03-31 10:06:46 +00003290 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3291 RegDeleteValueW(hkey, lpNameW);
3292 RegCloseKey(hkey);
3293 }
Detlef Riekenberg473717f2008-05-06 20:26:05 +02003294
3295 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3296 RegDeleteValueW(hkey, lpNameW);
3297 RegCloseKey(hkey);
3298 }
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003299 return TRUE;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003300}
3301
3302/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003303 * SetPrinterA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003304 */
3305BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3306 DWORD Command)
3307{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003308 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003309 return FALSE;
3310}
3311
3312/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003313 * SetJobA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003314 */
3315BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
Huw Davies1ed9bac2005-07-13 14:14:37 +00003316 LPBYTE pJob, DWORD Command)
Huw D M Daviese39b6761999-05-17 16:20:51 +00003317{
Huw Daviesf675a782005-07-12 19:19:09 +00003318 BOOL ret;
3319 LPBYTE JobW;
3320 UNICODE_STRING usBuffer;
3321
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003322 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
Huw Daviesf675a782005-07-12 19:19:09 +00003323
3324 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3325 are all ignored by SetJob, so we don't bother copying them */
3326 switch(Level)
3327 {
3328 case 0:
3329 JobW = NULL;
3330 break;
3331 case 1:
3332 {
3333 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3334 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3335
3336 JobW = (LPBYTE)info1W;
3337 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3338 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3339 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3340 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3341 info1W->Status = info1A->Status;
3342 info1W->Priority = info1A->Priority;
3343 info1W->Position = info1A->Position;
3344 info1W->PagesPrinted = info1A->PagesPrinted;
3345 break;
3346 }
3347 case 2:
3348 {
3349 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3350 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3351
3352 JobW = (LPBYTE)info2W;
3353 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3354 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3355 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3356 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3357 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3358 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3359 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3360 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3361 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3362 info2W->Status = info2A->Status;
3363 info2W->Priority = info2A->Priority;
3364 info2W->Position = info2A->Position;
3365 info2W->StartTime = info2A->StartTime;
3366 info2W->UntilTime = info2A->UntilTime;
3367 info2W->PagesPrinted = info2A->PagesPrinted;
3368 break;
3369 }
3370 case 3:
3371 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3372 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3373 break;
3374 default:
3375 SetLastError(ERROR_INVALID_LEVEL);
3376 return FALSE;
3377 }
3378
3379 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3380
3381 switch(Level)
3382 {
3383 case 1:
3384 {
3385 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3386 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3387 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3388 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3389 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3390 break;
3391 }
3392 case 2:
3393 {
3394 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3395 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3396 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3397 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3398 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3399 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3400 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3401 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3402 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3403 break;
3404 }
3405 }
3406 HeapFree(GetProcessHeap(), 0, JobW);
3407
3408 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003409}
3410
3411/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003412 * SetJobW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003413 */
3414BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
Huw Davies1ed9bac2005-07-13 14:14:37 +00003415 LPBYTE pJob, DWORD Command)
Huw D M Daviese39b6761999-05-17 16:20:51 +00003416{
Huw Davies1ed9bac2005-07-13 14:14:37 +00003417 BOOL ret = FALSE;
3418 job_t *job;
3419
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003420 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
Huw Davies1ed9bac2005-07-13 14:14:37 +00003421 FIXME("Ignoring everything other than document title\n");
3422
3423 EnterCriticalSection(&printer_handles_cs);
3424 job = get_job(hPrinter, JobId);
3425 if(!job)
3426 goto end;
3427
3428 switch(Level)
3429 {
3430 case 0:
3431 break;
3432 case 1:
3433 {
3434 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3435 HeapFree(GetProcessHeap(), 0, job->document_title);
3436 job->document_title = strdupW(info1->pDocument);
3437 break;
3438 }
3439 case 2:
3440 {
3441 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3442 HeapFree(GetProcessHeap(), 0, job->document_title);
3443 job->document_title = strdupW(info2->pDocument);
3444 break;
3445 }
3446 case 3:
3447 break;
3448 default:
3449 SetLastError(ERROR_INVALID_LEVEL);
3450 goto end;
3451 }
3452 ret = TRUE;
3453end:
3454 LeaveCriticalSection(&printer_handles_cs);
3455 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00003456}
3457
3458/*****************************************************************************
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003459 * EndDocPrinter [WINSPOOL.@]
3460 */
3461BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3462{
Huw Davies6fd3c472005-07-08 14:19:18 +00003463 opened_printer_t *printer;
3464 BOOL ret = FALSE;
3465 TRACE("(%p)\n", hPrinter);
3466
3467 EnterCriticalSection(&printer_handles_cs);
3468
3469 printer = get_opened_printer(hPrinter);
3470 if(!printer)
3471 {
3472 SetLastError(ERROR_INVALID_HANDLE);
3473 goto end;
3474 }
3475
3476 if(!printer->doc)
3477 {
3478 SetLastError(ERROR_SPL_NO_STARTDOC);
3479 goto end;
3480 }
3481
3482 CloseHandle(printer->doc->hf);
3483 ScheduleJob(hPrinter, printer->doc->job_id);
3484 HeapFree(GetProcessHeap(), 0, printer->doc);
3485 printer->doc = NULL;
3486 ret = TRUE;
3487end:
3488 LeaveCriticalSection(&printer_handles_cs);
3489 return ret;
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003490}
3491
3492/*****************************************************************************
3493 * EndPagePrinter [WINSPOOL.@]
3494 */
3495BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3496{
Huw Davies6fd3c472005-07-08 14:19:18 +00003497 FIXME("(%p): stub\n", hPrinter);
3498 return TRUE;
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003499}
3500
3501/*****************************************************************************
3502 * StartDocPrinterA [WINSPOOL.@]
3503 */
3504DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3505{
Huw Daviesd8302662005-06-30 18:10:59 +00003506 UNICODE_STRING usBuffer;
3507 DOC_INFO_2W doc2W;
3508 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3509 DWORD ret;
3510
3511 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3512 or one (DOC_INFO_3) extra DWORDs */
3513
3514 switch(Level) {
3515 case 2:
3516 doc2W.JobId = doc2->JobId;
3517 /* fall through */
3518 case 3:
3519 doc2W.dwMode = doc2->dwMode;
3520 /* fall through */
3521 case 1:
3522 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3523 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3524 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3525 break;
3526
3527 default:
3528 SetLastError(ERROR_INVALID_LEVEL);
3529 return FALSE;
3530 }
3531
3532 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3533
3534 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3535 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3536 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3537
3538 return ret;
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003539}
3540
3541/*****************************************************************************
3542 * StartDocPrinterW [WINSPOOL.@]
3543 */
3544DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3545{
Huw Daviesd8302662005-06-30 18:10:59 +00003546 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
Huw Davies6fd3c472005-07-08 14:19:18 +00003547 opened_printer_t *printer;
3548 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3549 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
Huw Davies1ed9bac2005-07-13 14:14:37 +00003550 JOB_INFO_1W job_info;
Huw Davies6fd3c472005-07-08 14:19:18 +00003551 DWORD needed, ret = 0;
3552 HANDLE hf;
3553 WCHAR *filename;
Huw Daviesd8302662005-06-30 18:10:59 +00003554
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003555 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
Huw Daviesd8302662005-06-30 18:10:59 +00003556 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3557 debugstr_w(doc->pDatatype));
Huw Davies6fd3c472005-07-08 14:19:18 +00003558
3559 if(Level < 1 || Level > 3)
3560 {
3561 SetLastError(ERROR_INVALID_LEVEL);
3562 return 0;
3563 }
3564
3565 EnterCriticalSection(&printer_handles_cs);
3566 printer = get_opened_printer(hPrinter);
3567 if(!printer)
3568 {
3569 SetLastError(ERROR_INVALID_HANDLE);
3570 goto end;
3571 }
3572
3573 if(printer->doc)
3574 {
3575 SetLastError(ERROR_INVALID_PRINTER_STATE);
3576 goto end;
3577 }
3578
3579 /* Even if we're printing to a file we still add a print job, we'll
3580 just ignore the spool file name */
3581
3582 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3583 {
Francois Gouget42c41142007-01-18 11:37:51 +01003584 ERR("AddJob failed gle %u\n", GetLastError());
Huw Davies6fd3c472005-07-08 14:19:18 +00003585 goto end;
3586 }
3587
3588 if(doc->pOutputFile)
3589 filename = doc->pOutputFile;
3590 else
3591 filename = addjob->Path;
3592
3593 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3594 if(hf == INVALID_HANDLE_VALUE)
3595 goto end;
3596
Huw Davies1ed9bac2005-07-13 14:14:37 +00003597 memset(&job_info, 0, sizeof(job_info));
3598 job_info.pDocument = doc->pDocName;
3599 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
Huw Davies6fd3c472005-07-08 14:19:18 +00003600
3601 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3602 printer->doc->hf = hf;
3603 ret = printer->doc->job_id = addjob->JobId;
3604end:
3605 LeaveCriticalSection(&printer_handles_cs);
3606
3607 return ret;
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003608}
3609
3610/*****************************************************************************
3611 * StartPagePrinter [WINSPOOL.@]
3612 */
3613BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3614{
Huw Davies6fd3c472005-07-08 14:19:18 +00003615 FIXME("(%p): stub\n", hPrinter);
3616 return TRUE;
Dimitrie O. Paun6d267e92002-12-17 21:00:38 +00003617}
3618
3619/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003620 * GetFormA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003621 */
3622BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3623 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3624{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003625 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
Vincent Béron9a624912002-05-31 23:06:46 +00003626 Level,pForm,cbBuf,pcbNeeded);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003627 return FALSE;
3628}
3629
3630/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003631 * GetFormW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003632 */
3633BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3634 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3635{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003636 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
Huw D M Daviese39b6761999-05-17 16:20:51 +00003637 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3638 return FALSE;
3639}
3640
3641/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003642 * SetFormA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003643 */
3644BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3645 LPBYTE pForm)
3646{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003647 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003648 return FALSE;
3649}
3650
3651/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003652 * SetFormW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003653 */
3654BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3655 LPBYTE pForm)
3656{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003657 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003658 return FALSE;
3659}
3660
3661/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003662 * ReadPrinter [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003663 */
3664BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3665 LPDWORD pNoBytesRead)
3666{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003667 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003668 return FALSE;
3669}
3670
3671/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003672 * ResetPrinterA [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003673 */
3674BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3675{
Michael Stefaniucea335dd2002-10-22 00:47:33 +00003676 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003677 return FALSE;
3678}
3679
3680/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00003681 * ResetPrinterW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00003682 */
3683BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3684{
Michael Stefaniucea335dd2002-10-22 00:47:33 +00003685 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
Huw D M Daviese39b6761999-05-17 16:20:51 +00003686 return FALSE;
3687}
3688
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003689/*****************************************************************************
3690 * WINSPOOL_GetDWORDFromReg
3691 *
3692 * Return DWORD associated with ValueName from hkey.
Vincent Béron9a624912002-05-31 23:06:46 +00003693 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003694static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3695{
3696 DWORD sz = sizeof(DWORD), type, value = 0;
3697 LONG ret;
3698
3699 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3700
3701 if(ret != ERROR_SUCCESS) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003702 WARN("Got ret = %d on name %s\n", ret, ValueName);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003703 return 0;
3704 }
3705 if(type != REG_DWORD) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003706 ERR("Got type %d\n", type);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003707 return 0;
3708 }
3709 return value;
3710}
Huw D M Davies450270b1999-07-10 11:58:50 +00003711
Detlef Riekenberg4b531542007-07-26 23:05:27 +02003712
3713/*****************************************************************************
3714 * get_filename_from_reg [internal]
3715 *
3716 * Get ValueName from hkey storing result in out
3717 * when the Value in the registry has only a filename, use driverdir as prefix
3718 * outlen is space left in out
3719 * String is stored either as unicode or ascii
3720 *
3721 */
3722
3723static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3724 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3725{
3726 WCHAR filename[MAX_PATH];
3727 DWORD size;
3728 DWORD type;
3729 LONG ret;
3730 LPWSTR buffer = filename;
3731 LPWSTR ptr;
3732
3733 *needed = 0;
3734 size = sizeof(filename);
3735 buffer[0] = '\0';
3736 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3737 if (ret == ERROR_MORE_DATA) {
3738 TRACE("need dynamic buffer: %u\n", size);
3739 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3740 if (!buffer) {
3741 /* No Memory is bad */
3742 return FALSE;
3743 }
3744 buffer[0] = '\0';
3745 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3746 }
3747
3748 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3749 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3750 return FALSE;
3751 }
3752
3753 ptr = buffer;
3754 while (ptr) {
3755 /* do we have a full path ? */
3756 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3757 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3758
3759 if (!ret) {
3760 /* we must build the full Path */
3761 *needed += dirlen;
3762 if ((out) && (outlen > dirlen)) {
3763 if (unicode) {
3764 lstrcpyW((LPWSTR)out, driverdir);
3765 }
3766 else
3767 {
3768 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3769 }
3770 out += dirlen;
3771 outlen -= dirlen;
3772 }
3773 else
3774 out = NULL;
3775 }
3776
3777 /* write the filename */
3778 if (unicode) {
3779 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3780 if ((out) && (outlen >= size)) {
3781 lstrcpyW((LPWSTR)out, ptr);
3782 out += size;
3783 outlen -= size;
3784 }
3785 else
3786 out = NULL;
3787 }
3788 else
3789 {
3790 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3791 if ((out) && (outlen >= size)) {
3792 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3793 out += size;
3794 outlen -= size;
3795 }
3796 else
3797 out = NULL;
3798 }
3799 *needed += size;
3800 ptr += lstrlenW(ptr)+1;
3801 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3802 }
3803
3804 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3805
3806 /* write the multisz-termination */
3807 if (type == REG_MULTI_SZ) {
3808 size = (unicode) ? sizeof(WCHAR) : 1;
3809
3810 *needed += size;
3811 if (out && (outlen >= size)) {
3812 memset (out, 0, size);
3813 }
3814 }
3815 return TRUE;
3816}
3817
Huw D M Davies450270b1999-07-10 11:58:50 +00003818/*****************************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003819 * WINSPOOL_GetStringFromReg
Huw D M Davies450270b1999-07-10 11:58:50 +00003820 *
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003821 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3822 * String is stored either as unicode or ascii.
3823 * Bit of a hack here to get the ValueName if we want ascii.
Vincent Béron9a624912002-05-31 23:06:46 +00003824 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003825static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3826 DWORD buflen, DWORD *needed,
3827 BOOL unicode)
Huw D M Davies450270b1999-07-10 11:58:50 +00003828{
3829 DWORD sz = buflen, type;
3830 LONG ret;
3831
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003832 if(unicode)
3833 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3834 else {
Alexandre Julliard27319982006-11-17 15:29:40 +01003835 LPSTR ValueNameA = strdupWtoA(ValueName);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003836 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3837 HeapFree(GetProcessHeap(),0,ValueNameA);
3838 }
Huw D M Davies450270b1999-07-10 11:58:50 +00003839 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003840 WARN("Got ret = %d\n", ret);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003841 *needed = 0;
Huw D M Davies450270b1999-07-10 11:58:50 +00003842 return FALSE;
3843 }
Dmitry Timoshkovb13c4982006-04-14 22:34:57 +09003844 /* add space for terminating '\0' */
3845 sz += unicode ? sizeof(WCHAR) : 1;
Huw D M Davies450270b1999-07-10 11:58:50 +00003846 *needed = sz;
Dmitry Timoshkovb13c4982006-04-14 22:34:57 +09003847
3848 if (ptr)
3849 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3850
Huw D M Davies450270b1999-07-10 11:58:50 +00003851 return TRUE;
3852}
3853
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003854/*****************************************************************************
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003855 * WINSPOOL_GetDefaultDevMode
3856 *
3857 * Get a default DevMode values for wineps.
3858 * FIXME - use ppd.
3859 */
3860
3861static void WINSPOOL_GetDefaultDevMode(
3862 LPBYTE ptr,
3863 DWORD buflen, DWORD *needed,
3864 BOOL unicode)
3865{
3866 DEVMODEA dm;
Mike McCormack516a5772005-08-19 10:04:03 +00003867 static const char szwps[] = "wineps.drv";
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003868
3869 /* fill default DEVMODE - should be read from ppd... */
3870 ZeroMemory( &dm, sizeof(dm) );
Mike McCormack516a5772005-08-19 10:04:03 +00003871 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003872 dm.dmSpecVersion = DM_SPECVERSION;
3873 dm.dmDriverVersion = 1;
3874 dm.dmSize = sizeof(DEVMODEA);
3875 dm.dmDriverExtra = 0;
3876 dm.dmFields =
3877 DM_ORIENTATION | DM_PAPERSIZE |
3878 DM_PAPERLENGTH | DM_PAPERWIDTH |
3879 DM_SCALE |
3880 DM_COPIES |
3881 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3882 DM_YRESOLUTION | DM_TTOPTION;
3883
3884 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3885 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3886 dm.u1.s1.dmPaperLength = 2970;
3887 dm.u1.s1.dmPaperWidth = 2100;
3888
Dmitry Timoshkovd43fdc52007-11-01 14:22:11 +08003889 dm.u1.s1.dmScale = 100;
3890 dm.u1.s1.dmCopies = 1;
3891 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3892 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003893 /* dm.dmColor */
3894 /* dm.dmDuplex */
3895 dm.dmYResolution = 300; /* 300dpi */
3896 dm.dmTTOption = DMTT_BITMAP;
3897 /* dm.dmCollate */
3898 /* dm.dmFormName */
3899 /* dm.dmLogPixels */
3900 /* dm.dmBitsPerPel */
3901 /* dm.dmPelsWidth */
3902 /* dm.dmPelsHeight */
Dmitry Timoshkovd43fdc52007-11-01 14:22:11 +08003903 /* dm.u2.dmDisplayFlags */
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003904 /* dm.dmDisplayFrequency */
3905 /* dm.dmICMMethod */
3906 /* dm.dmICMIntent */
3907 /* dm.dmMediaType */
3908 /* dm.dmDitherType */
3909 /* dm.dmReserved1 */
3910 /* dm.dmReserved2 */
3911 /* dm.dmPanningWidth */
3912 /* dm.dmPanningHeight */
3913
3914 if(unicode) {
3915 if(buflen >= sizeof(DEVMODEW)) {
Dmitry Timoshkov3a910c72003-08-12 20:42:18 +00003916 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003917 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3918 HeapFree(GetProcessHeap(),0,pdmW);
3919 }
3920 *needed = sizeof(DEVMODEW);
3921 }
3922 else
3923 {
3924 if(buflen >= sizeof(DEVMODEA)) {
3925 memcpy(ptr, &dm, sizeof(DEVMODEA));
3926 }
3927 *needed = sizeof(DEVMODEA);
3928 }
3929}
3930
3931/*****************************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003932 * WINSPOOL_GetDevModeFromReg
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00003933 *
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003934 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3935 * DevMode is stored either as unicode or ascii.
Vincent Béron9a624912002-05-31 23:06:46 +00003936 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003937static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3938 LPBYTE ptr,
3939 DWORD buflen, DWORD *needed,
3940 BOOL unicode)
3941{
3942 DWORD sz = buflen, type;
3943 LONG ret;
3944
Hidenori Takeshimab5446372001-09-07 18:35:58 +00003945 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003946 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
Gerard Patelaaaee1b2000-08-16 12:43:00 +00003947 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3948 if (sz < sizeof(DEVMODEA))
3949 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02003950 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
Marcus Meissner0c630122001-05-09 17:10:41 +00003951 return FALSE;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003952 }
Gerard Patelaaaee1b2000-08-16 12:43:00 +00003953 /* ensures that dmSize is not erratically bogus if registry is invalid */
3954 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3955 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003956 if(unicode) {
3957 sz += (CCHDEVICENAME + CCHFORMNAME);
3958 if(buflen >= sz) {
Dmitry Timoshkov3a910c72003-08-12 20:42:18 +00003959 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00003960 memcpy(ptr, dmW, sz);
3961 HeapFree(GetProcessHeap(),0,dmW);
3962 }
3963 }
3964 *needed = sz;
3965 return TRUE;
3966}
3967
3968/*********************************************************************
Huw Davies09a2c892007-04-12 14:08:22 +01003969 * WINSPOOL_GetPrinter_1
3970 *
3971 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3972 * The strings are either stored as unicode or ascii.
3973 */
3974static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3975 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3976 BOOL unicode)
3977{
3978 DWORD size, left = cbBuf;
3979 BOOL space = (cbBuf > 0);
3980 LPBYTE ptr = buf;
3981
3982 *pcbNeeded = 0;
3983
3984 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3985 unicode)) {
3986 if(space && size <= left) {
3987 pi1->pName = (LPWSTR)ptr;
3988 ptr += size;
3989 left -= size;
3990 } else
3991 space = FALSE;
3992 *pcbNeeded += size;
3993 }
3994
3995 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3996 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3997 unicode)) {
3998 if(space && size <= left) {
3999 pi1->pDescription = (LPWSTR)ptr;
4000 ptr += size;
4001 left -= size;
4002 } else
4003 space = FALSE;
4004 *pcbNeeded += size;
4005 }
4006
4007 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4008 unicode)) {
4009 if(space && size <= left) {
4010 pi1->pComment = (LPWSTR)ptr;
4011 ptr += size;
4012 left -= size;
4013 } else
4014 space = FALSE;
4015 *pcbNeeded += size;
4016 }
4017
4018 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4019
4020 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4021 memset(pi1, 0, sizeof(*pi1));
4022
4023 return space;
4024}
4025/*********************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004026 * WINSPOOL_GetPrinter_2
4027 *
4028 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
4029 * The strings are either stored as unicode or ascii.
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004030 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004031static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4032 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4033 BOOL unicode)
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004034{
4035 DWORD size, left = cbBuf;
4036 BOOL space = (cbBuf > 0);
4037 LPBYTE ptr = buf;
4038
4039 *pcbNeeded = 0;
4040
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004041 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4042 unicode)) {
4043 if(space && size <= left) {
4044 pi2->pPrinterName = (LPWSTR)ptr;
4045 ptr += size;
4046 left -= size;
4047 } else
4048 space = FALSE;
4049 *pcbNeeded += size;
4050 }
4051 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
4052 unicode)) {
4053 if(space && size <= left) {
4054 pi2->pShareName = (LPWSTR)ptr;
4055 ptr += size;
4056 left -= size;
4057 } else
4058 space = FALSE;
4059 *pcbNeeded += size;
4060 }
4061 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4062 unicode)) {
4063 if(space && size <= left) {
4064 pi2->pPortName = (LPWSTR)ptr;
4065 ptr += size;
4066 left -= size;
4067 } else
4068 space = FALSE;
4069 *pcbNeeded += size;
4070 }
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
4072 &size, unicode)) {
4073 if(space && size <= left) {
4074 pi2->pDriverName = (LPWSTR)ptr;
4075 ptr += size;
4076 left -= size;
4077 } else
4078 space = FALSE;
4079 *pcbNeeded += size;
4080 }
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4082 unicode)) {
4083 if(space && size <= left) {
4084 pi2->pComment = (LPWSTR)ptr;
4085 ptr += size;
4086 left -= size;
4087 } else
4088 space = FALSE;
4089 *pcbNeeded += size;
4090 }
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4092 unicode)) {
4093 if(space && size <= left) {
4094 pi2->pLocation = (LPWSTR)ptr;
4095 ptr += size;
4096 left -= size;
4097 } else
4098 space = FALSE;
4099 *pcbNeeded += size;
4100 }
4101 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4102 &size, unicode)) {
4103 if(space && size <= left) {
4104 pi2->pDevMode = (LPDEVMODEW)ptr;
4105 ptr += size;
4106 left -= size;
4107 } else
4108 space = FALSE;
4109 *pcbNeeded += size;
4110 }
Hidenori Takeshimab5446372001-09-07 18:35:58 +00004111 else
4112 {
Hidenori Takeshimab5446372001-09-07 18:35:58 +00004113 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4114 if(space && size <= left) {
4115 pi2->pDevMode = (LPDEVMODEW)ptr;
4116 ptr += size;
4117 left -= size;
4118 } else
4119 space = FALSE;
4120 *pcbNeeded += size;
4121 }
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004122 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4123 &size, unicode)) {
4124 if(space && size <= left) {
4125 pi2->pSepFile = (LPWSTR)ptr;
4126 ptr += size;
4127 left -= size;
4128 } else
4129 space = FALSE;
4130 *pcbNeeded += size;
4131 }
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4133 &size, unicode)) {
4134 if(space && size <= left) {
4135 pi2->pPrintProcessor = (LPWSTR)ptr;
4136 ptr += size;
4137 left -= size;
4138 } else
4139 space = FALSE;
4140 *pcbNeeded += size;
4141 }
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4143 &size, unicode)) {
4144 if(space && size <= left) {
4145 pi2->pDatatype = (LPWSTR)ptr;
4146 ptr += size;
4147 left -= size;
4148 } else
4149 space = FALSE;
4150 *pcbNeeded += size;
4151 }
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4153 &size, unicode)) {
4154 if(space && size <= left) {
4155 pi2->pParameters = (LPWSTR)ptr;
4156 ptr += size;
4157 left -= size;
4158 } else
4159 space = FALSE;
4160 *pcbNeeded += size;
4161 }
4162 if(pi2) {
Vincent Béron9a624912002-05-31 23:06:46 +00004163 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004164 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4165 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4166 "Default Priority");
4167 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4168 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4169 }
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004170
4171 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4172 memset(pi2, 0, sizeof(*pi2));
4173
4174 return space;
4175}
4176
4177/*********************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004178 * WINSPOOL_GetPrinter_4
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004179 *
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004180 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004181 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004182static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4183 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4184 BOOL unicode)
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004185{
4186 DWORD size, left = cbBuf;
4187 BOOL space = (cbBuf > 0);
4188 LPBYTE ptr = buf;
4189
4190 *pcbNeeded = 0;
4191
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004192 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4193 unicode)) {
4194 if(space && size <= left) {
4195 pi4->pPrinterName = (LPWSTR)ptr;
4196 ptr += size;
4197 left -= size;
4198 } else
4199 space = FALSE;
4200 *pcbNeeded += size;
4201 }
4202 if(pi4) {
Vincent Béron9a624912002-05-31 23:06:46 +00004203 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004204 }
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004205
4206 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4207 memset(pi4, 0, sizeof(*pi4));
4208
4209 return space;
4210}
4211
4212/*********************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004213 * WINSPOOL_GetPrinter_5
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004214 *
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004215 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004216 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004217static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4218 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4219 BOOL unicode)
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004220{
4221 DWORD size, left = cbBuf;
4222 BOOL space = (cbBuf > 0);
4223 LPBYTE ptr = buf;
4224
4225 *pcbNeeded = 0;
4226
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004227 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4228 unicode)) {
4229 if(space && size <= left) {
4230 pi5->pPrinterName = (LPWSTR)ptr;
4231 ptr += size;
4232 left -= size;
4233 } else
4234 space = FALSE;
4235 *pcbNeeded += size;
4236 }
4237 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4238 unicode)) {
4239 if(space && size <= left) {
4240 pi5->pPortName = (LPWSTR)ptr;
4241 ptr += size;
4242 left -= size;
4243 } else
4244 space = FALSE;
4245 *pcbNeeded += size;
4246 }
4247 if(pi5) {
Vincent Béron9a624912002-05-31 23:06:46 +00004248 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004249 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
Vincent Béron9a624912002-05-31 23:06:46 +00004250 "dnsTimeout");
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004251 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
Vincent Béron9a624912002-05-31 23:06:46 +00004252 "txTimeout");
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004253 }
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004254
4255 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4256 memset(pi5, 0, sizeof(*pi5));
4257
4258 return space;
4259}
Huw D M Davies450270b1999-07-10 11:58:50 +00004260
Detlef Riekenbergae91e972008-02-26 23:09:55 +01004261/*********************************************************************
4262 * WINSPOOL_GetPrinter_7
4263 *
4264 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4265 */
4266static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4267 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4268{
4269 DWORD size, left = cbBuf;
4270 BOOL space = (cbBuf > 0);
4271 LPBYTE ptr = buf;
4272
4273 *pcbNeeded = 0;
4274
4275 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4276 {
4277 if (space && size <= left) {
4278 pi7->pszObjectGUID = (LPWSTR)ptr;
4279 ptr += size;
4280 left -= size;
4281 } else
4282 space = FALSE;
4283 *pcbNeeded += size;
4284 }
4285 if (pi7) {
4286 /* We do not have a Directory Service */
4287 pi7->dwAction = DSPRINT_UNPUBLISH;
4288 }
4289
4290 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4291 memset(pi7, 0, sizeof(*pi7));
4292
4293 return space;
4294}
4295
Detlef Riekenberg81dadcb2008-02-28 21:46:17 +01004296/*********************************************************************
4297 * WINSPOOL_GetPrinter_9
4298 *
4299 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4300 * The strings are either stored as unicode or ascii.
4301 */
4302static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4303 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4304{
4305 DWORD size;
4306 BOOL space = (cbBuf > 0);
4307
4308 *pcbNeeded = 0;
4309
4310 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4311 if(space && size <= cbBuf) {
4312 pi9->pDevMode = (LPDEVMODEW)buf;
4313 } else
4314 space = FALSE;
4315 *pcbNeeded += size;
4316 }
4317 else
4318 {
4319 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4320 if(space && size <= cbBuf) {
4321 pi9->pDevMode = (LPDEVMODEW)buf;
4322 } else
4323 space = FALSE;
4324 *pcbNeeded += size;
4325 }
4326
4327 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4328 memset(pi9, 0, sizeof(*pi9));
4329
4330 return space;
4331}
4332
Huw D M Daviese39b6761999-05-17 16:20:51 +00004333/*****************************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004334 * WINSPOOL_GetPrinter
4335 *
4336 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4337 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4338 * just a collection of pointers to strings.
Huw D M Daviese39b6761999-05-17 16:20:51 +00004339 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004340static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4341 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
Huw D M Daviese39b6761999-05-17 16:20:51 +00004342{
Alexandre Julliarde1635e92001-02-28 05:26:08 +00004343 LPCWSTR name;
Huw D M Davies450270b1999-07-10 11:58:50 +00004344 DWORD size, needed = 0;
4345 LPBYTE ptr = NULL;
4346 HKEY hkeyPrinter, hkeyPrinters;
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004347 BOOL ret;
4348
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004349 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
Huw D M Daviese39b6761999-05-17 16:20:51 +00004350
Huw Daviesdf9c4342005-07-05 11:00:09 +00004351 if (!(name = get_opened_printer_name(hPrinter))) {
4352 SetLastError(ERROR_INVALID_HANDLE);
4353 return FALSE;
4354 }
Alexandre Julliarde1635e92001-02-28 05:26:08 +00004355
Detlef Riekenberg358ce062006-05-21 14:35:29 +02004356 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw D M Davies450270b1999-07-10 11:58:50 +00004357 ERROR_SUCCESS) {
4358 ERR("Can't create Printers key\n");
4359 return FALSE;
4360 }
Alexandre Julliarde1635e92001-02-28 05:26:08 +00004361 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4362 {
4363 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
Huw D M Davies450270b1999-07-10 11:58:50 +00004364 RegCloseKey(hkeyPrinters);
4365 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4366 return FALSE;
4367 }
Huw D M Daviese39b6761999-05-17 16:20:51 +00004368
Huw D M Davies450270b1999-07-10 11:58:50 +00004369 switch(Level) {
4370 case 2:
4371 {
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004372 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
Huw D M Davies450270b1999-07-10 11:58:50 +00004373
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004374 size = sizeof(PRINTER_INFO_2W);
Huw D M Davies450270b1999-07-10 11:58:50 +00004375 if(size <= cbBuf) {
4376 ptr = pPrinter + size;
4377 cbBuf -= size;
4378 memset(pPrinter, 0, size);
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004379 } else {
4380 pi2 = NULL;
Huw D M Davies450270b1999-07-10 11:58:50 +00004381 cbBuf = 0;
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004382 }
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004383 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4384 unicode);
Huw D M Davies450270b1999-07-10 11:58:50 +00004385 needed += size;
Huw D M Davies450270b1999-07-10 11:58:50 +00004386 break;
4387 }
Vincent Béron9a624912002-05-31 23:06:46 +00004388
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004389 case 4:
4390 {
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004391 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
Vincent Béron9a624912002-05-31 23:06:46 +00004392
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004393 size = sizeof(PRINTER_INFO_4W);
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004394 if(size <= cbBuf) {
4395 ptr = pPrinter + size;
4396 cbBuf -= size;
4397 memset(pPrinter, 0, size);
4398 } else {
4399 pi4 = NULL;
4400 cbBuf = 0;
4401 }
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004402 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4403 unicode);
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004404 needed += size;
4405 break;
4406 }
4407
4408
Huw D M Davies450270b1999-07-10 11:58:50 +00004409 case 5:
4410 {
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004411 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
Huw D M Davies450270b1999-07-10 11:58:50 +00004412
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004413 size = sizeof(PRINTER_INFO_5W);
Huw D M Davies450270b1999-07-10 11:58:50 +00004414 if(size <= cbBuf) {
4415 ptr = pPrinter + size;
4416 cbBuf -= size;
4417 memset(pPrinter, 0, size);
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004418 } else {
4419 pi5 = NULL;
Huw D M Davies450270b1999-07-10 11:58:50 +00004420 cbBuf = 0;
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004421 }
Huw D M Davies450270b1999-07-10 11:58:50 +00004422
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004423 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4424 unicode);
Huw D M Davies450270b1999-07-10 11:58:50 +00004425 needed += size;
Huw D M Davies450270b1999-07-10 11:58:50 +00004426 break;
4427 }
4428
Detlef Riekenbergae91e972008-02-26 23:09:55 +01004429
4430 case 6:
4431 {
4432 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4433
4434 size = sizeof(PRINTER_INFO_6);
4435 if (size <= cbBuf) {
4436 /* FIXME: We do not update the status yet */
4437 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4438 ret = TRUE;
4439 } else {
4440 ret = FALSE;
4441 }
4442
4443 needed += size;
4444 break;
4445 }
4446
4447 case 7:
4448 {
4449 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4450
4451 size = sizeof(PRINTER_INFO_7W);
4452 if (size <= cbBuf) {
4453 ptr = pPrinter + size;
4454 cbBuf -= size;
4455 memset(pPrinter, 0, size);
4456 } else {
4457 pi7 = NULL;
4458 cbBuf = 0;
4459 }
4460
4461 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4462 needed += size;
4463 break;
4464 }
4465
4466
Detlef Riekenberg81dadcb2008-02-28 21:46:17 +01004467 case 9:
4468 {
4469 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4470
4471 size = sizeof(PRINTER_INFO_9W);
4472 if(size <= cbBuf) {
4473 ptr = pPrinter + size;
4474 cbBuf -= size;
4475 memset(pPrinter, 0, size);
4476 } else {
4477 pi9 = NULL;
4478 cbBuf = 0;
4479 }
4480
4481 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4482 needed += size;
4483 break;
4484 }
4485
4486
Huw D M Davies450270b1999-07-10 11:58:50 +00004487 default:
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004488 FIXME("Unimplemented level %d\n", Level);
Huw D M Davies450270b1999-07-10 11:58:50 +00004489 SetLastError(ERROR_INVALID_LEVEL);
4490 RegCloseKey(hkeyPrinters);
4491 RegCloseKey(hkeyPrinter);
4492 return FALSE;
4493 }
4494
4495 RegCloseKey(hkeyPrinter);
4496 RegCloseKey(hkeyPrinters);
4497
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004498 TRACE("returning %d needed = %d\n", ret, needed);
Huw D M Davies450270b1999-07-10 11:58:50 +00004499 if(pcbNeeded) *pcbNeeded = needed;
Huw D M Daviesc7665eb1999-09-10 14:37:29 +00004500 if(!ret)
4501 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4502 return ret;
Huw D M Daviese39b6761999-05-17 16:20:51 +00004503}
4504
4505/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00004506 * GetPrinterW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00004507 */
4508BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004509 DWORD cbBuf, LPDWORD pcbNeeded)
Huw D M Daviese39b6761999-05-17 16:20:51 +00004510{
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004511 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4512 TRUE);
Huw D M Daviese39b6761999-05-17 16:20:51 +00004513}
4514
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004515/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00004516 * GetPrinterA [WINSPOOL.@]
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004517 */
4518BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4519 DWORD cbBuf, LPDWORD pcbNeeded)
4520{
4521 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4522 FALSE);
4523}
4524
4525/*****************************************************************************
4526 * WINSPOOL_EnumPrinters
4527 *
4528 * Implementation of EnumPrintersA|W
4529 */
4530static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4531 DWORD dwLevel, LPBYTE lpbPrinters,
4532 DWORD cbBuf, LPDWORD lpdwNeeded,
4533 LPDWORD lpdwReturned, BOOL unicode)
4534
4535{
4536 HKEY hkeyPrinters, hkeyPrinter;
4537 WCHAR PrinterName[255];
4538 DWORD needed = 0, number = 0;
4539 DWORD used, i, left;
4540 PBYTE pi, buf;
4541
4542 if(lpbPrinters)
4543 memset(lpbPrinters, 0, cbBuf);
4544 if(lpdwReturned)
4545 *lpdwReturned = 0;
Huw D M Davies87f98a52001-01-09 20:52:17 +00004546 if(lpdwNeeded)
4547 *lpdwNeeded = 0;
4548
4549 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4550 if(dwType == PRINTER_ENUM_DEFAULT)
4551 return TRUE;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004552
Marcus Meissner75e4e942002-09-09 19:19:18 +00004553 if (dwType & PRINTER_ENUM_CONNECTIONS) {
Detlef Riekenbergbc85a342007-01-21 20:49:34 +01004554 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4555 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4556 if (!dwType) {
4557 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4558 *lpdwNeeded = 0;
4559 *lpdwReturned = 0;
4560 return TRUE;
4561 }
4562
Marcus Meissner75e4e942002-09-09 19:19:18 +00004563 }
4564
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004565 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004566 FIXME("dwType = %08x\n", dwType);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004567 SetLastError(ERROR_INVALID_FLAGS);
4568 return FALSE;
4569 }
4570
Detlef Riekenberg358ce062006-05-21 14:35:29 +02004571 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004572 ERROR_SUCCESS) {
4573 ERR("Can't create Printers key\n");
4574 return FALSE;
4575 }
Vincent Béron9a624912002-05-31 23:06:46 +00004576
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004577 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4578 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4579 RegCloseKey(hkeyPrinters);
4580 ERR("Can't query Printers key\n");
4581 return FALSE;
4582 }
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004583 TRACE("Found %d printers\n", number);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004584
4585 switch(dwLevel) {
4586 case 1:
Huw Davies09a2c892007-04-12 14:08:22 +01004587 used = number * sizeof(PRINTER_INFO_1W);
4588 break;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004589 case 2:
4590 used = number * sizeof(PRINTER_INFO_2W);
4591 break;
4592 case 4:
4593 used = number * sizeof(PRINTER_INFO_4W);
4594 break;
4595 case 5:
4596 used = number * sizeof(PRINTER_INFO_5W);
4597 break;
4598
4599 default:
4600 SetLastError(ERROR_INVALID_LEVEL);
4601 RegCloseKey(hkeyPrinters);
4602 return FALSE;
4603 }
4604 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4605
4606 for(i = 0; i < number; i++) {
Vitaly Lipatov914e78a2007-12-01 19:43:37 +03004607 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004608 ERROR_SUCCESS) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004609 ERR("Can't enum key number %d\n", i);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004610 RegCloseKey(hkeyPrinters);
4611 return FALSE;
4612 }
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004613 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004614 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4615 ERROR_SUCCESS) {
4616 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4617 RegCloseKey(hkeyPrinters);
4618 return FALSE;
4619 }
4620
4621 if(cbBuf > used) {
4622 buf = lpbPrinters + used;
4623 left = cbBuf - used;
4624 } else {
4625 buf = NULL;
4626 left = 0;
4627 }
4628
4629 switch(dwLevel) {
Huw Davies09a2c892007-04-12 14:08:22 +01004630 case 1:
4631 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4632 left, &needed, unicode);
4633 used += needed;
4634 if(pi) pi += sizeof(PRINTER_INFO_1W);
4635 break;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004636 case 2:
4637 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4638 left, &needed, unicode);
4639 used += needed;
4640 if(pi) pi += sizeof(PRINTER_INFO_2W);
4641 break;
4642 case 4:
4643 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4644 left, &needed, unicode);
4645 used += needed;
4646 if(pi) pi += sizeof(PRINTER_INFO_4W);
4647 break;
4648 case 5:
4649 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4650 left, &needed, unicode);
4651 used += needed;
4652 if(pi) pi += sizeof(PRINTER_INFO_5W);
4653 break;
4654 default:
4655 ERR("Shouldn't be here!\n");
4656 RegCloseKey(hkeyPrinter);
4657 RegCloseKey(hkeyPrinters);
4658 return FALSE;
4659 }
4660 RegCloseKey(hkeyPrinter);
4661 }
4662 RegCloseKey(hkeyPrinters);
4663
4664 if(lpdwNeeded)
4665 *lpdwNeeded = used;
4666
4667 if(used > cbBuf) {
4668 if(lpbPrinters)
4669 memset(lpbPrinters, 0, cbBuf);
4670 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4671 return FALSE;
4672 }
4673 if(lpdwReturned)
Vincent Béron9a624912002-05-31 23:06:46 +00004674 *lpdwReturned = number;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004675 SetLastError(ERROR_SUCCESS);
4676 return TRUE;
4677}
4678
4679
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004680/******************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00004681 * EnumPrintersW [WINSPOOL.@]
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004682 *
4683 * Enumerates the available printers, print servers and print
4684 * providers, depending on the specified flags, name and level.
4685 *
4686 * RETURNS:
4687 *
4688 * If level is set to 1:
Huw Davies09a2c892007-04-12 14:08:22 +01004689 * Returns an array of PRINTER_INFO_1 data structures in the
4690 * lpbPrinters buffer.
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004691 *
4692 * If level is set to 2:
4693 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
Vincent Béron9a624912002-05-31 23:06:46 +00004694 * Returns an array of PRINTER_INFO_2 data structures in the
4695 * lpbPrinters buffer. Note that according to MSDN also an
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004696 * OpenPrinter should be performed on every remote printer.
4697 *
4698 * If level is set to 4 (officially WinNT only):
4699 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4700 * Fast: Only the registry is queried to retrieve printer names,
4701 * no connection to the driver is made.
Vincent Béron9a624912002-05-31 23:06:46 +00004702 * Returns an array of PRINTER_INFO_4 data structures in the
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004703 * lpbPrinters buffer.
4704 *
4705 * If level is set to 5 (officially WinNT4/Win9x only):
4706 * Fast: Only the registry is queried to retrieve printer names,
4707 * no connection to the driver is made.
Vincent Béron9a624912002-05-31 23:06:46 +00004708 * Returns an array of PRINTER_INFO_5 data structures in the
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004709 * lpbPrinters buffer.
4710 *
4711 * If level set to 3 or 6+:
Alexandre Julliarde1635e92001-02-28 05:26:08 +00004712 * returns zero (failure!)
Vincent Béron9a624912002-05-31 23:06:46 +00004713 *
Alexandre Julliarde1635e92001-02-28 05:26:08 +00004714 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004715 * for information.
4716 *
4717 * BUGS:
4718 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4719 * - Only levels 2, 4 and 5 are implemented at the moment.
4720 * - 16-bit printer drivers are not enumerated.
Vincent Béron9a624912002-05-31 23:06:46 +00004721 * - Returned amount of bytes used/needed does not match the real Windoze
4722 * implementation (as in this implementation, all strings are part
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004723 * of the buffer, whereas Win32 keeps them somewhere else)
4724 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4725 *
4726 * NOTE:
4727 * - In a regular Wine installation, no registry settings for printers
4728 * exist, which makes this function return an empty list.
4729 */
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004730BOOL WINAPI EnumPrintersW(
Patrik Stridvall2b3aa612000-12-01 23:58:28 +00004731 DWORD dwType, /* [in] Types of print objects to enumerate */
4732 LPWSTR lpszName, /* [in] name of objects to enumerate */
4733 DWORD dwLevel, /* [in] type of printer info structure */
4734 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4735 DWORD cbBuf, /* [in] max size of buffer in bytes */
4736 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4737 LPDWORD lpdwReturned /* [out] number of entries returned */
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004738 )
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004739{
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004740 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4741 lpdwNeeded, lpdwReturned, TRUE);
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004742}
4743
4744/******************************************************************
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +01004745 * EnumPrintersA [WINSPOOL.@]
4746 *
4747 * See EnumPrintersW
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004748 *
4749 */
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +01004750BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4751 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004752{
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +01004753 BOOL ret;
4754 UNICODE_STRING pNameU;
4755 LPWSTR pNameW;
4756 LPBYTE pPrintersW;
Huw Davies9108eed2006-12-04 14:32:36 +00004757
Detlef Riekenberg9e35ee82008-03-22 19:28:50 +01004758 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4759 pPrinters, cbBuf, pcbNeeded, pcReturned);
4760
4761 pNameW = asciitounicode(&pNameU, pName);
4762
4763 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4764 MS Office need this */
4765 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4766
4767 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4768
4769 RtlFreeUnicodeString(&pNameU);
4770 if (ret) {
4771 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4772 }
4773 HeapFree(GetProcessHeap(), 0, pPrintersW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00004774 return ret;
Huw D M Daviescb6aa381999-10-31 17:34:31 +00004775}
4776
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004777/*****************************************************************************
4778 * WINSPOOL_GetDriverInfoFromReg [internal]
4779 *
4780 * Enters the information from the registry into the DRIVER_INFO struct
4781 *
4782 * RETURNS
4783 * zero if the printer driver does not exist in the registry
4784 * (only if Level > 1) otherwise nonzero
4785 */
4786static BOOL WINSPOOL_GetDriverInfoFromReg(
4787 HKEY hkeyDrivers,
4788 LPWSTR DriverName,
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004789 const printenv_t * env,
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004790 DWORD Level,
4791 LPBYTE ptr, /* DRIVER_INFO */
4792 LPBYTE pDriverStrings, /* strings buffer */
4793 DWORD cbBuf, /* size of string buffer */
4794 LPDWORD pcbNeeded, /* space needed for str. */
4795 BOOL unicode) /* type of strings */
Dmitry Timoshkovb13c4982006-04-14 22:34:57 +09004796{
4797 DWORD size, tmp;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004798 HKEY hkeyDriver;
Detlef Riekenberg4b531542007-07-26 23:05:27 +02004799 WCHAR driverdir[MAX_PATH];
4800 DWORD dirlen;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004801 LPBYTE strPtr = pDriverStrings;
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004802 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004803
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004804 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4805 debugstr_w(DriverName), env,
4806 Level, di, pDriverStrings, cbBuf, unicode);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004807
Detlef Riekenberga2daf752007-07-26 23:14:55 +02004808 if (di) ZeroMemory(di, di_sizeof[Level]);
4809
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004810 if (unicode) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004811 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004812 if (*pcbNeeded <= cbBuf)
4813 strcpyW((LPWSTR)strPtr, DriverName);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004814 }
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004815 else
4816 {
4817 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4818 if (*pcbNeeded <= cbBuf)
4819 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004820 }
4821
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004822 /* pName for level 1 has a different offset! */
4823 if (Level == 1) {
4824 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4825 return TRUE;
4826 }
4827
4828 /* .cVersion and .pName for level > 1 */
4829 if (di) {
4830 di->cVersion = env->driverversion;
4831 di->pName = (LPWSTR) strPtr;
4832 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4833 }
4834
Detlef Riekenberg4b531542007-07-26 23:05:27 +02004835 /* Reserve Space for the largest subdir and a Backslash*/
4836 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4837 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4838 /* Should never Fail */
4839 return FALSE;
4840 }
4841 lstrcatW(driverdir, env->versionsubdir);
4842 lstrcatW(driverdir, backslashW);
4843
4844 /* dirlen must not include the terminating zero */
4845 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4846 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4847
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004848 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
Francois Gouget42c41142007-01-18 11:37:51 +01004849 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004850 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4851 return FALSE;
4852 }
4853
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004854 /* pEnvironment */
4855 if (unicode)
4856 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004857 else
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004858 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4859
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004860 *pcbNeeded += size;
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004861 if (*pcbNeeded <= cbBuf) {
4862 if (unicode) {
4863 lstrcpyW((LPWSTR)strPtr, env->envname);
4864 }
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004865 else
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02004866 {
4867 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4868 }
4869 if (di) di->pEnvironment = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004870 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4871 }
4872
Detlef Riekenberg4b531542007-07-26 23:05:27 +02004873 /* .pDriverPath is the Graphics rendering engine.
4874 The full Path is required to avoid a crash in some apps */
4875 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004876 *pcbNeeded += size;
Detlef Riekenberg4b531542007-07-26 23:05:27 +02004877 if (*pcbNeeded <= cbBuf)
4878 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4879
4880 if (di) di->pDriverPath = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004881 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4882 }
4883
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004884 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4885 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004886 *pcbNeeded += size;
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004887 if (*pcbNeeded <= cbBuf)
4888 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4889
4890 if (di) di->pDataFile = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004891 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4892 }
4893
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004894 /* .pConfigFile is the Driver user Interface */
4895 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004896 *pcbNeeded += size;
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004897 if (*pcbNeeded <= cbBuf)
4898 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4899
4900 if (di) di->pConfigFile = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004901 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4902 }
4903
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004904 if (Level == 2 ) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004905 RegCloseKey(hkeyDriver);
Hans Leidekker61faa6b2006-10-13 11:51:23 +02004906 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004907 return TRUE;
4908 }
4909
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004910 if (Level == 5 ) {
4911 RegCloseKey(hkeyDriver);
4912 FIXME("level 5: incomplete\n");
4913 return TRUE;
4914 }
4915
4916 /* .pHelpFile */
4917 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004918 *pcbNeeded += size;
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004919 if (*pcbNeeded <= cbBuf)
4920 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4921
4922 if (di) di->pHelpFile = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004923 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4924 }
4925
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004926 /* .pDependentFiles */
4927 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004928 *pcbNeeded += size;
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004929 if (*pcbNeeded <= cbBuf)
4930 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4931
4932 if (di) di->pDependentFiles = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004933 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4934 }
Detlef Riekenberg449fa0d2007-08-24 20:05:57 +02004935 else if (GetVersion() & 0x80000000) {
Francois Gougetb2bc7122007-09-27 18:57:51 +02004936 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
Detlef Riekenberg449fa0d2007-08-24 20:05:57 +02004937 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4938 *pcbNeeded += size;
4939 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4940
4941 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4942 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4943 }
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004944
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004945 /* .pMonitorName is the optional Language Monitor */
4946 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004947 *pcbNeeded += size;
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004948 if (*pcbNeeded <= cbBuf)
4949 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4950
4951 if (di) di->pMonitorName = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004952 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4953 }
4954
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004955 /* .pDefaultDataType */
4956 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004957 *pcbNeeded += size;
4958 if(*pcbNeeded <= cbBuf)
Detlef Riekenberg7a2c4fb2007-07-26 23:24:31 +02004959 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4960
4961 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00004962 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4963 }
4964
Detlef Riekenberg510c4dc2007-07-26 23:37:22 +02004965 if (Level == 3 ) {
4966 RegCloseKey(hkeyDriver);
4967 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4968 return TRUE;
4969 }
4970
4971 /* .pszzPreviousNames */
4972 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4973 *pcbNeeded += size;
4974 if(*pcbNeeded <= cbBuf)
4975 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4976
4977 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4978 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4979 }
4980
4981 if (Level == 4 ) {
4982 RegCloseKey(hkeyDriver);
4983 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4984 return TRUE;
4985 }
4986
4987 /* support is missing, but not important enough for a FIXME */
4988 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4989
4990 /* .pszMfgName */
4991 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4992 *pcbNeeded += size;
4993 if(*pcbNeeded <= cbBuf)
4994 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4995
4996 if (di) di->pszMfgName = (LPWSTR)strPtr;
4997 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 }
4999
5000 /* .pszOEMUrl */
5001 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
5002 *pcbNeeded += size;
5003 if(*pcbNeeded <= cbBuf)
5004 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
5005
5006 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5007 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5008 }
5009
5010 /* .pszHardwareID */
5011 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
5012 *pcbNeeded += size;
5013 if(*pcbNeeded <= cbBuf)
5014 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
5015
5016 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5017 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5018 }
5019
5020 /* .pszProvider */
5021 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
5022 *pcbNeeded += size;
5023 if(*pcbNeeded <= cbBuf)
5024 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
5025
5026 if (di) di->pszProvider = (LPWSTR)strPtr;
5027 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5028 }
5029
5030 if (Level == 6 ) {
5031 RegCloseKey(hkeyDriver);
5032 return TRUE;
5033 }
5034
5035 /* support is missing, but not important enough for a FIXME */
5036 TRACE("level 8: incomplete\n");
5037
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005038 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005039 RegCloseKey(hkeyDriver);
5040 return TRUE;
5041}
Huw D M Davies450270b1999-07-10 11:58:50 +00005042
Huw D M Daviese39b6761999-05-17 16:20:51 +00005043/*****************************************************************************
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005044 * WINSPOOL_GetPrinterDriver
Huw D M Daviese39b6761999-05-17 16:20:51 +00005045 */
Vitaly Lipatovc9d78fc2007-02-18 13:51:09 +03005046static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005047 DWORD Level, LPBYTE pDriverInfo,
5048 DWORD cbBuf, LPDWORD pcbNeeded,
5049 BOOL unicode)
Huw D M Daviese39b6761999-05-17 16:20:51 +00005050{
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005051 LPCWSTR name;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005052 WCHAR DriverName[100];
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005053 DWORD ret, type, size, needed = 0;
Huw D M Davies450270b1999-07-10 11:58:50 +00005054 LPBYTE ptr = NULL;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005055 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005056 const printenv_t * env;
Vincent Béron9a624912002-05-31 23:06:46 +00005057
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005058 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005059 Level,pDriverInfo,cbBuf, pcbNeeded);
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005060
Ulrich Czekalla6a80c8a2000-02-25 21:38:17 +00005061
Huw Daviesdf9c4342005-07-05 11:00:09 +00005062 if (!(name = get_opened_printer_name(hPrinter))) {
5063 SetLastError(ERROR_INVALID_HANDLE);
5064 return FALSE;
5065 }
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005066
Detlef Riekenberga2daf752007-07-26 23:14:55 +02005067 if (Level < 1 || Level == 7 || Level > 8) {
Huw D M Davies450270b1999-07-10 11:58:50 +00005068 SetLastError(ERROR_INVALID_LEVEL);
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005069 return FALSE;
Huw D M Davies450270b1999-07-10 11:58:50 +00005070 }
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005071
5072 env = validate_envW(pEnvironment);
5073 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5074
Detlef Riekenberg358ce062006-05-21 14:35:29 +02005075 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
Huw D M Davies450270b1999-07-10 11:58:50 +00005076 ERROR_SUCCESS) {
5077 ERR("Can't create Printers key\n");
5078 return FALSE;
5079 }
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005080 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
Huw D M Davies450270b1999-07-10 11:58:50 +00005081 != ERROR_SUCCESS) {
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005082 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
Huw D M Davies450270b1999-07-10 11:58:50 +00005083 RegCloseKey(hkeyPrinters);
5084 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
5085 return FALSE;
5086 }
5087 size = sizeof(DriverName);
Gerard Patel14c94292001-10-28 21:16:38 +00005088 DriverName[0] = 0;
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005089 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5090 (LPBYTE)DriverName, &size);
Huw D M Davies450270b1999-07-10 11:58:50 +00005091 RegCloseKey(hkeyPrinter);
5092 RegCloseKey(hkeyPrinters);
5093 if(ret != ERROR_SUCCESS) {
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005094 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
Huw D M Davies450270b1999-07-10 11:58:50 +00005095 return FALSE;
5096 }
Stefan Leichterca1661c2000-11-06 05:26:00 +00005097
5098 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5099 if(!hkeyDrivers) {
Huw D M Davies450270b1999-07-10 11:58:50 +00005100 ERR("Can't create Drivers key\n");
5101 return FALSE;
5102 }
Huw D M Davies450270b1999-07-10 11:58:50 +00005103
Detlef Riekenberga2daf752007-07-26 23:14:55 +02005104 size = di_sizeof[Level];
5105 if ((size <= cbBuf) && pDriverInfo)
Huw D M Davies450270b1999-07-10 11:58:50 +00005106 ptr = pDriverInfo + size;
Huw D M Davies450270b1999-07-10 11:58:50 +00005107
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005108 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
Detlef Riekenberga2daf752007-07-26 23:14:55 +02005109 env, Level, pDriverInfo, ptr,
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005110 (cbBuf < size) ? 0 : cbBuf - size,
5111 &needed, unicode)) {
5112 RegCloseKey(hkeyDrivers);
5113 return FALSE;
Huw D M Davies450270b1999-07-10 11:58:50 +00005114 }
Huw D M Davies450270b1999-07-10 11:58:50 +00005115
Huw D M Davies450270b1999-07-10 11:58:50 +00005116 RegCloseKey(hkeyDrivers);
5117
Stefan Leichtera2053ab2000-11-12 03:39:53 +00005118 if(pcbNeeded) *pcbNeeded = size + needed;
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005119 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005120 if(cbBuf >= needed) return TRUE;
Huw D M Davies450270b1999-07-10 11:58:50 +00005121 SetLastError(ERROR_INSUFFICIENT_BUFFER);
Huw D M Daviese39b6761999-05-17 16:20:51 +00005122 return FALSE;
5123}
5124
5125/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005126 * GetPrinterDriverA [WINSPOOL.@]
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005127 */
5128BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5129 DWORD Level, LPBYTE pDriverInfo,
5130 DWORD cbBuf, LPDWORD pcbNeeded)
5131{
5132 BOOL ret;
Matthew Davison60009b92003-01-23 23:07:38 +00005133 UNICODE_STRING pEnvW;
Duane Clark0987ae02003-02-12 01:19:25 +00005134 PWSTR pwstrEnvW;
5135
5136 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5137 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005138 cbBuf, pcbNeeded, FALSE);
Matthew Davison60009b92003-01-23 23:07:38 +00005139 RtlFreeUnicodeString(&pEnvW);
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005140 return ret;
5141}
5142/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005143 * GetPrinterDriverW [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00005144 */
5145BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
Vincent Béron9a624912002-05-31 23:06:46 +00005146 DWORD Level, LPBYTE pDriverInfo,
Huw D M Daviese39b6761999-05-17 16:20:51 +00005147 DWORD cbBuf, LPDWORD pcbNeeded)
5148{
Huw D M Davies7aaabc32000-05-25 23:02:46 +00005149 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5150 pDriverInfo, cbBuf, pcbNeeded, TRUE);
Huw D M Daviese39b6761999-05-17 16:20:51 +00005151}
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005152
5153/*****************************************************************************
Stefan Leichterfacaee42003-01-03 03:04:46 +00005154 * GetPrinterDriverDirectoryW [WINSPOOL.@]
Detlef Riekenbergf1522442005-11-28 17:29:38 +01005155 *
5156 * Return the PATH for the Printer-Drivers (UNICODE)
5157 *
5158 * PARAMS
5159 * pName [I] Servername (NT only) or NULL (local Computer)
5160 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5161 * Level [I] Structure-Level (must be 1)
5162 * pDriverDirectory [O] PTR to Buffer that receives the Result
5163 * cbBuf [I] Size of Buffer at pDriverDirectory
5164 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5165 * required for pDriverDirectory
5166 *
5167 * RETURNS
5168 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5169 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
Francois Gouget5127dc92005-12-02 16:15:09 +01005170 * if cbBuf is too small
Detlef Riekenbergf1522442005-11-28 17:29:38 +01005171 *
5172 * Native Values returned in pDriverDirectory on Success:
5173 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5174 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5175 *| win9x(Windows 4.0): "%winsysdir%"
5176 *
5177 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5178 *
5179 * FIXME
Detlef Riekenberg366f4522006-02-01 12:32:10 +01005180 *- Only NULL or "" is supported for pName
Detlef Riekenbergf1522442005-11-28 17:29:38 +01005181 *
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005182 */
Stefan Leichterfacaee42003-01-03 03:04:46 +00005183BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005184 DWORD Level, LPBYTE pDriverDirectory,
5185 DWORD cbBuf, LPDWORD pcbNeeded)
5186{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005187 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
Stefan Leichterfacaee42003-01-03 03:04:46 +00005188 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
Vincent Béron9a624912002-05-31 23:06:46 +00005189
Detlef Riekenberg36130b42008-02-04 09:51:38 +01005190 if ((backend == NULL) && !load_backend()) return FALSE;
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +01005191
Detlef Riekenberg36130b42008-02-04 09:51:38 +01005192 if (Level != 1) {
5193 /* (Level != 1) is ignored in win9x */
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +01005194 SetLastError(ERROR_INVALID_LEVEL);
5195 return FALSE;
5196 }
Detlef Riekenberg36130b42008-02-04 09:51:38 +01005197 if (pcbNeeded == NULL) {
5198 /* (pcbNeeded == NULL) is ignored in win9x */
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +01005199 SetLastError(RPC_X_NULL_REF_POINTER);
5200 return FALSE;
5201 }
Detlef Riekenberg36130b42008-02-04 09:51:38 +01005202
5203 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5204 pDriverDirectory, cbBuf, pcbNeeded);
5205
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005206}
5207
5208
5209/*****************************************************************************
Stefan Leichterfacaee42003-01-03 03:04:46 +00005210 * GetPrinterDriverDirectoryA [WINSPOOL.@]
Detlef Riekenbergf1522442005-11-28 17:29:38 +01005211 *
5212 * Return the PATH for the Printer-Drivers (ANSI)
5213 *
5214 * See GetPrinterDriverDirectoryW.
5215 *
5216 * NOTES
5217 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5218 *
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005219 */
Stefan Leichterfacaee42003-01-03 03:04:46 +00005220BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005221 DWORD Level, LPBYTE pDriverDirectory,
5222 DWORD cbBuf, LPDWORD pcbNeeded)
5223{
Stefan Leichterfacaee42003-01-03 03:04:46 +00005224 UNICODE_STRING nameW, environmentW;
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005225 BOOL ret;
Stefan Leichterfacaee42003-01-03 03:04:46 +00005226 DWORD pcbNeededW;
5227 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5228 WCHAR *driverDirectoryW = NULL;
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005229
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005230 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +01005231 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5232
Stefan Leichterfacaee42003-01-03 03:04:46 +00005233 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5234
5235 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5236 else nameW.Buffer = NULL;
5237 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5238 else environmentW.Buffer = NULL;
5239
5240 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5241 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5242 if (ret) {
Stefan Leichter87808532003-01-15 00:51:16 +00005243 DWORD needed;
Detlef Riekenberg23ead2b2006-01-18 12:26:32 +01005244 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
Mike McCormack516a5772005-08-19 10:04:03 +00005245 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
Stefan Leichter7a78ca02003-01-08 19:52:25 +00005246 if(pcbNeeded)
Stefan Leichter87808532003-01-15 00:51:16 +00005247 *pcbNeeded = needed;
5248 ret = (needed <= cbBuf) ? TRUE : FALSE;
Stefan Leichterfacaee42003-01-03 03:04:46 +00005249 } else
Stefan Leichter7a78ca02003-01-08 19:52:25 +00005250 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
Stefan Leichterfacaee42003-01-03 03:04:46 +00005251
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005252 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
Stefan Leichterfacaee42003-01-03 03:04:46 +00005253
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00005254 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
Stefan Leichterfacaee42003-01-03 03:04:46 +00005255 RtlFreeUnicodeString(&environmentW);
5256 RtlFreeUnicodeString(&nameW);
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005257
5258 return ret;
5259}
5260
Huw D M Daviese39b6761999-05-17 16:20:51 +00005261/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005262 * AddPrinterDriverA [WINSPOOL.@]
Detlef Riekenbergb068ce52007-08-24 00:02:11 +02005263 *
5264 * See AddPrinterDriverW.
5265 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00005266 */
Huw D M Daviesee2d9d51999-05-22 18:53:56 +00005267BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
Huw D M Daviese39b6761999-05-17 16:20:51 +00005268{
Detlef Riekenbergb068ce52007-08-24 00:02:11 +02005269 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5270 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
Huw D M Daviese39b6761999-05-17 16:20:51 +00005271}
Hans Leidekker8facd462005-01-03 20:24:39 +00005272
Detlef Riekenbergb068ce52007-08-24 00:02:11 +02005273/******************************************************************************
5274 * AddPrinterDriverW (WINSPOOL.@)
5275 *
5276 * Install a Printer Driver
5277 *
5278 * PARAMS
5279 * pName [I] Servername or NULL (local Computer)
5280 * level [I] Level for the supplied DRIVER_INFO_*W struct
5281 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5282 *
5283 * RESULTS
5284 * Success: TRUE
5285 * Failure: FALSE
5286 *
Huw D M Daviese39b6761999-05-17 16:20:51 +00005287 */
Detlef Riekenbergb068ce52007-08-24 00:02:11 +02005288BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
Huw D M Daviese39b6761999-05-17 16:20:51 +00005289{
Detlef Riekenbergb068ce52007-08-24 00:02:11 +02005290 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5291 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
Huw D M Daviese39b6761999-05-17 16:20:51 +00005292}
5293
Hans Leidekker8facd462005-01-03 20:24:39 +00005294/*****************************************************************************
5295 * AddPrintProcessorA [WINSPOOL.@]
5296 */
5297BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5298 LPSTR pPrintProcessorName)
5299{
5300 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5301 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5302 return FALSE;
5303}
5304
5305/*****************************************************************************
5306 * AddPrintProcessorW [WINSPOOL.@]
5307 */
5308BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5309 LPWSTR pPrintProcessorName)
5310{
5311 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5312 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5313 return FALSE;
5314}
5315
5316/*****************************************************************************
5317 * AddPrintProvidorA [WINSPOOL.@]
5318 */
5319BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5320{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005321 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
Hans Leidekker8facd462005-01-03 20:24:39 +00005322 return FALSE;
5323}
5324
5325/*****************************************************************************
5326 * AddPrintProvidorW [WINSPOOL.@]
5327 */
5328BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5329{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005330 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
Hans Leidekker8facd462005-01-03 20:24:39 +00005331 return FALSE;
5332}
5333
5334/*****************************************************************************
5335 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5336 */
5337LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5338 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5339{
5340 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5341 pDevModeOutput, pDevModeInput);
5342 return 0;
5343}
5344
5345/*****************************************************************************
5346 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5347 */
5348LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5349 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5350{
5351 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5352 pDevModeOutput, pDevModeInput);
5353 return 0;
5354}
Huw D M Daviese39b6761999-05-17 16:20:51 +00005355
5356/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005357 * PrinterProperties [WINSPOOL.@]
Huw D M Daviese39b6761999-05-17 16:20:51 +00005358 *
5359 * Displays a dialog to set the properties of the printer.
5360 *
Vincent Béron9a624912002-05-31 23:06:46 +00005361 * RETURNS
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005362 * nonzero on success or zero on failure
Huw D M Daviese39b6761999-05-17 16:20:51 +00005363 *
5364 * BUGS
5365 * implemented as stub only
5366 */
Patrik Stridvall2b3aa612000-12-01 23:58:28 +00005367BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5368 HANDLE hPrinter /* [in] handle to printer object */
Huw D M Daviese39b6761999-05-17 16:20:51 +00005369){
Michael Stefaniucea335dd2002-10-22 00:47:33 +00005370 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
Huw D M Daviese39b6761999-05-17 16:20:51 +00005371 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5372 return FALSE;
5373}
5374
Huw D M Daviesbb140561999-07-23 19:23:49 +00005375/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005376 * EnumJobsA [WINSPOOL.@]
Huw D M Daviesbb140561999-07-23 19:23:49 +00005377 *
5378 */
5379BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5380 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5381 LPDWORD pcReturned)
5382{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005383 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
Marcus Meissnerf061f762002-11-12 02:22:24 +00005384 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5385 );
Huw D M Daviesbb140561999-07-23 19:23:49 +00005386 if(pcbNeeded) *pcbNeeded = 0;
5387 if(pcReturned) *pcReturned = 0;
Marcus Meissnerf061f762002-11-12 02:22:24 +00005388 return FALSE;
Huw D M Daviesbb140561999-07-23 19:23:49 +00005389}
Huw D M Daviese39b6761999-05-17 16:20:51 +00005390
Huw D M Daviesbb140561999-07-23 19:23:49 +00005391
5392/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005393 * EnumJobsW [WINSPOOL.@]
Huw D M Daviesbb140561999-07-23 19:23:49 +00005394 *
5395 */
5396BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5397 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5398 LPDWORD pcReturned)
5399{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005400 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
Marcus Meissnerf061f762002-11-12 02:22:24 +00005401 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5402 );
Huw D M Daviesbb140561999-07-23 19:23:49 +00005403 if(pcbNeeded) *pcbNeeded = 0;
5404 if(pcReturned) *pcReturned = 0;
Marcus Meissnerf061f762002-11-12 02:22:24 +00005405 return FALSE;
Huw D M Daviesbb140561999-07-23 19:23:49 +00005406}
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005407
5408/*****************************************************************************
5409 * WINSPOOL_EnumPrinterDrivers [internal]
5410 *
Vincent Béron9a624912002-05-31 23:06:46 +00005411 * Delivers information about all printer drivers installed on the
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005412 * localhost or a given server
5413 *
5414 * RETURNS
Alexandre Julliarde1635e92001-02-28 05:26:08 +00005415 * nonzero on success or zero on failure. If the buffer for the returned
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005416 * information is too small the function will return an error
5417 *
5418 * BUGS
5419 * - only implemented for localhost, foreign hosts will return an error
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005420 */
Vitaly Lipatovc9d78fc2007-02-18 13:51:09 +03005421static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005422 DWORD Level, LPBYTE pDriverInfo,
5423 DWORD cbBuf, LPDWORD pcbNeeded,
5424 LPDWORD pcReturned, BOOL unicode)
5425
5426{ HKEY hkeyDrivers;
5427 DWORD i, needed, number = 0, size = 0;
5428 WCHAR DriverNameW[255];
5429 PBYTE ptr;
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005430 const printenv_t * env;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005431
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005432 TRACE("%s,%s,%d,%p,%d,%d\n",
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005433 debugstr_w(pName), debugstr_w(pEnvironment),
5434 Level, pDriverInfo, cbBuf, unicode);
5435
5436 /* check for local drivers */
Detlef Riekenberg5de733e2006-05-20 18:39:20 +02005437 if((pName) && (pName[0])) {
5438 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5439 SetLastError(ERROR_ACCESS_DENIED);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005440 return FALSE;
5441 }
5442
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005443 env = validate_envW(pEnvironment);
5444 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5445
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005446 /* check input parameter */
Detlef Riekenberga2daf752007-07-26 23:14:55 +02005447 if ((Level < 1) || (Level == 7) || (Level > 8)) {
Mike McCormack1a10b1c2004-11-24 18:11:28 +00005448 SetLastError(ERROR_INVALID_LEVEL);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005449 return FALSE;
5450 }
5451
Detlef Riekenberg5c04d1f2007-08-10 10:47:36 +02005452 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5453 SetLastError(RPC_X_NULL_REF_POINTER);
5454 return FALSE;
5455 }
5456
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005457 /* initialize return values */
5458 if(pDriverInfo)
5459 memset( pDriverInfo, 0, cbBuf);
5460 *pcbNeeded = 0;
5461 *pcReturned = 0;
5462
Stefan Leichterca1661c2000-11-06 05:26:00 +00005463 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5464 if(!hkeyDrivers) {
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005465 ERR("Can't open Drivers key\n");
5466 return FALSE;
5467 }
5468
5469 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5470 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5471 RegCloseKey(hkeyDrivers);
5472 ERR("Can't query Drivers key\n");
5473 return FALSE;
5474 }
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005475 TRACE("Found %d Drivers\n", number);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005476
5477 /* get size of single struct
5478 * unicode and ascii structure have the same size
5479 */
Detlef Riekenberga2daf752007-07-26 23:14:55 +02005480 size = di_sizeof[Level];
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005481
5482 /* calculate required buffer size */
5483 *pcbNeeded = size * number;
5484
5485 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5486 i < number;
5487 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
Vitaly Lipatov914e78a2007-12-01 19:43:37 +03005488 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005489 != ERROR_SUCCESS) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005490 ERR("Can't enum key number %d\n", i);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005491 RegCloseKey(hkeyDrivers);
5492 return FALSE;
5493 }
5494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
Detlef Riekenberg92f843d2007-07-22 17:21:25 +02005495 env, Level, ptr,
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005496 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5497 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5498 &needed, unicode)) {
5499 RegCloseKey(hkeyDrivers);
5500 return FALSE;
5501 }
5502 (*pcbNeeded) += needed;
5503 }
5504
5505 RegCloseKey(hkeyDrivers);
5506
5507 if(cbBuf < *pcbNeeded){
5508 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5509 return FALSE;
5510 }
5511
Detlef Riekenberg7bb00b12005-09-13 10:32:33 +00005512 *pcReturned = number;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005513 return TRUE;
5514}
5515
5516/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005517 * EnumPrinterDriversW [WINSPOOL.@]
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005518 *
5519 * see function EnumPrinterDrivers for RETURNS, BUGS
5520 */
5521BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5522 LPBYTE pDriverInfo, DWORD cbBuf,
5523 LPDWORD pcbNeeded, LPDWORD pcReturned)
5524{
5525 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5526 cbBuf, pcbNeeded, pcReturned, TRUE);
5527}
5528
5529/*****************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005530 * EnumPrinterDriversA [WINSPOOL.@]
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005531 *
5532 * see function EnumPrinterDrivers for RETURNS, BUGS
5533 */
5534BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5535 LPBYTE pDriverInfo, DWORD cbBuf,
5536 LPDWORD pcbNeeded, LPDWORD pcReturned)
5537{ BOOL ret;
Matthew Davison60009b92003-01-23 23:07:38 +00005538 UNICODE_STRING pNameW, pEnvironmentW;
Duane Clark0987ae02003-02-12 01:19:25 +00005539 PWSTR pwstrNameW, pwstrEnvironmentW;
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005540
Duane Clark0987ae02003-02-12 01:19:25 +00005541 pwstrNameW = asciitounicode(&pNameW, pName);
5542 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005543
Duane Clark0987ae02003-02-12 01:19:25 +00005544 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
Matthew Davison60009b92003-01-23 23:07:38 +00005545 Level, pDriverInfo, cbBuf, pcbNeeded,
5546 pcReturned, FALSE);
Duane Clark0987ae02003-02-12 01:19:25 +00005547 RtlFreeUnicodeString(&pNameW);
5548 RtlFreeUnicodeString(&pEnvironmentW);
Stefan Leichter5cfe1772000-09-29 21:05:11 +00005549
5550 return ret;
5551}
Alexandre Julliard89b18a72000-11-28 22:33:46 +00005552
Alexandre Julliard89b18a72000-11-28 22:33:46 +00005553/******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00005554 * EnumPortsA (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01005555 *
5556 * See EnumPortsW.
5557 *
Alexandre Julliard89b18a72000-11-28 22:33:46 +00005558 */
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005559BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5560 LPDWORD pcbNeeded, LPDWORD pcReturned)
Alexandre Julliard89b18a72000-11-28 22:33:46 +00005561{
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005562 BOOL res;
5563 LPBYTE bufferW = NULL;
5564 LPWSTR nameW = NULL;
5565 DWORD needed = 0;
5566 DWORD numentries = 0;
5567 INT len;
Huw Davies686a9f92003-05-19 23:19:21 +00005568
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005569 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5570 cbBuf, pcbNeeded, pcReturned);
Huw Davies686a9f92003-05-19 23:19:21 +00005571
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005572 /* convert servername to unicode */
5573 if (pName) {
5574 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5575 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5576 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
Huw Davies686a9f92003-05-19 23:19:21 +00005577 }
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005578 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5579 needed = cbBuf * sizeof(WCHAR);
5580 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5581 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
Huw Davies686a9f92003-05-19 23:19:21 +00005582
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005583 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5584 if (pcbNeeded) needed = *pcbNeeded;
5585 /* HeapReAlloc return NULL, when bufferW was NULL */
5586 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5587 HeapAlloc(GetProcessHeap(), 0, needed);
Huw Davies686a9f92003-05-19 23:19:21 +00005588
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005589 /* Try again with the large Buffer */
5590 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
Huw Davies686a9f92003-05-19 23:19:21 +00005591 }
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005592 needed = pcbNeeded ? *pcbNeeded : 0;
5593 numentries = pcReturned ? *pcReturned : 0;
Huw Davies686a9f92003-05-19 23:19:21 +00005594
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005595 /*
5596 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5597 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5598 */
5599 if (res) {
Francois Gougetb0bde6b2007-01-18 11:35:50 +01005600 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005601 DWORD entrysize = 0;
5602 DWORD index;
5603 LPSTR ptr;
5604 LPPORT_INFO_2W pi2w;
5605 LPPORT_INFO_2A pi2a;
Huw Davies686a9f92003-05-19 23:19:21 +00005606
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005607 needed = 0;
5608 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
Huw Davies686a9f92003-05-19 23:19:21 +00005609
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005610 /* First pass: calculate the size for all Entries */
5611 pi2w = (LPPORT_INFO_2W) bufferW;
5612 pi2a = (LPPORT_INFO_2A) pPorts;
5613 index = 0;
5614 while (index < numentries) {
5615 index++;
5616 needed += entrysize; /* PORT_INFO_?A */
5617 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
Mike McCormackd71bc332004-10-18 19:38:57 +00005618
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005619 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5620 NULL, 0, NULL, NULL);
5621 if (Level > 1) {
5622 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5623 NULL, 0, NULL, NULL);
5624 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5625 NULL, 0, NULL, NULL);
Huw Davies686a9f92003-05-19 23:19:21 +00005626 }
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005627 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5628 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5629 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
Mike McCormackd71bc332004-10-18 19:38:57 +00005630 }
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005631
5632 /* check for errors and quit on failure */
5633 if (cbBuf < needed) {
5634 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5635 res = FALSE;
5636 goto cleanup;
5637 }
5638 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5639 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5640 cbBuf -= len ; /* free Bytes in the user-Buffer */
5641 pi2w = (LPPORT_INFO_2W) bufferW;
5642 pi2a = (LPPORT_INFO_2A) pPorts;
5643 index = 0;
5644 /* Second Pass: Fill the User Buffer (if we have one) */
5645 while ((index < numentries) && pPorts) {
5646 index++;
5647 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5648 pi2a->pPortName = ptr;
5649 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5650 ptr, cbBuf , NULL, NULL);
5651 ptr += len;
5652 cbBuf -= len;
5653 if (Level > 1) {
5654 pi2a->pMonitorName = ptr;
5655 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5656 ptr, cbBuf, NULL, NULL);
5657 ptr += len;
5658 cbBuf -= len;
5659
5660 pi2a->pDescription = ptr;
5661 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5662 ptr, cbBuf, NULL, NULL);
5663 ptr += len;
5664 cbBuf -= len;
5665
5666 pi2a->fPortType = pi2w->fPortType;
5667 pi2a->Reserved = 0; /* documented: "must be zero" */
5668
5669 }
5670 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5671 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5672 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5673 }
Huw Davies686a9f92003-05-19 23:19:21 +00005674 }
5675
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005676cleanup:
5677 if (pcbNeeded) *pcbNeeded = needed;
5678 if (pcReturned) *pcReturned = (res) ? numentries : 0;
Huw Davies686a9f92003-05-19 23:19:21 +00005679
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005680 HeapFree(GetProcessHeap(), 0, nameW);
5681 HeapFree(GetProcessHeap(), 0, bufferW);
Huw Davies686a9f92003-05-19 23:19:21 +00005682
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005683 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5684 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
Huw Davies686a9f92003-05-19 23:19:21 +00005685
Detlef Riekenbergecce2d82006-11-04 00:27:31 +01005686 return (res);
5687
Alexandre Julliard89b18a72000-11-28 22:33:46 +00005688}
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005689
Hans Leidekker8facd462005-01-03 20:24:39 +00005690/******************************************************************************
5691 * EnumPortsW (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01005692 *
5693 * Enumerate available Ports
5694 *
5695 * PARAMS
5696 * name [I] Servername or NULL (local Computer)
5697 * level [I] Structure-Level (1 or 2)
5698 * buffer [O] PTR to Buffer that receives the Result
5699 * bufsize [I] Size of Buffer at buffer
5700 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5701 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5702 *
5703 * RETURNS
5704 * Success: TRUE
5705 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5706 *
Hans Leidekker8facd462005-01-03 20:24:39 +00005707 */
Detlef Riekenberg412acde2006-11-04 00:27:16 +01005708
5709BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
Hans Leidekker8facd462005-01-03 20:24:39 +00005710{
Detlef Riekenberg412acde2006-11-04 00:27:16 +01005711 DWORD needed = 0;
5712 DWORD numentries = 0;
5713 BOOL res = FALSE;
5714
5715 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5716 cbBuf, pcbNeeded, pcReturned);
5717
5718 if (pName && (pName[0])) {
5719 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5720 SetLastError(ERROR_ACCESS_DENIED);
5721 goto emP_cleanup;
5722 }
5723
5724 /* Level is not checked in win9x */
5725 if (!Level || (Level > 2)) {
5726 WARN("level (%d) is ignored in win9x\n", Level);
5727 SetLastError(ERROR_INVALID_LEVEL);
5728 goto emP_cleanup;
5729 }
5730 if (!pcbNeeded) {
5731 SetLastError(RPC_X_NULL_REF_POINTER);
5732 goto emP_cleanup;
5733 }
5734
5735 EnterCriticalSection(&monitor_handles_cs);
5736 monitor_loadall();
5737
5738 /* Scan all local Ports */
5739 numentries = 0;
5740 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5741
5742 /* we calculated the needed buffersize. now do the error-checks */
5743 if (cbBuf < needed) {
5744 monitor_unloadall();
5745 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5746 goto emP_cleanup_cs;
5747 }
5748 else if (!pPorts || !pcReturned) {
5749 monitor_unloadall();
5750 SetLastError(RPC_X_NULL_REF_POINTER);
5751 goto emP_cleanup_cs;
5752 }
5753
5754 /* Fill the Buffer */
5755 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5756 res = TRUE;
5757 monitor_unloadall();
5758
5759emP_cleanup_cs:
5760 LeaveCriticalSection(&monitor_handles_cs);
5761
5762emP_cleanup:
5763 if (pcbNeeded) *pcbNeeded = needed;
5764 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5765
5766 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5767 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5768
5769 return (res);
Hans Leidekker8facd462005-01-03 20:24:39 +00005770}
Stefan Leichter03210d42004-03-07 03:46:54 +00005771
5772/******************************************************************************
5773 * GetDefaultPrinterW (WINSPOOL.@)
5774 *
5775 * FIXME
5776 * This function must read the value from data 'device' of key
5777 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5778 */
5779BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5780{
5781 BOOL retval = TRUE;
5782 DWORD insize, len;
5783 WCHAR *buffer, *ptr;
5784
5785 if (!namesize)
5786 {
5787 SetLastError(ERROR_INVALID_PARAMETER);
5788 return FALSE;
5789 }
5790
5791 /* make the buffer big enough for the stuff from the profile/registry,
5792 * the content must fit into the local buffer to compute the correct
Francois Gougetf5c9da62005-05-06 15:44:31 +00005793 * size even if the extern buffer is too small or not given.
Stefan Leichter03210d42004-03-07 03:46:54 +00005794 * (20 for ,driver,port) */
5795 insize = *namesize;
5796 len = max(100, (insize + 20));
5797 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5798
5799 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5800 {
5801 SetLastError (ERROR_FILE_NOT_FOUND);
5802 retval = FALSE;
5803 goto end;
5804 }
5805 TRACE("%s\n", debugstr_w(buffer));
5806
5807 if ((ptr = strchrW(buffer, ',')) == NULL)
5808 {
5809 SetLastError(ERROR_INVALID_NAME);
5810 retval = FALSE;
5811 goto end;
5812 }
5813
5814 *ptr = 0;
5815 *namesize = strlenW(buffer) + 1;
5816 if(!name || (*namesize > insize))
5817 {
5818 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5819 retval = FALSE;
5820 goto end;
5821 }
5822 strcpyW(name, buffer);
5823
5824end:
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00005825 HeapFree( GetProcessHeap(), 0, buffer);
Stefan Leichter03210d42004-03-07 03:46:54 +00005826 return retval;
5827}
5828
5829
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005830/******************************************************************************
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005831 * GetDefaultPrinterA (WINSPOOL.@)
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005832 */
5833BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5834{
Stefan Leichter03210d42004-03-07 03:46:54 +00005835 BOOL retval = TRUE;
5836 DWORD insize = 0;
5837 WCHAR *bufferW = NULL;
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005838
Stefan Leichter03210d42004-03-07 03:46:54 +00005839 if (!namesize)
5840 {
5841 SetLastError(ERROR_INVALID_PARAMETER);
5842 return FALSE;
5843 }
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005844
Stefan Leichter03210d42004-03-07 03:46:54 +00005845 if(name && *namesize) {
5846 insize = *namesize;
5847 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5848 }
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005849
Stefan Leichter03210d42004-03-07 03:46:54 +00005850 if(!GetDefaultPrinterW( bufferW, namesize)) {
5851 retval = FALSE;
5852 goto end;
5853 }
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005854
Stefan Leichter03210d42004-03-07 03:46:54 +00005855 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5856 NULL, NULL);
5857 if (!*namesize)
5858 {
5859 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5860 retval = FALSE;
5861 }
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005862 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005863
Stefan Leichter03210d42004-03-07 03:46:54 +00005864end:
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00005865 HeapFree( GetProcessHeap(), 0, bufferW);
Stefan Leichter03210d42004-03-07 03:46:54 +00005866 return retval;
Mark G. Adamsa0324f72002-01-22 00:49:24 +00005867}
5868
5869
5870/******************************************************************************
Detlef Riekenberge267ccf2006-02-20 11:51:04 +01005871 * SetDefaultPrinterW (WINSPOOL.204)
5872 *
5873 * Set the Name of the Default Printer
5874 *
5875 * PARAMS
5876 * pszPrinter [I] Name of the Printer or NULL
5877 *
5878 * RETURNS
5879 * Success: True
5880 * Failure: FALSE
5881 *
5882 * NOTES
5883 * When the Parameter is NULL or points to an Empty String and
5884 * a Default Printer was already present, then this Function changes nothing.
5885 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5886 * the First enumerated local Printer is used.
5887 *
5888 */
5889BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5890{
5891
5892 TRACE("(%s)\n", debugstr_w(pszPrinter));
5893
5894 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5895 return FALSE;
5896}
5897
5898/******************************************************************************
5899 * SetDefaultPrinterA (WINSPOOL.202)
5900 *
5901 * See SetDefaultPrinterW.
5902 *
5903 */
5904BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5905{
5906
5907 TRACE("(%s)\n", debugstr_a(pszPrinter));
5908
5909 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5910 return FALSE;
5911}
5912
5913
5914/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00005915 * SetPrinterDataExA (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005916 */
Alexandre Julliard4d626b02003-11-11 20:38:51 +00005917DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5918 LPCSTR pValueName, DWORD Type,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005919 LPBYTE pData, DWORD cbData)
5920{
5921 HKEY hkeyPrinter, hkeySubkey;
5922 DWORD ret;
5923
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005924 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005925 debugstr_a(pValueName), Type, pData, cbData);
5926
5927 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5928 != ERROR_SUCCESS)
5929 return ret;
5930
5931 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5932 != ERROR_SUCCESS) {
5933 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5934 RegCloseKey(hkeyPrinter);
5935 return ret;
5936 }
5937 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5938 RegCloseKey(hkeySubkey);
5939 RegCloseKey(hkeyPrinter);
5940 return ret;
5941}
5942
5943/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00005944 * SetPrinterDataExW (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005945 */
Alexandre Julliard4d626b02003-11-11 20:38:51 +00005946DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5947 LPCWSTR pValueName, DWORD Type,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005948 LPBYTE pData, DWORD cbData)
5949{
5950 HKEY hkeyPrinter, hkeySubkey;
5951 DWORD ret;
5952
Hans Leidekker61faa6b2006-10-13 11:51:23 +02005953 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005954 debugstr_w(pValueName), Type, pData, cbData);
5955
5956 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5957 != ERROR_SUCCESS)
5958 return ret;
5959
5960 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5961 != ERROR_SUCCESS) {
5962 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5963 RegCloseKey(hkeyPrinter);
5964 return ret;
5965 }
5966 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5967 RegCloseKey(hkeySubkey);
5968 RegCloseKey(hkeyPrinter);
5969 return ret;
5970}
5971
5972/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00005973 * SetPrinterDataA (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005974 */
5975DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5976 LPBYTE pData, DWORD cbData)
5977{
5978 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5979 pData, cbData);
5980}
5981
5982/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00005983 * SetPrinterDataW (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005984 */
5985DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5986 LPBYTE pData, DWORD cbData)
5987{
5988 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5989 pData, cbData);
5990}
5991
5992/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00005993 * GetPrinterDataExA (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005994 */
Alexandre Julliard4d626b02003-11-11 20:38:51 +00005995DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5996 LPCSTR pValueName, LPDWORD pType,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00005997 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5998{
5999 HKEY hkeyPrinter, hkeySubkey;
6000 DWORD ret;
6001
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006002 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006003 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
6004 pcbNeeded);
6005
6006 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6007 != ERROR_SUCCESS)
6008 return ret;
6009
6010 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6011 != ERROR_SUCCESS) {
6012 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
6013 RegCloseKey(hkeyPrinter);
6014 return ret;
6015 }
6016 *pcbNeeded = nSize;
6017 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6018 RegCloseKey(hkeySubkey);
6019 RegCloseKey(hkeyPrinter);
6020 return ret;
6021}
6022
6023/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00006024 * GetPrinterDataExW (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006025 */
Alexandre Julliard4d626b02003-11-11 20:38:51 +00006026DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6027 LPCWSTR pValueName, LPDWORD pType,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006028 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6029{
6030 HKEY hkeyPrinter, hkeySubkey;
6031 DWORD ret;
6032
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006033 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006034 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
6035 pcbNeeded);
6036
6037 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6038 != ERROR_SUCCESS)
6039 return ret;
6040
6041 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6042 != ERROR_SUCCESS) {
6043 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
6044 RegCloseKey(hkeyPrinter);
6045 return ret;
6046 }
6047 *pcbNeeded = nSize;
6048 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6049 RegCloseKey(hkeySubkey);
6050 RegCloseKey(hkeyPrinter);
6051 return ret;
6052}
6053
6054/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00006055 * GetPrinterDataA (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006056 */
6057DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6058 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6059{
6060 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6061 pData, nSize, pcbNeeded);
6062}
6063
6064/******************************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00006065 * GetPrinterDataW (WINSPOOL.@)
Huw D M Daviesd2b850e2001-02-12 01:26:47 +00006066 */
6067DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6068 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6069{
6070 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6071 pData, nSize, pcbNeeded);
6072}
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006073
6074/*******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00006075 * EnumPrinterDataExW [WINSPOOL.@]
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006076 */
6077DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6078 LPBYTE pEnumValues, DWORD cbEnumValues,
6079 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6080{
6081 HKEY hkPrinter, hkSubKey;
6082 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6083 cbValueNameLen, cbMaxValueLen, cbValueLen,
6084 cbBufSize, dwType;
6085 LPWSTR lpValueName;
6086 HANDLE hHeap;
6087 PBYTE lpValue;
6088 PPRINTER_ENUM_VALUESW ppev;
6089
Michael Stefaniucea335dd2002-10-22 00:47:33 +00006090 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006091
6092 if (pKeyName == NULL || *pKeyName == 0)
6093 return ERROR_INVALID_PARAMETER;
6094
6095 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6096 if (ret != ERROR_SUCCESS)
6097 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006098 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006099 hPrinter, ret);
6100 return ret;
6101 }
6102
6103 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6104 if (ret != ERROR_SUCCESS)
6105 {
6106 r = RegCloseKey (hkPrinter);
6107 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006108 WARN ("RegCloseKey returned %i\n", r);
6109 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006110 debugstr_w (pKeyName), ret);
6111 return ret;
6112 }
6113
6114 ret = RegCloseKey (hkPrinter);
6115 if (ret != ERROR_SUCCESS)
6116 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006117 ERR ("RegCloseKey returned %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006118 r = RegCloseKey (hkSubKey);
6119 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006120 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006121 return ret;
6122 }
6123
6124 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6125 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6126 if (ret != ERROR_SUCCESS)
6127 {
6128 r = RegCloseKey (hkSubKey);
6129 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006130 WARN ("RegCloseKey returned %i\n", r);
6131 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006132 return ret;
6133 }
6134
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006135 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6136 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006137
6138 if (cValues == 0) /* empty key */
6139 {
6140 r = RegCloseKey (hkSubKey);
6141 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006142 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006143 *pcbEnumValues = *pnEnumValues = 0;
6144 return ERROR_SUCCESS;
6145 }
6146
6147 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6148
6149 hHeap = GetProcessHeap ();
Francois Gouget9b0b1e02003-01-14 23:43:41 +00006150 if (hHeap == NULL)
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006151 {
6152 ERR ("GetProcessHeap failed\n");
6153 r = RegCloseKey (hkSubKey);
6154 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006155 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006156 return ERROR_OUTOFMEMORY;
6157 }
6158
6159 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6160 if (lpValueName == NULL)
6161 {
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02006162 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006163 r = RegCloseKey (hkSubKey);
6164 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006165 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006166 return ERROR_OUTOFMEMORY;
6167 }
6168
6169 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6170 if (lpValue == NULL)
6171 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006172 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006173 if (HeapFree (hHeap, 0, lpValueName) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006174 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006175 r = RegCloseKey (hkSubKey);
6176 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006177 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006178 return ERROR_OUTOFMEMORY;
6179 }
6180
6181 TRACE ("pass 1: calculating buffer required for all names and values\n");
6182
6183 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6184
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006185 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006186
6187 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6188 {
6189 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6190 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6191 NULL, NULL, lpValue, &cbValueLen);
6192 if (ret != ERROR_SUCCESS)
6193 {
6194 if (HeapFree (hHeap, 0, lpValue) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006195 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006196 if (HeapFree (hHeap, 0, lpValueName) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006197 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006198 r = RegCloseKey (hkSubKey);
6199 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006200 WARN ("RegCloseKey returned %i\n", r);
6201 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006202 return ret;
6203 }
6204
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02006205 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006206 debugstr_w (lpValueName), dwIndex,
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02006207 cbValueNameLen + 1, cbValueLen);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006208
6209 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6210 cbBufSize += cbValueLen;
6211 }
6212
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006213 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006214
6215 *pcbEnumValues = cbBufSize;
6216 *pnEnumValues = cValues;
6217
6218 if (cbEnumValues < cbBufSize) /* buffer too small */
6219 {
6220 if (HeapFree (hHeap, 0, lpValue) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006221 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006222 if (HeapFree (hHeap, 0, lpValueName) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006223 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006224 r = RegCloseKey (hkSubKey);
6225 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006226 WARN ("RegCloseKey returned %i\n", r);
6227 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006228 return ERROR_MORE_DATA;
6229 }
6230
6231 TRACE ("pass 2: copying all names and values to buffer\n");
6232
6233 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6234 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6235
6236 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6237 {
6238 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6239 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6240 NULL, &dwType, lpValue, &cbValueLen);
6241 if (ret != ERROR_SUCCESS)
6242 {
6243 if (HeapFree (hHeap, 0, lpValue) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006244 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006245 if (HeapFree (hHeap, 0, lpValueName) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006246 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006247 r = RegCloseKey (hkSubKey);
6248 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006249 WARN ("RegCloseKey returned %i\n", r);
6250 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006251 return ret;
6252 }
6253
6254 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6255 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6256 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6257 pEnumValues += cbValueNameLen;
6258
6259 /* return # of *bytes* (including trailing \0), not # of chars */
6260 ppev[dwIndex].cbValueName = cbValueNameLen;
6261
6262 ppev[dwIndex].dwType = dwType;
6263
6264 memcpy (pEnumValues, lpValue, cbValueLen);
6265 ppev[dwIndex].pData = pEnumValues;
6266 pEnumValues += cbValueLen;
6267
6268 ppev[dwIndex].cbData = cbValueLen;
6269
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006270 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006271 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6272 }
6273
6274 if (HeapFree (hHeap, 0, lpValue) == 0)
6275 {
6276 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006277 ERR ("HeapFree failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006278 if (HeapFree (hHeap, 0, lpValueName) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006279 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006280 r = RegCloseKey (hkSubKey);
6281 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006282 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006283 return ret;
6284 }
6285
6286 if (HeapFree (hHeap, 0, lpValueName) == 0)
6287 {
6288 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006289 ERR ("HeapFree failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006290 r = RegCloseKey (hkSubKey);
6291 if (r != ERROR_SUCCESS)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006292 WARN ("RegCloseKey returned %i\n", r);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006293 return ret;
6294 }
6295
6296 ret = RegCloseKey (hkSubKey);
6297 if (ret != ERROR_SUCCESS)
6298 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006299 ERR ("RegCloseKey returned %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006300 return ret;
6301 }
6302
6303 return ERROR_SUCCESS;
6304}
6305
6306/*******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00006307 * EnumPrinterDataExA [WINSPOOL.@]
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006308 *
6309 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6310 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6311 * what Windows 2000 SP1 does.
6312 *
6313 */
6314DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6315 LPBYTE pEnumValues, DWORD cbEnumValues,
6316 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6317{
6318 INT len;
6319 LPWSTR pKeyNameW;
6320 DWORD ret, dwIndex, dwBufSize;
6321 HANDLE hHeap;
6322 LPSTR pBuffer;
6323
Michael Stefaniucea335dd2002-10-22 00:47:33 +00006324 TRACE ("%p %s\n", hPrinter, pKeyName);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006325
6326 if (pKeyName == NULL || *pKeyName == 0)
6327 return ERROR_INVALID_PARAMETER;
6328
6329 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6330 if (len == 0)
6331 {
6332 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006333 ERR ("MultiByteToWideChar failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006334 return ret;
6335 }
6336
6337 hHeap = GetProcessHeap ();
Francois Gouget9b0b1e02003-01-14 23:43:41 +00006338 if (hHeap == NULL)
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006339 {
6340 ERR ("GetProcessHeap failed\n");
6341 return ERROR_OUTOFMEMORY;
6342 }
6343
6344 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6345 if (pKeyNameW == NULL)
6346 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006347 ERR ("Failed to allocate %i bytes from process heap\n",
Alexandre Julliardb0ea5772006-10-20 12:16:45 +02006348 (LONG)(len * sizeof (WCHAR)));
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006349 return ERROR_OUTOFMEMORY;
6350 }
6351
6352 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6353 {
6354 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006355 ERR ("MultiByteToWideChar failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006356 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006357 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006358 return ret;
6359 }
6360
6361 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6362 pcbEnumValues, pnEnumValues);
6363 if (ret != ERROR_SUCCESS)
6364 {
6365 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006366 WARN ("HeapFree failed with code %i\n", GetLastError ());
6367 TRACE ("EnumPrinterDataExW returned %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006368 return ret;
6369 }
6370
6371 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6372 {
6373 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006374 ERR ("HeapFree failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006375 return ret;
Vincent Béron9a624912002-05-31 23:06:46 +00006376 }
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006377
6378 if (*pnEnumValues == 0) /* empty key */
6379 return ERROR_SUCCESS;
6380
6381 dwBufSize = 0;
6382 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6383 {
6384 PPRINTER_ENUM_VALUESW ppev =
6385 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6386
6387 if (dwBufSize < ppev->cbValueName)
6388 dwBufSize = ppev->cbValueName;
6389
6390 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6391 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6392 dwBufSize = ppev->cbData;
6393 }
6394
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006395 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006396
6397 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6398 if (pBuffer == NULL)
6399 {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006400 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006401 return ERROR_OUTOFMEMORY;
6402 }
6403
6404 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6405 {
6406 PPRINTER_ENUM_VALUESW ppev =
6407 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6408
6409 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6410 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6411 NULL);
6412 if (len == 0)
6413 {
6414 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006415 ERR ("WideCharToMultiByte failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006416 if (HeapFree (hHeap, 0, pBuffer) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006417 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006418 return ret;
6419 }
6420
6421 memcpy (ppev->pValueName, pBuffer, len);
6422
6423 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6424
6425 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6426 ppev->dwType != REG_MULTI_SZ)
6427 continue;
6428
6429 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6430 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6431 if (len == 0)
6432 {
6433 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006434 ERR ("WideCharToMultiByte failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006435 if (HeapFree (hHeap, 0, pBuffer) == 0)
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006436 WARN ("HeapFree failed with code %i\n", GetLastError ());
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006437 return ret;
6438 }
6439
6440 memcpy (ppev->pData, pBuffer, len);
6441
6442 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6443 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6444 }
6445
6446 if (HeapFree (hHeap, 0, pBuffer) == 0)
6447 {
6448 ret = GetLastError ();
Hans Leidekker61faa6b2006-10-13 11:51:23 +02006449 ERR ("HeapFree failed with code %i\n", ret);
Ian Pilcherccfe6e92001-02-21 04:00:40 +00006450 return ret;
6451 }
6452
6453 return ERROR_SUCCESS;
6454}
Aric Stewart6d5cd452003-05-13 22:25:12 +00006455
6456/******************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006457 * AbortPrinter (WINSPOOL.@)
6458 */
6459BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6460{
6461 FIXME("(%p), stub!\n", hPrinter);
6462 return TRUE;
6463}
6464
6465/******************************************************************************
Aric Stewart6d5cd452003-05-13 22:25:12 +00006466 * AddPortA (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006467 *
6468 * See AddPortW.
6469 *
Aric Stewart6d5cd452003-05-13 22:25:12 +00006470 */
Hans Leidekker8facd462005-01-03 20:24:39 +00006471BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
Aric Stewart6d5cd452003-05-13 22:25:12 +00006472{
Detlef Riekenberg1f3c2892006-11-28 00:49:54 +01006473 LPWSTR nameW = NULL;
6474 LPWSTR monitorW = NULL;
6475 DWORD len;
6476 BOOL res;
6477
6478 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6479
6480 if (pName) {
6481 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6482 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6483 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6484 }
6485
6486 if (pMonitorName) {
6487 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6488 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6489 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6490 }
6491 res = AddPortW(nameW, hWnd, monitorW);
6492 HeapFree(GetProcessHeap(), 0, nameW);
6493 HeapFree(GetProcessHeap(), 0, monitorW);
6494 return res;
Hans Leidekker8facd462005-01-03 20:24:39 +00006495}
6496
6497/******************************************************************************
6498 * AddPortW (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006499 *
6500 * Add a Port for a specific Monitor
6501 *
6502 * PARAMS
6503 * pName [I] Servername or NULL (local Computer)
6504 * hWnd [I] Handle to parent Window for the Dialog-Box
6505 * pMonitorName [I] Name of the Monitor that manage the Port
6506 *
6507 * RETURNS
6508 * Success: TRUE
6509 * Failure: FALSE
6510 *
Hans Leidekker8facd462005-01-03 20:24:39 +00006511 */
6512BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6513{
Detlef Riekenberg03daa602006-11-28 00:49:06 +01006514 monitor_t * pm;
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006515 monitor_t * pui;
6516 DWORD res;
Detlef Riekenberg03daa602006-11-28 00:49:06 +01006517
6518 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6519
6520 if (pName && pName[0]) {
6521 SetLastError(ERROR_INVALID_PARAMETER);
6522 return FALSE;
6523 }
6524
6525 if (!pMonitorName) {
6526 SetLastError(RPC_X_NULL_REF_POINTER);
6527 return FALSE;
6528 }
6529
6530 /* an empty Monitorname is Invalid */
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006531 if (!pMonitorName[0]) {
6532 SetLastError(ERROR_NOT_SUPPORTED);
6533 return FALSE;
6534 }
Detlef Riekenberg03daa602006-11-28 00:49:06 +01006535
6536 pm = monitor_load(pMonitorName, NULL);
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006537 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6538 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6539 TRACE("got %d with %u\n", res, GetLastError());
6540 res = TRUE;
Detlef Riekenberg03daa602006-11-28 00:49:06 +01006541 }
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006542 else
6543 {
6544 pui = monitor_loadui(pm);
6545 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6546 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6547 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6548 TRACE("got %d with %u\n", res, GetLastError());
6549 res = TRUE;
6550 }
6551 else
6552 {
6553 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6554 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
Detlef Riekenberg03daa602006-11-28 00:49:06 +01006555
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006556 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6557 SetLastError(ERROR_NOT_SUPPORTED);
6558 res = FALSE;
6559 }
6560 monitor_unload(pui);
6561 }
Detlef Riekenberg5012fa02007-01-15 05:37:24 +01006562 monitor_unload(pm);
6563 TRACE("returning %d with %u\n", res, GetLastError());
6564 return res;
Aric Stewart6d5cd452003-05-13 22:25:12 +00006565}
Mike McCormack0f669e42003-08-12 18:54:26 +00006566
6567/******************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006568 * AddPortExA (WINSPOOL.@)
6569 *
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006570 * See AddPortExW.
6571 *
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006572 */
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006573BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006574{
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006575 PORT_INFO_2W pi2W;
6576 PORT_INFO_2A * pi2A;
6577 LPWSTR nameW = NULL;
6578 LPWSTR monitorW = NULL;
6579 DWORD len;
6580 BOOL res;
6581
6582 pi2A = (PORT_INFO_2A *) pBuffer;
6583
6584 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6585 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6586
6587 if ((level < 1) || (level > 2)) {
6588 SetLastError(ERROR_INVALID_LEVEL);
6589 return FALSE;
6590 }
6591
6592 if (!pi2A) {
6593 SetLastError(ERROR_INVALID_PARAMETER);
6594 return FALSE;
6595 }
6596
6597 if (pName) {
6598 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6599 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6600 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6601 }
6602
6603 if (pMonitorName) {
6604 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6605 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6606 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6607 }
6608
6609 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6610
6611 if (pi2A->pPortName) {
6612 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6613 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6614 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6615 }
6616
6617 if (level > 1) {
6618 if (pi2A->pMonitorName) {
6619 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6620 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6621 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6622 }
6623
6624 if (pi2A->pDescription) {
6625 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6626 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6627 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6628 }
6629 pi2W.fPortType = pi2A->fPortType;
6630 pi2W.Reserved = pi2A->Reserved;
6631 }
6632
6633 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6634
6635 HeapFree(GetProcessHeap(), 0, nameW);
6636 HeapFree(GetProcessHeap(), 0, monitorW);
6637 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6638 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6639 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6640 return res;
6641
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006642}
6643
6644/******************************************************************************
6645 * AddPortExW (WINSPOOL.@)
6646 *
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006647 * Add a Port for a specific Monitor, without presenting a user interface
6648 *
6649 * PARAMS
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006650 * pName [I] Servername or NULL (local Computer)
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006651 * level [I] Structure-Level (1 or 2) for pBuffer
6652 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6653 * pMonitorName [I] Name of the Monitor that manage the Port
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006654 *
6655 * RETURNS
6656 * Success: TRUE
6657 * Failure: FALSE
6658 *
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006659 */
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006660BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006661{
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006662 PORT_INFO_2W * pi2;
6663 monitor_t * pm;
6664 DWORD res = FALSE;
6665
6666 pi2 = (PORT_INFO_2W *) pBuffer;
6667
6668 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6669 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6670 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6671 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6672
6673
6674 if ((level < 1) || (level > 2)) {
6675 SetLastError(ERROR_INVALID_LEVEL);
6676 return FALSE;
6677 }
6678
Detlef Riekenberg4307f642007-06-18 00:58:49 +02006679 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006680 SetLastError(ERROR_INVALID_PARAMETER);
6681 return FALSE;
6682 }
6683
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006684 /* load the Monitor */
6685 pm = monitor_load(pMonitorName, NULL);
Detlef Riekenberg4307f642007-06-18 00:58:49 +02006686 if (!pm) {
6687 SetLastError(ERROR_INVALID_PARAMETER);
6688 return FALSE;
6689 }
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006690
6691 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6692 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6693 TRACE("got %u with %u\n", res, GetLastError());
6694 }
Detlef Riekenberg4307f642007-06-18 00:58:49 +02006695 else
6696 {
6697 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6698 }
Detlef Riekenberg0c717992007-06-04 00:23:55 +02006699 monitor_unload(pm);
6700 return res;
Hans Leidekker1e33aca2005-02-21 18:33:55 +00006701}
6702
6703/******************************************************************************
6704 * AddPrinterConnectionA (WINSPOOL.@)
6705 */
6706BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6707{
6708 FIXME("%s\n", debugstr_a(pName));
6709 return FALSE;
6710}
6711
6712/******************************************************************************
6713 * AddPrinterConnectionW (WINSPOOL.@)
6714 */
6715BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6716{
6717 FIXME("%s\n", debugstr_w(pName));
6718 return FALSE;
6719}
6720
6721/******************************************************************************
Detlef Riekenberg29444b42007-08-15 23:30:59 +02006722 * AddPrinterDriverExW (WINSPOOL.@)
6723 *
6724 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6725 *
6726 * PARAMS
6727 * pName [I] Servername or NULL (local Computer)
6728 * level [I] Level for the supplied DRIVER_INFO_*W struct
6729 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6730 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6731 *
6732 * RESULTS
6733 * Success: TRUE
6734 * Failure: FALSE
6735 *
Mike McCormack0f669e42003-08-12 18:54:26 +00006736 */
Detlef Riekenberg29444b42007-08-15 23:30:59 +02006737BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
Mike McCormack0f669e42003-08-12 18:54:26 +00006738{
Detlef Riekenberg29444b42007-08-15 23:30:59 +02006739 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6740
Detlef Riekenberg6ec7c2d2008-02-08 00:41:24 +01006741 if ((backend == NULL) && !load_backend()) return FALSE;
6742
Detlef Riekenberg29444b42007-08-15 23:30:59 +02006743 if (level < 2 || level == 5 || level == 7 || level > 8) {
6744 SetLastError(ERROR_INVALID_LEVEL);
6745 return FALSE;
6746 }
6747
6748 if (!pDriverInfo) {
6749 SetLastError(ERROR_INVALID_PARAMETER);
6750 return FALSE;
6751 }
6752
Detlef Riekenberg6ec7c2d2008-02-08 00:41:24 +01006753 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
Mike McCormack0f669e42003-08-12 18:54:26 +00006754}
6755
6756/******************************************************************************
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006757 * AddPrinterDriverExA (WINSPOOL.@)
6758 *
6759 * See AddPrinterDriverExW.
6760 *
Mike McCormack0f669e42003-08-12 18:54:26 +00006761 */
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006762BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
Mike McCormack0f669e42003-08-12 18:54:26 +00006763{
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006764 DRIVER_INFO_8A *diA;
6765 DRIVER_INFO_8W diW;
6766 LPWSTR nameW = NULL;
6767 DWORD lenA;
6768 DWORD len;
6769 DWORD res = FALSE;
6770
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006771 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6772
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006773 diA = (DRIVER_INFO_8A *) pDriverInfo;
6774 ZeroMemory(&diW, sizeof(diW));
6775
6776 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6777 SetLastError(ERROR_INVALID_LEVEL);
6778 return FALSE;
6779 }
6780
6781 if (diA == NULL) {
6782 SetLastError(ERROR_INVALID_PARAMETER);
6783 return FALSE;
6784 }
6785
6786 /* convert servername to unicode */
6787 if (pName) {
6788 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6789 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6790 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6791 }
6792
6793 /* common fields */
6794 diW.cVersion = diA->cVersion;
6795
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006796 if (diA->pName) {
6797 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6798 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6799 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6800 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006801
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006802 if (diA->pEnvironment) {
6803 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6804 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6805 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6806 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006807
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006808 if (diA->pDriverPath) {
6809 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6810 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6811 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6812 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006813
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006814 if (diA->pDataFile) {
6815 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6816 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6817 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6818 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006819
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006820 if (diA->pConfigFile) {
6821 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6822 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6823 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6824 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006825
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006826 if ((Level > 2) && diA->pDependentFiles) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006827 lenA = multi_sz_lenA(diA->pDependentFiles);
6828 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6829 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6830 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006831 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006832
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006833 if ((Level > 2) && diA->pMonitorName) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006834 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6835 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6836 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6837 }
6838
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006839 if ((Level > 3) && diA->pDefaultDataType) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006840 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6841 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6842 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006843 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006844
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006845 if ((Level > 3) && diA->pszzPreviousNames) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006846 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6847 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6848 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6849 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6850 }
6851
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006852 if ((Level > 5) && diA->pszMfgName) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006853 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6854 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6855 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006856 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006857
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006858 if ((Level > 5) && diA->pszOEMUrl) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006859 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6860 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6861 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006862 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006863
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006864 if ((Level > 5) && diA->pszHardwareID) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006865 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6866 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6867 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006868 }
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006869
Detlef Riekenberg9be4cc32007-08-22 23:41:44 +02006870 if ((Level > 5) && diA->pszProvider) {
Detlef Riekenberg4ff59a82007-08-16 05:18:08 +02006871 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6872 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6873 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6874 }
6875
6876 if (Level > 7) {
6877 FIXME("level %u is incomplete\n", Level);
6878 }
6879
6880 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6881 TRACE("got %u with %u\n", res, GetLastError());
6882 HeapFree(GetProcessHeap(), 0, nameW);
6883 HeapFree(GetProcessHeap(), 0, diW.pName);
6884 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6885 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6886 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6887 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6888 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6889 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6890 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6891 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6892 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6893 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6894 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6895 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6896
6897 TRACE("=> %u with %u\n", res, GetLastError());
6898 return res;
Mike McCormack0f669e42003-08-12 18:54:26 +00006899}
6900
6901/******************************************************************************
Hans Leidekker8facd462005-01-03 20:24:39 +00006902 * ConfigurePortA (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006903 *
6904 * See ConfigurePortW.
6905 *
Hans Leidekker8facd462005-01-03 20:24:39 +00006906 */
6907BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6908{
Detlef Riekenberg6d88e432006-11-09 00:04:11 +01006909 LPWSTR nameW = NULL;
6910 LPWSTR portW = NULL;
6911 INT len;
6912 DWORD res;
6913
6914 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6915
6916 /* convert servername to unicode */
6917 if (pName) {
6918 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6919 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6921 }
6922
6923 /* convert portname to unicode */
6924 if (pPortName) {
6925 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6926 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6927 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6928 }
6929
6930 res = ConfigurePortW(nameW, hWnd, portW);
6931 HeapFree(GetProcessHeap(), 0, nameW);
6932 HeapFree(GetProcessHeap(), 0, portW);
6933 return res;
Hans Leidekker8facd462005-01-03 20:24:39 +00006934}
6935
6936/******************************************************************************
6937 * ConfigurePortW (WINSPOOL.@)
Detlef Riekenberg1395d142005-12-06 10:57:01 +01006938 *
6939 * Display the Configuration-Dialog for a specific Port
6940 *
6941 * PARAMS
6942 * pName [I] Servername or NULL (local Computer)
6943 * hWnd [I] Handle to parent Window for the Dialog-Box
6944 * pPortName [I] Name of the Port, that should be configured
6945 *
6946 * RETURNS
6947 * Success: TRUE
6948 * Failure: FALSE
6949 *
Hans Leidekker8facd462005-01-03 20:24:39 +00006950 */
6951BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6952{
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006953 monitor_t * pm;
Detlef Riekenberge576b092007-01-11 13:10:37 +01006954 monitor_t * pui;
6955 DWORD res;
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006956
6957 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6958
6959 if (pName && pName[0]) {
6960 SetLastError(ERROR_INVALID_PARAMETER);
6961 return FALSE;
6962 }
6963
6964 if (!pPortName) {
6965 SetLastError(RPC_X_NULL_REF_POINTER);
6966 return FALSE;
6967 }
6968
6969 /* an empty Portname is Invalid, but can popup a Dialog */
Detlef Riekenberge576b092007-01-11 13:10:37 +01006970 if (!pPortName[0]) {
6971 SetLastError(ERROR_NOT_SUPPORTED);
6972 return FALSE;
6973 }
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006974
6975 pm = monitor_load_by_port(pPortName);
Detlef Riekenberge576b092007-01-11 13:10:37 +01006976 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6977 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6978 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6979 TRACE("got %d with %u\n", res, GetLastError());
6980 }
6981 else
6982 {
6983 pui = monitor_loadui(pm);
6984 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6985 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6986 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6987 TRACE("got %d with %u\n", res, GetLastError());
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006988 }
6989 else
6990 {
Detlef Riekenberge576b092007-01-11 13:10:37 +01006991 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6992 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6993
6994 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6995 SetLastError(ERROR_NOT_SUPPORTED);
6996 res = FALSE;
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006997 }
Detlef Riekenberge576b092007-01-11 13:10:37 +01006998 monitor_unload(pui);
Detlef Riekenberga44e0ac2006-11-09 00:04:08 +01006999 }
7000 monitor_unload(pm);
7001
Detlef Riekenberge576b092007-01-11 13:10:37 +01007002 TRACE("returning %d with %u\n", res, GetLastError());
7003 return res;
Hans Leidekker8facd462005-01-03 20:24:39 +00007004}
7005
7006/******************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007007 * ConnectToPrinterDlg (WINSPOOL.@)
7008 */
7009HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7010{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007011 FIXME("%p %x\n", hWnd, Flags);
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007012 return NULL;
7013}
7014
7015/******************************************************************************
7016 * DeletePrinterConnectionA (WINSPOOL.@)
7017 */
7018BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7019{
7020 FIXME("%s\n", debugstr_a(pName));
7021 return TRUE;
7022}
7023
7024/******************************************************************************
7025 * DeletePrinterConnectionW (WINSPOOL.@)
7026 */
7027BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7028{
7029 FIXME("%s\n", debugstr_w(pName));
7030 return TRUE;
7031}
7032
7033/******************************************************************************
Mike McCormack0f669e42003-08-12 18:54:26 +00007034 * DeletePrinterDriverExW (WINSPOOL.@)
7035 */
7036BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7037 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7038{
Huw Davies388fd472006-11-07 12:27:09 +00007039 HKEY hkey_drivers;
7040 BOOL ret = FALSE;
7041
7042 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
Mike McCormack0f669e42003-08-12 18:54:26 +00007043 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
Huw Davies388fd472006-11-07 12:27:09 +00007044
7045 if(pName && pName[0])
7046 {
7047 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7048 SetLastError(ERROR_INVALID_PARAMETER);
7049 return FALSE;
7050 }
7051
7052 if(dwDeleteFlag)
7053 {
7054 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7055 SetLastError(ERROR_INVALID_PARAMETER);
7056 return FALSE;
7057 }
7058
7059 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
7060
7061 if(!hkey_drivers)
7062 {
7063 ERR("Can't open drivers key\n");
7064 return FALSE;
7065 }
7066
Stefan Leichter06b64a12007-06-05 18:47:17 +02007067 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
Huw Davies388fd472006-11-07 12:27:09 +00007068 ret = TRUE;
7069
7070 RegCloseKey(hkey_drivers);
7071
7072 return ret;
Mike McCormack0f669e42003-08-12 18:54:26 +00007073}
7074
7075/******************************************************************************
7076 * DeletePrinterDriverExA (WINSPOOL.@)
7077 */
7078BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7079 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7080{
Huw Davies7ce85a82006-11-07 12:06:04 +00007081 UNICODE_STRING NameW, EnvW, DriverW;
7082 BOOL ret;
7083
7084 asciitounicode(&NameW, pName);
7085 asciitounicode(&EnvW, pEnvironment);
7086 asciitounicode(&DriverW, pDriverName);
7087
7088 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7089
7090 RtlFreeUnicodeString(&DriverW);
7091 RtlFreeUnicodeString(&EnvW);
7092 RtlFreeUnicodeString(&NameW);
7093
7094 return ret;
Mike McCormack0f669e42003-08-12 18:54:26 +00007095}
7096
7097/******************************************************************************
7098 * DeletePrinterDataExW (WINSPOOL.@)
7099 */
7100DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7101 LPCWSTR pValueName)
7102{
7103 FIXME("%p %s %s\n", hPrinter,
7104 debugstr_w(pKeyName), debugstr_w(pValueName));
7105 return ERROR_INVALID_PARAMETER;
7106}
7107
7108/******************************************************************************
7109 * DeletePrinterDataExA (WINSPOOL.@)
7110 */
7111DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7112 LPCSTR pValueName)
7113{
7114 FIXME("%p %s %s\n", hPrinter,
7115 debugstr_a(pKeyName), debugstr_a(pValueName));
7116 return ERROR_INVALID_PARAMETER;
7117}
7118
Hans Leidekker8facd462005-01-03 20:24:39 +00007119/******************************************************************************
7120 * DeletePrintProcessorA (WINSPOOL.@)
7121 */
7122BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7123{
7124 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7125 debugstr_a(pPrintProcessorName));
7126 return TRUE;
7127}
7128
7129/******************************************************************************
7130 * DeletePrintProcessorW (WINSPOOL.@)
7131 */
7132BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7133{
7134 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7135 debugstr_w(pPrintProcessorName));
7136 return TRUE;
7137}
7138
7139/******************************************************************************
7140 * DeletePrintProvidorA (WINSPOOL.@)
7141 */
7142BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7143{
7144 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7145 debugstr_a(pPrintProviderName));
7146 return TRUE;
7147}
7148
7149/******************************************************************************
7150 * DeletePrintProvidorW (WINSPOOL.@)
7151 */
7152BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7153{
7154 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7155 debugstr_w(pPrintProviderName));
7156 return TRUE;
7157}
7158
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007159/******************************************************************************
7160 * EnumFormsA (WINSPOOL.@)
7161 */
7162BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7163 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7164{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007165 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
Detlef Riekenberg89ed2d92006-06-16 09:54:55 +02007166 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007167 return FALSE;
7168}
7169
7170/******************************************************************************
7171 * EnumFormsW (WINSPOOL.@)
7172 */
7173BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7174 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7175{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007176 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
Detlef Riekenberg89ed2d92006-06-16 09:54:55 +02007177 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007178 return FALSE;
7179}
7180
Steven Edwards86b30562004-03-17 01:42:46 +00007181/*****************************************************************************
7182 * EnumMonitorsA [WINSPOOL.@]
7183 *
Detlef Riekenberga5219472005-12-06 11:33:52 +01007184 * See EnumMonitorsW.
7185 *
Steven Edwards86b30562004-03-17 01:42:46 +00007186 */
7187BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7188 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7189{
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007190 BOOL res;
7191 LPBYTE bufferW = NULL;
7192 LPWSTR nameW = NULL;
7193 DWORD needed = 0;
7194 DWORD numentries = 0;
7195 INT len;
7196
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007197 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
Steven Edwards86b30562004-03-17 01:42:46 +00007198 cbBuf, pcbNeeded, pcReturned);
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007199
7200 /* convert servername to unicode */
7201 if (pName) {
7202 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7203 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7204 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7205 }
7206 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7207 needed = cbBuf * sizeof(WCHAR);
7208 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7209 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7210
7211 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7212 if (pcbNeeded) needed = *pcbNeeded;
7213 /* HeapReAlloc return NULL, when bufferW was NULL */
7214 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7215 HeapAlloc(GetProcessHeap(), 0, needed);
7216
7217 /* Try again with the large Buffer */
7218 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7219 }
7220 numentries = pcReturned ? *pcReturned : 0;
7221 needed = 0;
7222 /*
7223 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7224 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7225 */
7226 if (res) {
Francois Gougetb0bde6b2007-01-18 11:35:50 +01007227 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007228 DWORD entrysize = 0;
7229 DWORD index;
7230 LPSTR ptr;
7231 LPMONITOR_INFO_2W mi2w;
7232 LPMONITOR_INFO_2A mi2a;
7233
7234 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7235 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7236
7237 /* First pass: calculate the size for all Entries */
7238 mi2w = (LPMONITOR_INFO_2W) bufferW;
7239 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7240 index = 0;
7241 while (index < numentries) {
7242 index++;
7243 needed += entrysize; /* MONITOR_INFO_?A */
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007244 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007245
7246 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7247 NULL, 0, NULL, NULL);
7248 if (Level > 1) {
7249 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7250 NULL, 0, NULL, NULL);
7251 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7252 NULL, 0, NULL, NULL);
7253 }
7254 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7255 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7256 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7257 }
7258
7259 /* check for errors and quit on failure */
7260 if (cbBuf < needed) {
7261 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7262 res = FALSE;
7263 goto emA_cleanup;
7264 }
7265 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7266 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7267 cbBuf -= len ; /* free Bytes in the user-Buffer */
7268 mi2w = (LPMONITOR_INFO_2W) bufferW;
7269 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7270 index = 0;
7271 /* Second Pass: Fill the User Buffer (if we have one) */
7272 while ((index < numentries) && pMonitors) {
7273 index++;
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007274 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007275 mi2a->pName = ptr;
7276 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7277 ptr, cbBuf , NULL, NULL);
7278 ptr += len;
7279 cbBuf -= len;
7280 if (Level > 1) {
7281 mi2a->pEnvironment = ptr;
7282 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7283 ptr, cbBuf, NULL, NULL);
7284 ptr += len;
7285 cbBuf -= len;
7286
7287 mi2a->pDLLName = ptr;
7288 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7289 ptr, cbBuf, NULL, NULL);
7290 ptr += len;
7291 cbBuf -= len;
7292 }
7293 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7294 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7295 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7296 }
7297 }
7298emA_cleanup:
7299 if (pcbNeeded) *pcbNeeded = needed;
7300 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7301
7302 HeapFree(GetProcessHeap(), 0, nameW);
7303 HeapFree(GetProcessHeap(), 0, bufferW);
7304
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007305 TRACE("returning %d with %d (%d byte for %d entries)\n",
Detlef Riekenberg603f13e2006-03-31 14:32:02 +02007306 (res), GetLastError(), needed, numentries);
7307
7308 return (res);
7309
Steven Edwards86b30562004-03-17 01:42:46 +00007310}
7311
7312/*****************************************************************************
7313 * EnumMonitorsW [WINSPOOL.@]
7314 *
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007315 * Enumerate available Port-Monitors
Detlef Riekenberga5219472005-12-06 11:33:52 +01007316 *
7317 * PARAMS
7318 * pName [I] Servername or NULL (local Computer)
7319 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7320 * pMonitors [O] PTR to Buffer that receives the Result
7321 * cbBuf [I] Size of Buffer at pMonitors
7322 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7323 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7324 *
7325 * RETURNS
7326 * Success: TRUE
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007327 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
Detlef Riekenberga5219472005-12-06 11:33:52 +01007328 *
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007329 * NOTES
7330 * Windows reads the Registry once and cache the Results.
7331 *
7332 *| Language-Monitors are also installed in the same Registry-Location but
7333 *| they are filtered in Windows (not returned by EnumMonitors).
7334 *| We do no filtering to simplify our Code.
Detlef Riekenberga5219472005-12-06 11:33:52 +01007335 *
Steven Edwards86b30562004-03-17 01:42:46 +00007336 */
7337BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7338 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7339{
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007340 DWORD needed = 0;
7341 DWORD numentries = 0;
Detlef Riekenberg50b32da2006-04-08 19:17:06 +02007342 BOOL res = FALSE;
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007343
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007344 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
Steven Edwards86b30562004-03-17 01:42:46 +00007345 cbBuf, pcbNeeded, pcReturned);
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007346
7347 if (pName && (lstrlenW(pName))) {
7348 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7349 SetLastError(ERROR_ACCESS_DENIED);
7350 goto emW_cleanup;
7351 }
7352
7353 /* Level is not checked in win9x */
7354 if (!Level || (Level > 2)) {
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007355 WARN("level (%d) is ignored in win9x\n", Level);
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007356 SetLastError(ERROR_INVALID_LEVEL);
7357 goto emW_cleanup;
7358 }
7359 if (!pcbNeeded) {
7360 SetLastError(RPC_X_NULL_REF_POINTER);
7361 goto emW_cleanup;
7362 }
7363
7364 /* Scan all Monitor-Keys */
7365 numentries = 0;
7366 needed = get_local_monitors(Level, NULL, 0, &numentries);
7367
7368 /* we calculated the needed buffersize. now do the error-checks */
7369 if (cbBuf < needed) {
7370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7371 goto emW_cleanup;
7372 }
7373 else if (!pMonitors || !pcReturned) {
7374 SetLastError(RPC_X_NULL_REF_POINTER);
7375 goto emW_cleanup;
7376 }
7377
7378 /* fill the Buffer with the Monitor-Keys */
7379 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7380 res = TRUE;
7381
7382emW_cleanup:
7383 if (pcbNeeded) *pcbNeeded = needed;
7384 if (pcReturned) *pcReturned = numentries;
7385
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007386 TRACE("returning %d with %d (%d byte for %d entries)\n",
Detlef Riekenberg4b008052006-03-31 14:30:10 +02007387 res, GetLastError(), needed, numentries);
7388
7389 return (res);
Steven Edwards86b30562004-03-17 01:42:46 +00007390}
7391
Mike McCormack0f669e42003-08-12 18:54:26 +00007392/******************************************************************************
Detlef Riekenberg94a87842008-03-07 23:49:57 +01007393 * SpoolerInit (WINSPOOL.@)
7394 *
7395 * Initialize the Spooler
7396 *
7397 * RETURNS
7398 * Success: TRUE
7399 * Failure: FALSE
7400 *
7401 * NOTES
7402 * The function fails on windows, when the spooler service is not running
7403 *
7404 */
7405BOOL WINAPI SpoolerInit(void)
7406{
7407
7408 if ((backend == NULL) && !load_backend()) return FALSE;
7409 return TRUE;
7410}
7411
7412/******************************************************************************
Mike McCormack0f669e42003-08-12 18:54:26 +00007413 * XcvDataW (WINSPOOL.@)
7414 *
Detlef Riekenberge82d2282007-01-05 01:11:21 +01007415 * Execute commands in the Printmonitor DLL
7416 *
7417 * PARAMS
7418 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7419 * pszDataName [i] Name of the command to execute
7420 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7421 * cbInputData [i] Size in Bytes of Buffer at pInputData
7422 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7423 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7424 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7425 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7426 *
7427 * RETURNS
7428 * Success: TRUE
7429 * Failure: FALSE
7430 *
7431 * NOTES
7432 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7433 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7434 *
7435 * Minimal List of commands, that a Printmonitor DLL should support:
7436 *
7437 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7438 *| "AddPort" : Add a Port
7439 *| "DeletePort": Delete a Port
7440 *
7441 * Many Printmonitors support additional commands. Examples for localspl.dll:
7442 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7443 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7444 *
Mike McCormack0f669e42003-08-12 18:54:26 +00007445 */
7446BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7447 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7448 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7449{
Detlef Riekenberge82d2282007-01-05 01:11:21 +01007450 opened_printer_t *printer;
7451
7452 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
Mike McCormack0f669e42003-08-12 18:54:26 +00007453 pInputData, cbInputData, pOutputData,
7454 cbOutputData, pcbOutputNeeded, pdwStatus);
Detlef Riekenberge82d2282007-01-05 01:11:21 +01007455
7456 printer = get_opened_printer(hXcv);
7457 if (!printer || (!printer->hXcv)) {
7458 SetLastError(ERROR_INVALID_HANDLE);
7459 return FALSE;
7460 }
7461
Detlef Riekenbergb86a7642007-01-15 05:38:28 +01007462 if (!pcbOutputNeeded) {
7463 SetLastError(ERROR_INVALID_PARAMETER);
7464 return FALSE;
7465 }
7466
7467 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7468 SetLastError(RPC_X_NULL_REF_POINTER);
7469 return FALSE;
7470 }
7471
7472 *pcbOutputNeeded = 0;
7473
Detlef Riekenberge82d2282007-01-05 01:11:21 +01007474 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7475 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7476
7477 return TRUE;
Mike McCormack0f669e42003-08-12 18:54:26 +00007478}
Ulrich Czekalla601d4662004-10-29 21:27:38 +00007479
Hans Leidekker8facd462005-01-03 20:24:39 +00007480/*****************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007481 * EnumPrinterDataA [WINSPOOL.@]
7482 *
7483 */
7484DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7485 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7486 DWORD cbData, LPDWORD pcbData )
7487{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007488 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007489 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7490 return ERROR_NO_MORE_ITEMS;
7491}
7492
7493/*****************************************************************************
7494 * EnumPrinterDataW [WINSPOOL.@]
7495 *
7496 */
7497DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7498 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7499 DWORD cbData, LPDWORD pcbData )
7500{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007501 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007502 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7503 return ERROR_NO_MORE_ITEMS;
7504}
7505
7506/*****************************************************************************
Hans Leidekker8facd462005-01-03 20:24:39 +00007507 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7508 *
7509 */
7510BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7511 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7512 LPDWORD pcbNeeded, LPDWORD pcReturned)
7513{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007514 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
Hans Leidekker8facd462005-01-03 20:24:39 +00007515 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7516 pcbNeeded, pcReturned);
7517 return FALSE;
7518}
7519
7520/*****************************************************************************
7521 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7522 *
7523 */
7524BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7525 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7526 LPDWORD pcbNeeded, LPDWORD pcReturned)
7527{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007528 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
Hans Leidekker8facd462005-01-03 20:24:39 +00007529 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7530 pcbNeeded, pcReturned);
7531 return FALSE;
7532}
Ulrich Czekalla601d4662004-10-29 21:27:38 +00007533
7534/*****************************************************************************
7535 * EnumPrintProcessorsA [WINSPOOL.@]
7536 *
7537 */
7538BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7539 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7540{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007541 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
Ulrich Czekalla601d4662004-10-29 21:27:38 +00007542 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7543 return FALSE;
7544}
7545
7546/*****************************************************************************
7547 * EnumPrintProcessorsW [WINSPOOL.@]
7548 *
7549 */
7550BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7551 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7552{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007553 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
Ulrich Czekalla601d4662004-10-29 21:27:38 +00007554 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7555 cbBuf, pcbNeeded, pcbReturned);
7556 return FALSE;
7557}
Hans Leidekker8facd462005-01-03 20:24:39 +00007558
7559/*****************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007560 * ExtDeviceMode [WINSPOOL.@]
7561 *
7562 */
7563LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7564 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7565 DWORD fMode)
7566{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007567 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007568 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7569 debugstr_a(pProfile), fMode);
7570 return -1;
7571}
7572
7573/*****************************************************************************
7574 * FindClosePrinterChangeNotification [WINSPOOL.@]
7575 *
7576 */
7577BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7578{
7579 FIXME("Stub: %p\n", hChange);
7580 return TRUE;
7581}
7582
7583/*****************************************************************************
7584 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7585 *
7586 */
7587HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7588 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7589{
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007590 FIXME("Stub: %p %x %x %p\n",
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007591 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7592 return INVALID_HANDLE_VALUE;
7593}
7594
7595/*****************************************************************************
7596 * FindNextPrinterChangeNotification [WINSPOOL.@]
7597 *
7598 */
7599BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7600 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7601{
7602 FIXME("Stub: %p %p %p %p\n",
7603 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7604 return FALSE;
7605}
7606
7607/*****************************************************************************
7608 * FreePrinterNotifyInfo [WINSPOOL.@]
7609 *
7610 */
7611BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7612{
7613 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7614 return TRUE;
7615}
7616
7617/*****************************************************************************
Huw Davies03f36e62005-07-18 13:13:31 +00007618 * string_to_buf
7619 *
7620 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7621 * ansi depending on the unicode parameter.
7622 */
7623static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7624{
7625 if(!str)
7626 {
7627 *size = 0;
7628 return TRUE;
7629 }
7630
7631 if(unicode)
7632 {
7633 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7634 if(*size <= cb)
7635 {
7636 memcpy(ptr, str, *size);
7637 return TRUE;
7638 }
7639 return FALSE;
7640 }
7641 else
7642 {
7643 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7644 if(*size <= cb)
7645 {
Mike McCormack516a5772005-08-19 10:04:03 +00007646 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
Huw Davies03f36e62005-07-18 13:13:31 +00007647 return TRUE;
7648 }
7649 return FALSE;
7650 }
7651}
7652
7653/*****************************************************************************
7654 * get_job_info_1
7655 */
7656static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7657 LPDWORD pcbNeeded, BOOL unicode)
7658{
7659 DWORD size, left = cbBuf;
7660 BOOL space = (cbBuf > 0);
7661 LPBYTE ptr = buf;
7662
7663 *pcbNeeded = 0;
7664
7665 if(space)
7666 {
7667 ji1->JobId = job->job_id;
7668 }
7669
7670 string_to_buf(job->document_title, ptr, left, &size, unicode);
7671 if(space && size <= left)
7672 {
7673 ji1->pDocument = (LPWSTR)ptr;
7674 ptr += size;
7675 left -= size;
7676 }
7677 else
7678 space = FALSE;
7679 *pcbNeeded += size;
7680
7681 return space;
7682}
7683
7684/*****************************************************************************
7685 * get_job_info_2
7686 */
7687static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7688 LPDWORD pcbNeeded, BOOL unicode)
7689{
7690 DWORD size, left = cbBuf;
7691 BOOL space = (cbBuf > 0);
7692 LPBYTE ptr = buf;
7693
7694 *pcbNeeded = 0;
7695
7696 if(space)
7697 {
7698 ji2->JobId = job->job_id;
7699 }
7700
7701 string_to_buf(job->document_title, ptr, left, &size, unicode);
7702 if(space && size <= left)
7703 {
7704 ji2->pDocument = (LPWSTR)ptr;
7705 ptr += size;
7706 left -= size;
7707 }
7708 else
7709 space = FALSE;
7710 *pcbNeeded += size;
7711
7712 return space;
7713}
7714
7715/*****************************************************************************
7716 * get_job_info
7717 */
7718static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7719 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7720{
7721 BOOL ret = FALSE;
7722 DWORD needed = 0, size;
7723 job_t *job;
7724 LPBYTE ptr = pJob;
7725
Hans Leidekker61faa6b2006-10-13 11:51:23 +02007726 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
Huw Davies03f36e62005-07-18 13:13:31 +00007727
7728 EnterCriticalSection(&printer_handles_cs);
7729 job = get_job(hPrinter, JobId);
7730 if(!job)
7731 goto end;
7732
7733 switch(Level)
7734 {
7735 case 1:
7736 size = sizeof(JOB_INFO_1W);
7737 if(cbBuf >= size)
7738 {
7739 cbBuf -= size;
7740 ptr += size;
7741 memset(pJob, 0, size);
7742 }
7743 else
7744 cbBuf = 0;
7745 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7746 needed += size;
7747 break;
7748
7749 case 2:
7750 size = sizeof(JOB_INFO_2W);
7751 if(cbBuf >= size)
7752 {
7753 cbBuf -= size;
7754 ptr += size;
7755 memset(pJob, 0, size);
7756 }
7757 else
7758 cbBuf = 0;
7759 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7760 needed += size;
7761 break;
7762
7763 case 3:
7764 size = sizeof(JOB_INFO_3);
7765 if(cbBuf >= size)
7766 {
7767 cbBuf -= size;
7768 memset(pJob, 0, size);
7769 ret = TRUE;
7770 }
7771 else
7772 cbBuf = 0;
7773 needed = size;
7774 break;
7775
7776 default:
7777 SetLastError(ERROR_INVALID_LEVEL);
7778 goto end;
7779 }
7780 if(pcbNeeded)
7781 *pcbNeeded = needed;
7782end:
7783 LeaveCriticalSection(&printer_handles_cs);
7784 return ret;
7785}
7786
7787/*****************************************************************************
Hans Leidekker8facd462005-01-03 20:24:39 +00007788 * GetJobA [WINSPOOL.@]
7789 *
7790 */
7791BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
Huw Davies03f36e62005-07-18 13:13:31 +00007792 DWORD cbBuf, LPDWORD pcbNeeded)
Hans Leidekker8facd462005-01-03 20:24:39 +00007793{
Huw Davies03f36e62005-07-18 13:13:31 +00007794 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
Hans Leidekker8facd462005-01-03 20:24:39 +00007795}
7796
7797/*****************************************************************************
7798 * GetJobW [WINSPOOL.@]
7799 *
7800 */
7801BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
Huw Davies03f36e62005-07-18 13:13:31 +00007802 DWORD cbBuf, LPDWORD pcbNeeded)
Hans Leidekker8facd462005-01-03 20:24:39 +00007803{
Huw Davies03f36e62005-07-18 13:13:31 +00007804 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
Hans Leidekker8facd462005-01-03 20:24:39 +00007805}
Hans Leidekker1e33aca2005-02-21 18:33:55 +00007806
7807/*****************************************************************************
Huw Daviesc108d802005-07-10 17:39:01 +00007808 * schedule_lpr
7809 */
7810static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7811{
7812 char *unixname, *queue, *cmd;
7813 char fmt[] = "lpr -P%s %s";
7814 DWORD len;
7815
7816 if(!(unixname = wine_get_unix_file_name(filename)))
7817 return FALSE;
7818
7819 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7820 queue = HeapAlloc(GetProcessHeap(), 0, len);
7821 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7822
7823 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7824 sprintf(cmd, fmt, queue, unixname);
7825
7826 TRACE("printing with: %s\n", cmd);
7827 system(cmd);
7828
7829 HeapFree(GetProcessHeap(), 0, cmd);
7830 HeapFree(GetProcessHeap(), 0, queue);
7831 HeapFree(GetProcessHeap(), 0, unixname);
7832 return TRUE;
7833}
7834
7835/*****************************************************************************
Huw Davies18116de2005-07-11 13:21:48 +00007836 * schedule_cups
7837 */
Huw Davies183fcb52005-07-15 09:55:23 +00007838static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
Huw Davies18116de2005-07-11 13:21:48 +00007839{
Alexandre Julliard702d3552007-07-02 17:30:44 +02007840#ifdef SONAME_LIBCUPS
Huw Davies18116de2005-07-11 13:21:48 +00007841 if(pcupsPrintFile)
7842 {
Huw Davies183fcb52005-07-15 09:55:23 +00007843 char *unixname, *queue, *doc_titleA;
Huw Davies18116de2005-07-11 13:21:48 +00007844 DWORD len;
7845 BOOL ret;
7846
7847 if(!(unixname = wine_get_unix_file_name(filename)))
7848 return FALSE;
7849
7850 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7851 queue = HeapAlloc(GetProcessHeap(), 0, len);
7852 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7853
Huw Davies183fcb52005-07-15 09:55:23 +00007854 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7855 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7856 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7857
Huw Davies18116de2005-07-11 13:21:48 +00007858 TRACE("printing via cups\n");
Huw Davies183fcb52005-07-15 09:55:23 +00007859 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7860 HeapFree(GetProcessHeap(), 0, doc_titleA);
Huw Davies18116de2005-07-11 13:21:48 +00007861 HeapFree(GetProcessHeap(), 0, queue);
7862 HeapFree(GetProcessHeap(), 0, unixname);
7863 return ret;
7864 }
7865 else
7866#endif
7867 {
7868 return schedule_lpr(printer_name, filename);
7869 }
7870}
7871
Huw Daviese502d4d2005-07-12 17:01:44 +00007872INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7873{
7874 LPWSTR filename;
7875
7876 switch(msg)
7877 {
7878 case WM_INITDIALOG:
7879 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7880 return TRUE;
7881
7882 case WM_COMMAND:
7883 if(HIWORD(wparam) == BN_CLICKED)
7884 {
7885 if(LOWORD(wparam) == IDOK)
7886 {
7887 HANDLE hf;
Huw Davies3b77de92005-07-22 18:28:12 +00007888 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
Huw Daviese502d4d2005-07-12 17:01:44 +00007889 LPWSTR *output;
7890
7891 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7892 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
Huw Davies3b77de92005-07-22 18:28:12 +00007893
Huw Daviese502d4d2005-07-12 17:01:44 +00007894 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7895 {
7896 WCHAR caption[200], message[200];
7897 int mb_ret;
7898
7899 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7900 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7901 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7902 if(mb_ret == IDCANCEL)
7903 {
7904 HeapFree(GetProcessHeap(), 0, filename);
7905 return TRUE;
7906 }
7907 }
7908 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7909 if(hf == INVALID_HANDLE_VALUE)
7910 {
7911 WCHAR caption[200], message[200];
7912
7913 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7914 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7915 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7916 HeapFree(GetProcessHeap(), 0, filename);
7917 return TRUE;
7918 }
7919 CloseHandle(hf);
7920 DeleteFileW(filename);
7921 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7922 *output = filename;
7923 EndDialog(hwnd, IDOK);
7924 return TRUE;
7925 }
7926 if(LOWORD(wparam) == IDCANCEL)
7927 {
7928 EndDialog(hwnd, IDCANCEL);
7929 return TRUE;
7930 }
7931 }
7932 return FALSE;
7933 }
7934 return FALSE;
7935}
7936
7937/*****************************************************************************
Huw Davies3b77de92005-07-22 18:28:12 +00007938 * get_filename
7939 */
7940static BOOL get_filename(LPWSTR *filename)
7941{
7942 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7943 file_dlg_proc, (LPARAM)filename) == IDOK;
7944}
7945
7946/*****************************************************************************
Huw Daviese502d4d2005-07-12 17:01:44 +00007947 * schedule_file
7948 */
7949static BOOL schedule_file(LPCWSTR filename)
7950{
7951 LPWSTR output = NULL;
7952
Huw Davies3b77de92005-07-22 18:28:12 +00007953 if(get_filename(&output))
Huw Daviese502d4d2005-07-12 17:01:44 +00007954 {
7955 TRACE("copy to %s\n", debugstr_w(output));
7956 CopyFileW(filename, output, FALSE);
7957 HeapFree(GetProcessHeap(), 0, output);
7958 return TRUE;
7959 }
7960 return FALSE;
7961}
Huw Davies0a4681f2005-07-20 17:48:53 +00007962
7963/*****************************************************************************
7964 * schedule_pipe
7965 */
7966static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7967{
7968#ifdef HAVE_FORK
7969 char *unixname, *cmdA;
7970 DWORD len;
7971 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7972 BOOL ret = FALSE;
7973 char buf[1024];
7974
7975 if(!(unixname = wine_get_unix_file_name(filename)))
7976 return FALSE;
7977
7978 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7979 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7980 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7981
7982 TRACE("printing with: %s\n", cmdA);
7983
7984 if((file_fd = open(unixname, O_RDONLY)) == -1)
7985 goto end;
7986
7987 if (pipe(fds))
7988 {
7989 ERR("pipe() failed!\n");
7990 goto end;
7991 }
7992
7993 if (fork() == 0)
7994 {
7995 close(0);
7996 dup2(fds[0], 0);
7997 close(fds[1]);
7998
7999 /* reset signals that we previously set to SIG_IGN */
8000 signal(SIGPIPE, SIG_DFL);
8001 signal(SIGCHLD, SIG_DFL);
8002
Ken Thomases1f420962007-02-28 14:04:54 -06008003 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
8004 _exit(1);
Huw Davies0a4681f2005-07-20 17:48:53 +00008005 }
8006
Detlef Riekenberg50b32da2006-04-08 19:17:06 +02008007 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
Huw Davies0a4681f2005-07-20 17:48:53 +00008008 write(fds[1], buf, no_read);
8009
8010 ret = TRUE;
8011
8012end:
8013 if(file_fd != -1) close(file_fd);
8014 if(fds[0] != -1) close(fds[0]);
8015 if(fds[1] != -1) close(fds[1]);
8016
8017 HeapFree(GetProcessHeap(), 0, cmdA);
8018 HeapFree(GetProcessHeap(), 0, unixname);
8019 return ret;
8020#else
8021 return FALSE;
8022#endif
8023}
8024
8025/*****************************************************************************
8026 * schedule_unixfile
8027 */
8028static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8029{
8030 int in_fd, out_fd, no_read;
8031 char buf[1024];
8032 BOOL ret = FALSE;
8033 char *unixname, *outputA;
8034 DWORD len;
8035
8036 if(!(unixname = wine_get_unix_file_name(filename)))
8037 return FALSE;
8038
8039 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
8040 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8041 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
8042
8043 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8044 in_fd = open(unixname, O_RDONLY);
8045 if(out_fd == -1 || in_fd == -1)
8046 goto end;
8047
Detlef Riekenberg50b32da2006-04-08 19:17:06 +02008048 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
Huw Davies0a4681f2005-07-20 17:48:53 +00008049 write(out_fd, buf, no_read);
8050
8051 ret = TRUE;
8052end:
8053 if(in_fd != -1) close(in_fd);
8054 if(out_fd != -1) close(out_fd);
8055 HeapFree(GetProcessHeap(), 0, outputA);
8056 HeapFree(GetProcessHeap(), 0, unixname);
8057 return ret;
8058}
8059
Huw Davies18116de2005-07-11 13:21:48 +00008060/*****************************************************************************
Hans Leidekker1e33aca2005-02-21 18:33:55 +00008061 * ScheduleJob [WINSPOOL.@]
8062 *
8063 */
8064BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8065{
Huw Davies344090f2005-07-06 15:44:15 +00008066 opened_printer_t *printer;
8067 BOOL ret = FALSE;
8068 struct list *cursor, *cursor2;
8069
Hans Leidekker61faa6b2006-10-13 11:51:23 +02008070 TRACE("(%p, %x)\n", hPrinter, dwJobID);
Huw Davies344090f2005-07-06 15:44:15 +00008071 EnterCriticalSection(&printer_handles_cs);
8072 printer = get_opened_printer(hPrinter);
8073 if(!printer)
8074 goto end;
8075
Huw Davies48a52d02005-07-19 19:12:13 +00008076 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
Huw Davies344090f2005-07-06 15:44:15 +00008077 {
8078 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8079 HANDLE hf;
8080
8081 if(job->job_id != dwJobID) continue;
8082
8083 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8084 if(hf != INVALID_HANDLE_VALUE)
8085 {
Huw Daviesc108d802005-07-10 17:39:01 +00008086 PRINTER_INFO_5W *pi5;
8087 DWORD needed;
Huw Davies0a4681f2005-07-20 17:48:53 +00008088 HKEY hkey;
8089 WCHAR output[1024];
8090 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8091 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
Huw Daviesc108d802005-07-10 17:39:01 +00008092
8093 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8094 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8095 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
Hans Leidekker61faa6b2006-10-13 11:51:23 +02008096 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
Huw Daviesc108d802005-07-10 17:39:01 +00008097 debugstr_w(pi5->pPortName));
8098
Huw Davies0a4681f2005-07-20 17:48:53 +00008099 output[0] = 0;
8100
8101 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8102 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8103 {
8104 DWORD type, count = sizeof(output);
8105 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
8106 RegCloseKey(hkey);
8107 }
8108 if(output[0] == '|')
8109 {
8110 schedule_pipe(output + 1, job->filename);
8111 }
8112 else if(output[0])
8113 {
8114 schedule_unixfile(output, job->filename);
8115 }
8116 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
Huw Daviesc108d802005-07-10 17:39:01 +00008117 {
8118 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
8119 }
Huw Davies18116de2005-07-11 13:21:48 +00008120 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
8121 {
Huw Davies183fcb52005-07-15 09:55:23 +00008122 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
Huw Davies18116de2005-07-11 13:21:48 +00008123 }
Huw Daviese502d4d2005-07-12 17:01:44 +00008124 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
8125 {
8126 schedule_file(job->filename);
8127 }
Huw Daviesc108d802005-07-10 17:39:01 +00008128 else
8129 {
8130 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
8131 }
Huw Daviesc108d802005-07-10 17:39:01 +00008132 HeapFree(GetProcessHeap(), 0, pi5);
Huw Davies344090f2005-07-06 15:44:15 +00008133 CloseHandle(hf);
8134 DeleteFileW(job->filename);
8135 }
8136 list_remove(cursor);
Huw Davies1ed9bac2005-07-13 14:14:37 +00008137 HeapFree(GetProcessHeap(), 0, job->document_title);
Huw Davies344090f2005-07-06 15:44:15 +00008138 HeapFree(GetProcessHeap(), 0, job->filename);
8139 HeapFree(GetProcessHeap(), 0, job);
8140 ret = TRUE;
8141 break;
8142 }
8143end:
8144 LeaveCriticalSection(&printer_handles_cs);
8145 return ret;
Hans Leidekker1e33aca2005-02-21 18:33:55 +00008146}
Huw Davies3b77de92005-07-22 18:28:12 +00008147
8148/*****************************************************************************
8149 * StartDocDlgA [WINSPOOL.@]
8150 */
Hans Leidekkerab85b652006-10-06 14:25:54 +02008151LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
Huw Davies3b77de92005-07-22 18:28:12 +00008152{
8153 UNICODE_STRING usBuffer;
8154 DOCINFOW docW;
8155 LPWSTR retW;
Hans Leidekkerab85b652006-10-06 14:25:54 +02008156 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
Huw Davies3b77de92005-07-22 18:28:12 +00008157 LPSTR ret = NULL;
8158
8159 docW.cbSize = sizeof(docW);
Hans Leidekkerab85b652006-10-06 14:25:54 +02008160 if (doc->lpszDocName)
8161 {
8162 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8163 if (!(docW.lpszDocName = docnameW)) return NULL;
8164 }
8165 if (doc->lpszOutput)
8166 {
8167 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8168 if (!(docW.lpszOutput = outputW)) return NULL;
8169 }
8170 if (doc->lpszDatatype)
8171 {
8172 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8173 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8174 }
Huw Davies3b77de92005-07-22 18:28:12 +00008175 docW.fwType = doc->fwType;
8176
8177 retW = StartDocDlgW(hPrinter, &docW);
8178
8179 if(retW)
8180 {
8181 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8182 ret = HeapAlloc(GetProcessHeap(), 0, len);
8183 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8184 HeapFree(GetProcessHeap(), 0, retW);
8185 }
8186
Hans Leidekkerab85b652006-10-06 14:25:54 +02008187 HeapFree(GetProcessHeap(), 0, datatypeW);
8188 HeapFree(GetProcessHeap(), 0, outputW);
8189 HeapFree(GetProcessHeap(), 0, docnameW);
Huw Davies3b77de92005-07-22 18:28:12 +00008190
8191 return ret;
8192}
8193
8194/*****************************************************************************
8195 * StartDocDlgW [WINSPOOL.@]
8196 *
8197 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8198 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8199 * port is "FILE:". Also returns the full path if passed a relative path.
8200 *
8201 * The caller should free the returned string from the process heap.
8202 */
8203LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8204{
8205 LPWSTR ret = NULL;
8206 DWORD len, attr;
8207
8208 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8209 {
8210 PRINTER_INFO_5W *pi5;
8211 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8212 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8213 return NULL;
8214 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8215 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8216 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8217 {
8218 HeapFree(GetProcessHeap(), 0, pi5);
8219 return NULL;
8220 }
8221 HeapFree(GetProcessHeap(), 0, pi5);
8222 }
8223
8224 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8225 {
8226 LPWSTR name;
James Hawkins68406932007-01-11 03:19:58 -06008227
8228 if (get_filename(&name))
Huw Davies3b77de92005-07-22 18:28:12 +00008229 {
8230 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8231 {
8232 HeapFree(GetProcessHeap(), 0, name);
8233 return NULL;
8234 }
8235 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8236 GetFullPathNameW(name, len, ret, NULL);
8237 HeapFree(GetProcessHeap(), 0, name);
8238 }
8239 return ret;
8240 }
8241
8242 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8243 return NULL;
8244
8245 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8246 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8247
8248 attr = GetFileAttributesW(ret);
8249 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8250 {
8251 HeapFree(GetProcessHeap(), 0, ret);
8252 ret = NULL;
8253 }
8254 return ret;
8255}