msxml4/tests: Copy namespaces as attributes tests.
[wine.git] / dlls / localspl / provider.c
blob26e9c66bea0f7c769f1a158ecb1ab767c09bca76
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 *print_proc;
281 WCHAR *datatype;
282 DEVMODEW *devmode;
283 job_info_t *doc;
284 } printer_t;
286 /* ############################### */
288 static struct list monitor_handles = LIST_INIT( monitor_handles );
289 static monitor_t * pm_localport;
291 static struct list printers = LIST_INIT(printers);
292 static LONG last_job_id;
294 static const WCHAR fmt_driversW[] =
295 L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
296 static const WCHAR fmt_printprocessorsW[] =
297 L"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors\\";
298 static const WCHAR monitorsW[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
299 static const WCHAR printersW[] = L"System\\CurrentControlSet\\Control\\Print\\Printers";
300 static const WCHAR winnt_cv_portsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
301 static const WCHAR x86_envnameW[] = L"Windows NT x86";
304 static const printenv_t env_ia64 = {L"Windows IA64", L"ia64", 3,
305 L"\\Version-3", L"\\3"};
307 static const printenv_t env_x86 = {x86_envnameW, L"w32x86", 3,
308 L"\\Version-3", L"\\3"};
310 static const printenv_t env_x64 = {L"Windows x64", L"x64", 3,
311 L"\\Version-3", L"\\3"};
313 static const printenv_t env_arm = {L"Windows ARM", L"arm", 3,
314 L"\\Version-3", L"\\3"};
316 static const printenv_t env_arm64 = {L"Windows ARM64", L"arm64", 3,
317 L"\\Version-3", L"\\3"};
319 static const printenv_t env_win40 = {L"Windows 4.0", L"win40", 0,
320 L"\\Version-0", L"\\0"};
322 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_arm, &env_arm64, &env_win40};
324 #ifdef __i386__
325 #define env_arch env_x86
326 #elif defined __x86_64__
327 #define env_arch env_x64
328 #elif defined __arm__
329 #define env_arch env_arm
330 #elif defined __aarch64__
331 #define env_arch env_arm64
332 #else
333 #error not defined for this cpu
334 #endif
337 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
338 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
339 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
340 0, sizeof(DRIVER_INFO_8W)};
342 static BOOL WINAPI fpClosePrinter(HANDLE);
344 /******************************************************************
345 * apd_copyfile [internal]
347 * Copy a file from the driverdirectory to the versioned directory
349 * RETURNS
350 * Success: TRUE
351 * Failure: FALSE
354 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
356 WCHAR *srcname;
357 BOOL res;
359 apd->src[apd->srclen] = '\0';
360 apd->dst[apd->dstlen] = '\0';
362 if (!pathname || !pathname[0]) {
363 /* nothing to copy */
364 return TRUE;
367 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
368 srcname = pathname;
369 else
371 srcname = apd->src;
372 lstrcatW( srcname, file_part );
374 lstrcatW( apd->dst, file_part );
376 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
378 /* FIXME: handle APD_COPY_NEW_FILES */
379 res = CopyFileW(srcname, apd->dst, FALSE);
380 TRACE("got %d with %lu\n", res, GetLastError());
382 return apd->lazy || res;
385 /******************************************************************
386 * copy_servername_from_name (internal)
388 * for an external server, the serverpart from the name is copied.
390 * RETURNS
391 * the length (in WCHAR) of the serverpart (0 for the local computer)
392 * (-length), when the name is too long
395 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
397 LPCWSTR server;
398 LPWSTR ptr;
399 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
400 DWORD len;
401 DWORD serverlen;
403 if (target) *target = '\0';
405 if (name == NULL) return 0;
406 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
408 server = &name[2];
409 /* skip over both backslash, find separator '\' */
410 ptr = wcschr(server, '\\');
411 serverlen = (ptr) ? ptr - server : wcslen(server);
413 /* servername is empty */
414 if (serverlen == 0) return 0;
416 TRACE("found %s\n", debugstr_wn(server, serverlen));
418 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
420 if (target) {
421 memcpy(target, server, serverlen * sizeof(WCHAR));
422 target[serverlen] = '\0';
425 len = ARRAY_SIZE(buffer);
426 if (GetComputerNameW(buffer, &len)) {
427 if ((serverlen == len) && (wcsnicmp(server, buffer, len) == 0)) {
428 /* The requested Servername is our computername */
429 return 0;
432 return serverlen;
435 /******************************************************************
436 * get_basename_from_name (internal)
438 * skip over the serverpart from the full name
441 static LPCWSTR get_basename_from_name(LPCWSTR name)
443 if (name == NULL) return NULL;
444 if ((name[0] == '\\') && (name[1] == '\\')) {
445 /* skip over the servername and search for the following '\' */
446 name = wcschr(&name[2], '\\');
447 if ((name) && (name[1])) {
448 /* found a separator ('\') followed by a name:
449 skip over the separator and return the rest */
450 name++;
452 else
454 /* no basename present (we found only a servername) */
455 return NULL;
458 return name;
461 /******************************************************************
462 * monitor_unload [internal]
464 * release a printmonitor and unload it from memory, when needed
467 static void monitor_unload(monitor_t * pm)
469 if (pm == NULL) return;
470 TRACE("%p (refcount: %ld) %s\n", pm, pm->refcount, debugstr_w(pm->name));
472 EnterCriticalSection(&monitor_handles_cs);
474 if (pm->refcount) pm->refcount--;
476 if (pm->refcount == 0) {
477 list_remove(&pm->entry);
479 if (pm->monitor.pfnShutdown)
480 pm->monitor.pfnShutdown(pm->hmon);
482 FreeLibrary(pm->hdll);
483 free(pm->name);
484 free(pm->dllname);
485 free(pm);
487 LeaveCriticalSection(&monitor_handles_cs);
490 /******************************************************************
491 * monitor_unloadall [internal]
493 * release all registered printmonitors and unload them from memory, when needed
497 static void monitor_unloadall(void)
499 monitor_t * pm;
500 monitor_t * next;
502 EnterCriticalSection(&monitor_handles_cs);
503 /* iterate through the list, with safety against removal */
504 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
506 /* skip monitorui dlls */
507 if (pm->monitor.cbSize) monitor_unload(pm);
509 LeaveCriticalSection(&monitor_handles_cs);
512 static printer_info_t *find_printer_info(const WCHAR *name, unsigned int len)
514 printer_info_t *info;
516 EnterCriticalSection(&printers_cs);
517 LIST_FOR_EACH_ENTRY(info, &printers, printer_info_t, entry)
519 if (!wcsncmp(info->name, name, len) && (len == -1 || !info->name[len]))
521 InterlockedIncrement(&info->ref);
522 LeaveCriticalSection(&printers_cs);
523 return info;
526 LeaveCriticalSection(&printers_cs);
527 return NULL;
530 static WCHAR * reg_query_value(HKEY key, const WCHAR *name)
532 DWORD size, type;
533 WCHAR *ret;
535 if (RegQueryValueExW(key, name, 0, &type, NULL, &size) != ERROR_SUCCESS
536 || type != REG_SZ)
537 return NULL;
539 ret = malloc(size);
540 if (!ret)
541 return NULL;
543 if (RegQueryValueExW(key, name, 0, NULL, (BYTE *)ret, &size) != ERROR_SUCCESS)
545 free(ret);
546 return NULL;
548 return ret;
551 static DWORD reg_query_dword(HKEY hkey, const WCHAR *name)
553 DWORD type, val, size = sizeof(size);
555 if (RegQueryValueExW(hkey, name, 0, &type, (BYTE*)&val, &size))
556 return 0;
557 if (type != REG_DWORD)
558 return 0;
559 return val;
562 static printer_info_t* get_printer_info(const WCHAR *name)
564 HKEY hkey, hprinter = NULL;
565 printer_info_t *info;
566 LSTATUS ret;
568 EnterCriticalSection(&printers_cs);
569 info = find_printer_info(name, -1);
570 if (info)
572 LeaveCriticalSection(&printers_cs);
573 return info;
576 ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkey);
577 if (ret == ERROR_SUCCESS)
578 ret = RegOpenKeyW(hkey, name, &hprinter);
579 RegCloseKey(hkey);
580 if (ret != ERROR_SUCCESS)
582 LeaveCriticalSection(&printers_cs);
583 return NULL;
586 info = calloc(1, sizeof(*info));
587 if (!info)
589 LeaveCriticalSection(&printers_cs);
590 RegCloseKey(hprinter);
591 return NULL;
594 info->name = wcsdup(name);
595 info->port = reg_query_value(hprinter, L"Port");
596 info->print_proc = reg_query_value(hprinter, L"Print Processor");
597 info->datatype = reg_query_value(hprinter, L"Datatype");
598 info->attributes = reg_query_dword(hprinter, L"Attributes");
599 RegCloseKey(hprinter);
601 if (!info->name || !info->port || !info->print_proc || !info->datatype)
603 free(info->name);
604 free(info->port);
605 free(info->print_proc);
606 free(info->datatype);
607 free(info);
609 LeaveCriticalSection(&printers_cs);
610 return NULL;
613 info->ref = 1;
614 list_add_head(&printers, &info->entry);
615 InitializeCriticalSection(&info->jobs_cs);
616 list_init(&info->jobs);
618 LeaveCriticalSection(&printers_cs);
619 return info;
622 static void free_job(job_info_t *job)
624 list_remove(&job->entry);
625 free(job->filename);
626 free(job->port);
627 free(job->datatype);
628 free(job->document_title);
629 free(job->devmode);
630 CloseHandle(job->hf);
631 free(job);
634 static void release_printer_info(printer_info_t *info)
636 if (!info)
637 return;
639 if (!InterlockedDecrement(&info->ref))
641 EnterCriticalSection(&printers_cs);
642 list_remove(&info->entry);
643 LeaveCriticalSection(&printers_cs);
645 free(info->name);
646 free(info->port);
647 free(info->print_proc);
648 free(info->datatype);
649 DeleteCriticalSection(&info->jobs_cs);
650 while (!list_empty(&info->jobs))
652 job_info_t *job = LIST_ENTRY(list_head(&info->jobs), job_info_t, entry);
653 free_job(job);
655 free(info);
659 static DEVMODEW * dup_devmode(const DEVMODEW *dm)
661 DEVMODEW *ret;
663 if (!dm) return NULL;
664 ret = malloc(dm->dmSize + dm->dmDriverExtra);
665 if (ret) memcpy(ret, dm, dm->dmSize + dm->dmDriverExtra);
666 return ret;
669 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
670 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
671 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
673 FIXME("stub\n");
674 return ERROR_CALL_NOT_IMPLEMENTED;
677 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
678 PHANDLE phkResult, HANDLE hSpooler)
680 FIXME("stub\n");
681 return ERROR_CALL_NOT_IMPLEMENTED;
684 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
686 FIXME("stub\n");
687 return ERROR_CALL_NOT_IMPLEMENTED;
690 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
692 FIXME("stub\n");
693 return ERROR_CALL_NOT_IMPLEMENTED;
696 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
697 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
699 FIXME("stub\n");
700 return ERROR_CALL_NOT_IMPLEMENTED;
703 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
704 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
705 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
706 HANDLE hSpooler)
708 FIXME("stub\n");
709 return ERROR_CALL_NOT_IMPLEMENTED;
712 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
713 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
715 FIXME("stub\n");
716 return ERROR_CALL_NOT_IMPLEMENTED;
719 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
721 FIXME("stub\n");
722 return ERROR_CALL_NOT_IMPLEMENTED;
725 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
726 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
727 HANDLE hSpooler)
729 FIXME("stub\n");
730 return ERROR_CALL_NOT_IMPLEMENTED;
733 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
734 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
736 FIXME("stub\n");
737 return ERROR_CALL_NOT_IMPLEMENTED;
740 static MONITORREG monreg =
742 sizeof(MONITORREG),
743 CreateKey,
744 OpenKey,
745 CloseKey,
746 DeleteKey,
747 EnumKey,
748 QueryInfoKey,
749 SetValue,
750 DeleteValue,
751 EnumValue,
752 QueryValue
755 static BOOL WINAPI monitor2_EnumPorts(HANDLE hmon, WCHAR *name, DWORD level,
756 BYTE *buf, DWORD size, DWORD *needed, DWORD *count)
758 return ((MONITOREX*)hmon)->Monitor.pfnEnumPorts(name, level,
759 buf, size, needed, count);
762 static BOOL WINAPI monitor2_OpenPort(HANDLE hmon, WCHAR *name, HANDLE *hport)
764 return ((MONITOREX*)hmon)->Monitor.pfnOpenPort(name, hport);
767 static BOOL WINAPI monitor2_AddPort(HANDLE hmon, WCHAR *name,
768 HWND hwnd, WCHAR *monitor_name)
770 return ((MONITOREX*)hmon)->Monitor.pfnAddPort(name, hwnd, monitor_name);
773 static BOOL WINAPI monitor2_AddPortEx(HANDLE hmon, WCHAR *name, DWORD level,
774 BYTE *buf, WCHAR *monitor_name)
776 return ((MONITOREX*)hmon)->Monitor.pfnAddPortEx(name, level, buf, monitor_name);
779 static BOOL WINAPI monitor2_ConfigurePort(HANDLE hmon, WCHAR *name,
780 HWND hwnd, WCHAR *port_name)
782 return ((MONITOREX*)hmon)->Monitor.pfnConfigurePort(name, hwnd, port_name);
785 static BOOL WINAPI monitor2_DeletePort(HANDLE hmon, WCHAR *name,
786 HWND hwnd, WCHAR *port_name)
788 return ((MONITOREX*)hmon)->Monitor.pfnDeletePort(name, hwnd, port_name);
791 static BOOL WINAPI monitor2_XcvOpenPort(HANDLE hmon, const WCHAR *obj,
792 ACCESS_MASK granted_access, HANDLE *hxcv)
794 return ((MONITOREX*)hmon)->Monitor.pfnXcvOpenPort(obj, granted_access, hxcv);
797 /******************************************************************
798 * monitor_load [internal]
800 * load a printmonitor, get the dllname from the registry, when needed
801 * initialize the monitor and dump found function-pointers
803 * On failure, SetLastError() is called and NULL is returned
806 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
808 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
809 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
810 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
811 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
812 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
814 monitor_t * pm = NULL;
815 monitor_t * cursor;
816 LPWSTR regroot = NULL;
817 LPWSTR driver = dllname;
818 HKEY hroot = 0;
820 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
821 /* Is the Monitor already loaded? */
822 EnterCriticalSection(&monitor_handles_cs);
824 if (name) {
825 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
827 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
828 pm = cursor;
829 break;
834 if (pm == NULL) {
835 pm = calloc(1, sizeof(monitor_t));
836 if (pm == NULL) goto cleanup;
837 list_add_tail(&monitor_handles, &pm->entry);
839 pm->refcount++;
841 if (pm->name == NULL) {
842 /* Load the monitor */
843 DWORD len;
845 if (name) {
846 len = wcslen(monitorsW) + wcslen(name) + 2;
847 regroot = malloc(len * sizeof(WCHAR));
850 if (regroot) {
851 lstrcpyW(regroot, monitorsW);
852 lstrcatW(regroot, name);
853 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
854 /* Get the Driver from the Registry */
855 if (!driver)
856 driver = reg_query_value(hroot, L"Driver");
858 else
859 WARN("%s not found\n", debugstr_w(regroot));
862 pm->name = wcsdup(name);
863 pm->dllname = wcsdup(driver);
865 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
866 monitor_unload(pm);
867 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
868 pm = NULL;
869 goto cleanup;
872 pm->hdll = LoadLibraryW(driver);
873 TRACE("%p: LoadLibrary(%s) => %ld\n", pm->hdll, debugstr_w(driver), GetLastError());
875 if (pm->hdll == NULL) {
876 monitor_unload(pm);
877 SetLastError(ERROR_MOD_NOT_FOUND);
878 pm = NULL;
879 goto cleanup;
882 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
883 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
884 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
885 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
886 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
889 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
890 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
891 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
892 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
893 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
895 if (pInitializePrintMonitorUI != NULL) {
896 pm->monitorUI = pInitializePrintMonitorUI();
897 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
898 if (pm->monitorUI) {
899 TRACE("0x%08lx: dwMonitorSize (%ld)\n",
900 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
905 if (pInitializePrintMonitor2 && hroot) {
906 MONITORINIT init;
907 MONITOR2 *monitor2;
908 HANDLE hmon;
910 memset(&init, 0, sizeof(init));
911 init.cbSize = sizeof(init);
912 init.hckRegistryRoot = hroot;
913 init.pMonitorReg = &monreg;
914 init.bLocal = TRUE;
916 monitor2 = pInitializePrintMonitor2(&init, &hmon);
917 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
918 monitor2, debugstr_w(driver), debugstr_w(regroot));
919 if (monitor2)
921 memcpy(&pm->monitor, monitor2, min(monitor2->cbSize, sizeof(pm->monitor)));
922 pm->hmon = hmon;
925 else if (pInitializePrintMonitor && regroot) {
927 pm->monitorex = pInitializePrintMonitor(regroot);
928 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
929 pm->monitorex, debugstr_w(driver), debugstr_w(regroot));
930 if (pm->monitorex)
932 pm->hmon = (HANDLE)pm->monitorex;
934 pm->monitor.cbSize = sizeof(pm->monitor);
935 if (pm->monitorex->Monitor.pfnEnumPorts)
936 pm->monitor.pfnEnumPorts = monitor2_EnumPorts;
937 if (pm->monitorex->Monitor.pfnOpenPort)
938 pm->monitor.pfnOpenPort = monitor2_OpenPort;
939 pm->monitor.pfnStartDocPort = pm->monitorex->Monitor.pfnStartDocPort;
940 pm->monitor.pfnWritePort = pm->monitorex->Monitor.pfnWritePort;
941 pm->monitor.pfnReadPort = pm->monitorex->Monitor.pfnReadPort;
942 pm->monitor.pfnEndDocPort = pm->monitorex->Monitor.pfnEndDocPort;
943 pm->monitor.pfnClosePort = pm->monitorex->Monitor.pfnClosePort;
944 if (pm->monitorex->Monitor.pfnAddPort)
945 pm->monitor.pfnAddPort = monitor2_AddPort;
946 if (pm->monitorex->Monitor.pfnAddPortEx)
947 pm->monitor.pfnAddPortEx = monitor2_AddPortEx;
948 if (pm->monitorex->Monitor.pfnConfigurePort)
949 pm->monitor.pfnConfigurePort = monitor2_ConfigurePort;
950 if (pm->monitorex->Monitor.pfnDeletePort)
951 pm->monitor.pfnDeletePort = monitor2_DeletePort;
952 pm->monitor.pfnGetPrinterDataFromPort =
953 pm->monitorex->Monitor.pfnGetPrinterDataFromPort;
954 pm->monitor.pfnSetPortTimeOuts = pm->monitorex->Monitor.pfnSetPortTimeOuts;
955 if (pm->monitorex->Monitor.pfnXcvOpenPort)
956 pm->monitor.pfnXcvOpenPort = monitor2_XcvOpenPort;
957 pm->monitor.pfnXcvDataPort = pm->monitorex->Monitor.pfnXcvDataPort;
958 pm->monitor.pfnXcvClosePort = pm->monitorex->Monitor.pfnXcvClosePort;
962 if (!pm->monitor.cbSize && regroot) {
963 if (pInitializeMonitorEx != NULL) {
964 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
966 if (pInitializeMonitor != NULL) {
967 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
970 if (!pm->monitor.cbSize && !pm->monitorUI) {
971 monitor_unload(pm);
972 SetLastError(ERROR_PROC_NOT_FOUND);
973 pm = NULL;
976 cleanup:
977 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, L"Local Port") == 0)) {
978 pm->refcount++;
979 pm_localport = pm;
981 LeaveCriticalSection(&monitor_handles_cs);
982 if (driver != dllname) free(driver);
983 if (hroot) RegCloseKey(hroot);
984 free(regroot);
985 TRACE("=> %p\n", pm);
986 return pm;
989 /******************************************************************
990 * monitor_loadall [internal]
992 * Load all registered monitors
995 static DWORD monitor_loadall(void)
997 monitor_t * pm;
998 DWORD registered = 0;
999 DWORD loaded = 0;
1000 HKEY hmonitors;
1001 WCHAR buffer[MAX_PATH];
1002 DWORD id = 0;
1004 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
1005 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1006 NULL, NULL, NULL, NULL, NULL);
1008 TRACE("%ld monitors registered\n", registered);
1010 while (id < registered) {
1011 buffer[0] = '\0';
1012 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1013 pm = monitor_load(buffer, NULL);
1014 if (pm) loaded++;
1015 id++;
1017 RegCloseKey(hmonitors);
1019 TRACE("%ld monitors loaded\n", loaded);
1020 return loaded;
1023 /******************************************************************
1024 * monitor_loadui [internal]
1026 * load the userinterface-dll for a given portmonitor
1028 * On failure, NULL is returned
1030 static monitor_t * monitor_loadui(monitor_t * pm)
1032 monitor_t * pui = NULL;
1033 WCHAR buffer[MAX_PATH];
1034 HANDLE hXcv;
1035 DWORD len;
1036 DWORD res = 0;
1038 if (pm == NULL) return NULL;
1039 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1041 /* Try the Portmonitor first; works for many monitors */
1042 if (pm->monitorUI) {
1043 EnterCriticalSection(&monitor_handles_cs);
1044 pm->refcount++;
1045 LeaveCriticalSection(&monitor_handles_cs);
1046 return pm;
1049 /* query the userinterface-dllname from the Portmonitor */
1050 /* building (",XcvMonitor %s",pm->name) not needed yet */
1051 if (pm->monitor.pfnXcvOpenPort)
1052 res = pm->monitor.pfnXcvOpenPort(pm->hmon, L"", SERVER_ACCESS_ADMINISTER, &hXcv);
1053 TRACE("got %lu with %p\n", res, hXcv);
1054 if (res) {
1055 res = pm->monitor.pfnXcvDataPort(hXcv, L"MonitorUI", NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1056 TRACE("got %lu with %s\n", res, debugstr_w(buffer));
1057 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
1058 pm->monitor.pfnXcvClosePort(hXcv);
1060 return pui;
1063 /******************************************************************
1064 * monitor_load_by_port [internal]
1066 * load a printmonitor for a given port
1068 * On failure, NULL is returned
1071 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1073 HKEY hroot;
1074 HKEY hport;
1075 LPWSTR buffer;
1076 monitor_t * pm = NULL;
1077 DWORD registered = 0;
1078 DWORD id = 0;
1079 DWORD len;
1081 TRACE("(%s)\n", debugstr_w(portname));
1083 /* wine specific ports */
1084 if (portname[0] == '|' || portname[0] == '/' ||
1085 !wcsncmp(portname, L"LPR:", 4) || !wcsncmp(portname, L"CUPS:", 5))
1086 return monitor_load(L"Local Port", NULL);
1088 /* Try the Local Monitor first */
1089 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
1090 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1091 /* found the portname */
1092 RegCloseKey(hroot);
1093 return monitor_load(L"Local Port", NULL);
1095 RegCloseKey(hroot);
1098 len = MAX_PATH + wcslen(L"\\Ports\\") + wcslen(portname) + 1;
1099 buffer = malloc(len * sizeof(WCHAR));
1100 if (buffer == NULL) return NULL;
1102 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
1103 EnterCriticalSection(&monitor_handles_cs);
1104 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1106 while ((pm == NULL) && (id < registered)) {
1107 buffer[0] = '\0';
1108 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1109 TRACE("testing %s\n", debugstr_w(buffer));
1110 len = wcslen(buffer);
1111 lstrcatW(buffer, L"\\Ports\\");
1112 lstrcatW(buffer, portname);
1113 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1114 RegCloseKey(hport);
1115 buffer[len] = '\0'; /* use only the Monitor-Name */
1116 pm = monitor_load(buffer, NULL);
1118 id++;
1120 LeaveCriticalSection(&monitor_handles_cs);
1121 RegCloseKey(hroot);
1123 free(buffer);
1124 return pm;
1127 /******************************************************************
1128 * Return the number of bytes for an multi_sz string.
1129 * The result includes all \0s
1130 * (specifically the extra \0, that is needed as multi_sz terminator).
1132 static int multi_sz_lenW(const WCHAR *str)
1134 const WCHAR *ptr = str;
1135 if (!str) return 0;
1138 ptr += wcslen(ptr) + 1;
1139 } while (*ptr);
1141 return (ptr - str + 1) * sizeof(WCHAR);
1144 /******************************************************************
1145 * validate_envW [internal]
1147 * validate the user-supplied printing-environment
1149 * PARAMS
1150 * env [I] PTR to Environment-String or NULL
1152 * RETURNS
1153 * Success: PTR to printenv_t
1154 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
1156 * NOTES
1157 * An empty string is handled the same way as NULL.
1161 static const printenv_t * validate_envW(LPCWSTR env)
1163 const printenv_t *result = NULL;
1164 unsigned int i;
1166 TRACE("(%s)\n", debugstr_w(env));
1167 if (env && env[0])
1169 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
1171 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
1173 result = all_printenv[i];
1174 break;
1177 if (result == NULL) {
1178 FIXME("unsupported Environment: %s\n", debugstr_w(env));
1179 SetLastError(ERROR_INVALID_ENVIRONMENT);
1181 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
1183 else
1185 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_arch;
1188 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
1189 return result;
1192 /*****************************************************************************
1193 * enumerate the local monitors (INTERNAL)
1195 * returns the needed size (in bytes) for pMonitors
1196 * and *lpreturned is set to number of entries returned in pMonitors
1198 * Language-Monitors are also installed in the same Registry-Location but
1199 * they are filtered in Windows (not returned by EnumMonitors).
1200 * We do no filtering to simplify our Code.
1203 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
1205 HKEY hroot = NULL;
1206 HKEY hentry = NULL;
1207 LPWSTR ptr;
1208 LPMONITOR_INFO_2W mi;
1209 WCHAR buffer[MAX_PATH];
1210 WCHAR dllname[MAX_PATH];
1211 DWORD dllsize;
1212 DWORD len;
1213 DWORD index = 0;
1214 DWORD needed = 0;
1215 DWORD numentries;
1216 DWORD entrysize;
1218 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
1220 numentries = *lpreturned; /* this is 0, when we scan the registry */
1221 len = entrysize * numentries;
1222 ptr = (LPWSTR) &pMonitors[len];
1224 numentries = 0;
1225 len = ARRAY_SIZE(buffer);
1226 buffer[0] = '\0';
1228 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
1229 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
1230 /* Scan all Monitor-Registry-Keys */
1231 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1232 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
1233 dllsize = sizeof(dllname);
1234 dllname[0] = '\0';
1236 /* The Monitor must have a Driver-DLL */
1237 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1238 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
1239 /* We found a valid DLL for this Monitor. */
1240 TRACE("using Driver: %s\n", debugstr_w(dllname));
1242 RegCloseKey(hentry);
1245 /* Windows returns only Port-Monitors here, but to simplify our code,
1246 we do no filtering for Language-Monitors */
1247 if (dllname[0]) {
1248 numentries++;
1249 needed += entrysize;
1250 needed += (len+1) * sizeof(WCHAR); /* len is wcslen(monitorname) */
1251 if (level > 1) {
1252 /* we install and return only monitors for "Windows NT x86" */
1253 needed += (wcslen(x86_envnameW) +1) * sizeof(WCHAR);
1254 needed += dllsize;
1257 /* required size is calculated. Now fill the user-buffer */
1258 if (pMonitors && (cbBuf >= needed)){
1259 mi = (LPMONITOR_INFO_2W) pMonitors;
1260 pMonitors += entrysize;
1262 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
1263 mi->pName = ptr;
1264 lstrcpyW(ptr, buffer); /* Name of the Monitor */
1265 ptr += (len+1); /* len is wcslen(monitorname) */
1266 if (level > 1) {
1267 mi->pEnvironment = ptr;
1268 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
1269 ptr += (wcslen(x86_envnameW)+1);
1271 mi->pDLLName = ptr;
1272 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
1273 ptr += (dllsize / sizeof(WCHAR));
1277 index++;
1278 len = ARRAY_SIZE(buffer);
1279 buffer[0] = '\0';
1281 RegCloseKey(hroot);
1283 *lpreturned = numentries;
1284 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1285 return needed;
1288 /*****************************************************************************
1289 * enumerate the local print processors (INTERNAL)
1291 * returns the needed size (in bytes) for pPPInfo
1292 * and *lpreturned is set to number of entries returned in pPPInfo
1295 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
1297 HKEY hroot = NULL;
1298 HKEY hentry = NULL;
1299 LPWSTR ptr;
1300 PPRINTPROCESSOR_INFO_1W ppi;
1301 WCHAR buffer[MAX_PATH];
1302 WCHAR dllname[MAX_PATH];
1303 DWORD dllsize;
1304 DWORD len;
1305 DWORD index = 0;
1306 DWORD needed = 0;
1307 DWORD numentries;
1309 numentries = *lpreturned; /* this is 0, when we scan the registry */
1310 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
1311 ptr = (LPWSTR) &pPPInfo[len];
1313 numentries = 0;
1314 len = ARRAY_SIZE(buffer);
1315 buffer[0] = '\0';
1317 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
1318 /* add "winprint" first */
1319 numentries++;
1320 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(L"winprint");
1321 if (pPPInfo && (cbBuf >= needed)){
1322 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1323 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1325 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1326 ppi->pName = ptr;
1327 lstrcpyW(ptr, L"winprint"); /* Name of the Print Processor */
1328 ptr += ARRAY_SIZE(L"winprint");
1331 /* Scan all Printprocessor Keys */
1332 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
1333 (lstrcmpiW(buffer, L"winprint") != 0)) {
1334 TRACE("PrintProcessor_%ld: %s\n", numentries, debugstr_w(buffer));
1335 dllsize = sizeof(dllname);
1336 dllname[0] = '\0';
1338 /* The Print Processor must have a Driver-DLL */
1339 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1340 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
1341 /* We found a valid DLL for this Print Processor */
1342 TRACE("using Driver: %s\n", debugstr_w(dllname));
1344 RegCloseKey(hentry);
1347 if (dllname[0]) {
1348 numentries++;
1349 needed += sizeof(PRINTPROCESSOR_INFO_1W);
1350 needed += (len+1) * sizeof(WCHAR); /* len is wcslen(printprocessor name) */
1352 /* required size is calculated. Now fill the user-buffer */
1353 if (pPPInfo && (cbBuf >= needed)){
1354 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1355 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1357 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1358 ppi->pName = ptr;
1359 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
1360 ptr += (len+1); /* len is wcslen(printprosessor name) */
1363 index++;
1364 len = ARRAY_SIZE(buffer);
1365 buffer[0] = '\0';
1367 RegCloseKey(hroot);
1369 *lpreturned = numentries;
1370 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1371 return needed;
1374 /******************************************************************
1375 * enumerate the local Ports from all loaded monitors (internal)
1377 * returns the needed size (in bytes) for pPorts
1378 * and *lpreturned is set to number of entries returned in pPorts
1381 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1383 monitor_t * pm;
1384 LPWSTR ptr;
1385 LPPORT_INFO_2W cache;
1386 LPPORT_INFO_2W out;
1387 LPBYTE pi_buffer = NULL;
1388 DWORD pi_allocated = 0;
1389 DWORD pi_needed;
1390 DWORD pi_index;
1391 DWORD pi_returned;
1392 DWORD res;
1393 DWORD outindex = 0;
1394 DWORD needed;
1395 DWORD numentries;
1396 DWORD entrysize;
1398 TRACE("(%ld, %p, %ld, %p)\n", level, pPorts, cbBuf, lpreturned);
1399 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1401 numentries = *lpreturned; /* this is 0, when we scan the registry */
1402 needed = entrysize * numentries;
1403 ptr = (LPWSTR) &pPorts[needed];
1405 numentries = 0;
1406 needed = 0;
1408 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1410 if (pm->monitor.pfnEnumPorts) {
1411 pi_needed = 0;
1412 pi_returned = 0;
1413 res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level, pi_buffer,
1414 pi_allocated, &pi_needed, &pi_returned);
1415 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1416 /* Do not use realloc (we do not need the old data in the buffer) */
1417 free(pi_buffer);
1418 pi_buffer = malloc(pi_needed);
1419 pi_allocated = (pi_buffer) ? pi_needed : 0;
1420 res = pm->monitor.pfnEnumPorts(pm->hmon, NULL, level,
1421 pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1423 TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n",
1424 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1426 numentries += pi_returned;
1427 needed += pi_needed;
1429 /* fill the output-buffer (pPorts), if we have one */
1430 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1431 pi_index = 0;
1432 while (pi_returned > pi_index) {
1433 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1434 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1435 out->pPortName = ptr;
1436 lstrcpyW(ptr, cache->pPortName);
1437 ptr += (wcslen(ptr)+1);
1438 if (level > 1) {
1439 out->pMonitorName = ptr;
1440 lstrcpyW(ptr, cache->pMonitorName);
1441 ptr += (wcslen(ptr)+1);
1443 out->pDescription = ptr;
1444 lstrcpyW(ptr, cache->pDescription);
1445 ptr += (wcslen(ptr)+1);
1446 out->fPortType = cache->fPortType;
1447 out->Reserved = cache->Reserved;
1449 pi_index++;
1450 outindex++;
1455 /* the temporary portinfo-buffer is no longer needed */
1456 free(pi_buffer);
1458 *lpreturned = numentries;
1459 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1460 return needed;
1464 /*****************************************************************************
1465 * open_driver_reg [internal]
1467 * opens the registry for the printer drivers depending on the given input
1468 * variable pEnvironment
1470 * RETURNS:
1471 * Success: the opened hkey
1472 * Failure: NULL
1474 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1476 HKEY retval = NULL;
1477 LPWSTR buffer;
1478 const printenv_t * env;
1480 TRACE("(%s)\n", debugstr_w(pEnvironment));
1482 env = validate_envW(pEnvironment);
1483 if (!env) return NULL;
1485 buffer = malloc(sizeof(fmt_driversW) +
1486 (wcslen(env->envname) + wcslen(env->versionregpath)) * sizeof(WCHAR));
1488 if (buffer) {
1489 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1490 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1491 free(buffer);
1493 return retval;
1496 /*****************************************************************************
1497 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1499 * Return the PATH for the Printer-Drivers
1501 * PARAMS
1502 * pName [I] Servername (NT only) or NULL (local Computer)
1503 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1504 * Level [I] Structure-Level (must be 1)
1505 * pDriverDirectory [O] PTR to Buffer that receives the Result
1506 * cbBuf [I] Size of Buffer at pDriverDirectory
1507 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1508 * required for pDriverDirectory
1510 * RETURNS
1511 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1512 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1513 * if cbBuf is too small
1515 * Native Values returned in pDriverDirectory on Success:
1516 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1517 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1518 *| win9x(Windows 4.0): "%winsysdir%"
1520 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1523 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1524 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1526 DWORD needed;
1527 const printenv_t * env;
1528 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1530 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
1531 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1533 if (pName != NULL && pName[0]) {
1534 FIXME("server %s not supported\n", debugstr_w(pName));
1535 SetLastError(ERROR_INVALID_PARAMETER);
1536 return FALSE;
1539 env = validate_envW(pEnvironment);
1540 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1543 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1544 needed = GetSystemDirectoryW(NULL, 0);
1545 /* add the Size for the Subdirectories */
1546 needed += wcslen(L"\\spool");
1547 needed += wcslen(L"\\drivers\\");
1548 needed += wcslen(env->subdir);
1549 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1551 *pcbNeeded = needed;
1553 if (needed > cbBuf) {
1554 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1555 return FALSE;
1558 if (dir == NULL) {
1559 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1560 SetLastError(ERROR_INVALID_USER_BUFFER);
1561 return FALSE;
1564 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1565 /* add the Subdirectories */
1566 lstrcatW( dir, L"\\spool" );
1567 CreateDirectoryW( dir, NULL );
1568 lstrcatW( dir, L"\\drivers\\" );
1569 CreateDirectoryW( dir, NULL );
1570 lstrcatW( dir, env->subdir );
1571 CreateDirectoryW( dir, NULL );
1573 TRACE( "=> %s\n", debugstr_w( dir ) );
1574 return TRUE;
1577 /******************************************************************
1578 * driver_load [internal]
1580 * load a driver user interface dll
1582 * On failure, NULL is returned
1586 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1588 WCHAR fullname[MAX_PATH];
1589 HMODULE hui;
1590 DWORD len;
1592 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1594 /* build the driverdir */
1595 len = sizeof(fullname) -
1596 (wcslen(env->versionsubdir) + 1 + wcslen(dllname) + 1) * sizeof(WCHAR);
1598 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1599 (LPBYTE) fullname, len, &len)) {
1600 /* Should never fail */
1601 SetLastError(ERROR_BUFFER_OVERFLOW);
1602 return NULL;
1605 lstrcatW(fullname, env->versionsubdir);
1606 lstrcatW(fullname, L"\\");
1607 lstrcatW(fullname, dllname);
1609 hui = LoadLibraryW(fullname);
1610 TRACE("%p: LoadLibrary(%s) %ld\n", hui, debugstr_w(fullname), GetLastError());
1612 return hui;
1615 static job_info_t * get_job(printer_info_t *info, DWORD job_id)
1617 job_info_t *job;
1619 LIST_FOR_EACH_ENTRY(job, &info->jobs, job_info_t, entry)
1621 if(job->id == job_id)
1622 return job;
1624 return NULL;
1627 static HANDLE server_alloc_handle(const WCHAR *name, BOOL *stop_search)
1629 server_t *server;
1631 *stop_search = FALSE;
1632 if (name)
1633 return NULL;
1635 server = malloc(sizeof(*server));
1636 if (!server)
1638 *stop_search = TRUE;
1639 return NULL;
1641 server->type = HANDLE_SERVER;
1642 return (HANDLE)server;
1645 static HANDLE xcv_alloc_handle(const WCHAR *name, PRINTER_DEFAULTSW *def, BOOL *stop_search)
1647 static const WCHAR xcv_monitor[] = L"XcvMonitor ";
1648 static const WCHAR xcv_port[] = L"XcvPort ";
1649 BOOL mon;
1650 xcv_t *xcv;
1652 *stop_search = FALSE;
1653 if (name[0] != ',')
1654 return NULL;
1656 name++;
1657 while (*name == ' ')
1658 name++;
1660 mon = !wcsncmp(name, xcv_monitor, ARRAY_SIZE(xcv_monitor) - 1);
1661 if (mon)
1663 name += ARRAY_SIZE(xcv_monitor) - 1;
1665 else
1667 if (wcsncmp(name, xcv_port, ARRAY_SIZE(xcv_port) - 1)) return NULL;
1668 name += ARRAY_SIZE(xcv_port) - 1;
1671 *stop_search = TRUE;
1672 xcv = calloc(1, sizeof(*xcv));
1673 if (!xcv)
1674 return NULL;
1675 xcv->header.type = HANDLE_XCV;
1677 if (mon)
1678 xcv->pm = monitor_load(name, NULL);
1679 else
1680 xcv->pm = monitor_load_by_port(name);
1681 if (!xcv->pm)
1683 free(xcv);
1684 SetLastError(ERROR_UNKNOWN_PORT);
1685 return NULL;
1688 if (xcv->pm->monitor.pfnXcvOpenPort)
1690 xcv->pm->monitor.pfnXcvOpenPort(xcv->pm->hmon, name,
1691 def ? def->DesiredAccess : 0, &xcv->hxcv);
1693 if (!xcv->hxcv)
1695 fpClosePrinter((HANDLE)xcv);
1696 SetLastError(ERROR_INVALID_PARAMETER);
1697 return NULL;
1699 return (HANDLE)xcv;
1702 static HANDLE port_alloc_handle(const WCHAR *name, BOOL *stop_search)
1704 static const WCHAR portW[] = L"Port";
1706 unsigned int i, name_len;
1707 WCHAR *port_name;
1708 port_t *port;
1710 *stop_search = FALSE;
1711 for (name_len = 0; name[name_len] != ','; name_len++)
1713 if (!name[name_len])
1714 return NULL;
1717 for (i = name_len + 1; name[i] == ' '; i++);
1718 if (wcscmp(name + i, portW))
1719 return NULL;
1721 *stop_search = TRUE;
1722 port_name = malloc((name_len + 1) * sizeof(WCHAR));
1723 if (!port_name)
1724 return NULL;
1725 memcpy(port_name, name, name_len * sizeof(WCHAR));
1726 port_name[name_len] = 0;
1728 port = calloc(1, sizeof(*port));
1729 if (!port)
1731 free(port_name);
1732 return NULL;
1734 port->header.type = HANDLE_PORT;
1736 port->mon = monitor_load_by_port(port_name);
1737 if (!port->mon)
1739 free(port_name);
1740 free(port);
1741 return NULL;
1743 if (!port->mon->monitor.pfnOpenPort || !port->mon->monitor.pfnWritePort
1744 || !port->mon->monitor.pfnClosePort || !port->mon->monitor.pfnStartDocPort
1745 || !port->mon->monitor.pfnEndDocPort)
1747 FIXME("port not supported: %s\n", debugstr_w(name));
1748 free(port_name);
1749 fpClosePrinter((HANDLE)port);
1750 return NULL;
1753 port->mon->monitor.pfnOpenPort(port->mon->hmon, port_name, &port->hport);
1754 free(port_name);
1755 if (!port->hport)
1757 fpClosePrinter((HANDLE)port);
1758 return NULL;
1760 return (HANDLE)port;
1763 static HANDLE job_alloc_handle(const WCHAR *name, BOOL *stop_search)
1765 static const WCHAR jobW[] = L"Job ";
1767 unsigned int name_len, job_id;
1768 printer_info_t *printer_info;
1769 job_info_t *job_info;
1770 job_t *job;
1772 *stop_search = FALSE;
1773 for (name_len = 0; name[name_len] != ','; name_len++)
1775 if (!name[name_len])
1776 return NULL;
1779 for (job_id = name_len + 1; name[job_id] == ' '; job_id++);
1780 if (!name[job_id])
1781 return NULL;
1783 if (wcsncmp(name + job_id, jobW, ARRAY_SIZE(jobW) - 1))
1784 return NULL;
1786 *stop_search = TRUE;
1787 job_id += ARRAY_SIZE(jobW) - 1;
1788 job_id = wcstoul(name + job_id, NULL, 10);
1790 printer_info = find_printer_info(name, name_len);
1791 if (!printer_info)
1793 SetLastError(ERROR_INVALID_PRINTER_NAME);
1794 return NULL;
1797 EnterCriticalSection(&printer_info->jobs_cs);
1799 job_info = get_job(printer_info, job_id);
1800 if (!job_info)
1802 LeaveCriticalSection(&printer_info->jobs_cs);
1803 release_printer_info(printer_info);
1804 SetLastError(ERROR_INVALID_PRINTER_NAME);
1805 return NULL;
1808 job = malloc(sizeof(*job));
1809 if (!job)
1811 LeaveCriticalSection(&printer_info->jobs_cs);
1812 release_printer_info(printer_info);
1813 return NULL;
1815 job->header.type = HANDLE_JOB;
1816 job->hf = CreateFileW(job_info->filename, GENERIC_READ,
1817 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
1818 NULL, OPEN_EXISTING, 0, NULL);
1820 LeaveCriticalSection(&printer_info->jobs_cs);
1821 release_printer_info(printer_info);
1823 if (job->hf == INVALID_HANDLE_VALUE)
1825 free(job);
1826 return NULL;
1828 return (HANDLE)job;
1831 static HANDLE printer_alloc_handle(const WCHAR *name, const WCHAR *basename,
1832 PRINTER_DEFAULTSW *def)
1834 printer_t *printer;
1835 HKEY hroot, hkey;
1836 LSTATUS status;
1838 printer = calloc(1, sizeof(*printer));
1839 if (!printer)
1840 return NULL;
1841 printer->header.type = HANDLE_PRINTER;
1843 /* clone the full name */
1844 printer->name = wcsdup(name);
1845 if (name && !printer->name)
1847 fpClosePrinter((HANDLE)printer);
1848 return NULL;
1851 printer->info = get_printer_info(basename);
1852 if (!printer->info)
1854 fpClosePrinter((HANDLE)printer);
1855 SetLastError(ERROR_INVALID_PRINTER_NAME);
1856 return NULL;
1859 if (def && def->pDatatype)
1860 printer->datatype = wcsdup(def->pDatatype);
1861 if (def && def->pDevMode)
1862 printer->devmode = dup_devmode(def->pDevMode);
1864 hroot = open_driver_reg(env_arch.envname);
1865 if (hroot)
1867 status = RegOpenKeyW(hroot, name, &hkey);
1868 RegCloseKey(hroot);
1869 if (status == ERROR_SUCCESS)
1871 printer->print_proc = reg_query_value(hkey, L"Print Processor");
1872 RegCloseKey(hkey);
1875 if (!printer->print_proc)
1876 printer->print_proc = wcsdup(L"winprint");
1878 return (HANDLE)printer;
1881 static inline WCHAR *get_file_part( WCHAR *name )
1883 WCHAR *ptr = wcsrchr( name, '\\' );
1884 if (ptr) return ptr + 1;
1885 return name;
1888 /******************************************************************************
1889 * myAddPrinterDriverEx [internal]
1891 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1892 * and a special mode with lazy error checking.
1895 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1897 const printenv_t *env;
1898 apd_data_t apd;
1899 DRIVER_INFO_8W di;
1900 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1901 HMODULE hui;
1902 WCHAR *file;
1903 HKEY hroot;
1904 HKEY hdrv;
1905 DWORD disposition;
1906 DWORD len;
1907 LONG lres;
1908 BOOL res;
1910 /* we need to set all entries in the Registry, independent from the Level of
1911 DRIVER_INFO, that the caller supplied */
1913 ZeroMemory(&di, sizeof(di));
1914 if (pDriverInfo && (level < ARRAY_SIZE(di_sizeof))) {
1915 memcpy(&di, pDriverInfo, di_sizeof[level]);
1918 /* dump the most used infos */
1919 TRACE("%p: .cVersion : 0x%lx/%ld\n", pDriverInfo, di.cVersion, di.cVersion);
1920 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1921 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1922 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1923 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1924 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1925 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1926 /* dump only the first of the additional Files */
1927 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1930 /* check environment */
1931 env = validate_envW(di.pEnvironment);
1932 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1934 /* fill the copy-data / get the driverdir */
1935 len = sizeof(apd.src) - sizeof(L"\\3") - sizeof(WCHAR);
1936 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1937 (LPBYTE) apd.src, len, &len)) {
1938 /* Should never fail */
1939 return FALSE;
1941 memcpy(apd.dst, apd.src, len);
1942 lstrcatW(apd.src, L"\\");
1943 apd.srclen = wcslen(apd.src);
1944 lstrcatW(apd.dst, env->versionsubdir);
1945 lstrcatW(apd.dst, L"\\");
1946 apd.dstlen = wcslen(apd.dst);
1947 apd.copyflags = dwFileCopyFlags;
1948 apd.lazy = lazy;
1949 CreateDirectoryW(apd.src, NULL);
1950 CreateDirectoryW(apd.dst, NULL);
1952 hroot = open_driver_reg(env->envname);
1953 if (!hroot) {
1954 ERR("Can't create Drivers key\n");
1955 return FALSE;
1958 /* Fill the Registry for the Driver */
1959 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1960 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1961 &hdrv, &disposition)) != ERROR_SUCCESS) {
1963 ERR("can't create driver %s: %lu\n", debugstr_w(di.pName), lres);
1964 RegCloseKey(hroot);
1965 SetLastError(lres);
1966 return FALSE;
1968 RegCloseKey(hroot);
1970 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1971 RegSetValueExW(hdrv, L"Version", 0, REG_DWORD, (const BYTE*) &env->driverversion,
1972 sizeof(DWORD));
1974 file = get_file_part( di.pDriverPath );
1975 RegSetValueExW( hdrv, L"Driver", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1976 apd_copyfile( di.pDriverPath, file, &apd );
1978 file = get_file_part( di.pDataFile );
1979 RegSetValueExW( hdrv, L"Data File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1980 apd_copyfile( di.pDataFile, file, &apd );
1982 file = get_file_part( di.pConfigFile );
1983 RegSetValueExW( hdrv, L"Configuration File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1984 apd_copyfile( di.pConfigFile, file, &apd );
1986 /* settings for level 3 */
1987 if (di.pHelpFile)
1989 file = get_file_part( di.pHelpFile );
1990 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (BYTE*)file, (wcslen( file ) + 1) * sizeof(WCHAR) );
1991 apd_copyfile( di.pHelpFile, file, &apd );
1993 else
1994 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (const BYTE*)L"", sizeof(L"") );
1996 if (di.pDependentFiles && *di.pDependentFiles)
1998 WCHAR *reg, *reg_ptr, *in_ptr;
1999 reg = reg_ptr = malloc( multi_sz_lenW( di.pDependentFiles ) );
2001 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += wcslen( in_ptr ) + 1)
2003 file = get_file_part( in_ptr );
2004 len = wcslen( file ) + 1;
2005 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
2006 reg_ptr += len;
2007 apd_copyfile( in_ptr, file, &apd );
2009 *reg_ptr = 0;
2011 RegSetValueExW( hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (BYTE*)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
2012 free( reg );
2014 else
2015 RegSetValueExW(hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
2017 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
2018 if (di.pMonitorName)
2019 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (BYTE*)di.pMonitorName,
2020 (wcslen(di.pMonitorName)+1)* sizeof(WCHAR));
2021 else
2022 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
2024 if (di.pDefaultDataType)
2025 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (BYTE*)di.pDefaultDataType,
2026 (wcslen(di.pDefaultDataType)+1)* sizeof(WCHAR));
2027 else
2028 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
2030 /* settings for level 4 */
2031 if (di.pszzPreviousNames)
2032 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (BYTE*)di.pszzPreviousNames,
2033 multi_sz_lenW(di.pszzPreviousNames));
2034 else
2035 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
2037 if (di.pszPrintProcessor)
2038 RegSetValueExW(hdrv, L"Print Processor", 0, REG_SZ, (BYTE*)di.pszPrintProcessor,
2039 (wcslen(di.pszPrintProcessor) + 1) * sizeof(WCHAR));
2040 else
2041 RegSetValueExW(hdrv, L"Print Processor", 0, REG_SZ, (const BYTE*)L"winprint", sizeof(L"winprint"));
2043 if (level > 5) TRACE("level %lu for Driver %s is incomplete\n", level, debugstr_w(di.pName));
2045 RegCloseKey(hdrv);
2046 hui = driver_load(env, di.pConfigFile);
2047 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
2048 if (hui && pDrvDriverEvent) {
2050 /* Support for DrvDriverEvent is optional */
2051 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
2052 /* MSDN: level for DRIVER_INFO is 1 to 3 */
2053 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
2054 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
2056 FreeLibrary(hui);
2058 TRACE("=> TRUE with %lu\n", GetLastError());
2059 return TRUE;
2063 /******************************************************************************
2064 * fpAddMonitor [exported through PRINTPROVIDOR]
2066 * Install a Printmonitor
2068 * PARAMS
2069 * pName [I] Servername or NULL (local Computer)
2070 * Level [I] Structure-Level (Must be 2)
2071 * pMonitors [I] PTR to MONITOR_INFO_2
2073 * RETURNS
2074 * Success: TRUE
2075 * Failure: FALSE
2077 * NOTES
2078 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2081 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2083 const printenv_t * env;
2084 monitor_t * pm = NULL;
2085 LPMONITOR_INFO_2W mi2w;
2086 HKEY hroot = NULL;
2087 HKEY hentry = NULL;
2088 DWORD disposition;
2089 BOOL res = FALSE;
2091 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2092 TRACE("(%s, %ld, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2093 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
2095 if (copy_servername_from_name(pName, NULL)) {
2096 FIXME("server %s not supported\n", debugstr_w(pName));
2097 SetLastError(ERROR_ACCESS_DENIED);
2098 return FALSE;
2101 if (!mi2w->pName || (! mi2w->pName[0])) {
2102 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2103 SetLastError(ERROR_INVALID_PARAMETER);
2104 return FALSE;
2107 env = validate_envW(mi2w->pEnvironment);
2108 if (!env)
2109 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2111 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2112 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2113 SetLastError(ERROR_INVALID_PARAMETER);
2114 return FALSE;
2117 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2118 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2119 return FALSE;
2122 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2123 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2124 &disposition) == ERROR_SUCCESS) {
2126 /* Some installers set options for the port before calling AddMonitor.
2127 We query the "Driver" entry to verify that the monitor is installed,
2128 before we return an error.
2129 When a user installs two print monitors at the same time with the
2130 same name, a race condition is possible but silently ignored. */
2132 DWORD namesize = 0;
2134 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2135 (RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL,
2136 &namesize) == ERROR_SUCCESS)) {
2137 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2138 /* 9x use ERROR_ALREADY_EXISTS */
2139 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2141 else
2143 INT len;
2144 len = (wcslen(mi2w->pDLLName) +1) * sizeof(WCHAR);
2145 res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ,
2146 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2148 /* Load and initialize the monitor. SetLastError() is called on failure */
2149 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL)
2151 RegDeleteKeyW(hroot, mi2w->pName);
2152 res = FALSE;
2154 else
2155 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
2158 RegCloseKey(hentry);
2161 RegCloseKey(hroot);
2162 return (res);
2165 /******************************************************************************
2166 * fpAddPort [exported through PRINTPROVIDOR]
2168 * Add a Port for a specific Monitor
2170 * PARAMS
2171 * pName [I] Servername or NULL (local Computer)
2172 * hWnd [I] Handle to parent Window for the Dialog-Box
2173 * pMonitorName [I] Name of the Monitor that manage the Port
2175 * RETURNS
2176 * Success: TRUE
2177 * Failure: FALSE
2180 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
2182 monitor_t * pm;
2183 monitor_t * pui;
2184 LONG lres;
2185 DWORD res;
2187 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
2189 lres = copy_servername_from_name(pName, NULL);
2190 if (lres) {
2191 FIXME("server %s not supported\n", debugstr_w(pName));
2192 SetLastError(ERROR_INVALID_PARAMETER);
2193 return FALSE;
2196 /* an empty Monitorname is Invalid */
2197 if (!pMonitorName[0]) {
2198 SetLastError(ERROR_NOT_SUPPORTED);
2199 return FALSE;
2202 pm = monitor_load(pMonitorName, NULL);
2203 if (pm && pm->monitor.pfnAddPort) {
2204 res = pm->monitor.pfnAddPort(pm->hmon, pName, hWnd, pMonitorName);
2205 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
2207 else
2209 pui = monitor_loadui(pm);
2210 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
2211 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
2212 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
2214 else
2216 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2217 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
2218 pui, debugstr_w(pui ? pui->dllname : NULL));
2220 SetLastError(ERROR_NOT_SUPPORTED);
2221 res = FALSE;
2223 monitor_unload(pui);
2225 monitor_unload(pm);
2227 TRACE("returning %ld with %lu\n", res, GetLastError());
2228 return res;
2231 /******************************************************************************
2232 * fpAddPortEx [exported through PRINTPROVIDOR]
2234 * Add a Port for a specific Monitor, without presenting a user interface
2236 * PARAMS
2237 * pName [I] Servername or NULL (local Computer)
2238 * level [I] Structure-Level (1 or 2) for pBuffer
2239 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
2240 * pMonitorName [I] Name of the Monitor that manage the Port
2242 * RETURNS
2243 * Success: TRUE
2244 * Failure: FALSE
2247 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
2249 PORT_INFO_2W * pi2;
2250 monitor_t * pm;
2251 DWORD lres;
2252 DWORD res;
2254 pi2 = (PORT_INFO_2W *) pBuffer;
2256 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
2257 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
2258 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
2259 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
2261 lres = copy_servername_from_name(pName, NULL);
2262 if (lres) {
2263 FIXME("server %s not supported\n", debugstr_w(pName));
2264 SetLastError(ERROR_INVALID_PARAMETER);
2265 return FALSE;
2268 if ((level < 1) || (level > 2)) {
2269 SetLastError(ERROR_INVALID_LEVEL);
2270 return FALSE;
2273 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
2274 SetLastError(ERROR_INVALID_PARAMETER);
2275 return FALSE;
2278 /* load the Monitor */
2279 pm = monitor_load(pMonitorName, NULL);
2280 if (pm && pm->monitor.pfnAddPortEx)
2282 res = pm->monitor.pfnAddPortEx(pm->hmon, pName, level, pBuffer, pMonitorName);
2283 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
2285 else
2287 FIXME("not implemented for %s (monitor %p: %s)\n",
2288 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
2289 SetLastError(ERROR_INVALID_PARAMETER);
2290 res = FALSE;
2292 monitor_unload(pm);
2293 return res;
2296 /******************************************************************************
2297 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
2299 * Install a Printer Driver with the Option to upgrade / downgrade the Files
2301 * PARAMS
2302 * pName [I] Servername or NULL (local Computer)
2303 * level [I] Level for the supplied DRIVER_INFO_*W struct
2304 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
2305 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
2307 * RESULTS
2308 * Success: TRUE
2309 * Failure: FALSE
2312 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
2314 LONG lres;
2316 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
2317 lres = copy_servername_from_name(pName, NULL);
2318 if (lres) {
2319 FIXME("server %s not supported\n", debugstr_w(pName));
2320 SetLastError(ERROR_ACCESS_DENIED);
2321 return FALSE;
2324 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
2325 TRACE("Flags 0x%lx ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
2328 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
2331 /******************************************************************************
2332 * fpConfigurePort [exported through PRINTPROVIDOR]
2334 * Display the Configuration-Dialog for a specific Port
2336 * PARAMS
2337 * pName [I] Servername or NULL (local Computer)
2338 * hWnd [I] Handle to parent Window for the Dialog-Box
2339 * pPortName [I] Name of the Port, that should be configured
2341 * RETURNS
2342 * Success: TRUE
2343 * Failure: FALSE
2346 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2348 monitor_t * pm;
2349 monitor_t * pui;
2350 LONG lres;
2351 DWORD res;
2353 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2355 lres = copy_servername_from_name(pName, NULL);
2356 if (lres) {
2357 FIXME("server %s not supported\n", debugstr_w(pName));
2358 SetLastError(ERROR_INVALID_NAME);
2359 return FALSE;
2362 /* an empty Portname is Invalid, but can popup a Dialog */
2363 if (!pPortName[0]) {
2364 SetLastError(ERROR_NOT_SUPPORTED);
2365 return FALSE;
2368 pm = monitor_load_by_port(pPortName);
2369 if (pm && pm->monitor.pfnConfigurePort)
2371 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2372 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2373 res = pm->monitor.pfnConfigurePort(pm->hmon, pName, hWnd, pPortName);
2374 TRACE("got %ld with %lu\n", res, GetLastError());
2376 else
2378 pui = monitor_loadui(pm);
2379 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
2380 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2381 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2382 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
2383 TRACE("got %ld with %lu\n", res, GetLastError());
2385 else
2387 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2388 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2389 pui, debugstr_w(pui ? pui->dllname : NULL));
2391 SetLastError(ERROR_NOT_SUPPORTED);
2392 res = FALSE;
2394 monitor_unload(pui);
2396 monitor_unload(pm);
2398 TRACE("returning %ld with %lu\n", res, GetLastError());
2399 return res;
2402 /******************************************************************
2403 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2405 * Delete a specific Printmonitor from a Printing-Environment
2407 * PARAMS
2408 * pName [I] Servername or NULL (local Computer)
2409 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2410 * pMonitorName [I] Name of the Monitor, that should be deleted
2412 * RETURNS
2413 * Success: TRUE
2414 * Failure: FALSE
2416 * NOTES
2417 * pEnvironment is ignored in Windows for the local Computer.
2421 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2423 monitor_t *pm;
2424 HKEY hroot = NULL;
2425 LONG lres;
2427 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2428 debugstr_w(pMonitorName));
2430 lres = copy_servername_from_name(pName, NULL);
2431 if (lres) {
2432 FIXME("server %s not supported\n", debugstr_w(pName));
2433 SetLastError(ERROR_INVALID_NAME);
2434 return FALSE;
2437 /* pEnvironment is ignored in Windows for the local Computer */
2438 if (!pMonitorName || !pMonitorName[0]) {
2439 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2440 SetLastError(ERROR_INVALID_PARAMETER);
2441 return FALSE;
2444 /* Unload the monitor if it's loaded */
2445 EnterCriticalSection(&monitor_handles_cs);
2446 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
2448 if (pm->name && !lstrcmpW(pMonitorName, pm->name))
2450 monitor_unload(pm);
2451 break;
2454 LeaveCriticalSection(&monitor_handles_cs);
2456 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2457 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2458 return FALSE;
2461 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2462 TRACE("%s deleted\n", debugstr_w(pMonitorName));
2463 RegCloseKey(hroot);
2464 return TRUE;
2467 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
2468 RegCloseKey(hroot);
2470 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2471 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2472 return FALSE;
2475 static BOOL WINAPI fpResetPrinter(HANDLE hprinter, PRINTER_DEFAULTSW *def)
2477 printer_t *printer = (printer_t *)hprinter;
2479 if (!printer || printer->header.type != HANDLE_PRINTER)
2481 SetLastError(ERROR_INVALID_HANDLE);
2482 return FALSE;
2485 if (!def)
2487 SetLastError(ERROR_INVALID_PARAMETER);
2488 return FALSE;
2491 free(printer->datatype);
2492 if (def->pDatatype)
2493 printer->datatype = wcsdup(def->pDatatype);
2494 else
2495 printer->datatype = NULL;
2497 free(printer->devmode);
2498 if (def->pDevMode)
2499 printer->devmode = dup_devmode(def->pDevMode);
2500 else
2501 printer->devmode = NULL;
2502 return TRUE;
2505 /*****************************************************************************
2506 * fpDeletePort [exported through PRINTPROVIDOR]
2508 * Delete a specific Port
2510 * PARAMS
2511 * pName [I] Servername or NULL (local Computer)
2512 * hWnd [I] Handle to parent Window for the Dialog-Box
2513 * pPortName [I] Name of the Port, that should be deleted
2515 * RETURNS
2516 * Success: TRUE
2517 * Failure: FALSE
2520 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2522 monitor_t * pm;
2523 monitor_t * pui;
2524 LONG lres;
2525 DWORD res;
2527 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2529 lres = copy_servername_from_name(pName, NULL);
2530 if (lres) {
2531 FIXME("server %s not supported\n", debugstr_w(pName));
2532 SetLastError(ERROR_INVALID_NAME);
2533 return FALSE;
2536 /* an empty Portname is Invalid */
2537 if (!pPortName[0]) {
2538 SetLastError(ERROR_NOT_SUPPORTED);
2539 return FALSE;
2542 pm = monitor_load_by_port(pPortName);
2543 if (pm && pm->monitor.pfnDeletePort)
2545 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2546 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2547 res = pm->monitor.pfnDeletePort(pm->hmon, pName, hWnd, pPortName);
2548 TRACE("got %ld with %lu\n", res, GetLastError());
2550 else
2552 pui = monitor_loadui(pm);
2553 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2554 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2555 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2556 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2557 TRACE("got %ld with %lu\n", res, GetLastError());
2559 else
2561 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2562 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2563 pui, debugstr_w(pui ? pui->dllname : NULL));
2565 SetLastError(ERROR_NOT_SUPPORTED);
2566 res = FALSE;
2568 monitor_unload(pui);
2570 monitor_unload(pm);
2572 TRACE("returning %ld with %lu\n", res, GetLastError());
2573 return res;
2576 /*****************************************************************************
2577 * fpEnumMonitors [exported through PRINTPROVIDOR]
2579 * Enumerate available Port-Monitors
2581 * PARAMS
2582 * pName [I] Servername or NULL (local Computer)
2583 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2584 * pMonitors [O] PTR to Buffer that receives the Result
2585 * cbBuf [I] Size of Buffer at pMonitors
2586 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2587 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2589 * RETURNS
2590 * Success: TRUE
2591 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2593 * NOTES
2594 * Windows reads the Registry once and cache the Results.
2597 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
2598 LPDWORD pcbNeeded, LPDWORD pcReturned)
2600 DWORD numentries = 0;
2601 DWORD needed = 0;
2602 LONG lres;
2603 BOOL res = FALSE;
2605 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
2606 cbBuf, pcbNeeded, pcReturned);
2608 lres = copy_servername_from_name(pName, NULL);
2609 if (lres) {
2610 FIXME("server %s not supported\n", debugstr_w(pName));
2611 SetLastError(ERROR_INVALID_NAME);
2612 goto em_cleanup;
2615 if (!Level || (Level > 2)) {
2616 WARN("level (%ld) is ignored in win9x\n", Level);
2617 SetLastError(ERROR_INVALID_LEVEL);
2618 return FALSE;
2621 /* Scan all Monitor-Keys */
2622 numentries = 0;
2623 needed = get_local_monitors(Level, NULL, 0, &numentries);
2625 /* we calculated the needed buffersize. now do more error-checks */
2626 if (cbBuf < needed) {
2627 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2628 goto em_cleanup;
2631 /* fill the Buffer with the Monitor-Keys */
2632 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2633 res = TRUE;
2635 em_cleanup:
2636 if (pcbNeeded) *pcbNeeded = needed;
2637 if (pcReturned) *pcReturned = numentries;
2639 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2640 res, GetLastError(), needed, numentries);
2642 return (res);
2645 /******************************************************************************
2646 * fpEnumPorts [exported through PRINTPROVIDOR]
2648 * Enumerate available Ports
2650 * PARAMS
2651 * pName [I] Servername or NULL (local Computer)
2652 * Level [I] Structure-Level (1 or 2)
2653 * pPorts [O] PTR to Buffer that receives the Result
2654 * cbBuf [I] Size of Buffer at pPorts
2655 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2656 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2658 * RETURNS
2659 * Success: TRUE
2660 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2663 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2664 LPDWORD pcbNeeded, LPDWORD pcReturned)
2666 DWORD needed = 0;
2667 DWORD numentries = 0;
2668 LONG lres;
2669 BOOL res = FALSE;
2671 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2672 cbBuf, pcbNeeded, pcReturned);
2674 lres = copy_servername_from_name(pName, NULL);
2675 if (lres) {
2676 FIXME("server %s not supported\n", debugstr_w(pName));
2677 SetLastError(ERROR_INVALID_NAME);
2678 goto emP_cleanup;
2681 if (!Level || (Level > 2)) {
2682 SetLastError(ERROR_INVALID_LEVEL);
2683 goto emP_cleanup;
2686 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2687 SetLastError(RPC_X_NULL_REF_POINTER);
2688 goto emP_cleanup;
2691 EnterCriticalSection(&monitor_handles_cs);
2692 monitor_loadall();
2694 /* Scan all local Ports */
2695 numentries = 0;
2696 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2698 /* we calculated the needed buffersize. now do the error-checks */
2699 if (cbBuf < needed) {
2700 monitor_unloadall();
2701 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2702 goto emP_cleanup_cs;
2704 else if (!pPorts || !pcReturned) {
2705 monitor_unloadall();
2706 SetLastError(RPC_X_NULL_REF_POINTER);
2707 goto emP_cleanup_cs;
2710 /* Fill the Buffer */
2711 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2712 res = TRUE;
2713 monitor_unloadall();
2715 emP_cleanup_cs:
2716 LeaveCriticalSection(&monitor_handles_cs);
2718 emP_cleanup:
2719 if (pcbNeeded) *pcbNeeded = needed;
2720 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2722 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
2723 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2725 return (res);
2728 static BOOL WINAPI fpAddPrintProcessor(WCHAR *name, WCHAR *environment, WCHAR *path,
2729 WCHAR *print_proc)
2731 const printenv_t * env;
2732 HKEY hroot = NULL;
2733 WCHAR *regpath;
2734 LSTATUS s;
2736 TRACE("(%s, %s, %s, %s)\n", debugstr_w(name), debugstr_w(environment),
2737 debugstr_w(path), debugstr_w(print_proc));
2739 if (!path || !print_proc)
2741 SetLastError(ERROR_INVALID_PARAMETER);
2742 return FALSE;
2745 if (name && name[0])
2747 FIXME("server %s not supported\n", debugstr_w(name));
2748 SetLastError(ERROR_INVALID_NAME);
2749 return FALSE;
2752 env = validate_envW(environment);
2753 if (!env)
2754 return FALSE;
2756 regpath = malloc(sizeof(fmt_printprocessorsW) +
2757 wcslen(env->envname) * sizeof(WCHAR));
2758 if (!regpath)
2759 return FALSE;
2760 wsprintfW(regpath, fmt_printprocessorsW, env->envname);
2762 s = RegCreateKeyW(HKEY_LOCAL_MACHINE, regpath, &hroot);
2763 free(regpath);
2764 if (!s)
2766 s = RegSetKeyValueW(hroot, print_proc, L"Driver", REG_SZ, path,
2767 (wcslen(path) + 1) * sizeof(WCHAR));
2769 RegCloseKey(hroot);
2770 if (s)
2772 SetLastError(s);
2773 return FALSE;
2776 return TRUE;
2779 /*****************************************************************************
2780 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2782 * Enumerate available Print Processors
2784 * PARAMS
2785 * pName [I] Servername or NULL (local Computer)
2786 * pEnvironment [I] Printing-Environment or NULL (Default)
2787 * Level [I] Structure-Level (Only 1 is allowed)
2788 * pPPInfo [O] PTR to Buffer that receives the Result
2789 * cbBuf [I] Size of Buffer at pMonitors
2790 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2791 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2793 * RETURNS
2794 * Success: TRUE
2795 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2798 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2799 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2801 const printenv_t * env;
2802 LPWSTR regpathW = NULL;
2803 DWORD numentries = 0;
2804 DWORD needed = 0;
2805 LONG lres;
2806 BOOL res = FALSE;
2808 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2809 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2811 lres = copy_servername_from_name(pName, NULL);
2812 if (lres) {
2813 FIXME("server %s not supported\n", debugstr_w(pName));
2814 SetLastError(ERROR_INVALID_NAME);
2815 goto epp_cleanup;
2818 if (Level != 1) {
2819 SetLastError(ERROR_INVALID_LEVEL);
2820 goto epp_cleanup;
2823 env = validate_envW(pEnvironment);
2824 if (!env)
2825 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2827 regpathW = malloc(sizeof(fmt_printprocessorsW) +
2828 (wcslen(env->envname) * sizeof(WCHAR)));
2830 if (!regpathW)
2831 goto epp_cleanup;
2833 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2835 /* Scan all Printprocessor-Keys */
2836 numentries = 0;
2837 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2839 /* we calculated the needed buffersize. now do more error-checks */
2840 if (cbBuf < needed) {
2841 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2842 goto epp_cleanup;
2845 /* fill the Buffer with the Printprocessor Infos */
2846 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2847 res = TRUE;
2849 epp_cleanup:
2850 free(regpathW);
2851 if (pcbNeeded) *pcbNeeded = needed;
2852 if (pcReturned) *pcReturned = numentries;
2854 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2855 res, GetLastError(), needed, numentries);
2857 return (res);
2860 /******************************************************************************
2861 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2863 * Return the PATH for the Print-Processors
2865 * PARAMS
2866 * pName [I] Servername or NULL (this computer)
2867 * pEnvironment [I] Printing-Environment or NULL (Default)
2868 * level [I] Structure-Level (must be 1)
2869 * pPPInfo [O] PTR to Buffer that receives the Result
2870 * cbBuf [I] Size of Buffer at pPPInfo
2871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2873 * RETURNS
2874 * Success: TRUE
2875 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2877 * Native Values returned in pPPInfo on Success for this computer:
2878 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2879 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2880 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2882 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2885 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2886 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2888 const printenv_t * env;
2889 DWORD needed;
2890 LONG lres;
2892 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2893 level, pPPInfo, cbBuf, pcbNeeded);
2895 *pcbNeeded = 0;
2896 lres = copy_servername_from_name(pName, NULL);
2897 if (lres) {
2898 FIXME("server %s not supported\n", debugstr_w(pName));
2899 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2900 return FALSE;
2903 env = validate_envW(pEnvironment);
2904 if (!env)
2905 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2907 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2908 needed = GetSystemDirectoryW(NULL, 0);
2909 /* add the Size for the Subdirectories */
2910 needed += wcslen(L"\\spool\\prtprocs\\");
2911 needed += wcslen(env->subdir);
2912 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2914 *pcbNeeded = needed;
2916 if (needed > cbBuf) {
2917 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2918 return FALSE;
2921 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2922 /* add the Subdirectories */
2923 lstrcatW((LPWSTR) pPPInfo, L"\\spool\\prtprocs\\");
2924 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2925 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2926 return TRUE;
2929 /******************************************************************************
2930 * fpOpenPrinter [exported through PRINTPROVIDOR]
2932 * Open a Printer / Printserver or a Printer-Object
2934 * PARAMS
2935 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2936 * pPrinter [O] The resulting Handle is stored here
2937 * pDefaults [I] PTR to Default Printer Settings or NULL
2939 * RETURNS
2940 * Success: TRUE
2941 * Failure: FALSE
2943 * NOTES
2944 * lpPrinterName is one of:
2945 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2946 *| Printer: "PrinterName"
2947 *| Printer-Object: "PrinterName,Job xxx"
2948 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2949 *| XcvPort: "Servername,XcvPort PortName"
2953 static BOOL WINAPI fpOpenPrinter(WCHAR *name, HANDLE *hprinter,
2954 PRINTER_DEFAULTSW *def)
2956 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
2957 const WCHAR *basename;
2958 BOOL stop_search;
2960 TRACE("(%s, %p, %p)\n", debugstr_w(name), hprinter, def);
2962 if (copy_servername_from_name(name, servername))
2964 FIXME("server %s not supported\n", debugstr_w(servername));
2965 SetLastError(ERROR_INVALID_PRINTER_NAME);
2966 return FALSE;
2969 basename = get_basename_from_name(name);
2970 if (name != basename) TRACE("converted %s to %s\n",
2971 debugstr_w(name), debugstr_w(basename));
2973 /* an empty basename is invalid */
2974 if (basename && (!basename[0]))
2976 SetLastError(ERROR_INVALID_PARAMETER);
2977 return FALSE;
2980 *hprinter = server_alloc_handle(basename, &stop_search);
2981 if (!*hprinter && !stop_search)
2982 *hprinter = xcv_alloc_handle(basename, def, &stop_search);
2983 if (!*hprinter && !stop_search)
2984 *hprinter = port_alloc_handle(basename, &stop_search);
2985 if (!*hprinter && !stop_search)
2986 *hprinter = job_alloc_handle(basename, &stop_search);
2987 if (!*hprinter && !stop_search)
2988 *hprinter = printer_alloc_handle(name, basename, def);
2990 TRACE("==> %p\n", *hprinter);
2991 return *hprinter != 0;
2994 /******************************************************************************
2995 * fpXcvData [exported through PRINTPROVIDOR]
2997 * Execute commands in the Printmonitor DLL
2999 * PARAMS
3000 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
3001 * pszDataName [i] Name of the command to execute
3002 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
3003 * cbInputData [i] Size in Bytes of Buffer at pInputData
3004 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
3005 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
3006 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
3007 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
3009 * RETURNS
3010 * Success: TRUE
3011 * Failure: FALSE
3013 * NOTES
3014 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
3015 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
3017 * Minimal List of commands, that a Printmonitor DLL should support:
3019 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
3020 *| "AddPort" : Add a Port
3021 *| "DeletePort": Delete a Port
3023 * Many Printmonitors support additional commands. Examples for localspl.dll:
3024 * "GetDefaultCommConfig", "SetDefaultCommConfig",
3025 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
3028 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
3029 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
3030 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3032 xcv_t *xcv = (xcv_t *)hXcv;
3034 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
3035 pInputData, cbInputData, pOutputData,
3036 cbOutputData, pcbOutputNeeded, pdwStatus);
3038 if (!xcv || xcv->header.type != HANDLE_XCV) {
3039 SetLastError(ERROR_INVALID_HANDLE);
3040 return FALSE;
3043 if (!pcbOutputNeeded) {
3044 SetLastError(ERROR_INVALID_PARAMETER);
3045 return FALSE;
3048 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
3049 SetLastError(RPC_X_NULL_REF_POINTER);
3050 return FALSE;
3053 *pcbOutputNeeded = 0;
3055 if (xcv->pm->monitor.pfnXcvDataPort)
3056 *pdwStatus = xcv->pm->monitor.pfnXcvDataPort(xcv->hxcv, pszDataName,
3057 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
3059 return TRUE;
3062 static inline size_t form_struct_size( DWORD level )
3064 if (level == 1) return sizeof(FORM_INFO_1W);
3065 if (level == 2) return sizeof(FORM_INFO_2W);
3067 SetLastError( ERROR_INVALID_LEVEL );
3068 return 0;
3071 static void fill_builtin_form_info( BYTE **base, WCHAR **strings, const struct builtin_form *form, DWORD level,
3072 DWORD size, DWORD *used )
3074 FORM_INFO_2W *info = *(FORM_INFO_2W**)base;
3075 DWORD name_len = wcslen( form->name ) + 1, res_len = 0, keyword_len, total_size;
3076 static const WCHAR dll_name[] = L"localspl.dll";
3077 const WCHAR *resource;
3079 total_size = name_len * sizeof(WCHAR);
3081 if (level > 1)
3083 keyword_len = WideCharToMultiByte( CP_ACP, 0, form->name, -1, NULL, 0, NULL, NULL );
3084 keyword_len = (keyword_len + 1) & ~1;
3085 total_size += keyword_len;
3086 res_len = LoadStringW( localspl_instance, form->res_id, (WCHAR *)&resource, 0 );
3087 if (res_len && resource[res_len - 1]) res_len++;
3088 total_size += (res_len + ARRAY_SIZE(dll_name)) * sizeof(WCHAR);
3091 if (*used + total_size <= size)
3093 info->Flags = FORM_BUILTIN;
3094 info->pName = memcpy( *strings, form->name, name_len * sizeof(WCHAR) );
3095 *strings += name_len;
3096 info->Size = form->size;
3097 info->ImageableArea.left = info->ImageableArea.top = 0;
3098 info->ImageableArea.right = info->Size.cx;
3099 info->ImageableArea.bottom = info->Size.cy;
3100 if (level > 1)
3102 info->pKeyword = (char *)*strings;
3103 WideCharToMultiByte( CP_ACP, 0, form->name, -1, (char *)info->pKeyword, keyword_len, NULL, NULL );
3104 *strings += keyword_len / sizeof(WCHAR);
3105 info->StringType = STRING_MUIDLL;
3106 info->pMuiDll = memcpy( *strings, dll_name, sizeof(dll_name) );
3107 *strings += ARRAY_SIZE(dll_name);
3108 info->dwResourceId = form->res_id;
3109 if (res_len)
3111 info->StringType |= STRING_LANGPAIR;
3112 info->pDisplayName = memcpy( *strings, resource, (res_len - 1) * sizeof(WCHAR) );
3113 info->pDisplayName[res_len - 1] = '\0';
3114 *strings += res_len;
3115 info->wLangId = GetUserDefaultLangID();
3117 else
3119 info->pDisplayName = NULL;
3120 info->wLangId = 0;
3125 *base += form_struct_size( level );
3126 *used += total_size;
3129 static BOOL WINAPI fpAddForm( HANDLE printer, DWORD level, BYTE *form )
3131 FIXME( "(%p, %ld, %p): stub\n", printer, level, form );
3132 return TRUE;
3135 static BOOL WINAPI fpDeleteForm( HANDLE printer, WCHAR *name )
3137 FIXME( "(%p, %s): stub\n", printer, debugstr_w( name ) );
3138 return TRUE;
3141 static BOOL WINAPI fpGetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
3143 size_t struct_size = form_struct_size( level );
3144 const struct builtin_form *builtin = NULL;
3145 WCHAR *strings = NULL;
3146 BYTE *base = form;
3147 DWORD i;
3149 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
3151 *needed = 0;
3153 if (!struct_size) return FALSE;
3155 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
3157 if (!wcscmp( name, builtin_forms[i].name ))
3159 builtin = builtin_forms + i;
3160 break;
3164 if (!builtin)
3166 SetLastError( ERROR_INVALID_FORM_NAME );
3167 return FALSE;
3170 *needed = struct_size;
3171 if (*needed < size) strings = (WCHAR *)(form + *needed);
3173 fill_builtin_form_info( &base, &strings, builtin, level, size, needed );
3175 if (*needed > size)
3177 SetLastError( ERROR_INSUFFICIENT_BUFFER );
3178 return FALSE;
3180 return TRUE;
3183 static BOOL WINAPI fpSetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
3185 FIXME( "(%p, %s, %ld, %p): stub\n", printer, debugstr_w( name ), level, form );
3186 return FALSE;
3189 static BOOL WINAPI fpEnumForms( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
3191 DWORD num = ARRAY_SIZE(builtin_forms), i;
3192 WCHAR *strings = NULL;
3193 BYTE *base = form;
3194 size_t struct_size = form_struct_size( level );
3196 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
3198 *count = *needed = 0;
3200 if (!struct_size) return FALSE;
3202 *needed = num * struct_size;
3203 if (*needed < size) strings = (WCHAR *)(form + *needed);
3205 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
3206 fill_builtin_form_info( &base, &strings, builtin_forms + i, level, size, needed );
3208 if (*needed > size)
3210 SetLastError( ERROR_INSUFFICIENT_BUFFER );
3211 return FALSE;
3214 *count = i;
3215 return TRUE;
3218 static size_t get_spool_filename(DWORD job_id, WCHAR *buf, size_t len)
3220 static const WCHAR spool_path[] = L"spool\\PRINTERS\\";
3221 size_t ret;
3223 ret = GetSystemDirectoryW(NULL, 0) + ARRAY_SIZE(spool_path) + 10;
3224 if (len < ret)
3225 return ret;
3227 ret = GetSystemDirectoryW(buf, ret);
3228 if (buf[ret - 1] != '\\')
3229 buf[ret++] = '\\';
3230 memcpy(buf + ret, spool_path, sizeof(spool_path));
3231 ret += ARRAY_SIZE(spool_path) - 1;
3232 swprintf(buf + ret, 10, L"%05d.SPL", job_id);
3233 ret += 10;
3234 return ret;
3237 static job_info_t* add_job(printer_t *printer, DOC_INFO_1W *info, BOOL create)
3239 DWORD job_id, last_id;
3240 size_t len;
3241 job_info_t *job;
3243 job = calloc(1, sizeof(*job));
3244 if (!job)
3245 return NULL;
3246 len = get_spool_filename(0, NULL, 0);
3247 job->filename = malloc(len * sizeof(WCHAR));
3248 if (!job->filename)
3250 free(job);
3251 return NULL;
3253 job->port = wcsdup(info->pOutputFile);
3254 if (info->pOutputFile && !job->port)
3256 free(job->filename);
3257 free(job);
3258 return NULL;
3261 while (1)
3263 last_id = last_job_id;
3264 job_id = last_id < MAX_JOB_ID ? last_id + 1 : 1;
3265 if (InterlockedCompareExchange(&last_job_id, job_id, last_id) == last_id)
3266 break;
3269 job->id = job_id;
3270 get_spool_filename(job_id, job->filename, len);
3271 if (create)
3273 job->hf = CreateFileW(job->filename, GENERIC_WRITE, FILE_SHARE_READ,
3274 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3275 if (job->hf == INVALID_HANDLE_VALUE)
3277 free(job->filename);
3278 free(job);
3279 return NULL;
3282 else
3284 job->hf = NULL;
3286 job->document_title = wcsdup(info->pDocName);
3287 job->datatype = wcsdup(info->pDatatype);
3288 job->devmode = dup_devmode(printer->devmode);
3290 EnterCriticalSection(&printer->info->jobs_cs);
3291 list_add_tail(&printer->info->jobs, &job->entry);
3292 LeaveCriticalSection(&printer->info->jobs_cs);
3293 return job;
3296 static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size, DWORD *needed)
3298 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W *)data;
3299 printer_t *printer = (printer_t *)hprinter;
3300 DOC_INFO_1W doc_info;
3301 job_info_t *job;
3302 size_t len;
3304 TRACE("(%p %ld %p %ld %p)\n", hprinter, level, data, size, needed);
3306 if (!printer || printer->header.type != HANDLE_PRINTER)
3308 SetLastError(ERROR_INVALID_HANDLE);
3309 return FALSE;
3312 if (level != 1)
3314 SetLastError(ERROR_INVALID_LEVEL);
3315 return FALSE;
3318 if (!needed)
3320 SetLastError(ERROR_INVALID_PARAMETER);
3321 return FALSE;
3324 len = get_spool_filename(0, NULL, 0);
3325 *needed = sizeof(*addjob) + len * sizeof(WCHAR);
3326 if (size < *needed)
3328 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3329 return FALSE;
3332 memset(&doc_info, 0, sizeof(doc_info));
3333 doc_info.pDocName = (WCHAR *)L"Local Downlevel Document";
3334 job = add_job(printer, &doc_info, FALSE);
3335 if (!job)
3336 return FALSE;
3338 addjob->JobId = job->id;
3339 addjob->Path = (WCHAR *)(addjob + 1);
3340 memcpy(addjob->Path, job->filename, len * sizeof(WCHAR));
3341 return TRUE;
3344 typedef struct {
3345 HMODULE hmod;
3346 WCHAR *name;
3347 BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD,
3348 BYTE *, DWORD, DWORD *, DWORD *);
3349 HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *);
3350 BOOL (WINAPI *print)(HANDLE, WCHAR *);
3351 BOOL (WINAPI *close)(HANDLE);
3352 } printproc_t;
3354 static printproc_t * print_proc_load(const WCHAR *name)
3356 WCHAR *reg_path, path[2 * MAX_PATH];
3357 printproc_t *ret;
3358 DWORD size, len;
3359 LSTATUS status;
3360 HKEY hkey;
3362 size = sizeof(fmt_printprocessorsW) +
3363 (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR);
3364 reg_path = malloc(size);
3365 if (!reg_path)
3366 return NULL;
3367 swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname);
3368 wcscat(reg_path, name);
3370 status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey);
3371 free(reg_path);
3372 if (status != ERROR_SUCCESS)
3373 return NULL;
3375 if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size))
3377 RegCloseKey(hkey);
3378 return NULL;
3380 len = size / sizeof(WCHAR);
3381 path[len - 1] = '\\';
3383 size = sizeof(path) - len * sizeof(WCHAR);
3384 status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size);
3385 RegCloseKey(hkey);
3386 if (status != ERROR_SUCCESS)
3387 return NULL;
3389 ret = malloc(sizeof(*ret));
3390 if (!ret)
3391 return NULL;
3393 TRACE("loading print processor: %s\n", debugstr_w(path));
3395 ret->hmod = LoadLibraryW(path);
3396 if (!ret->hmod)
3398 free(ret);
3399 return NULL;
3402 ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW");
3403 ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor");
3404 ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor");
3405 ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor");
3406 if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close)
3408 FreeLibrary(ret->hmod);
3409 free(ret);
3410 return NULL;
3413 ret->name = wcsdup(name);
3414 return ret;
3417 static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype)
3419 DATATYPES_INFO_1W *types;
3420 DWORD size, no, i;
3422 if (!datatype)
3423 return FALSE;
3425 pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no);
3426 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3427 return FALSE;
3429 types = malloc(size);
3430 if (!types)
3431 return FALSE;
3433 if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no))
3435 free(types);
3436 return FALSE;
3439 for (i = 0; i < no; i++)
3441 if (!wcscmp(types[i].pName, datatype))
3442 break;
3444 free(types);
3445 return i < no;
3448 static void print_proc_unload(printproc_t *pp)
3450 FreeLibrary(pp->hmod);
3451 free(pp->name);
3452 free(pp);
3455 static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_info)
3457 printer_t *printer = (printer_t *)hprinter;
3458 DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info;
3459 BOOL datatype_valid = FALSE;
3460 WCHAR *datatype;
3461 printproc_t *pp;
3463 TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n",
3464 hprinter, level, doc_info, debugstr_w(info->pDocName),
3465 debugstr_w(info->pOutputFile), debugstr_w(info->pDatatype));
3467 if (!printer)
3469 SetLastError(ERROR_INVALID_HANDLE);
3470 return 0;
3473 if (printer->header.type == HANDLE_PORT)
3475 port_t *port = (port_t *)hprinter;
3476 /* TODO: pass printer name and job_id */
3477 return port->mon->monitor.pfnStartDocPort(port->hport,
3478 NULL, 0, level, doc_info);
3481 if (printer->header.type != HANDLE_PRINTER)
3483 SetLastError(ERROR_INVALID_HANDLE);
3484 return 0;
3487 if (level < 1 || level > 3)
3489 SetLastError(ERROR_INVALID_LEVEL);
3490 return 0;
3493 if (printer->doc)
3495 SetLastError(ERROR_INVALID_PRINTER_STATE);
3496 return 0;
3499 if (info->pDatatype)
3500 datatype = info->pDatatype;
3501 else if (printer->datatype)
3502 datatype = printer->datatype;
3503 else
3504 datatype = printer->info->datatype;
3506 if (!datatype || ((printer->info->attributes & PRINTER_ATTRIBUTE_RAW_ONLY) &&
3507 wcsicmp(datatype, L"RAW")))
3509 TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype));
3510 SetLastError(ERROR_INVALID_DATATYPE);
3511 return 0;
3514 pp = print_proc_load(printer->info->print_proc);
3515 if (!pp)
3517 WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc));
3519 else
3521 datatype_valid = print_proc_check_datatype(pp, datatype);
3522 print_proc_unload(pp);
3525 if (!datatype_valid)
3527 pp = print_proc_load(printer->print_proc);
3528 if (!pp)
3529 return 0;
3531 datatype_valid = print_proc_check_datatype(pp, datatype);
3532 print_proc_unload(pp);
3535 if (!datatype_valid)
3537 TRACE("%s datatype not supported by %s\n", debugstr_w(datatype),
3538 debugstr_w(printer->info->print_proc));
3539 SetLastError(ERROR_INVALID_DATATYPE);
3540 return 0;
3543 printer->doc = add_job(printer, info, TRUE);
3544 return printer->doc ? printer->doc->id : 0;
3547 static BOOL WINAPI fpWritePrinter(HANDLE hprinter, void *buf, DWORD size, DWORD *written)
3549 handle_header_t *header = (handle_header_t *)hprinter;
3551 TRACE("(%p, %p, %ld, %p)\n", hprinter, buf, size, written);
3553 if (!header)
3555 SetLastError(ERROR_INVALID_HANDLE);
3556 return FALSE;
3559 if (header->type == HANDLE_PORT)
3561 port_t *port = (port_t *)hprinter;
3563 return port->mon->monitor.pfnWritePort(port->hport, buf, size, written);
3566 if (header->type == HANDLE_PRINTER)
3568 printer_t *printer = (printer_t *)hprinter;
3570 if (!printer->doc)
3572 SetLastError(ERROR_SPL_NO_STARTDOC);
3573 return FALSE;
3576 return WriteFile(printer->doc->hf, buf, size, written, NULL);
3579 SetLastError(ERROR_INVALID_HANDLE);
3580 return FALSE;
3583 static BOOL WINAPI fpSetJob(HANDLE hprinter, DWORD job_id,
3584 DWORD level, BYTE *data, DWORD command)
3586 printer_t *printer = (printer_t *)hprinter;
3587 BOOL ret = FALSE;
3588 job_info_t *job;
3590 TRACE("(%p, %ld, %ld, %p, %ld)\n", hprinter, job_id, level, data, command);
3591 FIXME("Ignoring everything other than document title\n");
3593 if (!printer || printer->header.type != HANDLE_PRINTER)
3595 SetLastError(ERROR_INVALID_HANDLE);
3596 return 0;
3599 EnterCriticalSection(&printer->info->jobs_cs);
3600 job = get_job(printer->info, job_id);
3601 if (!job)
3603 LeaveCriticalSection(&printer->info->jobs_cs);
3604 return FALSE;
3607 switch(level)
3609 case 0:
3610 ret = TRUE;
3611 break;
3612 case 1:
3614 JOB_INFO_1W *info1 = (JOB_INFO_1W *)job;
3615 WCHAR *title = wcsdup(info1->pDocument);
3617 if (title)
3619 free(job->document_title);
3620 job->document_title = title;
3621 ret = TRUE;
3623 break;
3625 case 2:
3627 JOB_INFO_2W *info2 = (JOB_INFO_2W *)job;
3628 WCHAR *title = wcsdup(info2->pDocument);
3629 DEVMODEW *devmode = dup_devmode(info2->pDevMode);
3631 if (!title || !devmode)
3633 free(title);
3634 free(devmode);
3636 else
3638 free(job->document_title);
3639 free(job->devmode);
3640 job->document_title = title;
3641 job->devmode = devmode;
3642 ret = TRUE;
3644 break;
3646 case 3:
3647 FIXME("level 3 stub\n");
3648 ret = TRUE;
3649 break;
3650 default:
3651 SetLastError(ERROR_INVALID_LEVEL);
3652 break;
3655 LeaveCriticalSection(&printer->info->jobs_cs);
3656 return ret;
3659 static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level,
3660 BYTE *data, DWORD size, DWORD *needed)
3662 printer_t *printer = (printer_t *)hprinter;
3663 BOOL ret = TRUE;
3664 DWORD s = 0;
3665 job_info_t *job;
3666 WCHAR *p;
3668 TRACE("%p %ld %ld %p %ld %p\n", hprinter, job_id, level, data, size, needed);
3670 if (!printer || printer->header.type != HANDLE_PRINTER)
3672 SetLastError(ERROR_INVALID_HANDLE);
3673 return FALSE;
3676 if (!needed)
3678 SetLastError(ERROR_INVALID_PARAMETER);
3679 return FALSE;
3682 EnterCriticalSection(&printer->info->jobs_cs);
3683 job = get_job(printer->info, job_id);
3684 if (!job)
3686 LeaveCriticalSection(&printer->info->jobs_cs);
3687 return FALSE;
3690 switch(level)
3692 case 1:
3693 s = sizeof(JOB_INFO_1W);
3694 s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0;
3695 s += printer->info->name ?
3696 (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0;
3698 if (size >= s)
3700 JOB_INFO_1W *info = (JOB_INFO_1W *)data;
3702 p = (WCHAR *)(info + 1);
3703 memset(info, 0, sizeof(*info));
3704 info->JobId = job->id;
3705 if (job->document_title)
3707 info->pDocument = p;
3708 wcscpy(p, job->document_title);
3709 p += wcslen(job->document_title) + 1;
3711 if (printer->info->name)
3713 info->pPrinterName = p;
3714 wcscpy(p, printer->info->name);
3717 break;
3718 case 2:
3719 s = sizeof(JOB_INFO_2W);
3720 s += job->document_title ? (wcslen(job->document_title) + 1) * sizeof(WCHAR) : 0;
3721 s += printer->info->name ?
3722 (wcslen(printer->info->name) + 1) * sizeof(WCHAR) : 0;
3723 if (job->devmode)
3725 /* align DEVMODE to a DWORD boundary */
3726 s += (4 - (s & 3)) & 3;
3727 s += job->devmode->dmSize + job->devmode->dmDriverExtra;
3730 if (size >= s)
3732 JOB_INFO_2W *info = (JOB_INFO_2W *)data;
3734 p = (WCHAR *)(info + 1);
3735 memset(info, 0, sizeof(*info));
3736 info->JobId = job->id;
3737 if (job->document_title)
3739 info->pDocument = p;
3740 wcscpy(p, job->document_title);
3741 p += wcslen(job->document_title) + 1;
3743 if (printer->info->name)
3745 info->pPrinterName = p;
3746 wcscpy(p, printer->info->name);
3747 p += wcslen(printer->info->name) + 1;
3749 if (job->devmode)
3751 DEVMODEW *devmode = (DEVMODEW *)(data + s - job->devmode->dmSize
3752 - job->devmode->dmDriverExtra);
3753 info->pDevMode = devmode;
3754 memcpy(devmode, job->devmode, job->devmode->dmSize + job->devmode->dmDriverExtra);
3757 break;
3758 case 3:
3759 FIXME("level 3 stub\n");
3760 s = sizeof(JOB_INFO_3);
3762 if (size >= s)
3763 memset(data, 0, sizeof(JOB_INFO_3));
3764 break;
3765 default:
3766 SetLastError(ERROR_INVALID_LEVEL);
3767 ret = FALSE;
3768 break;
3771 LeaveCriticalSection(&printer->info->jobs_cs);
3773 *needed = s;
3774 if (size < s)
3776 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3777 ret = FALSE;
3779 return ret;
3782 static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id)
3784 printer_t *printer = (printer_t *)hprinter;
3785 WCHAR output[1024], name[1024], *datatype;
3786 BOOL datatype_valid = FALSE, ret = TRUE;
3787 PRINTPROCESSOROPENDATA pp_data;
3788 const WCHAR *port_name, *port;
3789 job_info_t *job;
3790 printproc_t *pp;
3791 HANDLE hpp;
3792 HKEY hkey;
3794 TRACE("%p %ld\n", hprinter, job_id);
3796 if (!printer || printer->header.type != HANDLE_PRINTER)
3798 SetLastError(ERROR_INVALID_HANDLE);
3799 return FALSE;
3802 EnterCriticalSection(&printer->info->jobs_cs);
3803 job = get_job(printer->info, job_id);
3804 if (!job)
3806 LeaveCriticalSection(&printer->info->jobs_cs);
3807 return FALSE;
3810 port = job->port;
3811 if (!port || !*port)
3812 port = printer->info->port;
3813 TRACE("need to schedule job %ld filename %s to port %s\n", job->id,
3814 debugstr_w(job->filename), debugstr_w(port));
3816 port_name = port;
3817 if ((isalpha(port[0]) && port[1] == ':') ||
3818 !wcsncmp(port, L"FILE:", ARRAY_SIZE(L"FILE:") - 1))
3820 port_name = L"FILE:";
3822 else if (!RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Wine\\Printing\\Spooler", &hkey))
3824 DWORD type, count = sizeof(output);
3825 if (!RegQueryValueExW(hkey, port, NULL, &type, (BYTE *)output, &count))
3827 TRACE("overriding port %s -> %s\n", debugstr_w(port), debugstr_w(output));
3828 port_name = output;
3830 RegCloseKey(hkey);
3833 if (job->datatype)
3834 datatype = job->datatype;
3835 else if (printer->datatype)
3836 datatype = printer->datatype;
3837 else
3838 datatype = printer->info->datatype;
3840 pp = print_proc_load(printer->info->print_proc);
3841 if (!pp)
3843 WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc));
3845 else
3847 datatype_valid = print_proc_check_datatype(pp, datatype);
3848 if (!datatype_valid)
3849 print_proc_unload(pp);
3852 if (!datatype_valid)
3854 pp = print_proc_load(printer->print_proc);
3855 if (!pp)
3856 return FALSE;
3858 datatype_valid = print_proc_check_datatype(pp, datatype);
3861 if (!datatype_valid)
3863 WARN("%s datatype not supported by %s\n", debugstr_w(datatype),
3864 debugstr_w(printer->info->print_proc));
3865 print_proc_unload(pp);
3866 return FALSE;
3869 swprintf(name, ARRAY_SIZE(name), L"%s, Port", port_name);
3870 pp_data.pDevMode = job->devmode;
3871 pp_data.pDatatype = datatype;
3872 pp_data.pParameters = NULL;
3873 pp_data.pDocumentName = job->document_title;
3874 pp_data.JobId = job->id;
3875 pp_data.pOutputFile = (WCHAR *)port;
3876 pp_data.pPrinterName = printer->name;
3877 hpp = pp->open(name, &pp_data);
3878 if (!hpp)
3880 WARN("OpenPrintProcessor failed %ld\n", GetLastError());
3881 print_proc_unload(pp);
3882 return FALSE;
3885 swprintf(name, ARRAY_SIZE(name), L"%s, Job %d", printer->name, job->id);
3886 ret = pp->print(hpp, name);
3887 if (!ret)
3888 WARN("PrintDocumentOnPrintProcessor failed %ld\n", GetLastError());
3889 pp->close(hpp);
3890 print_proc_unload(pp);
3892 if (!(printer->info->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS))
3893 DeleteFileW(job->filename);
3894 free_job(job);
3895 LeaveCriticalSection(&printer->info->jobs_cs);
3896 return ret;
3899 static BOOL WINAPI fpAbortPrinter(HANDLE hprinter)
3901 printer_t *printer = (printer_t *)hprinter;
3902 job_info_t *job;
3904 TRACE("%p\n", hprinter);
3906 if (!printer)
3908 SetLastError(ERROR_INVALID_HANDLE);
3909 return 0;
3912 if (printer->header.type != HANDLE_PRINTER)
3914 FIXME("%x handle not supported\n", printer->header.type);
3915 return FALSE;
3918 if (!printer->doc)
3920 SetLastError(ERROR_SPL_NO_STARTDOC);
3921 return FALSE;
3924 CloseHandle(printer->doc->hf);
3925 printer->doc->hf = NULL;
3927 EnterCriticalSection(&printer->info->jobs_cs);
3928 job = get_job(printer->info, printer->doc->id);
3929 if (job) free_job(job);
3930 LeaveCriticalSection(&printer->info->jobs_cs);
3932 printer->doc = NULL;
3933 return TRUE;
3936 static BOOL WINAPI fpReadPrinter(HANDLE hprinter, void *buf, DWORD size, DWORD *bytes_read)
3938 job_t *job = (job_t *)hprinter;
3940 TRACE("%p %p %lu %p\n", hprinter, buf, size, bytes_read);
3942 if (!job || (job->header.type != HANDLE_JOB))
3944 SetLastError(ERROR_INVALID_HANDLE);
3945 return FALSE;
3948 return ReadFile(job->hf, buf, size, bytes_read, NULL);
3951 static BOOL WINAPI fpEndDocPrinter(HANDLE hprinter)
3953 printer_t *printer = (printer_t *)hprinter;
3954 BOOL ret;
3956 TRACE("%p\n", hprinter);
3958 if (!printer)
3960 SetLastError(ERROR_INVALID_HANDLE);
3961 return 0;
3964 if (printer->header.type == HANDLE_PORT)
3966 port_t *port = (port_t *)hprinter;
3967 return port->mon->monitor.pfnEndDocPort(port->hport);
3970 if (printer->header.type != HANDLE_PRINTER)
3972 SetLastError(ERROR_INVALID_HANDLE);
3973 return FALSE;
3976 if (!printer->doc)
3978 SetLastError(ERROR_SPL_NO_STARTDOC);
3979 return FALSE;
3982 CloseHandle(printer->doc->hf);
3983 printer->doc->hf = NULL;
3984 ret = fpScheduleJob(hprinter, printer->doc->id);
3985 printer->doc = NULL;
3986 return ret;
3989 /******************************************************************************
3990 * fpClosePrinter [exported through PRINTPROVIDOR]
3992 * Close a printer handle and free associated resources
3994 * PARAMS
3995 * hPrinter [I] Printerhandle to close
3997 * RESULTS
3998 * Success: TRUE
3999 * Failure: FALSE
4002 static BOOL WINAPI fpClosePrinter(HANDLE hprinter)
4004 handle_header_t *header = (handle_header_t *)hprinter;
4006 TRACE("(%p)\n", hprinter);
4008 if (!header)
4009 return FALSE;
4011 if (header->type == HANDLE_SERVER)
4013 free(header);
4015 else if (header->type == HANDLE_XCV)
4017 xcv_t *xcv = (xcv_t *)hprinter;
4019 if (xcv->hxcv && xcv->pm->monitor.pfnXcvClosePort)
4020 xcv->pm->monitor.pfnXcvClosePort(xcv->hxcv);
4022 monitor_unload(xcv->pm);
4023 free(xcv);
4025 else if (header->type == HANDLE_PORT)
4027 port_t *port = (port_t *)hprinter;
4029 if (port->hport)
4030 port->mon->monitor.pfnClosePort(port->hport);
4031 if (port->mon)
4032 monitor_unload(port->mon);
4033 free(port);
4035 else if (header->type == HANDLE_JOB)
4037 job_t *job = (job_t *)hprinter;
4039 CloseHandle(job->hf);
4040 free(job);
4042 else if (header->type == HANDLE_PRINTER)
4044 printer_t *printer = (printer_t *)hprinter;
4046 if(printer->doc)
4047 fpEndDocPrinter(hprinter);
4049 release_printer_info(printer->info);
4050 free(printer->name);
4051 free(printer->print_proc);
4052 free(printer->datatype);
4053 free(printer->devmode);
4054 free(printer);
4056 else
4058 ERR("invalid handle type\n");
4059 return FALSE;
4061 return TRUE;
4064 static BOOL WINAPI fpSeekPrinter(HANDLE hprinter, LARGE_INTEGER distance,
4065 LARGE_INTEGER *pos, DWORD method, BOOL bwrite)
4067 job_t *job = (job_t *)hprinter;
4069 TRACE("(%p %I64d %p %lx %x)\n", hprinter, distance.QuadPart, pos, method, bwrite);
4071 if (!job)
4073 SetLastError(ERROR_INVALID_HANDLE);
4074 return FALSE;
4077 if (job->header.type != HANDLE_JOB)
4079 FIXME("handle %x not supported\n", job->header.type);
4080 return FALSE;
4083 if (bwrite)
4085 if (pos)
4086 pos->QuadPart = 0;
4087 return TRUE;
4090 return SetFilePointerEx(job->hf, distance, pos, method);
4093 static const PRINTPROVIDOR backend = {
4094 fpOpenPrinter,
4095 fpSetJob,
4096 fpGetJob,
4097 NULL, /* fpEnumJobs */
4098 NULL, /* fpAddPrinter */
4099 NULL, /* fpDeletePrinter */
4100 NULL, /* fpSetPrinter */
4101 NULL, /* fpGetPrinter */
4102 NULL, /* fpEnumPrinters */
4103 NULL, /* fpAddPrinterDriver */
4104 NULL, /* fpEnumPrinterDrivers */
4105 NULL, /* fpGetPrinterDriver */
4106 fpGetPrinterDriverDirectory,
4107 NULL, /* fpDeletePrinterDriver */
4108 fpAddPrintProcessor,
4109 fpEnumPrintProcessors,
4110 fpGetPrintProcessorDirectory,
4111 NULL, /* fpDeletePrintProcessor */
4112 NULL, /* fpEnumPrintProcessorDatatypes */
4113 fpStartDocPrinter,
4114 NULL, /* fpStartPagePrinter */
4115 fpWritePrinter,
4116 NULL, /* fpEndPagePrinter */
4117 fpAbortPrinter,
4118 fpReadPrinter,
4119 fpEndDocPrinter,
4120 fpAddJob,
4121 fpScheduleJob,
4122 NULL, /* fpGetPrinterData */
4123 NULL, /* fpSetPrinterData */
4124 NULL, /* fpWaitForPrinterChange */
4125 fpClosePrinter,
4126 fpAddForm,
4127 fpDeleteForm,
4128 fpGetForm,
4129 fpSetForm,
4130 fpEnumForms,
4131 fpEnumMonitors,
4132 fpEnumPorts,
4133 fpAddPort,
4134 fpConfigurePort,
4135 fpDeletePort,
4136 NULL, /* fpCreatePrinterIC */
4137 NULL, /* fpPlayGdiScriptOnPrinterIC */
4138 NULL, /* fpDeletePrinterIC */
4139 NULL, /* fpAddPrinterConnection */
4140 NULL, /* fpDeletePrinterConnection */
4141 NULL, /* fpPrinterMessageBox */
4142 fpAddMonitor,
4143 fpDeleteMonitor,
4144 fpResetPrinter,
4145 NULL, /* fpGetPrinterDriverEx */
4146 NULL, /* fpFindFirstPrinterChangeNotification */
4147 NULL, /* fpFindClosePrinterChangeNotification */
4148 fpAddPortEx,
4149 NULL, /* fpShutDown */
4150 NULL, /* fpRefreshPrinterChangeNotification */
4151 NULL, /* fpOpenPrinterEx */
4152 NULL, /* fpAddPrinterEx */
4153 NULL, /* fpSetPort */
4154 NULL, /* fpEnumPrinterData */
4155 NULL, /* fpDeletePrinterData */
4156 NULL, /* fpClusterSplOpen */
4157 NULL, /* fpClusterSplClose */
4158 NULL, /* fpClusterSplIsAlive */
4159 NULL, /* fpSetPrinterDataEx */
4160 NULL, /* fpGetPrinterDataEx */
4161 NULL, /* fpEnumPrinterDataEx */
4162 NULL, /* fpEnumPrinterKey */
4163 NULL, /* fpDeletePrinterDataEx */
4164 NULL, /* fpDeletePrinterKey */
4165 fpSeekPrinter,
4166 NULL, /* fpDeletePrinterDriverEx */
4167 NULL, /* fpAddPerMachineConnection */
4168 NULL, /* fpDeletePerMachineConnection */
4169 NULL, /* fpEnumPerMachineConnections */
4170 fpXcvData,
4171 fpAddPrinterDriverEx,
4172 NULL, /* fpSplReadPrinter */
4173 NULL, /* fpDriverUnloadComplete */
4174 NULL, /* fpGetSpoolFileInfo */
4175 NULL, /* fpCommitSpoolData */
4176 NULL, /* fpCloseSpoolFileHandle */
4177 NULL, /* fpFlushPrinter */
4178 NULL, /* fpSendRecvBidiData */
4179 NULL /* fpAddDriverCatalog */
4182 /*****************************************************
4183 * InitializePrintProvidor (localspl.@)
4185 * Initialize the Printprovider
4187 * PARAMS
4188 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
4189 * cbPrintProvidor [I] Size of Buffer in Bytes
4190 * pFullRegistryPath [I] Registry-Path for the Printprovidor
4192 * RETURNS
4193 * Success: TRUE and pPrintProvidor filled
4194 * Failure: FALSE
4196 * NOTES
4197 * The RegistryPath should be:
4198 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
4199 * but this Parameter is ignored in "localspl.dll".
4203 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
4204 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
4207 TRACE("(%p, %lu, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
4208 memcpy(pPrintProvidor, &backend,
4209 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
4211 return TRUE;