localspl: Add partial support for PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS attribute.
[wine.git] / dlls / localspl / provider.c
blob9e990c75e0f0f704e5d216bfc84b7f94a9d85b5a
1 /*
2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winnls.h"
31 #include "winspool.h"
32 #include "winuser.h"
33 #include "ddk/winddiui.h"
34 #include "ddk/winsplp.h"
36 #include "wine/debug.h"
37 #include "wine/list.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
42 static const struct builtin_form
44 const WCHAR *name;
45 SIZEL size;
46 DWORD res_id;
47 } builtin_forms[] =
49 { L"Letter", { 215900, 279400 }, IDS_FORM_LETTER },
50 { L"Letter Small", { 215900, 279400 }, IDS_FORM_LETTER_SMALL },
51 { L"Tabloid", { 279400, 431800 }, IDS_FORM_TABLOID },
52 { L"Ledger", { 431800, 279400 }, IDS_FORM_LEDGER },
53 { L"Legal", { 215900, 355600 }, IDS_FORM_LEGAL },
54 { L"Statement", { 139700, 215900 }, IDS_FORM_STATEMENT },
55 { L"Executive", { 184150, 266700 }, IDS_FORM_EXECUTIVE },
56 { L"A3", { 297000, 420000 }, IDS_FORM_A3 },
57 { L"A4", { 210000, 297000 }, IDS_FORM_A4 },
58 { L"A4 Small", { 210000, 297000 }, IDS_FORM_A4_SMALL },
59 { L"A5", { 148000, 210000 }, IDS_FORM_A5 },
60 { L"B4 (JIS)", { 257000, 364000 }, IDS_FORM_B4_JIS },
61 { L"B5 (JIS)", { 182000, 257000 }, IDS_FORM_B5_JIS },
62 { L"Folio", { 215900, 330200 }, IDS_FORM_FOLIO },
63 { L"Quarto", { 215000, 275000 }, IDS_FORM_QUARTO },
64 { L"10x14", { 254000, 355600 }, IDS_FORM_10x14 },
65 { L"11x17", { 279400, 431800 }, IDS_FORM_11x17 },
66 { L"Note", { 215900, 279400 }, IDS_FORM_NOTE },
67 { L"Envelope #9", { 98425, 225425 }, IDS_FORM_ENVELOPE_9 },
68 { L"Envelope #10", { 104775, 241300 }, IDS_FORM_ENVELOPE_10 },
69 { L"Envelope #11", { 114300, 263525 }, IDS_FORM_ENVELOPE_11 },
70 { L"Envelope #12", { 120650, 279400 }, IDS_FORM_ENVELOPE_12 },
71 { L"Envelope #14", { 127000, 292100 }, IDS_FORM_ENVELOPE_14 },
72 { L"C size sheet", { 431800, 558800 }, IDS_FORM_C_SIZE_SHEET },
73 { L"D size sheet", { 558800, 863600 }, IDS_FORM_D_SIZE_SHEET },
74 { L"E size sheet", { 863600, 1117600 }, IDS_FORM_E_SIZE_SHEET },
75 { L"Envelope DL", { 110000, 220000 }, IDS_FORM_ENVELOPE_DL },
76 { L"Envelope C5", { 162000, 229000 }, IDS_FORM_ENVELOPE_C5 },
77 { L"Envelope C3", { 324000, 458000 }, IDS_FORM_ENVELOPE_C3 },
78 { L"Envelope C4", { 229000, 324000 }, IDS_FORM_ENVELOPE_C4 },
79 { L"Envelope C6", { 114000, 162000 }, IDS_FORM_ENVELOPE_C6 },
80 { L"Envelope C65", { 114000, 229000 }, IDS_FORM_ENVELOPE_C65 },
81 { L"Envelope B4", { 250000, 353000 }, IDS_FORM_ENVELOPE_B4 },
82 { L"Envelope B5", { 176000, 250000 }, IDS_FORM_ENVELOPE_B5 },
83 { L"Envelope B6", { 176000, 125000 }, IDS_FORM_ENVELOPE_B6 },
84 { L"Envelope", { 110000, 230000 }, IDS_FORM_ENVELOPE },
85 { L"Envelope Monarch", { 98425, 190500 }, IDS_FORM_ENVELOPE_MONARCH },
86 { L"6 3/4 Envelope", { 92075, 165100 }, IDS_FORM_6_34_ENVELOPE },
87 { L"US Std Fanfold", { 377825, 279400 }, IDS_FORM_US_STD_FANFOLD },
88 { L"German Std Fanfold", { 215900, 304800 }, IDS_FORM_GERMAN_STD_FANFOLD },
89 { L"German Legal Fanfold", { 215900, 330200 }, IDS_FORM_GERMAN_LEGAL_FANFOLD },
90 { L"B4 (ISO)", { 250000, 353000 }, IDS_FORM_B4_ISO },
91 { L"Japanese Postcard", { 100000, 148000 }, IDS_FORM_JAPANESE_POSTCARD },
92 { L"9x11", { 228600, 279400 }, IDS_FORM_9x11 },
93 { L"10x11", { 254000, 279400 }, IDS_FORM_10x11 },
94 { L"15x11", { 381000, 279400 }, IDS_FORM_15x11 },
95 { L"Envelope Invite", { 220000, 220000 }, IDS_FORM_ENVELOPE_INVITE },
96 { L"Letter Extra", { 241300, 304800 }, IDS_FORM_LETTER_EXTRA },
97 { L"Legal Extra", { 241300, 381000 }, IDS_FORM_LEGAL_EXTRA },
98 { L"Tabloid Extra", { 304800, 457200 }, IDS_FORM_TABLOID_EXTRA },
99 { L"A4 Extra", { 235458, 322326 }, IDS_FORM_A4_EXTRA },
100 { L"Letter Transverse", { 215900, 279400 }, IDS_FORM_LETTER_TRANSVERSE },
101 { L"A4 Transverse", { 210000, 297000 }, IDS_FORM_A4_TRANSVERSE },
102 { L"Letter Extra Transverse", { 241300, 304800 }, IDS_FORM_LETTER_EXTRA_TRANSVERSE },
103 { L"Super A", { 227000, 356000 }, IDS_FORM_SUPER_A },
104 { L"Super B", { 305000, 487000 }, IDS_FORM_SUPER_B },
105 { L"Letter Plus", { 215900, 322326 }, IDS_FORM_LETTER_PLUS },
106 { L"A4 Plus", { 210000, 330000 }, IDS_FORM_A4_PLUS },
107 { L"A5 Transverse", { 148000, 210000 }, IDS_FORM_A5_TRANSVERSE },
108 { L"B5 (JIS) Transverse", { 182000, 257000 }, IDS_FORM_B5_JIS_TRANSVERSE },
109 { L"A3 Extra", { 322000, 445000 }, IDS_FORM_A3_EXTRA },
110 { L"A5 Extra", { 174000, 235000 }, IDS_FORM_A5_EXTRA },
111 { L"B5 (ISO) Extra", { 201000, 276000 }, IDS_FORM_B5_ISO_EXTRA },
112 { L"A2", { 420000, 594000 }, IDS_FORM_A2 },
113 { L"A3 Transverse", { 297000, 420000 }, IDS_FORM_A3_TRANSVERSE },
114 { L"A3 Extra Transverse", { 322000, 445000 }, IDS_FORM_A3_EXTRA_TRANSVERSE },
115 { L"Japanese Double Postcard", { 200000, 148000 }, IDS_FORM_JAPANESE_DOUBLE_POSTCARD },
116 { L"A6", { 105000, 148000 }, IDS_FORM_A6 },
117 { L"Japanese Envelope Kaku #2", { 240000, 332000 }, IDS_FORM_JAPANESE_ENVELOPE_KAKU_2 },
118 { L"Japanese Envelope Kaku #3", { 216000, 277000 }, IDS_FORM_JAPANESE_ENVELOPE_KAKU_3 },
119 { L"Japanese Envelope Chou #3", { 120000, 235000 }, IDS_FORM_JAPANESE_ENVELOPE_CHOU_3 },
120 { L"Japanese Envelope Chou #4", { 90000, 205000 }, IDS_FORM_JAPANESE_ENVELOPE_CHOU_4 },
121 { L"Letter Rotated", { 279400, 215900 }, IDS_FORM_LETTER_ROTATED },
122 { L"A3 Rotated", { 420000, 297000 }, IDS_FORM_A3_ROTATED },
123 { L"A4 Rotated", { 297000, 210000 }, IDS_FORM_A4_ROTATED },
124 { L"A5 Rotated", { 210000, 148000 }, IDS_FORM_A5_ROTATED },
125 { L"B4 (JIS) Rotated", { 364000, 257000 }, IDS_FORM_B4_JIS_ROTATED },
126 { L"B5 (JIS) Rotated", { 257000, 182000 }, IDS_FORM_B5_JIS_ROTATED },
127 { L"Japanese Postcard Rotated", { 148000, 100000 }, IDS_FORM_JAPANESE_POSTCARD_ROTATED },
128 { L"Double Japan Postcard Rotated", { 148000, 200000 }, IDS_FORM_DOUBLE_JAPAN_POSTCARD_ROTATED },
129 { L"A6 Rotated", { 148000, 105000 }, IDS_FORM_A6_ROTATED },
130 { L"Japan Envelope Kaku #2 Rotated", { 332000, 240000 }, IDS_FORM_JAPAN_ENVELOPE_KAKU_2_ROTATED },
131 { L"Japan Envelope Kaku #3 Rotated", { 277000, 216000 }, IDS_FORM_JAPAN_ENVELOPE_KAKU_3_ROTATED },
132 { L"Japan Envelope Chou #3 Rotated", { 235000, 120000 }, IDS_FORM_JAPAN_ENVELOPE_CHOU_3_ROTATED },
133 { L"Japan Envelope Chou #4 Rotated", { 205000, 90000 }, IDS_FORM_JAPAN_ENVELOPE_CHOU_4_ROTATED },
134 { L"B6 (JIS)", { 128000, 182000 }, IDS_FORM_B6_JIS },
135 { L"B6 (JIS) Rotated", { 182000, 128000 }, IDS_FORM_B6_JIS_ROTATED },
136 { L"12x11", { 304932, 279521 }, IDS_FORM_12x11 },
137 { L"Japan Envelope You #4", { 105000, 235000 }, IDS_FORM_JAPAN_ENVELOPE_YOU_4 },
138 { L"Japan Envelope You #4 Rotated", { 235000, 105000 }, IDS_FORM_JAPAN_ENVELOPE_YOU_4_ROTATED },
139 { L"PRC 16K", { 188000, 260000 }, IDS_FORM_PRC_16K },
140 { L"PRC 32K", { 130000, 184000 }, IDS_FORM_PRC_32K },
141 { L"PRC 32K(Big)", { 140000, 203000 }, IDS_FORM_PRC_32K_BIG },
142 { L"PRC Envelope #1", { 102000, 165000 }, IDS_FORM_PRC_ENVELOPE_1 },
143 { L"PRC Envelope #2", { 102000, 176000 }, IDS_FORM_PRC_ENVELOPE_2 },
144 { L"PRC Envelope #3", { 125000, 176000 }, IDS_FORM_PRC_ENVELOPE_3 },
145 { L"PRC Envelope #4", { 110000, 208000 }, IDS_FORM_PRC_ENVELOPE_4 },
146 { L"PRC Envelope #5", { 110000, 220000 }, IDS_FORM_PRC_ENVELOPE_5 },
147 { L"PRC Envelope #6", { 120000, 230000 }, IDS_FORM_PRC_ENVELOPE_6 },
148 { L"PRC Envelope #7", { 160000, 230000 }, IDS_FORM_PRC_ENVELOPE_7 },
149 { L"PRC Envelope #8", { 120000, 309000 }, IDS_FORM_PRC_ENVELOPE_8 },
150 { L"PRC Envelope #9", { 229000, 324000 }, IDS_FORM_PRC_ENVELOPE_9 },
151 { L"PRC Envelope #10", { 324000, 458000 }, IDS_FORM_PRC_ENVELOPE_10 },
152 { L"PRC 16K Rotated", { 260000, 188000 }, IDS_FORM_PRC_16K_ROTATED },
153 { L"PRC 32K Rotated", { 184000, 130000 }, IDS_FORM_PRC_32K_ROTATED },
154 { L"PRC 32K(Big) Rotated", { 203000, 140000 }, IDS_FORM_PRC_32K_BIG_ROTATED },
155 { L"PRC Envelope #1 Rotated", { 165000, 102000 }, IDS_FORM_PRC_ENVELOPE_1_ROTATED },
156 { L"PRC Envelope #2 Rotated", { 176000, 102000 }, IDS_FORM_PRC_ENVELOPE_2_ROTATED },
157 { L"PRC Envelope #3 Rotated", { 176000, 125000 }, IDS_FORM_PRC_ENVELOPE_3_ROTATED },
158 { L"PRC Envelope #4 Rotated", { 208000, 110000 }, IDS_FORM_PRC_ENVELOPE_4_ROTATED },
159 { L"PRC Envelope #5 Rotated", { 220000, 110000 }, IDS_FORM_PRC_ENVELOPE_5_ROTATED },
160 { L"PRC Envelope #6 Rotated", { 230000, 120000 }, IDS_FORM_PRC_ENVELOPE_6_ROTATED },
161 { L"PRC Envelope #7 Rotated", { 230000, 160000 }, IDS_FORM_PRC_ENVELOPE_7_ROTATED },
162 { L"PRC Envelope #8 Rotated", { 309000, 120000 }, IDS_FORM_PRC_ENVELOPE_8_ROTATED },
163 { L"PRC Envelope #9 Rotated", { 324000, 229000 }, IDS_FORM_PRC_ENVELOPE_9_ROTATED },
164 { L"PRC Envelope #10 Rotated", { 458000, 324000 }, IDS_FORM_PRC_ENVELOPE_10_ROTATED }
168 /* ############################### */
170 static CRITICAL_SECTION monitor_handles_cs;
171 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
173 0, 0, &monitor_handles_cs,
174 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
175 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
177 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
179 static CRITICAL_SECTION printers_cs;
180 static CRITICAL_SECTION_DEBUG printers_cs_debug =
182 0, 0, &printers_cs,
183 { &printers_cs_debug.ProcessLocksList, &printers_cs_debug.ProcessLocksList },
184 0, 0, { (DWORD_PTR)(__FILE__ ": printers_cs") }
186 static CRITICAL_SECTION printers_cs = { &printers_cs_debug, -1, 0, 0, 0, 0 };
188 /* ############################### */
190 typedef struct {
191 WCHAR src[MAX_PATH+MAX_PATH];
192 WCHAR dst[MAX_PATH+MAX_PATH];
193 DWORD srclen;
194 DWORD dstlen;
195 DWORD copyflags;
196 BOOL lazy;
197 } apd_data_t;
199 typedef struct {
200 struct list entry;
201 LPWSTR name;
202 LPWSTR dllname;
203 PMONITORUI monitorUI;
204 MONITOR2 monitor;
205 const MONITOREX *monitorex;
206 HANDLE hmon;
207 HMODULE hdll;
208 DWORD refcount;
209 } monitor_t;
211 typedef struct {
212 LPCWSTR envname;
213 LPCWSTR subdir;
214 DWORD driverversion;
215 LPCWSTR versionregpath;
216 LPCWSTR versionsubdir;
217 } printenv_t;
219 #define MAX_JOB_ID 99999
221 typedef struct {
222 struct list entry;
223 DWORD id;
224 WCHAR *filename;
225 WCHAR *port;
226 WCHAR *datatype;
227 WCHAR *document_title;
228 DEVMODEW *devmode;
229 HANDLE hf;
230 } job_info_t;
232 typedef struct {
233 WCHAR *name;
234 struct list entry;
235 LONG ref;
237 WCHAR *port;
238 WCHAR *print_proc;
239 WCHAR *datatype;
240 DWORD attributes;
242 CRITICAL_SECTION jobs_cs;
243 struct list jobs;
244 } printer_info_t;
246 typedef struct {
247 enum
249 HANDLE_SERVER,
250 HANDLE_PRINTER,
251 HANDLE_XCV,
252 HANDLE_PORT,
253 HANDLE_JOB,
254 } type;
255 } handle_header_t;
257 typedef handle_header_t server_t;
259 typedef struct {
260 handle_header_t header;
261 monitor_t *pm;
262 HANDLE hxcv;
263 } xcv_t;
265 typedef struct {
266 handle_header_t header;
267 monitor_t *mon;
268 HANDLE hport;
269 } port_t;
271 typedef struct {
272 handle_header_t header;
273 HANDLE hf;
274 } job_t;
276 typedef struct {
277 handle_header_t header;
278 printer_info_t *info;
279 WCHAR *name;
280 WCHAR *datatype;
281 DEVMODEW *devmode;
282 job_info_t *doc;
283 } printer_t;
285 /* ############################### */
287 static struct list monitor_handles = LIST_INIT( monitor_handles );
288 static monitor_t * pm_localport;
290 static struct list printers = LIST_INIT(printers);
291 static LONG last_job_id;
293 static const WCHAR fmt_driversW[] =
294 L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
295 static const WCHAR fmt_printprocessorsW[] =
296 L"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors\\";
297 static const WCHAR monitorsW[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
298 static const WCHAR printersW[] = L"System\\CurrentControlSet\\Control\\Print\\Printers";
299 static const WCHAR winnt_cv_portsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
300 static const WCHAR x86_envnameW[] = L"Windows NT x86";
303 static const printenv_t env_ia64 = {L"Windows IA64", L"ia64", 3,
304 L"\\Version-3", L"\\3"};
306 static const printenv_t env_x86 = {x86_envnameW, L"w32x86", 3,
307 L"\\Version-3", L"\\3"};
309 static const printenv_t env_x64 = {L"Windows x64", L"x64", 3,
310 L"\\Version-3", L"\\3"};
312 static const printenv_t env_arm = {L"Windows ARM", L"arm", 3,
313 L"\\Version-3", L"\\3"};
315 static const printenv_t env_arm64 = {L"Windows ARM64", L"arm64", 3,
316 L"\\Version-3", L"\\3"};
318 static const printenv_t env_win40 = {L"Windows 4.0", L"win40", 0,
319 L"\\Version-0", L"\\0"};
321 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_arm, &env_arm64, &env_win40};
323 #ifdef __i386__
324 #define env_arch env_x86
325 #elif defined __x86_64__
326 #define env_arch env_x64
327 #elif defined __arm__
328 #define env_arch env_arm
329 #elif defined __aarch64__
330 #define env_arch env_arm64
331 #else
332 #error not defined for this cpu
333 #endif
336 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
337 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
338 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
339 0, sizeof(DRIVER_INFO_8W)};
341 static BOOL WINAPI fpClosePrinter(HANDLE);
343 /******************************************************************
344 * apd_copyfile [internal]
346 * Copy a file from the driverdirectory to the versioned directory
348 * RETURNS
349 * Success: TRUE
350 * Failure: FALSE
353 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
355 WCHAR *srcname;
356 BOOL res;
358 apd->src[apd->srclen] = '\0';
359 apd->dst[apd->dstlen] = '\0';
361 if (!pathname || !pathname[0]) {
362 /* nothing to copy */
363 return TRUE;
366 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
367 srcname = pathname;
368 else
370 srcname = apd->src;
371 lstrcatW( srcname, file_part );
373 lstrcatW( apd->dst, file_part );
375 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
377 /* FIXME: handle APD_COPY_NEW_FILES */
378 res = CopyFileW(srcname, apd->dst, FALSE);
379 TRACE("got %d with %lu\n", res, GetLastError());
381 return apd->lazy || res;
384 /******************************************************************
385 * copy_servername_from_name (internal)
387 * for an external server, the serverpart from the name is copied.
389 * RETURNS
390 * the length (in WCHAR) of the serverpart (0 for the local computer)
391 * (-length), when the name is too long
394 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
396 LPCWSTR server;
397 LPWSTR ptr;
398 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
399 DWORD len;
400 DWORD serverlen;
402 if (target) *target = '\0';
404 if (name == NULL) return 0;
405 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
407 server = &name[2];
408 /* skip over both backslash, find separator '\' */
409 ptr = wcschr(server, '\\');
410 serverlen = (ptr) ? ptr - server : wcslen(server);
412 /* servername is empty */
413 if (serverlen == 0) return 0;
415 TRACE("found %s\n", debugstr_wn(server, serverlen));
417 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
419 if (target) {
420 memcpy(target, server, serverlen * sizeof(WCHAR));
421 target[serverlen] = '\0';
424 len = ARRAY_SIZE(buffer);
425 if (GetComputerNameW(buffer, &len)) {
426 if ((serverlen == len) && (wcsnicmp(server, buffer, len) == 0)) {
427 /* The requested Servername is our computername */
428 return 0;
431 return serverlen;
434 /******************************************************************
435 * get_basename_from_name (internal)
437 * skip over the serverpart from the full name
440 static LPCWSTR get_basename_from_name(LPCWSTR name)
442 if (name == NULL) return NULL;
443 if ((name[0] == '\\') && (name[1] == '\\')) {
444 /* skip over the servername and search for the following '\' */
445 name = wcschr(&name[2], '\\');
446 if ((name) && (name[1])) {
447 /* found a separator ('\') followed by a name:
448 skip over the separator and return the rest */
449 name++;
451 else
453 /* no basename present (we found only a servername) */
454 return NULL;
457 return name;
460 /******************************************************************
461 * monitor_unload [internal]
463 * release a printmonitor and unload it from memory, when needed
466 static void monitor_unload(monitor_t * pm)
468 if (pm == NULL) return;
469 TRACE("%p (refcount: %ld) %s\n", pm, pm->refcount, debugstr_w(pm->name));
471 EnterCriticalSection(&monitor_handles_cs);
473 if (pm->refcount) pm->refcount--;
475 if (pm->refcount == 0) {
476 list_remove(&pm->entry);
478 if (pm->monitor.pfnShutdown)
479 pm->monitor.pfnShutdown(pm->hmon);
481 FreeLibrary(pm->hdll);
482 free(pm->name);
483 free(pm->dllname);
484 free(pm);
486 LeaveCriticalSection(&monitor_handles_cs);
489 /******************************************************************
490 * monitor_unloadall [internal]
492 * release all registered printmonitors and unload them from memory, when needed
496 static void monitor_unloadall(void)
498 monitor_t * pm;
499 monitor_t * next;
501 EnterCriticalSection(&monitor_handles_cs);
502 /* iterate through the list, with safety against removal */
503 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
505 /* skip monitorui dlls */
506 if (pm->monitor.cbSize) monitor_unload(pm);
508 LeaveCriticalSection(&monitor_handles_cs);
511 static printer_info_t *find_printer_info(const WCHAR *name, unsigned int len)
513 printer_info_t *info;
515 EnterCriticalSection(&printers_cs);
516 LIST_FOR_EACH_ENTRY(info, &printers, printer_info_t, entry)
518 if (!wcsncmp(info->name, name, len) && (len == -1 || !info->name[len]))
520 InterlockedIncrement(&info->ref);
521 LeaveCriticalSection(&printers_cs);
522 return info;
525 LeaveCriticalSection(&printers_cs);
526 return NULL;
529 static WCHAR * reg_query_value(HKEY key, const WCHAR *name)
531 DWORD size, type;
532 WCHAR *ret;
534 if (RegQueryValueExW(key, name, 0, &type, NULL, &size) != ERROR_SUCCESS
535 || type != REG_SZ)
536 return NULL;
538 ret = malloc(size);
539 if (!ret)
540 return NULL;
542 if (RegQueryValueExW(key, name, 0, NULL, (BYTE *)ret, &size) != ERROR_SUCCESS)
544 free(ret);
545 return NULL;
547 return ret;
550 static DWORD reg_query_dword(HKEY hkey, const WCHAR *name)
552 DWORD type, val, size = sizeof(size);
554 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE*)&val, &size))
555 return 0;
556 if (type != REG_DWORD)
557 return 0;
558 return val;
561 static printer_info_t* get_printer_info(const WCHAR *name)
563 HKEY hkey, hprinter = NULL;
564 printer_info_t *info;
565 LSTATUS ret;
567 EnterCriticalSection(&printers_cs);
568 info = find_printer_info(name, -1);
569 if (info)
571 LeaveCriticalSection(&printers_cs);
572 return info;
575 ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkey);
576 if (ret == ERROR_SUCCESS)
577 ret = RegOpenKeyW(hkey, name, &hprinter);
578 RegCloseKey(hkey);
579 if (ret != ERROR_SUCCESS)
581 LeaveCriticalSection(&printers_cs);
582 return NULL;
585 info = calloc(1, sizeof(*info));
586 if (!info)
588 LeaveCriticalSection(&printers_cs);
589 RegCloseKey(hprinter);
590 return NULL;
593 info->name = wcsdup(name);
594 info->port = reg_query_value(hprinter, L"Port");
595 info->print_proc = reg_query_value(hprinter, L"Print Processor");
596 info->datatype = reg_query_value(hprinter, L"Datatype");
597 info->attributes = reg_query_dword(hprinter, L"Attributes");
598 RegCloseKey(hprinter);
600 if (!info->name || !info->port || !info->print_proc || !info->datatype)
602 free(info->name);
603 free(info->port);
604 free(info->print_proc);
605 free(info->datatype);
606 free(info);
608 LeaveCriticalSection(&printers_cs);
609 return NULL;
612 info->ref = 1;
613 list_add_head(&printers, &info->entry);
614 InitializeCriticalSection(&info->jobs_cs);
615 list_init(&info->jobs);
617 LeaveCriticalSection(&printers_cs);
618 return info;
621 static void free_job(job_info_t *job)
623 list_remove(&job->entry);
624 free(job->filename);
625 free(job->port);
626 free(job->datatype);
627 free(job->document_title);
628 free(job->devmode);
629 CloseHandle(job->hf);
630 free(job);
633 static void release_printer_info(printer_info_t *info)
635 if (!info)
636 return;
638 if (!InterlockedDecrement(&info->ref))
640 EnterCriticalSection(&printers_cs);
641 list_remove(&info->entry);
642 LeaveCriticalSection(&printers_cs);
644 free(info->name);
645 free(info->port);
646 free(info->print_proc);
647 free(info->datatype);
648 DeleteCriticalSection(&info->jobs_cs);
649 while (!list_empty(&info->jobs))
651 job_info_t *job = LIST_ENTRY(list_head(&info->jobs), job_info_t, entry);
652 free_job(job);
654 free(info);
658 static DEVMODEW * dup_devmode(const DEVMODEW *dm)
660 DEVMODEW *ret;
662 if (!dm) return NULL;
663 ret = malloc(dm->dmSize + dm->dmDriverExtra);
664 if (ret) memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra);
665 return ret;
668 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
669 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
670 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
672 FIXME("stub\n");
673 return ERROR_CALL_NOT_IMPLEMENTED;
676 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
677 PHANDLE phkResult, HANDLE hSpooler)
679 FIXME("stub\n");
680 return ERROR_CALL_NOT_IMPLEMENTED;
683 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
685 FIXME("stub\n");
686 return ERROR_CALL_NOT_IMPLEMENTED;
689 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
691 FIXME("stub\n");
692 return ERROR_CALL_NOT_IMPLEMENTED;
695 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
696 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
698 FIXME("stub\n");
699 return ERROR_CALL_NOT_IMPLEMENTED;
702 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
703 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
704 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
705 HANDLE hSpooler)
707 FIXME("stub\n");
708 return ERROR_CALL_NOT_IMPLEMENTED;
711 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
712 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
714 FIXME("stub\n");
715 return ERROR_CALL_NOT_IMPLEMENTED;
718 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
720 FIXME("stub\n");
721 return ERROR_CALL_NOT_IMPLEMENTED;
724 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
725 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
726 HANDLE hSpooler)
728 FIXME("stub\n");
729 return ERROR_CALL_NOT_IMPLEMENTED;
732 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
733 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
735 FIXME("stub\n");
736 return ERROR_CALL_NOT_IMPLEMENTED;
739 static MONITORREG monreg =
741 sizeof(MONITORREG),
742 CreateKey,
743 OpenKey,
744 CloseKey,
745 DeleteKey,
746 EnumKey,
747 QueryInfoKey,
748 SetValue,
749 DeleteValue,
750 EnumValue,
751 QueryValue
754 static BOOL WINAPI monitor2_EnumPorts(HANDLE hmon, WCHAR *name, DWORD level,
755 BYTE *buf, DWORD size, DWORD *needed, DWORD *count)
757 return ((MONITOREX*)hmon)->Monitor.pfnEnumPorts(name, level,
758 buf, size, needed, count);
761 static BOOL WINAPI monitor2_OpenPort(HANDLE hmon, WCHAR *name, HANDLE *hport)
763 return ((MONITOREX*)hmon)->Monitor.pfnOpenPort(name, hport);
766 static BOOL WINAPI monitor2_AddPort(HANDLE hmon, WCHAR *name,
767 HWND hwnd, WCHAR *monitor_name)
769 return ((MONITOREX*)hmon)->Monitor.pfnAddPort(name, hwnd, monitor_name);
772 static BOOL WINAPI monitor2_AddPortEx(HANDLE hmon, WCHAR *name, DWORD level,
773 BYTE *buf, WCHAR *monitor_name)
775 return ((MONITOREX*)hmon)->Monitor.pfnAddPortEx(name, level, buf, monitor_name);
778 static BOOL WINAPI monitor2_ConfigurePort(HANDLE hmon, WCHAR *name,
779 HWND hwnd, WCHAR *port_name)
781 return ((MONITOREX*)hmon)->Monitor.pfnConfigurePort(name, hwnd, port_name);
784 static BOOL WINAPI monitor2_DeletePort(HANDLE hmon, WCHAR *name,
785 HWND hwnd, WCHAR *port_name)
787 return ((MONITOREX*)hmon)->Monitor.pfnDeletePort(name, hwnd, port_name);
790 static BOOL WINAPI monitor2_XcvOpenPort(HANDLE hmon, const WCHAR *obj,
791 ACCESS_MASK granted_access, HANDLE *hxcv)
793 return ((MONITOREX*)hmon)->Monitor.pfnXcvOpenPort(obj, granted_access, hxcv);
796 /******************************************************************
797 * monitor_load [internal]
799 * load a printmonitor, get the dllname from the registry, when needed
800 * initialize the monitor and dump found function-pointers
802 * On failure, SetLastError() is called and NULL is returned
805 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
807 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
808 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
809 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
810 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
811 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
813 monitor_t * pm = NULL;
814 monitor_t * cursor;
815 LPWSTR regroot = NULL;
816 LPWSTR driver = dllname;
817 HKEY hroot = 0;
819 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
820 /* Is the Monitor already loaded? */
821 EnterCriticalSection(&monitor_handles_cs);
823 if (name) {
824 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
826 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
827 pm = cursor;
828 break;
833 if (pm == NULL) {
834 pm = calloc(1, sizeof(monitor_t));
835 if (pm == NULL) goto cleanup;
836 list_add_tail(&monitor_handles, &pm->entry);
838 pm->refcount++;
840 if (pm->name == NULL) {
841 /* Load the monitor */
842 DWORD len;
844 if (name) {
845 len = wcslen(monitorsW) + wcslen(name) + 2;
846 regroot = malloc(len * sizeof(WCHAR));
849 if (regroot) {
850 lstrcpyW(regroot, monitorsW);
851 lstrcatW(regroot, name);
852 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
853 /* Get the Driver from the Registry */
854 if (!driver)
855 driver = reg_query_value(hroot, L"Driver");
857 else
858 WARN("%s not found\n", debugstr_w(regroot));
861 pm->name = wcsdup(name);
862 pm->dllname = wcsdup(driver);
864 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
865 monitor_unload(pm);
866 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
867 pm = NULL;
868 goto cleanup;
871 pm->hdll = LoadLibraryW(driver);
872 TRACE("%p: LoadLibrary(%s) => %ld\n", pm->hdll, debugstr_w(driver), GetLastError());
874 if (pm->hdll == NULL) {
875 monitor_unload(pm);
876 SetLastError(ERROR_MOD_NOT_FOUND);
877 pm = NULL;
878 goto cleanup;
881 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
882 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
883 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
884 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
885 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
888 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
889 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
890 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
891 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
892 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
894 if (pInitializePrintMonitorUI != NULL) {
895 pm->monitorUI = pInitializePrintMonitorUI();
896 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
897 if (pm->monitorUI) {
898 TRACE("0x%08lx: dwMonitorSize (%ld)\n",
899 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
904 if (pInitializePrintMonitor2 && hroot) {
905 MONITORINIT init;
906 MONITOR2 *monitor2;
907 HANDLE hmon;
909 memset(&init, 0, sizeof(init));
910 init.cbSize = sizeof(init);
911 init.hckRegistryRoot = hroot;
912 init.pMonitorReg = &monreg;
913 init.bLocal = TRUE;
915 monitor2 = pInitializePrintMonitor2(&init, &hmon);
916 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
917 monitor2, debugstr_w(driver), debugstr_w(regroot));
918 if (monitor2)
920 memcpy(&pm->monitor, monitor2, min(monitor2->cbSize, sizeof(pm->monitor)));
921 pm->hmon = hmon;
924 else if (pInitializePrintMonitor && regroot) {
926 pm->monitorex = pInitializePrintMonitor(regroot);
927 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
928 pm->monitorex, debugstr_w(driver), debugstr_w(regroot));
929 if (pm->monitorex)
931 pm->hmon = (HANDLE)pm->monitorex;
933 pm->monitor.cbSize = sizeof(pm->monitor);
934 if (pm->monitorex->Monitor.pfnEnumPorts)
935 pm->monitor.pfnEnumPorts = monitor2_EnumPorts;
936 if (pm->monitorex->Monitor.pfnOpenPort)
937 pm->monitor.pfnOpenPort = monitor2_OpenPort;
938 pm->monitor.pfnStartDocPort = pm->monitorex->Monitor.pfnStartDocPort;
939 pm->monitor.pfnWritePort = pm->monitorex->Monitor.pfnWritePort;
940 pm->monitor.pfnReadPort = pm->monitorex->Monitor.pfnReadPort;
941 pm->monitor.pfnEndDocPort = pm->monitorex->Monitor.pfnEndDocPort;
942 pm->monitor.pfnClosePort = pm->monitorex->Monitor.pfnClosePort;
943 if (pm->monitorex->Monitor.pfnAddPort)
944 pm->monitor.pfnAddPort = monitor2_AddPort;
945 if (pm->monitorex->Monitor.pfnAddPortEx)
946 pm->monitor.pfnAddPortEx = monitor2_AddPortEx;
947 if (pm->monitorex->Monitor.pfnConfigurePort)
948 pm->monitor.pfnConfigurePort = monitor2_ConfigurePort;
949 if (pm->monitorex->Monitor.pfnDeletePort)
950 pm->monitor.pfnDeletePort = monitor2_DeletePort;
951 pm->monitor.pfnGetPrinterDataFromPort =
952 pm->monitorex->Monitor.pfnGetPrinterDataFromPort;
953 pm->monitor.pfnSetPortTimeOuts = pm->monitorex->Monitor.pfnSetPortTimeOuts;
954 if (pm->monitorex->Monitor.pfnXcvOpenPort)
955 pm->monitor.pfnXcvOpenPort = monitor2_XcvOpenPort;
956 pm->monitor.pfnXcvDataPort = pm->monitorex->Monitor.pfnXcvDataPort;
957 pm->monitor.pfnXcvClosePort = pm->monitorex->Monitor.pfnXcvClosePort;
961 if (!pm->monitor.cbSize && regroot) {
962 if (pInitializeMonitorEx != NULL) {
963 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
965 if (pInitializeMonitor != NULL) {
966 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
969 if (!pm->monitor.cbSize && !pm->monitorUI) {
970 monitor_unload(pm);
971 SetLastError(ERROR_PROC_NOT_FOUND);
972 pm = NULL;
975 cleanup:
976 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, L"Local Port") == 0)) {
977 pm->refcount++;
978 pm_localport = pm;
980 LeaveCriticalSection(&monitor_handles_cs);
981 if (driver != dllname) free(driver);
982 if (hroot) RegCloseKey(hroot);
983 free(regroot);
984 TRACE("=> %p\n", pm);
985 return pm;
988 /******************************************************************
989 * monitor_loadall [internal]
991 * Load all registered monitors
994 static DWORD monitor_loadall(void)
996 monitor_t * pm;
997 DWORD registered = 0;
998 DWORD loaded = 0;
999 HKEY hmonitors;
1000 WCHAR buffer[MAX_PATH];
1001 DWORD id = 0;
1003 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
1004 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1005 NULL, NULL, NULL, NULL, NULL);
1007 TRACE("%ld monitors registered\n", registered);
1009 while (id < registered) {
1010 buffer[0] = '\0';
1011 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1012 pm = monitor_load(buffer, NULL);
1013 if (pm) loaded++;
1014 id++;
1016 RegCloseKey(hmonitors);
1018 TRACE("%ld monitors loaded\n", loaded);
1019 return loaded;
1022 /******************************************************************
1023 * monitor_loadui [internal]
1025 * load the userinterface-dll for a given portmonitor
1027 * On failure, NULL is returned
1029 static monitor_t * monitor_loadui(monitor_t * pm)
1031 monitor_t * pui = NULL;
1032 WCHAR buffer[MAX_PATH];
1033 HANDLE hXcv;
1034 DWORD len;
1035 DWORD res = 0;
1037 if (pm == NULL) return NULL;
1038 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1040 /* Try the Portmonitor first; works for many monitors */
1041 if (pm->monitorUI) {
1042 EnterCriticalSection(&monitor_handles_cs);
1043 pm->refcount++;
1044 LeaveCriticalSection(&monitor_handles_cs);
1045 return pm;
1048 /* query the userinterface-dllname from the Portmonitor */
1049 /* building (",XcvMonitor %s",pm->name) not needed yet */
1050 if (pm->monitor.pfnXcvOpenPort)
1051 res = pm->monitor.pfnXcvOpenPort(pm->hmon, L"", SERVER_ACCESS_ADMINISTER, &hXcv);
1052 TRACE("got %lu with %p\n", res, hXcv);
1053 if (res) {
1054 res = pm->monitor.pfnXcvDataPort(hXcv, L"MonitorUI", NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1055 TRACE("got %lu with %s\n", res, debugstr_w(buffer));
1056 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
1057 pm->monitor.pfnXcvClosePort(hXcv);
1059 return pui;
1062 /******************************************************************
1063 * monitor_load_by_port [internal]
1065 * load a printmonitor for a given port
1067 * On failure, NULL is returned
1070 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1072 HKEY hroot;
1073 HKEY hport;
1074 LPWSTR buffer;
1075 monitor_t * pm = NULL;
1076 DWORD registered = 0;
1077 DWORD id = 0;
1078 DWORD len;
1080 TRACE("(%s)\n", debugstr_w(portname));
1082 /* wine specific ports */
1083 if (portname[0] == '|' || portname[0] == '/' ||
1084 !wcsncmp(portname, L"LPR:", 4) || !wcsncmp(portname, L"CUPS:", 5))
1085 return monitor_load(L"Local Port", NULL);
1087 /* Try the Local Monitor first */
1088 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
1089 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1090 /* found the portname */
1091 RegCloseKey(hroot);
1092 return monitor_load(L"Local Port", NULL);
1094 RegCloseKey(hroot);
1097 len = MAX_PATH + wcslen(L"\\Ports\\") + wcslen(portname) + 1;
1098 buffer = malloc(len * sizeof(WCHAR));
1099 if (buffer == NULL) return NULL;
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
1102 EnterCriticalSection(&monitor_handles_cs);
1103 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1105 while ((pm == NULL) && (id < registered)) {
1106 buffer[0] = '\0';
1107 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1108 TRACE("testing %s\n", debugstr_w(buffer));
1109 len = wcslen(buffer);
1110 lstrcatW(buffer, L"\\Ports\\");
1111 lstrcatW(buffer, portname);
1112 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1113 RegCloseKey(hport);
1114 buffer[len] = '\0'; /* use only the Monitor-Name */
1115 pm = monitor_load(buffer, NULL);
1117 id++;
1119 LeaveCriticalSection(&monitor_handles_cs);
1120 RegCloseKey(hroot);
1122 free(buffer);
1123 return pm;
1126 /******************************************************************
1127 * Return the number of bytes for an multi_sz string.
1128 * The result includes all \0s
1129 * (specifically the extra \0, that is needed as multi_sz terminator).
1131 static int multi_sz_lenW(const WCHAR *str)
1133 const WCHAR *ptr = str;
1134 if (!str) return 0;
1137 ptr += wcslen(ptr) + 1;
1138 } while (*ptr);
1140 return (ptr - str + 1) * sizeof(WCHAR);
1143 /******************************************************************
1144 * validate_envW [internal]
1146 * validate the user-supplied printing-environment
1148 * PARAMS
1149 * env [I] PTR to Environment-String or NULL
1151 * RETURNS
1152 * Success: PTR to printenv_t
1153 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
1155 * NOTES
1156 * An empty string is handled the same way as NULL.
1160 static const printenv_t * validate_envW(LPCWSTR env)
1162 const printenv_t *result = NULL;
1163 unsigned int i;
1165 TRACE("(%s)\n", debugstr_w(env));
1166 if (env && env[0])
1168 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
1170 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
1172 result = all_printenv[i];
1173 break;
1176 if (result == NULL) {
1177 FIXME("unsupported Environment: %s\n", debugstr_w(env));
1178 SetLastError(ERROR_INVALID_ENVIRONMENT);
1180 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
1182 else
1184 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_arch;
1187 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
1188 return result;
1191 /*****************************************************************************
1192 * enumerate the local monitors (INTERNAL)
1194 * returns the needed size (in bytes) for pMonitors
1195 * and *lpreturned is set to number of entries returned in pMonitors
1197 * Language-Monitors are also installed in the same Registry-Location but
1198 * they are filtered in Windows (not returned by EnumMonitors).
1199 * We do no filtering to simplify our Code.
1202 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
1204 HKEY hroot = NULL;
1205 HKEY hentry = NULL;
1206 LPWSTR ptr;
1207 LPMONITOR_INFO_2W mi;
1208 WCHAR buffer[MAX_PATH];
1209 WCHAR dllname[MAX_PATH];
1210 DWORD dllsize;
1211 DWORD len;
1212 DWORD index = 0;
1213 DWORD needed = 0;
1214 DWORD numentries;
1215 DWORD entrysize;
1217 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
1219 numentries = *lpreturned; /* this is 0, when we scan the registry */
1220 len = entrysize * numentries;
1221 ptr = (LPWSTR) &pMonitors[len];
1223 numentries = 0;
1224 len = ARRAY_SIZE(buffer);
1225 buffer[0] = '\0';
1227 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
1228 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
1229 /* Scan all Monitor-Registry-Keys */
1230 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1231 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
1232 dllsize = sizeof(dllname);
1233 dllname[0] = '\0';
1235 /* The Monitor must have a Driver-DLL */
1236 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1237 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
1238 /* We found a valid DLL for this Monitor. */
1239 TRACE("using Driver: %s\n", debugstr_w(dllname));
1241 RegCloseKey(hentry);
1244 /* Windows returns only Port-Monitors here, but to simplify our code,
1245 we do no filtering for Language-Monitors */
1246 if (dllname[0]) {
1247 numentries++;
1248 needed += entrysize;
1249 needed += (len+1) * sizeof(WCHAR); /* len is wcslen(monitorname) */
1250 if (level > 1) {
1251 /* we install and return only monitors for "Windows NT x86" */
1252 needed += (wcslen(x86_envnameW) +1) * sizeof(WCHAR);
1253 needed += dllsize;
1256 /* required size is calculated. Now fill the user-buffer */
1257 if (pMonitors && (cbBuf >= needed)){
1258 mi = (LPMONITOR_INFO_2W) pMonitors;
1259 pMonitors += entrysize;
1261 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
1262 mi->pName = ptr;
1263 lstrcpyW(ptr, buffer); /* Name of the Monitor */
1264 ptr += (len+1); /* len is wcslen(monitorname) */
1265 if (level > 1) {
1266 mi->pEnvironment = ptr;
1267 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
1268 ptr += (wcslen(x86_envnameW)+1);
1270 mi->pDLLName = ptr;
1271 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
1272 ptr += (dllsize / sizeof(WCHAR));
1276 index++;
1277 len = ARRAY_SIZE(buffer);
1278 buffer[0] = '\0';
1280 RegCloseKey(hroot);
1282 *lpreturned = numentries;
1283 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1284 return needed;
1287 /*****************************************************************************
1288 * enumerate the local print processors (INTERNAL)
1290 * returns the needed size (in bytes) for pPPInfo
1291 * and *lpreturned is set to number of entries returned in pPPInfo
1294 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
1296 HKEY hroot = NULL;
1297 HKEY hentry = NULL;
1298 LPWSTR ptr;
1299 PPRINTPROCESSOR_INFO_1W ppi;
1300 WCHAR buffer[MAX_PATH];
1301 WCHAR dllname[MAX_PATH];
1302 DWORD dllsize;
1303 DWORD len;
1304 DWORD index = 0;
1305 DWORD needed = 0;
1306 DWORD numentries;
1308 numentries = *lpreturned; /* this is 0, when we scan the registry */
1309 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
1310 ptr = (LPWSTR) &pPPInfo[len];
1312 numentries = 0;
1313 len = ARRAY_SIZE(buffer);
1314 buffer[0] = '\0';
1316 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
1317 /* add "winprint" first */
1318 numentries++;
1319 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(L"winprint");
1320 if (pPPInfo && (cbBuf >= needed)){
1321 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1322 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1324 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1325 ppi->pName = ptr;
1326 lstrcpyW(ptr, L"winprint"); /* Name of the Print Processor */
1327 ptr += ARRAY_SIZE(L"winprint");
1330 /* Scan all Printprocessor Keys */
1331 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
1332 (lstrcmpiW(buffer, L"winprint") != 0)) {
1333 TRACE("PrintProcessor_%ld: %s\n", numentries, debugstr_w(buffer));
1334 dllsize = sizeof(dllname);
1335 dllname[0] = '\0';
1337 /* The Print Processor must have a Driver-DLL */
1338 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1339 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
1340 /* We found a valid DLL for this Print Processor */
1341 TRACE("using Driver: %s\n", debugstr_w(dllname));
1343 RegCloseKey(hentry);
1346 if (dllname[0]) {
1347 numentries++;
1348 needed += sizeof(PRINTPROCESSOR_INFO_1W);
1349 needed += (len+1) * sizeof(WCHAR); /* len is wcslen(printprocessor name) */
1351 /* required size is calculated. Now fill the user-buffer */
1352 if (pPPInfo && (cbBuf >= needed)){
1353 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1354 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1356 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1357 ppi->pName = ptr;
1358 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
1359 ptr += (len+1); /* len is wcslen(printprosessor name) */
1362 index++;
1363 len = ARRAY_SIZE(buffer);
1364 buffer[0] = '\0';
1366 RegCloseKey(hroot);
1368 *lpreturned = numentries;
1369 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1370 return needed;
1373 /******************************************************************
1374 * enumerate the local Ports from all loaded monitors (internal)
1376 * returns the needed size (in bytes) for pPorts
1377 * and *lpreturned is set to number of entries returned in pPorts
1380 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1382 monitor_t * pm;
1383 LPWSTR ptr;
1384 LPPORT_INFO_2W cache;
1385 LPPORT_INFO_2W out;
1386 LPBYTE pi_buffer = NULL;
1387 DWORD pi_allocated = 0;
1388 DWORD pi_needed;
1389 DWORD pi_index;
1390 DWORD pi_returned;
1391 DWORD res;
1392 DWORD outindex = 0;
1393 DWORD needed;
1394 DWORD numentries;
1395 DWORD entrysize;
1397 TRACE("(%ld, %p, %ld, %p)\n", level, pPorts, cbBuf, lpreturned);
1398 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1400 numentries = *lpreturned; /* this is 0, when we scan the registry */
1401 needed = entrysize * numentries;
1402 ptr = (LPWSTR) &pPorts[needed];
1404 numentries = 0;
1405 needed = 0;
1407 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1409 if (pm->monitor.pfnEnumPorts) {
1410 pi_needed = 0;
1411 pi_returned = 0;
1412 res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level, pi_buffer,
1413 pi_allocated, &pi_needed, &pi_returned);
1414 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1415 /* Do not use realloc (we do not need the old data in the buffer) */
1416 free(pi_buffer);
1417 pi_buffer = malloc(pi_needed);
1418 pi_allocated = (pi_buffer) ? pi_needed : 0;
1419 res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level,
1420 pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1422 TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n",
1423 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1425 numentries += pi_returned;
1426 needed += pi_needed;
1428 /* fill the output-buffer (pPorts), if we have one */
1429 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1430 pi_index = 0;
1431 while (pi_returned > pi_index) {
1432 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1433 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1434 out->pPortName = ptr;
1435 lstrcpyW(ptr, cache->pPortName);
1436 ptr += (wcslen(ptr)+1);
1437 if (level > 1) {
1438 out->pMonitorName = ptr;
1439 lstrcpyW(ptr, cache->pMonitorName);
1440 ptr += (wcslen(ptr)+1);
1442 out->pDescription = ptr;
1443 lstrcpyW(ptr, cache->pDescription);
1444 ptr += (wcslen(ptr)+1);
1445 out->fPortType = cache->fPortType;
1446 out->Reserved = cache->Reserved;
1448 pi_index++;
1449 outindex++;
1454 /* the temporary portinfo-buffer is no longer needed */
1455 free(pi_buffer);
1457 *lpreturned = numentries;
1458 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1459 return needed;
1463 /*****************************************************************************
1464 * open_driver_reg [internal]
1466 * opens the registry for the printer drivers depending on the given input
1467 * variable pEnvironment
1469 * RETURNS:
1470 * Success: the opened hkey
1471 * Failure: NULL
1473 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1475 HKEY retval = NULL;
1476 LPWSTR buffer;
1477 const printenv_t * env;
1479 TRACE("(%s)\n", debugstr_w(pEnvironment));
1481 env = validate_envW(pEnvironment);
1482 if (!env) return NULL;
1484 buffer = malloc(sizeof(fmt_driversW) +
1485 (wcslen(env->envname) + wcslen(env->versionregpath)) * sizeof(WCHAR));
1487 if (buffer) {
1488 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1489 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1490 free(buffer);
1492 return retval;
1495 /*****************************************************************************
1496 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1498 * Return the PATH for the Printer-Drivers
1500 * PARAMS
1501 * pName [I] Servername (NT only) or NULL (local Computer)
1502 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1503 * Level [I] Structure-Level (must be 1)
1504 * pDriverDirectory [O] PTR to Buffer that receives the Result
1505 * cbBuf [I] Size of Buffer at pDriverDirectory
1506 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1507 * required for pDriverDirectory
1509 * RETURNS
1510 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1511 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1512 * if cbBuf is too small
1514 * Native Values returned in pDriverDirectory on Success:
1515 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1516 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1517 *| win9x(Windows 4.0): "%winsysdir%"
1519 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1522 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1523 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1525 DWORD needed;
1526 const printenv_t * env;
1527 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1529 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
1530 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1532 if (pName != NULL && pName[0]) {
1533 FIXME("server %s not supported\n", debugstr_w(pName));
1534 SetLastError(ERROR_INVALID_PARAMETER);
1535 return FALSE;
1538 env = validate_envW(pEnvironment);
1539 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1542 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1543 needed = GetSystemDirectoryW(NULL, 0);
1544 /* add the Size for the Subdirectories */
1545 needed += wcslen(L"\\spool");
1546 needed += wcslen(L"\\drivers\\");
1547 needed += wcslen(env->subdir);
1548 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1550 *pcbNeeded = needed;
1552 if (needed > cbBuf) {
1553 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1554 return FALSE;
1557 if (dir == NULL) {
1558 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1559 SetLastError(ERROR_INVALID_USER_BUFFER);
1560 return FALSE;
1563 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1564 /* add the Subdirectories */
1565 lstrcatW( dir, L"\\spool" );
1566 CreateDirectoryW( dir, NULL );
1567 lstrcatW( dir, L"\\drivers\\" );
1568 CreateDirectoryW( dir, NULL );
1569 lstrcatW( dir, env->subdir );
1570 CreateDirectoryW( dir, NULL );
1572 TRACE( "=> %s\n", debugstr_w( dir ) );
1573 return TRUE;
1576 /******************************************************************
1577 * driver_load [internal]
1579 * load a driver user interface dll
1581 * On failure, NULL is returned
1585 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1587 WCHAR fullname[MAX_PATH];
1588 HMODULE hui;
1589 DWORD len;
1591 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1593 /* build the driverdir */
1594 len = sizeof(fullname) -
1595 (wcslen(env->versionsubdir) + 1 + wcslen(dllname) + 1) * sizeof(WCHAR);
1597 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1598 (LPBYTE) fullname, len, &len)) {
1599 /* Should never fail */
1600 SetLastError(ERROR_BUFFER_OVERFLOW);
1601 return NULL;
1604 lstrcatW(fullname, env->versionsubdir);
1605 lstrcatW(fullname, L"\\");
1606 lstrcatW(fullname, dllname);
1608 hui = LoadLibraryW(fullname);
1609 TRACE("%p: LoadLibrary(%s) %ld\n", hui, debugstr_w(fullname), GetLastError());
1611 return hui;
1614 static job_info_t * get_job(printer_info_t *info, DWORD job_id)
1616 job_info_t *job;
1618 LIST_FOR_EACH_ENTRY(job, &info->jobs, job_info_t, entry)
1620 if(job->id == job_id)
1621 return job;
1623 return NULL;
1626 static HANDLE server_alloc_handle(const WCHAR *name, BOOL *stop_search)
1628 server_t *server;
1630 *stop_search = FALSE;
1631 if (name)
1632 return NULL;
1634 server = malloc(sizeof(*server));
1635 if (!server)
1637 *stop_search = TRUE;
1638 return NULL;
1640 server->type = HANDLE_SERVER;
1641 return (HANDLE)server;
1644 static HANDLE xcv_alloc_handle(const WCHAR *name, PRINTER_DEFAULTSW *def, BOOL *stop_search)
1646 static const WCHAR xcv_monitor[] = L"XcvMonitor ";
1647 static const WCHAR xcv_port[] = L"XcvPort ";
1648 BOOL mon, port;
1649 xcv_t *xcv;
1651 *stop_search = FALSE;
1652 if (name[0] != ',')
1653 return NULL;
1655 name++;
1656 while (*name == ' ')
1657 name++;
1659 mon = !wcsncmp(name, xcv_monitor, ARRAY_SIZE(xcv_monitor) - 1);
1660 if (mon)
1662 name += ARRAY_SIZE(xcv_monitor) - 1;
1664 else
1666 port = !wcsncmp(name, xcv_port, ARRAY_SIZE(xcv_port) - 1);
1667 name += ARRAY_SIZE(xcv_port) - 1;
1669 if (!port && !mon)
1670 return NULL;
1672 *stop_search = TRUE;
1673 xcv = calloc(1, sizeof(*xcv));
1674 if (!xcv)
1675 return NULL;
1676 xcv->header.type = HANDLE_XCV;
1678 if (mon)
1679 xcv->pm = monitor_load(name, NULL);
1680 else
1681 xcv->pm = monitor_load_by_port(name);
1682 if (!xcv->pm)
1684 free(xcv);
1685 SetLastError(ERROR_UNKNOWN_PORT);
1686 return NULL;
1689 if (xcv->pm->monitor.pfnXcvOpenPort)
1691 xcv->pm->monitor.pfnXcvOpenPort(xcv->pm->hmon, name,
1692 def ? def->DesiredAccess : 0, &xcv->hxcv);
1694 if (!xcv->hxcv)
1696 fpClosePrinter((HANDLE)xcv);
1697 SetLastError(ERROR_INVALID_PARAMETER);
1698 return NULL;
1700 return (HANDLE)xcv;
1703 static HANDLE port_alloc_handle(const WCHAR *name, BOOL *stop_search)
1705 static const WCHAR portW[] = L"Port";
1707 unsigned int i, name_len;
1708 WCHAR *port_name;
1709 port_t *port;
1711 *stop_search = FALSE;
1712 for (name_len = 0; name[name_len] != ','; name_len++)
1714 if (!name[name_len])
1715 return NULL;
1718 for (i = name_len + 1; name[i] == ' '; i++);
1719 if (wcscmp(name + i, portW))
1720 return NULL;
1722 *stop_search = TRUE;
1723 port_name = malloc((name_len + 1) * sizeof(WCHAR));
1724 if (!port_name)
1725 return NULL;
1726 memcpy(port_name, name, name_len * sizeof(WCHAR));
1727 port_name[name_len] = 0;
1729 port = calloc(1, sizeof(*port));
1730 if (!port)
1732 free(port_name);
1733 return NULL;
1735 port->header.type = HANDLE_PORT;
1737 port->mon = monitor_load_by_port(port_name);
1738 if (!port->mon)
1740 free(port_name);
1741 free(port);
1742 return NULL;
1744 if (!port->mon->monitor.pfnOpenPort || !port->mon->monitor.pfnWritePort
1745 || !port->mon->monitor.pfnClosePort || !port->mon->monitor.pfnStartDocPort
1746 || !port->mon->monitor.pfnEndDocPort)
1748 FIXME("port not supported: %s\n", debugstr_w(name));
1749 free(port_name);
1750 fpClosePrinter((HANDLE)port);
1751 return NULL;
1754 port->mon->monitor.pfnOpenPort(port->mon->hmon, port_name, &port->hport);
1755 free(port_name);
1756 if (!port->hport)
1758 fpClosePrinter((HANDLE)port);
1759 return NULL;
1761 return (HANDLE)port;
1764 static HANDLE job_alloc_handle(const WCHAR *name, BOOL *stop_search)
1766 static const WCHAR jobW[] = L"Job ";
1768 unsigned int name_len, job_id;
1769 printer_info_t *printer_info;
1770 job_info_t *job_info;
1771 job_t *job;
1773 *stop_search = FALSE;
1774 for (name_len = 0; name[name_len] != ','; name_len++)
1776 if (!name[name_len])
1777 return NULL;
1780 for (job_id = name_len + 1; name[job_id] == ' '; job_id++);
1781 if (!name[job_id])
1782 return NULL;
1784 if (wcsncmp(name + job_id, jobW, ARRAY_SIZE(jobW) - 1))
1785 return NULL;
1787 *stop_search = TRUE;
1788 job_id += ARRAY_SIZE(jobW) - 1;
1789 job_id = wcstoul(name + job_id, NULL, 10);
1791 printer_info = find_printer_info(name, name_len);
1792 if (!printer_info)
1794 SetLastError(ERROR_INVALID_PRINTER_NAME);
1795 return NULL;
1798 EnterCriticalSection(&printer_info->jobs_cs);
1800 job_info = get_job(printer_info, job_id);
1801 if (!job_info)
1803 LeaveCriticalSection(&printer_info->jobs_cs);
1804 release_printer_info(printer_info);
1805 SetLastError(ERROR_INVALID_PRINTER_NAME);
1806 return NULL;
1809 job = malloc(sizeof(*job));
1810 if (!job)
1812 LeaveCriticalSection(&printer_info->jobs_cs);
1813 release_printer_info(printer_info);
1814 return NULL;
1816 job->header.type = HANDLE_JOB;
1817 job->hf = CreateFileW(job_info->filename, GENERIC_READ,
1818 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
1819 NULL, OPEN_EXISTING, 0, NULL);
1821 LeaveCriticalSection(&printer_info->jobs_cs);
1822 release_printer_info(printer_info);
1824 if (job->hf == INVALID_HANDLE_VALUE)
1826 free(job);
1827 return NULL;
1829 return (HANDLE)job;
1832 static HANDLE printer_alloc_handle(const WCHAR *name, const WCHAR *basename,
1833 PRINTER_DEFAULTSW *def)
1835 printer_t *printer;
1837 printer = calloc(1, sizeof(*printer));
1838 if (!printer)
1839 return NULL;
1840 printer->header.type = HANDLE_PRINTER;
1842 /* clone the full name */
1843 printer->name = wcsdup(name);
1844 if (name && !printer->name)
1846 fpClosePrinter((HANDLE)printer);
1847 return NULL;
1850 printer->info = get_printer_info(basename);
1851 if (!printer->info)
1853 fpClosePrinter((HANDLE)printer);
1854 SetLastError(ERROR_INVALID_PRINTER_NAME);
1855 return NULL;
1858 if (def && def->pDatatype)
1859 printer->datatype = wcsdup(def->pDatatype);
1860 if (def && def->pDevMode)
1861 printer->devmode = dup_devmode(def->pDevMode);
1863 return (HANDLE)printer;
1866 static inline WCHAR *get_file_part( WCHAR *name )
1868 WCHAR *ptr = wcsrchr( name, '\\' );
1869 if (ptr) return ptr + 1;
1870 return name;
1873 /******************************************************************************
1874 * myAddPrinterDriverEx [internal]
1876 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1877 * and a special mode with lazy error checking.
1880 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1882 const printenv_t *env;
1883 apd_data_t apd;
1884 DRIVER_INFO_8W di;
1885 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1886 HMODULE hui;
1887 WCHAR *file;
1888 HKEY hroot;
1889 HKEY hdrv;
1890 DWORD disposition;
1891 DWORD len;
1892 LONG lres;
1893 BOOL res;
1895 /* we need to set all entries in the Registry, independent from the Level of
1896 DRIVER_INFO, that the caller supplied */
1898 ZeroMemory(&di, sizeof(di));
1899 if (pDriverInfo && (level < ARRAY_SIZE(di_sizeof))) {
1900 memcpy(&di, pDriverInfo, di_sizeof[level]);
1903 /* dump the most used infos */
1904 TRACE("%p: .cVersion : 0x%lx/%ld\n", pDriverInfo, di.cVersion, di.cVersion);
1905 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1906 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1907 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1908 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1909 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1910 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1911 /* dump only the first of the additional Files */
1912 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1915 /* check environment */
1916 env = validate_envW(di.pEnvironment);
1917 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1919 /* fill the copy-data / get the driverdir */
1920 len = sizeof(apd.src) - sizeof(L"\\3") - sizeof(WCHAR);
1921 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1922 (LPBYTE) apd.src, len, &len)) {
1923 /* Should never fail */
1924 return FALSE;
1926 memcpy(apd.dst, apd.src, len);
1927 lstrcatW(apd.src, L"\\");
1928 apd.srclen = wcslen(apd.src);
1929 lstrcatW(apd.dst, env->versionsubdir);
1930 lstrcatW(apd.dst, L"\\");
1931 apd.dstlen = wcslen(apd.dst);
1932 apd.copyflags = dwFileCopyFlags;
1933 apd.lazy = lazy;
1934 CreateDirectoryW(apd.src, NULL);
1935 CreateDirectoryW(apd.dst, NULL);
1937 hroot = open_driver_reg(env->envname);
1938 if (!hroot) {
1939 ERR("Can't create Drivers key\n");
1940 return FALSE;
1943 /* Fill the Registry for the Driver */
1944 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1945 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1946 &hdrv, &disposition)) != ERROR_SUCCESS) {
1948 ERR("can't create driver %s: %lu\n", debugstr_w(di.pName), lres);
1949 RegCloseKey(hroot);
1950 SetLastError(lres);
1951 return FALSE;
1953 RegCloseKey(hroot);
1955 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1956 RegSetValueExW(hdrv, L"Version", 0, REG_DWORD, (const BYTE*) &env->driverversion,
1957 sizeof(DWORD));
1959 file = get_file_part( di.pDriverPath );
1960 RegSetValueExW( hdrv, L"Driver", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1961 apd_copyfile( di.pDriverPath, file, &apd );
1963 file = get_file_part( di.pDataFile );
1964 RegSetValueExW( hdrv, L"Data File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1965 apd_copyfile( di.pDataFile, file, &apd );
1967 file = get_file_part( di.pConfigFile );
1968 RegSetValueExW( hdrv, L"Configuration File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1969 apd_copyfile( di.pConfigFile, file, &apd );
1971 /* settings for level 3 */
1972 if (di.pHelpFile)
1974 file = get_file_part( di.pHelpFile );
1975 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1976 apd_copyfile( di.pHelpFile, file, &apd );
1978 else
1979 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (const BYTE*)L"", sizeof(L"") );
1981 if (di.pDependentFiles && *di.pDependentFiles)
1983 WCHAR *reg, *reg_ptr, *in_ptr;
1984 reg = reg_ptr = malloc( multi_sz_lenW( di.pDependentFiles ) );
1986 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += wcslen( in_ptr ) + 1)
1988 file = get_file_part( in_ptr );
1989 len = wcslen( file ) + 1;
1990 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1991 reg_ptr += len;
1992 apd_copyfile( in_ptr, file, &apd );
1994 *reg_ptr = 0;
1996 RegSetValueExW( hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (BYTE*)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1997 free( reg );
1999 else
2000 RegSetValueExW(hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
2002 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
2003 if (di.pMonitorName)
2004 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (BYTE*)di.pMonitorName,
2005 (wcslen(di.pMonitorName)+1)* sizeof(WCHAR));
2006 else
2007 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
2009 if (di.pDefaultDataType)
2010 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (BYTE*)di.pDefaultDataType,
2011 (wcslen(di.pDefaultDataType)+1)* sizeof(WCHAR));
2012 else
2013 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
2015 /* settings for level 4 */
2016 if (di.pszzPreviousNames)
2017 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (BYTE*)di.pszzPreviousNames,
2018 multi_sz_lenW(di.pszzPreviousNames));
2019 else
2020 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
2022 if (level > 5) TRACE("level %lu for Driver %s is incomplete\n", level, debugstr_w(di.pName));
2024 RegCloseKey(hdrv);
2025 hui = driver_load(env, di.pConfigFile);
2026 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
2027 if (hui && pDrvDriverEvent) {
2029 /* Support for DrvDriverEvent is optional */
2030 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
2031 /* MSDN: level for DRIVER_INFO is 1 to 3 */
2032 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
2033 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
2035 FreeLibrary(hui);
2037 TRACE("=> TRUE with %lu\n", GetLastError());
2038 return TRUE;
2042 /******************************************************************************
2043 * fpAddMonitor [exported through PRINTPROVIDOR]
2045 * Install a Printmonitor
2047 * PARAMS
2048 * pName [I] Servername or NULL (local Computer)
2049 * Level [I] Structure-Level (Must be 2)
2050 * pMonitors [I] PTR to MONITOR_INFO_2
2052 * RETURNS
2053 * Success: TRUE
2054 * Failure: FALSE
2056 * NOTES
2057 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2060 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2062 const printenv_t * env;
2063 monitor_t * pm = NULL;
2064 LPMONITOR_INFO_2W mi2w;
2065 HKEY hroot = NULL;
2066 HKEY hentry = NULL;
2067 DWORD disposition;
2068 BOOL res = FALSE;
2070 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2071 TRACE("(%s, %ld, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2072 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
2074 if (copy_servername_from_name(pName, NULL)) {
2075 FIXME("server %s not supported\n", debugstr_w(pName));
2076 SetLastError(ERROR_ACCESS_DENIED);
2077 return FALSE;
2080 if (!mi2w->pName || (! mi2w->pName[0])) {
2081 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2082 SetLastError(ERROR_INVALID_PARAMETER);
2083 return FALSE;
2086 env = validate_envW(mi2w->pEnvironment);
2087 if (!env)
2088 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2090 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2091 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2092 SetLastError(ERROR_INVALID_PARAMETER);
2093 return FALSE;
2096 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2097 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2098 return FALSE;
2101 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2102 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2103 &disposition) == ERROR_SUCCESS) {
2105 /* Some installers set options for the port before calling AddMonitor.
2106 We query the "Driver" entry to verify that the monitor is installed,
2107 before we return an error.
2108 When a user installs two print monitors at the same time with the
2109 same name, a race condition is possible but silently ignored. */
2111 DWORD namesize = 0;
2113 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2114 (RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL,
2115 &namesize) == ERROR_SUCCESS)) {
2116 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2117 /* 9x use ERROR_ALREADY_EXISTS */
2118 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2120 else
2122 INT len;
2123 len = (wcslen(mi2w->pDLLName) +1) * sizeof(WCHAR);
2124 res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ,
2125 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2127 /* Load and initialize the monitor. SetLastError() is called on failure */
2128 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL)
2130 RegDeleteKeyW(hroot, mi2w->pName);
2131 res = FALSE;
2133 else
2134 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
2137 RegCloseKey(hentry);
2140 RegCloseKey(hroot);
2141 return (res);
2144 /******************************************************************************
2145 * fpAddPort [exported through PRINTPROVIDOR]
2147 * Add a Port for a specific Monitor
2149 * PARAMS
2150 * pName [I] Servername or NULL (local Computer)
2151 * hWnd [I] Handle to parent Window for the Dialog-Box
2152 * pMonitorName [I] Name of the Monitor that manage the Port
2154 * RETURNS
2155 * Success: TRUE
2156 * Failure: FALSE
2159 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
2161 monitor_t * pm;
2162 monitor_t * pui;
2163 LONG lres;
2164 DWORD res;
2166 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
2168 lres = copy_servername_from_name(pName, NULL);
2169 if (lres) {
2170 FIXME("server %s not supported\n", debugstr_w(pName));
2171 SetLastError(ERROR_INVALID_PARAMETER);
2172 return FALSE;
2175 /* an empty Monitorname is Invalid */
2176 if (!pMonitorName[0]) {
2177 SetLastError(ERROR_NOT_SUPPORTED);
2178 return FALSE;
2181 pm = monitor_load(pMonitorName, NULL);
2182 if (pm && pm->monitor.pfnAddPort) {
2183 res = pm->monitor.pfnAddPort(pm->hmon, pName, hWnd, pMonitorName);
2184 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
2186 else
2188 pui = monitor_loadui(pm);
2189 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
2190 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
2191 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
2193 else
2195 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2196 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
2197 pui, debugstr_w(pui ? pui->dllname : NULL));
2199 SetLastError(ERROR_NOT_SUPPORTED);
2200 res = FALSE;
2202 monitor_unload(pui);
2204 monitor_unload(pm);
2206 TRACE("returning %ld with %lu\n", res, GetLastError());
2207 return res;
2210 /******************************************************************************
2211 * fpAddPortEx [exported through PRINTPROVIDOR]
2213 * Add a Port for a specific Monitor, without presenting a user interface
2215 * PARAMS
2216 * pName [I] Servername or NULL (local Computer)
2217 * level [I] Structure-Level (1 or 2) for pBuffer
2218 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
2219 * pMonitorName [I] Name of the Monitor that manage the Port
2221 * RETURNS
2222 * Success: TRUE
2223 * Failure: FALSE
2226 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
2228 PORT_INFO_2W * pi2;
2229 monitor_t * pm;
2230 DWORD lres;
2231 DWORD res;
2233 pi2 = (PORT_INFO_2W *) pBuffer;
2235 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
2236 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
2237 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
2238 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
2240 lres = copy_servername_from_name(pName, NULL);
2241 if (lres) {
2242 FIXME("server %s not supported\n", debugstr_w(pName));
2243 SetLastError(ERROR_INVALID_PARAMETER);
2244 return FALSE;
2247 if ((level < 1) || (level > 2)) {
2248 SetLastError(ERROR_INVALID_LEVEL);
2249 return FALSE;
2252 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
2253 SetLastError(ERROR_INVALID_PARAMETER);
2254 return FALSE;
2257 /* load the Monitor */
2258 pm = monitor_load(pMonitorName, NULL);
2259 if (pm && pm->monitor.pfnAddPortEx)
2261 res = pm->monitor.pfnAddPortEx(pm->hmon, pName, level, pBuffer, pMonitorName);
2262 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
2264 else
2266 FIXME("not implemented for %s (monitor %p: %s)\n",
2267 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
2268 SetLastError(ERROR_INVALID_PARAMETER);
2269 res = FALSE;
2271 monitor_unload(pm);
2272 return res;
2275 /******************************************************************************
2276 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
2278 * Install a Printer Driver with the Option to upgrade / downgrade the Files
2280 * PARAMS
2281 * pName [I] Servername or NULL (local Computer)
2282 * level [I] Level for the supplied DRIVER_INFO_*W struct
2283 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
2284 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
2286 * RESULTS
2287 * Success: TRUE
2288 * Failure: FALSE
2291 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
2293 LONG lres;
2295 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
2296 lres = copy_servername_from_name(pName, NULL);
2297 if (lres) {
2298 FIXME("server %s not supported\n", debugstr_w(pName));
2299 SetLastError(ERROR_ACCESS_DENIED);
2300 return FALSE;
2303 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
2304 TRACE("Flags 0x%lx ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
2307 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
2310 /******************************************************************************
2311 * fpConfigurePort [exported through PRINTPROVIDOR]
2313 * Display the Configuration-Dialog for a specific Port
2315 * PARAMS
2316 * pName [I] Servername or NULL (local Computer)
2317 * hWnd [I] Handle to parent Window for the Dialog-Box
2318 * pPortName [I] Name of the Port, that should be configured
2320 * RETURNS
2321 * Success: TRUE
2322 * Failure: FALSE
2325 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2327 monitor_t * pm;
2328 monitor_t * pui;
2329 LONG lres;
2330 DWORD res;
2332 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2334 lres = copy_servername_from_name(pName, NULL);
2335 if (lres) {
2336 FIXME("server %s not supported\n", debugstr_w(pName));
2337 SetLastError(ERROR_INVALID_NAME);
2338 return FALSE;
2341 /* an empty Portname is Invalid, but can popup a Dialog */
2342 if (!pPortName[0]) {
2343 SetLastError(ERROR_NOT_SUPPORTED);
2344 return FALSE;
2347 pm = monitor_load_by_port(pPortName);
2348 if (pm && pm->monitor.pfnConfigurePort)
2350 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2351 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2352 res = pm->monitor.pfnConfigurePort(pm->hmon, pName, hWnd, pPortName);
2353 TRACE("got %ld with %lu\n", res, GetLastError());
2355 else
2357 pui = monitor_loadui(pm);
2358 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
2359 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2360 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2361 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
2362 TRACE("got %ld with %lu\n", res, GetLastError());
2364 else
2366 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2367 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2368 pui, debugstr_w(pui ? pui->dllname : NULL));
2370 SetLastError(ERROR_NOT_SUPPORTED);
2371 res = FALSE;
2373 monitor_unload(pui);
2375 monitor_unload(pm);
2377 TRACE("returning %ld with %lu\n", res, GetLastError());
2378 return res;
2381 /******************************************************************
2382 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2384 * Delete a specific Printmonitor from a Printing-Environment
2386 * PARAMS
2387 * pName [I] Servername or NULL (local Computer)
2388 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2389 * pMonitorName [I] Name of the Monitor, that should be deleted
2391 * RETURNS
2392 * Success: TRUE
2393 * Failure: FALSE
2395 * NOTES
2396 * pEnvironment is ignored in Windows for the local Computer.
2400 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2402 monitor_t *pm;
2403 HKEY hroot = NULL;
2404 LONG lres;
2406 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2407 debugstr_w(pMonitorName));
2409 lres = copy_servername_from_name(pName, NULL);
2410 if (lres) {
2411 FIXME("server %s not supported\n", debugstr_w(pName));
2412 SetLastError(ERROR_INVALID_NAME);
2413 return FALSE;
2416 /* pEnvironment is ignored in Windows for the local Computer */
2417 if (!pMonitorName || !pMonitorName[0]) {
2418 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2419 SetLastError(ERROR_INVALID_PARAMETER);
2420 return FALSE;
2423 /* Unload the monitor if it's loaded */
2424 EnterCriticalSection(&monitor_handles_cs);
2425 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
2427 if (pm->name && !lstrcmpW(pMonitorName, pm->name))
2429 monitor_unload(pm);
2430 break;
2433 LeaveCriticalSection(&monitor_handles_cs);
2435 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2436 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2437 return FALSE;
2440 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2441 TRACE("%s deleted\n", debugstr_w(pMonitorName));
2442 RegCloseKey(hroot);
2443 return TRUE;
2446 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
2447 RegCloseKey(hroot);
2449 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2450 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2451 return FALSE;
2454 /*****************************************************************************
2455 * fpDeletePort [exported through PRINTPROVIDOR]
2457 * Delete a specific Port
2459 * PARAMS
2460 * pName [I] Servername or NULL (local Computer)
2461 * hWnd [I] Handle to parent Window for the Dialog-Box
2462 * pPortName [I] Name of the Port, that should be deleted
2464 * RETURNS
2465 * Success: TRUE
2466 * Failure: FALSE
2469 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2471 monitor_t * pm;
2472 monitor_t * pui;
2473 LONG lres;
2474 DWORD res;
2476 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2478 lres = copy_servername_from_name(pName, NULL);
2479 if (lres) {
2480 FIXME("server %s not supported\n", debugstr_w(pName));
2481 SetLastError(ERROR_INVALID_NAME);
2482 return FALSE;
2485 /* an empty Portname is Invalid */
2486 if (!pPortName[0]) {
2487 SetLastError(ERROR_NOT_SUPPORTED);
2488 return FALSE;
2491 pm = monitor_load_by_port(pPortName);
2492 if (pm && pm->monitor.pfnDeletePort)
2494 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2495 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2496 res = pm->monitor.pfnDeletePort(pm->hmon, pName, hWnd, pPortName);
2497 TRACE("got %ld with %lu\n", res, GetLastError());
2499 else
2501 pui = monitor_loadui(pm);
2502 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2503 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2504 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2505 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2506 TRACE("got %ld with %lu\n", res, GetLastError());
2508 else
2510 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2511 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2512 pui, debugstr_w(pui ? pui->dllname : NULL));
2514 SetLastError(ERROR_NOT_SUPPORTED);
2515 res = FALSE;
2517 monitor_unload(pui);
2519 monitor_unload(pm);
2521 TRACE("returning %ld with %lu\n", res, GetLastError());
2522 return res;
2525 /*****************************************************************************
2526 * fpEnumMonitors [exported through PRINTPROVIDOR]
2528 * Enumerate available Port-Monitors
2530 * PARAMS
2531 * pName [I] Servername or NULL (local Computer)
2532 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2533 * pMonitors [O] PTR to Buffer that receives the Result
2534 * cbBuf [I] Size of Buffer at pMonitors
2535 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2536 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2538 * RETURNS
2539 * Success: TRUE
2540 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2542 * NOTES
2543 * Windows reads the Registry once and cache the Results.
2546 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
2547 LPDWORD pcbNeeded, LPDWORD pcReturned)
2549 DWORD numentries = 0;
2550 DWORD needed = 0;
2551 LONG lres;
2552 BOOL res = FALSE;
2554 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
2555 cbBuf, pcbNeeded, pcReturned);
2557 lres = copy_servername_from_name(pName, NULL);
2558 if (lres) {
2559 FIXME("server %s not supported\n", debugstr_w(pName));
2560 SetLastError(ERROR_INVALID_NAME);
2561 goto em_cleanup;
2564 if (!Level || (Level > 2)) {
2565 WARN("level (%ld) is ignored in win9x\n", Level);
2566 SetLastError(ERROR_INVALID_LEVEL);
2567 return FALSE;
2570 /* Scan all Monitor-Keys */
2571 numentries = 0;
2572 needed = get_local_monitors(Level, NULL, 0, &numentries);
2574 /* we calculated the needed buffersize. now do more error-checks */
2575 if (cbBuf < needed) {
2576 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2577 goto em_cleanup;
2580 /* fill the Buffer with the Monitor-Keys */
2581 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2582 res = TRUE;
2584 em_cleanup:
2585 if (pcbNeeded) *pcbNeeded = needed;
2586 if (pcReturned) *pcReturned = numentries;
2588 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2589 res, GetLastError(), needed, numentries);
2591 return (res);
2594 /******************************************************************************
2595 * fpEnumPorts [exported through PRINTPROVIDOR]
2597 * Enumerate available Ports
2599 * PARAMS
2600 * pName [I] Servername or NULL (local Computer)
2601 * Level [I] Structure-Level (1 or 2)
2602 * pPorts [O] PTR to Buffer that receives the Result
2603 * cbBuf [I] Size of Buffer at pPorts
2604 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2605 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2607 * RETURNS
2608 * Success: TRUE
2609 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2612 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2613 LPDWORD pcbNeeded, LPDWORD pcReturned)
2615 DWORD needed = 0;
2616 DWORD numentries = 0;
2617 LONG lres;
2618 BOOL res = FALSE;
2620 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2621 cbBuf, pcbNeeded, pcReturned);
2623 lres = copy_servername_from_name(pName, NULL);
2624 if (lres) {
2625 FIXME("server %s not supported\n", debugstr_w(pName));
2626 SetLastError(ERROR_INVALID_NAME);
2627 goto emP_cleanup;
2630 if (!Level || (Level > 2)) {
2631 SetLastError(ERROR_INVALID_LEVEL);
2632 goto emP_cleanup;
2635 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2636 SetLastError(RPC_X_NULL_REF_POINTER);
2637 goto emP_cleanup;
2640 EnterCriticalSection(&monitor_handles_cs);
2641 monitor_loadall();
2643 /* Scan all local Ports */
2644 numentries = 0;
2645 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2647 /* we calculated the needed buffersize. now do the error-checks */
2648 if (cbBuf < needed) {
2649 monitor_unloadall();
2650 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2651 goto emP_cleanup_cs;
2653 else if (!pPorts || !pcReturned) {
2654 monitor_unloadall();
2655 SetLastError(RPC_X_NULL_REF_POINTER);
2656 goto emP_cleanup_cs;
2659 /* Fill the Buffer */
2660 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2661 res = TRUE;
2662 monitor_unloadall();
2664 emP_cleanup_cs:
2665 LeaveCriticalSection(&monitor_handles_cs);
2667 emP_cleanup:
2668 if (pcbNeeded) *pcbNeeded = needed;
2669 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2671 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
2672 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2674 return (res);
2677 static BOOL WINAPI fpAddPrintProcessor(WCHAR *name, WCHAR *environment, WCHAR *path,
2678 WCHAR *print_proc)
2680 const printenv_t * env;
2681 HKEY hroot = NULL;
2682 WCHAR *regpath;
2683 LSTATUS s;
2685 TRACE("(%s, %s, %s, %s)\n", debugstr_w(name), debugstr_w(environment),
2686 debugstr_w(path), debugstr_w(print_proc));
2688 if (!path || !print_proc)
2690 SetLastError(ERROR_INVALID_PARAMETER);
2691 return FALSE;
2694 if (name && name[0])
2696 FIXME("server %s not supported\n", debugstr_w(name));
2697 SetLastError(ERROR_INVALID_NAME);
2698 return FALSE;
2701 env = validate_envW(environment);
2702 if (!env)
2703 return FALSE;
2705 regpath = malloc(sizeof(fmt_printprocessorsW) +
2706 wcslen(env->envname) * sizeof(WCHAR));
2707 if (!regpath)
2708 return FALSE;
2709 wsprintfW(regpath, fmt_printprocessorsW, env->envname);
2711 s = RegCreateKeyW(HKEY_LOCAL_MACHINE, regpath, &hroot);
2712 free(regpath);
2713 if (!s)
2715 s = RegSetKeyValueW(hroot, print_proc, L"Driver", REG_SZ, path,
2716 (wcslen(path) + 1) * sizeof(WCHAR));
2718 RegCloseKey(hroot);
2719 if (s)
2721 SetLastError(s);
2722 return FALSE;
2725 return TRUE;
2728 /*****************************************************************************
2729 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2731 * Enumerate available Print Processors
2733 * PARAMS
2734 * pName [I] Servername or NULL (local Computer)
2735 * pEnvironment [I] Printing-Environment or NULL (Default)
2736 * Level [I] Structure-Level (Only 1 is allowed)
2737 * pPPInfo [O] PTR to Buffer that receives the Result
2738 * cbBuf [I] Size of Buffer at pMonitors
2739 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2740 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2742 * RETURNS
2743 * Success: TRUE
2744 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2747 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2748 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2750 const printenv_t * env;
2751 LPWSTR regpathW = NULL;
2752 DWORD numentries = 0;
2753 DWORD needed = 0;
2754 LONG lres;
2755 BOOL res = FALSE;
2757 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2758 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2760 lres = copy_servername_from_name(pName, NULL);
2761 if (lres) {
2762 FIXME("server %s not supported\n", debugstr_w(pName));
2763 SetLastError(ERROR_INVALID_NAME);
2764 goto epp_cleanup;
2767 if (Level != 1) {
2768 SetLastError(ERROR_INVALID_LEVEL);
2769 goto epp_cleanup;
2772 env = validate_envW(pEnvironment);
2773 if (!env)
2774 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2776 regpathW = malloc(sizeof(fmt_printprocessorsW) +
2777 (wcslen(env->envname) * sizeof(WCHAR)));
2779 if (!regpathW)
2780 goto epp_cleanup;
2782 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2784 /* Scan all Printprocessor-Keys */
2785 numentries = 0;
2786 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2788 /* we calculated the needed buffersize. now do more error-checks */
2789 if (cbBuf < needed) {
2790 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2791 goto epp_cleanup;
2794 /* fill the Buffer with the Printprocessor Infos */
2795 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2796 res = TRUE;
2798 epp_cleanup:
2799 free(regpathW);
2800 if (pcbNeeded) *pcbNeeded = needed;
2801 if (pcReturned) *pcReturned = numentries;
2803 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2804 res, GetLastError(), needed, numentries);
2806 return (res);
2809 /******************************************************************************
2810 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2812 * Return the PATH for the Print-Processors
2814 * PARAMS
2815 * pName [I] Servername or NULL (this computer)
2816 * pEnvironment [I] Printing-Environment or NULL (Default)
2817 * level [I] Structure-Level (must be 1)
2818 * pPPInfo [O] PTR to Buffer that receives the Result
2819 * cbBuf [I] Size of Buffer at pPPInfo
2820 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2822 * RETURNS
2823 * Success: TRUE
2824 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2826 * Native Values returned in pPPInfo on Success for this computer:
2827 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2828 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2829 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2831 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2834 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2835 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2837 const printenv_t * env;
2838 DWORD needed;
2839 LONG lres;
2841 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2842 level, pPPInfo, cbBuf, pcbNeeded);
2844 *pcbNeeded = 0;
2845 lres = copy_servername_from_name(pName, NULL);
2846 if (lres) {
2847 FIXME("server %s not supported\n", debugstr_w(pName));
2848 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2849 return FALSE;
2852 env = validate_envW(pEnvironment);
2853 if (!env)
2854 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2856 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2857 needed = GetSystemDirectoryW(NULL, 0);
2858 /* add the Size for the Subdirectories */
2859 needed += wcslen(L"\\spool\\prtprocs\\");
2860 needed += wcslen(env->subdir);
2861 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2863 *pcbNeeded = needed;
2865 if (needed > cbBuf) {
2866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2867 return FALSE;
2870 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2871 /* add the Subdirectories */
2872 lstrcatW((LPWSTR) pPPInfo, L"\\spool\\prtprocs\\");
2873 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2874 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2875 return TRUE;
2878 /******************************************************************************
2879 * fpOpenPrinter [exported through PRINTPROVIDOR]
2881 * Open a Printer / Printserver or a Printer-Object
2883 * PARAMS
2884 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2885 * pPrinter [O] The resulting Handle is stored here
2886 * pDefaults [I] PTR to Default Printer Settings or NULL
2888 * RETURNS
2889 * Success: TRUE
2890 * Failure: FALSE
2892 * NOTES
2893 * lpPrinterName is one of:
2894 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2895 *| Printer: "PrinterName"
2896 *| Printer-Object: "PrinterName,Job xxx"
2897 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2898 *| XcvPort: "Servername,XcvPort PortName"
2902 static BOOL WINAPI fpOpenPrinter(WCHAR *name, HANDLE *hprinter,
2903 PRINTER_DEFAULTSW *def)
2905 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
2906 const WCHAR *basename;
2907 BOOL stop_search;
2909 TRACE("(%s, %p, %p)\n", debugstr_w(name), hprinter, def);
2911 if (copy_servername_from_name(name, servername))
2913 FIXME("server %s not supported\n", debugstr_w(servername));
2914 SetLastError(ERROR_INVALID_PRINTER_NAME);
2915 return FALSE;
2918 basename = get_basename_from_name(name);
2919 if (name != basename) TRACE("converted %s to %s\n",
2920 debugstr_w(name), debugstr_w(basename));
2922 /* an empty basename is invalid */
2923 if (basename && (!basename[0]))
2925 SetLastError(ERROR_INVALID_PARAMETER);
2926 return FALSE;
2929 *hprinter = server_alloc_handle(basename, &stop_search);
2930 if (!*hprinter && !stop_search)
2931 *hprinter = xcv_alloc_handle(basename, def, &stop_search);
2932 if (!*hprinter && !stop_search)
2933 *hprinter = port_alloc_handle(basename, &stop_search);
2934 if (!*hprinter && !stop_search)
2935 *hprinter = job_alloc_handle(basename, &stop_search);
2936 if (!*hprinter && !stop_search)
2937 *hprinter = printer_alloc_handle(name, basename, def);
2939 TRACE("==> %p\n", *hprinter);
2940 return *hprinter != 0;
2943 /******************************************************************************
2944 * fpXcvData [exported through PRINTPROVIDOR]
2946 * Execute commands in the Printmonitor DLL
2948 * PARAMS
2949 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2950 * pszDataName [i] Name of the command to execute
2951 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2952 * cbInputData [i] Size in Bytes of Buffer at pInputData
2953 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2954 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2955 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2956 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2958 * RETURNS
2959 * Success: TRUE
2960 * Failure: FALSE
2962 * NOTES
2963 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2964 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2966 * Minimal List of commands, that a Printmonitor DLL should support:
2968 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2969 *| "AddPort" : Add a Port
2970 *| "DeletePort": Delete a Port
2972 * Many Printmonitors support additional commands. Examples for localspl.dll:
2973 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2974 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2977 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2978 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2979 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2981 xcv_t *xcv = (xcv_t *)hXcv;
2983 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2984 pInputData, cbInputData, pOutputData,
2985 cbOutputData, pcbOutputNeeded, pdwStatus);
2987 if (!xcv || xcv->header.type != HANDLE_XCV) {
2988 SetLastError(ERROR_INVALID_HANDLE);
2989 return FALSE;
2992 if (!pcbOutputNeeded) {
2993 SetLastError(ERROR_INVALID_PARAMETER);
2994 return FALSE;
2997 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2998 SetLastError(RPC_X_NULL_REF_POINTER);
2999 return FALSE;
3002 *pcbOutputNeeded = 0;
3004 if (xcv->pm->monitor.pfnXcvDataPort)
3005 *pdwStatus = xcv->pm->monitor.pfnXcvDataPort(xcv->hxcv, pszDataName,
3006 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
3008 return TRUE;
3011 static inline size_t form_struct_size( DWORD level )
3013 if (level == 1) return sizeof(FORM_INFO_1W);
3014 if (level == 2) return sizeof(FORM_INFO_2W);
3016 SetLastError( ERROR_INVALID_LEVEL );
3017 return 0;
3020 static void fill_builtin_form_info( BYTE **base, WCHAR **strings, const struct builtin_form *form, DWORD level,
3021 DWORD size, DWORD *used )
3023 FORM_INFO_2W *info = *(FORM_INFO_2W**)base;
3024 DWORD name_len = wcslen( form->name ) + 1, res_len = 0, keyword_len, total_size;
3025 static const WCHAR dll_name[] = L"localspl.dll";
3026 const WCHAR *resource;
3028 total_size = name_len * sizeof(WCHAR);
3030 if (level > 1)
3032 keyword_len = WideCharToMultiByte( CP_ACP, 0, form->name, -1, NULL, 0, NULL, NULL );
3033 keyword_len = (keyword_len + 1) & ~1;
3034 total_size += keyword_len;
3035 res_len = LoadStringW( localspl_instance, form->res_id, (WCHAR *)&resource, 0 );
3036 if (res_len && resource[res_len - 1]) res_len++;
3037 total_size += (res_len + ARRAY_SIZE(dll_name)) * sizeof(WCHAR);
3040 if (*used + total_size <= size)
3042 info->Flags = FORM_BUILTIN;
3043 info->pName = memcpy( *strings, form->name, name_len * sizeof(WCHAR) );
3044 *strings += name_len;
3045 info->Size = form->size;
3046 info->ImageableArea.left = info->ImageableArea.top = 0;
3047 info->ImageableArea.right = info->Size.cx;
3048 info->ImageableArea.bottom = info->Size.cy;
3049 if (level > 1)
3051 info->pKeyword = (char *)*strings;
3052 WideCharToMultiByte( CP_ACP, 0, form->name, -1, (char *)info->pKeyword, keyword_len, NULL, NULL );
3053 *strings += keyword_len / sizeof(WCHAR);
3054 info->StringType = STRING_MUIDLL;
3055 info->pMuiDll = memcpy( *strings, dll_name, sizeof(dll_name) );
3056 *strings += ARRAY_SIZE(dll_name);
3057 info->dwResourceId = form->res_id;
3058 if (res_len)
3060 info->StringType |= STRING_LANGPAIR;
3061 info->pDisplayName = memcpy( *strings, resource, (res_len - 1) * sizeof(WCHAR) );
3062 info->pDisplayName[res_len - 1] = '\0';
3063 *strings += res_len;
3064 info->wLangId = GetUserDefaultLangID();
3066 else
3068 info->pDisplayName = NULL;
3069 info->wLangId = 0;
3074 *base += form_struct_size( level );
3075 *used += total_size;
3078 static BOOL WINAPI fpAddForm( HANDLE printer, DWORD level, BYTE *form )
3080 FIXME( "(%p, %ld, %p): stub\n", printer, level, form );
3081 return TRUE;
3084 static BOOL WINAPI fpDeleteForm( HANDLE printer, WCHAR *name )
3086 FIXME( "(%p, %s): stub\n", printer, debugstr_w( name ) );
3087 return TRUE;
3090 static BOOL WINAPI fpGetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3092 size_t struct_size = form_struct_size( level );
3093 const struct builtin_form *builtin = NULL;
3094 WCHAR *strings = NULL;
3095 BYTE *base = form;
3096 DWORD i;
3098 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
3100 *needed = 0;
3102 if (!struct_size) return FALSE;
3104 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
3106 if (!wcscmp( name, builtin_forms[i].name ))
3108 builtin = builtin_forms + i;
3109 break;
3113 if (!builtin)
3115 SetLastError( ERROR_INVALID_FORM_NAME );
3116 return FALSE;
3119 *needed = struct_size;
3120 if (*needed < size) strings = (WCHAR *)(form + *needed);
3122 fill_builtin_form_info( &base, &strings, builtin, level, size, needed );
3124 if (*needed > size)
3126 SetLastError( ERROR_INSUFFICIENT_BUFFER );
3127 return FALSE;
3129 return TRUE;
3132 static BOOL WINAPI fpSetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
3134 FIXME( "(%p, %s, %ld, %p): stub\n", printer, debugstr_w( name ), level, form );
3135 return FALSE;
3138 static BOOL WINAPI fpEnumForms( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
3140 DWORD num = ARRAY_SIZE(builtin_forms), i;
3141 WCHAR *strings = NULL;
3142 BYTE *base = form;
3143 size_t struct_size = form_struct_size( level );
3145 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
3147 *count = *needed = 0;
3149 if (!struct_size) return FALSE;
3151 *needed = num * struct_size;
3152 if (*needed < size) strings = (WCHAR *)(form + *needed);
3154 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
3155 fill_builtin_form_info( &base, &strings, builtin_forms + i, level, size, needed );
3157 if (*needed > size)
3159 SetLastError( ERROR_INSUFFICIENT_BUFFER );
3160 return FALSE;
3163 *count = i;
3164 return TRUE;
3167 static size_t get_spool_filename(DWORD job_id, WCHAR *buf, size_t len)
3169 static const WCHAR spool_path[] = L"spool\\PRINTERS\\";
3170 size_t ret;
3172 ret = GetSystemDirectoryW(NULL, 0) + ARRAY_SIZE(spool_path) + 10;
3173 if (len < ret)
3174 return ret;
3176 ret = GetSystemDirectoryW(buf, ret);
3177 if (buf[ret - 1] != '\\')
3178 buf[ret++] = '\\';
3179 memcpy(buf + ret, spool_path, sizeof(spool_path));
3180 ret += ARRAY_SIZE(spool_path) - 1;
3181 swprintf(buf + ret, 10, L"%05d.SPL", job_id);
3182 ret += 10;
3183 return ret;
3186 static job_info_t* add_job(printer_t *printer, DOC_INFO_1W *info, BOOL create)
3188 DWORD job_id, last_id;
3189 size_t len;
3190 job_info_t *job;
3192 job = calloc(1, sizeof(*job));
3193 if (!job)
3194 return NULL;
3195 len = get_spool_filename(0, NULL, 0);
3196 job->filename = malloc(len * sizeof(WCHAR));
3197 if (!job->filename)
3199 free(job);
3200 return NULL;
3202 job->port = wcsdup(info->pOutputFile);
3203 if (info->pOutputFile && !job->port)
3205 free(job->filename);
3206 free(job);
3207 return NULL;
3210 while (1)
3212 last_id = last_job_id;
3213 job_id = last_id < MAX_JOB_ID ? last_id + 1 : 1;
3214 if (InterlockedCompareExchange(&last_job_id, job_id, last_id) == last_id)
3215 break;
3218 job->id = job_id;
3219 get_spool_filename(job_id, job->filename, len);
3220 if (create)
3222 job->hf = CreateFileW(job->filename, GENERIC_WRITE, FILE_SHARE_READ,
3223 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3224 if (job->hf == INVALID_HANDLE_VALUE)
3226 free(job->filename);
3227 free(job);
3228 return NULL;
3231 else
3233 job->hf = NULL;
3235 job->document_title = wcsdup(info->pDocName);
3236 job->datatype = wcsdup(info->pDatatype);
3237 job->devmode = dup_devmode(printer->devmode);
3239 EnterCriticalSection(&printer->info->jobs_cs);
3240 list_add_tail(&printer->info->jobs, &job->entry);
3241 LeaveCriticalSection(&printer->info->jobs_cs);
3242 return job;
3245 static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size, DWORD *needed)
3247 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W *)data;
3248 printer_t *printer = (printer_t *)hprinter;
3249 DOC_INFO_1W doc_info;
3250 job_info_t *job;
3251 size_t len;
3253 TRACE("(%p %ld %p %ld %p)\n", hprinter, level, data, size, needed);
3255 if (!printer || printer->header.type != HANDLE_PRINTER)
3257 SetLastError(ERROR_INVALID_HANDLE);
3258 return FALSE;
3261 if (level != 1)
3263 SetLastError(ERROR_INVALID_LEVEL);
3264 return FALSE;
3267 if (!needed)
3269 SetLastError(ERROR_INVALID_PARAMETER);
3270 return FALSE;
3273 len = get_spool_filename(0, NULL, 0);
3274 *needed = sizeof(*addjob) + len * sizeof(WCHAR);
3275 if (size < *needed)
3277 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3278 return FALSE;
3281 memset(&doc_info, 0, sizeof(doc_info));
3282 doc_info.pDocName = (WCHAR *)L"Local Downlevel Document";
3283 job = add_job(printer, &doc_info, FALSE);
3284 if (!job)
3285 return FALSE;
3287 addjob->JobId = job->id;
3288 addjob->Path = (WCHAR *)(addjob + 1);
3289 memcpy(addjob->Path, job->filename, len * sizeof(WCHAR));
3290 return TRUE;
3293 typedef struct {
3294 HMODULE hmod;
3295 WCHAR *name;
3296 BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD,
3297 BYTE *, DWORD, DWORD *, DWORD *);
3298 HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *);
3299 BOOL (WINAPI *print)(HANDLE, WCHAR *);
3300 BOOL (WINAPI *close)(HANDLE);
3301 } printproc_t;
3303 static printproc_t * print_proc_load(const WCHAR *name)
3305 WCHAR *reg_path, path[2 * MAX_PATH];
3306 printproc_t *ret;
3307 DWORD size, len;
3308 LSTATUS status;
3309 HKEY hkey;
3311 size = sizeof(fmt_printprocessorsW) +
3312 (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR);
3313 reg_path = malloc(size);
3314 if (!reg_path)
3315 return NULL;
3316 swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname);
3317 wcscat(reg_path, name);
3319 status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey);
3320 free(reg_path);
3321 if (status != ERROR_SUCCESS)
3322 return NULL;
3324 if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size))
3326 RegCloseKey(hkey);
3327 return NULL;
3329 len = size / sizeof(WCHAR);
3330 path[len - 1] = '\\';
3332 size = sizeof(path) - len * sizeof(WCHAR);
3333 status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size);
3334 RegCloseKey(hkey);
3335 if (status != ERROR_SUCCESS)
3336 return NULL;
3338 ret = malloc(sizeof(*ret));
3339 if (!ret)
3340 return NULL;
3342 TRACE("loading print processor: %s\n", debugstr_w(path));
3344 ret->hmod = LoadLibraryW(path);
3345 if (!ret->hmod)
3347 free(ret);
3348 return NULL;
3351 ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW");
3352 ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor");
3353 ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor");
3354 ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor");
3355 if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close)
3357 FreeLibrary(ret->hmod);
3358 free(ret);
3359 return NULL;
3362 ret->name = wcsdup(name);
3363 return ret;
3366 static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype)
3368 DATATYPES_INFO_1W *types;
3369 DWORD size, no, i;
3371 if (!datatype)
3372 return FALSE;
3374 pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no);
3375 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3376 return FALSE;
3378 types = malloc(size);
3379 if (!types)
3380 return FALSE;
3382 if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no))
3384 free(types);
3385 return FALSE;
3388 for (i = 0; i < no; i++)
3390 if (!wcscmp(types[i].pName, datatype))
3391 break;
3393 free(types);
3394 return i < no;
3397 static void print_proc_unload(printproc_t *pp)
3399 FreeLibrary(pp->hmod);
3400 free(pp->name);
3401 free(pp);
3404 static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_info)
3406 printer_t *printer = (printer_t *)hprinter;
3407 DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info;
3408 BOOL datatype_valid;
3409 WCHAR *datatype;
3410 printproc_t *pp;
3412 TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n",
3413 hprinter, level, doc_info, debugstr_w(info->pDocName),
3414 debugstr_w(info->pOutputFile), debugstr_w(info->pDatatype));
3416 if (!printer)
3418 SetLastError(ERROR_INVALID_HANDLE);
3419 return 0;
3422 if (printer->header.type == HANDLE_PORT)
3424 port_t *port = (port_t *)hprinter;
3425 /* TODO: pass printer name and job_id */
3426 return port->mon->monitor.pfnStartDocPort(port->hport,
3427 NULL, 0, level, doc_info);
3430 if (printer->header.type != HANDLE_PRINTER)
3432 SetLastError(ERROR_INVALID_HANDLE);
3433 return 0;
3436 if (level < 1 || level > 3)
3438 SetLastError(ERROR_INVALID_LEVEL);
3439 return 0;
3442 if (printer->doc)
3444 SetLastError(ERROR_INVALID_PRINTER_STATE);
3445 return 0;
3448 if (info->pDatatype)
3449 datatype = info->pDatatype;
3450 else if (printer->datatype)
3451 datatype = printer->datatype;
3452 else
3453 datatype = printer->info->datatype;
3455 if (!datatype || ((printer->info->attributes & PRINTER_ATTRIBUTE_RAW_ONLY) &&
3456 wcsicmp(datatype, L"RAW")))
3458 TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype));
3459 SetLastError(ERROR_INVALID_DATATYPE);
3460 return 0;
3463 pp = print_proc_load(printer->info->print_proc);
3464 if (!pp)
3466 WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc));
3467 pp = print_proc_load(L"winprint");
3469 if (!pp)
3470 return 0;
3472 datatype_valid = print_proc_check_datatype(pp, datatype);
3473 print_proc_unload(pp);
3474 if (!datatype_valid)
3476 TRACE("%s datatype not supported by %s\n", debugstr_w(datatype),
3477 debugstr_w(printer->info->print_proc));
3478 SetLastError(ERROR_INVALID_DATATYPE);
3479 return 0;
3482 printer->doc = add_job(printer, info, TRUE);
3483 return printer->doc ? printer->doc->id : 0;
3486 static BOOL WINAPI fpWritePrinter(HANDLE hprinter, void *buf, DWORD size, DWORD *written)
3488 handle_header_t *header = (handle_header_t *)hprinter;
3490 TRACE("(%p, %p, %ld, %p)\n", hprinter, buf, size, written);
3492 if (!header)
3494 SetLastError(ERROR_INVALID_HANDLE);
3495 return FALSE;
3498 if (header->type == HANDLE_PORT)
3500 port_t *port = (port_t *)hprinter;
3502 return port->mon->monitor.pfnWritePort(port->hport, buf, size, written);
3505 if (header->type == HANDLE_PRINTER)
3507 printer_t *printer = (printer_t *)hprinter;
3509 if (!printer->doc)
3511 SetLastError(ERROR_SPL_NO_STARTDOC);
3512 return FALSE;
3515 return WriteFile(printer->doc->hf, buf, size, written, NULL);
3518 SetLastError(ERROR_INVALID_HANDLE);
3519 return FALSE;
3522 static BOOL WINAPI fpSetJob(HANDLE hprinter, DWORD job_id,
3523 DWORD level, BYTE *data, DWORD command)
3525 printer_t *printer = (printer_t *)hprinter;
3526 BOOL ret = FALSE;
3527 job_info_t *job;
3529 TRACE("(%p, %ld, %ld, %p, %ld)\n", hprinter, job_id, level, data, command);
3530 FIXME("Ignoring everything other than document title\n");
3532 if (!printer || printer->header.type != HANDLE_PRINTER)
3534 SetLastError(ERROR_INVALID_HANDLE);
3535 return 0;
3538 EnterCriticalSection(&printer->info->jobs_cs);
3539 job = get_job(printer->info, job_id);
3540 if (!job)
3542 LeaveCriticalSection(&printer->info->jobs_cs);
3543 return FALSE;
3546 switch(level)
3548 case 0:
3549 ret = TRUE;
3550 break;
3551 case 1:
3553 JOB_INFO_1W *info1 = (JOB_INFO_1W *)job;
3554 WCHAR *title = wcsdup(info1->pDocument);
3556 if (title)
3558 free(job->document_title);
3559 job->document_title = title;
3560 ret = TRUE;
3562 break;
3564 case 2:
3566 JOB_INFO_2W *info2 = (JOB_INFO_2W *)job;
3567 WCHAR *title = wcsdup(info2->pDocument);
3568 DEVMODEW *devmode = dup_devmode(info2->pDevMode);
3570 if (!title || !devmode)
3572 free(title);
3573 free(devmode);
3575 else
3577 free(job->document_title);
3578 free(job->devmode);
3579 job->document_title = title;
3580 job->devmode = devmode;
3581 ret = TRUE;
3583 break;
3585 case 3:
3586 FIXME("level 3 stub\n");
3587 ret = TRUE;
3588 break;
3589 default:
3590 SetLastError(ERROR_INVALID_LEVEL);
3591 break;
3594 LeaveCriticalSection(&printer->info->jobs_cs);
3595 return ret;
3598 static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level,
3599 BYTE *data, DWORD size, DWORD *needed)
3601 printer_t *printer = (printer_t *)hprinter;
3602 BOOL ret = TRUE;
3603 DWORD s = 0;
3604 job_info_t *job;
3605 WCHAR *p;
3607 TRACE("%p %ld %ld %p %ld %p\n", hprinter, job_id, level, data, size, needed);
3609 if (!printer || printer->header.type != HANDLE_PRINTER)
3611 SetLastError(ERROR_INVALID_HANDLE);
3612 return FALSE;
3615 if (!needed)
3617 SetLastError(ERROR_INVALID_PARAMETER);
3618 return FALSE;
3621 EnterCriticalSection(&printer->info->jobs_cs);
3622 job = get_job(printer->info, job_id);
3623 if (!job)
3625 LeaveCriticalSection(&printer->info->jobs_cs);
3626 return FALSE;
3629 switch(level)
3631 case 1:
3632 s = sizeof(JOB_INFO_1W);
3633 s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0;
3634 s += printer->info->name ?
3635 (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0;
3637 if (size >= s)
3639 JOB_INFO_1W *info = (JOB_INFO_1W *)data;
3641 p = (WCHAR *)(info + 1);
3642 memset(info, 0, sizeof(*info));
3643 info->JobId = job->id;
3644 if (job->document_title)
3646 info->pDocument = p;
3647 wcscpy(p, job->document_title);
3648 p += wcslen(job->document_title) + 1;
3650 if (printer->info->name)
3652 info->pPrinterName = p;
3653 wcscpy(p, printer->info->name);
3656 break;
3657 case 2:
3658 s = sizeof(JOB_INFO_2W);
3659 s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0;
3660 s += printer->info->name ?
3661 (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0;
3662 if (job->devmode)
3664 /* align DEVMODE to a DWORD boundary */
3665 s += (4 - (s & 3)) & 3;
3666 s += job->devmode->dmSize + job->devmode->dmDriverExtra;
3669 if (size >= s)
3671 JOB_INFO_2W *info = (JOB_INFO_2W *)data;
3673 p = (WCHAR *)(info + 1);
3674 memset(info, 0, sizeof(*info));
3675 info->JobId = job->id;
3676 if (job->document_title)
3678 info->pDocument = p;
3679 wcscpy(p, job->document_title);
3680 p += wcslen(job->document_title) + 1;
3682 if (printer->info->name)
3684 info->pPrinterName = p;
3685 wcscpy(p, printer->info->name);
3686 p += wcslen(printer->info->name) + 1;
3688 if (job->devmode)
3690 DEVMODEW *devmode = (DEVMODEW *)(data + s - job->devmode->dmSize
3691 - job->devmode->dmDriverExtra);
3692 info->pDevMode = devmode;
3693 memcpy(devmode, job->devmode, job->devmode->dmSize + job->devmode->dmDriverExtra);
3696 break;
3697 case 3:
3698 FIXME("level 3 stub\n");
3699 s = sizeof(JOB_INFO_3);
3701 if (size >= s)
3702 memset(data, 0, sizeof(JOB_INFO_3));
3703 break;
3704 default:
3705 SetLastError(ERROR_INVALID_LEVEL);
3706 ret = FALSE;
3707 break;
3710 LeaveCriticalSection(&printer->info->jobs_cs);
3712 *needed = s;
3713 if (size < s)
3715 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3716 ret = FALSE;
3718 return ret;
3721 static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id)
3723 printer_t *printer = (printer_t *)hprinter;
3724 WCHAR output[1024], name[1024], *datatype;
3725 PRINTPROCESSOROPENDATA pp_data;
3726 const WCHAR *port_name, *port;
3727 job_info_t *job;
3728 printproc_t *pp;
3729 BOOL ret = TRUE;
3730 HANDLE hpp;
3731 HKEY hkey;
3733 TRACE("%p %ld\n", hprinter, job_id);
3735 if (!printer || printer->header.type != HANDLE_PRINTER)
3737 SetLastError(ERROR_INVALID_HANDLE);
3738 return FALSE;
3741 EnterCriticalSection(&printer->info->jobs_cs);
3742 job = get_job(printer->info, job_id);
3743 if (!job)
3745 LeaveCriticalSection(&printer->info->jobs_cs);
3746 return FALSE;
3749 port = job->port;
3750 if (!port || !*port)
3751 port = printer->info->port;
3752 TRACE("need to schedule job %ld filename %s to port %s\n", job->id,
3753 debugstr_w(job->filename), debugstr_w(port));
3755 port_name = port;
3756 if ((isalpha(port[0]) && port[1] == ':') ||
3757 !wcsncmp(port, L"FILE:", ARRAY_SIZE(L"FILE:") - 1))
3759 port_name = L"FILE:";
3761 else if (!RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Wine\\Printing\\Spooler", &hkey))
3763 DWORD type, count = sizeof(output);
3764 if (!RegQueryValueExW(hkey, port, NULL, &type, (BYTE *)output, &count))
3766 TRACE("overriding port %s -> %s\n", debugstr_w(port), debugstr_w(output));
3767 port_name = output;
3769 RegCloseKey(hkey);
3772 pp = print_proc_load(printer->info->print_proc);
3773 if (!pp)
3775 WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc));
3776 pp = print_proc_load(L"winprint");
3778 if (!pp)
3779 return FALSE;
3781 if (job->datatype)
3782 datatype = job->datatype;
3783 else if (printer->datatype)
3784 datatype = printer->datatype;
3785 else
3786 datatype = printer->info->datatype;
3788 if (!print_proc_check_datatype(pp, datatype))
3790 WARN("%s datatype not supported by %s\n", debugstr_w(datatype),
3791 debugstr_w(printer->info->print_proc));
3792 print_proc_unload(pp);
3793 return FALSE;
3796 swprintf(name, ARRAY_SIZE(name), L"%s, Port", port_name);
3797 pp_data.pDevMode = job->devmode;
3798 pp_data.pDatatype = datatype;
3799 pp_data.pParameters = NULL;
3800 pp_data.pDocumentName = job->document_title;
3801 pp_data.JobId = job->id;
3802 pp_data.pOutputFile = (WCHAR *)port;
3803 pp_data.pPrinterName = printer->name;
3804 hpp = pp->open(name, &pp_data);
3805 if (!hpp)
3807 WARN("OpenPrintProcessor failed %ld\n", GetLastError());
3808 print_proc_unload(pp);
3809 return FALSE;
3812 swprintf(name, ARRAY_SIZE(name), L"%s, Job %d", printer->name, job->id);
3813 ret = pp->print(hpp, name);
3814 if (!ret)
3815 WARN("PrintDocumentOnPrintProcessor failed %ld\n", GetLastError());
3816 pp->close(hpp);
3817 print_proc_unload(pp);
3819 if (!(printer->info->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS))
3820 DeleteFileW(job->filename);
3821 free_job(job);
3822 LeaveCriticalSection(&printer->info->jobs_cs);
3823 return ret;
3826 static BOOL WINAPI fpReadPrinter(HANDLE hprinter, void *buf, DWORD size, DWORD *bytes_read)
3828 job_t *job = (job_t *)hprinter;
3830 TRACE("%p %p %lu %p\n", hprinter, buf, size, bytes_read);
3832 if (!job || (job->header.type != HANDLE_JOB))
3834 SetLastError(ERROR_INVALID_HANDLE);
3835 return FALSE;
3838 return ReadFile(job->hf, buf, size, bytes_read, NULL);
3841 static BOOL WINAPI fpEndDocPrinter(HANDLE hprinter)
3843 printer_t *printer = (printer_t *)hprinter;
3844 BOOL ret;
3846 TRACE("%p\n", hprinter);
3848 if (!printer)
3850 SetLastError(ERROR_INVALID_HANDLE);
3851 return 0;
3854 if (printer->header.type == HANDLE_PORT)
3856 port_t *port = (port_t *)hprinter;
3857 return port->mon->monitor.pfnEndDocPort(port->hport);
3860 if (printer->header.type != HANDLE_PRINTER)
3862 SetLastError(ERROR_INVALID_HANDLE);
3863 return FALSE;
3866 if (!printer->doc)
3868 SetLastError(ERROR_SPL_NO_STARTDOC);
3869 return FALSE;
3872 CloseHandle(printer->doc->hf);
3873 printer->doc->hf = NULL;
3874 ret = fpScheduleJob(hprinter, printer->doc->id);
3875 printer->doc = NULL;
3876 return ret;
3879 /******************************************************************************
3880 * fpClosePrinter [exported through PRINTPROVIDOR]
3882 * Close a printer handle and free associated resources
3884 * PARAMS
3885 * hPrinter [I] Printerhandle to close
3887 * RESULTS
3888 * Success: TRUE
3889 * Failure: FALSE
3892 static BOOL WINAPI fpClosePrinter(HANDLE hprinter)
3894 handle_header_t *header = (handle_header_t *)hprinter;
3896 TRACE("(%p)\n", hprinter);
3898 if (!header)
3899 return FALSE;
3901 if (header->type == HANDLE_SERVER)
3903 free(header);
3905 else if (header->type == HANDLE_XCV)
3907 xcv_t *xcv = (xcv_t *)hprinter;
3909 if (xcv->hxcv && xcv->pm->monitor.pfnXcvClosePort)
3910 xcv->pm->monitor.pfnXcvClosePort(xcv->hxcv);
3912 monitor_unload(xcv->pm);
3913 free(xcv);
3915 else if (header->type == HANDLE_PORT)
3917 port_t *port = (port_t *)hprinter;
3919 if (port->hport)
3920 port->mon->monitor.pfnClosePort(port->hport);
3921 if (port->mon)
3922 monitor_unload(port->mon);
3923 free(port);
3925 else if (header->type == HANDLE_JOB)
3927 job_t *job = (job_t *)hprinter;
3929 CloseHandle(job->hf);
3930 free(job);
3932 else if (header->type == HANDLE_PRINTER)
3934 printer_t *printer = (printer_t *)hprinter;
3936 if(printer->doc)
3937 fpEndDocPrinter(hprinter);
3939 release_printer_info(printer->info);
3940 free(printer->name);
3941 free(printer->datatype);
3942 free(printer->devmode);
3943 free(printer);
3945 else
3947 ERR("invalid handle type\n");
3948 return FALSE;
3950 return TRUE;
3953 static BOOL WINAPI fpSeekPrinter(HANDLE hprinter, LARGE_INTEGER distance,
3954 LARGE_INTEGER *pos, DWORD method, BOOL bwrite)
3956 job_t *job = (job_t *)hprinter;
3958 TRACE("(%p %I64d %p %lx %x)\n", hprinter, distance.QuadPart, pos, method, bwrite);
3960 if (!job)
3962 SetLastError(ERROR_INVALID_HANDLE);
3963 return FALSE;
3966 if (job->header.type != HANDLE_JOB)
3968 FIXME("handle %x not supported\n", job->header.type);
3969 return FALSE;
3972 if (bwrite)
3974 if (pos)
3975 pos->QuadPart = 0;
3976 return TRUE;
3979 return SetFilePointerEx(job->hf, distance, pos, method);
3982 static const PRINTPROVIDOR backend = {
3983 fpOpenPrinter,
3984 fpSetJob,
3985 fpGetJob,
3986 NULL, /* fpEnumJobs */
3987 NULL, /* fpAddPrinter */
3988 NULL, /* fpDeletePrinter */
3989 NULL, /* fpSetPrinter */
3990 NULL, /* fpGetPrinter */
3991 NULL, /* fpEnumPrinters */
3992 NULL, /* fpAddPrinterDriver */
3993 NULL, /* fpEnumPrinterDrivers */
3994 NULL, /* fpGetPrinterDriver */
3995 fpGetPrinterDriverDirectory,
3996 NULL, /* fpDeletePrinterDriver */
3997 fpAddPrintProcessor,
3998 fpEnumPrintProcessors,
3999 fpGetPrintProcessorDirectory,
4000 NULL, /* fpDeletePrintProcessor */
4001 NULL, /* fpEnumPrintProcessorDatatypes */
4002 fpStartDocPrinter,
4003 NULL, /* fpStartPagePrinter */
4004 fpWritePrinter,
4005 NULL, /* fpEndPagePrinter */
4006 NULL, /* fpAbortPrinter */
4007 fpReadPrinter,
4008 fpEndDocPrinter,
4009 fpAddJob,
4010 fpScheduleJob,
4011 NULL, /* fpGetPrinterData */
4012 NULL, /* fpSetPrinterData */
4013 NULL, /* fpWaitForPrinterChange */
4014 fpClosePrinter,
4015 fpAddForm,
4016 fpDeleteForm,
4017 fpGetForm,
4018 fpSetForm,
4019 fpEnumForms,
4020 fpEnumMonitors,
4021 fpEnumPorts,
4022 fpAddPort,
4023 fpConfigurePort,
4024 fpDeletePort,
4025 NULL, /* fpCreatePrinterIC */
4026 NULL, /* fpPlayGdiScriptOnPrinterIC */
4027 NULL, /* fpDeletePrinterIC */
4028 NULL, /* fpAddPrinterConnection */
4029 NULL, /* fpDeletePrinterConnection */
4030 NULL, /* fpPrinterMessageBox */
4031 fpAddMonitor,
4032 fpDeleteMonitor,
4033 NULL, /* fpResetPrinter */
4034 NULL, /* fpGetPrinterDriverEx */
4035 NULL, /* fpFindFirstPrinterChangeNotification */
4036 NULL, /* fpFindClosePrinterChangeNotification */
4037 fpAddPortEx,
4038 NULL, /* fpShutDown */
4039 NULL, /* fpRefreshPrinterChangeNotification */
4040 NULL, /* fpOpenPrinterEx */
4041 NULL, /* fpAddPrinterEx */
4042 NULL, /* fpSetPort */
4043 NULL, /* fpEnumPrinterData */
4044 NULL, /* fpDeletePrinterData */
4045 NULL, /* fpClusterSplOpen */
4046 NULL, /* fpClusterSplClose */
4047 NULL, /* fpClusterSplIsAlive */
4048 NULL, /* fpSetPrinterDataEx */
4049 NULL, /* fpGetPrinterDataEx */
4050 NULL, /* fpEnumPrinterDataEx */
4051 NULL, /* fpEnumPrinterKey */
4052 NULL, /* fpDeletePrinterDataEx */
4053 NULL, /* fpDeletePrinterKey */
4054 fpSeekPrinter,
4055 NULL, /* fpDeletePrinterDriverEx */
4056 NULL, /* fpAddPerMachineConnection */
4057 NULL, /* fpDeletePerMachineConnection */
4058 NULL, /* fpEnumPerMachineConnections */
4059 fpXcvData,
4060 fpAddPrinterDriverEx,
4061 NULL, /* fpSplReadPrinter */
4062 NULL, /* fpDriverUnloadComplete */
4063 NULL, /* fpGetSpoolFileInfo */
4064 NULL, /* fpCommitSpoolData */
4065 NULL, /* fpCloseSpoolFileHandle */
4066 NULL, /* fpFlushPrinter */
4067 NULL, /* fpSendRecvBidiData */
4068 NULL /* fpAddDriverCatalog */
4071 /*****************************************************
4072 * InitializePrintProvidor (localspl.@)
4074 * Initialize the Printprovider
4076 * PARAMS
4077 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
4078 * cbPrintProvidor [I] Size of Buffer in Bytes
4079 * pFullRegistryPath [I] Registry-Path for the Printprovidor
4081 * RETURNS
4082 * Success: TRUE and pPrintProvidor filled
4083 * Failure: FALSE
4085 * NOTES
4086 * The RegistryPath should be:
4087 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
4088 * but this Parameter is ignored in "localspl.dll".
4092 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
4093 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
4096 TRACE("(%p, %lu, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
4097 memcpy(pPrintProvidor, &backend,
4098 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
4100 return TRUE;