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
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
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
=
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 /* ############################### */
191 WCHAR src
[MAX_PATH
+MAX_PATH
];
192 WCHAR dst
[MAX_PATH
+MAX_PATH
];
203 PMONITORUI monitorUI
;
205 const MONITOREX
*monitorex
;
215 LPCWSTR versionregpath
;
216 LPCWSTR versionsubdir
;
219 #define MAX_JOB_ID 99999
227 WCHAR
*document_title
;
242 CRITICAL_SECTION jobs_cs
;
257 typedef handle_header_t server_t
;
260 handle_header_t header
;
266 handle_header_t header
;
272 handle_header_t header
;
277 handle_header_t header
;
278 printer_info_t
*info
;
285 /* ############################### */
287 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
288 static monitor_t
* pm_localport
;
290 static struct list printers
= LIST_INIT(printers
);
291 static LONG last_job_id
;
293 static const WCHAR fmt_driversW
[] =
294 L
"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
295 static const WCHAR fmt_printprocessorsW
[] =
296 L
"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors\\";
297 static const WCHAR monitorsW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
298 static const WCHAR printersW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Printers";
299 static const WCHAR winnt_cv_portsW
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
300 static const WCHAR x86_envnameW
[] = L
"Windows NT x86";
303 static const printenv_t env_ia64
= {L
"Windows IA64", L
"ia64", 3,
304 L
"\\Version-3", L
"\\3"};
306 static const printenv_t env_x86
= {x86_envnameW
, L
"w32x86", 3,
307 L
"\\Version-3", L
"\\3"};
309 static const printenv_t env_x64
= {L
"Windows x64", L
"x64", 3,
310 L
"\\Version-3", L
"\\3"};
312 static const printenv_t env_arm
= {L
"Windows ARM", L
"arm", 3,
313 L
"\\Version-3", L
"\\3"};
315 static const printenv_t env_arm64
= {L
"Windows ARM64", L
"arm64", 3,
316 L
"\\Version-3", L
"\\3"};
318 static const printenv_t env_win40
= {L
"Windows 4.0", L
"win40", 0,
319 L
"\\Version-0", L
"\\0"};
321 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_arm
, &env_arm64
, &env_win40
};
324 #define env_arch env_x86
325 #elif defined __x86_64__
326 #define env_arch env_x64
327 #elif defined __arm__
328 #define env_arch env_arm
329 #elif defined __aarch64__
330 #define env_arch env_arm64
332 #error not defined for this cpu
336 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
337 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
338 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
339 0, sizeof(DRIVER_INFO_8W
)};
341 static BOOL WINAPI
fpClosePrinter(HANDLE
);
343 /******************************************************************
344 * apd_copyfile [internal]
346 * Copy a file from the driverdirectory to the versioned directory
353 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
358 apd
->src
[apd
->srclen
] = '\0';
359 apd
->dst
[apd
->dstlen
] = '\0';
361 if (!pathname
|| !pathname
[0]) {
362 /* nothing to copy */
366 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
371 lstrcatW( srcname
, file_part
);
373 lstrcatW( apd
->dst
, file_part
);
375 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
377 /* FIXME: handle APD_COPY_NEW_FILES */
378 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
379 TRACE("got %d with %lu\n", res
, GetLastError());
381 return apd
->lazy
|| res
;
384 /******************************************************************
385 * copy_servername_from_name (internal)
387 * for an external server, the serverpart from the name is copied.
390 * the length (in WCHAR) of the serverpart (0 for the local computer)
391 * (-length), when the name is too long
394 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
398 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
402 if (target
) *target
= '\0';
404 if (name
== NULL
) return 0;
405 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
408 /* skip over both backslash, find separator '\' */
409 ptr
= wcschr(server
, '\\');
410 serverlen
= (ptr
) ? ptr
- server
: wcslen(server
);
412 /* servername is empty */
413 if (serverlen
== 0) return 0;
415 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
417 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
420 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
421 target
[serverlen
] = '\0';
424 len
= ARRAY_SIZE(buffer
);
425 if (GetComputerNameW(buffer
, &len
)) {
426 if ((serverlen
== len
) && (wcsnicmp(server
, buffer
, len
) == 0)) {
427 /* The requested Servername is our computername */
434 /******************************************************************
435 * get_basename_from_name (internal)
437 * skip over the serverpart from the full name
440 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
442 if (name
== NULL
) return NULL
;
443 if ((name
[0] == '\\') && (name
[1] == '\\')) {
444 /* skip over the servername and search for the following '\' */
445 name
= wcschr(&name
[2], '\\');
446 if ((name
) && (name
[1])) {
447 /* found a separator ('\') followed by a name:
448 skip over the separator and return the rest */
453 /* no basename present (we found only a servername) */
460 /******************************************************************
461 * monitor_unload [internal]
463 * release a printmonitor and unload it from memory, when needed
466 static void monitor_unload(monitor_t
* pm
)
468 if (pm
== NULL
) return;
469 TRACE("%p (refcount: %ld) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
471 EnterCriticalSection(&monitor_handles_cs
);
473 if (pm
->refcount
) pm
->refcount
--;
475 if (pm
->refcount
== 0) {
476 list_remove(&pm
->entry
);
478 if (pm
->monitor
.pfnShutdown
)
479 pm
->monitor
.pfnShutdown(pm
->hmon
);
481 FreeLibrary(pm
->hdll
);
486 LeaveCriticalSection(&monitor_handles_cs
);
489 /******************************************************************
490 * monitor_unloadall [internal]
492 * release all registered printmonitors and unload them from memory, when needed
496 static void monitor_unloadall(void)
501 EnterCriticalSection(&monitor_handles_cs
);
502 /* iterate through the list, with safety against removal */
503 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
505 /* skip monitorui dlls */
506 if (pm
->monitor
.cbSize
) monitor_unload(pm
);
508 LeaveCriticalSection(&monitor_handles_cs
);
511 static printer_info_t
*find_printer_info(const WCHAR
*name
, unsigned int len
)
513 printer_info_t
*info
;
515 EnterCriticalSection(&printers_cs
);
516 LIST_FOR_EACH_ENTRY(info
, &printers
, printer_info_t
, entry
)
518 if (!wcsncmp(info
->name
, name
, len
) && (len
== -1 || !info
->name
[len
]))
520 InterlockedIncrement(&info
->ref
);
521 LeaveCriticalSection(&printers_cs
);
525 LeaveCriticalSection(&printers_cs
);
529 static WCHAR
* reg_query_value(HKEY key
, const WCHAR
*name
)
534 if (RegQueryValueExW(key
, name
, 0, &type
, NULL
, &size
) != ERROR_SUCCESS
542 if (RegQueryValueExW(key
, name
, 0, NULL
, (BYTE
*)ret
, &size
) != ERROR_SUCCESS
)
550 static DWORD
reg_query_dword(HKEY hkey
, const WCHAR
*name
)
552 DWORD type
, val
, size
= sizeof(size
);
554 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&val
, &size
))
556 if (type
!= REG_DWORD
)
561 static printer_info_t
* get_printer_info(const WCHAR
*name
)
563 HKEY hkey
, hprinter
= NULL
;
564 printer_info_t
*info
;
567 EnterCriticalSection(&printers_cs
);
568 info
= find_printer_info(name
, -1);
571 LeaveCriticalSection(&printers_cs
);
575 ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkey
);
576 if (ret
== ERROR_SUCCESS
)
577 ret
= RegOpenKeyW(hkey
, name
, &hprinter
);
579 if (ret
!= ERROR_SUCCESS
)
581 LeaveCriticalSection(&printers_cs
);
585 info
= calloc(1, sizeof(*info
));
588 LeaveCriticalSection(&printers_cs
);
589 RegCloseKey(hprinter
);
593 info
->name
= wcsdup(name
);
594 info
->port
= reg_query_value(hprinter
, L
"Port");
595 info
->print_proc
= reg_query_value(hprinter
, L
"Print Processor");
596 info
->datatype
= reg_query_value(hprinter
, L
"Datatype");
597 info
->attributes
= reg_query_dword(hprinter
, L
"Attributes");
598 RegCloseKey(hprinter
);
600 if (!info
->name
|| !info
->port
|| !info
->print_proc
|| !info
->datatype
)
604 free(info
->print_proc
);
605 free(info
->datatype
);
608 LeaveCriticalSection(&printers_cs
);
613 list_add_head(&printers
, &info
->entry
);
614 InitializeCriticalSection(&info
->jobs_cs
);
615 list_init(&info
->jobs
);
617 LeaveCriticalSection(&printers_cs
);
621 static void free_job(job_info_t
*job
)
623 list_remove(&job
->entry
);
627 free(job
->document_title
);
629 CloseHandle(job
->hf
);
633 static void release_printer_info(printer_info_t
*info
)
638 if (!InterlockedDecrement(&info
->ref
))
640 EnterCriticalSection(&printers_cs
);
641 list_remove(&info
->entry
);
642 LeaveCriticalSection(&printers_cs
);
646 free(info
->print_proc
);
647 free(info
->datatype
);
648 DeleteCriticalSection(&info
->jobs_cs
);
649 while (!list_empty(&info
->jobs
))
651 job_info_t
*job
= LIST_ENTRY(list_head(&info
->jobs
), job_info_t
, entry
);
658 static DEVMODEW
* dup_devmode(const DEVMODEW
*dm
)
662 if (!dm
) return NULL
;
663 ret
= malloc(dm
->dmSize
+ dm
->dmDriverExtra
);
664 if (ret
) memcpy(ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
668 static LONG WINAPI
CreateKey(HANDLE hcKey
, LPCWSTR pszSubKey
, DWORD dwOptions
,
669 REGSAM samDesired
, PSECURITY_ATTRIBUTES pSecurityAttributes
,
670 PHANDLE phckResult
, PDWORD pdwDisposition
, HANDLE hSpooler
)
673 return ERROR_CALL_NOT_IMPLEMENTED
;
676 static LONG WINAPI
OpenKey(HANDLE hcKey
, LPCWSTR pszSubKey
, REGSAM samDesired
,
677 PHANDLE phkResult
, HANDLE hSpooler
)
680 return ERROR_CALL_NOT_IMPLEMENTED
;
683 static LONG WINAPI
CloseKey(HANDLE hcKey
, HANDLE hSpooler
)
686 return ERROR_CALL_NOT_IMPLEMENTED
;
689 static LONG WINAPI
DeleteKey(HANDLE hcKey
, LPCWSTR pszSubKey
, HANDLE hSpooler
)
692 return ERROR_CALL_NOT_IMPLEMENTED
;
695 static LONG WINAPI
EnumKey(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszName
,
696 PDWORD pcchName
, PFILETIME pftLastWriteTime
, HANDLE hSpooler
)
699 return ERROR_CALL_NOT_IMPLEMENTED
;
702 static LONG WINAPI
QueryInfoKey(HANDLE hcKey
, PDWORD pcSubKeys
, PDWORD pcbKey
,
703 PDWORD pcValues
, PDWORD pcbValue
, PDWORD pcbData
,
704 PDWORD pcbSecurityDescriptor
, PFILETIME pftLastWriteTime
,
708 return ERROR_CALL_NOT_IMPLEMENTED
;
711 static LONG WINAPI
SetValue(HANDLE hcKey
, LPCWSTR pszValue
, DWORD dwType
,
712 const BYTE
* pData
, DWORD cbData
, HANDLE hSpooler
)
715 return ERROR_CALL_NOT_IMPLEMENTED
;
718 static LONG WINAPI
DeleteValue(HANDLE hcKey
, LPCWSTR pszValue
, HANDLE hSpooler
)
721 return ERROR_CALL_NOT_IMPLEMENTED
;
724 static LONG WINAPI
EnumValue(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszValue
,
725 PDWORD pcbValue
, PDWORD pType
, PBYTE pData
, PDWORD pcbData
,
729 return ERROR_CALL_NOT_IMPLEMENTED
;
732 static LONG WINAPI
QueryValue(HANDLE hcKey
, LPCWSTR pszValue
, PDWORD pType
,
733 PBYTE pData
, PDWORD pcbData
, HANDLE hSpooler
)
736 return ERROR_CALL_NOT_IMPLEMENTED
;
739 static MONITORREG monreg
=
754 static BOOL WINAPI
monitor2_EnumPorts(HANDLE hmon
, WCHAR
*name
, DWORD level
,
755 BYTE
*buf
, DWORD size
, DWORD
*needed
, DWORD
*count
)
757 return ((MONITOREX
*)hmon
)->Monitor
.pfnEnumPorts(name
, level
,
758 buf
, size
, needed
, count
);
761 static BOOL WINAPI
monitor2_OpenPort(HANDLE hmon
, WCHAR
*name
, HANDLE
*hport
)
763 return ((MONITOREX
*)hmon
)->Monitor
.pfnOpenPort(name
, hport
);
766 static BOOL WINAPI
monitor2_AddPort(HANDLE hmon
, WCHAR
*name
,
767 HWND hwnd
, WCHAR
*monitor_name
)
769 return ((MONITOREX
*)hmon
)->Monitor
.pfnAddPort(name
, hwnd
, monitor_name
);
772 static BOOL WINAPI
monitor2_AddPortEx(HANDLE hmon
, WCHAR
*name
, DWORD level
,
773 BYTE
*buf
, WCHAR
*monitor_name
)
775 return ((MONITOREX
*)hmon
)->Monitor
.pfnAddPortEx(name
, level
, buf
, monitor_name
);
778 static BOOL WINAPI
monitor2_ConfigurePort(HANDLE hmon
, WCHAR
*name
,
779 HWND hwnd
, WCHAR
*port_name
)
781 return ((MONITOREX
*)hmon
)->Monitor
.pfnConfigurePort(name
, hwnd
, port_name
);
784 static BOOL WINAPI
monitor2_DeletePort(HANDLE hmon
, WCHAR
*name
,
785 HWND hwnd
, WCHAR
*port_name
)
787 return ((MONITOREX
*)hmon
)->Monitor
.pfnDeletePort(name
, hwnd
, port_name
);
790 static BOOL WINAPI
monitor2_XcvOpenPort(HANDLE hmon
, const WCHAR
*obj
,
791 ACCESS_MASK granted_access
, HANDLE
*hxcv
)
793 return ((MONITOREX
*)hmon
)->Monitor
.pfnXcvOpenPort(obj
, granted_access
, hxcv
);
796 /******************************************************************
797 * monitor_load [internal]
799 * load a printmonitor, get the dllname from the registry, when needed
800 * initialize the monitor and dump found function-pointers
802 * On failure, SetLastError() is called and NULL is returned
805 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
807 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
808 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
809 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
810 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
811 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
813 monitor_t
* pm
= NULL
;
815 LPWSTR regroot
= NULL
;
816 LPWSTR driver
= dllname
;
819 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
820 /* Is the Monitor already loaded? */
821 EnterCriticalSection(&monitor_handles_cs
);
824 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
826 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
834 pm
= calloc(1, sizeof(monitor_t
));
835 if (pm
== NULL
) goto cleanup
;
836 list_add_tail(&monitor_handles
, &pm
->entry
);
840 if (pm
->name
== NULL
) {
841 /* Load the monitor */
845 len
= wcslen(monitorsW
) + wcslen(name
) + 2;
846 regroot
= malloc(len
* sizeof(WCHAR
));
850 lstrcpyW(regroot
, monitorsW
);
851 lstrcatW(regroot
, name
);
852 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
853 /* Get the Driver from the Registry */
855 driver
= reg_query_value(hroot
, L
"Driver");
858 WARN("%s not found\n", debugstr_w(regroot
));
861 pm
->name
= wcsdup(name
);
862 pm
->dllname
= wcsdup(driver
);
864 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
866 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
871 pm
->hdll
= LoadLibraryW(driver
);
872 TRACE("%p: LoadLibrary(%s) => %ld\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
874 if (pm
->hdll
== NULL
) {
876 SetLastError(ERROR_MOD_NOT_FOUND
);
881 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
882 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
883 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
884 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
885 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
888 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
889 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
890 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
891 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
892 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
894 if (pInitializePrintMonitorUI
!= NULL
) {
895 pm
->monitorUI
= pInitializePrintMonitorUI();
896 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
898 TRACE("0x%08lx: dwMonitorSize (%ld)\n",
899 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
904 if (pInitializePrintMonitor2
&& hroot
) {
909 memset(&init
, 0, sizeof(init
));
910 init
.cbSize
= sizeof(init
);
911 init
.hckRegistryRoot
= hroot
;
912 init
.pMonitorReg
= &monreg
;
915 monitor2
= pInitializePrintMonitor2(&init
, &hmon
);
916 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
917 monitor2
, debugstr_w(driver
), debugstr_w(regroot
));
920 memcpy(&pm
->monitor
, monitor2
, min(monitor2
->cbSize
, sizeof(pm
->monitor
)));
924 else if (pInitializePrintMonitor
&& regroot
) {
926 pm
->monitorex
= pInitializePrintMonitor(regroot
);
927 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
928 pm
->monitorex
, debugstr_w(driver
), debugstr_w(regroot
));
931 pm
->hmon
= (HANDLE
)pm
->monitorex
;
933 pm
->monitor
.cbSize
= sizeof(pm
->monitor
);
934 if (pm
->monitorex
->Monitor
.pfnEnumPorts
)
935 pm
->monitor
.pfnEnumPorts
= monitor2_EnumPorts
;
936 if (pm
->monitorex
->Monitor
.pfnOpenPort
)
937 pm
->monitor
.pfnOpenPort
= monitor2_OpenPort
;
938 pm
->monitor
.pfnStartDocPort
= pm
->monitorex
->Monitor
.pfnStartDocPort
;
939 pm
->monitor
.pfnWritePort
= pm
->monitorex
->Monitor
.pfnWritePort
;
940 pm
->monitor
.pfnReadPort
= pm
->monitorex
->Monitor
.pfnReadPort
;
941 pm
->monitor
.pfnEndDocPort
= pm
->monitorex
->Monitor
.pfnEndDocPort
;
942 pm
->monitor
.pfnClosePort
= pm
->monitorex
->Monitor
.pfnClosePort
;
943 if (pm
->monitorex
->Monitor
.pfnAddPort
)
944 pm
->monitor
.pfnAddPort
= monitor2_AddPort
;
945 if (pm
->monitorex
->Monitor
.pfnAddPortEx
)
946 pm
->monitor
.pfnAddPortEx
= monitor2_AddPortEx
;
947 if (pm
->monitorex
->Monitor
.pfnConfigurePort
)
948 pm
->monitor
.pfnConfigurePort
= monitor2_ConfigurePort
;
949 if (pm
->monitorex
->Monitor
.pfnDeletePort
)
950 pm
->monitor
.pfnDeletePort
= monitor2_DeletePort
;
951 pm
->monitor
.pfnGetPrinterDataFromPort
=
952 pm
->monitorex
->Monitor
.pfnGetPrinterDataFromPort
;
953 pm
->monitor
.pfnSetPortTimeOuts
= pm
->monitorex
->Monitor
.pfnSetPortTimeOuts
;
954 if (pm
->monitorex
->Monitor
.pfnXcvOpenPort
)
955 pm
->monitor
.pfnXcvOpenPort
= monitor2_XcvOpenPort
;
956 pm
->monitor
.pfnXcvDataPort
= pm
->monitorex
->Monitor
.pfnXcvDataPort
;
957 pm
->monitor
.pfnXcvClosePort
= pm
->monitorex
->Monitor
.pfnXcvClosePort
;
961 if (!pm
->monitor
.cbSize
&& regroot
) {
962 if (pInitializeMonitorEx
!= NULL
) {
963 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
965 if (pInitializeMonitor
!= NULL
) {
966 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
969 if (!pm
->monitor
.cbSize
&& !pm
->monitorUI
) {
971 SetLastError(ERROR_PROC_NOT_FOUND
);
976 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, L
"Local Port") == 0)) {
980 LeaveCriticalSection(&monitor_handles_cs
);
981 if (driver
!= dllname
) free(driver
);
982 if (hroot
) RegCloseKey(hroot
);
984 TRACE("=> %p\n", pm
);
988 /******************************************************************
989 * monitor_loadall [internal]
991 * Load all registered monitors
994 static DWORD
monitor_loadall(void)
997 DWORD registered
= 0;
1000 WCHAR buffer
[MAX_PATH
];
1003 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1004 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1005 NULL
, NULL
, NULL
, NULL
, NULL
);
1007 TRACE("%ld monitors registered\n", registered
);
1009 while (id
< registered
) {
1011 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1012 pm
= monitor_load(buffer
, NULL
);
1016 RegCloseKey(hmonitors
);
1018 TRACE("%ld monitors loaded\n", loaded
);
1022 /******************************************************************
1023 * monitor_loadui [internal]
1025 * load the userinterface-dll for a given portmonitor
1027 * On failure, NULL is returned
1029 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1031 monitor_t
* pui
= NULL
;
1032 WCHAR buffer
[MAX_PATH
];
1037 if (pm
== NULL
) return NULL
;
1038 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1040 /* Try the Portmonitor first; works for many monitors */
1041 if (pm
->monitorUI
) {
1042 EnterCriticalSection(&monitor_handles_cs
);
1044 LeaveCriticalSection(&monitor_handles_cs
);
1048 /* query the userinterface-dllname from the Portmonitor */
1049 /* building (",XcvMonitor %s",pm->name) not needed yet */
1050 if (pm
->monitor
.pfnXcvOpenPort
)
1051 res
= pm
->monitor
.pfnXcvOpenPort(pm
->hmon
, L
"", SERVER_ACCESS_ADMINISTER
, &hXcv
);
1052 TRACE("got %lu with %p\n", res
, hXcv
);
1054 res
= pm
->monitor
.pfnXcvDataPort(hXcv
, L
"MonitorUI", NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1055 TRACE("got %lu with %s\n", res
, debugstr_w(buffer
));
1056 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
1057 pm
->monitor
.pfnXcvClosePort(hXcv
);
1062 /******************************************************************
1063 * monitor_load_by_port [internal]
1065 * load a printmonitor for a given port
1067 * On failure, NULL is returned
1070 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1075 monitor_t
* pm
= NULL
;
1076 DWORD registered
= 0;
1080 TRACE("(%s)\n", debugstr_w(portname
));
1082 /* wine specific ports */
1083 if (portname
[0] == '|' || portname
[0] == '/' ||
1084 !wcsncmp(portname
, L
"LPR:", 4) || !wcsncmp(portname
, L
"CUPS:", 5))
1085 return monitor_load(L
"Local Port", NULL
);
1087 /* Try the Local Monitor first */
1088 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
1089 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1090 /* found the portname */
1092 return monitor_load(L
"Local Port", NULL
);
1097 len
= MAX_PATH
+ wcslen(L
"\\Ports\\") + wcslen(portname
) + 1;
1098 buffer
= malloc(len
* sizeof(WCHAR
));
1099 if (buffer
== NULL
) return NULL
;
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
1102 EnterCriticalSection(&monitor_handles_cs
);
1103 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1105 while ((pm
== NULL
) && (id
< registered
)) {
1107 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1108 TRACE("testing %s\n", debugstr_w(buffer
));
1109 len
= wcslen(buffer
);
1110 lstrcatW(buffer
, L
"\\Ports\\");
1111 lstrcatW(buffer
, portname
);
1112 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1114 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1115 pm
= monitor_load(buffer
, NULL
);
1119 LeaveCriticalSection(&monitor_handles_cs
);
1126 /******************************************************************
1127 * Return the number of bytes for an multi_sz string.
1128 * The result includes all \0s
1129 * (specifically the extra \0, that is needed as multi_sz terminator).
1131 static int multi_sz_lenW(const WCHAR
*str
)
1133 const WCHAR
*ptr
= str
;
1137 ptr
+= wcslen(ptr
) + 1;
1140 return (ptr
- str
+ 1) * sizeof(WCHAR
);
1143 /******************************************************************
1144 * validate_envW [internal]
1146 * validate the user-supplied printing-environment
1149 * env [I] PTR to Environment-String or NULL
1152 * Success: PTR to printenv_t
1153 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
1156 * An empty string is handled the same way as NULL.
1160 static const printenv_t
* validate_envW(LPCWSTR env
)
1162 const printenv_t
*result
= NULL
;
1165 TRACE("(%s)\n", debugstr_w(env
));
1168 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
1170 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
1172 result
= all_printenv
[i
];
1176 if (result
== NULL
) {
1177 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
1178 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1180 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
1184 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_arch
;
1187 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
1191 /*****************************************************************************
1192 * enumerate the local monitors (INTERNAL)
1194 * returns the needed size (in bytes) for pMonitors
1195 * and *lpreturned is set to number of entries returned in pMonitors
1197 * Language-Monitors are also installed in the same Registry-Location but
1198 * they are filtered in Windows (not returned by EnumMonitors).
1199 * We do no filtering to simplify our Code.
1202 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
1207 LPMONITOR_INFO_2W mi
;
1208 WCHAR buffer
[MAX_PATH
];
1209 WCHAR dllname
[MAX_PATH
];
1217 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
1219 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1220 len
= entrysize
* numentries
;
1221 ptr
= (LPWSTR
) &pMonitors
[len
];
1224 len
= ARRAY_SIZE(buffer
);
1227 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
1228 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
1229 /* Scan all Monitor-Registry-Keys */
1230 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1231 TRACE("Monitor_%ld: %s\n", numentries
, debugstr_w(buffer
));
1232 dllsize
= sizeof(dllname
);
1235 /* The Monitor must have a Driver-DLL */
1236 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
1237 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
1238 /* We found a valid DLL for this Monitor. */
1239 TRACE("using Driver: %s\n", debugstr_w(dllname
));
1241 RegCloseKey(hentry
);
1244 /* Windows returns only Port-Monitors here, but to simplify our code,
1245 we do no filtering for Language-Monitors */
1248 needed
+= entrysize
;
1249 needed
+= (len
+1) * sizeof(WCHAR
); /* len is wcslen(monitorname) */
1251 /* we install and return only monitors for "Windows NT x86" */
1252 needed
+= (wcslen(x86_envnameW
) +1) * sizeof(WCHAR
);
1256 /* required size is calculated. Now fill the user-buffer */
1257 if (pMonitors
&& (cbBuf
>= needed
)){
1258 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
1259 pMonitors
+= entrysize
;
1261 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi
, level
, numentries
);
1263 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
1264 ptr
+= (len
+1); /* len is wcslen(monitorname) */
1266 mi
->pEnvironment
= ptr
;
1267 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
1268 ptr
+= (wcslen(x86_envnameW
)+1);
1271 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
1272 ptr
+= (dllsize
/ sizeof(WCHAR
));
1277 len
= ARRAY_SIZE(buffer
);
1282 *lpreturned
= numentries
;
1283 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1287 /*****************************************************************************
1288 * enumerate the local print processors (INTERNAL)
1290 * returns the needed size (in bytes) for pPPInfo
1291 * and *lpreturned is set to number of entries returned in pPPInfo
1294 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
1299 PPRINTPROCESSOR_INFO_1W ppi
;
1300 WCHAR buffer
[MAX_PATH
];
1301 WCHAR dllname
[MAX_PATH
];
1308 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1309 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
1310 ptr
= (LPWSTR
) &pPPInfo
[len
];
1313 len
= ARRAY_SIZE(buffer
);
1316 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
1317 /* add "winprint" first */
1319 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(L
"winprint");
1320 if (pPPInfo
&& (cbBuf
>= needed
)){
1321 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
1322 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1324 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi
, numentries
);
1326 lstrcpyW(ptr
, L
"winprint"); /* Name of the Print Processor */
1327 ptr
+= ARRAY_SIZE(L
"winprint");
1330 /* Scan all Printprocessor Keys */
1331 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
1332 (lstrcmpiW(buffer
, L
"winprint") != 0)) {
1333 TRACE("PrintProcessor_%ld: %s\n", numentries
, debugstr_w(buffer
));
1334 dllsize
= sizeof(dllname
);
1337 /* The Print Processor must have a Driver-DLL */
1338 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
1339 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
1340 /* We found a valid DLL for this Print Processor */
1341 TRACE("using Driver: %s\n", debugstr_w(dllname
));
1343 RegCloseKey(hentry
);
1348 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1349 needed
+= (len
+1) * sizeof(WCHAR
); /* len is wcslen(printprocessor name) */
1351 /* required size is calculated. Now fill the user-buffer */
1352 if (pPPInfo
&& (cbBuf
>= needed
)){
1353 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
1354 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1356 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi
, numentries
);
1358 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
1359 ptr
+= (len
+1); /* len is wcslen(printprosessor name) */
1363 len
= ARRAY_SIZE(buffer
);
1368 *lpreturned
= numentries
;
1369 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1373 /******************************************************************
1374 * enumerate the local Ports from all loaded monitors (internal)
1376 * returns the needed size (in bytes) for pPorts
1377 * and *lpreturned is set to number of entries returned in pPorts
1380 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1384 LPPORT_INFO_2W cache
;
1386 LPBYTE pi_buffer
= NULL
;
1387 DWORD pi_allocated
= 0;
1397 TRACE("(%ld, %p, %ld, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1398 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1400 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1401 needed
= entrysize
* numentries
;
1402 ptr
= (LPWSTR
) &pPorts
[needed
];
1407 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1409 if (pm
->monitor
.pfnEnumPorts
) {
1412 res
= pm
->monitor
.pfnEnumPorts(pm
->hmon
, NULL
, level
, pi_buffer
,
1413 pi_allocated
, &pi_needed
, &pi_returned
);
1414 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1415 /* Do not use realloc (we do not need the old data in the buffer) */
1417 pi_buffer
= malloc(pi_needed
);
1418 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1419 res
= pm
->monitor
.pfnEnumPorts(pm
->hmon
, NULL
, level
,
1420 pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1422 TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n",
1423 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1425 numentries
+= pi_returned
;
1426 needed
+= pi_needed
;
1428 /* fill the output-buffer (pPorts), if we have one */
1429 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1431 while (pi_returned
> pi_index
) {
1432 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1433 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1434 out
->pPortName
= ptr
;
1435 lstrcpyW(ptr
, cache
->pPortName
);
1436 ptr
+= (wcslen(ptr
)+1);
1438 out
->pMonitorName
= ptr
;
1439 lstrcpyW(ptr
, cache
->pMonitorName
);
1440 ptr
+= (wcslen(ptr
)+1);
1442 out
->pDescription
= ptr
;
1443 lstrcpyW(ptr
, cache
->pDescription
);
1444 ptr
+= (wcslen(ptr
)+1);
1445 out
->fPortType
= cache
->fPortType
;
1446 out
->Reserved
= cache
->Reserved
;
1454 /* the temporary portinfo-buffer is no longer needed */
1457 *lpreturned
= numentries
;
1458 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1463 /*****************************************************************************
1464 * open_driver_reg [internal]
1466 * opens the registry for the printer drivers depending on the given input
1467 * variable pEnvironment
1470 * Success: the opened hkey
1473 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1477 const printenv_t
* env
;
1479 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1481 env
= validate_envW(pEnvironment
);
1482 if (!env
) return NULL
;
1484 buffer
= malloc(sizeof(fmt_driversW
) +
1485 (wcslen(env
->envname
) + wcslen(env
->versionregpath
)) * sizeof(WCHAR
));
1488 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1489 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1495 /*****************************************************************************
1496 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1498 * Return the PATH for the Printer-Drivers
1501 * pName [I] Servername (NT only) or NULL (local Computer)
1502 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1503 * Level [I] Structure-Level (must be 1)
1504 * pDriverDirectory [O] PTR to Buffer that receives the Result
1505 * cbBuf [I] Size of Buffer at pDriverDirectory
1506 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1507 * required for pDriverDirectory
1510 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1511 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1512 * if cbBuf is too small
1514 * Native Values returned in pDriverDirectory on Success:
1515 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1516 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1517 *| win9x(Windows 4.0): "%winsysdir%"
1519 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1522 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1523 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1526 const printenv_t
* env
;
1527 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1529 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
1530 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1532 if (pName
!= NULL
&& pName
[0]) {
1533 FIXME("server %s not supported\n", debugstr_w(pName
));
1534 SetLastError(ERROR_INVALID_PARAMETER
);
1538 env
= validate_envW(pEnvironment
);
1539 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1542 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1543 needed
= GetSystemDirectoryW(NULL
, 0);
1544 /* add the Size for the Subdirectories */
1545 needed
+= wcslen(L
"\\spool");
1546 needed
+= wcslen(L
"\\drivers\\");
1547 needed
+= wcslen(env
->subdir
);
1548 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1550 *pcbNeeded
= needed
;
1552 if (needed
> cbBuf
) {
1553 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1558 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1559 SetLastError(ERROR_INVALID_USER_BUFFER
);
1563 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1564 /* add the Subdirectories */
1565 lstrcatW( dir
, L
"\\spool" );
1566 CreateDirectoryW( dir
, NULL
);
1567 lstrcatW( dir
, L
"\\drivers\\" );
1568 CreateDirectoryW( dir
, NULL
);
1569 lstrcatW( dir
, env
->subdir
);
1570 CreateDirectoryW( dir
, NULL
);
1572 TRACE( "=> %s\n", debugstr_w( dir
) );
1576 /******************************************************************
1577 * driver_load [internal]
1579 * load a driver user interface dll
1581 * On failure, NULL is returned
1585 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1587 WCHAR fullname
[MAX_PATH
];
1591 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1593 /* build the driverdir */
1594 len
= sizeof(fullname
) -
1595 (wcslen(env
->versionsubdir
) + 1 + wcslen(dllname
) + 1) * sizeof(WCHAR
);
1597 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1598 (LPBYTE
) fullname
, len
, &len
)) {
1599 /* Should never fail */
1600 SetLastError(ERROR_BUFFER_OVERFLOW
);
1604 lstrcatW(fullname
, env
->versionsubdir
);
1605 lstrcatW(fullname
, L
"\\");
1606 lstrcatW(fullname
, dllname
);
1608 hui
= LoadLibraryW(fullname
);
1609 TRACE("%p: LoadLibrary(%s) %ld\n", hui
, debugstr_w(fullname
), GetLastError());
1614 static job_info_t
* get_job(printer_info_t
*info
, DWORD job_id
)
1618 LIST_FOR_EACH_ENTRY(job
, &info
->jobs
, job_info_t
, entry
)
1620 if(job
->id
== job_id
)
1626 static HANDLE
server_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1630 *stop_search
= FALSE
;
1634 server
= malloc(sizeof(*server
));
1637 *stop_search
= TRUE
;
1640 server
->type
= HANDLE_SERVER
;
1641 return (HANDLE
)server
;
1644 static HANDLE
xcv_alloc_handle(const WCHAR
*name
, PRINTER_DEFAULTSW
*def
, BOOL
*stop_search
)
1646 static const WCHAR xcv_monitor
[] = L
"XcvMonitor ";
1647 static const WCHAR xcv_port
[] = L
"XcvPort ";
1651 *stop_search
= FALSE
;
1656 while (*name
== ' ')
1659 mon
= !wcsncmp(name
, xcv_monitor
, ARRAY_SIZE(xcv_monitor
) - 1);
1662 name
+= ARRAY_SIZE(xcv_monitor
) - 1;
1666 port
= !wcsncmp(name
, xcv_port
, ARRAY_SIZE(xcv_port
) - 1);
1667 name
+= ARRAY_SIZE(xcv_port
) - 1;
1672 *stop_search
= TRUE
;
1673 xcv
= calloc(1, sizeof(*xcv
));
1676 xcv
->header
.type
= HANDLE_XCV
;
1679 xcv
->pm
= monitor_load(name
, NULL
);
1681 xcv
->pm
= monitor_load_by_port(name
);
1685 SetLastError(ERROR_UNKNOWN_PORT
);
1689 if (xcv
->pm
->monitor
.pfnXcvOpenPort
)
1691 xcv
->pm
->monitor
.pfnXcvOpenPort(xcv
->pm
->hmon
, name
,
1692 def
? def
->DesiredAccess
: 0, &xcv
->hxcv
);
1696 fpClosePrinter((HANDLE
)xcv
);
1697 SetLastError(ERROR_INVALID_PARAMETER
);
1703 static HANDLE
port_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1705 static const WCHAR portW
[] = L
"Port";
1707 unsigned int i
, name_len
;
1711 *stop_search
= FALSE
;
1712 for (name_len
= 0; name
[name_len
] != ','; name_len
++)
1714 if (!name
[name_len
])
1718 for (i
= name_len
+ 1; name
[i
] == ' '; i
++);
1719 if (wcscmp(name
+ i
, portW
))
1722 *stop_search
= TRUE
;
1723 port_name
= malloc((name_len
+ 1) * sizeof(WCHAR
));
1726 memcpy(port_name
, name
, name_len
* sizeof(WCHAR
));
1727 port_name
[name_len
] = 0;
1729 port
= calloc(1, sizeof(*port
));
1735 port
->header
.type
= HANDLE_PORT
;
1737 port
->mon
= monitor_load_by_port(port_name
);
1744 if (!port
->mon
->monitor
.pfnOpenPort
|| !port
->mon
->monitor
.pfnWritePort
1745 || !port
->mon
->monitor
.pfnClosePort
|| !port
->mon
->monitor
.pfnStartDocPort
1746 || !port
->mon
->monitor
.pfnEndDocPort
)
1748 FIXME("port not supported: %s\n", debugstr_w(name
));
1750 fpClosePrinter((HANDLE
)port
);
1754 port
->mon
->monitor
.pfnOpenPort(port
->mon
->hmon
, port_name
, &port
->hport
);
1758 fpClosePrinter((HANDLE
)port
);
1761 return (HANDLE
)port
;
1764 static HANDLE
job_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1766 static const WCHAR jobW
[] = L
"Job ";
1768 unsigned int name_len
, job_id
;
1769 printer_info_t
*printer_info
;
1770 job_info_t
*job_info
;
1773 *stop_search
= FALSE
;
1774 for (name_len
= 0; name
[name_len
] != ','; name_len
++)
1776 if (!name
[name_len
])
1780 for (job_id
= name_len
+ 1; name
[job_id
] == ' '; job_id
++);
1784 if (wcsncmp(name
+ job_id
, jobW
, ARRAY_SIZE(jobW
) - 1))
1787 *stop_search
= TRUE
;
1788 job_id
+= ARRAY_SIZE(jobW
) - 1;
1789 job_id
= wcstoul(name
+ job_id
, NULL
, 10);
1791 printer_info
= find_printer_info(name
, name_len
);
1794 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1798 EnterCriticalSection(&printer_info
->jobs_cs
);
1800 job_info
= get_job(printer_info
, job_id
);
1803 LeaveCriticalSection(&printer_info
->jobs_cs
);
1804 release_printer_info(printer_info
);
1805 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1809 job
= malloc(sizeof(*job
));
1812 LeaveCriticalSection(&printer_info
->jobs_cs
);
1813 release_printer_info(printer_info
);
1816 job
->header
.type
= HANDLE_JOB
;
1817 job
->hf
= CreateFileW(job_info
->filename
, GENERIC_READ
,
1818 FILE_SHARE_WRITE
| FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1819 NULL
, OPEN_EXISTING
, 0, NULL
);
1821 LeaveCriticalSection(&printer_info
->jobs_cs
);
1822 release_printer_info(printer_info
);
1824 if (job
->hf
== INVALID_HANDLE_VALUE
)
1832 static HANDLE
printer_alloc_handle(const WCHAR
*name
, const WCHAR
*basename
,
1833 PRINTER_DEFAULTSW
*def
)
1837 printer
= calloc(1, sizeof(*printer
));
1840 printer
->header
.type
= HANDLE_PRINTER
;
1842 /* clone the full name */
1843 printer
->name
= wcsdup(name
);
1844 if (name
&& !printer
->name
)
1846 fpClosePrinter((HANDLE
)printer
);
1850 printer
->info
= get_printer_info(basename
);
1853 fpClosePrinter((HANDLE
)printer
);
1854 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1858 if (def
&& def
->pDatatype
)
1859 printer
->datatype
= wcsdup(def
->pDatatype
);
1860 if (def
&& def
->pDevMode
)
1861 printer
->devmode
= dup_devmode(def
->pDevMode
);
1863 return (HANDLE
)printer
;
1866 static inline WCHAR
*get_file_part( WCHAR
*name
)
1868 WCHAR
*ptr
= wcsrchr( name
, '\\' );
1869 if (ptr
) return ptr
+ 1;
1873 /******************************************************************************
1874 * myAddPrinterDriverEx [internal]
1876 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1877 * and a special mode with lazy error checking.
1880 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1882 const printenv_t
*env
;
1885 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1895 /* we need to set all entries in the Registry, independent from the Level of
1896 DRIVER_INFO, that the caller supplied */
1898 ZeroMemory(&di
, sizeof(di
));
1899 if (pDriverInfo
&& (level
< ARRAY_SIZE(di_sizeof
))) {
1900 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1903 /* dump the most used infos */
1904 TRACE("%p: .cVersion : 0x%lx/%ld\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1905 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1906 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1907 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1908 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1909 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1910 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1911 /* dump only the first of the additional Files */
1912 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1915 /* check environment */
1916 env
= validate_envW(di
.pEnvironment
);
1917 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1919 /* fill the copy-data / get the driverdir */
1920 len
= sizeof(apd
.src
) - sizeof(L
"\\3") - sizeof(WCHAR
);
1921 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1922 (LPBYTE
) apd
.src
, len
, &len
)) {
1923 /* Should never fail */
1926 memcpy(apd
.dst
, apd
.src
, len
);
1927 lstrcatW(apd
.src
, L
"\\");
1928 apd
.srclen
= wcslen(apd
.src
);
1929 lstrcatW(apd
.dst
, env
->versionsubdir
);
1930 lstrcatW(apd
.dst
, L
"\\");
1931 apd
.dstlen
= wcslen(apd
.dst
);
1932 apd
.copyflags
= dwFileCopyFlags
;
1934 CreateDirectoryW(apd
.src
, NULL
);
1935 CreateDirectoryW(apd
.dst
, NULL
);
1937 hroot
= open_driver_reg(env
->envname
);
1939 ERR("Can't create Drivers key\n");
1943 /* Fill the Registry for the Driver */
1944 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1945 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1946 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1948 ERR("can't create driver %s: %lu\n", debugstr_w(di
.pName
), lres
);
1955 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1956 RegSetValueExW(hdrv
, L
"Version", 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1959 file
= get_file_part( di
.pDriverPath
);
1960 RegSetValueExW( hdrv
, L
"Driver", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1961 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1963 file
= get_file_part( di
.pDataFile
);
1964 RegSetValueExW( hdrv
, L
"Data File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1965 apd_copyfile( di
.pDataFile
, file
, &apd
);
1967 file
= get_file_part( di
.pConfigFile
);
1968 RegSetValueExW( hdrv
, L
"Configuration File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1969 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1971 /* settings for level 3 */
1974 file
= get_file_part( di
.pHelpFile
);
1975 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1976 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1979 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
"") );
1981 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1983 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1984 reg
= reg_ptr
= malloc( multi_sz_lenW( di
.pDependentFiles
) );
1986 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= wcslen( in_ptr
) + 1)
1988 file
= get_file_part( in_ptr
);
1989 len
= wcslen( file
) + 1;
1990 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1992 apd_copyfile( in_ptr
, file
, &apd
);
1996 RegSetValueExW( hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (BYTE
*)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
2000 RegSetValueExW(hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2002 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
2003 if (di
.pMonitorName
)
2004 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (BYTE
*)di
.pMonitorName
,
2005 (wcslen(di
.pMonitorName
)+1)* sizeof(WCHAR
));
2007 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2009 if (di
.pDefaultDataType
)
2010 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (BYTE
*)di
.pDefaultDataType
,
2011 (wcslen(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
2013 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2015 /* settings for level 4 */
2016 if (di
.pszzPreviousNames
)
2017 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (BYTE
*)di
.pszzPreviousNames
,
2018 multi_sz_lenW(di
.pszzPreviousNames
));
2020 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2022 if (level
> 5) TRACE("level %lu for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
2025 hui
= driver_load(env
, di
.pConfigFile
);
2026 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
2027 if (hui
&& pDrvDriverEvent
) {
2029 /* Support for DrvDriverEvent is optional */
2030 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
2031 /* MSDN: level for DRIVER_INFO is 1 to 3 */
2032 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
2033 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
2037 TRACE("=> TRUE with %lu\n", GetLastError());
2042 /******************************************************************************
2043 * fpAddMonitor [exported through PRINTPROVIDOR]
2045 * Install a Printmonitor
2048 * pName [I] Servername or NULL (local Computer)
2049 * Level [I] Structure-Level (Must be 2)
2050 * pMonitors [I] PTR to MONITOR_INFO_2
2057 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2060 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2062 const printenv_t
* env
;
2063 monitor_t
* pm
= NULL
;
2064 LPMONITOR_INFO_2W mi2w
;
2070 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2071 TRACE("(%s, %ld, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2072 debugstr_w(mi2w
->pName
), debugstr_w(mi2w
->pEnvironment
), debugstr_w(mi2w
->pDLLName
));
2074 if (copy_servername_from_name(pName
, NULL
)) {
2075 FIXME("server %s not supported\n", debugstr_w(pName
));
2076 SetLastError(ERROR_ACCESS_DENIED
);
2080 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2081 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2082 SetLastError(ERROR_INVALID_PARAMETER
);
2086 env
= validate_envW(mi2w
->pEnvironment
);
2088 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2090 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2091 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2092 SetLastError(ERROR_INVALID_PARAMETER
);
2096 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2097 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2101 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2102 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2103 &disposition
) == ERROR_SUCCESS
) {
2105 /* Some installers set options for the port before calling AddMonitor.
2106 We query the "Driver" entry to verify that the monitor is installed,
2107 before we return an error.
2108 When a user installs two print monitors at the same time with the
2109 same name, a race condition is possible but silently ignored. */
2113 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2114 (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, NULL
,
2115 &namesize
) == ERROR_SUCCESS
)) {
2116 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2117 /* 9x use ERROR_ALREADY_EXISTS */
2118 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2123 len
= (wcslen(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2124 res
= (RegSetValueExW(hentry
, L
"Driver", 0, REG_SZ
,
2125 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2127 /* Load and initialize the monitor. SetLastError() is called on failure */
2128 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
)
2130 RegDeleteKeyW(hroot
, mi2w
->pName
);
2134 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
2137 RegCloseKey(hentry
);
2144 /******************************************************************************
2145 * fpAddPort [exported through PRINTPROVIDOR]
2147 * Add a Port for a specific Monitor
2150 * pName [I] Servername or NULL (local Computer)
2151 * hWnd [I] Handle to parent Window for the Dialog-Box
2152 * pMonitorName [I] Name of the Monitor that manage the Port
2159 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
2166 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
2168 lres
= copy_servername_from_name(pName
, NULL
);
2170 FIXME("server %s not supported\n", debugstr_w(pName
));
2171 SetLastError(ERROR_INVALID_PARAMETER
);
2175 /* an empty Monitorname is Invalid */
2176 if (!pMonitorName
[0]) {
2177 SetLastError(ERROR_NOT_SUPPORTED
);
2181 pm
= monitor_load(pMonitorName
, NULL
);
2182 if (pm
&& pm
->monitor
.pfnAddPort
) {
2183 res
= pm
->monitor
.pfnAddPort(pm
->hmon
, pName
, hWnd
, pMonitorName
);
2184 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
2188 pui
= monitor_loadui(pm
);
2189 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
2190 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
2191 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
2195 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2196 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2197 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2199 SetLastError(ERROR_NOT_SUPPORTED
);
2202 monitor_unload(pui
);
2206 TRACE("returning %ld with %lu\n", res
, GetLastError());
2210 /******************************************************************************
2211 * fpAddPortEx [exported through PRINTPROVIDOR]
2213 * Add a Port for a specific Monitor, without presenting a user interface
2216 * pName [I] Servername or NULL (local Computer)
2217 * level [I] Structure-Level (1 or 2) for pBuffer
2218 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
2219 * pMonitorName [I] Name of the Monitor that manage the Port
2226 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
2233 pi2
= (PORT_INFO_2W
*) pBuffer
;
2235 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
2236 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
2237 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
2238 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
2240 lres
= copy_servername_from_name(pName
, NULL
);
2242 FIXME("server %s not supported\n", debugstr_w(pName
));
2243 SetLastError(ERROR_INVALID_PARAMETER
);
2247 if ((level
< 1) || (level
> 2)) {
2248 SetLastError(ERROR_INVALID_LEVEL
);
2252 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
2253 SetLastError(ERROR_INVALID_PARAMETER
);
2257 /* load the Monitor */
2258 pm
= monitor_load(pMonitorName
, NULL
);
2259 if (pm
&& pm
->monitor
.pfnAddPortEx
)
2261 res
= pm
->monitor
.pfnAddPortEx(pm
->hmon
, pName
, level
, pBuffer
, pMonitorName
);
2262 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
2266 FIXME("not implemented for %s (monitor %p: %s)\n",
2267 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
2268 SetLastError(ERROR_INVALID_PARAMETER
);
2275 /******************************************************************************
2276 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
2278 * Install a Printer Driver with the Option to upgrade / downgrade the Files
2281 * pName [I] Servername or NULL (local Computer)
2282 * level [I] Level for the supplied DRIVER_INFO_*W struct
2283 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
2284 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
2291 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
2295 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
2296 lres
= copy_servername_from_name(pName
, NULL
);
2298 FIXME("server %s not supported\n", debugstr_w(pName
));
2299 SetLastError(ERROR_ACCESS_DENIED
);
2303 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
2304 TRACE("Flags 0x%lx ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
2307 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
2310 /******************************************************************************
2311 * fpConfigurePort [exported through PRINTPROVIDOR]
2313 * Display the Configuration-Dialog for a specific Port
2316 * pName [I] Servername or NULL (local Computer)
2317 * hWnd [I] Handle to parent Window for the Dialog-Box
2318 * pPortName [I] Name of the Port, that should be configured
2325 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2332 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2334 lres
= copy_servername_from_name(pName
, NULL
);
2336 FIXME("server %s not supported\n", debugstr_w(pName
));
2337 SetLastError(ERROR_INVALID_NAME
);
2341 /* an empty Portname is Invalid, but can popup a Dialog */
2342 if (!pPortName
[0]) {
2343 SetLastError(ERROR_NOT_SUPPORTED
);
2347 pm
= monitor_load_by_port(pPortName
);
2348 if (pm
&& pm
->monitor
.pfnConfigurePort
)
2350 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2351 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2352 res
= pm
->monitor
.pfnConfigurePort(pm
->hmon
, pName
, hWnd
, pPortName
);
2353 TRACE("got %ld with %lu\n", res
, GetLastError());
2357 pui
= monitor_loadui(pm
);
2358 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
2359 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2360 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2361 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
2362 TRACE("got %ld with %lu\n", res
, GetLastError());
2366 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2367 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2368 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2370 SetLastError(ERROR_NOT_SUPPORTED
);
2373 monitor_unload(pui
);
2377 TRACE("returning %ld with %lu\n", res
, GetLastError());
2381 /******************************************************************
2382 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2384 * Delete a specific Printmonitor from a Printing-Environment
2387 * pName [I] Servername or NULL (local Computer)
2388 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2389 * pMonitorName [I] Name of the Monitor, that should be deleted
2396 * pEnvironment is ignored in Windows for the local Computer.
2400 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2406 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2407 debugstr_w(pMonitorName
));
2409 lres
= copy_servername_from_name(pName
, NULL
);
2411 FIXME("server %s not supported\n", debugstr_w(pName
));
2412 SetLastError(ERROR_INVALID_NAME
);
2416 /* pEnvironment is ignored in Windows for the local Computer */
2417 if (!pMonitorName
|| !pMonitorName
[0]) {
2418 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2419 SetLastError(ERROR_INVALID_PARAMETER
);
2423 /* Unload the monitor if it's loaded */
2424 EnterCriticalSection(&monitor_handles_cs
);
2425 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
2427 if (pm
->name
&& !lstrcmpW(pMonitorName
, pm
->name
))
2433 LeaveCriticalSection(&monitor_handles_cs
);
2435 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2436 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2440 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2441 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
2446 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
2449 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2450 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2454 /*****************************************************************************
2455 * fpDeletePort [exported through PRINTPROVIDOR]
2457 * Delete a specific Port
2460 * pName [I] Servername or NULL (local Computer)
2461 * hWnd [I] Handle to parent Window for the Dialog-Box
2462 * pPortName [I] Name of the Port, that should be deleted
2469 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2476 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2478 lres
= copy_servername_from_name(pName
, NULL
);
2480 FIXME("server %s not supported\n", debugstr_w(pName
));
2481 SetLastError(ERROR_INVALID_NAME
);
2485 /* an empty Portname is Invalid */
2486 if (!pPortName
[0]) {
2487 SetLastError(ERROR_NOT_SUPPORTED
);
2491 pm
= monitor_load_by_port(pPortName
);
2492 if (pm
&& pm
->monitor
.pfnDeletePort
)
2494 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2495 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2496 res
= pm
->monitor
.pfnDeletePort(pm
->hmon
, pName
, hWnd
, pPortName
);
2497 TRACE("got %ld with %lu\n", res
, GetLastError());
2501 pui
= monitor_loadui(pm
);
2502 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2503 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2504 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2505 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2506 TRACE("got %ld with %lu\n", res
, GetLastError());
2510 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2511 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2512 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2514 SetLastError(ERROR_NOT_SUPPORTED
);
2517 monitor_unload(pui
);
2521 TRACE("returning %ld with %lu\n", res
, GetLastError());
2525 /*****************************************************************************
2526 * fpEnumMonitors [exported through PRINTPROVIDOR]
2528 * Enumerate available Port-Monitors
2531 * pName [I] Servername or NULL (local Computer)
2532 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2533 * pMonitors [O] PTR to Buffer that receives the Result
2534 * cbBuf [I] Size of Buffer at pMonitors
2535 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2536 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2540 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2543 * Windows reads the Registry once and cache the Results.
2546 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
2547 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2549 DWORD numentries
= 0;
2554 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
2555 cbBuf
, pcbNeeded
, pcReturned
);
2557 lres
= copy_servername_from_name(pName
, NULL
);
2559 FIXME("server %s not supported\n", debugstr_w(pName
));
2560 SetLastError(ERROR_INVALID_NAME
);
2564 if (!Level
|| (Level
> 2)) {
2565 WARN("level (%ld) is ignored in win9x\n", Level
);
2566 SetLastError(ERROR_INVALID_LEVEL
);
2570 /* Scan all Monitor-Keys */
2572 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
2574 /* we calculated the needed buffersize. now do more error-checks */
2575 if (cbBuf
< needed
) {
2576 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2580 /* fill the Buffer with the Monitor-Keys */
2581 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2585 if (pcbNeeded
) *pcbNeeded
= needed
;
2586 if (pcReturned
) *pcReturned
= numentries
;
2588 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2589 res
, GetLastError(), needed
, numentries
);
2594 /******************************************************************************
2595 * fpEnumPorts [exported through PRINTPROVIDOR]
2597 * Enumerate available Ports
2600 * pName [I] Servername or NULL (local Computer)
2601 * Level [I] Structure-Level (1 or 2)
2602 * pPorts [O] PTR to Buffer that receives the Result
2603 * cbBuf [I] Size of Buffer at pPorts
2604 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2605 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2609 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2612 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2613 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2616 DWORD numentries
= 0;
2620 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2621 cbBuf
, pcbNeeded
, pcReturned
);
2623 lres
= copy_servername_from_name(pName
, NULL
);
2625 FIXME("server %s not supported\n", debugstr_w(pName
));
2626 SetLastError(ERROR_INVALID_NAME
);
2630 if (!Level
|| (Level
> 2)) {
2631 SetLastError(ERROR_INVALID_LEVEL
);
2635 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2636 SetLastError(RPC_X_NULL_REF_POINTER
);
2640 EnterCriticalSection(&monitor_handles_cs
);
2643 /* Scan all local Ports */
2645 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2647 /* we calculated the needed buffersize. now do the error-checks */
2648 if (cbBuf
< needed
) {
2649 monitor_unloadall();
2650 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2651 goto emP_cleanup_cs
;
2653 else if (!pPorts
|| !pcReturned
) {
2654 monitor_unloadall();
2655 SetLastError(RPC_X_NULL_REF_POINTER
);
2656 goto emP_cleanup_cs
;
2659 /* Fill the Buffer */
2660 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2662 monitor_unloadall();
2665 LeaveCriticalSection(&monitor_handles_cs
);
2668 if (pcbNeeded
) *pcbNeeded
= needed
;
2669 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2671 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
2672 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2677 static BOOL WINAPI
fpAddPrintProcessor(WCHAR
*name
, WCHAR
*environment
, WCHAR
*path
,
2680 const printenv_t
* env
;
2685 TRACE("(%s, %s, %s, %s)\n", debugstr_w(name
), debugstr_w(environment
),
2686 debugstr_w(path
), debugstr_w(print_proc
));
2688 if (!path
|| !print_proc
)
2690 SetLastError(ERROR_INVALID_PARAMETER
);
2694 if (name
&& name
[0])
2696 FIXME("server %s not supported\n", debugstr_w(name
));
2697 SetLastError(ERROR_INVALID_NAME
);
2701 env
= validate_envW(environment
);
2705 regpath
= malloc(sizeof(fmt_printprocessorsW
) +
2706 wcslen(env
->envname
) * sizeof(WCHAR
));
2709 wsprintfW(regpath
, fmt_printprocessorsW
, env
->envname
);
2711 s
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpath
, &hroot
);
2715 s
= RegSetKeyValueW(hroot
, print_proc
, L
"Driver", REG_SZ
, path
,
2716 (wcslen(path
) + 1) * sizeof(WCHAR
));
2728 /*****************************************************************************
2729 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2731 * Enumerate available Print Processors
2734 * pName [I] Servername or NULL (local Computer)
2735 * pEnvironment [I] Printing-Environment or NULL (Default)
2736 * Level [I] Structure-Level (Only 1 is allowed)
2737 * pPPInfo [O] PTR to Buffer that receives the Result
2738 * cbBuf [I] Size of Buffer at pMonitors
2739 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2740 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2744 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2747 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2748 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2750 const printenv_t
* env
;
2751 LPWSTR regpathW
= NULL
;
2752 DWORD numentries
= 0;
2757 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2758 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2760 lres
= copy_servername_from_name(pName
, NULL
);
2762 FIXME("server %s not supported\n", debugstr_w(pName
));
2763 SetLastError(ERROR_INVALID_NAME
);
2768 SetLastError(ERROR_INVALID_LEVEL
);
2772 env
= validate_envW(pEnvironment
);
2774 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2776 regpathW
= malloc(sizeof(fmt_printprocessorsW
) +
2777 (wcslen(env
->envname
) * sizeof(WCHAR
)));
2782 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2784 /* Scan all Printprocessor-Keys */
2786 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2788 /* we calculated the needed buffersize. now do more error-checks */
2789 if (cbBuf
< needed
) {
2790 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2794 /* fill the Buffer with the Printprocessor Infos */
2795 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2800 if (pcbNeeded
) *pcbNeeded
= needed
;
2801 if (pcReturned
) *pcReturned
= numentries
;
2803 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2804 res
, GetLastError(), needed
, numentries
);
2809 /******************************************************************************
2810 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2812 * Return the PATH for the Print-Processors
2815 * pName [I] Servername or NULL (this computer)
2816 * pEnvironment [I] Printing-Environment or NULL (Default)
2817 * level [I] Structure-Level (must be 1)
2818 * pPPInfo [O] PTR to Buffer that receives the Result
2819 * cbBuf [I] Size of Buffer at pPPInfo
2820 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2824 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2826 * Native Values returned in pPPInfo on Success for this computer:
2827 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2828 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2829 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2831 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2834 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2835 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2837 const printenv_t
* env
;
2841 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2842 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2845 lres
= copy_servername_from_name(pName
, NULL
);
2847 FIXME("server %s not supported\n", debugstr_w(pName
));
2848 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2852 env
= validate_envW(pEnvironment
);
2854 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2856 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2857 needed
= GetSystemDirectoryW(NULL
, 0);
2858 /* add the Size for the Subdirectories */
2859 needed
+= wcslen(L
"\\spool\\prtprocs\\");
2860 needed
+= wcslen(env
->subdir
);
2861 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2863 *pcbNeeded
= needed
;
2865 if (needed
> cbBuf
) {
2866 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2870 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2871 /* add the Subdirectories */
2872 lstrcatW((LPWSTR
) pPPInfo
, L
"\\spool\\prtprocs\\");
2873 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2874 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2878 /******************************************************************************
2879 * fpOpenPrinter [exported through PRINTPROVIDOR]
2881 * Open a Printer / Printserver or a Printer-Object
2884 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2885 * pPrinter [O] The resulting Handle is stored here
2886 * pDefaults [I] PTR to Default Printer Settings or NULL
2893 * lpPrinterName is one of:
2894 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2895 *| Printer: "PrinterName"
2896 *| Printer-Object: "PrinterName,Job xxx"
2897 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2898 *| XcvPort: "Servername,XcvPort PortName"
2902 static BOOL WINAPI
fpOpenPrinter(WCHAR
*name
, HANDLE
*hprinter
,
2903 PRINTER_DEFAULTSW
*def
)
2905 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
2906 const WCHAR
*basename
;
2909 TRACE("(%s, %p, %p)\n", debugstr_w(name
), hprinter
, def
);
2911 if (copy_servername_from_name(name
, servername
))
2913 FIXME("server %s not supported\n", debugstr_w(servername
));
2914 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2918 basename
= get_basename_from_name(name
);
2919 if (name
!= basename
) TRACE("converted %s to %s\n",
2920 debugstr_w(name
), debugstr_w(basename
));
2922 /* an empty basename is invalid */
2923 if (basename
&& (!basename
[0]))
2925 SetLastError(ERROR_INVALID_PARAMETER
);
2929 *hprinter
= server_alloc_handle(basename
, &stop_search
);
2930 if (!*hprinter
&& !stop_search
)
2931 *hprinter
= xcv_alloc_handle(basename
, def
, &stop_search
);
2932 if (!*hprinter
&& !stop_search
)
2933 *hprinter
= port_alloc_handle(basename
, &stop_search
);
2934 if (!*hprinter
&& !stop_search
)
2935 *hprinter
= job_alloc_handle(basename
, &stop_search
);
2936 if (!*hprinter
&& !stop_search
)
2937 *hprinter
= printer_alloc_handle(name
, basename
, def
);
2939 TRACE("==> %p\n", *hprinter
);
2940 return *hprinter
!= 0;
2943 /******************************************************************************
2944 * fpXcvData [exported through PRINTPROVIDOR]
2946 * Execute commands in the Printmonitor DLL
2949 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2950 * pszDataName [i] Name of the command to execute
2951 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2952 * cbInputData [i] Size in Bytes of Buffer at pInputData
2953 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2954 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2955 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2956 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2963 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2964 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2966 * Minimal List of commands, that a Printmonitor DLL should support:
2968 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2969 *| "AddPort" : Add a Port
2970 *| "DeletePort": Delete a Port
2972 * Many Printmonitors support additional commands. Examples for localspl.dll:
2973 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2974 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2977 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2978 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2979 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2981 xcv_t
*xcv
= (xcv_t
*)hXcv
;
2983 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2984 pInputData
, cbInputData
, pOutputData
,
2985 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2987 if (!xcv
|| xcv
->header
.type
!= HANDLE_XCV
) {
2988 SetLastError(ERROR_INVALID_HANDLE
);
2992 if (!pcbOutputNeeded
) {
2993 SetLastError(ERROR_INVALID_PARAMETER
);
2997 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2998 SetLastError(RPC_X_NULL_REF_POINTER
);
3002 *pcbOutputNeeded
= 0;
3004 if (xcv
->pm
->monitor
.pfnXcvDataPort
)
3005 *pdwStatus
= xcv
->pm
->monitor
.pfnXcvDataPort(xcv
->hxcv
, pszDataName
,
3006 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
3011 static inline size_t form_struct_size( DWORD level
)
3013 if (level
== 1) return sizeof(FORM_INFO_1W
);
3014 if (level
== 2) return sizeof(FORM_INFO_2W
);
3016 SetLastError( ERROR_INVALID_LEVEL
);
3020 static void fill_builtin_form_info( BYTE
**base
, WCHAR
**strings
, const struct builtin_form
*form
, DWORD level
,
3021 DWORD size
, DWORD
*used
)
3023 FORM_INFO_2W
*info
= *(FORM_INFO_2W
**)base
;
3024 DWORD name_len
= wcslen( form
->name
) + 1, res_len
= 0, keyword_len
, total_size
;
3025 static const WCHAR dll_name
[] = L
"localspl.dll";
3026 const WCHAR
*resource
;
3028 total_size
= name_len
* sizeof(WCHAR
);
3032 keyword_len
= WideCharToMultiByte( CP_ACP
, 0, form
->name
, -1, NULL
, 0, NULL
, NULL
);
3033 keyword_len
= (keyword_len
+ 1) & ~1;
3034 total_size
+= keyword_len
;
3035 res_len
= LoadStringW( localspl_instance
, form
->res_id
, (WCHAR
*)&resource
, 0 );
3036 if (res_len
&& resource
[res_len
- 1]) res_len
++;
3037 total_size
+= (res_len
+ ARRAY_SIZE(dll_name
)) * sizeof(WCHAR
);
3040 if (*used
+ total_size
<= size
)
3042 info
->Flags
= FORM_BUILTIN
;
3043 info
->pName
= memcpy( *strings
, form
->name
, name_len
* sizeof(WCHAR
) );
3044 *strings
+= name_len
;
3045 info
->Size
= form
->size
;
3046 info
->ImageableArea
.left
= info
->ImageableArea
.top
= 0;
3047 info
->ImageableArea
.right
= info
->Size
.cx
;
3048 info
->ImageableArea
.bottom
= info
->Size
.cy
;
3051 info
->pKeyword
= (char *)*strings
;
3052 WideCharToMultiByte( CP_ACP
, 0, form
->name
, -1, (char *)info
->pKeyword
, keyword_len
, NULL
, NULL
);
3053 *strings
+= keyword_len
/ sizeof(WCHAR
);
3054 info
->StringType
= STRING_MUIDLL
;
3055 info
->pMuiDll
= memcpy( *strings
, dll_name
, sizeof(dll_name
) );
3056 *strings
+= ARRAY_SIZE(dll_name
);
3057 info
->dwResourceId
= form
->res_id
;
3060 info
->StringType
|= STRING_LANGPAIR
;
3061 info
->pDisplayName
= memcpy( *strings
, resource
, (res_len
- 1) * sizeof(WCHAR
) );
3062 info
->pDisplayName
[res_len
- 1] = '\0';
3063 *strings
+= res_len
;
3064 info
->wLangId
= GetUserDefaultLangID();
3068 info
->pDisplayName
= NULL
;
3074 *base
+= form_struct_size( level
);
3075 *used
+= total_size
;
3078 static BOOL WINAPI
fpAddForm( HANDLE printer
, DWORD level
, BYTE
*form
)
3080 FIXME( "(%p, %ld, %p): stub\n", printer
, level
, form
);
3084 static BOOL WINAPI
fpDeleteForm( HANDLE printer
, WCHAR
*name
)
3086 FIXME( "(%p, %s): stub\n", printer
, debugstr_w( name
) );
3090 static BOOL WINAPI
fpGetForm( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3092 size_t struct_size
= form_struct_size( level
);
3093 const struct builtin_form
*builtin
= NULL
;
3094 WCHAR
*strings
= NULL
;
3098 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
, size
, needed
);
3102 if (!struct_size
) return FALSE
;
3104 for (i
= 0; i
< ARRAY_SIZE(builtin_forms
); i
++)
3106 if (!wcscmp( name
, builtin_forms
[i
].name
))
3108 builtin
= builtin_forms
+ i
;
3115 SetLastError( ERROR_INVALID_FORM_NAME
);
3119 *needed
= struct_size
;
3120 if (*needed
< size
) strings
= (WCHAR
*)(form
+ *needed
);
3122 fill_builtin_form_info( &base
, &strings
, builtin
, level
, size
, needed
);
3126 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
3132 static BOOL WINAPI
fpSetForm( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
)
3134 FIXME( "(%p, %s, %ld, %p): stub\n", printer
, debugstr_w( name
), level
, form
);
3138 static BOOL WINAPI
fpEnumForms( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
3140 DWORD num
= ARRAY_SIZE(builtin_forms
), i
;
3141 WCHAR
*strings
= NULL
;
3143 size_t struct_size
= form_struct_size( level
);
3145 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer
, level
, form
, size
, needed
, count
);
3147 *count
= *needed
= 0;
3149 if (!struct_size
) return FALSE
;
3151 *needed
= num
* struct_size
;
3152 if (*needed
< size
) strings
= (WCHAR
*)(form
+ *needed
);
3154 for (i
= 0; i
< ARRAY_SIZE(builtin_forms
); i
++)
3155 fill_builtin_form_info( &base
, &strings
, builtin_forms
+ i
, level
, size
, needed
);
3159 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
3167 static size_t get_spool_filename(DWORD job_id
, WCHAR
*buf
, size_t len
)
3169 static const WCHAR spool_path
[] = L
"spool\\PRINTERS\\";
3172 ret
= GetSystemDirectoryW(NULL
, 0) + ARRAY_SIZE(spool_path
) + 10;
3176 ret
= GetSystemDirectoryW(buf
, ret
);
3177 if (buf
[ret
- 1] != '\\')
3179 memcpy(buf
+ ret
, spool_path
, sizeof(spool_path
));
3180 ret
+= ARRAY_SIZE(spool_path
) - 1;
3181 swprintf(buf
+ ret
, 10, L
"%05d.SPL", job_id
);
3186 static job_info_t
* add_job(printer_t
*printer
, DOC_INFO_1W
*info
, BOOL create
)
3188 DWORD job_id
, last_id
;
3192 job
= calloc(1, sizeof(*job
));
3195 len
= get_spool_filename(0, NULL
, 0);
3196 job
->filename
= malloc(len
* sizeof(WCHAR
));
3202 job
->port
= wcsdup(info
->pOutputFile
);
3203 if (info
->pOutputFile
&& !job
->port
)
3205 free(job
->filename
);
3212 last_id
= last_job_id
;
3213 job_id
= last_id
< MAX_JOB_ID
? last_id
+ 1 : 1;
3214 if (InterlockedCompareExchange(&last_job_id
, job_id
, last_id
) == last_id
)
3219 get_spool_filename(job_id
, job
->filename
, len
);
3222 job
->hf
= CreateFileW(job
->filename
, GENERIC_WRITE
, FILE_SHARE_READ
,
3223 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3224 if (job
->hf
== INVALID_HANDLE_VALUE
)
3226 free(job
->filename
);
3235 job
->document_title
= wcsdup(info
->pDocName
);
3236 job
->datatype
= wcsdup(info
->pDatatype
);
3237 job
->devmode
= dup_devmode(printer
->devmode
);
3239 EnterCriticalSection(&printer
->info
->jobs_cs
);
3240 list_add_tail(&printer
->info
->jobs
, &job
->entry
);
3241 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3245 static BOOL WINAPI
fpAddJob(HANDLE hprinter
, DWORD level
, BYTE
*data
, DWORD size
, DWORD
*needed
)
3247 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*)data
;
3248 printer_t
*printer
= (printer_t
*)hprinter
;
3249 DOC_INFO_1W doc_info
;
3253 TRACE("(%p %ld %p %ld %p)\n", hprinter
, level
, data
, size
, needed
);
3255 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3257 SetLastError(ERROR_INVALID_HANDLE
);
3263 SetLastError(ERROR_INVALID_LEVEL
);
3269 SetLastError(ERROR_INVALID_PARAMETER
);
3273 len
= get_spool_filename(0, NULL
, 0);
3274 *needed
= sizeof(*addjob
) + len
* sizeof(WCHAR
);
3277 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3281 memset(&doc_info
, 0, sizeof(doc_info
));
3282 doc_info
.pDocName
= (WCHAR
*)L
"Local Downlevel Document";
3283 job
= add_job(printer
, &doc_info
, FALSE
);
3287 addjob
->JobId
= job
->id
;
3288 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
3289 memcpy(addjob
->Path
, job
->filename
, len
* sizeof(WCHAR
));
3296 BOOL (WINAPI
*enum_datatypes
)(WCHAR
*, WCHAR
*, DWORD
,
3297 BYTE
*, DWORD
, DWORD
*, DWORD
*);
3298 HANDLE (WINAPI
*open
)(WCHAR
*, PRINTPROCESSOROPENDATA
*);
3299 BOOL (WINAPI
*print
)(HANDLE
, WCHAR
*);
3300 BOOL (WINAPI
*close
)(HANDLE
);
3303 static printproc_t
* print_proc_load(const WCHAR
*name
)
3305 WCHAR
*reg_path
, path
[2 * MAX_PATH
];
3311 size
= sizeof(fmt_printprocessorsW
) +
3312 (wcslen(env_arch
.envname
) + wcslen(name
)) * sizeof(WCHAR
);
3313 reg_path
= malloc(size
);
3316 swprintf(reg_path
, size
/ sizeof(WCHAR
), fmt_printprocessorsW
, env_arch
.envname
);
3317 wcscat(reg_path
, name
);
3319 status
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, reg_path
, &hkey
);
3321 if (status
!= ERROR_SUCCESS
)
3324 if (!fpGetPrintProcessorDirectory(NULL
, NULL
, 1, (BYTE
*)path
, sizeof(path
), &size
))
3329 len
= size
/ sizeof(WCHAR
);
3330 path
[len
- 1] = '\\';
3332 size
= sizeof(path
) - len
* sizeof(WCHAR
);
3333 status
= RegQueryValueExW(hkey
, L
"Driver", NULL
, NULL
, (BYTE
*)(path
+ len
), &size
);
3335 if (status
!= ERROR_SUCCESS
)
3338 ret
= malloc(sizeof(*ret
));
3342 TRACE("loading print processor: %s\n", debugstr_w(path
));
3344 ret
->hmod
= LoadLibraryW(path
);
3351 ret
->enum_datatypes
= (void *)GetProcAddress(ret
->hmod
, "EnumPrintProcessorDatatypesW");
3352 ret
->open
= (void *)GetProcAddress(ret
->hmod
, "OpenPrintProcessor");
3353 ret
->print
= (void *)GetProcAddress(ret
->hmod
, "PrintDocumentOnPrintProcessor");
3354 ret
->close
= (void *)GetProcAddress(ret
->hmod
, "ClosePrintProcessor");
3355 if (!ret
->enum_datatypes
|| !ret
->open
|| !ret
->print
|| !ret
->close
)
3357 FreeLibrary(ret
->hmod
);
3362 ret
->name
= wcsdup(name
);
3366 static BOOL
print_proc_check_datatype(printproc_t
*pp
, const WCHAR
*datatype
)
3368 DATATYPES_INFO_1W
*types
;
3374 pp
->enum_datatypes(NULL
, pp
->name
, 1, NULL
, 0, &size
, &no
);
3375 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
3378 types
= malloc(size
);
3382 if (!pp
->enum_datatypes(NULL
, pp
->name
, 1, (BYTE
*)types
, size
, &size
, &no
))
3388 for (i
= 0; i
< no
; i
++)
3390 if (!wcscmp(types
[i
].pName
, datatype
))
3397 static void print_proc_unload(printproc_t
*pp
)
3399 FreeLibrary(pp
->hmod
);
3404 static DWORD WINAPI
fpStartDocPrinter(HANDLE hprinter
, DWORD level
, BYTE
*doc_info
)
3406 printer_t
*printer
= (printer_t
*)hprinter
;
3407 DOC_INFO_1W
*info
= (DOC_INFO_1W
*)doc_info
;
3408 BOOL datatype_valid
;
3412 TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n",
3413 hprinter
, level
, doc_info
, debugstr_w(info
->pDocName
),
3414 debugstr_w(info
->pOutputFile
), debugstr_w(info
->pDatatype
));
3418 SetLastError(ERROR_INVALID_HANDLE
);
3422 if (printer
->header
.type
== HANDLE_PORT
)
3424 port_t
*port
= (port_t
*)hprinter
;
3425 /* TODO: pass printer name and job_id */
3426 return port
->mon
->monitor
.pfnStartDocPort(port
->hport
,
3427 NULL
, 0, level
, doc_info
);
3430 if (printer
->header
.type
!= HANDLE_PRINTER
)
3432 SetLastError(ERROR_INVALID_HANDLE
);
3436 if (level
< 1 || level
> 3)
3438 SetLastError(ERROR_INVALID_LEVEL
);
3444 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3448 if (info
->pDatatype
)
3449 datatype
= info
->pDatatype
;
3450 else if (printer
->datatype
)
3451 datatype
= printer
->datatype
;
3453 datatype
= printer
->info
->datatype
;
3455 if (!datatype
|| ((printer
->info
->attributes
& PRINTER_ATTRIBUTE_RAW_ONLY
) &&
3456 wcsicmp(datatype
, L
"RAW")))
3458 TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype
));
3459 SetLastError(ERROR_INVALID_DATATYPE
);
3463 pp
= print_proc_load(printer
->info
->print_proc
);
3466 WARN("failed to load %s print processor\n", debugstr_w(printer
->info
->print_proc
));
3467 pp
= print_proc_load(L
"winprint");
3472 datatype_valid
= print_proc_check_datatype(pp
, datatype
);
3473 print_proc_unload(pp
);
3474 if (!datatype_valid
)
3476 TRACE("%s datatype not supported by %s\n", debugstr_w(datatype
),
3477 debugstr_w(printer
->info
->print_proc
));
3478 SetLastError(ERROR_INVALID_DATATYPE
);
3482 printer
->doc
= add_job(printer
, info
, TRUE
);
3483 return printer
->doc
? printer
->doc
->id
: 0;
3486 static BOOL WINAPI
fpWritePrinter(HANDLE hprinter
, void *buf
, DWORD size
, DWORD
*written
)
3488 handle_header_t
*header
= (handle_header_t
*)hprinter
;
3490 TRACE("(%p, %p, %ld, %p)\n", hprinter
, buf
, size
, written
);
3494 SetLastError(ERROR_INVALID_HANDLE
);
3498 if (header
->type
== HANDLE_PORT
)
3500 port_t
*port
= (port_t
*)hprinter
;
3502 return port
->mon
->monitor
.pfnWritePort(port
->hport
, buf
, size
, written
);
3505 if (header
->type
== HANDLE_PRINTER
)
3507 printer_t
*printer
= (printer_t
*)hprinter
;
3511 SetLastError(ERROR_SPL_NO_STARTDOC
);
3515 return WriteFile(printer
->doc
->hf
, buf
, size
, written
, NULL
);
3518 SetLastError(ERROR_INVALID_HANDLE
);
3522 static BOOL WINAPI
fpSetJob(HANDLE hprinter
, DWORD job_id
,
3523 DWORD level
, BYTE
*data
, DWORD command
)
3525 printer_t
*printer
= (printer_t
*)hprinter
;
3529 TRACE("(%p, %ld, %ld, %p, %ld)\n", hprinter
, job_id
, level
, data
, command
);
3530 FIXME("Ignoring everything other than document title\n");
3532 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3534 SetLastError(ERROR_INVALID_HANDLE
);
3538 EnterCriticalSection(&printer
->info
->jobs_cs
);
3539 job
= get_job(printer
->info
, job_id
);
3542 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3553 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)job
;
3554 WCHAR
*title
= wcsdup(info1
->pDocument
);
3558 free(job
->document_title
);
3559 job
->document_title
= title
;
3566 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)job
;
3567 WCHAR
*title
= wcsdup(info2
->pDocument
);
3568 DEVMODEW
*devmode
= dup_devmode(info2
->pDevMode
);
3570 if (!title
|| !devmode
)
3577 free(job
->document_title
);
3579 job
->document_title
= title
;
3580 job
->devmode
= devmode
;
3586 FIXME("level 3 stub\n");
3590 SetLastError(ERROR_INVALID_LEVEL
);
3594 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3598 static BOOL WINAPI
fpGetJob(HANDLE hprinter
, DWORD job_id
, DWORD level
,
3599 BYTE
*data
, DWORD size
, DWORD
*needed
)
3601 printer_t
*printer
= (printer_t
*)hprinter
;
3607 TRACE("%p %ld %ld %p %ld %p\n", hprinter
, job_id
, level
, data
, size
, needed
);
3609 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3611 SetLastError(ERROR_INVALID_HANDLE
);
3617 SetLastError(ERROR_INVALID_PARAMETER
);
3621 EnterCriticalSection(&printer
->info
->jobs_cs
);
3622 job
= get_job(printer
->info
, job_id
);
3625 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3632 s
= sizeof(JOB_INFO_1W
);
3633 s
+= job
->document_title
? (wcslen(job
->document_title
) + 1) * sizeof(WCHAR
) : 0;
3634 s
+= printer
->info
->name
?
3635 (wcslen(printer
->info
->name
) + 1) * sizeof(WCHAR
) : 0;
3639 JOB_INFO_1W
*info
= (JOB_INFO_1W
*)data
;
3641 p
= (WCHAR
*)(info
+ 1);
3642 memset(info
, 0, sizeof(*info
));
3643 info
->JobId
= job
->id
;
3644 if (job
->document_title
)
3646 info
->pDocument
= p
;
3647 wcscpy(p
, job
->document_title
);
3648 p
+= wcslen(job
->document_title
) + 1;
3650 if (printer
->info
->name
)
3652 info
->pPrinterName
= p
;
3653 wcscpy(p
, printer
->info
->name
);
3658 s
= sizeof(JOB_INFO_2W
);
3659 s
+= job
->document_title
? (wcslen(job
->document_title
) + 1) * sizeof(WCHAR
) : 0;
3660 s
+= printer
->info
->name
?
3661 (wcslen(printer
->info
->name
) + 1) * sizeof(WCHAR
) : 0;
3664 /* align DEVMODE to a DWORD boundary */
3665 s
+= (4 - (s
& 3)) & 3;
3666 s
+= job
->devmode
->dmSize
+ job
->devmode
->dmDriverExtra
;
3671 JOB_INFO_2W
*info
= (JOB_INFO_2W
*)data
;
3673 p
= (WCHAR
*)(info
+ 1);
3674 memset(info
, 0, sizeof(*info
));
3675 info
->JobId
= job
->id
;
3676 if (job
->document_title
)
3678 info
->pDocument
= p
;
3679 wcscpy(p
, job
->document_title
);
3680 p
+= wcslen(job
->document_title
) + 1;
3682 if (printer
->info
->name
)
3684 info
->pPrinterName
= p
;
3685 wcscpy(p
, printer
->info
->name
);
3686 p
+= wcslen(printer
->info
->name
) + 1;
3690 DEVMODEW
*devmode
= (DEVMODEW
*)(data
+ s
- job
->devmode
->dmSize
3691 - job
->devmode
->dmDriverExtra
);
3692 info
->pDevMode
= devmode
;
3693 memcpy(devmode
, job
->devmode
, job
->devmode
->dmSize
+ job
->devmode
->dmDriverExtra
);
3698 FIXME("level 3 stub\n");
3699 s
= sizeof(JOB_INFO_3
);
3702 memset(data
, 0, sizeof(JOB_INFO_3
));
3705 SetLastError(ERROR_INVALID_LEVEL
);
3710 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3715 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3721 static BOOL WINAPI
fpScheduleJob(HANDLE hprinter
, DWORD job_id
)
3723 printer_t
*printer
= (printer_t
*)hprinter
;
3724 WCHAR output
[1024], name
[1024], *datatype
;
3725 PRINTPROCESSOROPENDATA pp_data
;
3726 const WCHAR
*port_name
, *port
;
3733 TRACE("%p %ld\n", hprinter
, job_id
);
3735 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3737 SetLastError(ERROR_INVALID_HANDLE
);
3741 EnterCriticalSection(&printer
->info
->jobs_cs
);
3742 job
= get_job(printer
->info
, job_id
);
3745 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3750 if (!port
|| !*port
)
3751 port
= printer
->info
->port
;
3752 TRACE("need to schedule job %ld filename %s to port %s\n", job
->id
,
3753 debugstr_w(job
->filename
), debugstr_w(port
));
3756 if ((isalpha(port
[0]) && port
[1] == ':') ||
3757 !wcsncmp(port
, L
"FILE:", ARRAY_SIZE(L
"FILE:") - 1))
3759 port_name
= L
"FILE:";
3761 else if (!RegOpenKeyW(HKEY_CURRENT_USER
, L
"Software\\Wine\\Printing\\Spooler", &hkey
))
3763 DWORD type
, count
= sizeof(output
);
3764 if (!RegQueryValueExW(hkey
, port
, NULL
, &type
, (BYTE
*)output
, &count
))
3766 TRACE("overriding port %s -> %s\n", debugstr_w(port
), debugstr_w(output
));
3772 pp
= print_proc_load(printer
->info
->print_proc
);
3775 WARN("failed to load %s print processor\n", debugstr_w(printer
->info
->print_proc
));
3776 pp
= print_proc_load(L
"winprint");
3782 datatype
= job
->datatype
;
3783 else if (printer
->datatype
)
3784 datatype
= printer
->datatype
;
3786 datatype
= printer
->info
->datatype
;
3788 if (!print_proc_check_datatype(pp
, datatype
))
3790 WARN("%s datatype not supported by %s\n", debugstr_w(datatype
),
3791 debugstr_w(printer
->info
->print_proc
));
3792 print_proc_unload(pp
);
3796 swprintf(name
, ARRAY_SIZE(name
), L
"%s, Port", port_name
);
3797 pp_data
.pDevMode
= job
->devmode
;
3798 pp_data
.pDatatype
= datatype
;
3799 pp_data
.pParameters
= NULL
;
3800 pp_data
.pDocumentName
= job
->document_title
;
3801 pp_data
.JobId
= job
->id
;
3802 pp_data
.pOutputFile
= (WCHAR
*)port
;
3803 pp_data
.pPrinterName
= printer
->name
;
3804 hpp
= pp
->open(name
, &pp_data
);
3807 WARN("OpenPrintProcessor failed %ld\n", GetLastError());
3808 print_proc_unload(pp
);
3812 swprintf(name
, ARRAY_SIZE(name
), L
"%s, Job %d", printer
->name
, job
->id
);
3813 ret
= pp
->print(hpp
, name
);
3815 WARN("PrintDocumentOnPrintProcessor failed %ld\n", GetLastError());
3817 print_proc_unload(pp
);
3819 if (!(printer
->info
->attributes
& PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
))
3820 DeleteFileW(job
->filename
);
3822 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3826 static BOOL WINAPI
fpReadPrinter(HANDLE hprinter
, void *buf
, DWORD size
, DWORD
*bytes_read
)
3828 job_t
*job
= (job_t
*)hprinter
;
3830 TRACE("%p %p %lu %p\n", hprinter
, buf
, size
, bytes_read
);
3832 if (!job
|| (job
->header
.type
!= HANDLE_JOB
))
3834 SetLastError(ERROR_INVALID_HANDLE
);
3838 return ReadFile(job
->hf
, buf
, size
, bytes_read
, NULL
);
3841 static BOOL WINAPI
fpEndDocPrinter(HANDLE hprinter
)
3843 printer_t
*printer
= (printer_t
*)hprinter
;
3846 TRACE("%p\n", hprinter
);
3850 SetLastError(ERROR_INVALID_HANDLE
);
3854 if (printer
->header
.type
== HANDLE_PORT
)
3856 port_t
*port
= (port_t
*)hprinter
;
3857 return port
->mon
->monitor
.pfnEndDocPort(port
->hport
);
3860 if (printer
->header
.type
!= HANDLE_PRINTER
)
3862 SetLastError(ERROR_INVALID_HANDLE
);
3868 SetLastError(ERROR_SPL_NO_STARTDOC
);
3872 CloseHandle(printer
->doc
->hf
);
3873 printer
->doc
->hf
= NULL
;
3874 ret
= fpScheduleJob(hprinter
, printer
->doc
->id
);
3875 printer
->doc
= NULL
;
3879 /******************************************************************************
3880 * fpClosePrinter [exported through PRINTPROVIDOR]
3882 * Close a printer handle and free associated resources
3885 * hPrinter [I] Printerhandle to close
3892 static BOOL WINAPI
fpClosePrinter(HANDLE hprinter
)
3894 handle_header_t
*header
= (handle_header_t
*)hprinter
;
3896 TRACE("(%p)\n", hprinter
);
3901 if (header
->type
== HANDLE_SERVER
)
3905 else if (header
->type
== HANDLE_XCV
)
3907 xcv_t
*xcv
= (xcv_t
*)hprinter
;
3909 if (xcv
->hxcv
&& xcv
->pm
->monitor
.pfnXcvClosePort
)
3910 xcv
->pm
->monitor
.pfnXcvClosePort(xcv
->hxcv
);
3912 monitor_unload(xcv
->pm
);
3915 else if (header
->type
== HANDLE_PORT
)
3917 port_t
*port
= (port_t
*)hprinter
;
3920 port
->mon
->monitor
.pfnClosePort(port
->hport
);
3922 monitor_unload(port
->mon
);
3925 else if (header
->type
== HANDLE_JOB
)
3927 job_t
*job
= (job_t
*)hprinter
;
3929 CloseHandle(job
->hf
);
3932 else if (header
->type
== HANDLE_PRINTER
)
3934 printer_t
*printer
= (printer_t
*)hprinter
;
3937 fpEndDocPrinter(hprinter
);
3939 release_printer_info(printer
->info
);
3940 free(printer
->name
);
3941 free(printer
->datatype
);
3942 free(printer
->devmode
);
3947 ERR("invalid handle type\n");
3953 static BOOL WINAPI
fpSeekPrinter(HANDLE hprinter
, LARGE_INTEGER distance
,
3954 LARGE_INTEGER
*pos
, DWORD method
, BOOL bwrite
)
3956 job_t
*job
= (job_t
*)hprinter
;
3958 TRACE("(%p %I64d %p %lx %x)\n", hprinter
, distance
.QuadPart
, pos
, method
, bwrite
);
3962 SetLastError(ERROR_INVALID_HANDLE
);
3966 if (job
->header
.type
!= HANDLE_JOB
)
3968 FIXME("handle %x not supported\n", job
->header
.type
);
3979 return SetFilePointerEx(job
->hf
, distance
, pos
, method
);
3982 static const PRINTPROVIDOR backend
= {
3986 NULL
, /* fpEnumJobs */
3987 NULL
, /* fpAddPrinter */
3988 NULL
, /* fpDeletePrinter */
3989 NULL
, /* fpSetPrinter */
3990 NULL
, /* fpGetPrinter */
3991 NULL
, /* fpEnumPrinters */
3992 NULL
, /* fpAddPrinterDriver */
3993 NULL
, /* fpEnumPrinterDrivers */
3994 NULL
, /* fpGetPrinterDriver */
3995 fpGetPrinterDriverDirectory
,
3996 NULL
, /* fpDeletePrinterDriver */
3997 fpAddPrintProcessor
,
3998 fpEnumPrintProcessors
,
3999 fpGetPrintProcessorDirectory
,
4000 NULL
, /* fpDeletePrintProcessor */
4001 NULL
, /* fpEnumPrintProcessorDatatypes */
4003 NULL
, /* fpStartPagePrinter */
4005 NULL
, /* fpEndPagePrinter */
4006 NULL
, /* fpAbortPrinter */
4011 NULL
, /* fpGetPrinterData */
4012 NULL
, /* fpSetPrinterData */
4013 NULL
, /* fpWaitForPrinterChange */
4025 NULL
, /* fpCreatePrinterIC */
4026 NULL
, /* fpPlayGdiScriptOnPrinterIC */
4027 NULL
, /* fpDeletePrinterIC */
4028 NULL
, /* fpAddPrinterConnection */
4029 NULL
, /* fpDeletePrinterConnection */
4030 NULL
, /* fpPrinterMessageBox */
4033 NULL
, /* fpResetPrinter */
4034 NULL
, /* fpGetPrinterDriverEx */
4035 NULL
, /* fpFindFirstPrinterChangeNotification */
4036 NULL
, /* fpFindClosePrinterChangeNotification */
4038 NULL
, /* fpShutDown */
4039 NULL
, /* fpRefreshPrinterChangeNotification */
4040 NULL
, /* fpOpenPrinterEx */
4041 NULL
, /* fpAddPrinterEx */
4042 NULL
, /* fpSetPort */
4043 NULL
, /* fpEnumPrinterData */
4044 NULL
, /* fpDeletePrinterData */
4045 NULL
, /* fpClusterSplOpen */
4046 NULL
, /* fpClusterSplClose */
4047 NULL
, /* fpClusterSplIsAlive */
4048 NULL
, /* fpSetPrinterDataEx */
4049 NULL
, /* fpGetPrinterDataEx */
4050 NULL
, /* fpEnumPrinterDataEx */
4051 NULL
, /* fpEnumPrinterKey */
4052 NULL
, /* fpDeletePrinterDataEx */
4053 NULL
, /* fpDeletePrinterKey */
4055 NULL
, /* fpDeletePrinterDriverEx */
4056 NULL
, /* fpAddPerMachineConnection */
4057 NULL
, /* fpDeletePerMachineConnection */
4058 NULL
, /* fpEnumPerMachineConnections */
4060 fpAddPrinterDriverEx
,
4061 NULL
, /* fpSplReadPrinter */
4062 NULL
, /* fpDriverUnloadComplete */
4063 NULL
, /* fpGetSpoolFileInfo */
4064 NULL
, /* fpCommitSpoolData */
4065 NULL
, /* fpCloseSpoolFileHandle */
4066 NULL
, /* fpFlushPrinter */
4067 NULL
, /* fpSendRecvBidiData */
4068 NULL
/* fpAddDriverCatalog */
4071 /*****************************************************
4072 * InitializePrintProvidor (localspl.@)
4074 * Initialize the Printprovider
4077 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
4078 * cbPrintProvidor [I] Size of Buffer in Bytes
4079 * pFullRegistryPath [I] Registry-Path for the Printprovidor
4082 * Success: TRUE and pPrintProvidor filled
4086 * The RegistryPath should be:
4087 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
4088 * but this Parameter is ignored in "localspl.dll".
4092 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
4093 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
4096 TRACE("(%p, %lu, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
4097 memcpy(pPrintProvidor
, &backend
,
4098 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));