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
;
286 /* ############################### */
288 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
289 static monitor_t
* pm_localport
;
291 static struct list printers
= LIST_INIT(printers
);
292 static LONG last_job_id
;
294 static const WCHAR fmt_driversW
[] =
295 L
"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
296 static const WCHAR fmt_printprocessorsW
[] =
297 L
"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors\\";
298 static const WCHAR monitorsW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
299 static const WCHAR printersW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Printers";
300 static const WCHAR winnt_cv_portsW
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
301 static const WCHAR x86_envnameW
[] = L
"Windows NT x86";
304 static const printenv_t env_ia64
= {L
"Windows IA64", L
"ia64", 3,
305 L
"\\Version-3", L
"\\3"};
307 static const printenv_t env_x86
= {x86_envnameW
, L
"w32x86", 3,
308 L
"\\Version-3", L
"\\3"};
310 static const printenv_t env_x64
= {L
"Windows x64", L
"x64", 3,
311 L
"\\Version-3", L
"\\3"};
313 static const printenv_t env_arm
= {L
"Windows ARM", L
"arm", 3,
314 L
"\\Version-3", L
"\\3"};
316 static const printenv_t env_arm64
= {L
"Windows ARM64", L
"arm64", 3,
317 L
"\\Version-3", L
"\\3"};
319 static const printenv_t env_win40
= {L
"Windows 4.0", L
"win40", 0,
320 L
"\\Version-0", L
"\\0"};
322 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_arm
, &env_arm64
, &env_win40
};
325 #define env_arch env_x86
326 #elif defined __x86_64__
327 #define env_arch env_x64
328 #elif defined __arm__
329 #define env_arch env_arm
330 #elif defined __aarch64__
331 #define env_arch env_arm64
333 #error not defined for this cpu
337 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
338 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
339 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
340 0, sizeof(DRIVER_INFO_8W
)};
342 static BOOL WINAPI
fpClosePrinter(HANDLE
);
344 /******************************************************************
345 * apd_copyfile [internal]
347 * Copy a file from the driverdirectory to the versioned directory
354 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
359 apd
->src
[apd
->srclen
] = '\0';
360 apd
->dst
[apd
->dstlen
] = '\0';
362 if (!pathname
|| !pathname
[0]) {
363 /* nothing to copy */
367 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
372 lstrcatW( srcname
, file_part
);
374 lstrcatW( apd
->dst
, file_part
);
376 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
378 /* FIXME: handle APD_COPY_NEW_FILES */
379 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
380 TRACE("got %d with %lu\n", res
, GetLastError());
382 return apd
->lazy
|| res
;
385 /******************************************************************
386 * copy_servername_from_name (internal)
388 * for an external server, the serverpart from the name is copied.
391 * the length (in WCHAR) of the serverpart (0 for the local computer)
392 * (-length), when the name is too long
395 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
399 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
403 if (target
) *target
= '\0';
405 if (name
== NULL
) return 0;
406 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
409 /* skip over both backslash, find separator '\' */
410 ptr
= wcschr(server
, '\\');
411 serverlen
= (ptr
) ? ptr
- server
: wcslen(server
);
413 /* servername is empty */
414 if (serverlen
== 0) return 0;
416 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
418 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
421 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
422 target
[serverlen
] = '\0';
425 len
= ARRAY_SIZE(buffer
);
426 if (GetComputerNameW(buffer
, &len
)) {
427 if ((serverlen
== len
) && (wcsnicmp(server
, buffer
, len
) == 0)) {
428 /* The requested Servername is our computername */
435 /******************************************************************
436 * get_basename_from_name (internal)
438 * skip over the serverpart from the full name
441 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
443 if (name
== NULL
) return NULL
;
444 if ((name
[0] == '\\') && (name
[1] == '\\')) {
445 /* skip over the servername and search for the following '\' */
446 name
= wcschr(&name
[2], '\\');
447 if ((name
) && (name
[1])) {
448 /* found a separator ('\') followed by a name:
449 skip over the separator and return the rest */
454 /* no basename present (we found only a servername) */
461 /******************************************************************
462 * monitor_unload [internal]
464 * release a printmonitor and unload it from memory, when needed
467 static void monitor_unload(monitor_t
* pm
)
469 if (pm
== NULL
) return;
470 TRACE("%p (refcount: %ld) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
472 EnterCriticalSection(&monitor_handles_cs
);
474 if (pm
->refcount
) pm
->refcount
--;
476 if (pm
->refcount
== 0) {
477 list_remove(&pm
->entry
);
479 if (pm
->monitor
.pfnShutdown
)
480 pm
->monitor
.pfnShutdown(pm
->hmon
);
482 FreeLibrary(pm
->hdll
);
487 LeaveCriticalSection(&monitor_handles_cs
);
490 /******************************************************************
491 * monitor_unloadall [internal]
493 * release all registered printmonitors and unload them from memory, when needed
497 static void monitor_unloadall(void)
502 EnterCriticalSection(&monitor_handles_cs
);
503 /* iterate through the list, with safety against removal */
504 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
506 /* skip monitorui dlls */
507 if (pm
->monitor
.cbSize
) monitor_unload(pm
);
509 LeaveCriticalSection(&monitor_handles_cs
);
512 static printer_info_t
*find_printer_info(const WCHAR
*name
, unsigned int len
)
514 printer_info_t
*info
;
516 EnterCriticalSection(&printers_cs
);
517 LIST_FOR_EACH_ENTRY(info
, &printers
, printer_info_t
, entry
)
519 if (!wcsncmp(info
->name
, name
, len
) && (len
== -1 || !info
->name
[len
]))
521 InterlockedIncrement(&info
->ref
);
522 LeaveCriticalSection(&printers_cs
);
526 LeaveCriticalSection(&printers_cs
);
530 static WCHAR
* reg_query_value(HKEY key
, const WCHAR
*name
)
535 if (RegQueryValueExW(key
, name
, 0, &type
, NULL
, &size
) != ERROR_SUCCESS
543 if (RegQueryValueExW(key
, name
, 0, NULL
, (BYTE
*)ret
, &size
) != ERROR_SUCCESS
)
551 static DWORD
reg_query_dword(HKEY hkey
, const WCHAR
*name
)
553 DWORD type
, val
, size
= sizeof(size
);
555 if (RegQueryValueExW(hkey
, name
, 0, &type
, (BYTE
*)&val
, &size
))
557 if (type
!= REG_DWORD
)
562 static printer_info_t
* get_printer_info(const WCHAR
*name
)
564 HKEY hkey
, hprinter
= NULL
;
565 printer_info_t
*info
;
568 EnterCriticalSection(&printers_cs
);
569 info
= find_printer_info(name
, -1);
572 LeaveCriticalSection(&printers_cs
);
576 ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkey
);
577 if (ret
== ERROR_SUCCESS
)
578 ret
= RegOpenKeyW(hkey
, name
, &hprinter
);
580 if (ret
!= ERROR_SUCCESS
)
582 LeaveCriticalSection(&printers_cs
);
586 info
= calloc(1, sizeof(*info
));
589 LeaveCriticalSection(&printers_cs
);
590 RegCloseKey(hprinter
);
594 info
->name
= wcsdup(name
);
595 info
->port
= reg_query_value(hprinter
, L
"Port");
596 info
->print_proc
= reg_query_value(hprinter
, L
"Print Processor");
597 info
->datatype
= reg_query_value(hprinter
, L
"Datatype");
598 info
->attributes
= reg_query_dword(hprinter
, L
"Attributes");
599 RegCloseKey(hprinter
);
601 if (!info
->name
|| !info
->port
|| !info
->print_proc
|| !info
->datatype
)
605 free(info
->print_proc
);
606 free(info
->datatype
);
609 LeaveCriticalSection(&printers_cs
);
614 list_add_head(&printers
, &info
->entry
);
615 InitializeCriticalSection(&info
->jobs_cs
);
616 list_init(&info
->jobs
);
618 LeaveCriticalSection(&printers_cs
);
622 static void free_job(job_info_t
*job
)
624 list_remove(&job
->entry
);
628 free(job
->document_title
);
630 CloseHandle(job
->hf
);
634 static void release_printer_info(printer_info_t
*info
)
639 if (!InterlockedDecrement(&info
->ref
))
641 EnterCriticalSection(&printers_cs
);
642 list_remove(&info
->entry
);
643 LeaveCriticalSection(&printers_cs
);
647 free(info
->print_proc
);
648 free(info
->datatype
);
649 DeleteCriticalSection(&info
->jobs_cs
);
650 while (!list_empty(&info
->jobs
))
652 job_info_t
*job
= LIST_ENTRY(list_head(&info
->jobs
), job_info_t
, entry
);
659 static DEVMODEW
* dup_devmode(const DEVMODEW
*dm
)
663 if (!dm
) return NULL
;
664 ret
= malloc(dm
->dmSize
+ dm
->dmDriverExtra
);
665 if (ret
) memcpy(ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
669 static LONG WINAPI
CreateKey(HANDLE hcKey
, LPCWSTR pszSubKey
, DWORD dwOptions
,
670 REGSAM samDesired
, PSECURITY_ATTRIBUTES pSecurityAttributes
,
671 PHANDLE phckResult
, PDWORD pdwDisposition
, HANDLE hSpooler
)
674 return ERROR_CALL_NOT_IMPLEMENTED
;
677 static LONG WINAPI
OpenKey(HANDLE hcKey
, LPCWSTR pszSubKey
, REGSAM samDesired
,
678 PHANDLE phkResult
, HANDLE hSpooler
)
681 return ERROR_CALL_NOT_IMPLEMENTED
;
684 static LONG WINAPI
CloseKey(HANDLE hcKey
, HANDLE hSpooler
)
687 return ERROR_CALL_NOT_IMPLEMENTED
;
690 static LONG WINAPI
DeleteKey(HANDLE hcKey
, LPCWSTR pszSubKey
, HANDLE hSpooler
)
693 return ERROR_CALL_NOT_IMPLEMENTED
;
696 static LONG WINAPI
EnumKey(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszName
,
697 PDWORD pcchName
, PFILETIME pftLastWriteTime
, HANDLE hSpooler
)
700 return ERROR_CALL_NOT_IMPLEMENTED
;
703 static LONG WINAPI
QueryInfoKey(HANDLE hcKey
, PDWORD pcSubKeys
, PDWORD pcbKey
,
704 PDWORD pcValues
, PDWORD pcbValue
, PDWORD pcbData
,
705 PDWORD pcbSecurityDescriptor
, PFILETIME pftLastWriteTime
,
709 return ERROR_CALL_NOT_IMPLEMENTED
;
712 static LONG WINAPI
SetValue(HANDLE hcKey
, LPCWSTR pszValue
, DWORD dwType
,
713 const BYTE
* pData
, DWORD cbData
, HANDLE hSpooler
)
716 return ERROR_CALL_NOT_IMPLEMENTED
;
719 static LONG WINAPI
DeleteValue(HANDLE hcKey
, LPCWSTR pszValue
, HANDLE hSpooler
)
722 return ERROR_CALL_NOT_IMPLEMENTED
;
725 static LONG WINAPI
EnumValue(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszValue
,
726 PDWORD pcbValue
, PDWORD pType
, PBYTE pData
, PDWORD pcbData
,
730 return ERROR_CALL_NOT_IMPLEMENTED
;
733 static LONG WINAPI
QueryValue(HANDLE hcKey
, LPCWSTR pszValue
, PDWORD pType
,
734 PBYTE pData
, PDWORD pcbData
, HANDLE hSpooler
)
737 return ERROR_CALL_NOT_IMPLEMENTED
;
740 static MONITORREG monreg
=
755 static BOOL WINAPI
monitor2_EnumPorts(HANDLE hmon
, WCHAR
*name
, DWORD level
,
756 BYTE
*buf
, DWORD size
, DWORD
*needed
, DWORD
*count
)
758 return ((MONITOREX
*)hmon
)->Monitor
.pfnEnumPorts(name
, level
,
759 buf
, size
, needed
, count
);
762 static BOOL WINAPI
monitor2_OpenPort(HANDLE hmon
, WCHAR
*name
, HANDLE
*hport
)
764 return ((MONITOREX
*)hmon
)->Monitor
.pfnOpenPort(name
, hport
);
767 static BOOL WINAPI
monitor2_AddPort(HANDLE hmon
, WCHAR
*name
,
768 HWND hwnd
, WCHAR
*monitor_name
)
770 return ((MONITOREX
*)hmon
)->Monitor
.pfnAddPort(name
, hwnd
, monitor_name
);
773 static BOOL WINAPI
monitor2_AddPortEx(HANDLE hmon
, WCHAR
*name
, DWORD level
,
774 BYTE
*buf
, WCHAR
*monitor_name
)
776 return ((MONITOREX
*)hmon
)->Monitor
.pfnAddPortEx(name
, level
, buf
, monitor_name
);
779 static BOOL WINAPI
monitor2_ConfigurePort(HANDLE hmon
, WCHAR
*name
,
780 HWND hwnd
, WCHAR
*port_name
)
782 return ((MONITOREX
*)hmon
)->Monitor
.pfnConfigurePort(name
, hwnd
, port_name
);
785 static BOOL WINAPI
monitor2_DeletePort(HANDLE hmon
, WCHAR
*name
,
786 HWND hwnd
, WCHAR
*port_name
)
788 return ((MONITOREX
*)hmon
)->Monitor
.pfnDeletePort(name
, hwnd
, port_name
);
791 static BOOL WINAPI
monitor2_XcvOpenPort(HANDLE hmon
, const WCHAR
*obj
,
792 ACCESS_MASK granted_access
, HANDLE
*hxcv
)
794 return ((MONITOREX
*)hmon
)->Monitor
.pfnXcvOpenPort(obj
, granted_access
, hxcv
);
797 /******************************************************************
798 * monitor_load [internal]
800 * load a printmonitor, get the dllname from the registry, when needed
801 * initialize the monitor and dump found function-pointers
803 * On failure, SetLastError() is called and NULL is returned
806 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
808 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
809 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
810 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
811 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
812 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
814 monitor_t
* pm
= NULL
;
816 LPWSTR regroot
= NULL
;
817 LPWSTR driver
= dllname
;
820 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
821 /* Is the Monitor already loaded? */
822 EnterCriticalSection(&monitor_handles_cs
);
825 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
827 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
835 pm
= calloc(1, sizeof(monitor_t
));
836 if (pm
== NULL
) goto cleanup
;
837 list_add_tail(&monitor_handles
, &pm
->entry
);
841 if (pm
->name
== NULL
) {
842 /* Load the monitor */
846 len
= wcslen(monitorsW
) + wcslen(name
) + 2;
847 regroot
= malloc(len
* sizeof(WCHAR
));
851 lstrcpyW(regroot
, monitorsW
);
852 lstrcatW(regroot
, name
);
853 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
854 /* Get the Driver from the Registry */
856 driver
= reg_query_value(hroot
, L
"Driver");
859 WARN("%s not found\n", debugstr_w(regroot
));
862 pm
->name
= wcsdup(name
);
863 pm
->dllname
= wcsdup(driver
);
865 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
867 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
872 pm
->hdll
= LoadLibraryW(driver
);
873 TRACE("%p: LoadLibrary(%s) => %ld\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
875 if (pm
->hdll
== NULL
) {
877 SetLastError(ERROR_MOD_NOT_FOUND
);
882 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
883 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
884 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
885 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
886 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
889 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
890 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
891 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
892 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
893 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
895 if (pInitializePrintMonitorUI
!= NULL
) {
896 pm
->monitorUI
= pInitializePrintMonitorUI();
897 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
899 TRACE("0x%08lx: dwMonitorSize (%ld)\n",
900 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
905 if (pInitializePrintMonitor2
&& hroot
) {
910 memset(&init
, 0, sizeof(init
));
911 init
.cbSize
= sizeof(init
);
912 init
.hckRegistryRoot
= hroot
;
913 init
.pMonitorReg
= &monreg
;
916 monitor2
= pInitializePrintMonitor2(&init
, &hmon
);
917 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
918 monitor2
, debugstr_w(driver
), debugstr_w(regroot
));
921 memcpy(&pm
->monitor
, monitor2
, min(monitor2
->cbSize
, sizeof(pm
->monitor
)));
925 else if (pInitializePrintMonitor
&& regroot
) {
927 pm
->monitorex
= pInitializePrintMonitor(regroot
);
928 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
929 pm
->monitorex
, debugstr_w(driver
), debugstr_w(regroot
));
932 pm
->hmon
= (HANDLE
)pm
->monitorex
;
934 pm
->monitor
.cbSize
= sizeof(pm
->monitor
);
935 if (pm
->monitorex
->Monitor
.pfnEnumPorts
)
936 pm
->monitor
.pfnEnumPorts
= monitor2_EnumPorts
;
937 if (pm
->monitorex
->Monitor
.pfnOpenPort
)
938 pm
->monitor
.pfnOpenPort
= monitor2_OpenPort
;
939 pm
->monitor
.pfnStartDocPort
= pm
->monitorex
->Monitor
.pfnStartDocPort
;
940 pm
->monitor
.pfnWritePort
= pm
->monitorex
->Monitor
.pfnWritePort
;
941 pm
->monitor
.pfnReadPort
= pm
->monitorex
->Monitor
.pfnReadPort
;
942 pm
->monitor
.pfnEndDocPort
= pm
->monitorex
->Monitor
.pfnEndDocPort
;
943 pm
->monitor
.pfnClosePort
= pm
->monitorex
->Monitor
.pfnClosePort
;
944 if (pm
->monitorex
->Monitor
.pfnAddPort
)
945 pm
->monitor
.pfnAddPort
= monitor2_AddPort
;
946 if (pm
->monitorex
->Monitor
.pfnAddPortEx
)
947 pm
->monitor
.pfnAddPortEx
= monitor2_AddPortEx
;
948 if (pm
->monitorex
->Monitor
.pfnConfigurePort
)
949 pm
->monitor
.pfnConfigurePort
= monitor2_ConfigurePort
;
950 if (pm
->monitorex
->Monitor
.pfnDeletePort
)
951 pm
->monitor
.pfnDeletePort
= monitor2_DeletePort
;
952 pm
->monitor
.pfnGetPrinterDataFromPort
=
953 pm
->monitorex
->Monitor
.pfnGetPrinterDataFromPort
;
954 pm
->monitor
.pfnSetPortTimeOuts
= pm
->monitorex
->Monitor
.pfnSetPortTimeOuts
;
955 if (pm
->monitorex
->Monitor
.pfnXcvOpenPort
)
956 pm
->monitor
.pfnXcvOpenPort
= monitor2_XcvOpenPort
;
957 pm
->monitor
.pfnXcvDataPort
= pm
->monitorex
->Monitor
.pfnXcvDataPort
;
958 pm
->monitor
.pfnXcvClosePort
= pm
->monitorex
->Monitor
.pfnXcvClosePort
;
962 if (!pm
->monitor
.cbSize
&& regroot
) {
963 if (pInitializeMonitorEx
!= NULL
) {
964 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
966 if (pInitializeMonitor
!= NULL
) {
967 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
970 if (!pm
->monitor
.cbSize
&& !pm
->monitorUI
) {
972 SetLastError(ERROR_PROC_NOT_FOUND
);
977 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, L
"Local Port") == 0)) {
981 LeaveCriticalSection(&monitor_handles_cs
);
982 if (driver
!= dllname
) free(driver
);
983 if (hroot
) RegCloseKey(hroot
);
985 TRACE("=> %p\n", pm
);
989 /******************************************************************
990 * monitor_loadall [internal]
992 * Load all registered monitors
995 static DWORD
monitor_loadall(void)
998 DWORD registered
= 0;
1001 WCHAR buffer
[MAX_PATH
];
1004 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1005 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1006 NULL
, NULL
, NULL
, NULL
, NULL
);
1008 TRACE("%ld monitors registered\n", registered
);
1010 while (id
< registered
) {
1012 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1013 pm
= monitor_load(buffer
, NULL
);
1017 RegCloseKey(hmonitors
);
1019 TRACE("%ld monitors loaded\n", loaded
);
1023 /******************************************************************
1024 * monitor_loadui [internal]
1026 * load the userinterface-dll for a given portmonitor
1028 * On failure, NULL is returned
1030 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1032 monitor_t
* pui
= NULL
;
1033 WCHAR buffer
[MAX_PATH
];
1038 if (pm
== NULL
) return NULL
;
1039 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1041 /* Try the Portmonitor first; works for many monitors */
1042 if (pm
->monitorUI
) {
1043 EnterCriticalSection(&monitor_handles_cs
);
1045 LeaveCriticalSection(&monitor_handles_cs
);
1049 /* query the userinterface-dllname from the Portmonitor */
1050 /* building (",XcvMonitor %s",pm->name) not needed yet */
1051 if (pm
->monitor
.pfnXcvOpenPort
)
1052 res
= pm
->monitor
.pfnXcvOpenPort(pm
->hmon
, L
"", SERVER_ACCESS_ADMINISTER
, &hXcv
);
1053 TRACE("got %lu with %p\n", res
, hXcv
);
1055 res
= pm
->monitor
.pfnXcvDataPort(hXcv
, L
"MonitorUI", NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1056 TRACE("got %lu with %s\n", res
, debugstr_w(buffer
));
1057 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
1058 pm
->monitor
.pfnXcvClosePort(hXcv
);
1063 /******************************************************************
1064 * monitor_load_by_port [internal]
1066 * load a printmonitor for a given port
1068 * On failure, NULL is returned
1071 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1076 monitor_t
* pm
= NULL
;
1077 DWORD registered
= 0;
1081 TRACE("(%s)\n", debugstr_w(portname
));
1083 /* wine specific ports */
1084 if (portname
[0] == '|' || portname
[0] == '/' ||
1085 !wcsncmp(portname
, L
"LPR:", 4) || !wcsncmp(portname
, L
"CUPS:", 5))
1086 return monitor_load(L
"Local Port", NULL
);
1088 /* Try the Local Monitor first */
1089 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
1090 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1091 /* found the portname */
1093 return monitor_load(L
"Local Port", NULL
);
1098 len
= MAX_PATH
+ wcslen(L
"\\Ports\\") + wcslen(portname
) + 1;
1099 buffer
= malloc(len
* sizeof(WCHAR
));
1100 if (buffer
== NULL
) return NULL
;
1102 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
1103 EnterCriticalSection(&monitor_handles_cs
);
1104 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1106 while ((pm
== NULL
) && (id
< registered
)) {
1108 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1109 TRACE("testing %s\n", debugstr_w(buffer
));
1110 len
= wcslen(buffer
);
1111 lstrcatW(buffer
, L
"\\Ports\\");
1112 lstrcatW(buffer
, portname
);
1113 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1115 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1116 pm
= monitor_load(buffer
, NULL
);
1120 LeaveCriticalSection(&monitor_handles_cs
);
1127 /******************************************************************
1128 * Return the number of bytes for an multi_sz string.
1129 * The result includes all \0s
1130 * (specifically the extra \0, that is needed as multi_sz terminator).
1132 static int multi_sz_lenW(const WCHAR
*str
)
1134 const WCHAR
*ptr
= str
;
1138 ptr
+= wcslen(ptr
) + 1;
1141 return (ptr
- str
+ 1) * sizeof(WCHAR
);
1144 /******************************************************************
1145 * validate_envW [internal]
1147 * validate the user-supplied printing-environment
1150 * env [I] PTR to Environment-String or NULL
1153 * Success: PTR to printenv_t
1154 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
1157 * An empty string is handled the same way as NULL.
1161 static const printenv_t
* validate_envW(LPCWSTR env
)
1163 const printenv_t
*result
= NULL
;
1166 TRACE("(%s)\n", debugstr_w(env
));
1169 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
1171 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
1173 result
= all_printenv
[i
];
1177 if (result
== NULL
) {
1178 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
1179 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1181 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
1185 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_arch
;
1188 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
1192 /*****************************************************************************
1193 * enumerate the local monitors (INTERNAL)
1195 * returns the needed size (in bytes) for pMonitors
1196 * and *lpreturned is set to number of entries returned in pMonitors
1198 * Language-Monitors are also installed in the same Registry-Location but
1199 * they are filtered in Windows (not returned by EnumMonitors).
1200 * We do no filtering to simplify our Code.
1203 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
1208 LPMONITOR_INFO_2W mi
;
1209 WCHAR buffer
[MAX_PATH
];
1210 WCHAR dllname
[MAX_PATH
];
1218 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
1220 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1221 len
= entrysize
* numentries
;
1222 ptr
= (LPWSTR
) &pMonitors
[len
];
1225 len
= ARRAY_SIZE(buffer
);
1228 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
1229 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
1230 /* Scan all Monitor-Registry-Keys */
1231 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1232 TRACE("Monitor_%ld: %s\n", numentries
, debugstr_w(buffer
));
1233 dllsize
= sizeof(dllname
);
1236 /* The Monitor must have a Driver-DLL */
1237 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
1238 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
1239 /* We found a valid DLL for this Monitor. */
1240 TRACE("using Driver: %s\n", debugstr_w(dllname
));
1242 RegCloseKey(hentry
);
1245 /* Windows returns only Port-Monitors here, but to simplify our code,
1246 we do no filtering for Language-Monitors */
1249 needed
+= entrysize
;
1250 needed
+= (len
+1) * sizeof(WCHAR
); /* len is wcslen(monitorname) */
1252 /* we install and return only monitors for "Windows NT x86" */
1253 needed
+= (wcslen(x86_envnameW
) +1) * sizeof(WCHAR
);
1257 /* required size is calculated. Now fill the user-buffer */
1258 if (pMonitors
&& (cbBuf
>= needed
)){
1259 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
1260 pMonitors
+= entrysize
;
1262 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi
, level
, numentries
);
1264 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
1265 ptr
+= (len
+1); /* len is wcslen(monitorname) */
1267 mi
->pEnvironment
= ptr
;
1268 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
1269 ptr
+= (wcslen(x86_envnameW
)+1);
1272 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
1273 ptr
+= (dllsize
/ sizeof(WCHAR
));
1278 len
= ARRAY_SIZE(buffer
);
1283 *lpreturned
= numentries
;
1284 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1288 /*****************************************************************************
1289 * enumerate the local print processors (INTERNAL)
1291 * returns the needed size (in bytes) for pPPInfo
1292 * and *lpreturned is set to number of entries returned in pPPInfo
1295 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
1300 PPRINTPROCESSOR_INFO_1W ppi
;
1301 WCHAR buffer
[MAX_PATH
];
1302 WCHAR dllname
[MAX_PATH
];
1309 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1310 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
1311 ptr
= (LPWSTR
) &pPPInfo
[len
];
1314 len
= ARRAY_SIZE(buffer
);
1317 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
1318 /* add "winprint" first */
1320 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(L
"winprint");
1321 if (pPPInfo
&& (cbBuf
>= needed
)){
1322 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
1323 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1325 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi
, numentries
);
1327 lstrcpyW(ptr
, L
"winprint"); /* Name of the Print Processor */
1328 ptr
+= ARRAY_SIZE(L
"winprint");
1331 /* Scan all Printprocessor Keys */
1332 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
1333 (lstrcmpiW(buffer
, L
"winprint") != 0)) {
1334 TRACE("PrintProcessor_%ld: %s\n", numentries
, debugstr_w(buffer
));
1335 dllsize
= sizeof(dllname
);
1338 /* The Print Processor must have a Driver-DLL */
1339 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
1340 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
1341 /* We found a valid DLL for this Print Processor */
1342 TRACE("using Driver: %s\n", debugstr_w(dllname
));
1344 RegCloseKey(hentry
);
1349 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1350 needed
+= (len
+1) * sizeof(WCHAR
); /* len is wcslen(printprocessor name) */
1352 /* required size is calculated. Now fill the user-buffer */
1353 if (pPPInfo
&& (cbBuf
>= needed
)){
1354 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
1355 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1357 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi
, numentries
);
1359 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
1360 ptr
+= (len
+1); /* len is wcslen(printprosessor name) */
1364 len
= ARRAY_SIZE(buffer
);
1369 *lpreturned
= numentries
;
1370 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1374 /******************************************************************
1375 * enumerate the local Ports from all loaded monitors (internal)
1377 * returns the needed size (in bytes) for pPorts
1378 * and *lpreturned is set to number of entries returned in pPorts
1381 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1385 LPPORT_INFO_2W cache
;
1387 LPBYTE pi_buffer
= NULL
;
1388 DWORD pi_allocated
= 0;
1398 TRACE("(%ld, %p, %ld, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1399 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1401 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1402 needed
= entrysize
* numentries
;
1403 ptr
= (LPWSTR
) &pPorts
[needed
];
1408 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1410 if (pm
->monitor
.pfnEnumPorts
) {
1413 res
= pm
->monitor
.pfnEnumPorts(pm
->hmon
, NULL
, level
, pi_buffer
,
1414 pi_allocated
, &pi_needed
, &pi_returned
);
1415 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1416 /* Do not use realloc (we do not need the old data in the buffer) */
1418 pi_buffer
= malloc(pi_needed
);
1419 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1420 res
= pm
->monitor
.pfnEnumPorts(pm
->hmon
, NULL
, level
,
1421 pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1423 TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n",
1424 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1426 numentries
+= pi_returned
;
1427 needed
+= pi_needed
;
1429 /* fill the output-buffer (pPorts), if we have one */
1430 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1432 while (pi_returned
> pi_index
) {
1433 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1434 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1435 out
->pPortName
= ptr
;
1436 lstrcpyW(ptr
, cache
->pPortName
);
1437 ptr
+= (wcslen(ptr
)+1);
1439 out
->pMonitorName
= ptr
;
1440 lstrcpyW(ptr
, cache
->pMonitorName
);
1441 ptr
+= (wcslen(ptr
)+1);
1443 out
->pDescription
= ptr
;
1444 lstrcpyW(ptr
, cache
->pDescription
);
1445 ptr
+= (wcslen(ptr
)+1);
1446 out
->fPortType
= cache
->fPortType
;
1447 out
->Reserved
= cache
->Reserved
;
1455 /* the temporary portinfo-buffer is no longer needed */
1458 *lpreturned
= numentries
;
1459 TRACE("need %ld byte for %ld entries\n", needed
, numentries
);
1464 /*****************************************************************************
1465 * open_driver_reg [internal]
1467 * opens the registry for the printer drivers depending on the given input
1468 * variable pEnvironment
1471 * Success: the opened hkey
1474 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1478 const printenv_t
* env
;
1480 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1482 env
= validate_envW(pEnvironment
);
1483 if (!env
) return NULL
;
1485 buffer
= malloc(sizeof(fmt_driversW
) +
1486 (wcslen(env
->envname
) + wcslen(env
->versionregpath
)) * sizeof(WCHAR
));
1489 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1490 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1496 /*****************************************************************************
1497 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1499 * Return the PATH for the Printer-Drivers
1502 * pName [I] Servername (NT only) or NULL (local Computer)
1503 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1504 * Level [I] Structure-Level (must be 1)
1505 * pDriverDirectory [O] PTR to Buffer that receives the Result
1506 * cbBuf [I] Size of Buffer at pDriverDirectory
1507 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1508 * required for pDriverDirectory
1511 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1512 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1513 * if cbBuf is too small
1515 * Native Values returned in pDriverDirectory on Success:
1516 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1517 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1518 *| win9x(Windows 4.0): "%winsysdir%"
1520 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1523 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1524 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1527 const printenv_t
* env
;
1528 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1530 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
1531 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1533 if (pName
!= NULL
&& pName
[0]) {
1534 FIXME("server %s not supported\n", debugstr_w(pName
));
1535 SetLastError(ERROR_INVALID_PARAMETER
);
1539 env
= validate_envW(pEnvironment
);
1540 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1543 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1544 needed
= GetSystemDirectoryW(NULL
, 0);
1545 /* add the Size for the Subdirectories */
1546 needed
+= wcslen(L
"\\spool");
1547 needed
+= wcslen(L
"\\drivers\\");
1548 needed
+= wcslen(env
->subdir
);
1549 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1551 *pcbNeeded
= needed
;
1553 if (needed
> cbBuf
) {
1554 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1559 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1560 SetLastError(ERROR_INVALID_USER_BUFFER
);
1564 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1565 /* add the Subdirectories */
1566 lstrcatW( dir
, L
"\\spool" );
1567 CreateDirectoryW( dir
, NULL
);
1568 lstrcatW( dir
, L
"\\drivers\\" );
1569 CreateDirectoryW( dir
, NULL
);
1570 lstrcatW( dir
, env
->subdir
);
1571 CreateDirectoryW( dir
, NULL
);
1573 TRACE( "=> %s\n", debugstr_w( dir
) );
1577 /******************************************************************
1578 * driver_load [internal]
1580 * load a driver user interface dll
1582 * On failure, NULL is returned
1586 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1588 WCHAR fullname
[MAX_PATH
];
1592 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1594 /* build the driverdir */
1595 len
= sizeof(fullname
) -
1596 (wcslen(env
->versionsubdir
) + 1 + wcslen(dllname
) + 1) * sizeof(WCHAR
);
1598 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1599 (LPBYTE
) fullname
, len
, &len
)) {
1600 /* Should never fail */
1601 SetLastError(ERROR_BUFFER_OVERFLOW
);
1605 lstrcatW(fullname
, env
->versionsubdir
);
1606 lstrcatW(fullname
, L
"\\");
1607 lstrcatW(fullname
, dllname
);
1609 hui
= LoadLibraryW(fullname
);
1610 TRACE("%p: LoadLibrary(%s) %ld\n", hui
, debugstr_w(fullname
), GetLastError());
1615 static job_info_t
* get_job(printer_info_t
*info
, DWORD job_id
)
1619 LIST_FOR_EACH_ENTRY(job
, &info
->jobs
, job_info_t
, entry
)
1621 if(job
->id
== job_id
)
1627 static HANDLE
server_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1631 *stop_search
= FALSE
;
1635 server
= malloc(sizeof(*server
));
1638 *stop_search
= TRUE
;
1641 server
->type
= HANDLE_SERVER
;
1642 return (HANDLE
)server
;
1645 static HANDLE
xcv_alloc_handle(const WCHAR
*name
, PRINTER_DEFAULTSW
*def
, BOOL
*stop_search
)
1647 static const WCHAR xcv_monitor
[] = L
"XcvMonitor ";
1648 static const WCHAR xcv_port
[] = L
"XcvPort ";
1652 *stop_search
= FALSE
;
1657 while (*name
== ' ')
1660 mon
= !wcsncmp(name
, xcv_monitor
, ARRAY_SIZE(xcv_monitor
) - 1);
1663 name
+= ARRAY_SIZE(xcv_monitor
) - 1;
1667 if (wcsncmp(name
, xcv_port
, ARRAY_SIZE(xcv_port
) - 1)) return NULL
;
1668 name
+= ARRAY_SIZE(xcv_port
) - 1;
1671 *stop_search
= TRUE
;
1672 xcv
= calloc(1, sizeof(*xcv
));
1675 xcv
->header
.type
= HANDLE_XCV
;
1678 xcv
->pm
= monitor_load(name
, NULL
);
1680 xcv
->pm
= monitor_load_by_port(name
);
1684 SetLastError(ERROR_UNKNOWN_PORT
);
1688 if (xcv
->pm
->monitor
.pfnXcvOpenPort
)
1690 xcv
->pm
->monitor
.pfnXcvOpenPort(xcv
->pm
->hmon
, name
,
1691 def
? def
->DesiredAccess
: 0, &xcv
->hxcv
);
1695 fpClosePrinter((HANDLE
)xcv
);
1696 SetLastError(ERROR_INVALID_PARAMETER
);
1702 static HANDLE
port_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1704 static const WCHAR portW
[] = L
"Port";
1706 unsigned int i
, name_len
;
1710 *stop_search
= FALSE
;
1711 for (name_len
= 0; name
[name_len
] != ','; name_len
++)
1713 if (!name
[name_len
])
1717 for (i
= name_len
+ 1; name
[i
] == ' '; i
++);
1718 if (wcscmp(name
+ i
, portW
))
1721 *stop_search
= TRUE
;
1722 port_name
= malloc((name_len
+ 1) * sizeof(WCHAR
));
1725 memcpy(port_name
, name
, name_len
* sizeof(WCHAR
));
1726 port_name
[name_len
] = 0;
1728 port
= calloc(1, sizeof(*port
));
1734 port
->header
.type
= HANDLE_PORT
;
1736 port
->mon
= monitor_load_by_port(port_name
);
1743 if (!port
->mon
->monitor
.pfnOpenPort
|| !port
->mon
->monitor
.pfnWritePort
1744 || !port
->mon
->monitor
.pfnClosePort
|| !port
->mon
->monitor
.pfnStartDocPort
1745 || !port
->mon
->monitor
.pfnEndDocPort
)
1747 FIXME("port not supported: %s\n", debugstr_w(name
));
1749 fpClosePrinter((HANDLE
)port
);
1753 port
->mon
->monitor
.pfnOpenPort(port
->mon
->hmon
, port_name
, &port
->hport
);
1757 fpClosePrinter((HANDLE
)port
);
1760 return (HANDLE
)port
;
1763 static HANDLE
job_alloc_handle(const WCHAR
*name
, BOOL
*stop_search
)
1765 static const WCHAR jobW
[] = L
"Job ";
1767 unsigned int name_len
, job_id
;
1768 printer_info_t
*printer_info
;
1769 job_info_t
*job_info
;
1772 *stop_search
= FALSE
;
1773 for (name_len
= 0; name
[name_len
] != ','; name_len
++)
1775 if (!name
[name_len
])
1779 for (job_id
= name_len
+ 1; name
[job_id
] == ' '; job_id
++);
1783 if (wcsncmp(name
+ job_id
, jobW
, ARRAY_SIZE(jobW
) - 1))
1786 *stop_search
= TRUE
;
1787 job_id
+= ARRAY_SIZE(jobW
) - 1;
1788 job_id
= wcstoul(name
+ job_id
, NULL
, 10);
1790 printer_info
= find_printer_info(name
, name_len
);
1793 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1797 EnterCriticalSection(&printer_info
->jobs_cs
);
1799 job_info
= get_job(printer_info
, job_id
);
1802 LeaveCriticalSection(&printer_info
->jobs_cs
);
1803 release_printer_info(printer_info
);
1804 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1808 job
= malloc(sizeof(*job
));
1811 LeaveCriticalSection(&printer_info
->jobs_cs
);
1812 release_printer_info(printer_info
);
1815 job
->header
.type
= HANDLE_JOB
;
1816 job
->hf
= CreateFileW(job_info
->filename
, GENERIC_READ
,
1817 FILE_SHARE_WRITE
| FILE_SHARE_READ
| FILE_SHARE_DELETE
,
1818 NULL
, OPEN_EXISTING
, 0, NULL
);
1820 LeaveCriticalSection(&printer_info
->jobs_cs
);
1821 release_printer_info(printer_info
);
1823 if (job
->hf
== INVALID_HANDLE_VALUE
)
1831 static HANDLE
printer_alloc_handle(const WCHAR
*name
, const WCHAR
*basename
,
1832 PRINTER_DEFAULTSW
*def
)
1838 printer
= calloc(1, sizeof(*printer
));
1841 printer
->header
.type
= HANDLE_PRINTER
;
1843 /* clone the full name */
1844 printer
->name
= wcsdup(name
);
1845 if (name
&& !printer
->name
)
1847 fpClosePrinter((HANDLE
)printer
);
1851 printer
->info
= get_printer_info(basename
);
1854 fpClosePrinter((HANDLE
)printer
);
1855 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1859 if (def
&& def
->pDatatype
)
1860 printer
->datatype
= wcsdup(def
->pDatatype
);
1861 if (def
&& def
->pDevMode
)
1862 printer
->devmode
= dup_devmode(def
->pDevMode
);
1864 hroot
= open_driver_reg(env_arch
.envname
);
1867 status
= RegOpenKeyW(hroot
, name
, &hkey
);
1869 if (status
== ERROR_SUCCESS
)
1871 printer
->print_proc
= reg_query_value(hkey
, L
"Print Processor");
1875 if (!printer
->print_proc
)
1876 printer
->print_proc
= wcsdup(L
"winprint");
1878 return (HANDLE
)printer
;
1881 static inline WCHAR
*get_file_part( WCHAR
*name
)
1883 WCHAR
*ptr
= wcsrchr( name
, '\\' );
1884 if (ptr
) return ptr
+ 1;
1888 /******************************************************************************
1889 * myAddPrinterDriverEx [internal]
1891 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1892 * and a special mode with lazy error checking.
1895 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1897 const printenv_t
*env
;
1900 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1910 /* we need to set all entries in the Registry, independent from the Level of
1911 DRIVER_INFO, that the caller supplied */
1913 ZeroMemory(&di
, sizeof(di
));
1914 if (pDriverInfo
&& (level
< ARRAY_SIZE(di_sizeof
))) {
1915 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1918 /* dump the most used infos */
1919 TRACE("%p: .cVersion : 0x%lx/%ld\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1920 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1921 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1922 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1923 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1924 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1925 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1926 /* dump only the first of the additional Files */
1927 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1930 /* check environment */
1931 env
= validate_envW(di
.pEnvironment
);
1932 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1934 /* fill the copy-data / get the driverdir */
1935 len
= sizeof(apd
.src
) - sizeof(L
"\\3") - sizeof(WCHAR
);
1936 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1937 (LPBYTE
) apd
.src
, len
, &len
)) {
1938 /* Should never fail */
1941 memcpy(apd
.dst
, apd
.src
, len
);
1942 lstrcatW(apd
.src
, L
"\\");
1943 apd
.srclen
= wcslen(apd
.src
);
1944 lstrcatW(apd
.dst
, env
->versionsubdir
);
1945 lstrcatW(apd
.dst
, L
"\\");
1946 apd
.dstlen
= wcslen(apd
.dst
);
1947 apd
.copyflags
= dwFileCopyFlags
;
1949 CreateDirectoryW(apd
.src
, NULL
);
1950 CreateDirectoryW(apd
.dst
, NULL
);
1952 hroot
= open_driver_reg(env
->envname
);
1954 ERR("Can't create Drivers key\n");
1958 /* Fill the Registry for the Driver */
1959 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1960 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1961 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1963 ERR("can't create driver %s: %lu\n", debugstr_w(di
.pName
), lres
);
1970 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1971 RegSetValueExW(hdrv
, L
"Version", 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1974 file
= get_file_part( di
.pDriverPath
);
1975 RegSetValueExW( hdrv
, L
"Driver", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1976 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1978 file
= get_file_part( di
.pDataFile
);
1979 RegSetValueExW( hdrv
, L
"Data File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1980 apd_copyfile( di
.pDataFile
, file
, &apd
);
1982 file
= get_file_part( di
.pConfigFile
);
1983 RegSetValueExW( hdrv
, L
"Configuration File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1984 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1986 /* settings for level 3 */
1989 file
= get_file_part( di
.pHelpFile
);
1990 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (BYTE
*)file
, (wcslen( file
) + 1) * sizeof(WCHAR
) );
1991 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1994 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
"") );
1996 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1998 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1999 reg
= reg_ptr
= malloc( multi_sz_lenW( di
.pDependentFiles
) );
2001 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= wcslen( in_ptr
) + 1)
2003 file
= get_file_part( in_ptr
);
2004 len
= wcslen( file
) + 1;
2005 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
2007 apd_copyfile( in_ptr
, file
, &apd
);
2011 RegSetValueExW( hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (BYTE
*)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
2015 RegSetValueExW(hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2017 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
2018 if (di
.pMonitorName
)
2019 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (BYTE
*)di
.pMonitorName
,
2020 (wcslen(di
.pMonitorName
)+1)* sizeof(WCHAR
));
2022 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2024 if (di
.pDefaultDataType
)
2025 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (BYTE
*)di
.pDefaultDataType
,
2026 (wcslen(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
2028 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2030 /* settings for level 4 */
2031 if (di
.pszzPreviousNames
)
2032 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (BYTE
*)di
.pszzPreviousNames
,
2033 multi_sz_lenW(di
.pszzPreviousNames
));
2035 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
2037 if (di
.pszPrintProcessor
)
2038 RegSetValueExW(hdrv
, L
"Print Processor", 0, REG_SZ
, (BYTE
*)di
.pszPrintProcessor
,
2039 (wcslen(di
.pszPrintProcessor
) + 1) * sizeof(WCHAR
));
2041 RegSetValueExW(hdrv
, L
"Print Processor", 0, REG_SZ
, (const BYTE
*)L
"winprint", sizeof(L
"winprint"));
2043 if (level
> 5) TRACE("level %lu for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
2046 hui
= driver_load(env
, di
.pConfigFile
);
2047 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
2048 if (hui
&& pDrvDriverEvent
) {
2050 /* Support for DrvDriverEvent is optional */
2051 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
2052 /* MSDN: level for DRIVER_INFO is 1 to 3 */
2053 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
2054 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
2058 TRACE("=> TRUE with %lu\n", GetLastError());
2063 /******************************************************************************
2064 * fpAddMonitor [exported through PRINTPROVIDOR]
2066 * Install a Printmonitor
2069 * pName [I] Servername or NULL (local Computer)
2070 * Level [I] Structure-Level (Must be 2)
2071 * pMonitors [I] PTR to MONITOR_INFO_2
2078 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2081 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2083 const printenv_t
* env
;
2084 monitor_t
* pm
= NULL
;
2085 LPMONITOR_INFO_2W mi2w
;
2091 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2092 TRACE("(%s, %ld, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2093 debugstr_w(mi2w
->pName
), debugstr_w(mi2w
->pEnvironment
), debugstr_w(mi2w
->pDLLName
));
2095 if (copy_servername_from_name(pName
, NULL
)) {
2096 FIXME("server %s not supported\n", debugstr_w(pName
));
2097 SetLastError(ERROR_ACCESS_DENIED
);
2101 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2102 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2103 SetLastError(ERROR_INVALID_PARAMETER
);
2107 env
= validate_envW(mi2w
->pEnvironment
);
2109 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2111 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2112 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2113 SetLastError(ERROR_INVALID_PARAMETER
);
2117 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2118 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2122 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2123 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2124 &disposition
) == ERROR_SUCCESS
) {
2126 /* Some installers set options for the port before calling AddMonitor.
2127 We query the "Driver" entry to verify that the monitor is installed,
2128 before we return an error.
2129 When a user installs two print monitors at the same time with the
2130 same name, a race condition is possible but silently ignored. */
2134 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2135 (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, NULL
,
2136 &namesize
) == ERROR_SUCCESS
)) {
2137 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2138 /* 9x use ERROR_ALREADY_EXISTS */
2139 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2144 len
= (wcslen(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2145 res
= (RegSetValueExW(hentry
, L
"Driver", 0, REG_SZ
,
2146 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2148 /* Load and initialize the monitor. SetLastError() is called on failure */
2149 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
)
2151 RegDeleteKeyW(hroot
, mi2w
->pName
);
2155 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
2158 RegCloseKey(hentry
);
2165 /******************************************************************************
2166 * fpAddPort [exported through PRINTPROVIDOR]
2168 * Add a Port for a specific Monitor
2171 * pName [I] Servername or NULL (local Computer)
2172 * hWnd [I] Handle to parent Window for the Dialog-Box
2173 * pMonitorName [I] Name of the Monitor that manage the Port
2180 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
2187 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
2189 lres
= copy_servername_from_name(pName
, NULL
);
2191 FIXME("server %s not supported\n", debugstr_w(pName
));
2192 SetLastError(ERROR_INVALID_PARAMETER
);
2196 /* an empty Monitorname is Invalid */
2197 if (!pMonitorName
[0]) {
2198 SetLastError(ERROR_NOT_SUPPORTED
);
2202 pm
= monitor_load(pMonitorName
, NULL
);
2203 if (pm
&& pm
->monitor
.pfnAddPort
) {
2204 res
= pm
->monitor
.pfnAddPort(pm
->hmon
, pName
, hWnd
, pMonitorName
);
2205 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
2209 pui
= monitor_loadui(pm
);
2210 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
2211 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
2212 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
2216 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2217 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2218 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2220 SetLastError(ERROR_NOT_SUPPORTED
);
2223 monitor_unload(pui
);
2227 TRACE("returning %ld with %lu\n", res
, GetLastError());
2231 /******************************************************************************
2232 * fpAddPortEx [exported through PRINTPROVIDOR]
2234 * Add a Port for a specific Monitor, without presenting a user interface
2237 * pName [I] Servername or NULL (local Computer)
2238 * level [I] Structure-Level (1 or 2) for pBuffer
2239 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
2240 * pMonitorName [I] Name of the Monitor that manage the Port
2247 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
2254 pi2
= (PORT_INFO_2W
*) pBuffer
;
2256 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
2257 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
2258 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
2259 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
2261 lres
= copy_servername_from_name(pName
, NULL
);
2263 FIXME("server %s not supported\n", debugstr_w(pName
));
2264 SetLastError(ERROR_INVALID_PARAMETER
);
2268 if ((level
< 1) || (level
> 2)) {
2269 SetLastError(ERROR_INVALID_LEVEL
);
2273 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
2274 SetLastError(ERROR_INVALID_PARAMETER
);
2278 /* load the Monitor */
2279 pm
= monitor_load(pMonitorName
, NULL
);
2280 if (pm
&& pm
->monitor
.pfnAddPortEx
)
2282 res
= pm
->monitor
.pfnAddPortEx(pm
->hmon
, pName
, level
, pBuffer
, pMonitorName
);
2283 TRACE("got %ld with %lu (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
2287 FIXME("not implemented for %s (monitor %p: %s)\n",
2288 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
2289 SetLastError(ERROR_INVALID_PARAMETER
);
2296 /******************************************************************************
2297 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
2299 * Install a Printer Driver with the Option to upgrade / downgrade the Files
2302 * pName [I] Servername or NULL (local Computer)
2303 * level [I] Level for the supplied DRIVER_INFO_*W struct
2304 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
2305 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
2312 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
2316 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
2317 lres
= copy_servername_from_name(pName
, NULL
);
2319 FIXME("server %s not supported\n", debugstr_w(pName
));
2320 SetLastError(ERROR_ACCESS_DENIED
);
2324 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
2325 TRACE("Flags 0x%lx ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
2328 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
2331 /******************************************************************************
2332 * fpConfigurePort [exported through PRINTPROVIDOR]
2334 * Display the Configuration-Dialog for a specific Port
2337 * pName [I] Servername or NULL (local Computer)
2338 * hWnd [I] Handle to parent Window for the Dialog-Box
2339 * pPortName [I] Name of the Port, that should be configured
2346 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2353 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2355 lres
= copy_servername_from_name(pName
, NULL
);
2357 FIXME("server %s not supported\n", debugstr_w(pName
));
2358 SetLastError(ERROR_INVALID_NAME
);
2362 /* an empty Portname is Invalid, but can popup a Dialog */
2363 if (!pPortName
[0]) {
2364 SetLastError(ERROR_NOT_SUPPORTED
);
2368 pm
= monitor_load_by_port(pPortName
);
2369 if (pm
&& pm
->monitor
.pfnConfigurePort
)
2371 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2372 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2373 res
= pm
->monitor
.pfnConfigurePort(pm
->hmon
, pName
, hWnd
, pPortName
);
2374 TRACE("got %ld with %lu\n", res
, GetLastError());
2378 pui
= monitor_loadui(pm
);
2379 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
2380 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2381 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2382 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
2383 TRACE("got %ld with %lu\n", res
, GetLastError());
2387 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2388 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2389 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2391 SetLastError(ERROR_NOT_SUPPORTED
);
2394 monitor_unload(pui
);
2398 TRACE("returning %ld with %lu\n", res
, GetLastError());
2402 /******************************************************************
2403 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2405 * Delete a specific Printmonitor from a Printing-Environment
2408 * pName [I] Servername or NULL (local Computer)
2409 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2410 * pMonitorName [I] Name of the Monitor, that should be deleted
2417 * pEnvironment is ignored in Windows for the local Computer.
2421 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2427 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2428 debugstr_w(pMonitorName
));
2430 lres
= copy_servername_from_name(pName
, NULL
);
2432 FIXME("server %s not supported\n", debugstr_w(pName
));
2433 SetLastError(ERROR_INVALID_NAME
);
2437 /* pEnvironment is ignored in Windows for the local Computer */
2438 if (!pMonitorName
|| !pMonitorName
[0]) {
2439 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2440 SetLastError(ERROR_INVALID_PARAMETER
);
2444 /* Unload the monitor if it's loaded */
2445 EnterCriticalSection(&monitor_handles_cs
);
2446 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
2448 if (pm
->name
&& !lstrcmpW(pMonitorName
, pm
->name
))
2454 LeaveCriticalSection(&monitor_handles_cs
);
2456 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2457 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2461 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2462 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
2467 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
2470 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2471 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2475 static BOOL WINAPI
fpResetPrinter(HANDLE hprinter
, PRINTER_DEFAULTSW
*def
)
2477 printer_t
*printer
= (printer_t
*)hprinter
;
2479 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
2481 SetLastError(ERROR_INVALID_HANDLE
);
2487 SetLastError(ERROR_INVALID_PARAMETER
);
2491 free(printer
->datatype
);
2493 printer
->datatype
= wcsdup(def
->pDatatype
);
2495 printer
->datatype
= NULL
;
2497 free(printer
->devmode
);
2499 printer
->devmode
= dup_devmode(def
->pDevMode
);
2501 printer
->devmode
= NULL
;
2505 /*****************************************************************************
2506 * fpDeletePort [exported through PRINTPROVIDOR]
2508 * Delete a specific Port
2511 * pName [I] Servername or NULL (local Computer)
2512 * hWnd [I] Handle to parent Window for the Dialog-Box
2513 * pPortName [I] Name of the Port, that should be deleted
2520 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2527 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2529 lres
= copy_servername_from_name(pName
, NULL
);
2531 FIXME("server %s not supported\n", debugstr_w(pName
));
2532 SetLastError(ERROR_INVALID_NAME
);
2536 /* an empty Portname is Invalid */
2537 if (!pPortName
[0]) {
2538 SetLastError(ERROR_NOT_SUPPORTED
);
2542 pm
= monitor_load_by_port(pPortName
);
2543 if (pm
&& pm
->monitor
.pfnDeletePort
)
2545 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2546 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2547 res
= pm
->monitor
.pfnDeletePort(pm
->hmon
, pName
, hWnd
, pPortName
);
2548 TRACE("got %ld with %lu\n", res
, GetLastError());
2552 pui
= monitor_loadui(pm
);
2553 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2554 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2555 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2556 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2557 TRACE("got %ld with %lu\n", res
, GetLastError());
2561 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2562 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2563 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2565 SetLastError(ERROR_NOT_SUPPORTED
);
2568 monitor_unload(pui
);
2572 TRACE("returning %ld with %lu\n", res
, GetLastError());
2576 /*****************************************************************************
2577 * fpEnumMonitors [exported through PRINTPROVIDOR]
2579 * Enumerate available Port-Monitors
2582 * pName [I] Servername or NULL (local Computer)
2583 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2584 * pMonitors [O] PTR to Buffer that receives the Result
2585 * cbBuf [I] Size of Buffer at pMonitors
2586 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2587 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2591 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2594 * Windows reads the Registry once and cache the Results.
2597 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
2598 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2600 DWORD numentries
= 0;
2605 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
2606 cbBuf
, pcbNeeded
, pcReturned
);
2608 lres
= copy_servername_from_name(pName
, NULL
);
2610 FIXME("server %s not supported\n", debugstr_w(pName
));
2611 SetLastError(ERROR_INVALID_NAME
);
2615 if (!Level
|| (Level
> 2)) {
2616 WARN("level (%ld) is ignored in win9x\n", Level
);
2617 SetLastError(ERROR_INVALID_LEVEL
);
2621 /* Scan all Monitor-Keys */
2623 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
2625 /* we calculated the needed buffersize. now do more error-checks */
2626 if (cbBuf
< needed
) {
2627 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2631 /* fill the Buffer with the Monitor-Keys */
2632 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2636 if (pcbNeeded
) *pcbNeeded
= needed
;
2637 if (pcReturned
) *pcReturned
= numentries
;
2639 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2640 res
, GetLastError(), needed
, numentries
);
2645 /******************************************************************************
2646 * fpEnumPorts [exported through PRINTPROVIDOR]
2648 * Enumerate available Ports
2651 * pName [I] Servername or NULL (local Computer)
2652 * Level [I] Structure-Level (1 or 2)
2653 * pPorts [O] PTR to Buffer that receives the Result
2654 * cbBuf [I] Size of Buffer at pPorts
2655 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2656 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2660 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2663 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2664 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2667 DWORD numentries
= 0;
2671 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2672 cbBuf
, pcbNeeded
, pcReturned
);
2674 lres
= copy_servername_from_name(pName
, NULL
);
2676 FIXME("server %s not supported\n", debugstr_w(pName
));
2677 SetLastError(ERROR_INVALID_NAME
);
2681 if (!Level
|| (Level
> 2)) {
2682 SetLastError(ERROR_INVALID_LEVEL
);
2686 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2687 SetLastError(RPC_X_NULL_REF_POINTER
);
2691 EnterCriticalSection(&monitor_handles_cs
);
2694 /* Scan all local Ports */
2696 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2698 /* we calculated the needed buffersize. now do the error-checks */
2699 if (cbBuf
< needed
) {
2700 monitor_unloadall();
2701 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2702 goto emP_cleanup_cs
;
2704 else if (!pPorts
|| !pcReturned
) {
2705 monitor_unloadall();
2706 SetLastError(RPC_X_NULL_REF_POINTER
);
2707 goto emP_cleanup_cs
;
2710 /* Fill the Buffer */
2711 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2713 monitor_unloadall();
2716 LeaveCriticalSection(&monitor_handles_cs
);
2719 if (pcbNeeded
) *pcbNeeded
= needed
;
2720 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2722 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
2723 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2728 static BOOL WINAPI
fpAddPrintProcessor(WCHAR
*name
, WCHAR
*environment
, WCHAR
*path
,
2731 const printenv_t
* env
;
2736 TRACE("(%s, %s, %s, %s)\n", debugstr_w(name
), debugstr_w(environment
),
2737 debugstr_w(path
), debugstr_w(print_proc
));
2739 if (!path
|| !print_proc
)
2741 SetLastError(ERROR_INVALID_PARAMETER
);
2745 if (name
&& name
[0])
2747 FIXME("server %s not supported\n", debugstr_w(name
));
2748 SetLastError(ERROR_INVALID_NAME
);
2752 env
= validate_envW(environment
);
2756 regpath
= malloc(sizeof(fmt_printprocessorsW
) +
2757 wcslen(env
->envname
) * sizeof(WCHAR
));
2760 wsprintfW(regpath
, fmt_printprocessorsW
, env
->envname
);
2762 s
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpath
, &hroot
);
2766 s
= RegSetKeyValueW(hroot
, print_proc
, L
"Driver", REG_SZ
, path
,
2767 (wcslen(path
) + 1) * sizeof(WCHAR
));
2779 /*****************************************************************************
2780 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2782 * Enumerate available Print Processors
2785 * pName [I] Servername or NULL (local Computer)
2786 * pEnvironment [I] Printing-Environment or NULL (Default)
2787 * Level [I] Structure-Level (Only 1 is allowed)
2788 * pPPInfo [O] PTR to Buffer that receives the Result
2789 * cbBuf [I] Size of Buffer at pMonitors
2790 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2791 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2795 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2798 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2799 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2801 const printenv_t
* env
;
2802 LPWSTR regpathW
= NULL
;
2803 DWORD numentries
= 0;
2808 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2809 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2811 lres
= copy_servername_from_name(pName
, NULL
);
2813 FIXME("server %s not supported\n", debugstr_w(pName
));
2814 SetLastError(ERROR_INVALID_NAME
);
2819 SetLastError(ERROR_INVALID_LEVEL
);
2823 env
= validate_envW(pEnvironment
);
2825 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2827 regpathW
= malloc(sizeof(fmt_printprocessorsW
) +
2828 (wcslen(env
->envname
) * sizeof(WCHAR
)));
2833 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2835 /* Scan all Printprocessor-Keys */
2837 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2839 /* we calculated the needed buffersize. now do more error-checks */
2840 if (cbBuf
< needed
) {
2841 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2845 /* fill the Buffer with the Printprocessor Infos */
2846 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2851 if (pcbNeeded
) *pcbNeeded
= needed
;
2852 if (pcReturned
) *pcReturned
= numentries
;
2854 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2855 res
, GetLastError(), needed
, numentries
);
2860 /******************************************************************************
2861 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2863 * Return the PATH for the Print-Processors
2866 * pName [I] Servername or NULL (this computer)
2867 * pEnvironment [I] Printing-Environment or NULL (Default)
2868 * level [I] Structure-Level (must be 1)
2869 * pPPInfo [O] PTR to Buffer that receives the Result
2870 * cbBuf [I] Size of Buffer at pPPInfo
2871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2875 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2877 * Native Values returned in pPPInfo on Success for this computer:
2878 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2879 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2880 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2882 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2885 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2886 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2888 const printenv_t
* env
;
2892 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2893 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2896 lres
= copy_servername_from_name(pName
, NULL
);
2898 FIXME("server %s not supported\n", debugstr_w(pName
));
2899 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2903 env
= validate_envW(pEnvironment
);
2905 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2907 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2908 needed
= GetSystemDirectoryW(NULL
, 0);
2909 /* add the Size for the Subdirectories */
2910 needed
+= wcslen(L
"\\spool\\prtprocs\\");
2911 needed
+= wcslen(env
->subdir
);
2912 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2914 *pcbNeeded
= needed
;
2916 if (needed
> cbBuf
) {
2917 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2921 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2922 /* add the Subdirectories */
2923 lstrcatW((LPWSTR
) pPPInfo
, L
"\\spool\\prtprocs\\");
2924 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2925 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2929 /******************************************************************************
2930 * fpOpenPrinter [exported through PRINTPROVIDOR]
2932 * Open a Printer / Printserver or a Printer-Object
2935 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2936 * pPrinter [O] The resulting Handle is stored here
2937 * pDefaults [I] PTR to Default Printer Settings or NULL
2944 * lpPrinterName is one of:
2945 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2946 *| Printer: "PrinterName"
2947 *| Printer-Object: "PrinterName,Job xxx"
2948 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2949 *| XcvPort: "Servername,XcvPort PortName"
2953 static BOOL WINAPI
fpOpenPrinter(WCHAR
*name
, HANDLE
*hprinter
,
2954 PRINTER_DEFAULTSW
*def
)
2956 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
2957 const WCHAR
*basename
;
2960 TRACE("(%s, %p, %p)\n", debugstr_w(name
), hprinter
, def
);
2962 if (copy_servername_from_name(name
, servername
))
2964 FIXME("server %s not supported\n", debugstr_w(servername
));
2965 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2969 basename
= get_basename_from_name(name
);
2970 if (name
!= basename
) TRACE("converted %s to %s\n",
2971 debugstr_w(name
), debugstr_w(basename
));
2973 /* an empty basename is invalid */
2974 if (basename
&& (!basename
[0]))
2976 SetLastError(ERROR_INVALID_PARAMETER
);
2980 *hprinter
= server_alloc_handle(basename
, &stop_search
);
2981 if (!*hprinter
&& !stop_search
)
2982 *hprinter
= xcv_alloc_handle(basename
, def
, &stop_search
);
2983 if (!*hprinter
&& !stop_search
)
2984 *hprinter
= port_alloc_handle(basename
, &stop_search
);
2985 if (!*hprinter
&& !stop_search
)
2986 *hprinter
= job_alloc_handle(basename
, &stop_search
);
2987 if (!*hprinter
&& !stop_search
)
2988 *hprinter
= printer_alloc_handle(name
, basename
, def
);
2990 TRACE("==> %p\n", *hprinter
);
2991 return *hprinter
!= 0;
2994 /******************************************************************************
2995 * fpXcvData [exported through PRINTPROVIDOR]
2997 * Execute commands in the Printmonitor DLL
3000 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
3001 * pszDataName [i] Name of the command to execute
3002 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
3003 * cbInputData [i] Size in Bytes of Buffer at pInputData
3004 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
3005 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
3006 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
3007 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
3014 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
3015 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
3017 * Minimal List of commands, that a Printmonitor DLL should support:
3019 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
3020 *| "AddPort" : Add a Port
3021 *| "DeletePort": Delete a Port
3023 * Many Printmonitors support additional commands. Examples for localspl.dll:
3024 * "GetDefaultCommConfig", "SetDefaultCommConfig",
3025 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
3028 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
3029 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
3030 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
3032 xcv_t
*xcv
= (xcv_t
*)hXcv
;
3034 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
3035 pInputData
, cbInputData
, pOutputData
,
3036 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
3038 if (!xcv
|| xcv
->header
.type
!= HANDLE_XCV
) {
3039 SetLastError(ERROR_INVALID_HANDLE
);
3043 if (!pcbOutputNeeded
) {
3044 SetLastError(ERROR_INVALID_PARAMETER
);
3048 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
3049 SetLastError(RPC_X_NULL_REF_POINTER
);
3053 *pcbOutputNeeded
= 0;
3055 if (xcv
->pm
->monitor
.pfnXcvDataPort
)
3056 *pdwStatus
= xcv
->pm
->monitor
.pfnXcvDataPort(xcv
->hxcv
, pszDataName
,
3057 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
3062 static inline size_t form_struct_size( DWORD level
)
3064 if (level
== 1) return sizeof(FORM_INFO_1W
);
3065 if (level
== 2) return sizeof(FORM_INFO_2W
);
3067 SetLastError( ERROR_INVALID_LEVEL
);
3071 static void fill_builtin_form_info( BYTE
**base
, WCHAR
**strings
, const struct builtin_form
*form
, DWORD level
,
3072 DWORD size
, DWORD
*used
)
3074 FORM_INFO_2W
*info
= *(FORM_INFO_2W
**)base
;
3075 DWORD name_len
= wcslen( form
->name
) + 1, res_len
= 0, keyword_len
, total_size
;
3076 static const WCHAR dll_name
[] = L
"localspl.dll";
3077 const WCHAR
*resource
;
3079 total_size
= name_len
* sizeof(WCHAR
);
3083 keyword_len
= WideCharToMultiByte( CP_ACP
, 0, form
->name
, -1, NULL
, 0, NULL
, NULL
);
3084 keyword_len
= (keyword_len
+ 1) & ~1;
3085 total_size
+= keyword_len
;
3086 res_len
= LoadStringW( localspl_instance
, form
->res_id
, (WCHAR
*)&resource
, 0 );
3087 if (res_len
&& resource
[res_len
- 1]) res_len
++;
3088 total_size
+= (res_len
+ ARRAY_SIZE(dll_name
)) * sizeof(WCHAR
);
3091 if (*used
+ total_size
<= size
)
3093 info
->Flags
= FORM_BUILTIN
;
3094 info
->pName
= memcpy( *strings
, form
->name
, name_len
* sizeof(WCHAR
) );
3095 *strings
+= name_len
;
3096 info
->Size
= form
->size
;
3097 info
->ImageableArea
.left
= info
->ImageableArea
.top
= 0;
3098 info
->ImageableArea
.right
= info
->Size
.cx
;
3099 info
->ImageableArea
.bottom
= info
->Size
.cy
;
3102 info
->pKeyword
= (char *)*strings
;
3103 WideCharToMultiByte( CP_ACP
, 0, form
->name
, -1, (char *)info
->pKeyword
, keyword_len
, NULL
, NULL
);
3104 *strings
+= keyword_len
/ sizeof(WCHAR
);
3105 info
->StringType
= STRING_MUIDLL
;
3106 info
->pMuiDll
= memcpy( *strings
, dll_name
, sizeof(dll_name
) );
3107 *strings
+= ARRAY_SIZE(dll_name
);
3108 info
->dwResourceId
= form
->res_id
;
3111 info
->StringType
|= STRING_LANGPAIR
;
3112 info
->pDisplayName
= memcpy( *strings
, resource
, (res_len
- 1) * sizeof(WCHAR
) );
3113 info
->pDisplayName
[res_len
- 1] = '\0';
3114 *strings
+= res_len
;
3115 info
->wLangId
= GetUserDefaultLangID();
3119 info
->pDisplayName
= NULL
;
3125 *base
+= form_struct_size( level
);
3126 *used
+= total_size
;
3129 static BOOL WINAPI
fpAddForm( HANDLE printer
, DWORD level
, BYTE
*form
)
3131 FIXME( "(%p, %ld, %p): stub\n", printer
, level
, form
);
3135 static BOOL WINAPI
fpDeleteForm( HANDLE printer
, WCHAR
*name
)
3137 FIXME( "(%p, %s): stub\n", printer
, debugstr_w( name
) );
3141 static BOOL WINAPI
fpGetForm( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
)
3143 size_t struct_size
= form_struct_size( level
);
3144 const struct builtin_form
*builtin
= NULL
;
3145 WCHAR
*strings
= NULL
;
3149 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer
, debugstr_w( name
), level
, form
, size
, needed
);
3153 if (!struct_size
) return FALSE
;
3155 for (i
= 0; i
< ARRAY_SIZE(builtin_forms
); i
++)
3157 if (!wcscmp( name
, builtin_forms
[i
].name
))
3159 builtin
= builtin_forms
+ i
;
3166 SetLastError( ERROR_INVALID_FORM_NAME
);
3170 *needed
= struct_size
;
3171 if (*needed
< size
) strings
= (WCHAR
*)(form
+ *needed
);
3173 fill_builtin_form_info( &base
, &strings
, builtin
, level
, size
, needed
);
3177 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
3183 static BOOL WINAPI
fpSetForm( HANDLE printer
, WCHAR
*name
, DWORD level
, BYTE
*form
)
3185 FIXME( "(%p, %s, %ld, %p): stub\n", printer
, debugstr_w( name
), level
, form
);
3189 static BOOL WINAPI
fpEnumForms( HANDLE printer
, DWORD level
, BYTE
*form
, DWORD size
, DWORD
*needed
, DWORD
*count
)
3191 DWORD num
= ARRAY_SIZE(builtin_forms
), i
;
3192 WCHAR
*strings
= NULL
;
3194 size_t struct_size
= form_struct_size( level
);
3196 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer
, level
, form
, size
, needed
, count
);
3198 *count
= *needed
= 0;
3200 if (!struct_size
) return FALSE
;
3202 *needed
= num
* struct_size
;
3203 if (*needed
< size
) strings
= (WCHAR
*)(form
+ *needed
);
3205 for (i
= 0; i
< ARRAY_SIZE(builtin_forms
); i
++)
3206 fill_builtin_form_info( &base
, &strings
, builtin_forms
+ i
, level
, size
, needed
);
3210 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
3218 static size_t get_spool_filename(DWORD job_id
, WCHAR
*buf
, size_t len
)
3220 static const WCHAR spool_path
[] = L
"spool\\PRINTERS\\";
3223 ret
= GetSystemDirectoryW(NULL
, 0) + ARRAY_SIZE(spool_path
) + 10;
3227 ret
= GetSystemDirectoryW(buf
, ret
);
3228 if (buf
[ret
- 1] != '\\')
3230 memcpy(buf
+ ret
, spool_path
, sizeof(spool_path
));
3231 ret
+= ARRAY_SIZE(spool_path
) - 1;
3232 swprintf(buf
+ ret
, 10, L
"%05d.SPL", job_id
);
3237 static job_info_t
* add_job(printer_t
*printer
, DOC_INFO_1W
*info
, BOOL create
)
3239 DWORD job_id
, last_id
;
3243 job
= calloc(1, sizeof(*job
));
3246 len
= get_spool_filename(0, NULL
, 0);
3247 job
->filename
= malloc(len
* sizeof(WCHAR
));
3253 job
->port
= wcsdup(info
->pOutputFile
);
3254 if (info
->pOutputFile
&& !job
->port
)
3256 free(job
->filename
);
3263 last_id
= last_job_id
;
3264 job_id
= last_id
< MAX_JOB_ID
? last_id
+ 1 : 1;
3265 if (InterlockedCompareExchange(&last_job_id
, job_id
, last_id
) == last_id
)
3270 get_spool_filename(job_id
, job
->filename
, len
);
3273 job
->hf
= CreateFileW(job
->filename
, GENERIC_WRITE
, FILE_SHARE_READ
,
3274 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3275 if (job
->hf
== INVALID_HANDLE_VALUE
)
3277 free(job
->filename
);
3286 job
->document_title
= wcsdup(info
->pDocName
);
3287 job
->datatype
= wcsdup(info
->pDatatype
);
3288 job
->devmode
= dup_devmode(printer
->devmode
);
3290 EnterCriticalSection(&printer
->info
->jobs_cs
);
3291 list_add_tail(&printer
->info
->jobs
, &job
->entry
);
3292 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3296 static BOOL WINAPI
fpAddJob(HANDLE hprinter
, DWORD level
, BYTE
*data
, DWORD size
, DWORD
*needed
)
3298 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*)data
;
3299 printer_t
*printer
= (printer_t
*)hprinter
;
3300 DOC_INFO_1W doc_info
;
3304 TRACE("(%p %ld %p %ld %p)\n", hprinter
, level
, data
, size
, needed
);
3306 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3308 SetLastError(ERROR_INVALID_HANDLE
);
3314 SetLastError(ERROR_INVALID_LEVEL
);
3320 SetLastError(ERROR_INVALID_PARAMETER
);
3324 len
= get_spool_filename(0, NULL
, 0);
3325 *needed
= sizeof(*addjob
) + len
* sizeof(WCHAR
);
3328 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3332 memset(&doc_info
, 0, sizeof(doc_info
));
3333 doc_info
.pDocName
= (WCHAR
*)L
"Local Downlevel Document";
3334 job
= add_job(printer
, &doc_info
, FALSE
);
3338 addjob
->JobId
= job
->id
;
3339 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
3340 memcpy(addjob
->Path
, job
->filename
, len
* sizeof(WCHAR
));
3347 BOOL (WINAPI
*enum_datatypes
)(WCHAR
*, WCHAR
*, DWORD
,
3348 BYTE
*, DWORD
, DWORD
*, DWORD
*);
3349 HANDLE (WINAPI
*open
)(WCHAR
*, PRINTPROCESSOROPENDATA
*);
3350 BOOL (WINAPI
*print
)(HANDLE
, WCHAR
*);
3351 BOOL (WINAPI
*close
)(HANDLE
);
3354 static printproc_t
* print_proc_load(const WCHAR
*name
)
3356 WCHAR
*reg_path
, path
[2 * MAX_PATH
];
3362 size
= sizeof(fmt_printprocessorsW
) +
3363 (wcslen(env_arch
.envname
) + wcslen(name
)) * sizeof(WCHAR
);
3364 reg_path
= malloc(size
);
3367 swprintf(reg_path
, size
/ sizeof(WCHAR
), fmt_printprocessorsW
, env_arch
.envname
);
3368 wcscat(reg_path
, name
);
3370 status
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, reg_path
, &hkey
);
3372 if (status
!= ERROR_SUCCESS
)
3375 if (!fpGetPrintProcessorDirectory(NULL
, NULL
, 1, (BYTE
*)path
, sizeof(path
), &size
))
3380 len
= size
/ sizeof(WCHAR
);
3381 path
[len
- 1] = '\\';
3383 size
= sizeof(path
) - len
* sizeof(WCHAR
);
3384 status
= RegQueryValueExW(hkey
, L
"Driver", NULL
, NULL
, (BYTE
*)(path
+ len
), &size
);
3386 if (status
!= ERROR_SUCCESS
)
3389 ret
= malloc(sizeof(*ret
));
3393 TRACE("loading print processor: %s\n", debugstr_w(path
));
3395 ret
->hmod
= LoadLibraryW(path
);
3402 ret
->enum_datatypes
= (void *)GetProcAddress(ret
->hmod
, "EnumPrintProcessorDatatypesW");
3403 ret
->open
= (void *)GetProcAddress(ret
->hmod
, "OpenPrintProcessor");
3404 ret
->print
= (void *)GetProcAddress(ret
->hmod
, "PrintDocumentOnPrintProcessor");
3405 ret
->close
= (void *)GetProcAddress(ret
->hmod
, "ClosePrintProcessor");
3406 if (!ret
->enum_datatypes
|| !ret
->open
|| !ret
->print
|| !ret
->close
)
3408 FreeLibrary(ret
->hmod
);
3413 ret
->name
= wcsdup(name
);
3417 static BOOL
print_proc_check_datatype(printproc_t
*pp
, const WCHAR
*datatype
)
3419 DATATYPES_INFO_1W
*types
;
3425 pp
->enum_datatypes(NULL
, pp
->name
, 1, NULL
, 0, &size
, &no
);
3426 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
3429 types
= malloc(size
);
3433 if (!pp
->enum_datatypes(NULL
, pp
->name
, 1, (BYTE
*)types
, size
, &size
, &no
))
3439 for (i
= 0; i
< no
; i
++)
3441 if (!wcscmp(types
[i
].pName
, datatype
))
3448 static void print_proc_unload(printproc_t
*pp
)
3450 FreeLibrary(pp
->hmod
);
3455 static DWORD WINAPI
fpStartDocPrinter(HANDLE hprinter
, DWORD level
, BYTE
*doc_info
)
3457 printer_t
*printer
= (printer_t
*)hprinter
;
3458 DOC_INFO_1W
*info
= (DOC_INFO_1W
*)doc_info
;
3459 BOOL datatype_valid
= FALSE
;
3463 TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n",
3464 hprinter
, level
, doc_info
, debugstr_w(info
->pDocName
),
3465 debugstr_w(info
->pOutputFile
), debugstr_w(info
->pDatatype
));
3469 SetLastError(ERROR_INVALID_HANDLE
);
3473 if (printer
->header
.type
== HANDLE_PORT
)
3475 port_t
*port
= (port_t
*)hprinter
;
3476 /* TODO: pass printer name and job_id */
3477 return port
->mon
->monitor
.pfnStartDocPort(port
->hport
,
3478 NULL
, 0, level
, doc_info
);
3481 if (printer
->header
.type
!= HANDLE_PRINTER
)
3483 SetLastError(ERROR_INVALID_HANDLE
);
3487 if (level
< 1 || level
> 3)
3489 SetLastError(ERROR_INVALID_LEVEL
);
3495 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3499 if (info
->pDatatype
)
3500 datatype
= info
->pDatatype
;
3501 else if (printer
->datatype
)
3502 datatype
= printer
->datatype
;
3504 datatype
= printer
->info
->datatype
;
3506 if (!datatype
|| ((printer
->info
->attributes
& PRINTER_ATTRIBUTE_RAW_ONLY
) &&
3507 wcsicmp(datatype
, L
"RAW")))
3509 TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype
));
3510 SetLastError(ERROR_INVALID_DATATYPE
);
3514 pp
= print_proc_load(printer
->info
->print_proc
);
3517 WARN("failed to load %s print processor\n", debugstr_w(printer
->info
->print_proc
));
3521 datatype_valid
= print_proc_check_datatype(pp
, datatype
);
3522 print_proc_unload(pp
);
3525 if (!datatype_valid
)
3527 pp
= print_proc_load(printer
->print_proc
);
3531 datatype_valid
= print_proc_check_datatype(pp
, datatype
);
3532 print_proc_unload(pp
);
3535 if (!datatype_valid
)
3537 TRACE("%s datatype not supported by %s\n", debugstr_w(datatype
),
3538 debugstr_w(printer
->info
->print_proc
));
3539 SetLastError(ERROR_INVALID_DATATYPE
);
3543 printer
->doc
= add_job(printer
, info
, TRUE
);
3544 return printer
->doc
? printer
->doc
->id
: 0;
3547 static BOOL WINAPI
fpWritePrinter(HANDLE hprinter
, void *buf
, DWORD size
, DWORD
*written
)
3549 handle_header_t
*header
= (handle_header_t
*)hprinter
;
3551 TRACE("(%p, %p, %ld, %p)\n", hprinter
, buf
, size
, written
);
3555 SetLastError(ERROR_INVALID_HANDLE
);
3559 if (header
->type
== HANDLE_PORT
)
3561 port_t
*port
= (port_t
*)hprinter
;
3563 return port
->mon
->monitor
.pfnWritePort(port
->hport
, buf
, size
, written
);
3566 if (header
->type
== HANDLE_PRINTER
)
3568 printer_t
*printer
= (printer_t
*)hprinter
;
3572 SetLastError(ERROR_SPL_NO_STARTDOC
);
3576 return WriteFile(printer
->doc
->hf
, buf
, size
, written
, NULL
);
3579 SetLastError(ERROR_INVALID_HANDLE
);
3583 static BOOL WINAPI
fpSetJob(HANDLE hprinter
, DWORD job_id
,
3584 DWORD level
, BYTE
*data
, DWORD command
)
3586 printer_t
*printer
= (printer_t
*)hprinter
;
3590 TRACE("(%p, %ld, %ld, %p, %ld)\n", hprinter
, job_id
, level
, data
, command
);
3591 FIXME("Ignoring everything other than document title\n");
3593 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3595 SetLastError(ERROR_INVALID_HANDLE
);
3599 EnterCriticalSection(&printer
->info
->jobs_cs
);
3600 job
= get_job(printer
->info
, job_id
);
3603 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3614 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)job
;
3615 WCHAR
*title
= wcsdup(info1
->pDocument
);
3619 free(job
->document_title
);
3620 job
->document_title
= title
;
3627 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)job
;
3628 WCHAR
*title
= wcsdup(info2
->pDocument
);
3629 DEVMODEW
*devmode
= dup_devmode(info2
->pDevMode
);
3631 if (!title
|| !devmode
)
3638 free(job
->document_title
);
3640 job
->document_title
= title
;
3641 job
->devmode
= devmode
;
3647 FIXME("level 3 stub\n");
3651 SetLastError(ERROR_INVALID_LEVEL
);
3655 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3659 static BOOL WINAPI
fpGetJob(HANDLE hprinter
, DWORD job_id
, DWORD level
,
3660 BYTE
*data
, DWORD size
, DWORD
*needed
)
3662 printer_t
*printer
= (printer_t
*)hprinter
;
3668 TRACE("%p %ld %ld %p %ld %p\n", hprinter
, job_id
, level
, data
, size
, needed
);
3670 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3672 SetLastError(ERROR_INVALID_HANDLE
);
3678 SetLastError(ERROR_INVALID_PARAMETER
);
3682 EnterCriticalSection(&printer
->info
->jobs_cs
);
3683 job
= get_job(printer
->info
, job_id
);
3686 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3693 s
= sizeof(JOB_INFO_1W
);
3694 s
+= job
->document_title
? (wcslen(job
->document_title
) + 1) * sizeof(WCHAR
) : 0;
3695 s
+= printer
->info
->name
?
3696 (wcslen(printer
->info
->name
) + 1) * sizeof(WCHAR
) : 0;
3700 JOB_INFO_1W
*info
= (JOB_INFO_1W
*)data
;
3702 p
= (WCHAR
*)(info
+ 1);
3703 memset(info
, 0, sizeof(*info
));
3704 info
->JobId
= job
->id
;
3705 if (job
->document_title
)
3707 info
->pDocument
= p
;
3708 wcscpy(p
, job
->document_title
);
3709 p
+= wcslen(job
->document_title
) + 1;
3711 if (printer
->info
->name
)
3713 info
->pPrinterName
= p
;
3714 wcscpy(p
, printer
->info
->name
);
3719 s
= sizeof(JOB_INFO_2W
);
3720 s
+= job
->document_title
? (wcslen(job
->document_title
) + 1) * sizeof(WCHAR
) : 0;
3721 s
+= printer
->info
->name
?
3722 (wcslen(printer
->info
->name
) + 1) * sizeof(WCHAR
) : 0;
3725 /* align DEVMODE to a DWORD boundary */
3726 s
+= (4 - (s
& 3)) & 3;
3727 s
+= job
->devmode
->dmSize
+ job
->devmode
->dmDriverExtra
;
3732 JOB_INFO_2W
*info
= (JOB_INFO_2W
*)data
;
3734 p
= (WCHAR
*)(info
+ 1);
3735 memset(info
, 0, sizeof(*info
));
3736 info
->JobId
= job
->id
;
3737 if (job
->document_title
)
3739 info
->pDocument
= p
;
3740 wcscpy(p
, job
->document_title
);
3741 p
+= wcslen(job
->document_title
) + 1;
3743 if (printer
->info
->name
)
3745 info
->pPrinterName
= p
;
3746 wcscpy(p
, printer
->info
->name
);
3747 p
+= wcslen(printer
->info
->name
) + 1;
3751 DEVMODEW
*devmode
= (DEVMODEW
*)(data
+ s
- job
->devmode
->dmSize
3752 - job
->devmode
->dmDriverExtra
);
3753 info
->pDevMode
= devmode
;
3754 memcpy(devmode
, job
->devmode
, job
->devmode
->dmSize
+ job
->devmode
->dmDriverExtra
);
3759 FIXME("level 3 stub\n");
3760 s
= sizeof(JOB_INFO_3
);
3763 memset(data
, 0, sizeof(JOB_INFO_3
));
3766 SetLastError(ERROR_INVALID_LEVEL
);
3771 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3776 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3782 static BOOL WINAPI
fpScheduleJob(HANDLE hprinter
, DWORD job_id
)
3784 printer_t
*printer
= (printer_t
*)hprinter
;
3785 WCHAR output
[1024], name
[1024], *datatype
;
3786 BOOL datatype_valid
= FALSE
, ret
= TRUE
;
3787 PRINTPROCESSOROPENDATA pp_data
;
3788 const WCHAR
*port_name
, *port
;
3794 TRACE("%p %ld\n", hprinter
, job_id
);
3796 if (!printer
|| printer
->header
.type
!= HANDLE_PRINTER
)
3798 SetLastError(ERROR_INVALID_HANDLE
);
3802 EnterCriticalSection(&printer
->info
->jobs_cs
);
3803 job
= get_job(printer
->info
, job_id
);
3806 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3811 if (!port
|| !*port
)
3812 port
= printer
->info
->port
;
3813 TRACE("need to schedule job %ld filename %s to port %s\n", job
->id
,
3814 debugstr_w(job
->filename
), debugstr_w(port
));
3817 if ((isalpha(port
[0]) && port
[1] == ':') ||
3818 !wcsncmp(port
, L
"FILE:", ARRAY_SIZE(L
"FILE:") - 1))
3820 port_name
= L
"FILE:";
3822 else if (!RegOpenKeyW(HKEY_CURRENT_USER
, L
"Software\\Wine\\Printing\\Spooler", &hkey
))
3824 DWORD type
, count
= sizeof(output
);
3825 if (!RegQueryValueExW(hkey
, port
, NULL
, &type
, (BYTE
*)output
, &count
))
3827 TRACE("overriding port %s -> %s\n", debugstr_w(port
), debugstr_w(output
));
3834 datatype
= job
->datatype
;
3835 else if (printer
->datatype
)
3836 datatype
= printer
->datatype
;
3838 datatype
= printer
->info
->datatype
;
3840 pp
= print_proc_load(printer
->info
->print_proc
);
3843 WARN("failed to load %s print processor\n", debugstr_w(printer
->info
->print_proc
));
3847 datatype_valid
= print_proc_check_datatype(pp
, datatype
);
3848 if (!datatype_valid
)
3849 print_proc_unload(pp
);
3852 if (!datatype_valid
)
3854 pp
= print_proc_load(printer
->print_proc
);
3858 datatype_valid
= print_proc_check_datatype(pp
, datatype
);
3861 if (!datatype_valid
)
3863 WARN("%s datatype not supported by %s\n", debugstr_w(datatype
),
3864 debugstr_w(printer
->info
->print_proc
));
3865 print_proc_unload(pp
);
3869 swprintf(name
, ARRAY_SIZE(name
), L
"%s, Port", port_name
);
3870 pp_data
.pDevMode
= job
->devmode
;
3871 pp_data
.pDatatype
= datatype
;
3872 pp_data
.pParameters
= NULL
;
3873 pp_data
.pDocumentName
= job
->document_title
;
3874 pp_data
.JobId
= job
->id
;
3875 pp_data
.pOutputFile
= (WCHAR
*)port
;
3876 pp_data
.pPrinterName
= printer
->name
;
3877 hpp
= pp
->open(name
, &pp_data
);
3880 WARN("OpenPrintProcessor failed %ld\n", GetLastError());
3881 print_proc_unload(pp
);
3885 swprintf(name
, ARRAY_SIZE(name
), L
"%s, Job %d", printer
->name
, job
->id
);
3886 ret
= pp
->print(hpp
, name
);
3888 WARN("PrintDocumentOnPrintProcessor failed %ld\n", GetLastError());
3890 print_proc_unload(pp
);
3892 if (!(printer
->info
->attributes
& PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
))
3893 DeleteFileW(job
->filename
);
3895 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3899 static BOOL WINAPI
fpAbortPrinter(HANDLE hprinter
)
3901 printer_t
*printer
= (printer_t
*)hprinter
;
3904 TRACE("%p\n", hprinter
);
3908 SetLastError(ERROR_INVALID_HANDLE
);
3912 if (printer
->header
.type
!= HANDLE_PRINTER
)
3914 FIXME("%x handle not supported\n", printer
->header
.type
);
3920 SetLastError(ERROR_SPL_NO_STARTDOC
);
3924 CloseHandle(printer
->doc
->hf
);
3925 printer
->doc
->hf
= NULL
;
3927 EnterCriticalSection(&printer
->info
->jobs_cs
);
3928 job
= get_job(printer
->info
, printer
->doc
->id
);
3929 if (job
) free_job(job
);
3930 LeaveCriticalSection(&printer
->info
->jobs_cs
);
3932 printer
->doc
= NULL
;
3936 static BOOL WINAPI
fpReadPrinter(HANDLE hprinter
, void *buf
, DWORD size
, DWORD
*bytes_read
)
3938 job_t
*job
= (job_t
*)hprinter
;
3940 TRACE("%p %p %lu %p\n", hprinter
, buf
, size
, bytes_read
);
3942 if (!job
|| (job
->header
.type
!= HANDLE_JOB
))
3944 SetLastError(ERROR_INVALID_HANDLE
);
3948 return ReadFile(job
->hf
, buf
, size
, bytes_read
, NULL
);
3951 static BOOL WINAPI
fpEndDocPrinter(HANDLE hprinter
)
3953 printer_t
*printer
= (printer_t
*)hprinter
;
3956 TRACE("%p\n", hprinter
);
3960 SetLastError(ERROR_INVALID_HANDLE
);
3964 if (printer
->header
.type
== HANDLE_PORT
)
3966 port_t
*port
= (port_t
*)hprinter
;
3967 return port
->mon
->monitor
.pfnEndDocPort(port
->hport
);
3970 if (printer
->header
.type
!= HANDLE_PRINTER
)
3972 SetLastError(ERROR_INVALID_HANDLE
);
3978 SetLastError(ERROR_SPL_NO_STARTDOC
);
3982 CloseHandle(printer
->doc
->hf
);
3983 printer
->doc
->hf
= NULL
;
3984 ret
= fpScheduleJob(hprinter
, printer
->doc
->id
);
3985 printer
->doc
= NULL
;
3989 /******************************************************************************
3990 * fpClosePrinter [exported through PRINTPROVIDOR]
3992 * Close a printer handle and free associated resources
3995 * hPrinter [I] Printerhandle to close
4002 static BOOL WINAPI
fpClosePrinter(HANDLE hprinter
)
4004 handle_header_t
*header
= (handle_header_t
*)hprinter
;
4006 TRACE("(%p)\n", hprinter
);
4011 if (header
->type
== HANDLE_SERVER
)
4015 else if (header
->type
== HANDLE_XCV
)
4017 xcv_t
*xcv
= (xcv_t
*)hprinter
;
4019 if (xcv
->hxcv
&& xcv
->pm
->monitor
.pfnXcvClosePort
)
4020 xcv
->pm
->monitor
.pfnXcvClosePort(xcv
->hxcv
);
4022 monitor_unload(xcv
->pm
);
4025 else if (header
->type
== HANDLE_PORT
)
4027 port_t
*port
= (port_t
*)hprinter
;
4030 port
->mon
->monitor
.pfnClosePort(port
->hport
);
4032 monitor_unload(port
->mon
);
4035 else if (header
->type
== HANDLE_JOB
)
4037 job_t
*job
= (job_t
*)hprinter
;
4039 CloseHandle(job
->hf
);
4042 else if (header
->type
== HANDLE_PRINTER
)
4044 printer_t
*printer
= (printer_t
*)hprinter
;
4047 fpEndDocPrinter(hprinter
);
4049 release_printer_info(printer
->info
);
4050 free(printer
->name
);
4051 free(printer
->print_proc
);
4052 free(printer
->datatype
);
4053 free(printer
->devmode
);
4058 ERR("invalid handle type\n");
4064 static BOOL WINAPI
fpSeekPrinter(HANDLE hprinter
, LARGE_INTEGER distance
,
4065 LARGE_INTEGER
*pos
, DWORD method
, BOOL bwrite
)
4067 job_t
*job
= (job_t
*)hprinter
;
4069 TRACE("(%p %I64d %p %lx %x)\n", hprinter
, distance
.QuadPart
, pos
, method
, bwrite
);
4073 SetLastError(ERROR_INVALID_HANDLE
);
4077 if (job
->header
.type
!= HANDLE_JOB
)
4079 FIXME("handle %x not supported\n", job
->header
.type
);
4090 return SetFilePointerEx(job
->hf
, distance
, pos
, method
);
4093 static const PRINTPROVIDOR backend
= {
4097 NULL
, /* fpEnumJobs */
4098 NULL
, /* fpAddPrinter */
4099 NULL
, /* fpDeletePrinter */
4100 NULL
, /* fpSetPrinter */
4101 NULL
, /* fpGetPrinter */
4102 NULL
, /* fpEnumPrinters */
4103 NULL
, /* fpAddPrinterDriver */
4104 NULL
, /* fpEnumPrinterDrivers */
4105 NULL
, /* fpGetPrinterDriver */
4106 fpGetPrinterDriverDirectory
,
4107 NULL
, /* fpDeletePrinterDriver */
4108 fpAddPrintProcessor
,
4109 fpEnumPrintProcessors
,
4110 fpGetPrintProcessorDirectory
,
4111 NULL
, /* fpDeletePrintProcessor */
4112 NULL
, /* fpEnumPrintProcessorDatatypes */
4114 NULL
, /* fpStartPagePrinter */
4116 NULL
, /* fpEndPagePrinter */
4122 NULL
, /* fpGetPrinterData */
4123 NULL
, /* fpSetPrinterData */
4124 NULL
, /* fpWaitForPrinterChange */
4136 NULL
, /* fpCreatePrinterIC */
4137 NULL
, /* fpPlayGdiScriptOnPrinterIC */
4138 NULL
, /* fpDeletePrinterIC */
4139 NULL
, /* fpAddPrinterConnection */
4140 NULL
, /* fpDeletePrinterConnection */
4141 NULL
, /* fpPrinterMessageBox */
4145 NULL
, /* fpGetPrinterDriverEx */
4146 NULL
, /* fpFindFirstPrinterChangeNotification */
4147 NULL
, /* fpFindClosePrinterChangeNotification */
4149 NULL
, /* fpShutDown */
4150 NULL
, /* fpRefreshPrinterChangeNotification */
4151 NULL
, /* fpOpenPrinterEx */
4152 NULL
, /* fpAddPrinterEx */
4153 NULL
, /* fpSetPort */
4154 NULL
, /* fpEnumPrinterData */
4155 NULL
, /* fpDeletePrinterData */
4156 NULL
, /* fpClusterSplOpen */
4157 NULL
, /* fpClusterSplClose */
4158 NULL
, /* fpClusterSplIsAlive */
4159 NULL
, /* fpSetPrinterDataEx */
4160 NULL
, /* fpGetPrinterDataEx */
4161 NULL
, /* fpEnumPrinterDataEx */
4162 NULL
, /* fpEnumPrinterKey */
4163 NULL
, /* fpDeletePrinterDataEx */
4164 NULL
, /* fpDeletePrinterKey */
4166 NULL
, /* fpDeletePrinterDriverEx */
4167 NULL
, /* fpAddPerMachineConnection */
4168 NULL
, /* fpDeletePerMachineConnection */
4169 NULL
, /* fpEnumPerMachineConnections */
4171 fpAddPrinterDriverEx
,
4172 NULL
, /* fpSplReadPrinter */
4173 NULL
, /* fpDriverUnloadComplete */
4174 NULL
, /* fpGetSpoolFileInfo */
4175 NULL
, /* fpCommitSpoolData */
4176 NULL
, /* fpCloseSpoolFileHandle */
4177 NULL
, /* fpFlushPrinter */
4178 NULL
, /* fpSendRecvBidiData */
4179 NULL
/* fpAddDriverCatalog */
4182 /*****************************************************
4183 * InitializePrintProvidor (localspl.@)
4185 * Initialize the Printprovider
4188 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
4189 * cbPrintProvidor [I] Size of Buffer in Bytes
4190 * pFullRegistryPath [I] Registry-Path for the Printprovidor
4193 * Success: TRUE and pPrintProvidor filled
4197 * The RegistryPath should be:
4198 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
4199 * but this Parameter is ignored in "localspl.dll".
4203 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
4204 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
4207 TRACE("(%p, %lu, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
4208 memcpy(pPrintProvidor
, &backend
,
4209 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));