comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / localspl / provider.c
blobca8dc5fbe78b28493533e2f75c7cda41b5e9af26
1 /*
2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "winspool.h"
31 #include "winuser.h"
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
35 #include "wine/debug.h"
36 #include "wine/heap.h"
37 #include "wine/list.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
42 static const struct builtin_form
44 const WCHAR *name;
45 SIZEL size;
46 DWORD res_id;
47 } builtin_forms[] =
49 { L"Letter", { 215900, 279400 }, IDS_FORM_LETTER },
50 { L"Letter Small", { 215900, 279400 }, IDS_FORM_LETTER_SMALL },
51 { L"Tabloid", { 279400, 431800 }, IDS_FORM_TABLOID },
52 { L"Ledger", { 431800, 279400 }, IDS_FORM_LEDGER },
53 { L"Legal", { 215900, 355600 }, IDS_FORM_LEGAL },
54 { L"Statement", { 139700, 215900 }, IDS_FORM_STATEMENT },
55 { L"Executive", { 184150, 266700 }, IDS_FORM_EXECUTIVE },
56 { L"A3", { 297000, 420000 }, IDS_FORM_A3 },
57 { L"A4", { 210000, 297000 }, IDS_FORM_A4 },
58 { L"A4 Small", { 210000, 297000 }, IDS_FORM_A4_SMALL },
59 { L"A5", { 148000, 210000 }, IDS_FORM_A5 },
60 { L"B4 (JIS)", { 257000, 364000 }, IDS_FORM_B4_JIS },
61 { L"B5 (JIS)", { 182000, 257000 }, IDS_FORM_B5_JIS },
62 { L"Folio", { 215900, 330200 }, IDS_FORM_FOLIO },
63 { L"Quarto", { 215000, 275000 }, IDS_FORM_QUARTO },
64 { L"10x14", { 254000, 355600 }, IDS_FORM_10x14 },
65 { L"11x17", { 279400, 431800 }, IDS_FORM_11x17 },
66 { L"Note", { 215900, 279400 }, IDS_FORM_NOTE },
67 { L"Envelope #9", { 98425, 225425 }, IDS_FORM_ENVELOPE_9 },
68 { L"Envelope #10", { 104775, 241300 }, IDS_FORM_ENVELOPE_10 },
69 { L"Envelope #11", { 114300, 263525 }, IDS_FORM_ENVELOPE_11 },
70 { L"Envelope #12", { 120650, 279400 }, IDS_FORM_ENVELOPE_12 },
71 { L"Envelope #14", { 127000, 292100 }, IDS_FORM_ENVELOPE_14 },
72 { L"C size sheet", { 431800, 558800 }, IDS_FORM_C_SIZE_SHEET },
73 { L"D size sheet", { 558800, 863600 }, IDS_FORM_D_SIZE_SHEET },
74 { L"E size sheet", { 863600, 1117600 }, IDS_FORM_E_SIZE_SHEET },
75 { L"Envelope DL", { 110000, 220000 }, IDS_FORM_ENVELOPE_DL },
76 { L"Envelope C5", { 162000, 229000 }, IDS_FORM_ENVELOPE_C5 },
77 { L"Envelope C3", { 324000, 458000 }, IDS_FORM_ENVELOPE_C3 },
78 { L"Envelope C4", { 229000, 324000 }, IDS_FORM_ENVELOPE_C4 },
79 { L"Envelope C6", { 114000, 162000 }, IDS_FORM_ENVELOPE_C6 },
80 { L"Envelope C65", { 114000, 229000 }, IDS_FORM_ENVELOPE_C65 },
81 { L"Envelope B4", { 250000, 353000 }, IDS_FORM_ENVELOPE_B4 },
82 { L"Envelope B5", { 176000, 250000 }, IDS_FORM_ENVELOPE_B5 },
83 { L"Envelope B6", { 176000, 125000 }, IDS_FORM_ENVELOPE_B6 },
84 { L"Envelope", { 110000, 230000 }, IDS_FORM_ENVELOPE },
85 { L"Envelope Monarch", { 98425, 190500 }, IDS_FORM_ENVELOPE_MONARCH },
86 { L"6 3/4 Envelope", { 92075, 165100 }, IDS_FORM_6_34_ENVELOPE },
87 { L"US Std Fanfold", { 377825, 279400 }, IDS_FORM_US_STD_FANFOLD },
88 { L"German Std Fanfold", { 215900, 304800 }, IDS_FORM_GERMAN_STD_FANFOLD },
89 { L"German Legal Fanfold", { 215900, 330200 }, IDS_FORM_GERMAN_LEGAL_FANFOLD },
90 { L"B4 (ISO)", { 250000, 353000 }, IDS_FORM_B4_ISO },
91 { L"Japanese Postcard", { 100000, 148000 }, IDS_FORM_JAPANESE_POSTCARD },
92 { L"9x11", { 228600, 279400 }, IDS_FORM_9x11 },
93 { L"10x11", { 254000, 279400 }, IDS_FORM_10x11 },
94 { L"15x11", { 381000, 279400 }, IDS_FORM_15x11 },
95 { L"Envelope Invite", { 220000, 220000 }, IDS_FORM_ENVELOPE_INVITE },
96 { L"Letter Extra", { 241300, 304800 }, IDS_FORM_LETTER_EXTRA },
97 { L"Legal Extra", { 241300, 381000 }, IDS_FORM_LEGAL_EXTRA },
98 { L"Tabloid Extra", { 304800, 457200 }, IDS_FORM_TABLOID_EXTRA },
99 { L"A4 Extra", { 235458, 322326 }, IDS_FORM_A4_EXTRA },
100 { L"Letter Transverse", { 215900, 279400 }, IDS_FORM_LETTER_TRANSVERSE },
101 { L"A4 Transverse", { 210000, 297000 }, IDS_FORM_A4_TRANSVERSE },
102 { L"Letter Extra Transverse", { 241300, 304800 }, IDS_FORM_LETTER_EXTRA_TRANSVERSE },
103 { L"Super A", { 227000, 356000 }, IDS_FORM_SUPER_A },
104 { L"Super B", { 305000, 487000 }, IDS_FORM_SUPER_B },
105 { L"Letter Plus", { 215900, 322326 }, IDS_FORM_LETTER_PLUS },
106 { L"A4 Plus", { 210000, 330000 }, IDS_FORM_A4_PLUS },
107 { L"A5 Transverse", { 148000, 210000 }, IDS_FORM_A5_TRANSVERSE },
108 { L"B5 (JIS) Transverse", { 182000, 257000 }, IDS_FORM_B5_JIS_TRANSVERSE },
109 { L"A3 Extra", { 322000, 445000 }, IDS_FORM_A3_EXTRA },
110 { L"A5 Extra", { 174000, 235000 }, IDS_FORM_A5_EXTRA },
111 { L"B5 (ISO) Extra", { 201000, 276000 }, IDS_FORM_B5_ISO_EXTRA },
112 { L"A2", { 420000, 594000 }, IDS_FORM_A2 },
113 { L"A3 Transverse", { 297000, 420000 }, IDS_FORM_A3_TRANSVERSE },
114 { L"A3 Extra Transverse", { 322000, 445000 }, IDS_FORM_A3_EXTRA_TRANSVERSE },
115 { L"Japanese Double Postcard", { 200000, 148000 }, IDS_FORM_JAPANESE_DOUBLE_POSTCARD },
116 { L"A6", { 105000, 148000 }, IDS_FORM_A6 },
117 { L"Japanese Envelope Kaku #2", { 240000, 332000 }, IDS_FORM_JAPANESE_ENVELOPE_KAKU_2 },
118 { L"Japanese Envelope Kaku #3", { 216000, 277000 }, IDS_FORM_JAPANESE_ENVELOPE_KAKU_3 },
119 { L"Japanese Envelope Chou #3", { 120000, 235000 }, IDS_FORM_JAPANESE_ENVELOPE_CHOU_3 },
120 { L"Japanese Envelope Chou #4", { 90000, 205000 }, IDS_FORM_JAPANESE_ENVELOPE_CHOU_4 },
121 { L"Letter Rotated", { 279400, 215900 }, IDS_FORM_LETTER_ROTATED },
122 { L"A3 Rotated", { 420000, 297000 }, IDS_FORM_A3_ROTATED },
123 { L"A4 Rotated", { 297000, 210000 }, IDS_FORM_A4_ROTATED },
124 { L"A5 Rotated", { 210000, 148000 }, IDS_FORM_A5_ROTATED },
125 { L"B4 (JIS) Rotated", { 364000, 257000 }, IDS_FORM_B4_JIS_ROTATED },
126 { L"B5 (JIS) Rotated", { 257000, 182000 }, IDS_FORM_B5_JIS_ROTATED },
127 { L"Japanese Postcard Rotated", { 148000, 100000 }, IDS_FORM_JAPANESE_POSTCARD_ROTATED },
128 { L"Double Japan Postcard Rotated", { 148000, 200000 }, IDS_FORM_DOUBLE_JAPAN_POSTCARD_ROTATED },
129 { L"A6 Rotated", { 148000, 105000 }, IDS_FORM_A6_ROTATED },
130 { L"Japan Envelope Kaku #2 Rotated", { 332000, 240000 }, IDS_FORM_JAPAN_ENVELOPE_KAKU_2_ROTATED },
131 { L"Japan Envelope Kaku #3 Rotated", { 277000, 216000 }, IDS_FORM_JAPAN_ENVELOPE_KAKU_3_ROTATED },
132 { L"Japan Envelope Chou #3 Rotated", { 235000, 120000 }, IDS_FORM_JAPAN_ENVELOPE_CHOU_3_ROTATED },
133 { L"Japan Envelope Chou #4 Rotated", { 205000, 90000 }, IDS_FORM_JAPAN_ENVELOPE_CHOU_4_ROTATED },
134 { L"B6 (JIS)", { 128000, 182000 }, IDS_FORM_B6_JIS },
135 { L"B6 (JIS) Rotated", { 182000, 128000 }, IDS_FORM_B6_JIS_ROTATED },
136 { L"12x11", { 304932, 279521 }, IDS_FORM_12x11 },
137 { L"Japan Envelope You #4", { 105000, 235000 }, IDS_FORM_JAPAN_ENVELOPE_YOU_4 },
138 { L"Japan Envelope You #4 Rotated", { 235000, 105000 }, IDS_FORM_JAPAN_ENVELOPE_YOU_4_ROTATED },
139 { L"PRC 16K", { 188000, 260000 }, IDS_FORM_PRC_16K },
140 { L"PRC 32K", { 130000, 184000 }, IDS_FORM_PRC_32K },
141 { L"PRC 32K(Big)", { 140000, 203000 }, IDS_FORM_PRC_32K_BIG },
142 { L"PRC Envelope #1", { 102000, 165000 }, IDS_FORM_PRC_ENVELOPE_1 },
143 { L"PRC Envelope #2", { 102000, 176000 }, IDS_FORM_PRC_ENVELOPE_2 },
144 { L"PRC Envelope #3", { 125000, 176000 }, IDS_FORM_PRC_ENVELOPE_3 },
145 { L"PRC Envelope #4", { 110000, 208000 }, IDS_FORM_PRC_ENVELOPE_4 },
146 { L"PRC Envelope #5", { 110000, 220000 }, IDS_FORM_PRC_ENVELOPE_5 },
147 { L"PRC Envelope #6", { 120000, 230000 }, IDS_FORM_PRC_ENVELOPE_6 },
148 { L"PRC Envelope #7", { 160000, 230000 }, IDS_FORM_PRC_ENVELOPE_7 },
149 { L"PRC Envelope #8", { 120000, 309000 }, IDS_FORM_PRC_ENVELOPE_8 },
150 { L"PRC Envelope #9", { 229000, 324000 }, IDS_FORM_PRC_ENVELOPE_9 },
151 { L"PRC Envelope #10", { 324000, 458000 }, IDS_FORM_PRC_ENVELOPE_10 },
152 { L"PRC 16K Rotated", { 260000, 188000 }, IDS_FORM_PRC_16K_ROTATED },
153 { L"PRC 32K Rotated", { 184000, 130000 }, IDS_FORM_PRC_32K_ROTATED },
154 { L"PRC 32K(Big) Rotated", { 203000, 140000 }, IDS_FORM_PRC_32K_BIG_ROTATED },
155 { L"PRC Envelope #1 Rotated", { 165000, 102000 }, IDS_FORM_PRC_ENVELOPE_1_ROTATED },
156 { L"PRC Envelope #2 Rotated", { 176000, 102000 }, IDS_FORM_PRC_ENVELOPE_2_ROTATED },
157 { L"PRC Envelope #3 Rotated", { 176000, 125000 }, IDS_FORM_PRC_ENVELOPE_3_ROTATED },
158 { L"PRC Envelope #4 Rotated", { 208000, 110000 }, IDS_FORM_PRC_ENVELOPE_4_ROTATED },
159 { L"PRC Envelope #5 Rotated", { 220000, 110000 }, IDS_FORM_PRC_ENVELOPE_5_ROTATED },
160 { L"PRC Envelope #6 Rotated", { 230000, 120000 }, IDS_FORM_PRC_ENVELOPE_6_ROTATED },
161 { L"PRC Envelope #7 Rotated", { 230000, 160000 }, IDS_FORM_PRC_ENVELOPE_7_ROTATED },
162 { L"PRC Envelope #8 Rotated", { 309000, 120000 }, IDS_FORM_PRC_ENVELOPE_8_ROTATED },
163 { L"PRC Envelope #9 Rotated", { 324000, 229000 }, IDS_FORM_PRC_ENVELOPE_9_ROTATED },
164 { L"PRC Envelope #10 Rotated", { 458000, 324000 }, IDS_FORM_PRC_ENVELOPE_10_ROTATED }
168 /* ############################### */
170 static CRITICAL_SECTION monitor_handles_cs;
171 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
173 0, 0, &monitor_handles_cs,
174 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
175 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
177 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
179 /* ############################### */
181 typedef struct {
182 WCHAR src[MAX_PATH+MAX_PATH];
183 WCHAR dst[MAX_PATH+MAX_PATH];
184 DWORD srclen;
185 DWORD dstlen;
186 DWORD copyflags;
187 BOOL lazy;
188 } apd_data_t;
190 typedef struct {
191 struct list entry;
192 LPWSTR name;
193 LPWSTR dllname;
194 PMONITORUI monitorUI;
195 MONITOR2 monitor;
196 BOOL (WINAPI *old_EnumPorts)(LPWSTR,DWORD,LPBYTE,DWORD,LPDWORD,LPDWORD);
197 BOOL (WINAPI *old_OpenPort)(LPWSTR,PHANDLE);
198 BOOL (WINAPI *old_OpenPortEx)(LPWSTR,LPWSTR,PHANDLE,struct _MONITOR *);
199 BOOL (WINAPI *old_AddPort)(LPWSTR,HWND,LPWSTR);
200 BOOL (WINAPI *old_AddPortEx)(LPWSTR,DWORD,LPBYTE,LPWSTR);
201 BOOL (WINAPI *old_ConfigurePort)(LPWSTR,HWND,LPWSTR);
202 BOOL (WINAPI *old_DeletePort)(LPWSTR,HWND,LPWSTR);
203 BOOL (WINAPI *old_XcvOpenPort)(LPCWSTR,ACCESS_MASK,PHANDLE);
204 HANDLE hmon;
205 HMODULE hdll;
206 DWORD refcount;
207 } monitor_t;
209 typedef struct {
210 LPCWSTR envname;
211 LPCWSTR subdir;
212 DWORD driverversion;
213 LPCWSTR versionregpath;
214 LPCWSTR versionsubdir;
215 } printenv_t;
217 typedef struct {
218 LPWSTR name;
219 LPWSTR printername;
220 monitor_t * pm;
221 HANDLE hXcv;
222 } printer_t;
224 /* ############################### */
226 static struct list monitor_handles = LIST_INIT( monitor_handles );
227 static monitor_t * pm_localport;
229 static const WCHAR fmt_driversW[] =
230 L"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
231 static const WCHAR fmt_printprocessorsW[] =
232 L"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors";
233 static const WCHAR monitorsW[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
234 static const WCHAR printersW[] = L"System\\CurrentControlSet\\Control\\Print\\Printers";
235 static const WCHAR winnt_cv_portsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
236 static const WCHAR x86_envnameW[] = L"Windows NT x86";
239 static const printenv_t env_ia64 = {L"Windows IA64", L"ia64", 3,
240 L"\\Version-3", L"\\3"};
242 static const printenv_t env_x86 = {x86_envnameW, L"w32x86", 3,
243 L"\\Version-3", L"\\3"};
245 static const printenv_t env_x64 = {L"Windows x64", L"x64", 3,
246 L"\\Version-3", L"\\3"};
248 static const printenv_t env_arm = {L"Windows ARM", L"arm", 3,
249 L"\\Version-3", L"\\3"};
251 static const printenv_t env_arm64 = {L"Windows ARM64", L"arm64", 3,
252 L"\\Version-3", L"\\3"};
254 static const printenv_t env_win40 = {L"Windows 4.0", L"win40", 0,
255 L"\\Version-0", L"\\0"};
257 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_arm, &env_arm64, &env_win40};
259 #ifdef __i386__
260 #define env_arch env_x86
261 #elif defined __x86_64__
262 #define env_arch env_x64
263 #elif defined __arm__
264 #define env_arch env_arm
265 #elif defined __aarch64__
266 #define env_arch env_arm64
267 #else
268 #error not defined for this cpu
269 #endif
272 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
273 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
274 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
275 0, sizeof(DRIVER_INFO_8W)};
278 /******************************************************************
279 * strdupW [internal]
281 * create a copy of a unicode-string
284 static LPWSTR strdupW(LPCWSTR p)
286 LPWSTR ret;
287 DWORD len;
289 if(!p) return NULL;
290 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
291 ret = heap_alloc(len);
292 if (ret) memcpy(ret, p, len);
293 return ret;
296 /******************************************************************
297 * apd_copyfile [internal]
299 * Copy a file from the driverdirectory to the versioned directory
301 * RETURNS
302 * Success: TRUE
303 * Failure: FALSE
306 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
308 WCHAR *srcname;
309 BOOL res;
311 apd->src[apd->srclen] = '\0';
312 apd->dst[apd->dstlen] = '\0';
314 if (!pathname || !pathname[0]) {
315 /* nothing to copy */
316 return TRUE;
319 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
320 srcname = pathname;
321 else
323 srcname = apd->src;
324 lstrcatW( srcname, file_part );
326 lstrcatW( apd->dst, file_part );
328 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
330 /* FIXME: handle APD_COPY_NEW_FILES */
331 res = CopyFileW(srcname, apd->dst, FALSE);
332 TRACE("got %d with %lu\n", res, GetLastError());
334 return apd->lazy || res;
337 /******************************************************************
338 * copy_servername_from_name (internal)
340 * for an external server, the serverpart from the name is copied.
342 * RETURNS
343 * the length (in WCHAR) of the serverpart (0 for the local computer)
344 * (-length), when the name is too long
347 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
349 LPCWSTR server;
350 LPWSTR ptr;
351 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
352 DWORD len;
353 DWORD serverlen;
355 if (target) *target = '\0';
357 if (name == NULL) return 0;
358 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
360 server = &name[2];
361 /* skip over both backslash, find separator '\' */
362 ptr = wcschr(server, '\\');
363 serverlen = (ptr) ? ptr - server : lstrlenW(server);
365 /* servername is empty */
366 if (serverlen == 0) return 0;
368 TRACE("found %s\n", debugstr_wn(server, serverlen));
370 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
372 if (target) {
373 memcpy(target, server, serverlen * sizeof(WCHAR));
374 target[serverlen] = '\0';
377 len = ARRAY_SIZE(buffer);
378 if (GetComputerNameW(buffer, &len)) {
379 if ((serverlen == len) && (wcsnicmp(server, buffer, len) == 0)) {
380 /* The requested Servername is our computername */
381 return 0;
384 return serverlen;
387 /******************************************************************
388 * get_basename_from_name (internal)
390 * skip over the serverpart from the full name
393 static LPCWSTR get_basename_from_name(LPCWSTR name)
395 if (name == NULL) return NULL;
396 if ((name[0] == '\\') && (name[1] == '\\')) {
397 /* skip over the servername and search for the following '\' */
398 name = wcschr(&name[2], '\\');
399 if ((name) && (name[1])) {
400 /* found a separator ('\') followed by a name:
401 skip over the separator and return the rest */
402 name++;
404 else
406 /* no basename present (we found only a servername) */
407 return NULL;
410 return name;
413 /******************************************************************
414 * monitor_unload [internal]
416 * release a printmonitor and unload it from memory, when needed
419 static void monitor_unload(monitor_t * pm)
421 if (pm == NULL) return;
422 TRACE("%p (refcount: %ld) %s\n", pm, pm->refcount, debugstr_w(pm->name));
424 EnterCriticalSection(&monitor_handles_cs);
426 if (pm->refcount) pm->refcount--;
428 if (pm->refcount == 0) {
429 list_remove(&pm->entry);
431 if (pm->monitor.pfnShutdown)
432 pm->monitor.pfnShutdown(pm->hmon);
434 FreeLibrary(pm->hdll);
435 heap_free(pm->name);
436 heap_free(pm->dllname);
437 heap_free(pm);
439 LeaveCriticalSection(&monitor_handles_cs);
442 /******************************************************************
443 * monitor_unloadall [internal]
445 * release all registered printmonitors and unload them from memory, when needed
449 static void monitor_unloadall(void)
451 monitor_t * pm;
452 monitor_t * next;
454 EnterCriticalSection(&monitor_handles_cs);
455 /* iterate through the list, with safety against removal */
456 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
458 /* skip monitorui dlls */
459 if (pm->monitor.cbSize) monitor_unload(pm);
461 LeaveCriticalSection(&monitor_handles_cs);
464 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
465 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
466 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
468 FIXME("stub\n");
469 return ERROR_CALL_NOT_IMPLEMENTED;
472 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
473 PHANDLE phkResult, HANDLE hSpooler)
475 FIXME("stub\n");
476 return ERROR_CALL_NOT_IMPLEMENTED;
479 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
481 FIXME("stub\n");
482 return ERROR_CALL_NOT_IMPLEMENTED;
485 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
487 FIXME("stub\n");
488 return ERROR_CALL_NOT_IMPLEMENTED;
491 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
492 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
494 FIXME("stub\n");
495 return ERROR_CALL_NOT_IMPLEMENTED;
498 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
499 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
500 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
501 HANDLE hSpooler)
503 FIXME("stub\n");
504 return ERROR_CALL_NOT_IMPLEMENTED;
507 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
508 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
510 FIXME("stub\n");
511 return ERROR_CALL_NOT_IMPLEMENTED;
514 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
516 FIXME("stub\n");
517 return ERROR_CALL_NOT_IMPLEMENTED;
520 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
521 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
522 HANDLE hSpooler)
524 FIXME("stub\n");
525 return ERROR_CALL_NOT_IMPLEMENTED;
528 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
529 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
531 FIXME("stub\n");
532 return ERROR_CALL_NOT_IMPLEMENTED;
535 static MONITORREG monreg =
537 sizeof(MONITORREG),
538 CreateKey,
539 OpenKey,
540 CloseKey,
541 DeleteKey,
542 EnumKey,
543 QueryInfoKey,
544 SetValue,
545 DeleteValue,
546 EnumValue,
547 QueryValue
550 /******************************************************************
551 * monitor_load [internal]
553 * load a printmonitor, get the dllname from the registry, when needed
554 * initialize the monitor and dump found function-pointers
556 * On failure, SetLastError() is called and NULL is returned
559 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
561 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
562 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
563 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
564 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
565 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
567 monitor_t * pm = NULL;
568 monitor_t * cursor;
569 LPWSTR regroot = NULL;
570 LPWSTR driver = dllname;
571 HKEY hroot = 0;
573 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
574 /* Is the Monitor already loaded? */
575 EnterCriticalSection(&monitor_handles_cs);
577 if (name) {
578 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
580 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
581 pm = cursor;
582 break;
587 if (pm == NULL) {
588 pm = heap_alloc_zero(sizeof(monitor_t));
589 if (pm == NULL) goto cleanup;
590 list_add_tail(&monitor_handles, &pm->entry);
592 pm->refcount++;
594 if (pm->name == NULL) {
595 /* Load the monitor */
596 DWORD len;
598 if (name) {
599 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
600 regroot = heap_alloc(len * sizeof(WCHAR));
603 if (regroot) {
604 lstrcpyW(regroot, monitorsW);
605 lstrcatW(regroot, name);
606 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
607 /* Get the Driver from the Registry */
608 if (driver == NULL) {
609 DWORD namesize;
610 if (RegQueryValueExW(hroot, L"Driver", NULL, NULL, NULL,
611 &namesize) == ERROR_SUCCESS) {
612 driver = heap_alloc(namesize);
613 RegQueryValueExW(hroot, L"Driver", NULL, NULL, (BYTE*)driver, &namesize);
617 else
618 WARN("%s not found\n", debugstr_w(regroot));
621 pm->name = strdupW(name);
622 pm->dllname = strdupW(driver);
624 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
625 monitor_unload(pm);
626 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
627 pm = NULL;
628 goto cleanup;
631 pm->hdll = LoadLibraryW(driver);
632 TRACE("%p: LoadLibrary(%s) => %ld\n", pm->hdll, debugstr_w(driver), GetLastError());
634 if (pm->hdll == NULL) {
635 monitor_unload(pm);
636 SetLastError(ERROR_MOD_NOT_FOUND);
637 pm = NULL;
638 goto cleanup;
641 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
642 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
643 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
644 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
645 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
648 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
649 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
650 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
651 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
652 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
654 if (pInitializePrintMonitorUI != NULL) {
655 pm->monitorUI = pInitializePrintMonitorUI();
656 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
657 if (pm->monitorUI) {
658 TRACE("0x%08lx: dwMonitorSize (%ld)\n",
659 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
664 if (pInitializePrintMonitor2 && hroot) {
665 MONITORINIT init;
666 MONITOR2 *monitor2;
667 HANDLE hmon;
669 memset(&init, 0, sizeof(init));
670 init.cbSize = sizeof(init);
671 init.hckRegistryRoot = hroot;
672 init.pMonitorReg = &monreg;
673 init.bLocal = TRUE;
675 monitor2 = pInitializePrintMonitor2(&init, &hmon);
676 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
677 monitor2, debugstr_w(driver), debugstr_w(regroot));
678 if (monitor2)
680 memcpy(&pm->monitor, monitor2, min(monitor2->cbSize, sizeof(pm->monitor)));
681 pm->hmon = hmon;
684 else if (pInitializePrintMonitor && regroot) {
685 MONITOREX *pmonitorEx;
687 pmonitorEx = pInitializePrintMonitor(regroot);
688 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
689 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
690 if (pmonitorEx)
692 /* Layout of MONITOREX and MONITOR2 mostly matches */
693 memcpy(&pm->monitor, pmonitorEx, min(pmonitorEx->dwMonitorSize + sizeof(void *), sizeof(pm->monitor)));
694 /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */
695 pm->monitor.cbSize += sizeof(void *);
697 pm->old_EnumPorts = pmonitorEx->Monitor.pfnEnumPorts;
698 pm->old_OpenPort = pmonitorEx->Monitor.pfnOpenPort;
699 pm->old_OpenPortEx = pmonitorEx->Monitor.pfnOpenPortEx;
700 pm->old_AddPort = pmonitorEx->Monitor.pfnAddPort;
701 pm->old_AddPortEx = pmonitorEx->Monitor.pfnAddPortEx;
702 pm->old_ConfigurePort = pmonitorEx->Monitor.pfnConfigurePort;
703 pm->old_DeletePort = pmonitorEx->Monitor.pfnDeletePort;
704 pm->old_XcvOpenPort = pmonitorEx->Monitor.pfnXcvOpenPort;
706 pm->monitor.pfnEnumPorts = NULL;
707 pm->monitor.pfnOpenPort = NULL;
708 pm->monitor.pfnOpenPortEx = NULL;
709 pm->monitor.pfnAddPort = NULL;
710 pm->monitor.pfnAddPortEx = NULL;
711 pm->monitor.pfnConfigurePort = NULL;
712 pm->monitor.pfnDeletePort = NULL;
713 pm->monitor.pfnXcvOpenPort = NULL;
717 if (!pm->monitor.cbSize && regroot) {
718 if (pInitializeMonitorEx != NULL) {
719 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
721 if (pInitializeMonitor != NULL) {
722 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
725 if (!pm->monitor.cbSize && !pm->monitorUI) {
726 monitor_unload(pm);
727 SetLastError(ERROR_PROC_NOT_FOUND);
728 pm = NULL;
731 cleanup:
732 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, L"Local Port") == 0)) {
733 pm->refcount++;
734 pm_localport = pm;
736 LeaveCriticalSection(&monitor_handles_cs);
737 if (driver != dllname) heap_free(driver);
738 if (hroot) RegCloseKey(hroot);
739 heap_free(regroot);
740 TRACE("=> %p\n", pm);
741 return pm;
744 /******************************************************************
745 * monitor_loadall [internal]
747 * Load all registered monitors
750 static DWORD monitor_loadall(void)
752 monitor_t * pm;
753 DWORD registered = 0;
754 DWORD loaded = 0;
755 HKEY hmonitors;
756 WCHAR buffer[MAX_PATH];
757 DWORD id = 0;
759 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
760 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
761 NULL, NULL, NULL, NULL, NULL);
763 TRACE("%ld monitors registered\n", registered);
765 while (id < registered) {
766 buffer[0] = '\0';
767 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
768 pm = monitor_load(buffer, NULL);
769 if (pm) loaded++;
770 id++;
772 RegCloseKey(hmonitors);
774 TRACE("%ld monitors loaded\n", loaded);
775 return loaded;
778 /******************************************************************
779 * monitor_loadui [internal]
781 * load the userinterface-dll for a given portmonitor
783 * On failure, NULL is returned
785 static monitor_t * monitor_loadui(monitor_t * pm)
787 monitor_t * pui = NULL;
788 WCHAR buffer[MAX_PATH];
789 HANDLE hXcv;
790 DWORD len;
791 DWORD res = 0;
793 if (pm == NULL) return NULL;
794 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
796 /* Try the Portmonitor first; works for many monitors */
797 if (pm->monitorUI) {
798 EnterCriticalSection(&monitor_handles_cs);
799 pm->refcount++;
800 LeaveCriticalSection(&monitor_handles_cs);
801 return pm;
804 /* query the userinterface-dllname from the Portmonitor */
805 /* building (",XcvMonitor %s",pm->name) not needed yet */
806 if (pm->monitor.pfnXcvOpenPort)
807 res = pm->monitor.pfnXcvOpenPort(pm->hmon, L"", SERVER_ACCESS_ADMINISTER, &hXcv);
808 else if (pm->old_XcvOpenPort)
809 res = pm->old_XcvOpenPort(L"", SERVER_ACCESS_ADMINISTER, &hXcv);
810 TRACE("got %lu with %p\n", res, hXcv);
811 if (res) {
812 res = pm->monitor.pfnXcvDataPort(hXcv, L"MonitorUI", NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
813 TRACE("got %lu with %s\n", res, debugstr_w(buffer));
814 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
815 pm->monitor.pfnXcvClosePort(hXcv);
817 return pui;
820 /******************************************************************
821 * monitor_load_by_port [internal]
823 * load a printmonitor for a given port
825 * On failure, NULL is returned
828 static monitor_t * monitor_load_by_port(LPCWSTR portname)
830 HKEY hroot;
831 HKEY hport;
832 LPWSTR buffer;
833 monitor_t * pm = NULL;
834 DWORD registered = 0;
835 DWORD id = 0;
836 DWORD len;
838 TRACE("(%s)\n", debugstr_w(portname));
840 /* Try the Local Monitor first */
841 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
842 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
843 /* found the portname */
844 RegCloseKey(hroot);
845 return monitor_load(L"Local Port", NULL);
847 RegCloseKey(hroot);
850 len = MAX_PATH + lstrlenW(L"\\Ports\\") + lstrlenW(portname) + 1;
851 buffer = heap_alloc(len * sizeof(WCHAR));
852 if (buffer == NULL) return NULL;
854 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
855 EnterCriticalSection(&monitor_handles_cs);
856 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
858 while ((pm == NULL) && (id < registered)) {
859 buffer[0] = '\0';
860 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
861 TRACE("testing %s\n", debugstr_w(buffer));
862 len = lstrlenW(buffer);
863 lstrcatW(buffer, L"\\Ports\\");
864 lstrcatW(buffer, portname);
865 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
866 RegCloseKey(hport);
867 buffer[len] = '\0'; /* use only the Monitor-Name */
868 pm = monitor_load(buffer, NULL);
870 id++;
872 LeaveCriticalSection(&monitor_handles_cs);
873 RegCloseKey(hroot);
875 heap_free(buffer);
876 return pm;
879 /******************************************************************
880 * Return the number of bytes for an multi_sz string.
881 * The result includes all \0s
882 * (specifically the extra \0, that is needed as multi_sz terminator).
884 static int multi_sz_lenW(const WCHAR *str)
886 const WCHAR *ptr = str;
887 if (!str) return 0;
890 ptr += lstrlenW(ptr) + 1;
891 } while (*ptr);
893 return (ptr - str + 1) * sizeof(WCHAR);
896 /******************************************************************
897 * validate_envW [internal]
899 * validate the user-supplied printing-environment
901 * PARAMS
902 * env [I] PTR to Environment-String or NULL
904 * RETURNS
905 * Success: PTR to printenv_t
906 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
908 * NOTES
909 * An empty string is handled the same way as NULL.
913 static const printenv_t * validate_envW(LPCWSTR env)
915 const printenv_t *result = NULL;
916 unsigned int i;
918 TRACE("(%s)\n", debugstr_w(env));
919 if (env && env[0])
921 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
923 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
925 result = all_printenv[i];
926 break;
929 if (result == NULL) {
930 FIXME("unsupported Environment: %s\n", debugstr_w(env));
931 SetLastError(ERROR_INVALID_ENVIRONMENT);
933 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
935 else
937 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_arch;
940 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
941 return result;
944 /*****************************************************************************
945 * enumerate the local monitors (INTERNAL)
947 * returns the needed size (in bytes) for pMonitors
948 * and *lpreturned is set to number of entries returned in pMonitors
950 * Language-Monitors are also installed in the same Registry-Location but
951 * they are filtered in Windows (not returned by EnumMonitors).
952 * We do no filtering to simplify our Code.
955 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
957 HKEY hroot = NULL;
958 HKEY hentry = NULL;
959 LPWSTR ptr;
960 LPMONITOR_INFO_2W mi;
961 WCHAR buffer[MAX_PATH];
962 WCHAR dllname[MAX_PATH];
963 DWORD dllsize;
964 DWORD len;
965 DWORD index = 0;
966 DWORD needed = 0;
967 DWORD numentries;
968 DWORD entrysize;
970 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
972 numentries = *lpreturned; /* this is 0, when we scan the registry */
973 len = entrysize * numentries;
974 ptr = (LPWSTR) &pMonitors[len];
976 numentries = 0;
977 len = ARRAY_SIZE(buffer);
978 buffer[0] = '\0';
980 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
981 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
982 /* Scan all Monitor-Registry-Keys */
983 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
984 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
985 dllsize = sizeof(dllname);
986 dllname[0] = '\0';
988 /* The Monitor must have a Driver-DLL */
989 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
990 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
991 /* We found a valid DLL for this Monitor. */
992 TRACE("using Driver: %s\n", debugstr_w(dllname));
994 RegCloseKey(hentry);
997 /* Windows returns only Port-Monitors here, but to simplify our code,
998 we do no filtering for Language-Monitors */
999 if (dllname[0]) {
1000 numentries++;
1001 needed += entrysize;
1002 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
1003 if (level > 1) {
1004 /* we install and return only monitors for "Windows NT x86" */
1005 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
1006 needed += dllsize;
1009 /* required size is calculated. Now fill the user-buffer */
1010 if (pMonitors && (cbBuf >= needed)){
1011 mi = (LPMONITOR_INFO_2W) pMonitors;
1012 pMonitors += entrysize;
1014 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
1015 mi->pName = ptr;
1016 lstrcpyW(ptr, buffer); /* Name of the Monitor */
1017 ptr += (len+1); /* len is lstrlenW(monitorname) */
1018 if (level > 1) {
1019 mi->pEnvironment = ptr;
1020 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
1021 ptr += (lstrlenW(x86_envnameW)+1);
1023 mi->pDLLName = ptr;
1024 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
1025 ptr += (dllsize / sizeof(WCHAR));
1029 index++;
1030 len = ARRAY_SIZE(buffer);
1031 buffer[0] = '\0';
1033 RegCloseKey(hroot);
1035 *lpreturned = numentries;
1036 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1037 return needed;
1040 /*****************************************************************************
1041 * enumerate the local print processors (INTERNAL)
1043 * returns the needed size (in bytes) for pPPInfo
1044 * and *lpreturned is set to number of entries returned in pPPInfo
1047 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
1049 HKEY hroot = NULL;
1050 HKEY hentry = NULL;
1051 LPWSTR ptr;
1052 PPRINTPROCESSOR_INFO_1W ppi;
1053 WCHAR buffer[MAX_PATH];
1054 WCHAR dllname[MAX_PATH];
1055 DWORD dllsize;
1056 DWORD len;
1057 DWORD index = 0;
1058 DWORD needed = 0;
1059 DWORD numentries;
1061 numentries = *lpreturned; /* this is 0, when we scan the registry */
1062 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
1063 ptr = (LPWSTR) &pPPInfo[len];
1065 numentries = 0;
1066 len = ARRAY_SIZE(buffer);
1067 buffer[0] = '\0';
1069 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
1070 /* add "winprint" first */
1071 numentries++;
1072 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(L"winprint");
1073 if (pPPInfo && (cbBuf >= needed)){
1074 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1075 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1077 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1078 ppi->pName = ptr;
1079 lstrcpyW(ptr, L"winprint"); /* Name of the Print Processor */
1080 ptr += ARRAY_SIZE(L"winprint");
1083 /* Scan all Printprocessor Keys */
1084 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
1085 (lstrcmpiW(buffer, L"winprint") != 0)) {
1086 TRACE("PrintProcessor_%ld: %s\n", numentries, debugstr_w(buffer));
1087 dllsize = sizeof(dllname);
1088 dllname[0] = '\0';
1090 /* The Print Processor must have a Driver-DLL */
1091 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
1092 if (RegQueryValueExW(hentry, L"Driver", NULL, NULL, (BYTE*)dllname, &dllsize) == ERROR_SUCCESS) {
1093 /* We found a valid DLL for this Print Processor */
1094 TRACE("using Driver: %s\n", debugstr_w(dllname));
1096 RegCloseKey(hentry);
1099 if (dllname[0]) {
1100 numentries++;
1101 needed += sizeof(PRINTPROCESSOR_INFO_1W);
1102 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
1104 /* required size is calculated. Now fill the user-buffer */
1105 if (pPPInfo && (cbBuf >= needed)){
1106 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
1107 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
1109 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%ld\n", ppi, numentries);
1110 ppi->pName = ptr;
1111 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
1112 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
1115 index++;
1116 len = ARRAY_SIZE(buffer);
1117 buffer[0] = '\0';
1119 RegCloseKey(hroot);
1121 *lpreturned = numentries;
1122 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1123 return needed;
1126 static BOOL wrap_EnumPorts(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer,
1127 DWORD size, LPDWORD needed, LPDWORD returned)
1129 if (pm->monitor.pfnEnumPorts)
1130 return pm->monitor.pfnEnumPorts(pm->hmon, name, level, buffer, size, needed, returned);
1132 if (pm->old_EnumPorts)
1133 return pm->old_EnumPorts(name, level, buffer, size, needed, returned);
1135 WARN("EnumPorts is not implemented by monitor\n");
1136 return FALSE;
1139 /******************************************************************
1140 * enumerate the local Ports from all loaded monitors (internal)
1142 * returns the needed size (in bytes) for pPorts
1143 * and *lpreturned is set to number of entries returned in pPorts
1146 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1148 monitor_t * pm;
1149 LPWSTR ptr;
1150 LPPORT_INFO_2W cache;
1151 LPPORT_INFO_2W out;
1152 LPBYTE pi_buffer = NULL;
1153 DWORD pi_allocated = 0;
1154 DWORD pi_needed;
1155 DWORD pi_index;
1156 DWORD pi_returned;
1157 DWORD res;
1158 DWORD outindex = 0;
1159 DWORD needed;
1160 DWORD numentries;
1161 DWORD entrysize;
1163 TRACE("(%ld, %p, %ld, %p)\n", level, pPorts, cbBuf, lpreturned);
1164 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1166 numentries = *lpreturned; /* this is 0, when we scan the registry */
1167 needed = entrysize * numentries;
1168 ptr = (LPWSTR) &pPorts[needed];
1170 numentries = 0;
1171 needed = 0;
1173 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1175 if (pm->monitor.pfnEnumPorts || pm->old_EnumPorts) {
1176 pi_needed = 0;
1177 pi_returned = 0;
1178 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1179 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1180 /* Do not use heap_realloc (we do not need the old data in the buffer) */
1181 heap_free(pi_buffer);
1182 pi_buffer = heap_alloc(pi_needed);
1183 pi_allocated = (pi_buffer) ? pi_needed : 0;
1184 res = wrap_EnumPorts(pm, NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1186 TRACE("(%s) got %ld with %ld (need %ld byte for %ld entries)\n",
1187 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1189 numentries += pi_returned;
1190 needed += pi_needed;
1192 /* fill the output-buffer (pPorts), if we have one */
1193 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1194 pi_index = 0;
1195 while (pi_returned > pi_index) {
1196 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1197 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1198 out->pPortName = ptr;
1199 lstrcpyW(ptr, cache->pPortName);
1200 ptr += (lstrlenW(ptr)+1);
1201 if (level > 1) {
1202 out->pMonitorName = ptr;
1203 lstrcpyW(ptr, cache->pMonitorName);
1204 ptr += (lstrlenW(ptr)+1);
1206 out->pDescription = ptr;
1207 lstrcpyW(ptr, cache->pDescription);
1208 ptr += (lstrlenW(ptr)+1);
1209 out->fPortType = cache->fPortType;
1210 out->Reserved = cache->Reserved;
1212 pi_index++;
1213 outindex++;
1218 /* the temporary portinfo-buffer is no longer needed */
1219 heap_free(pi_buffer);
1221 *lpreturned = numentries;
1222 TRACE("need %ld byte for %ld entries\n", needed, numentries);
1223 return needed;
1227 /*****************************************************************************
1228 * open_driver_reg [internal]
1230 * opens the registry for the printer drivers depending on the given input
1231 * variable pEnvironment
1233 * RETURNS:
1234 * Success: the opened hkey
1235 * Failure: NULL
1237 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1239 HKEY retval = NULL;
1240 LPWSTR buffer;
1241 const printenv_t * env;
1243 TRACE("(%s)\n", debugstr_w(pEnvironment));
1245 env = validate_envW(pEnvironment);
1246 if (!env) return NULL;
1248 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1249 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1251 if (buffer) {
1252 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1253 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1254 HeapFree(GetProcessHeap(), 0, buffer);
1256 return retval;
1259 /*****************************************************************************
1260 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1262 * Return the PATH for the Printer-Drivers
1264 * PARAMS
1265 * pName [I] Servername (NT only) or NULL (local Computer)
1266 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1267 * Level [I] Structure-Level (must be 1)
1268 * pDriverDirectory [O] PTR to Buffer that receives the Result
1269 * cbBuf [I] Size of Buffer at pDriverDirectory
1270 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1271 * required for pDriverDirectory
1273 * RETURNS
1274 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1275 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1276 * if cbBuf is too small
1278 * Native Values returned in pDriverDirectory on Success:
1279 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1280 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1281 *| win9x(Windows 4.0): "%winsysdir%"
1283 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1286 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1287 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1289 DWORD needed;
1290 const printenv_t * env;
1291 WCHAR * const dir = (WCHAR *)pDriverDirectory;
1293 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
1294 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1296 if (pName != NULL && pName[0]) {
1297 FIXME("server %s not supported\n", debugstr_w(pName));
1298 SetLastError(ERROR_INVALID_PARAMETER);
1299 return FALSE;
1302 env = validate_envW(pEnvironment);
1303 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1306 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1307 needed = GetSystemDirectoryW(NULL, 0);
1308 /* add the Size for the Subdirectories */
1309 needed += lstrlenW(L"\\spool");
1310 needed += lstrlenW(L"\\drivers\\");
1311 needed += lstrlenW(env->subdir);
1312 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1314 *pcbNeeded = needed;
1316 if (needed > cbBuf) {
1317 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1318 return FALSE;
1321 if (dir == NULL) {
1322 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1323 SetLastError(ERROR_INVALID_USER_BUFFER);
1324 return FALSE;
1327 GetSystemDirectoryW( dir, cbBuf / sizeof(WCHAR) );
1328 /* add the Subdirectories */
1329 lstrcatW( dir, L"\\spool" );
1330 CreateDirectoryW( dir, NULL );
1331 lstrcatW( dir, L"\\drivers\\" );
1332 CreateDirectoryW( dir, NULL );
1333 lstrcatW( dir, env->subdir );
1334 CreateDirectoryW( dir, NULL );
1336 TRACE( "=> %s\n", debugstr_w( dir ) );
1337 return TRUE;
1340 /******************************************************************
1341 * driver_load [internal]
1343 * load a driver user interface dll
1345 * On failure, NULL is returned
1349 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1351 WCHAR fullname[MAX_PATH];
1352 HMODULE hui;
1353 DWORD len;
1355 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1357 /* build the driverdir */
1358 len = sizeof(fullname) -
1359 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1361 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1362 (LPBYTE) fullname, len, &len)) {
1363 /* Should never fail */
1364 SetLastError(ERROR_BUFFER_OVERFLOW);
1365 return NULL;
1368 lstrcatW(fullname, env->versionsubdir);
1369 lstrcatW(fullname, L"\\");
1370 lstrcatW(fullname, dllname);
1372 hui = LoadLibraryW(fullname);
1373 TRACE("%p: LoadLibrary(%s) %ld\n", hui, debugstr_w(fullname), GetLastError());
1375 return hui;
1378 /******************************************************************
1379 * printer_free
1380 * free the data pointer of an opened printer
1382 static VOID printer_free(printer_t * printer)
1384 if (printer->hXcv)
1386 if (printer->pm->monitor.pfnXcvClosePort)
1387 printer->pm->monitor.pfnXcvClosePort(printer->hXcv);
1390 monitor_unload(printer->pm);
1392 heap_free(printer->printername);
1393 heap_free(printer->name);
1394 heap_free(printer);
1397 /******************************************************************
1398 * printer_alloc_handle
1399 * alloc a printer handle and remember the data pointer in the printer handle table
1402 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1404 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1405 printer_t *printer = NULL;
1406 LPCWSTR printername;
1407 HKEY hkeyPrinters;
1408 HKEY hkeyPrinter;
1409 DWORD len;
1411 if (copy_servername_from_name(name, servername)) {
1412 FIXME("server %s not supported\n", debugstr_w(servername));
1413 SetLastError(ERROR_INVALID_PRINTER_NAME);
1414 return NULL;
1417 printername = get_basename_from_name(name);
1418 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1420 /* an empty printername is invalid */
1421 if (printername && (!printername[0])) {
1422 SetLastError(ERROR_INVALID_PARAMETER);
1423 return NULL;
1426 printer = heap_alloc_zero(sizeof(printer_t));
1427 if (!printer) goto end;
1429 /* clone the base name. This is NULL for the printserver */
1430 printer->printername = strdupW(printername);
1432 /* clone the full name */
1433 printer->name = strdupW(name);
1434 if (name && (!printer->name)) {
1435 printer_free(printer);
1436 printer = NULL;
1438 if (printername) {
1439 len = ARRAY_SIZE(L",XcvMonitor ") - 1;
1440 if (wcsncmp(printername, L",XcvMonitor ", len) == 0) {
1441 /* OpenPrinter(",XcvMonitor ", ...) detected */
1442 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1443 printer->pm = monitor_load(&printername[len], NULL);
1444 if (printer->pm == NULL) {
1445 printer_free(printer);
1446 SetLastError(ERROR_UNKNOWN_PORT);
1447 printer = NULL;
1448 goto end;
1451 else
1453 len = ARRAY_SIZE(L",XcvPort ") - 1;
1454 if (wcsncmp( printername, L",XcvPort ", len) == 0) {
1455 /* OpenPrinter(",XcvPort ", ...) detected */
1456 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1457 printer->pm = monitor_load_by_port(&printername[len]);
1458 if (printer->pm == NULL) {
1459 printer_free(printer);
1460 SetLastError(ERROR_UNKNOWN_PORT);
1461 printer = NULL;
1462 goto end;
1467 if (printer->pm) {
1468 if (printer->pm->monitor.pfnXcvOpenPort)
1469 printer->pm->monitor.pfnXcvOpenPort(printer->pm->hmon, &printername[len],
1470 pDefault ? pDefault->DesiredAccess : 0,
1471 &printer->hXcv);
1472 else if (printer->pm->old_XcvOpenPort)
1473 printer->pm->old_XcvOpenPort(&printername[len],
1474 pDefault ? pDefault->DesiredAccess : 0,
1475 &printer->hXcv);
1476 if (printer->hXcv == NULL) {
1477 printer_free(printer);
1478 SetLastError(ERROR_INVALID_PARAMETER);
1479 printer = NULL;
1480 goto end;
1483 else
1485 /* Does the Printer exist? */
1486 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1487 ERR("Can't create Printers key\n");
1488 printer_free(printer);
1489 SetLastError(ERROR_INVALID_PRINTER_NAME);
1490 printer = NULL;
1491 goto end;
1493 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1494 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1495 RegCloseKey(hkeyPrinters);
1496 printer_free(printer);
1497 SetLastError(ERROR_INVALID_PRINTER_NAME);
1498 printer = NULL;
1499 goto end;
1501 RegCloseKey(hkeyPrinter);
1502 RegCloseKey(hkeyPrinters);
1505 else
1507 TRACE("using the local printserver\n");
1510 end:
1512 TRACE("==> %p\n", printer);
1513 return (HANDLE)printer;
1516 static inline WCHAR *get_file_part( WCHAR *name )
1518 WCHAR *ptr = wcsrchr( name, '\\' );
1519 if (ptr) return ptr + 1;
1520 return name;
1523 /******************************************************************************
1524 * myAddPrinterDriverEx [internal]
1526 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1527 * and a special mode with lazy error checking.
1530 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1532 const printenv_t *env;
1533 apd_data_t apd;
1534 DRIVER_INFO_8W di;
1535 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1536 HMODULE hui;
1537 WCHAR *file;
1538 HKEY hroot;
1539 HKEY hdrv;
1540 DWORD disposition;
1541 DWORD len;
1542 LONG lres;
1543 BOOL res;
1545 /* we need to set all entries in the Registry, independent from the Level of
1546 DRIVER_INFO, that the caller supplied */
1548 ZeroMemory(&di, sizeof(di));
1549 if (pDriverInfo && (level < ARRAY_SIZE(di_sizeof))) {
1550 memcpy(&di, pDriverInfo, di_sizeof[level]);
1553 /* dump the most used infos */
1554 TRACE("%p: .cVersion : 0x%lx/%ld\n", pDriverInfo, di.cVersion, di.cVersion);
1555 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1556 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1557 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1558 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1559 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1560 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1561 /* dump only the first of the additional Files */
1562 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1565 /* check environment */
1566 env = validate_envW(di.pEnvironment);
1567 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1569 /* fill the copy-data / get the driverdir */
1570 len = sizeof(apd.src) - sizeof(L"\\3") - sizeof(WCHAR);
1571 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1572 (LPBYTE) apd.src, len, &len)) {
1573 /* Should never fail */
1574 return FALSE;
1576 memcpy(apd.dst, apd.src, len);
1577 lstrcatW(apd.src, L"\\");
1578 apd.srclen = lstrlenW(apd.src);
1579 lstrcatW(apd.dst, env->versionsubdir);
1580 lstrcatW(apd.dst, L"\\");
1581 apd.dstlen = lstrlenW(apd.dst);
1582 apd.copyflags = dwFileCopyFlags;
1583 apd.lazy = lazy;
1584 CreateDirectoryW(apd.src, NULL);
1585 CreateDirectoryW(apd.dst, NULL);
1587 hroot = open_driver_reg(env->envname);
1588 if (!hroot) {
1589 ERR("Can't create Drivers key\n");
1590 return FALSE;
1593 /* Fill the Registry for the Driver */
1594 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1595 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1596 &hdrv, &disposition)) != ERROR_SUCCESS) {
1598 ERR("can't create driver %s: %lu\n", debugstr_w(di.pName), lres);
1599 RegCloseKey(hroot);
1600 SetLastError(lres);
1601 return FALSE;
1603 RegCloseKey(hroot);
1605 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1606 RegSetValueExW(hdrv, L"Version", 0, REG_DWORD, (const BYTE*) &env->driverversion,
1607 sizeof(DWORD));
1609 file = get_file_part( di.pDriverPath );
1610 RegSetValueExW( hdrv, L"Driver", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1611 apd_copyfile( di.pDriverPath, file, &apd );
1613 file = get_file_part( di.pDataFile );
1614 RegSetValueExW( hdrv, L"Data File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1615 apd_copyfile( di.pDataFile, file, &apd );
1617 file = get_file_part( di.pConfigFile );
1618 RegSetValueExW( hdrv, L"Configuration File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1619 apd_copyfile( di.pConfigFile, file, &apd );
1621 /* settings for level 3 */
1622 if (di.pHelpFile)
1624 file = get_file_part( di.pHelpFile );
1625 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (BYTE*)file, (lstrlenW( file ) + 1) * sizeof(WCHAR) );
1626 apd_copyfile( di.pHelpFile, file, &apd );
1628 else
1629 RegSetValueExW( hdrv, L"Help File", 0, REG_SZ, (const BYTE*)L"", sizeof(L"") );
1631 if (di.pDependentFiles && *di.pDependentFiles)
1633 WCHAR *reg, *reg_ptr, *in_ptr;
1634 reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1636 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += lstrlenW( in_ptr ) + 1)
1638 file = get_file_part( in_ptr );
1639 len = lstrlenW( file ) + 1;
1640 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1641 reg_ptr += len;
1642 apd_copyfile( in_ptr, file, &apd );
1644 *reg_ptr = 0;
1646 RegSetValueExW( hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (BYTE*)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1647 HeapFree( GetProcessHeap(), 0, reg );
1649 else
1650 RegSetValueExW(hdrv, L"Dependent Files", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
1652 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1653 if (di.pMonitorName)
1654 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (BYTE*)di.pMonitorName,
1655 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1656 else
1657 RegSetValueExW(hdrv, L"Monitor", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
1659 if (di.pDefaultDataType)
1660 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (BYTE*)di.pDefaultDataType,
1661 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1662 else
1663 RegSetValueExW(hdrv, L"Datatype", 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
1665 /* settings for level 4 */
1666 if (di.pszzPreviousNames)
1667 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (BYTE*)di.pszzPreviousNames,
1668 multi_sz_lenW(di.pszzPreviousNames));
1669 else
1670 RegSetValueExW(hdrv, L"Previous Names", 0, REG_MULTI_SZ, (const BYTE*)L"", sizeof(L""));
1672 if (level > 5) TRACE("level %lu for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1674 RegCloseKey(hdrv);
1675 hui = driver_load(env, di.pConfigFile);
1676 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1677 if (hui && pDrvDriverEvent) {
1679 /* Support for DrvDriverEvent is optional */
1680 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1681 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1682 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1683 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1685 FreeLibrary(hui);
1687 TRACE("=> TRUE with %lu\n", GetLastError());
1688 return TRUE;
1692 /******************************************************************************
1693 * fpAddMonitor [exported through PRINTPROVIDOR]
1695 * Install a Printmonitor
1697 * PARAMS
1698 * pName [I] Servername or NULL (local Computer)
1699 * Level [I] Structure-Level (Must be 2)
1700 * pMonitors [I] PTR to MONITOR_INFO_2
1702 * RETURNS
1703 * Success: TRUE
1704 * Failure: FALSE
1706 * NOTES
1707 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1710 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1712 const printenv_t * env;
1713 monitor_t * pm = NULL;
1714 LPMONITOR_INFO_2W mi2w;
1715 HKEY hroot = NULL;
1716 HKEY hentry = NULL;
1717 DWORD disposition;
1718 BOOL res = FALSE;
1720 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1721 TRACE("(%s, %ld, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1722 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
1724 if (copy_servername_from_name(pName, NULL)) {
1725 FIXME("server %s not supported\n", debugstr_w(pName));
1726 SetLastError(ERROR_ACCESS_DENIED);
1727 return FALSE;
1730 if (!mi2w->pName || (! mi2w->pName[0])) {
1731 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1732 SetLastError(ERROR_INVALID_PARAMETER);
1733 return FALSE;
1736 env = validate_envW(mi2w->pEnvironment);
1737 if (!env)
1738 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1740 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1741 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1742 SetLastError(ERROR_INVALID_PARAMETER);
1743 return FALSE;
1746 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1747 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1748 return FALSE;
1751 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1752 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1753 &disposition) == ERROR_SUCCESS) {
1755 /* Some installers set options for the port before calling AddMonitor.
1756 We query the "Driver" entry to verify that the monitor is installed,
1757 before we return an error.
1758 When a user installs two print monitors at the same time with the
1759 same name, a race condition is possible but silently ignored. */
1761 DWORD namesize = 0;
1763 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1764 (RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL,
1765 &namesize) == ERROR_SUCCESS)) {
1766 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1767 /* 9x use ERROR_ALREADY_EXISTS */
1768 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1770 else
1772 INT len;
1773 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1774 res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ,
1775 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1777 /* Load and initialize the monitor. SetLastError() is called on failure */
1778 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL)
1780 RegDeleteKeyW(hroot, mi2w->pName);
1781 res = FALSE;
1783 else
1784 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
1787 RegCloseKey(hentry);
1790 RegCloseKey(hroot);
1791 return (res);
1794 static BOOL wrap_AddPort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR monitor_name)
1796 if (pm->monitor.pfnAddPort)
1797 return pm->monitor.pfnAddPort(pm->hmon, name, hwnd, monitor_name);
1799 if (pm->old_AddPort)
1800 return pm->old_AddPort(name, hwnd, monitor_name);
1802 WARN("AddPort is not implemented by monitor\n");
1803 return FALSE;
1806 /******************************************************************************
1807 * fpAddPort [exported through PRINTPROVIDOR]
1809 * Add a Port for a specific Monitor
1811 * PARAMS
1812 * pName [I] Servername or NULL (local Computer)
1813 * hWnd [I] Handle to parent Window for the Dialog-Box
1814 * pMonitorName [I] Name of the Monitor that manage the Port
1816 * RETURNS
1817 * Success: TRUE
1818 * Failure: FALSE
1821 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1823 monitor_t * pm;
1824 monitor_t * pui;
1825 LONG lres;
1826 DWORD res;
1828 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1830 lres = copy_servername_from_name(pName, NULL);
1831 if (lres) {
1832 FIXME("server %s not supported\n", debugstr_w(pName));
1833 SetLastError(ERROR_INVALID_PARAMETER);
1834 return FALSE;
1837 /* an empty Monitorname is Invalid */
1838 if (!pMonitorName[0]) {
1839 SetLastError(ERROR_NOT_SUPPORTED);
1840 return FALSE;
1843 pm = monitor_load(pMonitorName, NULL);
1844 if (pm && (pm->monitor.pfnAddPort || pm->old_AddPort)) {
1845 res = wrap_AddPort(pm, pName, hWnd, pMonitorName);
1846 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1848 else
1850 pui = monitor_loadui(pm);
1851 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1852 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1853 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1855 else
1857 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1858 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1859 pui, debugstr_w(pui ? pui->dllname : NULL));
1861 SetLastError(ERROR_NOT_SUPPORTED);
1862 res = FALSE;
1864 monitor_unload(pui);
1866 monitor_unload(pm);
1868 TRACE("returning %ld with %lu\n", res, GetLastError());
1869 return res;
1872 static BOOL wrap_AddPortEx(monitor_t *pm, LPWSTR name, DWORD level, LPBYTE buffer, LPWSTR monitor_name)
1874 if (pm->monitor.pfnAddPortEx)
1875 return pm->monitor.pfnAddPortEx(pm->hmon, name, level, buffer, monitor_name);
1877 if (pm->old_AddPortEx)
1878 return pm->old_AddPortEx(name, level, buffer, monitor_name);
1880 WARN("AddPortEx is not implemented by monitor\n");
1881 return FALSE;
1884 /******************************************************************************
1885 * fpAddPortEx [exported through PRINTPROVIDOR]
1887 * Add a Port for a specific Monitor, without presenting a user interface
1889 * PARAMS
1890 * pName [I] Servername or NULL (local Computer)
1891 * level [I] Structure-Level (1 or 2) for pBuffer
1892 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1893 * pMonitorName [I] Name of the Monitor that manage the Port
1895 * RETURNS
1896 * Success: TRUE
1897 * Failure: FALSE
1900 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1902 PORT_INFO_2W * pi2;
1903 monitor_t * pm;
1904 DWORD lres;
1905 DWORD res;
1907 pi2 = (PORT_INFO_2W *) pBuffer;
1909 TRACE("(%s, %ld, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1910 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1911 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1912 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1914 lres = copy_servername_from_name(pName, NULL);
1915 if (lres) {
1916 FIXME("server %s not supported\n", debugstr_w(pName));
1917 SetLastError(ERROR_INVALID_PARAMETER);
1918 return FALSE;
1921 if ((level < 1) || (level > 2)) {
1922 SetLastError(ERROR_INVALID_LEVEL);
1923 return FALSE;
1926 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1927 SetLastError(ERROR_INVALID_PARAMETER);
1928 return FALSE;
1931 /* load the Monitor */
1932 pm = monitor_load(pMonitorName, NULL);
1933 if (pm && (pm->monitor.pfnAddPortEx || pm->old_AddPortEx))
1935 res = wrap_AddPortEx(pm, pName, level, pBuffer, pMonitorName);
1936 TRACE("got %ld with %lu (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1938 else
1940 FIXME("not implemented for %s (monitor %p: %s)\n",
1941 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
1942 SetLastError(ERROR_INVALID_PARAMETER);
1943 res = FALSE;
1945 monitor_unload(pm);
1946 return res;
1949 /******************************************************************************
1950 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1952 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1954 * PARAMS
1955 * pName [I] Servername or NULL (local Computer)
1956 * level [I] Level for the supplied DRIVER_INFO_*W struct
1957 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1958 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1960 * RESULTS
1961 * Success: TRUE
1962 * Failure: FALSE
1965 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1967 LONG lres;
1969 TRACE("(%s, %ld, %p, 0x%lx)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1970 lres = copy_servername_from_name(pName, NULL);
1971 if (lres) {
1972 FIXME("server %s not supported\n", debugstr_w(pName));
1973 SetLastError(ERROR_ACCESS_DENIED);
1974 return FALSE;
1977 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1978 TRACE("Flags 0x%lx ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1981 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1984 /******************************************************************************
1985 * fpClosePrinter [exported through PRINTPROVIDOR]
1987 * Close a printer handle and free associated resources
1989 * PARAMS
1990 * hPrinter [I] Printerhandle to close
1992 * RESULTS
1993 * Success: TRUE
1994 * Failure: FALSE
1997 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1999 printer_t *printer = (printer_t *) hPrinter;
2001 TRACE("(%p)\n", hPrinter);
2003 if (printer) {
2004 printer_free(printer);
2005 return TRUE;
2007 return FALSE;
2010 static BOOL wrap_ConfigurePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
2012 if (pm->monitor.pfnConfigurePort)
2013 return pm->monitor.pfnConfigurePort(pm->hmon, name, hwnd, port_name);
2015 if (pm->old_ConfigurePort)
2016 return pm->old_ConfigurePort(name, hwnd, port_name);
2018 WARN("ConfigurePort is not implemented by monitor\n");
2019 return FALSE;
2022 /******************************************************************************
2023 * fpConfigurePort [exported through PRINTPROVIDOR]
2025 * Display the Configuration-Dialog for a specific Port
2027 * PARAMS
2028 * pName [I] Servername or NULL (local Computer)
2029 * hWnd [I] Handle to parent Window for the Dialog-Box
2030 * pPortName [I] Name of the Port, that should be configured
2032 * RETURNS
2033 * Success: TRUE
2034 * Failure: FALSE
2037 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2039 monitor_t * pm;
2040 monitor_t * pui;
2041 LONG lres;
2042 DWORD res;
2044 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2046 lres = copy_servername_from_name(pName, NULL);
2047 if (lres) {
2048 FIXME("server %s not supported\n", debugstr_w(pName));
2049 SetLastError(ERROR_INVALID_NAME);
2050 return FALSE;
2053 /* an empty Portname is Invalid, but can popup a Dialog */
2054 if (!pPortName[0]) {
2055 SetLastError(ERROR_NOT_SUPPORTED);
2056 return FALSE;
2059 pm = monitor_load_by_port(pPortName);
2060 if (pm && (pm->monitor.pfnConfigurePort || pm->old_ConfigurePort))
2062 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2063 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2064 res = wrap_ConfigurePort(pm, pName, hWnd, pPortName);
2065 TRACE("got %ld with %lu\n", res, GetLastError());
2067 else
2069 pui = monitor_loadui(pm);
2070 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
2071 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2072 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2073 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
2074 TRACE("got %ld with %lu\n", res, GetLastError());
2076 else
2078 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2079 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2080 pui, debugstr_w(pui ? pui->dllname : NULL));
2082 SetLastError(ERROR_NOT_SUPPORTED);
2083 res = FALSE;
2085 monitor_unload(pui);
2087 monitor_unload(pm);
2089 TRACE("returning %ld with %lu\n", res, GetLastError());
2090 return res;
2093 /******************************************************************
2094 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2096 * Delete a specific Printmonitor from a Printing-Environment
2098 * PARAMS
2099 * pName [I] Servername or NULL (local Computer)
2100 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2101 * pMonitorName [I] Name of the Monitor, that should be deleted
2103 * RETURNS
2104 * Success: TRUE
2105 * Failure: FALSE
2107 * NOTES
2108 * pEnvironment is ignored in Windows for the local Computer.
2112 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2114 monitor_t *pm;
2115 HKEY hroot = NULL;
2116 LONG lres;
2118 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2119 debugstr_w(pMonitorName));
2121 lres = copy_servername_from_name(pName, NULL);
2122 if (lres) {
2123 FIXME("server %s not supported\n", debugstr_w(pName));
2124 SetLastError(ERROR_INVALID_NAME);
2125 return FALSE;
2128 /* pEnvironment is ignored in Windows for the local Computer */
2129 if (!pMonitorName || !pMonitorName[0]) {
2130 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2131 SetLastError(ERROR_INVALID_PARAMETER);
2132 return FALSE;
2135 /* Unload the monitor if it's loaded */
2136 EnterCriticalSection(&monitor_handles_cs);
2137 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
2139 if (pm->name && !lstrcmpW(pMonitorName, pm->name))
2141 monitor_unload(pm);
2142 break;
2145 LeaveCriticalSection(&monitor_handles_cs);
2147 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
2148 ERR("unable to create key %s\n", debugstr_w(monitorsW));
2149 return FALSE;
2152 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2153 TRACE("%s deleted\n", debugstr_w(pMonitorName));
2154 RegCloseKey(hroot);
2155 return TRUE;
2158 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
2159 RegCloseKey(hroot);
2161 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2162 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2163 return FALSE;
2166 static BOOL wrap_DeletePort(monitor_t *pm, LPWSTR name, HWND hwnd, LPWSTR port_name)
2168 if (pm->monitor.pfnDeletePort)
2169 return pm->monitor.pfnDeletePort(pm->hmon, name, hwnd, port_name);
2171 if (pm->old_ConfigurePort)
2172 return pm->old_DeletePort(name, hwnd, port_name);
2174 WARN("DeletePort is not implemented by monitor\n");
2175 return FALSE;
2178 /*****************************************************************************
2179 * fpDeletePort [exported through PRINTPROVIDOR]
2181 * Delete a specific Port
2183 * PARAMS
2184 * pName [I] Servername or NULL (local Computer)
2185 * hWnd [I] Handle to parent Window for the Dialog-Box
2186 * pPortName [I] Name of the Port, that should be deleted
2188 * RETURNS
2189 * Success: TRUE
2190 * Failure: FALSE
2193 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2195 monitor_t * pm;
2196 monitor_t * pui;
2197 LONG lres;
2198 DWORD res;
2200 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2202 lres = copy_servername_from_name(pName, NULL);
2203 if (lres) {
2204 FIXME("server %s not supported\n", debugstr_w(pName));
2205 SetLastError(ERROR_INVALID_NAME);
2206 return FALSE;
2209 /* an empty Portname is Invalid */
2210 if (!pPortName[0]) {
2211 SetLastError(ERROR_NOT_SUPPORTED);
2212 return FALSE;
2215 pm = monitor_load_by_port(pPortName);
2216 if (pm && (pm->monitor.pfnDeletePort || pm->old_DeletePort))
2218 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
2219 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2220 res = wrap_DeletePort(pm, pName, hWnd, pPortName);
2221 TRACE("got %ld with %lu\n", res, GetLastError());
2223 else
2225 pui = monitor_loadui(pm);
2226 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2227 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
2228 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2229 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2230 TRACE("got %ld with %lu\n", res, GetLastError());
2232 else
2234 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2235 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
2236 pui, debugstr_w(pui ? pui->dllname : NULL));
2238 SetLastError(ERROR_NOT_SUPPORTED);
2239 res = FALSE;
2241 monitor_unload(pui);
2243 monitor_unload(pm);
2245 TRACE("returning %ld with %lu\n", res, GetLastError());
2246 return res;
2249 /*****************************************************************************
2250 * fpEnumMonitors [exported through PRINTPROVIDOR]
2252 * Enumerate available Port-Monitors
2254 * PARAMS
2255 * pName [I] Servername or NULL (local Computer)
2256 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2257 * pMonitors [O] PTR to Buffer that receives the Result
2258 * cbBuf [I] Size of Buffer at pMonitors
2259 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2260 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2262 * RETURNS
2263 * Success: TRUE
2264 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2266 * NOTES
2267 * Windows reads the Registry once and cache the Results.
2270 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
2271 LPDWORD pcbNeeded, LPDWORD pcReturned)
2273 DWORD numentries = 0;
2274 DWORD needed = 0;
2275 LONG lres;
2276 BOOL res = FALSE;
2278 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
2279 cbBuf, pcbNeeded, pcReturned);
2281 lres = copy_servername_from_name(pName, NULL);
2282 if (lres) {
2283 FIXME("server %s not supported\n", debugstr_w(pName));
2284 SetLastError(ERROR_INVALID_NAME);
2285 goto em_cleanup;
2288 if (!Level || (Level > 2)) {
2289 WARN("level (%ld) is ignored in win9x\n", Level);
2290 SetLastError(ERROR_INVALID_LEVEL);
2291 return FALSE;
2294 /* Scan all Monitor-Keys */
2295 numentries = 0;
2296 needed = get_local_monitors(Level, NULL, 0, &numentries);
2298 /* we calculated the needed buffersize. now do more error-checks */
2299 if (cbBuf < needed) {
2300 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2301 goto em_cleanup;
2304 /* fill the Buffer with the Monitor-Keys */
2305 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2306 res = TRUE;
2308 em_cleanup:
2309 if (pcbNeeded) *pcbNeeded = needed;
2310 if (pcReturned) *pcReturned = numentries;
2312 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2313 res, GetLastError(), needed, numentries);
2315 return (res);
2318 /******************************************************************************
2319 * fpEnumPorts [exported through PRINTPROVIDOR]
2321 * Enumerate available Ports
2323 * PARAMS
2324 * pName [I] Servername or NULL (local Computer)
2325 * Level [I] Structure-Level (1 or 2)
2326 * pPorts [O] PTR to Buffer that receives the Result
2327 * cbBuf [I] Size of Buffer at pPorts
2328 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2329 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2331 * RETURNS
2332 * Success: TRUE
2333 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2336 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2337 LPDWORD pcbNeeded, LPDWORD pcReturned)
2339 DWORD needed = 0;
2340 DWORD numentries = 0;
2341 LONG lres;
2342 BOOL res = FALSE;
2344 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2345 cbBuf, pcbNeeded, pcReturned);
2347 lres = copy_servername_from_name(pName, NULL);
2348 if (lres) {
2349 FIXME("server %s not supported\n", debugstr_w(pName));
2350 SetLastError(ERROR_INVALID_NAME);
2351 goto emP_cleanup;
2354 if (!Level || (Level > 2)) {
2355 SetLastError(ERROR_INVALID_LEVEL);
2356 goto emP_cleanup;
2359 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2360 SetLastError(RPC_X_NULL_REF_POINTER);
2361 goto emP_cleanup;
2364 EnterCriticalSection(&monitor_handles_cs);
2365 monitor_loadall();
2367 /* Scan all local Ports */
2368 numentries = 0;
2369 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2371 /* we calculated the needed buffersize. now do the error-checks */
2372 if (cbBuf < needed) {
2373 monitor_unloadall();
2374 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2375 goto emP_cleanup_cs;
2377 else if (!pPorts || !pcReturned) {
2378 monitor_unloadall();
2379 SetLastError(RPC_X_NULL_REF_POINTER);
2380 goto emP_cleanup_cs;
2383 /* Fill the Buffer */
2384 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2385 res = TRUE;
2386 monitor_unloadall();
2388 emP_cleanup_cs:
2389 LeaveCriticalSection(&monitor_handles_cs);
2391 emP_cleanup:
2392 if (pcbNeeded) *pcbNeeded = needed;
2393 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2395 TRACE("returning %d with %ld (%ld byte for %ld of %ld entries)\n",
2396 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2398 return (res);
2401 /*****************************************************************************
2402 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2404 * Enumerate available Print Processors
2406 * PARAMS
2407 * pName [I] Servername or NULL (local Computer)
2408 * pEnvironment [I] Printing-Environment or NULL (Default)
2409 * Level [I] Structure-Level (Only 1 is allowed)
2410 * pPPInfo [O] PTR to Buffer that receives the Result
2411 * cbBuf [I] Size of Buffer at pMonitors
2412 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2413 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2415 * RETURNS
2416 * Success: TRUE
2417 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2420 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2421 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2423 const printenv_t * env;
2424 LPWSTR regpathW = NULL;
2425 DWORD numentries = 0;
2426 DWORD needed = 0;
2427 LONG lres;
2428 BOOL res = FALSE;
2430 TRACE("(%s, %s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2431 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2433 lres = copy_servername_from_name(pName, NULL);
2434 if (lres) {
2435 FIXME("server %s not supported\n", debugstr_w(pName));
2436 SetLastError(ERROR_INVALID_NAME);
2437 goto epp_cleanup;
2440 if (Level != 1) {
2441 SetLastError(ERROR_INVALID_LEVEL);
2442 goto epp_cleanup;
2445 env = validate_envW(pEnvironment);
2446 if (!env)
2447 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2449 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2450 (lstrlenW(env->envname) * sizeof(WCHAR)));
2452 if (!regpathW)
2453 goto epp_cleanup;
2455 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2457 /* Scan all Printprocessor-Keys */
2458 numentries = 0;
2459 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2461 /* we calculated the needed buffersize. now do more error-checks */
2462 if (cbBuf < needed) {
2463 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2464 goto epp_cleanup;
2467 /* fill the Buffer with the Printprocessor Infos */
2468 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2469 res = TRUE;
2471 epp_cleanup:
2472 heap_free(regpathW);
2473 if (pcbNeeded) *pcbNeeded = needed;
2474 if (pcReturned) *pcReturned = numentries;
2476 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
2477 res, GetLastError(), needed, numentries);
2479 return (res);
2482 /******************************************************************************
2483 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2485 * Return the PATH for the Print-Processors
2487 * PARAMS
2488 * pName [I] Servername or NULL (this computer)
2489 * pEnvironment [I] Printing-Environment or NULL (Default)
2490 * level [I] Structure-Level (must be 1)
2491 * pPPInfo [O] PTR to Buffer that receives the Result
2492 * cbBuf [I] Size of Buffer at pPPInfo
2493 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2495 * RETURNS
2496 * Success: TRUE
2497 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2499 * Native Values returned in pPPInfo on Success for this computer:
2500 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2501 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2502 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2504 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2507 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2508 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2510 const printenv_t * env;
2511 DWORD needed;
2512 LONG lres;
2514 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2515 level, pPPInfo, cbBuf, pcbNeeded);
2517 *pcbNeeded = 0;
2518 lres = copy_servername_from_name(pName, NULL);
2519 if (lres) {
2520 FIXME("server %s not supported\n", debugstr_w(pName));
2521 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2522 return FALSE;
2525 env = validate_envW(pEnvironment);
2526 if (!env)
2527 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2529 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2530 needed = GetSystemDirectoryW(NULL, 0);
2531 /* add the Size for the Subdirectories */
2532 needed += lstrlenW(L"\\spool\\prtprocs\\");
2533 needed += lstrlenW(env->subdir);
2534 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2536 *pcbNeeded = needed;
2538 if (needed > cbBuf) {
2539 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2540 return FALSE;
2543 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2544 /* add the Subdirectories */
2545 lstrcatW((LPWSTR) pPPInfo, L"\\spool\\prtprocs\\");
2546 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2547 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2548 return TRUE;
2551 /******************************************************************************
2552 * fpOpenPrinter [exported through PRINTPROVIDOR]
2554 * Open a Printer / Printserver or a Printer-Object
2556 * PARAMS
2557 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2558 * pPrinter [O] The resulting Handle is stored here
2559 * pDefaults [I] PTR to Default Printer Settings or NULL
2561 * RETURNS
2562 * Success: TRUE
2563 * Failure: FALSE
2565 * NOTES
2566 * lpPrinterName is one of:
2567 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2568 *| Printer: "PrinterName"
2569 *| Printer-Object: "PrinterName,Job xxx"
2570 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2571 *| XcvPort: "Servername,XcvPort PortName"
2575 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2576 LPPRINTER_DEFAULTSW pDefaults)
2579 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2581 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2583 return (*pPrinter != 0);
2586 /******************************************************************************
2587 * fpXcvData [exported through PRINTPROVIDOR]
2589 * Execute commands in the Printmonitor DLL
2591 * PARAMS
2592 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2593 * pszDataName [i] Name of the command to execute
2594 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2595 * cbInputData [i] Size in Bytes of Buffer at pInputData
2596 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2597 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2598 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2599 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2601 * RETURNS
2602 * Success: TRUE
2603 * Failure: FALSE
2605 * NOTES
2606 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2607 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2609 * Minimal List of commands, that a Printmonitor DLL should support:
2611 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2612 *| "AddPort" : Add a Port
2613 *| "DeletePort": Delete a Port
2615 * Many Printmonitors support additional commands. Examples for localspl.dll:
2616 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2617 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2620 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2621 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2622 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2624 printer_t *printer = (printer_t * ) hXcv;
2626 TRACE("(%p, %s, %p, %ld, %p, %ld, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2627 pInputData, cbInputData, pOutputData,
2628 cbOutputData, pcbOutputNeeded, pdwStatus);
2630 if (!printer || (!printer->hXcv)) {
2631 SetLastError(ERROR_INVALID_HANDLE);
2632 return FALSE;
2635 if (!pcbOutputNeeded) {
2636 SetLastError(ERROR_INVALID_PARAMETER);
2637 return FALSE;
2640 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2641 SetLastError(RPC_X_NULL_REF_POINTER);
2642 return FALSE;
2645 *pcbOutputNeeded = 0;
2647 if (printer->pm->monitor.pfnXcvDataPort)
2648 *pdwStatus = printer->pm->monitor.pfnXcvDataPort(printer->hXcv, pszDataName,
2649 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2651 return TRUE;
2654 static inline size_t form_struct_size( DWORD level )
2656 if (level == 1) return sizeof(FORM_INFO_1W);
2657 if (level == 2) return sizeof(FORM_INFO_2W);
2659 SetLastError( ERROR_INVALID_LEVEL );
2660 return 0;
2663 static void fill_builtin_form_info( BYTE **base, WCHAR **strings, const struct builtin_form *form, DWORD level,
2664 DWORD size, DWORD *used )
2666 FORM_INFO_2W *info = *(FORM_INFO_2W**)base;
2667 DWORD name_len = lstrlenW( form->name ) + 1, res_len, keyword_len, total_size;
2668 static const WCHAR dll_name[] = L"localspl.dll";
2669 const WCHAR *resource;
2671 total_size = name_len * sizeof(WCHAR);
2673 if (level > 1)
2675 keyword_len = WideCharToMultiByte( CP_ACP, 0, form->name, -1, NULL, 0, NULL, NULL );
2676 keyword_len = (keyword_len + 1) & ~1;
2677 total_size += keyword_len;
2678 res_len = LoadStringW( localspl_instance, form->res_id, (WCHAR *)&resource, 0 );
2679 if (res_len && resource[res_len - 1]) res_len++;
2680 total_size += (res_len + ARRAY_SIZE(dll_name)) * sizeof(WCHAR);
2683 if (*used + total_size <= size)
2685 info->Flags = FORM_BUILTIN;
2686 info->pName = memcpy( *strings, form->name, name_len * sizeof(WCHAR) );
2687 *strings += name_len;
2688 info->Size = form->size;
2689 info->ImageableArea.left = info->ImageableArea.top = 0;
2690 info->ImageableArea.right = info->Size.cx;
2691 info->ImageableArea.bottom = info->Size.cy;
2692 if (level > 1)
2694 info->pKeyword = (char *)*strings;
2695 WideCharToMultiByte( CP_ACP, 0, form->name, -1, (char *)info->pKeyword, keyword_len, NULL, NULL );
2696 *strings += keyword_len / sizeof(WCHAR);
2697 info->StringType = STRING_MUIDLL;
2698 info->pMuiDll = memcpy( *strings, dll_name, sizeof(dll_name) );
2699 *strings += ARRAY_SIZE(dll_name);
2700 info->dwResourceId = form->res_id;
2701 if (res_len)
2703 info->StringType |= STRING_LANGPAIR;
2704 info->pDisplayName = memcpy( *strings, resource, (res_len - 1) * sizeof(WCHAR) );
2705 info->pDisplayName[res_len - 1] = '\0';
2706 *strings += res_len;
2707 info->wLangId = GetUserDefaultLangID();
2709 else
2711 info->pDisplayName = NULL;
2712 info->wLangId = 0;
2717 *base += form_struct_size( level );
2718 *used += total_size;
2721 static BOOL WINAPI fpAddForm( HANDLE printer, DWORD level, BYTE *form )
2723 FIXME( "(%p, %ld, %p): stub\n", printer, level, form );
2724 return TRUE;
2727 static BOOL WINAPI fpDeleteForm( HANDLE printer, WCHAR *name )
2729 FIXME( "(%p, %s): stub\n", printer, debugstr_w( name ) );
2730 return TRUE;
2733 static BOOL WINAPI fpGetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
2735 size_t struct_size = form_struct_size( level );
2736 const struct builtin_form *builtin = NULL;
2737 WCHAR *strings = NULL;
2738 BYTE *base = form;
2739 DWORD i;
2741 TRACE( "(%p, %s, %ld, %p, %ld, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
2743 *needed = 0;
2745 if (!struct_size) return FALSE;
2747 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
2749 if (!wcscmp( name, builtin_forms[i].name ))
2751 builtin = builtin_forms + i;
2752 break;
2756 if (!builtin)
2758 SetLastError( ERROR_INVALID_FORM_NAME );
2759 return FALSE;
2762 *needed = struct_size;
2763 if (*needed < size) strings = (WCHAR *)(form + *needed);
2765 fill_builtin_form_info( &base, &strings, builtin, level, size, needed );
2767 if (*needed > size)
2769 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2770 return FALSE;
2772 return TRUE;
2775 static BOOL WINAPI fpSetForm( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
2777 FIXME( "(%p, %s, %ld, %p): stub\n", printer, debugstr_w( name ), level, form );
2778 return FALSE;
2781 static BOOL WINAPI fpEnumForms( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
2783 DWORD num = ARRAY_SIZE(builtin_forms), i;
2784 WCHAR *strings = NULL;
2785 BYTE *base = form;
2786 size_t struct_size = form_struct_size( level );
2788 TRACE( "(%p, %ld, %p, %ld, %p, %p)\n", printer, level, form, size, needed, count );
2790 *count = *needed = 0;
2792 if (!struct_size) return FALSE;
2794 *needed = num * struct_size;
2795 if (*needed < size) strings = (WCHAR *)(form + *needed);
2797 for (i = 0; i < ARRAY_SIZE(builtin_forms); i++)
2798 fill_builtin_form_info( &base, &strings, builtin_forms + i, level, size, needed );
2800 if (*needed > size)
2802 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2803 return FALSE;
2806 *count = i;
2807 return TRUE;
2810 static const PRINTPROVIDOR backend = {
2811 fpOpenPrinter,
2812 NULL, /* fpSetJob */
2813 NULL, /* fpGetJob */
2814 NULL, /* fpEnumJobs */
2815 NULL, /* fpAddPrinter */
2816 NULL, /* fpDeletePrinter */
2817 NULL, /* fpSetPrinter */
2818 NULL, /* fpGetPrinter */
2819 NULL, /* fpEnumPrinters */
2820 NULL, /* fpAddPrinterDriver */
2821 NULL, /* fpEnumPrinterDrivers */
2822 NULL, /* fpGetPrinterDriver */
2823 fpGetPrinterDriverDirectory,
2824 NULL, /* fpDeletePrinterDriver */
2825 NULL, /* fpAddPrintProcessor */
2826 fpEnumPrintProcessors,
2827 fpGetPrintProcessorDirectory,
2828 NULL, /* fpDeletePrintProcessor */
2829 NULL, /* fpEnumPrintProcessorDatatypes */
2830 NULL, /* fpStartDocPrinter */
2831 NULL, /* fpStartPagePrinter */
2832 NULL, /* fpWritePrinter */
2833 NULL, /* fpEndPagePrinter */
2834 NULL, /* fpAbortPrinter */
2835 NULL, /* fpReadPrinter */
2836 NULL, /* fpEndDocPrinter */
2837 NULL, /* fpAddJob */
2838 NULL, /* fpScheduleJob */
2839 NULL, /* fpGetPrinterData */
2840 NULL, /* fpSetPrinterData */
2841 NULL, /* fpWaitForPrinterChange */
2842 fpClosePrinter,
2843 fpAddForm,
2844 fpDeleteForm,
2845 fpGetForm,
2846 fpSetForm,
2847 fpEnumForms,
2848 fpEnumMonitors,
2849 fpEnumPorts,
2850 fpAddPort,
2851 fpConfigurePort,
2852 fpDeletePort,
2853 NULL, /* fpCreatePrinterIC */
2854 NULL, /* fpPlayGdiScriptOnPrinterIC */
2855 NULL, /* fpDeletePrinterIC */
2856 NULL, /* fpAddPrinterConnection */
2857 NULL, /* fpDeletePrinterConnection */
2858 NULL, /* fpPrinterMessageBox */
2859 fpAddMonitor,
2860 fpDeleteMonitor,
2861 NULL, /* fpResetPrinter */
2862 NULL, /* fpGetPrinterDriverEx */
2863 NULL, /* fpFindFirstPrinterChangeNotification */
2864 NULL, /* fpFindClosePrinterChangeNotification */
2865 fpAddPortEx,
2866 NULL, /* fpShutDown */
2867 NULL, /* fpRefreshPrinterChangeNotification */
2868 NULL, /* fpOpenPrinterEx */
2869 NULL, /* fpAddPrinterEx */
2870 NULL, /* fpSetPort */
2871 NULL, /* fpEnumPrinterData */
2872 NULL, /* fpDeletePrinterData */
2873 NULL, /* fpClusterSplOpen */
2874 NULL, /* fpClusterSplClose */
2875 NULL, /* fpClusterSplIsAlive */
2876 NULL, /* fpSetPrinterDataEx */
2877 NULL, /* fpGetPrinterDataEx */
2878 NULL, /* fpEnumPrinterDataEx */
2879 NULL, /* fpEnumPrinterKey */
2880 NULL, /* fpDeletePrinterDataEx */
2881 NULL, /* fpDeletePrinterKey */
2882 NULL, /* fpSeekPrinter */
2883 NULL, /* fpDeletePrinterDriverEx */
2884 NULL, /* fpAddPerMachineConnection */
2885 NULL, /* fpDeletePerMachineConnection */
2886 NULL, /* fpEnumPerMachineConnections */
2887 fpXcvData,
2888 fpAddPrinterDriverEx,
2889 NULL, /* fpSplReadPrinter */
2890 NULL, /* fpDriverUnloadComplete */
2891 NULL, /* fpGetSpoolFileInfo */
2892 NULL, /* fpCommitSpoolData */
2893 NULL, /* fpCloseSpoolFileHandle */
2894 NULL, /* fpFlushPrinter */
2895 NULL, /* fpSendRecvBidiData */
2896 NULL /* fpAddDriverCatalog */
2899 /*****************************************************
2900 * InitializePrintProvidor (localspl.@)
2902 * Initialize the Printprovider
2904 * PARAMS
2905 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2906 * cbPrintProvidor [I] Size of Buffer in Bytes
2907 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2909 * RETURNS
2910 * Success: TRUE and pPrintProvidor filled
2911 * Failure: FALSE
2913 * NOTES
2914 * The RegistryPath should be:
2915 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2916 * but this Parameter is ignored in "localspl.dll".
2920 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2921 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2924 TRACE("(%p, %lu, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2925 memcpy(pPrintProvidor, &backend,
2926 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2928 return TRUE;