1 /*
2 * WINSPOOL functions
3 *
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
10 *
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
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
59
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
64
65 /* ############################### */
66
67 static CRITICAL_SECTION monitor_handles_cs;
68 static 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 };
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
75
76
77 static CRITICAL_SECTION printer_handles_cs;
78 static 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 },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
83 };
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
85
86 /* ############################### */
87
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
98
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
103
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
108
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 HANDLE backend_printer;
113 jobqueue_t *queue;
114 started_doc_t *doc;
115 } opened_printer_t;
116
117 typedef struct {
118 struct list entry;
119 DWORD job_id;
120 WCHAR *filename;
121 WCHAR *document_title;
122 } job_t;
123
124
125 typedef struct {
126 LPCWSTR envname;
127 LPCWSTR subdir;
128 DWORD driverversion;
129 LPCWSTR versionregpath;
130 LPCWSTR versionsubdir;
131 } printenv_t;
132
133 /* ############################### */
134
135 static struct list monitor_handles = LIST_INIT( monitor_handles );
136 static monitor_t * pm_localport;
137
138 static opened_printer_t **printer_handles;
139 static UINT nb_printer_handles;
140 static LONG next_job_id = 1;
141
142 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
143 WORD fwCapability, LPSTR lpszOutput,
144 LPDEVMODEA lpdm );
145 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
146 LPSTR lpszDevice, LPSTR lpszPort,
147 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
148 DWORD fwMode );
149
150 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
151 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152 'c','o','n','t','r','o','l','\\',
153 'P','r','i','n','t','\\',
154 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
156
157 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
158 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159 'C','o','n','t','r','o','l','\\',
160 'P','r','i','n','t','\\',
161 'M','o','n','i','t','o','r','s','\\',0};
162
163 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
164 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165 'C','o','n','t','r','o','l','\\',
166 'P','r','i','n','t','\\',
167 'P','r','i','n','t','e','r','s',0};
168
169 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
170
171 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
172 'M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s',' ','N','T','\\',
174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'W','i','n','d','o','w','s',0};
176
177 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s',' ','N','T','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'D','e','v','i','c','e','s',0};
182
183 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
184 'M','i','c','r','o','s','o','f','t','\\',
185 'W','i','n','d','o','w','s',' ','N','T','\\',
186 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187 'P','o','r','t','s',0};
188
189 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s',' ','N','T','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'P','r','i','n','t','e','r','P','o','r','t','s',0};
194
195 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','',0};
197 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','',0};
200 static const WCHAR subdir_x64W[] = {'x','6','4',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','',0};
203 static const WCHAR Version0_SubdirW[] = {'\\','',0};
204 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
206
207 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
209
210 static const WCHAR backslashW[] = {'\\',0};
211 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
212 'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
225 static const WCHAR NameW[] = {'N','a','m','e',0};
226 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
236 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
237 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
238 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
239 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
240 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
241 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
242 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
243 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
244 static const WCHAR emptyStringW[] = {0};
245
246 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
247
248 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
249 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
250 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
251
252 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
253 'D','o','c','u','m','e','n','t',0};
254
255 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
256 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
257 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
258 0, sizeof(DRIVER_INFO_8W)};
259
260
261 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
262 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
263 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
264 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
265 sizeof(PRINTER_INFO_9W)};
266
267 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
268 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
269 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
270
271 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
272
273 /******************************************************************
274 * validate the user-supplied printing-environment [internal]
275 *
276 * PARAMS
277 * env [I] PTR to Environment-String or NULL
278 *
279 * RETURNS
280 * Failure: NULL
281 * Success: PTR to printenv_t
282 *
283 * NOTES
284 * An empty string is handled the same way as NULL.
285 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
286 *
287 */
288
289 static const printenv_t * validate_envW(LPCWSTR env)
290 {
291 const printenv_t *result = NULL;
292 unsigned int i;
293
294 TRACE("testing %s\n", debugstr_w(env));
295 if (env && env[0])
296 {
297 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
298 {
299 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
300 {
301 result = all_printenv[i];
302 break;
303 }
304 }
305
306 if (result == NULL) {
307 FIXME("unsupported Environment: %s\n", debugstr_w(env));
308 SetLastError(ERROR_INVALID_ENVIRONMENT);
309 }
310 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
311 }
312 else
313 {
314 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
315 }
316 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
317
318 return result;
319 }
320
321
322 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
323 if passed a NULL string. This returns NULLs to the result.
324 */
325 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
326 {
327 if ( (src) )
328 {
329 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
330 return usBufferPtr->Buffer;
331 }
332 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
333 return NULL;
334 }
335
336 static LPWSTR strdupW(LPCWSTR p)
337 {
338 LPWSTR ret;
339 DWORD len;
340
341 if(!p) return NULL;
342 len = (strlenW(p) + 1) * sizeof(WCHAR);
343 ret = HeapAlloc(GetProcessHeap(), 0, len);
344 memcpy(ret, p, len);
345 return ret;
346 }
347
348 static LPSTR strdupWtoA( LPCWSTR str )
349 {
350 LPSTR ret;
351 INT len;
352
353 if (!str) return NULL;
354 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
355 ret = HeapAlloc( GetProcessHeap(), 0, len );
356 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
357 return ret;
358 }
359
360 /******************************************************************
361 * Return the number of bytes for an multi_sz string.
362 * The result includes all \0s
363 * (specifically the extra \0, that is needed as multi_sz terminator).
364 */
365 #if 0
366 static int multi_sz_lenW(const WCHAR *str)
367 {
368 const WCHAR *ptr = str;
369 if(!str) return 0;
370 do
371 {
372 ptr += lstrlenW(ptr) + 1;
373 } while(*ptr);
374
375 return (ptr - str + 1) * sizeof(WCHAR);
376 }
377 #endif
378 /* ################################ */
379
380 static int multi_sz_lenA(const char *str)
381 {
382 const char *ptr = str;
383 if(!str) return 0;
384 do
385 {
386 ptr += lstrlenA(ptr) + 1;
387 } while(*ptr);
388
389 return ptr - str + 1;
390 }
391
392 static void
393 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
394 char qbuf[200];
395
396 /* If forcing, or no profile string entry for device yet, set the entry
397 *
398 * The always change entry if not WINEPS yet is discussable.
399 */
400 if (force ||
401 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
402 !strcmp(qbuf,"*") ||
403 !strstr(qbuf,"WINEPS.DRV")
404 ) {
405 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
406 HKEY hkey;
407
408 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
409 WriteProfileStringA("windows","device",buf);
410 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
411 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
412 RegCloseKey(hkey);
413 }
414 HeapFree(GetProcessHeap(),0,buf);
415 }
416 }
417
418 static BOOL add_printer_driver(const char *name)
419 {
420 DRIVER_INFO_3A di3a;
421
422 static char driver_9x[] = "wineps16.drv",
423 driver_nt[] = "wineps.drv",
424 env_9x[] = "Windows 4.0",
425 env_nt[] = "Windows NT x86",
426 data_file[] = "generic.ppd",
427 default_data_type[] = "RAW";
428
429 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
430 di3a.cVersion = 3;
431 di3a.pName = (char *)name;
432 di3a.pEnvironment = env_nt;
433 di3a.pDriverPath = driver_nt;
434 di3a.pDataFile = data_file;
435 di3a.pConfigFile = driver_nt;
436 di3a.pDefaultDataType = default_data_type;
437
438 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
439 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
440 {
441 di3a.cVersion = 0;
442 di3a.pEnvironment = env_9x;
443 di3a.pDriverPath = driver_9x;
444 di3a.pConfigFile = driver_9x;
445 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
446 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
447 {
448 return TRUE;
449 }
450 }
451 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
452 debugstr_a(di3a.pEnvironment), GetLastError());
453 return FALSE;
454 }
455
456 #ifdef SONAME_LIBCUPS
457 static typeof(cupsFreeDests) *pcupsFreeDests;
458 static typeof(cupsGetDests) *pcupsGetDests;
459 static typeof(cupsGetPPD) *pcupsGetPPD;
460 static typeof(cupsPrintFile) *pcupsPrintFile;
461 static void *cupshandle;
462
463 static BOOL CUPS_LoadPrinters(void)
464 {
465 int i, nrofdests;
466 BOOL hadprinter = FALSE, haddefault = FALSE;
467 cups_dest_t *dests;
468 PRINTER_INFO_2A pinfo2a;
469 char *port,*devline;
470 HKEY hkeyPrinter, hkeyPrinters, hkey;
471 char loaderror[256];
472
473 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
474 if (!cupshandle) {
475 TRACE("%s\n", loaderror);
476 return FALSE;
477 }
478 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
479
480 #define DYNCUPS(x) \
481 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
482 if (!p##x) return FALSE;
483
484 DYNCUPS(cupsFreeDests);
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
489
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
494 }
495
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* 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);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508 RegCloseKey(hkey);
509 }
510
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);
519
520 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 {
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 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
536 add_printer_driver(dests[i].name);
537
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 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;
549
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
553 }
554 }
555 HeapFree(GetProcessHeap(),0,port);
556
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
561 }
562 }
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 pcupsFreeDests(nrofdests, dests);
566 RegCloseKey(hkeyPrinters);
567 return hadprinter;
568 }
569 #endif
570
571 static BOOL
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573 PRINTER_INFO_2A pinfo2a;
574 char *e,*s,*name,*prettyname,*devname;
575 BOOL ret = FALSE, set_default = FALSE;
576 char *port = NULL, *devline,*env_default;
577 HKEY hkeyPrinter, hkeyPrinters, hkey;
578
579 while (isspace(*pent)) pent++;
580 s = strchr(pent,':');
581 if(s) *s='\0';
582 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
583 strcpy(name,pent);
584 if(s) {
585 *s=':';
586 pent = s;
587 } else
588 pent = "";
589
590 TRACE("name=%s entry=%s\n",name, pent);
591
592 if(ispunct(*name)) { /* a tc entry, not a real printer */
593 TRACE("skipping tc entry\n");
594 goto end;
595 }
596
597 if(strstr(pent,":server")) { /* server only version so skip */
598 TRACE("skipping server entry\n");
599 goto end;
600 }
601
602 /* Determine whether this is a postscript printer. */
603
604 ret = TRUE;
605 env_default = getenv("PRINTER");
606 prettyname = name;
607 /* Get longest name, usually the one at the right for later display. */
608 while((s=strchr(prettyname,'|'))) {
609 *s = '\0';
610 e = s;
611 while(isspace(*--e)) *e = '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname));
613 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
614 for(prettyname = s+1; isspace(*prettyname); prettyname++)
615 ;
616 }
617 e = prettyname + strlen(prettyname);
618 while(isspace(*--e)) *e = '\0';
619 TRACE("\t%s\n", debugstr_a(prettyname));
620 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
621
622 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623 * if it is too long, we use it as comment below. */
624 devname = prettyname;
625 if (strlen(devname)>=CCHDEVICENAME-1)
626 devname = name;
627 if (strlen(devname)>=CCHDEVICENAME-1) {
628 ret = FALSE;
629 goto end;
630 }
631
632 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
633 sprintf(port,"LPR:%s",name);
634
635 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
637 sprintf(devline, "WINEPS.DRV,%s", port);
638 WriteProfileStringA("devices", devname, devline);
639 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
640 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
641 RegCloseKey(hkey);
642 }
643
644 lstrcatA(devline, ",15,45");
645 WriteProfileStringA("PrinterPorts", devname, devline);
646 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
647 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
648 RegCloseKey(hkey);
649 }
650
651 HeapFree(GetProcessHeap(),0,devline);
652
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
654 ERROR_SUCCESS) {
655 ERR("Can't create Printers key\n");
656 ret = FALSE;
657 goto end;
658 }
659 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
660 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 and continue */
662 TRACE("Printer already exists\n");
663 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
664 RegCloseKey(hkeyPrinter);
665 } else {
666 static CHAR data_type[] = "RAW",
667 print_proc[] = "WinPrint",
668 comment[] = "WINEPS Printer using LPR",
669 params[] = "<parameters?>",
670 share_name[] = "<share name?>",
671 sep_file[] = "<sep file?>";
672
673 add_printer_driver(devname);
674
675 memset(&pinfo2a,0,sizeof(pinfo2a));
676 pinfo2a.pPrinterName = devname;
677 pinfo2a.pDatatype = data_type;
678 pinfo2a.pPrintProcessor = print_proc;
679 pinfo2a.pDriverName = devname;
680 pinfo2a.pComment = comment;
681 pinfo2a.pLocation = prettyname;
682 pinfo2a.pPortName = port;
683 pinfo2a.pParameters = params;
684 pinfo2a.pShareName = share_name;
685 pinfo2a.pSepFile = sep_file;
686
687 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
688 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
689 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
690 }
691 }
692 RegCloseKey(hkeyPrinters);
693
694 if (isfirst || set_default)
695 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
696
697 end:
698 HeapFree(GetProcessHeap(), 0, port);
699 HeapFree(GetProcessHeap(), 0, name);
700 return ret;
701 }
702
703 static BOOL
704 PRINTCAP_LoadPrinters(void) {
705 BOOL hadprinter = FALSE;
706 char buf[200];
707 FILE *f;
708 char *pent = NULL;
709 BOOL had_bash = FALSE;
710
711 f = fopen("/etc/printcap","r");
712 if (!f)
713 return FALSE;
714
715 while(fgets(buf,sizeof(buf),f)) {
716 char *start, *end;
717
718 end=strchr(buf,'\n');
719 if (end) *end='\0';
720
721 start = buf;
722 while(isspace(*start)) start++;
723 if(*start == '#' || *start == '\0')
724 continue;
725
726 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
727 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
728 HeapFree(GetProcessHeap(),0,pent);
729 pent = NULL;
730 }
731
732 if (end && *--end == '\\') {
733 *end = '\0';
734 had_bash = TRUE;
735 } else
736 had_bash = FALSE;
737
738 if (pent) {
739 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
740 strcat(pent,start);
741 } else {
742 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
743 strcpy(pent,start);
744 }
745
746 }
747 if(pent) {
748 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
749 HeapFree(GetProcessHeap(),0,pent);
750 }
751 fclose(f);
752 return hadprinter;
753 }
754
755 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
756 {
757 if (value)
758 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
759 (lstrlenW(value) + 1) * sizeof(WCHAR));
760 else
761 return ERROR_FILE_NOT_FOUND;
762 }
763
764 /******************************************************************
765 * monitor_unload [internal]
766 *
767 * release a printmonitor and unload it from memory, when needed
768 *
769 */
770 static void monitor_unload(monitor_t * pm)
771 {
772 if (pm == NULL) return;
773 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
774
775 EnterCriticalSection(&monitor_handles_cs);
776
777 if (pm->refcount) pm->refcount--;
778
779 if (pm->refcount == 0) {
780 list_remove(&pm->entry);
781 FreeLibrary(pm->hdll);
782 HeapFree(GetProcessHeap(), 0, pm->name);
783 HeapFree(GetProcessHeap(), 0, pm->dllname);
784 HeapFree(GetProcessHeap(), 0, pm);
785 }
786 LeaveCriticalSection(&monitor_handles_cs);
787 }
788
789 /******************************************************************
790 * monitor_load [internal]
791 *
792 * load a printmonitor, get the dllname from the registry, when needed
793 * initialize the monitor and dump found function-pointers
794 *
795 * On failure, SetLastError() is called and NULL is returned
796 */
797
798 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
799 {
800 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
801 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
802 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
803 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
804 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
805
806 monitor_t * pm = NULL;
807 monitor_t * cursor;
808 LPWSTR regroot = NULL;
809 LPWSTR driver = dllname;
810
811 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
812 /* Is the Monitor already loaded? */
813 EnterCriticalSection(&monitor_handles_cs);
814
815 if (name) {
816 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
817 {
818 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
819 pm = cursor;
820 break;
821 }
822 }
823 }
824
825 if (pm == NULL) {
826 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
827 if (pm == NULL) goto cleanup;
828 list_add_tail(&monitor_handles, &pm->entry);
829 }
830 pm->refcount++;
831
832 if (pm->name == NULL) {
833 /* Load the monitor */
834 LPMONITOREX pmonitorEx;
835 DWORD len;
836
837 if (name) {
838 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
839 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
840 }
841
842 if (regroot) {
843 lstrcpyW(regroot, MonitorsW);
844 lstrcatW(regroot, name);
845 /* Get the Driver from the Registry */
846 if (driver == NULL) {
847 HKEY hroot;
848 DWORD namesize;
849 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
850 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
851 &namesize) == ERROR_SUCCESS) {
852 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
853 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
854 }
855 RegCloseKey(hroot);
856 }
857 }
858 }
859
860 pm->name = strdupW(name);
861 pm->dllname = strdupW(driver);
862
863 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
864 monitor_unload(pm);
865 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
866 pm = NULL;
867 goto cleanup;
868 }
869
870 pm->hdll = LoadLibraryW(driver);
871 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
872
873 if (pm->hdll == NULL) {
874 monitor_unload(pm);
875 SetLastError(ERROR_MOD_NOT_FOUND);
876 pm = NULL;
877 goto cleanup;
878 }
879
880 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
881 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
882 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
883 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
884 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
885
886
887 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
888 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
889 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
890 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
891 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
892
893 if (pInitializePrintMonitorUI != NULL) {
894 pm->monitorUI = pInitializePrintMonitorUI();
895 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
896 if (pm->monitorUI) {
897 TRACE( "0x%08x: dwMonitorSize (%d)\n",
898 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
899
900 }
901 }
902
903 if (pInitializePrintMonitor && regroot) {
904 pmonitorEx = pInitializePrintMonitor(regroot);
905 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
906 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
907
908 if (pmonitorEx) {
909 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
910 pm->monitor = &(pmonitorEx->Monitor);
911 }
912 }
913
914 if (pm->monitor) {
915 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
916
917 }
918
919 if (!pm->monitor && regroot) {
920 if (pInitializePrintMonitor2 != NULL) {
921 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
922 }
923 if (pInitializeMonitorEx != NULL) {
924 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
925 }
926 if (pInitializeMonitor != NULL) {
927 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
928 }
929 }
930 if (!pm->monitor && !pm->monitorUI) {
931 monitor_unload(pm);
932 SetLastError(ERROR_PROC_NOT_FOUND);
933 pm = NULL;
934 }
935 }
936 cleanup:
937 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
938 pm->refcount++;
939 pm_localport = pm;
940 }
941 LeaveCriticalSection(&monitor_handles_cs);
942 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
943 HeapFree(GetProcessHeap(), 0, regroot);
944 TRACE("=> %p\n", pm);
945 return pm;
946 }
947
948 /******************************************************************
949 * monitor_loadui [internal]
950 *
951 * load the userinterface-dll for a given portmonitor
952 *
953 * On failure, NULL is returned
954 */
955
956 static monitor_t * monitor_loadui(monitor_t * pm)
957 {
958 monitor_t * pui = NULL;
959 LPWSTR buffer[MAX_PATH];
960 HANDLE hXcv;
961 DWORD len;
962 DWORD res;
963
964 if (pm == NULL) return NULL;
965 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
966
967 /* Try the Portmonitor first; works for many monitors */
968 if (pm->monitorUI) {
969 EnterCriticalSection(&monitor_handles_cs);
970 pm->refcount++;
971 LeaveCriticalSection(&monitor_handles_cs);
972 return pm;
973 }
974
975 /* query the userinterface-dllname from the Portmonitor */
976 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
977 /* building (",XcvMonitor %s",pm->name) not needed yet */
978 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
979 TRACE("got %u with %p\n", res, hXcv);
980 if (res) {
981 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
982 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
983 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
984 pm->monitor->pfnXcvClosePort(hXcv);
985 }
986 }
987 return pui;
988 }
989
990
991 /******************************************************************
992 * monitor_load_by_port [internal]
993 *
994 * load a printmonitor for a given port
995 *
996 * On failure, NULL is returned
997 */
998
999 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1000 {
1001 HKEY hroot;
1002 HKEY hport;
1003 LPWSTR buffer;
1004 monitor_t * pm = NULL;
1005 DWORD registered = 0;
1006 DWORD id = 0;
1007 DWORD len;
1008
1009 TRACE("(%s)\n", debugstr_w(portname));
1010
1011 /* Try the Local Monitor first */
1012 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1013 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1014 /* found the portname */
1015 RegCloseKey(hroot);
1016 return monitor_load(LocalPortW, NULL);
1017 }
1018 RegCloseKey(hroot);
1019 }
1020
1021 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1022 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1023 if (buffer == NULL) return NULL;
1024
1025 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1026 EnterCriticalSection(&monitor_handles_cs);
1027 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1028
1029 while ((pm == NULL) && (id < registered)) {
1030 buffer[0] = '\0';
1031 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1032 TRACE("testing %s\n", debugstr_w(buffer));
1033 len = lstrlenW(buffer);
1034 lstrcatW(buffer, bs_Ports_bsW);
1035 lstrcatW(buffer, portname);
1036 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1037 RegCloseKey(hport);
1038 buffer[len] = '\0'; /* use only the Monitor-Name */
1039 pm = monitor_load(buffer, NULL);
1040 }
1041 id++;
1042 }
1043 LeaveCriticalSection(&monitor_handles_cs);
1044 RegCloseKey(hroot);
1045 }
1046 HeapFree(GetProcessHeap(), 0, buffer);
1047 return pm;
1048 }
1049
1050 /******************************************************************
1051 * get_servername_from_name (internal)
1052 *
1053 * for an external server, a copy of the serverpart from the full name is returned
1054 *
1055 */
1056 static LPWSTR get_servername_from_name(LPCWSTR name)
1057 {
1058 LPWSTR server;
1059 LPWSTR ptr;
1060 WCHAR buffer[MAX_PATH];
1061 DWORD len;
1062
1063 if (name == NULL) return NULL;
1064 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1065
1066 server = strdupW(&name[2]); /* skip over both backslash */
1067 if (server == NULL) return NULL;
1068
1069 /* strip '\' and the printername */
1070 ptr = strchrW(server, '\\');
1071 if (ptr) ptr[0] = '\0';
1072
1073 TRACE("found %s\n", debugstr_w(server));
1074
1075 len = sizeof(buffer)/sizeof(buffer[0]);
1076 if (GetComputerNameW(buffer, &len)) {
1077 if (lstrcmpW(buffer, server) == 0) {
1078 /* The requested Servername is our computername */
1079 HeapFree(GetProcessHeap(), 0, server);
1080 return NULL;
1081 }
1082 }
1083 return server;
1084 }
1085
1086 /******************************************************************
1087 * get_basename_from_name (internal)
1088 *
1089 * skip over the serverpart from the full name
1090 *
1091 */
1092 static LPCWSTR get_basename_from_name(LPCWSTR name)
1093 {
1094 if (name == NULL) return NULL;
1095 if ((name[0] == '\\') && (name[1] == '\\')) {
1096 /* skip over the servername and search for the following '\' */
1097 name = strchrW(&name[2], '\\');
1098 if ((name) && (name[1])) {
1099 /* found a separator ('\') followed by a name:
1100 skip over the separator and return the rest */
1101 name++;
1102 }
1103 else
1104 {
1105 /* no basename present (we found only a servername) */
1106 return NULL;
1107 }
1108 }
1109 return name;
1110 }
1111
1112 /******************************************************************
1113 * get_opened_printer_entry
1114 * Get the first place empty in the opened printer table
1115 *
1116 * ToDo:
1117 * - pDefault is ignored
1118 */
1119 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1120 {
1121 UINT_PTR handle = nb_printer_handles, i;
1122 jobqueue_t *queue = NULL;
1123 opened_printer_t *printer = NULL;
1124 LPWSTR servername;
1125 LPCWSTR printername;
1126
1127 if ((backend == NULL) && !load_backend()) return NULL;
1128
1129 servername = get_servername_from_name(name);
1130 if (servername) {
1131 FIXME("server %s not supported\n", debugstr_w(servername));
1132 HeapFree(GetProcessHeap(), 0, servername);
1133 SetLastError(ERROR_INVALID_PRINTER_NAME);
1134 return NULL;
1135 }
1136
1137 printername = get_basename_from_name(name);
1138 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1139
1140 /* an empty printername is invalid */
1141 if (printername && (!printername[0])) {
1142 SetLastError(ERROR_INVALID_PARAMETER);
1143 return NULL;
1144 }
1145
1146 EnterCriticalSection(&printer_handles_cs);
1147
1148 for (i = 0; i < nb_printer_handles; i++)
1149 {
1150 if (!printer_handles[i])
1151 {
1152 if(handle == nb_printer_handles)
1153 handle = i;
1154 }
1155 else
1156 {
1157 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1158 queue = printer_handles[i]->queue;
1159 }
1160 }
1161
1162 if (handle >= nb_printer_handles)
1163 {
1164 opened_printer_t **new_array;
1165 if (printer_handles)
1166 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1167 (nb_printer_handles + 16) * sizeof(*new_array) );
1168 else
1169 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1170 (nb_printer_handles + 16) * sizeof(*new_array) );
1171
1172 if (!new_array)
1173 {
1174 handle = 0;
1175 goto end;
1176 }
1177 printer_handles = new_array;
1178 nb_printer_handles += 16;
1179 }
1180
1181 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1182 {
1183 handle = 0;
1184 goto end;
1185 }
1186
1187 /* get a printer handle from the backend */
1188 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1189 handle = 0;
1190 goto end;
1191 }
1192
1193 /* clone the base name. This is NULL for the printserver */
1194 printer->printername = strdupW(printername);
1195
1196 /* clone the full name */
1197 printer->name = strdupW(name);
1198 if (name && (!printer->name)) {
1199 handle = 0;
1200 goto end;
1201 }
1202
1203 if(queue)
1204 printer->queue = queue;
1205 else
1206 {
1207 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1208 if (!printer->queue) {
1209 handle = 0;
1210 goto end;
1211 }
1212 list_init(&printer->queue->jobs);
1213 printer->queue->ref = 0;
1214 }
1215 InterlockedIncrement(&printer->queue->ref);
1216
1217 printer_handles[handle] = printer;
1218 handle++;
1219 end:
1220 LeaveCriticalSection(&printer_handles_cs);
1221 if (!handle && printer) {
1222 /* Something failed: Free all resources */
1223 HeapFree(GetProcessHeap(), 0, printer->printername);
1224 HeapFree(GetProcessHeap(), 0, printer->name);
1225 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1226 HeapFree(GetProcessHeap(), 0, printer);
1227 }
1228
1229 return (HANDLE)handle;
1230 }
1231
1232 /******************************************************************
1233 * get_opened_printer
1234 * Get the pointer to the opened printer referred by the handle
1235 */
1236 static opened_printer_t *get_opened_printer(HANDLE hprn)
1237 {
1238 UINT_PTR idx = (UINT_PTR)hprn;
1239 opened_printer_t *ret = NULL;
1240
1241 EnterCriticalSection(&printer_handles_cs);
1242
1243 if ((idx > 0) && (idx <= nb_printer_handles)) {
1244 ret = printer_handles[idx - 1];
1245 }
1246 LeaveCriticalSection(&printer_handles_cs);
1247 return ret;
1248 }
1249
1250 /******************************************************************
1251 * get_opened_printer_name
1252 * Get the pointer to the opened printer name referred by the handle
1253 */
1254 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1255 {
1256 opened_printer_t *printer = get_opened_printer(hprn);
1257 if(!printer) return NULL;
1258 return printer->name;
1259 }
1260
1261 /******************************************************************
1262 * WINSPOOL_GetOpenedPrinterRegKey
1263 *
1264 */
1265 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1266 {
1267 LPCWSTR name = get_opened_printer_name(hPrinter);
1268 DWORD ret;
1269 HKEY hkeyPrinters;
1270
1271 if(!name) return ERROR_INVALID_HANDLE;
1272
1273 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1274 ERROR_SUCCESS)
1275 return ret;
1276
1277 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1278 {
1279 ERR("Can't find opened printer %s in registry\n",
1280 debugstr_w(name));
1281 RegCloseKey(hkeyPrinters);
1282 return ERROR_INVALID_PRINTER_NAME; /* ? */
1283 }
1284 RegCloseKey(hkeyPrinters);
1285 return ERROR_SUCCESS;
1286 }
1287
1288 void WINSPOOL_LoadSystemPrinters(void)
1289 {
1290 HKEY hkey, hkeyPrinters;
1291 HANDLE hprn;
1292 DWORD needed, num, i;
1293 WCHAR PrinterName[256];
1294 BOOL done = FALSE;
1295
1296 /* This ensures that all printer entries have a valid Name value. If causes
1297 problems later if they don't. If one is found to be missed we create one
1298 and set it equal to the name of the key */
1299 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1300 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1301 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1302 for(i = 0; i < num; i++) {
1303 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1304 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1305 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1306 set_reg_szW(hkey, NameW, PrinterName);
1307 }
1308 RegCloseKey(hkey);
1309 }
1310 }
1311 }
1312 }
1313 RegCloseKey(hkeyPrinters);
1314 }
1315
1316 /* We want to avoid calling AddPrinter on printers as much as
1317 possible, because on cups printers this will (eventually) lead
1318 to a call to cupsGetPPD which takes forever, even with non-cups
1319 printers AddPrinter takes a while. So we'll tag all printers that
1320 were automatically added last time around, if they still exist
1321 we'll leave them be otherwise we'll delete them. */
1322 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1323 if(needed) {
1324 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1325 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1326 for(i = 0; i < num; i++) {
1327 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1328 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1329 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1330 DWORD dw = 1;
1331 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1332 RegCloseKey(hkey);
1333 }
1334 ClosePrinter(hprn);
1335 }
1336 }
1337 }
1338 }
1339 HeapFree(GetProcessHeap(), 0, pi);
1340 }
1341
1342
1343 #ifdef SONAME_LIBCUPS
1344 done = CUPS_LoadPrinters();
1345 #endif
1346
1347 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1348 PRINTCAP_LoadPrinters();
1349
1350 /* Now enumerate the list again and delete any printers that are still tagged */
1351 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1352 if(needed) {
1353 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1354 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1355 for(i = 0; i < num; i++) {
1356 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1357 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1358 BOOL delete_driver = FALSE;
1359 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1360 DWORD dw, type, size = sizeof(dw);
1361 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1362 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1363 DeletePrinter(hprn);
1364 delete_driver = TRUE;
1365 }
1366 RegCloseKey(hkey);
1367 }
1368 ClosePrinter(hprn);
1369 if(delete_driver)
1370 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1371 }
1372 }
1373 }
1374 }
1375 HeapFree(GetProcessHeap(), 0, pi);
1376 }
1377
1378 return;
1379
1380 }
1381
1382 /******************************************************************
1383 * get_job
1384 *
1385 * Get the pointer to the specified job.
1386 * Should hold the printer_handles_cs before calling.
1387 */
1388 static job_t *get_job(HANDLE hprn, DWORD JobId)
1389 {
1390 opened_printer_t *printer = get_opened_printer(hprn);
1391 job_t *job;
1392
1393 if(!printer) return NULL;
1394 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1395 {
1396 if(job->job_id == JobId)
1397 return job;
1398 }
1399 return NULL;
1400 }
1401
1402 /***********************************************************
1403 * DEVMODEcpyAtoW
1404 */
1405 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1406 {
1407 BOOL Formname;
1408 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1409 DWORD size;
1410
1411 Formname = (dmA->dmSize > off_formname);
1412 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1413 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1414 dmW->dmDeviceName, CCHDEVICENAME);
1415 if(!Formname) {
1416 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1417 dmA->dmSize - CCHDEVICENAME);
1418 } else {
1419 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1420 off_formname - CCHDEVICENAME);
1421 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1422 dmW->dmFormName, CCHFORMNAME);
1423 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1424 (off_formname + CCHFORMNAME));
1425 }
1426 dmW->dmSize = size;
1427 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1428 dmA->dmDriverExtra);
1429 return dmW;
1430 }
1431
1432 /***********************************************************
1433 * DEVMODEdupWtoA
1434 * Creates an ansi copy of supplied devmode
1435 */
1436 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1437 {
1438 LPDEVMODEA dmA;
1439 DWORD size;
1440
1441 if (!dmW) return NULL;
1442 size = dmW->dmSize - CCHDEVICENAME -
1443 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1444
1445 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1446 if (!dmA) return NULL;
1447
1448 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1449 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1450
1451 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1452 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1453 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1454 }
1455 else
1456 {
1457 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1458 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1459 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1460 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1461
1462 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1463 }
1464
1465 dmA->dmSize = size;
1466 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1467 return dmA;
1468 }
1469
1470 /******************************************************************
1471 * convert_printerinfo_W_to_A [internal]
1472 *
1473 */
1474 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1475 DWORD level, DWORD outlen, DWORD numentries)
1476 {
1477 DWORD id = 0;
1478 LPSTR ptr;
1479 INT len;
1480
1481 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1482
1483 len = pi_sizeof[level] * numentries;
1484 ptr = (LPSTR) out + len;
1485 outlen -= len;
1486
1487 /* copy the numbers of all PRINTER_INFO_* first */
1488 memcpy(out, pPrintersW, len);
1489
1490 while (id < numentries) {
1491 switch (level) {
1492 case 1:
1493 {
1494 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1495 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1496
1497 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1498 if (piW->pDescription) {
1499 piA->pDescription = ptr;
1500 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1501 ptr, outlen, NULL, NULL);
1502 ptr += len;
1503 outlen -= len;
1504 }
1505 if (piW->pName) {
1506 piA->pName = ptr;
1507 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1508 ptr, outlen, NULL, NULL);
1509 ptr += len;
1510 outlen -= len;
1511 }
1512 if (piW->pComment) {
1513 piA->pComment = ptr;
1514 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1515 ptr, outlen, NULL, NULL);
1516 ptr += len;
1517 outlen -= len;
1518 }
1519 break;
1520 }
1521
1522 case 2:
1523 {
1524 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1525 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1526 LPDEVMODEA dmA;
1527
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1529 if (piW->pServerName) {
1530 piA->pServerName = ptr;
1531 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1532 ptr, outlen, NULL, NULL);
1533 ptr += len;
1534 outlen -= len;
1535 }
1536 if (piW->pPrinterName) {
1537 piA->pPrinterName = ptr;
1538 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1539 ptr, outlen, NULL, NULL);
1540 ptr += len;
1541 outlen -= len;
1542 }
1543 if (piW->pShareName) {
1544 piA->pShareName = ptr;
1545 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1546 ptr, outlen, NULL, NULL);
1547 ptr += len;
1548 outlen -= len;
1549 }
1550 if (piW->pPortName) {
1551 piA->pPortName = ptr;
1552 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1553 ptr, outlen, NULL, NULL);
1554 ptr += len;
1555 outlen -= len;
1556 }
1557 if (piW->pDriverName) {
1558 piA->pDriverName = ptr;
1559 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1560 ptr, outlen, NULL, NULL);
1561 ptr += len;
1562 outlen -= len;
1563 }
1564 if (piW->pComment) {
1565 piA->pComment = ptr;
1566 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1567 ptr, outlen, NULL, NULL);
1568 ptr += len;
1569 outlen -= len;
1570 }
1571 if (piW->pLocation) {
1572 piA->pLocation = ptr;
1573 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1574 ptr, outlen, NULL, NULL);
1575 ptr += len;
1576 outlen -= len;
1577 }
1578
1579 dmA = DEVMODEdupWtoA(piW->pDevMode);
1580 if (dmA) {
1581 /* align DEVMODEA to a DWORD boundary */
1582 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1583 ptr += len;
1584 outlen -= len;
1585
1586 piA->pDevMode = (LPDEVMODEA) ptr;
1587 len = dmA->dmSize + dmA->dmDriverExtra;
1588 memcpy(ptr, dmA, len);
1589 HeapFree(GetProcessHeap(), 0, dmA);
1590
1591 ptr += len;
1592 outlen -= len;
1593 }
1594
1595 if (piW->pSepFile) {
1596 piA->pSepFile = ptr;
1597 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1598 ptr, outlen, NULL, NULL);
1599 ptr += len;
1600 outlen -= len;
1601 }
1602 if (piW->pPrintProcessor) {
1603 piA->pPrintProcessor = ptr;
1604 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1605 ptr, outlen, NULL, NULL);
1606 ptr += len;
1607 outlen -= len;
1608 }
1609 if (piW->pDatatype) {
1610 piA->pDatatype = ptr;
1611 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1612 ptr, outlen, NULL, NULL);
1613 ptr += len;
1614 outlen -= len;
1615 }
1616 if (piW->pParameters) {
1617 piA->pParameters = ptr;
1618 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1619 ptr, outlen, NULL, NULL);
1620 ptr += len;
1621 outlen -= len;
1622 }
1623 if (piW->pSecurityDescriptor) {
1624 piA->pSecurityDescriptor = NULL;
1625 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1626 }
1627 break;
1628 }
1629
1630 case 4:
1631 {
1632 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1633 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1634
1635 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1636
1637 if (piW->pPrinterName) {
1638 piA->pPrinterName = ptr;
1639 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1640 ptr, outlen, NULL, NULL);
1641 ptr += len;
1642 outlen -= len;
1643 }
1644 if (piW->pServerName) {
1645 piA->pServerName = ptr;
1646 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1647 ptr, outlen, NULL, NULL);
1648 ptr += len;
1649 outlen -= len;
1650 }
1651 break;
1652 }
1653
1654 case 5:
1655 {
1656 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1657 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1658
1659 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1660
1661 if (piW->pPrinterName) {
1662 piA->pPrinterName = ptr;
1663 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1664 ptr, outlen, NULL, NULL);
1665 ptr += len;
1666 outlen -= len;
1667 }
1668 if (piW->pPortName) {
1669 piA->pPortName = ptr;
1670 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1671 ptr, outlen, NULL, NULL);
1672 ptr += len;
1673 outlen -= len;
1674 }
1675 break;
1676 }
1677
1678 default:
1679 FIXME("for level %u\n", level);
1680 }
1681 pPrintersW += pi_sizeof[level];
1682 out += pi_sizeof[level];
1683 id++;
1684 }
1685 }
1686
1687 /***********************************************************
1688 * PRINTER_INFO_2AtoW
1689 * Creates a unicode copy of PRINTER_INFO_2A on heap
1690 */
1691 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1692 {
1693 LPPRINTER_INFO_2W piW;
1694 UNICODE_STRING usBuffer;
1695
1696 if(!piA) return NULL;
1697 piW = HeapAlloc(heap, 0, sizeof(*piW));
1698 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1699
1700 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1701 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1702 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1703 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1704 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1705 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1706 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1707 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1708 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1709 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1710 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1711 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1712 return piW;
1713 }
1714
1715 /***********************************************************
1716 * FREE_PRINTER_INFO_2W
1717 * Free PRINTER_INFO_2W and all strings
1718 */
1719 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1720 {
1721 if(!piW) return;
1722
1723 HeapFree(heap,0,piW->pServerName);
1724 HeapFree(heap,0,piW->pPrinterName);
1725 HeapFree(heap,0,piW->pShareName);
1726 HeapFree(heap,0,piW->pPortName);
1727 HeapFree(heap,0,piW->pDriverName);
1728 HeapFree(heap,0,piW->pComment);
1729 HeapFree(heap,0,piW->pLocation);
1730 HeapFree(heap,0,piW->pDevMode);
1731 HeapFree(heap,0,piW->pSepFile);
1732 HeapFree(heap,0,piW->pPrintProcessor);
1733 HeapFree(heap,0,piW->pDatatype);
1734 HeapFree(heap,0,piW->pParameters);
1735 HeapFree(heap,0,piW);
1736 return;
1737 }
1738
1739 /******************************************************************
1740 * DeviceCapabilities [WINSPOOL.@]
1741 * DeviceCapabilitiesA [WINSPOOL.@]
1742 *
1743 */
1744 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1745 LPSTR pOutput, LPDEVMODEA lpdm)
1746 {
1747 INT ret;
1748
1749 if (!GDI_CallDeviceCapabilities16)
1750 {
1751 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1752 (LPCSTR)104 );
1753 if (!GDI_CallDeviceCapabilities16) return -1;
1754 }
1755 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1756
1757 /* If DC_PAPERSIZE map POINT16s to POINTs */
1758 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1759 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1760 POINT *pt = (POINT *)pOutput;
1761 INT i;
1762 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1763 for(i = 0; i < ret; i++, pt++)
1764 {
1765 pt->x = tmp[i].x;
1766 pt->y = tmp[i].y;
1767 }
1768 HeapFree( GetProcessHeap(), 0, tmp );
1769 }
1770 return ret;
1771 }
1772
1773
1774 /*****************************************************************************
1775 * DeviceCapabilitiesW [WINSPOOL.@]
1776 *
1777 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1778 *
1779 */
1780 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1781 WORD fwCapability, LPWSTR pOutput,
1782 const DEVMODEW *pDevMode)
1783 {
1784 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1785 LPSTR pDeviceA = strdupWtoA(pDevice);
1786 LPSTR pPortA = strdupWtoA(pPort);
1787 INT ret;
1788
1789 if(pOutput && (fwCapability == DC_BINNAMES ||
1790 fwCapability == DC_FILEDEPENDENCIES ||
1791 fwCapability == DC_PAPERNAMES)) {
1792 /* These need A -> W translation */
1793 INT size = 0, i;
1794 LPSTR pOutputA;
1795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1796 dmA);
1797 if(ret == -1)
1798 return ret;
1799 switch(fwCapability) {
1800 case DC_BINNAMES:
1801 size = 24;
1802 break;
1803 case DC_PAPERNAMES:
1804 case DC_FILEDEPENDENCIES:
1805 size = 64;
1806 break;
1807 }
1808 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1809 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1810 dmA);
1811 for(i = 0; i < ret; i++)
1812 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1813 pOutput + (i * size), size);
1814 HeapFree(GetProcessHeap(), 0, pOutputA);
1815 } else {
1816 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1817 (LPSTR)pOutput, dmA);
1818 }
1819 HeapFree(GetProcessHeap(),0,pPortA);
1820 HeapFree(GetProcessHeap(),0,pDeviceA);
1821 HeapFree(GetProcessHeap(),0,dmA);
1822 return ret;
1823 }
1824
1825 /******************************************************************
1826 * DocumentPropertiesA [WINSPOOL.@]
1827 *
1828 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1829 */
1830 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1831 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1832 LPDEVMODEA pDevModeInput,DWORD fMode )
1833 {
1834 LPSTR lpName = pDeviceName;
1835 static CHAR port[] = "LPT1:";
1836 LONG ret;
1837
1838 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1839 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1840 );
1841
1842 if(!pDeviceName) {
1843 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1844 if(!lpNameW) {
1845 ERR("no name from hPrinter?\n");
1846 SetLastError(ERROR_INVALID_HANDLE);
1847 return -1;
1848 }
1849 lpName = strdupWtoA(lpNameW);
1850 }
1851
1852 if (!GDI_CallExtDeviceMode16)
1853 {
1854 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1855 (LPCSTR)102 );
1856 if (!GDI_CallExtDeviceMode16) {
1857 ERR("No CallExtDeviceMode16?\n");
1858 return -1;
1859 }
1860 }
1861 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1862 pDevModeInput, NULL, fMode);
1863
1864 if(!pDeviceName)
1865 HeapFree(GetProcessHeap(),0,lpName);
1866 return ret;
1867 }
1868
1869
1870 /*****************************************************************************
1871 * DocumentPropertiesW (WINSPOOL.@)
1872 *
1873 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1874 */
1875 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1876 LPWSTR pDeviceName,
1877 LPDEVMODEW pDevModeOutput,
1878 LPDEVMODEW pDevModeInput, DWORD fMode)
1879 {
1880
1881 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1882 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1883 LPDEVMODEA pDevModeOutputA = NULL;
1884 LONG ret;
1885
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1888 fMode);
1889 if(pDevModeOutput) {
1890 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1891 if(ret < 0) return ret;
1892 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1893 }
1894 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1895 pDevModeInputA, fMode);
1896 if(pDevModeOutput) {
1897 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1898 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1899 }
1900 if(fMode == 0 && ret > 0)
1901 ret += (CCHDEVICENAME + CCHFORMNAME);
1902 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1903 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1904 return ret;
1905 }
1906
1907 /******************************************************************
1908 * OpenPrinterA [WINSPOOL.@]
1909 *
1910 * See OpenPrinterW.
1911 *
1912 */
1913 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1914 LPPRINTER_DEFAULTSA pDefault)
1915 {
1916 UNICODE_STRING lpPrinterNameW;
1917 UNICODE_STRING usBuffer;
1918 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1919 PWSTR pwstrPrinterNameW;
1920 BOOL ret;
1921
1922 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1923
1924 if(pDefault) {
1925 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1926 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1927 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1928 pDefaultW = &DefaultW;
1929 }
1930 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1931 if(pDefault) {
1932 RtlFreeUnicodeString(&usBuffer);
1933 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1934 }
1935 RtlFreeUnicodeString(&lpPrinterNameW);
1936 return ret;
1937 }
1938
1939 /******************************************************************
1940 * OpenPrinterW [WINSPOOL.@]
1941 *
1942 * Open a Printer / Printserver or a Printer-Object
1943 *
1944 * PARAMS
1945 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1946 * phPrinter [O] The resulting Handle is stored here
1947 * pDefault [I] PTR to Default Printer Settings or NULL
1948 *
1949 * RETURNS
1950 * Success: TRUE
1951 * Failure: FALSE
1952 *
1953 * NOTES
1954 * lpPrinterName is one of:
1955 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1956 *| Printer: "PrinterName"
1957 *| Printer-Object: "PrinterName,Job xxx"
1958 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1959 *| XcvPort: "Servername,XcvPort PortName"
1960 *
1961 * BUGS
1962 *| Printer-Object not supported
1963 *| pDefaults is ignored
1964 *
1965 */
1966 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1967 {
1968
1969 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1970 if (pDefault) {
1971 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1972 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1973 }
1974
1975 if(!phPrinter) {
1976 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1977 SetLastError(ERROR_INVALID_PARAMETER);
1978 return FALSE;
1979 }
1980
1981 /* Get the unique handle of the printer or Printserver */
1982 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1983 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1984 return (*phPrinter != 0);
1985 }
1986
1987 /******************************************************************
1988 * AddMonitorA [WINSPOOL.@]
1989 *
1990 * See AddMonitorW.
1991 *
1992 */
1993 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1994 {
1995 LPWSTR nameW = NULL;
1996 INT len;
1997 BOOL res;
1998 LPMONITOR_INFO_2A mi2a;
1999 MONITOR_INFO_2W mi2w;
2000
2001 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2002 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2003 debugstr_a(mi2a ? mi2a->pName : NULL),
2004 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2005 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2006
2007 if (Level != 2) {
2008 SetLastError(ERROR_INVALID_LEVEL);
2009 return FALSE;
2010 }
2011
2012 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2013 if (mi2a == NULL) {
2014 return FALSE;
2015 }
2016
2017 if (pName) {
2018 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2019 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2021 }
2022
2023 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2024 if (mi2a->pName) {
2025 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2026 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2028 }
2029 if (mi2a->pEnvironment) {
2030 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2031 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2032 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2033 }
2034 if (mi2a->pDLLName) {
2035 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2036 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2038 }
2039
2040 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2041
2042 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2045
2046 HeapFree(GetProcessHeap(), 0, nameW);
2047 return (res);
2048 }
2049
2050 /******************************************************************************
2051 * AddMonitorW [WINSPOOL.@]
2052 *
2053 * Install a Printmonitor
2054 *
2055 * PARAMS
2056 * pName [I] Servername or NULL (local Computer)
2057 * Level [I] Structure-Level (Must be 2)
2058 * pMonitors [I] PTR to MONITOR_INFO_2
2059 *
2060 * RETURNS
2061 * Success: TRUE
2062 * Failure: FALSE
2063 *
2064 * NOTES
2065 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2066 *
2067 */
2068 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2069 {
2070 LPMONITOR_INFO_2W mi2w;
2071
2072 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2073 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2074 debugstr_w(mi2w ? mi2w->pName : NULL),
2075 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2076 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2077
2078 if ((backend == NULL) && !load_backend()) return FALSE;
2079
2080 if (Level != 2) {
2081 SetLastError(ERROR_INVALID_LEVEL);
2082 return FALSE;
2083 }
2084
2085 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2086 if (mi2w == NULL) {
2087 return FALSE;
2088 }
2089
2090 return backend->fpAddMonitor(pName, Level, pMonitors);
2091 }
2092
2093 /******************************************************************
2094 * DeletePrinterDriverA [WINSPOOL.@]
2095 *
2096 */
2097 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2098 {
2099 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2100 }
2101
2102 /******************************************************************
2103 * DeletePrinterDriverW [WINSPOOL.@]
2104 *
2105 */
2106 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2107 {
2108 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2109 }
2110
2111 /******************************************************************
2112 * DeleteMonitorA [WINSPOOL.@]
2113 *
2114 * See DeleteMonitorW.
2115 *
2116 */
2117 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2118 {
2119 LPWSTR nameW = NULL;
2120 LPWSTR EnvironmentW = NULL;
2121 LPWSTR MonitorNameW = NULL;
2122 BOOL res;
2123 INT len;
2124
2125 if (pName) {
2126 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2127 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2128 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2129 }
2130
2131 if (pEnvironment) {
2132 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2133 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2134 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2135 }
2136 if (pMonitorName) {
2137 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2138 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2139 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2140 }
2141
2142 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2143
2144 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2145 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2146 HeapFree(GetProcessHeap(), 0, nameW);
2147 return (res);
2148 }
2149
2150 /******************************************************************
2151 * DeleteMonitorW [WINSPOOL.@]
2152 *
2153 * Delete a specific Printmonitor from a Printing-Environment
2154 *
2155 * PARAMS
2156 * pName [I] Servername or NULL (local Computer)
2157 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2158 * pMonitorName [I] Name of the Monitor, that should be deleted
2159 *
2160 * RETURNS
2161 * Success: TRUE
2162 * Failure: FALSE
2163 *
2164 * NOTES
2165 * pEnvironment is ignored in Windows for the local Computer.
2166 *
2167 */
2168 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2169 {
2170
2171 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2172 debugstr_w(pMonitorName));
2173
2174 if ((backend == NULL) && !load_backend()) return FALSE;
2175
2176 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2177 }
2178
2179
2180 /******************************************************************
2181 * DeletePortA [WINSPOOL.@]
2182 *
2183 * See DeletePortW.
2184 *
2185 */
2186 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2187 {
2188 LPWSTR nameW = NULL;
2189 LPWSTR portW = NULL;
2190 INT len;
2191 DWORD res;
2192
2193 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2194
2195 /* convert servername to unicode */
2196 if (pName) {
2197 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2198 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2199 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2200 }
2201
2202 /* convert portname to unicode */
2203 if (pPortName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2205 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2207 }
2208
2209 res = DeletePortW(nameW, hWnd, portW);
2210 HeapFree(GetProcessHeap(), 0, nameW);
2211 HeapFree(GetProcessHeap(), 0, portW);
2212 return res;
2213 }
2214
2215 /******************************************************************
2216 * DeletePortW [WINSPOOL.@]
2217 *
2218 * Delete a specific Port
2219 *
2220 * PARAMS
2221 * pName [I] Servername or NULL (local Computer)
2222 * hWnd [I] Handle to parent Window for the Dialog-Box
2223 * pPortName [I] Name of the Port, that should be deleted
2224 *
2225 * RETURNS
2226 * Success: TRUE
2227 * Failure: FALSE
2228 *
2229 */
2230 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2231 {
2232 monitor_t * pm;
2233 monitor_t * pui;
2234 DWORD res;
2235
2236 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2237
2238 if (pName && pName[0]) {
2239 SetLastError(ERROR_INVALID_PARAMETER);
2240 return FALSE;
2241 }
2242
2243 if (!pPortName) {
2244 SetLastError(RPC_X_NULL_REF_POINTER);
2245 return FALSE;
2246 }
2247
2248 /* an empty Portname is Invalid */
2249 if (!pPortName[0]) {
2250 SetLastError(ERROR_NOT_SUPPORTED);
2251 return FALSE;
2252 }
2253
2254 pm = monitor_load_by_port(pPortName);
2255 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2256 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2257 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2258 TRACE("got %d with %u\n", res, GetLastError());
2259 }
2260 else
2261 {
2262 pui = monitor_loadui(pm);
2263 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2264 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2265 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2266 TRACE("got %d with %u\n", res, GetLastError());
2267 }
2268 else
2269 {
2270 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2271 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2272
2273 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2274 SetLastError(ERROR_NOT_SUPPORTED);
2275 res = FALSE;
2276 }
2277 monitor_unload(pui);
2278 }
2279 monitor_unload(pm);
2280
2281 TRACE("returning %d with %u\n", res, GetLastError());
2282 return res;
2283 }
2284
2285 /******************************************************************************
2286 * SetPrinterW [WINSPOOL.@]
2287 */
2288 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2289 {
2290 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2292 return FALSE;
2293 }
2294
2295 /******************************************************************************
2296 * WritePrinter [WINSPOOL.@]
2297 */
2298 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2299 {
2300 opened_printer_t *printer;
2301 BOOL ret = FALSE;
2302
2303 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2304
2305 EnterCriticalSection(&printer_handles_cs);
2306 printer = get_opened_printer(hPrinter);
2307 if(!printer)
2308 {
2309 SetLastError(ERROR_INVALID_HANDLE);
2310 goto end;
2311 }
2312
2313 if(!printer->doc)
2314 {
2315 SetLastError(ERROR_SPL_NO_STARTDOC);
2316 goto end;
2317 }
2318
2319 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2320 end:
2321 LeaveCriticalSection(&printer_handles_cs);
2322 return ret;
2323 }
2324
2325 /*****************************************************************************
2326 * AddFormA [WINSPOOL.@]
2327 */
2328 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2329 {
2330 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2331 return 1;
2332 }
2333
2334 /*****************************************************************************
2335 * AddFormW [WINSPOOL.@]
2336 */
2337 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2338 {
2339 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2340 return 1;
2341 }
2342
2343 /*****************************************************************************
2344 * AddJobA [WINSPOOL.@]
2345 */
2346 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2347 {
2348 BOOL ret;
2349 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2350 DWORD needed;
2351
2352 if(Level != 1) {
2353 SetLastError(ERROR_INVALID_LEVEL);
2354 return FALSE;
2355 }
2356
2357 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2358
2359 if(ret) {
2360 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2361 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2362 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2363 if(*pcbNeeded > cbBuf) {
2364 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2365 ret = FALSE;
2366 } else {
2367 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2368 addjobA->JobId = addjobW->JobId;
2369 addjobA->Path = (char *)(addjobA + 1);
2370 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2371 }
2372 }
2373 return ret;
2374 }
2375
2376 /*****************************************************************************
2377 * AddJobW [WINSPOOL.@]
2378 */
2379 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2380 {
2381 opened_printer_t *printer;
2382 job_t *job;
2383 BOOL ret = FALSE;
2384 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2385 static const WCHAR fmtW[] = {'%','s','%','','5','d','.','S','P','L',0};
2386 WCHAR path[MAX_PATH], filename[MAX_PATH];
2387 DWORD len;
2388 ADDJOB_INFO_1W *addjob;
2389
2390 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2391
2392 EnterCriticalSection(&printer_handles_cs);
2393
2394 printer = get_opened_printer(hPrinter);
2395
2396 if(!printer) {
2397 SetLastError(ERROR_INVALID_HANDLE);
2398 goto end;
2399 }
2400
2401 if(Level != 1) {
2402 SetLastError(ERROR_INVALID_LEVEL);
2403 goto end;
2404 }
2405
2406 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2407 if(!job)
2408 goto end;
2409
2410 job->job_id = InterlockedIncrement(&next_job_id);
2411
2412 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2413 if(path[len - 1] != '\\')
2414 path[len++] = '\\';
2415 memcpy(path + len, spool_path, sizeof(spool_path));
2416 sprintfW(filename, fmtW, path, job->job_id);
2417
2418 len = strlenW(filename);
2419 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2420 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2421 job->document_title = strdupW(default_doc_title);
2422 list_add_tail(&printer->queue->jobs, &job->entry);
2423
2424 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2425 if(*pcbNeeded <= cbBuf) {
2426 addjob = (ADDJOB_INFO_1W*)pData;
2427 addjob->JobId = job->job_id;
2428 addjob->Path = (WCHAR *)(addjob + 1);
2429 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2430 ret = TRUE;
2431 } else
2432 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2433
2434 end:
2435 LeaveCriticalSection(&printer_handles_cs);
2436 return ret;
2437 }
2438
2439 /*****************************************************************************
2440 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2441 *
2442 * Return the PATH for the Print-Processors
2443 *
2444 * See GetPrintProcessorDirectoryW.
2445 *
2446 *
2447 */
2448 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2449 DWORD level, LPBYTE Info,
2450 DWORD cbBuf, LPDWORD pcbNeeded)
2451 {
2452 LPWSTR serverW = NULL;
2453 LPWSTR envW = NULL;
2454 BOOL ret;
2455 INT len;
2456
2457 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2458 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2459
2460
2461 if (server) {
2462 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2463 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2464 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2465 }
2466
2467 if (env) {
2468 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2469 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2471 }
2472
2473 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2474 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2475 */
2476 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2477 cbBuf, pcbNeeded);
2478
2479 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2480 cbBuf, NULL, NULL) > 0;
2481
2482
2483 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2484 HeapFree(GetProcessHeap(), 0, envW);
2485 HeapFree(GetProcessHeap(), 0, serverW);
2486 return ret;
2487 }
2488
2489 /*****************************************************************************
2490 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2491 *
2492 * Return the PATH for the Print-Processors
2493 *
2494 * PARAMS
2495 * server [I] Servername (NT only) or NULL (local Computer)
2496 * env [I] Printing-Environment (see below) or NULL (Default)
2497 * level [I] Structure-Level (must be 1)
2498 * Info [O] PTR to Buffer that receives the Result
2499 * cbBuf [I] Size of Buffer at "Info"
2500 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2501 * required for the Buffer at "Info"
2502 *
2503 * RETURNS
2504 * Success: TRUE and in pcbNeeded the Bytes used in Info
2505 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2506 * if cbBuf is too small
2507 *
2508 * Native Values returned in Info on Success:
2509 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2510 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2511 *| win9x(Windows 4.0): "%winsysdir%"
2512 *
2513 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2514 *
2515 * BUGS
2516 * Only NULL or "" is supported for server
2517 *
2518 */
2519 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2520 DWORD level, LPBYTE Info,
2521 DWORD cbBuf, LPDWORD pcbNeeded)
2522 {
2523 DWORD needed;
2524 const printenv_t * env_t;
2525
2526 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2527 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2528
2529 if(server != NULL && server[0]) {
2530 FIXME("server not supported: %s\n", debugstr_w(server));
2531 SetLastError(ERROR_INVALID_PARAMETER);
2532 return FALSE;
2533 }
2534
2535 env_t = validate_envW(env);
2536 if(!env_t) return FALSE; /* environment invalid or unsupported */
2537
2538 if(level != 1) {
2539 WARN("(Level: %d) is ignored in win9x\n", level);
2540 SetLastError(ERROR_INVALID_LEVEL);
2541 return FALSE;
2542 }
2543
2544 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2545 needed = GetSystemDirectoryW(NULL, 0);
2546 /* add the Size for the Subdirectories */
2547 needed += lstrlenW(spoolprtprocsW);
2548 needed += lstrlenW(env_t->subdir);
2549 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2550
2551 if(pcbNeeded) *pcbNeeded = needed;
2552 TRACE ("required: 0x%x/%d\n", needed, needed);
2553 if (needed > cbBuf) {
2554 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2555 return FALSE;
2556 }
2557 if(pcbNeeded == NULL) {
2558 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2559 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2560 SetLastError(RPC_X_NULL_REF_POINTER);
2561 return FALSE;
2562 }
2563 if(Info == NULL) {
2564 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2565 SetLastError(RPC_X_NULL_REF_POINTER);
2566 return FALSE;
2567 }
2568
2569 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2570 /* add the Subdirectories */
2571 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2572 lstrcatW((LPWSTR) Info, env_t->subdir);
2573 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2574 return TRUE;
2575 }
2576
2577 /*****************************************************************************
2578 * WINSPOOL_OpenDriverReg [internal]
2579 *
2580 * opens the registry for the printer drivers depending on the given input
2581 * variable pEnvironment
2582 *
2583 * RETURNS:
2584 * the opened hkey on success
2585 * NULL on error
2586 */
2587 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2588 {
2589 HKEY retval = NULL;
2590 LPWSTR buffer;
2591 const printenv_t * env;
2592
2593 TRACE("(%s, %d)\n",
2594 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2595
2596 if (!pEnvironment || unicode) {
2597 /* pEnvironment was NULL or a Unicode-String: use it direct */
2598 env = validate_envW(pEnvironment);
2599 }
2600 else
2601 {
2602 /* pEnvironment was an ANSI-String: convert to unicode first */
2603 LPWSTR buffer;
2604 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2605 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2606 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2607 env = validate_envW(buffer);
2608 HeapFree(GetProcessHeap(), 0, buffer);
2609 }
2610 if (!env) return NULL;
2611
2612 buffer = HeapAlloc( GetProcessHeap(), 0,
2613 (strlenW(DriversW) + strlenW(env->envname) +
2614 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2615 if(buffer) {
2616 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2617 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2618 HeapFree(GetProcessHeap(), 0, buffer);
2619 }
2620 return retval;
2621 }
2622
2623 /*****************************************************************************
2624 * AddPrinterW [WINSPOOL.@]
2625 */
2626 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2627 {
2628 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2629 LPDEVMODEA dmA;
2630 LPDEVMODEW dmW;
2631 HANDLE retval;
2632 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2633 LONG size;
2634 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2635 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2636 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2637 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2638 statusW[] = {'S','t','a','t','u','s',0},
2639 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2640
2641 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2642
2643 if(pName != NULL) {
2644 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2645 SetLastError(ERROR_INVALID_PARAMETER);
2646 return 0;
2647 }
2648 if(Level != 2) {
2649 ERR("Level = %d, unsupported!\n", Level);
2650 SetLastError(ERROR_INVALID_LEVEL);
2651 return 0;
2652 }
2653 if(!pPrinter) {
2654 SetLastError(ERROR_INVALID_PARAMETER);
2655 return 0;
2656 }
2657 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2658 ERROR_SUCCESS) {
2659 ERR("Can't create Printers key\n");
2660 return 0;
2661 }
2662 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2663 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2664 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2665 RegCloseKey(hkeyPrinter);
2666 RegCloseKey(hkeyPrinters);
2667 return 0;
2668 }
2669 RegCloseKey(hkeyPrinter);
2670 }
2671 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2672 if(!hkeyDrivers) {
2673 ERR("Can't create Drivers key\n");
2674 RegCloseKey(hkeyPrinters);
2675 return 0;
2676 }
2677 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2678 ERROR_SUCCESS) {
2679 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2680 RegCloseKey(hkeyPrinters);
2681 RegCloseKey(hkeyDrivers);
2682 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2683 return 0;
2684 }
2685 RegCloseKey(hkeyDriver);
2686 RegCloseKey(hkeyDrivers);
2687
2688 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2689 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2690 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2691 RegCloseKey(hkeyPrinters);
2692 return 0;
2693 }
2694
2695 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2696 ERROR_SUCCESS) {
2697 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2698 SetLastError(ERROR_INVALID_PRINTER_NAME);
2699 RegCloseKey(hkeyPrinters);
2700 return 0;
2701 }
2702 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2704 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2705
2706 /* See if we can load the driver. We may need the devmode structure anyway
2707 *
2708 * FIXME:
2709 * Note that DocumentPropertiesW will briefly try to open the printer we
2710 * just create to find a DEVMODEA struct (it will use the WINEPS default
2711 * one in case it is not there, so we are ok).
2712 */
2713 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2714
2715 if(size < 0) {
2716 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2717 size = sizeof(DEVMODEW);
2718 }
2719 if(pi->pDevMode)
2720 dmW = pi->pDevMode;
2721 else
2722 {
2723 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2724 dmW->dmSize = size;
2725 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2726 {
2727 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2728 HeapFree(GetProcessHeap(),0,dmW);
2729 dmW=NULL;
2730 }
2731 else
2732 {
2733 /* set devmode to printer name */
2734 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2735 }
2736 }
2737
2738 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2739 and we support these drivers. NT writes DEVMODEW so somehow
2740 we'll need to distinguish between these when we support NT
2741 drivers */
2742 if (dmW)
2743 {
2744 dmA = DEVMODEdupWtoA(dmW);
2745 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2746 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2747 HeapFree(GetProcessHeap(), 0, dmA);
2748 if(!pi->pDevMode)
2749 HeapFree(GetProcessHeap(), 0, dmW);
2750 }
2751 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2752 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2753 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2754 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2755
2756 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2757 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2758 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2759 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2760 (LPBYTE)&pi->Priority, sizeof(DWORD));
2761 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2762 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2763 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2764 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2765 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2766 (LPBYTE)&pi->Status, sizeof(DWORD));
2767 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2768 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2769
2770 RegCloseKey(hkeyPrinter);
2771 RegCloseKey(hkeyPrinters);
2772 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2773 ERR("OpenPrinter failing\n");
2774 return 0;
2775 }
2776 return retval;
2777 }
2778
2779 /*****************************************************************************
2780 * AddPrinterA [WINSPOOL.@]
2781 */
2782 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2783 {
2784 UNICODE_STRING pNameW;
2785 PWSTR pwstrNameW;
2786 PRINTER_INFO_2W *piW;
2787 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2788 HANDLE ret;
2789
2790 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2791 if(Level != 2) {
2792 ERR("Level = %d, unsupported!\n", Level);
2793 SetLastError(ERROR_INVALID_LEVEL);
2794 return 0;
2795 }
2796 pwstrNameW = asciitounicode(&pNameW,pName);
2797 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2798
2799 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2800
2801 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2802 RtlFreeUnicodeString(&pNameW);
2803 return ret;
2804 }
2805
2806
2807 /*****************************************************************************
2808 * ClosePrinter [WINSPOOL.@]
2809 */
2810 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2811 {
2812 UINT_PTR i = (UINT_PTR)hPrinter;
2813 opened_printer_t *printer = NULL;
2814 BOOL ret = FALSE;
2815
2816 TRACE("(%p)\n", hPrinter);
2817
2818 EnterCriticalSection(&printer_handles_cs);
2819
2820 if ((i > 0) && (i <= nb_printer_handles))
2821 printer = printer_handles[i - 1];
2822
2823
2824 if(printer)
2825 {
2826 struct list *cursor, *cursor2;
2827
2828 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2829
2830 if (printer->backend_printer) {
2831 backend->fpClosePrinter(printer->backend_printer);
2832 }
2833
2834 if(printer->doc)
2835 EndDocPrinter(hPrinter);
2836
2837 if(InterlockedDecrement(&printer->queue->ref) == 0)
2838 {
2839 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2840 {
2841 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2842 ScheduleJob(hPrinter, job->job_id);
2843 }
2844 HeapFree(GetProcessHeap(), 0, printer->queue);
2845 }
2846
2847 HeapFree(GetProcessHeap(), 0, printer->printername);
2848 HeapFree(GetProcessHeap(), 0, printer->name);
2849 HeapFree(GetProcessHeap(), 0, printer);
2850 printer_handles[i - 1] = NULL;
2851 ret = TRUE;
2852 }
2853 LeaveCriticalSection(&printer_handles_cs);
2854 return ret;
2855 }
2856
2857 /*****************************************************************************
2858 * DeleteFormA [WINSPOOL.@]
2859 */
2860 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2861 {
2862 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2863 return 1;
2864 }
2865
2866 /*****************************************************************************
2867 * DeleteFormW [WINSPOOL.@]
2868 */
2869 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2870 {
2871 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2872 return 1;
2873 }
2874
2875 /*****************************************************************************
2876 * DeletePrinter [WINSPOOL.@]
2877 */
2878 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2879 {
2880 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2881 HKEY hkeyPrinters, hkey;
2882
2883 if(!lpNameW) {
2884 SetLastError(ERROR_INVALID_HANDLE);
2885 return FALSE;
2886 }
2887 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2888 RegDeleteTreeW(hkeyPrinters, lpNameW);
2889 RegCloseKey(hkeyPrinters);
2890 }
2891 WriteProfileStringW(devicesW, lpNameW, NULL);
2892 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2893
2894 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2895 RegDeleteValueW(hkey, lpNameW);
2896 RegCloseKey(hkey);
2897 }
2898
2899 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2900 RegDeleteValueW(hkey, lpNameW);
2901 RegCloseKey(hkey);
2902 }
2903 return TRUE;
2904 }
2905
2906 /*****************************************************************************
2907 * SetPrinterA [WINSPOOL.@]
2908 */
2909 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2910 DWORD Command)
2911 {
2912 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2913 return FALSE;
2914 }
2915
2916 /*****************************************************************************
2917 * SetJobA [WINSPOOL.@]
2918 */
2919 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2920 LPBYTE pJob, DWORD Command)
2921 {
2922 BOOL ret;
2923 LPBYTE JobW;
2924 UNICODE_STRING usBuffer;
2925
2926 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2927
2928 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2929 are all ignored by SetJob, so we don't bother copying them */
2930 switch(Level)
2931 {
2932 case 0:
2933 JobW = NULL;
2934 break;
2935 case 1:
2936 {
2937 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2938 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2939
2940 JobW = (LPBYTE)info1W;
2941 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2942 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2943 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2944 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2945 info1W->Status = info1A->Status;
2946 info1W->Priority = info1A->Priority;
2947 info1W->Position = info1A->Position;
2948 info1W->PagesPrinted = info1A->PagesPrinted;
2949 break;
2950 }
2951 case 2:
2952 {
2953 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2954 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2955
2956 JobW = (LPBYTE)info2W;
2957 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2958 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2959 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2960 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2961 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2962 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2963 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2964 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2965 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2966 info2W->Status = info2A->Status;
2967 info2W->Priority = info2A->Priority;
2968 info2W->Position = info2A->Position;
2969 info2W->StartTime = info2A->StartTime;
2970 info2W->UntilTime = info2A->UntilTime;
2971 info2W->PagesPrinted = info2A->PagesPrinted;
2972 break;
2973 }
2974 case 3:
2975 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2976 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2977 break;
2978 default:
2979 SetLastError(ERROR_INVALID_LEVEL);
2980 return FALSE;
2981 }
2982
2983 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2984
2985 switch(Level)
2986 {
2987 case 1:
2988 {
2989 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2990 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2991 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2992 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2993 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2994 break;
2995 }
2996 case 2:
2997 {
2998 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2999 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3000 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3001 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3002 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3003 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3004 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3005 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3006 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3007 break;
3008 }
3009 }
3010 HeapFree(GetProcessHeap(), 0, JobW);
3011
3012 return ret;
3013 }
3014
3015 /*****************************************************************************
3016 * SetJobW [WINSPOOL.@]
3017 */
3018 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3019 LPBYTE pJob, DWORD Command)
3020 {
3021 BOOL ret = FALSE;
3022 job_t *job;
3023
3024 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3025 FIXME("Ignoring everything other than document title\n");
3026
3027 EnterCriticalSection(&printer_handles_cs);
3028 job = get_job(hPrinter, JobId);
3029 if(!job)
3030 goto end;
3031
3032 switch(Level)
3033 {
3034 case 0:
3035 break;
3036 case 1:
3037 {
3038 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3039 HeapFree(GetProcessHeap(), 0, job->document_title);
3040 job->document_title = strdupW(info1->pDocument);
3041 break;
3042 }
3043 case 2:
3044 {
3045 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3046 HeapFree(GetProcessHeap(), 0, job->document_title);
3047 job->document_title = strdupW(info2->pDocument);
3048 break;
3049 }
3050 case 3:
3051 break;
3052 default:
3053 SetLastError(ERROR_INVALID_LEVEL);
3054 goto end;
3055 }
3056 ret = TRUE;
3057 end:
3058 LeaveCriticalSection(&printer_handles_cs);
3059 return ret;
3060 }
3061
3062 /*****************************************************************************
3063 * EndDocPrinter [WINSPOOL.@]
3064 */
3065 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3066 {
3067 opened_printer_t *printer;
3068 BOOL ret = FALSE;
3069 TRACE("(%p)\n", hPrinter);
3070
3071 EnterCriticalSection(&printer_handles_cs);
3072
3073 printer = get_opened_printer(hPrinter);
3074 if(!printer)
3075 {
3076 SetLastError(ERROR_INVALID_HANDLE);
3077 goto end;
3078 }
3079
3080 if(!printer->doc)
3081 {
3082 SetLastError(ERROR_SPL_NO_STARTDOC);
3083 goto end;
3084 }
3085
3086 CloseHandle(printer->doc->hf);
3087 ScheduleJob(hPrinter, printer->doc->job_id);
3088 HeapFree(GetProcessHeap(), 0, printer->doc);
3089 printer->doc = NULL;
3090 ret = TRUE;
3091 end:
3092 LeaveCriticalSection(&printer_handles_cs);
3093 return ret;
3094 }
3095
3096 /*****************************************************************************
3097 * EndPagePrinter [WINSPOOL.@]
3098 */
3099 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3100 {
3101 FIXME("(%p): stub\n", hPrinter);
3102 return TRUE;
3103 }
3104
3105 /*****************************************************************************
3106 * StartDocPrinterA [WINSPOOL.@]
3107 */
3108 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3109 {
3110 UNICODE_STRING usBuffer;
3111 DOC_INFO_2W doc2W;
3112 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3113 DWORD ret;
3114
3115 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3116 or one (DOC_INFO_3) extra DWORDs */
3117
3118 switch(Level) {
3119 case 2:
3120 doc2W.JobId = doc2->JobId;
3121 /* fall through */
3122 case 3:
3123 doc2W.dwMode = doc2->dwMode;
3124 /* fall through */
3125 case 1:
3126 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3127 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3128 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3129 break;
3130
3131 default:
3132 SetLastError(ERROR_INVALID_LEVEL);
3133 return FALSE;
3134 }
3135
3136 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3137
3138 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3139 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3140 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3141
3142 return ret;
3143 }
3144
3145 /*****************************************************************************
3146 * StartDocPrinterW [WINSPOOL.@]
3147 */
3148 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3149 {
3150 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3151 opened_printer_t *printer;
3152 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3153 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3154 JOB_INFO_1W job_info;
3155 DWORD needed, ret = 0;
3156 HANDLE hf;
3157 WCHAR *filename;
3158
3159 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3160 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3161 debugstr_w(doc->pDatatype));
3162
3163 if(Level < 1 || Level > 3)
3164 {
3165 SetLastError(ERROR_INVALID_LEVEL);
3166 return 0;
3167 }
3168
3169 EnterCriticalSection(&printer_handles_cs);
3170 printer = get_opened_printer(hPrinter);
3171 if(!printer)
3172 {
3173 SetLastError(ERROR_INVALID_HANDLE);
3174 goto end;
3175 }
3176
3177 if(printer->doc)
3178 {
3179 SetLastError(ERROR_INVALID_PRINTER_STATE);
3180 goto end;
3181 }
3182
3183 /* Even if we're printing to a file we still add a print job, we'll
3184 just ignore the spool file name */
3185
3186 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3187 {
3188 ERR("AddJob failed gle %u\n", GetLastError());
3189 goto end;
3190 }
3191
3192 if(doc->pOutputFile)
3193 filename = doc->pOutputFile;
3194 else
3195 filename = addjob->Path;
3196
3197 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3198 if(hf == INVALID_HANDLE_VALUE)
3199 goto end;
3200
3201 memset(&job_info, 0, sizeof(job_info));
3202 job_info.pDocument = doc->pDocName;
3203 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3204
3205 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3206 printer->doc->hf = hf;
3207 ret = printer->doc->job_id = addjob->JobId;
3208 end:
3209 LeaveCriticalSection(&printer_handles_cs);
3210
3211 return ret;
3212 }
3213
3214 /*****************************************************************************
3215 * StartPagePrinter [WINSPOOL.@]
3216 */
3217 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3218 {
3219 FIXME("(%p): stub\n", hPrinter);
3220 return TRUE;
3221 }
3222
3223 /*****************************************************************************
3224 * GetFormA [WINSPOOL.@]
3225 */
3226 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3227 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3228 {
3229 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3230 Level,pForm,cbBuf,pcbNeeded);
3231 return FALSE;
3232 }
3233
3234 /*****************************************************************************
3235 * GetFormW [WINSPOOL.@]
3236 */
3237 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3238 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3239 {
3240 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3241 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3242 return FALSE;
3243 }
3244
3245 /*****************************************************************************
3246 * SetFormA [WINSPOOL.@]
3247 */
3248 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3249 LPBYTE pForm)
3250 {
3251 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3252 return FALSE;
3253 }
3254
3255 /*****************************************************************************
3256 * SetFormW [WINSPOOL.@]
3257 */
3258 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3259 LPBYTE pForm)
3260 {
3261 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3262 return FALSE;
3263 }
3264
3265 /*****************************************************************************
3266 * ReadPrinter [WINSPOOL.@]
3267 */
3268 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3269 LPDWORD pNoBytesRead)
3270 {
3271 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3272 return FALSE;
3273 }
3274
3275 /*****************************************************************************
3276 * ResetPrinterA [WINSPOOL.@]
3277 */
3278 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3279 {
3280 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3281 return FALSE;
3282 }
3283
3284 /*****************************************************************************
3285 * ResetPrinterW [WINSPOOL.@]
3286 */
3287 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3288 {
3289 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3290 return FALSE;
3291 }
3292
3293 /*****************************************************************************
3294 * WINSPOOL_GetDWORDFromReg
3295 *
3296 * Return DWORD associated with ValueName from hkey.
3297 */
3298 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3299 {
3300 DWORD sz = sizeof(DWORD), type, value = 0;
3301 LONG ret;
3302
3303 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3304
3305 if(ret != ERROR_SUCCESS) {
3306 WARN("Got ret = %d on name %s\n", ret, ValueName);
3307 return 0;
3308 }
3309 if(type != REG_DWORD) {
3310 ERR("Got type %d\n", type);
3311 return 0;
3312 }
3313 return value;
3314 }
3315
3316
3317 /*****************************************************************************
3318 * get_filename_from_reg [internal]
3319 *
3320 * Get ValueName from hkey storing result in out
3321 * when the Value in the registry has only a filename, use driverdir as prefix
3322 * outlen is space left in out
3323 * String is stored either as unicode or ascii
3324 *
3325 */
3326
3327 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3328 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3329 {
3330 WCHAR filename[MAX_PATH];
3331 DWORD size;
3332 DWORD type;
3333 LONG ret;
3334 LPWSTR buffer = filename;
3335 LPWSTR ptr;
3336
3337 *needed = 0;
3338 size = sizeof(filename);
3339 buffer[0] = '\0';
3340 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3341 if (ret == ERROR_MORE_DATA) {
3342 TRACE("need dynamic buffer: %u\n", size);
3343 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3344 if (!buffer) {
3345 /* No Memory is bad */
3346 return FALSE;
3347 }
3348 buffer[0] = '\0';
3349 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3350 }
3351
3352 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3353 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3354 return FALSE;
3355 }
3356
3357 ptr = buffer;
3358 while (ptr) {
3359 /* do we have a full path ? */
3360 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3361 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3362
3363 if (!ret) {
3364 /* we must build the full Path */
3365 *needed += dirlen;
3366 if ((out) && (outlen > dirlen)) {
3367 if (unicode) {
3368 lstrcpyW((LPWSTR)out, driverdir);
3369 }
3370 else
3371 {
3372 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3373 }
3374 out += dirlen;
3375 outlen -= dirlen;
3376 }
3377 else
3378 out = NULL;
3379 }
3380
3381 /* write the filename */
3382 if (unicode) {
3383 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3384 if ((out) && (outlen >= size)) {
3385 lstrcpyW((LPWSTR)out, ptr);
3386 out += size;
3387 outlen -= size;
3388 }
3389 else
3390 out = NULL;
3391 }
3392 else
3393 {
3394 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3395 if ((out) && (outlen >= size)) {
3396 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3397 out += size;
3398 outlen -= size;
3399 }
3400 else
3401 out = NULL;
3402 }
3403 *needed += size;
3404 ptr += lstrlenW(ptr)+1;
3405 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3406 }
3407
3408 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3409
3410 /* write the multisz-termination */
3411 if (type == REG_MULTI_SZ) {
3412 size = (unicode) ? sizeof(WCHAR) : 1;
3413
3414 *needed += size;
3415 if (out && (outlen >= size)) {
3416 memset (out, 0, size);
3417 }
3418 }
3419 return TRUE;
3420 }
3421
3422 /*****************************************************************************
3423 * WINSPOOL_GetStringFromReg
3424 *
3425 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3426 * String is stored either as unicode or ascii.
3427 * Bit of a hack here to get the ValueName if we want ascii.
3428 */
3429 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3430 DWORD buflen, DWORD *needed,
3431 BOOL unicode)
3432 {
3433 DWORD sz = buflen, type;
3434 LONG ret;
3435
3436 if(unicode)
3437 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3438 else {
3439 LPSTR ValueNameA = strdupWtoA(ValueName);
3440 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3441 HeapFree(GetProcessHeap(),0,ValueNameA);
3442 }
3443 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3444 WARN("Got ret = %d\n", ret);
3445 *needed = 0;
3446 return FALSE;
3447 }
3448 /* add space for terminating '\0' */
3449 sz += unicode ? sizeof(WCHAR) : 1;
3450 *needed = sz;
3451
3452 if (ptr)
3453 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3454
3455 return TRUE;
3456 }
3457
3458 /*****************************************************************************
3459 * WINSPOOL_GetDefaultDevMode
3460 *
3461 * Get a default DevMode values for wineps.
3462 * FIXME - use ppd.
3463 */
3464
3465 static void WINSPOOL_GetDefaultDevMode(
3466 LPBYTE ptr,
3467 DWORD buflen, DWORD *needed,
3468 BOOL unicode)
3469 {
3470 DEVMODEA dm;
3471 static const char szwps[] = "wineps.drv";
3472
3473 /* fill default DEVMODE - should be read from ppd... */
3474 ZeroMemory( &dm, sizeof(dm) );
3475 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3476 dm.dmSpecVersion = DM_SPECVERSION;
3477 dm.dmDriverVersion = 1;
3478 dm.dmSize = sizeof(DEVMODEA);
3479 dm.dmDriverExtra = 0;
3480 dm.dmFields =
3481 DM_ORIENTATION | DM_PAPERSIZE |
3482 DM_PAPERLENGTH | DM_PAPERWIDTH |
3483 DM_SCALE |
3484 DM_COPIES |
3485 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3486 DM_YRESOLUTION | DM_TTOPTION;
3487
3488 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3489 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3490 dm.u1.s1.dmPaperLength = 2970;
3491 dm.u1.s1.dmPaperWidth = 2100;
3492
3493 dm.u1.s1.dmScale = 100;
3494 dm.u1.s1.dmCopies = 1;
3495 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3496 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3497 /* dm.dmColor */
3498 /* dm.dmDuplex */
3499 dm.dmYResolution = 300; /* 300dpi */
3500 dm.dmTTOption = DMTT_BITMAP;
3501 /* dm.dmCollate */
3502 /* dm.dmFormName */
3503 /* dm.dmLogPixels */
3504 /* dm.dmBitsPerPel */
3505 /* dm.dmPelsWidth */
3506 /* dm.dmPelsHeight */
3507 /* dm.u2.dmDisplayFlags */
3508 /* dm.dmDisplayFrequency */
3509 /* dm.dmICMMethod */
3510 /* dm.dmICMIntent */
3511 /* dm.dmMediaType */
3512 /* dm.dmDitherType */
3513 /* dm.dmReserved1 */
3514 /* dm.dmReserved2 */
3515 /* dm.dmPanningWidth */
3516 /* dm.dmPanningHeight */
3517
3518 if(unicode) {
3519 if(buflen >= sizeof(DEVMODEW)) {
3520 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3521 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3522 HeapFree(GetProcessHeap(),0,pdmW);
3523 }
3524 *needed = sizeof(DEVMODEW);
3525 }
3526 else
3527 {
3528 if(buflen >= sizeof(DEVMODEA)) {
3529 memcpy(ptr, &dm, sizeof(DEVMODEA));
3530 }
3531 *needed = sizeof(DEVMODEA);
3532 }
3533 }
3534
3535 /*****************************************************************************
3536 * WINSPOOL_GetDevModeFromReg
3537 *
3538 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3539 * DevMode is stored either as unicode or ascii.
3540 */
3541 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3542 LPBYTE ptr,
3543 DWORD buflen, DWORD *needed,
3544 BOOL unicode)
3545 {
3546 DWORD sz = buflen, type;
3547 LONG ret;
3548
3549 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3550 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3551 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3552 if (sz < sizeof(DEVMODEA))
3553 {
3554 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3555 return FALSE;
3556 }
3557 /* ensures that dmSize is not erratically bogus if registry is invalid */
3558 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3559 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3560 if(unicode) {
3561 sz += (CCHDEVICENAME + CCHFORMNAME);
3562 if(buflen >= sz) {
3563 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3564 memcpy(ptr, dmW, sz);
3565 HeapFree(GetProcessHeap(),0,dmW);
3566 }
3567 }
3568 *needed = sz;
3569 return TRUE;
3570 }
3571
3572 /*********************************************************************
3573 * WINSPOOL_GetPrinter_1
3574 *
3575 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3576 * The strings are either stored as unicode or ascii.
3577 */
3578 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3580 BOOL unicode)
3581 {
3582 DWORD size, left = cbBuf;
3583 BOOL space = (cbBuf > 0);
3584 LPBYTE ptr = buf;
3585
3586 *pcbNeeded = 0;
3587
3588 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3589 unicode)) {
3590 if(space && size <= left) {
3591 pi1->pName = (LPWSTR)ptr;
3592 ptr += size;
3593 left -= size;
3594 } else
3595 space = FALSE;
3596 *pcbNeeded += size;
3597 }
3598
3599 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3600 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3601 unicode)) {
3602 if(space && size <= left) {
3603 pi1->pDescription = (LPWSTR)ptr;
3604 ptr += size;
3605 left -= size;
3606 } else
3607 space = FALSE;
3608 *pcbNeeded += size;
3609 }
3610
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3612 unicode)) {
3613 if(space && size <= left) {
3614 pi1->pComment = (LPWSTR)ptr;
3615 ptr += size;
3616 left -= size;
3617 } else
3618 space = FALSE;
3619 *pcbNeeded += size;
3620 }
3621
3622 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3623
3624 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3625 memset(pi1, 0, sizeof(*pi1));
3626
3627 return space;
3628 }
3629 /*********************************************************************
3630 * WINSPOOL_GetPrinter_2
3631 *
3632 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3633 * The strings are either stored as unicode or ascii.
3634 */
3635 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3636 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3637 BOOL unicode)
3638 {
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3641 LPBYTE ptr = buf;
3642
3643 *pcbNeeded = 0;
3644
3645 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3646 unicode)) {
3647 if(space && size <= left) {
3648 pi2->pPrinterName = (LPWSTR)ptr;
3649 ptr += size;
3650 left -= size;
3651 } else
3652 space = FALSE;
3653 *pcbNeeded += size;
3654 }
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3656 unicode)) {
3657 if(space && size <= left) {
3658 pi2->pShareName = (LPWSTR)ptr;
3659 ptr += size;
3660 left -= size;
3661 } else
3662 space = FALSE;
3663 *pcbNeeded += size;
3664 }
3665 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3666 unicode)) {
3667 if(space && size <= left) {
3668 pi2->pPortName = (LPWSTR)ptr;
3669 ptr += size;
3670 left -= size;
3671 } else
3672 space = FALSE;
3673 *pcbNeeded += size;
3674 }
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3676 &size, unicode)) {
3677 if(space && size <= left) {
3678 pi2->pDriverName = (LPWSTR)ptr;
3679 ptr += size;
3680 left -= size;
3681 } else
3682 space = FALSE;
3683 *pcbNeeded += size;
3684 }
3685 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3686 unicode)) {
3687 if(space && size <= left) {
3688 pi2->pComment = (LPWSTR)ptr;
3689 ptr += size;
3690 left -= size;
3691 } else
3692 space = FALSE;
3693 *pcbNeeded += size;
3694 }
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3696 unicode)) {
3697 if(space && size <= left) {
3698 pi2->pLocation = (LPWSTR)ptr;
3699 ptr += size;
3700 left -= size;
3701 } else
3702 space = FALSE;
3703 *pcbNeeded += size;
3704 }
3705 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3706 &size, unicode)) {
3707 if(space && size <= left) {
3708 pi2->pDevMode = (LPDEVMODEW)ptr;
3709 ptr += size;
3710 left -= size;
3711 } else
3712 space = FALSE;
3713 *pcbNeeded += size;
3714 }
3715 else
3716 {
3717 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3718 if(space && size <= left) {
3719 pi2->pDevMode = (LPDEVMODEW)ptr;
3720 ptr += size;
3721 left -= size;
3722 } else
3723 space = FALSE;
3724 *pcbNeeded += size;
3725 }
3726 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3727 &size, unicode)) {
3728 if(space && size <= left) {
3729 pi2->pSepFile = (LPWSTR)ptr;
3730 ptr += size;
3731 left -= size;
3732 } else
3733 space = FALSE;
3734 *pcbNeeded += size;
3735 }
3736 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3737 &size, unicode)) {
3738 if(space && size <= left) {
3739 pi2->pPrintProcessor = (LPWSTR)ptr;
3740 ptr += size;
3741 left -= size;
3742 } else
3743 space = FALSE;
3744 *pcbNeeded += size;
3745 }
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3747 &size, unicode)) {
3748 if(space && size <= left) {
3749 pi2->pDatatype = (LPWSTR)ptr;
3750 ptr += size;
3751 left -= size;
3752 } else
3753 space = FALSE;
3754 *pcbNeeded += size;
3755 }
3756 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3757 &size, unicode)) {
3758 if(space && size <= left) {
3759 pi2->pParameters = (LPWSTR)ptr;
3760 ptr += size;
3761 left -= size;
3762 } else
3763 space = FALSE;
3764 *pcbNeeded += size;
3765 }
3766 if(pi2) {
3767 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3768 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3769 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3770 "Default Priority");
3771 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3772 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3773 }
3774
3775 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3776 memset(pi2, 0, sizeof(*pi2));
3777
3778 return space;
3779 }
3780
3781 /*********************************************************************
3782 * WINSPOOL_GetPrinter_4
3783 *
3784 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3785 */
3786 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3787 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3788 BOOL unicode)
3789 {
3790 DWORD size, left = cbBuf;
3791 BOOL space = (cbBuf > 0);
3792 LPBYTE ptr = buf;
3793
3794 *pcbNeeded = 0;
3795
3796 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3797 unicode)) {
3798 if(space && size <= left) {
3799 pi4->pPrinterName = (LPWSTR)ptr;
3800 ptr += size;
3801 left -= size;
3802 } else
3803 space = FALSE;
3804 *pcbNeeded += size;
3805 }
3806 if(pi4) {
3807 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3808 }
3809
3810 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3811 memset(pi4, 0, sizeof(*pi4));
3812
3813 return space;
3814 }
3815
3816 /*********************************************************************
3817 * WINSPOOL_GetPrinter_5
3818 *
3819 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3820 */
3821 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3822 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3823 BOOL unicode)
3824 {
3825 DWORD size, left = cbBuf;
3826 BOOL space = (cbBuf > 0);