* Sync to trunk HEAD (r53298).
[reactos.git] / dll / win32 / localspl / provider.c
1 /*
2 * Implementation of the Local Printprovider
3 *
4 * Copyright 2006-2009 Detlef Riekenberg
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "winuser.h"
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
34
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
41
42 /* ############################### */
43
44 static CRITICAL_SECTION monitor_handles_cs;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
46 {
47 0, 0, &monitor_handles_cs,
48 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
49 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
50 };
51 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
52
53 /* ############################### */
54
55 typedef struct {
56 WCHAR src[MAX_PATH+MAX_PATH];
57 WCHAR dst[MAX_PATH+MAX_PATH];
58 DWORD srclen;
59 DWORD dstlen;
60 DWORD copyflags;
61 BOOL lazy;
62 } apd_data_t;
63
64 typedef struct {
65 struct list entry;
66 LPWSTR name;
67 LPWSTR dllname;
68 PMONITORUI monitorUI;
69 LPMONITOR monitor;
70 HMODULE hdll;
71 DWORD refcount;
72 DWORD dwMonitorSize;
73 } monitor_t;
74
75 typedef struct {
76 LPCWSTR envname;
77 LPCWSTR subdir;
78 DWORD driverversion;
79 LPCWSTR versionregpath;
80 LPCWSTR versionsubdir;
81 } printenv_t;
82
83 typedef struct {
84 LPWSTR name;
85 LPWSTR printername;
86 monitor_t * pm;
87 HANDLE hXcv;
88 } printer_t;
89
90 /* ############################### */
91
92 static struct list monitor_handles = LIST_INIT( monitor_handles );
93 static monitor_t * pm_localport;
94
95 static const PRINTPROVIDOR * pprovider = NULL;
96
97 static const WCHAR backslashW[] = {'\\',0};
98 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
106 static const WCHAR emptyW[] = {0};
107 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
108 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109 'c','o','n','t','r','o','l','\\',
110 'P','r','i','n','t','\\',
111 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
112 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
113 static const WCHAR fmt_printprocessorsW[] = { 'S','y','s','t','e','m','\\',
114 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'P','r','i','n','t','\\',
117 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
118 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
119 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
120 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
121 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
122 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
123 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
124 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
125 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
126 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
127 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'C','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'M','o','n','i','t','o','r','s','\\',0};
132 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
133 static const WCHAR nameW[] = {'N','a','m','e',0};
134 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
135 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
136 static const WCHAR portW[] = {'P','o','r','t',0};
137 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
138 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
139 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
140 'C','o','n','t','r','o','l','\\',
141 'P','r','i','n','t','\\',
142 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
144 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
145 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
146 static const WCHAR version0_subdirW[] = {'\\','0',0};
147 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
148 static const WCHAR version3_subdirW[] = {'\\','3',0};
149 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
150 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
152 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
153 'M','i','c','r','o','s','o','f','t','\\',
154 'W','i','n','d','o','w','s',' ','N','T','\\',
155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156 'P','o','r','t','s',0};
157 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
158 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
159 static const WCHAR x64_subdirW[] = {'x','6','4',0};
160 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
161 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
162 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
163 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
164
165
166 static const printenv_t env_ia64 = {ia64_envnameW, ia64_subdirW, 3,
167 version3_regpathW, version3_subdirW};
168
169 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
170 version3_regpathW, version3_subdirW};
171
172 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
173 version3_regpathW, version3_subdirW};
174
175 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
176 version0_regpathW, version0_subdirW};
177
178 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
179
180
181 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
182 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
183 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
184 0, sizeof(DRIVER_INFO_8W)};
185
186
187 /******************************************************************
188 * strdupW [internal]
189 *
190 * create a copy of a unicode-string
191 *
192 */
193 static LPWSTR strdupW(LPCWSTR p)
194 {
195 LPWSTR ret;
196 DWORD len;
197
198 if(!p) return NULL;
199 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
200 ret = heap_alloc(len);
201 if (ret) memcpy(ret, p, len);
202 return ret;
203 }
204
205 /******************************************************************
206 * apd_copyfile [internal]
207 *
208 * Copy a file from the driverdirectory to the versioned directory
209 *
210 * RETURNS
211 * Success: TRUE
212 * Failure: FALSE
213 *
214 */
215 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
216 {
217 LPWSTR ptr;
218 LPWSTR srcname;
219 DWORD res;
220
221 apd->src[apd->srclen] = '\0';
222 apd->dst[apd->dstlen] = '\0';
223
224 if (!filename || !filename[0]) {
225 /* nothing to copy */
226 return TRUE;
227 }
228
229 ptr = strrchrW(filename, '\\');
230 if (ptr) {
231 ptr++;
232 }
233 else
234 {
235 ptr = filename;
236 }
237
238 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
239 /* we have an absolute Path */
240 srcname = filename;
241 }
242 else
243 {
244 srcname = apd->src;
245 lstrcatW(srcname, ptr);
246 }
247 lstrcatW(apd->dst, ptr);
248
249 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
250
251 /* FIXME: handle APD_COPY_NEW_FILES */
252 res = CopyFileW(srcname, apd->dst, FALSE);
253 TRACE("got %u with %u\n", res, GetLastError());
254
255 return (apd->lazy) ? TRUE : res;
256 }
257
258 /******************************************************************
259 * copy_servername_from_name (internal)
260 *
261 * for an external server, the serverpart from the name is copied.
262 *
263 * RETURNS
264 * the length (in WCHAR) of the serverpart (0 for the local computer)
265 * (-length), when the name is to long
266 *
267 */
268 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
269 {
270 LPCWSTR server;
271 LPWSTR ptr;
272 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
273 DWORD len;
274 DWORD serverlen;
275
276 if (target) *target = '\0';
277
278 if (name == NULL) return 0;
279 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
280
281 server = &name[2];
282 /* skip over both backslash, find separator '\' */
283 ptr = strchrW(server, '\\');
284 serverlen = (ptr) ? ptr - server : lstrlenW(server);
285
286 /* servername is empty */
287 if (serverlen == 0) return 0;
288
289 TRACE("found %s\n", debugstr_wn(server, serverlen));
290
291 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
292
293 if (target) {
294 memcpy(target, server, serverlen * sizeof(WCHAR));
295 target[serverlen] = '\0';
296 }
297
298 len = sizeof(buffer) / sizeof(buffer[0]);
299 if (GetComputerNameW(buffer, &len)) {
300 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
301 /* The requested Servername is our computername */
302 return 0;
303 }
304 }
305 return serverlen;
306 }
307
308 /******************************************************************
309 * get_basename_from_name (internal)
310 *
311 * skip over the serverpart from the full name
312 *
313 */
314 static LPCWSTR get_basename_from_name(LPCWSTR name)
315 {
316 if (name == NULL) return NULL;
317 if ((name[0] == '\\') && (name[1] == '\\')) {
318 /* skip over the servername and search for the following '\' */
319 name = strchrW(&name[2], '\\');
320 if ((name) && (name[1])) {
321 /* found a separator ('\') followed by a name:
322 skip over the separator and return the rest */
323 name++;
324 }
325 else
326 {
327 /* no basename present (we found only a servername) */
328 return NULL;
329 }
330 }
331 return name;
332 }
333
334 /******************************************************************
335 * monitor_unload [internal]
336 *
337 * release a printmonitor and unload it from memory, when needed
338 *
339 */
340 static void monitor_unload(monitor_t * pm)
341 {
342 if (pm == NULL) return;
343 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
344
345 EnterCriticalSection(&monitor_handles_cs);
346
347 if (pm->refcount) pm->refcount--;
348
349 if (pm->refcount == 0) {
350 list_remove(&pm->entry);
351 FreeLibrary(pm->hdll);
352 heap_free(pm->name);
353 heap_free(pm->dllname);
354 heap_free(pm);
355 }
356 LeaveCriticalSection(&monitor_handles_cs);
357 }
358
359 /******************************************************************
360 * monitor_unloadall [internal]
361 *
362 * release all registered printmonitors and unload them from memory, when needed
363 *
364 */
365
366 static void monitor_unloadall(void)
367 {
368 monitor_t * pm;
369 monitor_t * next;
370
371 EnterCriticalSection(&monitor_handles_cs);
372 /* iterate through the list, with safety against removal */
373 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
374 {
375 /* skip monitorui dlls */
376 if (pm->monitor) monitor_unload(pm);
377 }
378 LeaveCriticalSection(&monitor_handles_cs);
379 }
380
381 /******************************************************************
382 * monitor_load [internal]
383 *
384 * load a printmonitor, get the dllname from the registry, when needed
385 * initialize the monitor and dump found function-pointers
386 *
387 * On failure, SetLastError() is called and NULL is returned
388 */
389
390 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
391 {
392 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
393 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
394 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
395 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
396 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
397
398 monitor_t * pm = NULL;
399 monitor_t * cursor;
400 LPWSTR regroot = NULL;
401 LPWSTR driver = dllname;
402
403 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
404 /* Is the Monitor already loaded? */
405 EnterCriticalSection(&monitor_handles_cs);
406
407 if (name) {
408 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
409 {
410 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
411 pm = cursor;
412 break;
413 }
414 }
415 }
416
417 if (pm == NULL) {
418 pm = heap_alloc_zero(sizeof(monitor_t));
419 if (pm == NULL) goto cleanup;
420 list_add_tail(&monitor_handles, &pm->entry);
421 }
422 pm->refcount++;
423
424 if (pm->name == NULL) {
425 /* Load the monitor */
426 LPMONITOREX pmonitorEx;
427 DWORD len;
428
429 if (name) {
430 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
431 regroot = heap_alloc(len * sizeof(WCHAR));
432 }
433
434 if (regroot) {
435 lstrcpyW(regroot, monitorsW);
436 lstrcatW(regroot, name);
437 /* Get the Driver from the Registry */
438 if (driver == NULL) {
439 HKEY hroot;
440 DWORD namesize;
441 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
442 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
443 &namesize) == ERROR_SUCCESS) {
444 driver = heap_alloc(namesize);
445 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
446 }
447 RegCloseKey(hroot);
448 }
449 }
450 }
451
452 pm->name = strdupW(name);
453 pm->dllname = strdupW(driver);
454
455 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
456 monitor_unload(pm);
457 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
458 pm = NULL;
459 goto cleanup;
460 }
461
462 pm->hdll = LoadLibraryW(driver);
463 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
464
465 if (pm->hdll == NULL) {
466 monitor_unload(pm);
467 SetLastError(ERROR_MOD_NOT_FOUND);
468 pm = NULL;
469 goto cleanup;
470 }
471
472 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
473 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
474 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
475 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
476 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
477
478
479 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
480 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
481 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
482 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
483 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
484
485 if (pInitializePrintMonitorUI != NULL) {
486 pm->monitorUI = pInitializePrintMonitorUI();
487 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
488 if (pm->monitorUI) {
489 TRACE("0x%08x: dwMonitorSize (%d)\n",
490 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
491
492 }
493 }
494
495 if (pInitializePrintMonitor && regroot) {
496 pmonitorEx = pInitializePrintMonitor(regroot);
497 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
498 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
499
500 if (pmonitorEx) {
501 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
502 pm->monitor = &(pmonitorEx->Monitor);
503 }
504 }
505
506 if (pm->monitor) {
507 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
508
509 }
510
511 if (!pm->monitor && regroot) {
512 if (pInitializePrintMonitor2 != NULL) {
513 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
514 }
515 if (pInitializeMonitorEx != NULL) {
516 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
517 }
518 if (pInitializeMonitor != NULL) {
519 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
520 }
521 }
522 if (!pm->monitor && !pm->monitorUI) {
523 monitor_unload(pm);
524 SetLastError(ERROR_PROC_NOT_FOUND);
525 pm = NULL;
526 }
527 }
528 cleanup:
529 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
530 pm->refcount++;
531 pm_localport = pm;
532 }
533 LeaveCriticalSection(&monitor_handles_cs);
534 if (driver != dllname) heap_free(driver);
535 heap_free(regroot);
536 TRACE("=> %p\n", pm);
537 return pm;
538 }
539
540 /******************************************************************
541 * monitor_loadall [internal]
542 *
543 * Load all registered monitors
544 *
545 */
546 static DWORD monitor_loadall(void)
547 {
548 monitor_t * pm;
549 DWORD registered = 0;
550 DWORD loaded = 0;
551 HKEY hmonitors;
552 WCHAR buffer[MAX_PATH];
553 DWORD id = 0;
554
555 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
556 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
557 NULL, NULL, NULL, NULL, NULL);
558
559 TRACE("%d monitors registered\n", registered);
560
561 while (id < registered) {
562 buffer[0] = '\0';
563 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
564 pm = monitor_load(buffer, NULL);
565 if (pm) loaded++;
566 id++;
567 }
568 RegCloseKey(hmonitors);
569 }
570 TRACE("%d monitors loaded\n", loaded);
571 return loaded;
572 }
573
574 /******************************************************************
575 * monitor_loadui [internal]
576 *
577 * load the userinterface-dll for a given portmonitor
578 *
579 * On failure, NULL is returned
580 */
581 static monitor_t * monitor_loadui(monitor_t * pm)
582 {
583 monitor_t * pui = NULL;
584 WCHAR buffer[MAX_PATH];
585 HANDLE hXcv;
586 DWORD len;
587 DWORD res;
588
589 if (pm == NULL) return NULL;
590 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
591
592 /* Try the Portmonitor first; works for many monitors */
593 if (pm->monitorUI) {
594 EnterCriticalSection(&monitor_handles_cs);
595 pm->refcount++;
596 LeaveCriticalSection(&monitor_handles_cs);
597 return pm;
598 }
599
600 /* query the userinterface-dllname from the Portmonitor */
601 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
602 /* building (",XcvMonitor %s",pm->name) not needed yet */
603 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
604 TRACE("got %u with %p\n", res, hXcv);
605 if (res) {
606 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
607 TRACE("got %u with %s\n", res, debugstr_w(buffer));
608 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
609 pm->monitor->pfnXcvClosePort(hXcv);
610 }
611 }
612 return pui;
613 }
614
615 /******************************************************************
616 * monitor_load_by_port [internal]
617 *
618 * load a printmonitor for a given port
619 *
620 * On failure, NULL is returned
621 */
622
623 static monitor_t * monitor_load_by_port(LPCWSTR portname)
624 {
625 HKEY hroot;
626 HKEY hport;
627 LPWSTR buffer;
628 monitor_t * pm = NULL;
629 DWORD registered = 0;
630 DWORD id = 0;
631 DWORD len;
632
633 TRACE("(%s)\n", debugstr_w(portname));
634
635 /* Try the Local Monitor first */
636 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
637 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
638 /* found the portname */
639 RegCloseKey(hroot);
640 return monitor_load(localportW, NULL);
641 }
642 RegCloseKey(hroot);
643 }
644
645 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
646 buffer = heap_alloc(len * sizeof(WCHAR));
647 if (buffer == NULL) return NULL;
648
649 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
650 EnterCriticalSection(&monitor_handles_cs);
651 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
652
653 while ((pm == NULL) && (id < registered)) {
654 buffer[0] = '\0';
655 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
656 TRACE("testing %s\n", debugstr_w(buffer));
657 len = lstrlenW(buffer);
658 lstrcatW(buffer, bs_ports_bsW);
659 lstrcatW(buffer, portname);
660 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
661 RegCloseKey(hport);
662 buffer[len] = '\0'; /* use only the Monitor-Name */
663 pm = monitor_load(buffer, NULL);
664 }
665 id++;
666 }
667 LeaveCriticalSection(&monitor_handles_cs);
668 RegCloseKey(hroot);
669 }
670 heap_free(buffer);
671 return pm;
672 }
673
674 /******************************************************************
675 * Return the number of bytes for an multi_sz string.
676 * The result includes all \0s
677 * (specifically the extra \0, that is needed as multi_sz terminator).
678 */
679 static int multi_sz_lenW(const WCHAR *str)
680 {
681 const WCHAR *ptr = str;
682 if (!str) return 0;
683 do
684 {
685 ptr += lstrlenW(ptr) + 1;
686 } while (*ptr);
687
688 return (ptr - str + 1) * sizeof(WCHAR);
689 }
690
691 /******************************************************************
692 * validate_envW [internal]
693 *
694 * validate the user-supplied printing-environment
695 *
696 * PARAMS
697 * env [I] PTR to Environment-String or NULL
698 *
699 * RETURNS
700 * Success: PTR to printenv_t
701 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
702 *
703 * NOTES
704 * An empty string is handled the same way as NULL.
705 *
706 */
707
708 static const printenv_t * validate_envW(LPCWSTR env)
709 {
710 const printenv_t *result = NULL;
711 unsigned int i;
712
713 TRACE("(%s)\n", debugstr_w(env));
714 if (env && env[0])
715 {
716 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
717 {
718 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
719 {
720 result = all_printenv[i];
721 break;
722 }
723 }
724 if (result == NULL) {
725 FIXME("unsupported Environment: %s\n", debugstr_w(env));
726 SetLastError(ERROR_INVALID_ENVIRONMENT);
727 }
728 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
729 }
730 else
731 {
732 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
733 }
734
735 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
736 return result;
737 }
738
739 /*****************************************************************************
740 * enumerate the local monitors (INTERNAL)
741 *
742 * returns the needed size (in bytes) for pMonitors
743 * and *lpreturned is set to number of entries returned in pMonitors
744 *
745 * Language-Monitors are also installed in the same Registry-Location but
746 * they are filtered in Windows (not returned by EnumMonitors).
747 * We do no filtering to simplify our Code.
748 *
749 */
750 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
751 {
752 HKEY hroot = NULL;
753 HKEY hentry = NULL;
754 LPWSTR ptr;
755 LPMONITOR_INFO_2W mi;
756 WCHAR buffer[MAX_PATH];
757 WCHAR dllname[MAX_PATH];
758 DWORD dllsize;
759 DWORD len;
760 DWORD index = 0;
761 DWORD needed = 0;
762 DWORD numentries;
763 DWORD entrysize;
764
765 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
766
767 numentries = *lpreturned; /* this is 0, when we scan the registry */
768 len = entrysize * numentries;
769 ptr = (LPWSTR) &pMonitors[len];
770
771 numentries = 0;
772 len = sizeof(buffer)/sizeof(buffer[0]);
773 buffer[0] = '\0';
774
775 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
776 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
777 /* Scan all Monitor-Registry-Keys */
778 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
779 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
780 dllsize = sizeof(dllname);
781 dllname[0] = '\0';
782
783 /* The Monitor must have a Driver-DLL */
784 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
785 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
786 /* We found a valid DLL for this Monitor. */
787 TRACE("using Driver: %s\n", debugstr_w(dllname));
788 }
789 RegCloseKey(hentry);
790 }
791
792 /* Windows returns only Port-Monitors here, but to simplify our code,
793 we do no filtering for Language-Monitors */
794 if (dllname[0]) {
795 numentries++;
796 needed += entrysize;
797 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
798 if (level > 1) {
799 /* we install and return only monitors for "Windows NT x86" */
800 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
801 needed += dllsize;
802 }
803
804 /* required size is calculated. Now fill the user-buffer */
805 if (pMonitors && (cbBuf >= needed)){
806 mi = (LPMONITOR_INFO_2W) pMonitors;
807 pMonitors += entrysize;
808
809 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
810 mi->pName = ptr;
811 lstrcpyW(ptr, buffer); /* Name of the Monitor */
812 ptr += (len+1); /* len is lstrlenW(monitorname) */
813 if (level > 1) {
814 mi->pEnvironment = ptr;
815 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
816 ptr += (lstrlenW(x86_envnameW)+1);
817
818 mi->pDLLName = ptr;
819 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
820 ptr += (dllsize / sizeof(WCHAR));
821 }
822 }
823 }
824 index++;
825 len = sizeof(buffer)/sizeof(buffer[0]);
826 buffer[0] = '\0';
827 }
828 RegCloseKey(hroot);
829 }
830 *lpreturned = numentries;
831 TRACE("need %d byte for %d entries\n", needed, numentries);
832 return needed;
833 }
834
835 /*****************************************************************************
836 * enumerate the local print processors (INTERNAL)
837 *
838 * returns the needed size (in bytes) for pPPInfo
839 * and *lpreturned is set to number of entries returned in pPPInfo
840 *
841 */
842 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
843 {
844 HKEY hroot = NULL;
845 HKEY hentry = NULL;
846 LPWSTR ptr;
847 PPRINTPROCESSOR_INFO_1W ppi;
848 WCHAR buffer[MAX_PATH];
849 WCHAR dllname[MAX_PATH];
850 DWORD dllsize;
851 DWORD len;
852 DWORD index = 0;
853 DWORD needed = 0;
854 DWORD numentries;
855
856 numentries = *lpreturned; /* this is 0, when we scan the registry */
857 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
858 ptr = (LPWSTR) &pPPInfo[len];
859
860 numentries = 0;
861 len = sizeof(buffer)/sizeof(buffer[0]);
862 buffer[0] = '\0';
863
864 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
865 /* add "winprint" first */
866 numentries++;
867 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
868 if (pPPInfo && (cbBuf >= needed)){
869 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
870 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
871
872 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
873 ppi->pName = ptr;
874 lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
875 ptr += sizeof(winprintW) / sizeof(WCHAR);
876 }
877
878 /* Scan all Printprocessor Keys */
879 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
880 (lstrcmpiW(buffer, winprintW) != 0)) {
881 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
882 dllsize = sizeof(dllname);
883 dllname[0] = '\0';
884
885 /* The Print Processor must have a Driver-DLL */
886 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
887 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
888 /* We found a valid DLL for this Print Processor */
889 TRACE("using Driver: %s\n", debugstr_w(dllname));
890 }
891 RegCloseKey(hentry);
892 }
893
894 if (dllname[0]) {
895 numentries++;
896 needed += sizeof(PRINTPROCESSOR_INFO_1W);
897 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
898
899 /* required size is calculated. Now fill the user-buffer */
900 if (pPPInfo && (cbBuf >= needed)){
901 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
902 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
903
904 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
905 ppi->pName = ptr;
906 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
907 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
908 }
909 }
910 index++;
911 len = sizeof(buffer)/sizeof(buffer[0]);
912 buffer[0] = '\0';
913 }
914 RegCloseKey(hroot);
915 }
916 *lpreturned = numentries;
917 TRACE("need %d byte for %d entries\n", needed, numentries);
918 return needed;
919 }
920
921 /******************************************************************
922 * enumerate the local Ports from all loaded monitors (internal)
923 *
924 * returns the needed size (in bytes) for pPorts
925 * and *lpreturned is set to number of entries returned in pPorts
926 *
927 */
928 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
929 {
930 monitor_t * pm;
931 LPWSTR ptr;
932 LPPORT_INFO_2W cache;
933 LPPORT_INFO_2W out;
934 LPBYTE pi_buffer = NULL;
935 DWORD pi_allocated = 0;
936 DWORD pi_needed;
937 DWORD pi_index;
938 DWORD pi_returned;
939 DWORD res;
940 DWORD outindex = 0;
941 DWORD needed;
942 DWORD numentries;
943 DWORD entrysize;
944
945
946 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
947 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
948
949 numentries = *lpreturned; /* this is 0, when we scan the registry */
950 needed = entrysize * numentries;
951 ptr = (LPWSTR) &pPorts[needed];
952
953 numentries = 0;
954 needed = 0;
955
956 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
957 {
958 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
959 pi_needed = 0;
960 pi_returned = 0;
961 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
962 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
963 /* Do not use heap_realloc (we do not need the old data in the buffer) */
964 heap_free(pi_buffer);
965 pi_buffer = heap_alloc(pi_needed);
966 pi_allocated = (pi_buffer) ? pi_needed : 0;
967 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
968 }
969 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
970 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
971
972 numentries += pi_returned;
973 needed += pi_needed;
974
975 /* fill the output-buffer (pPorts), if we have one */
976 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
977 pi_index = 0;
978 while (pi_returned > pi_index) {
979 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
980 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
981 out->pPortName = ptr;
982 lstrcpyW(ptr, cache->pPortName);
983 ptr += (lstrlenW(ptr)+1);
984 if (level > 1) {
985 out->pMonitorName = ptr;
986 lstrcpyW(ptr, cache->pMonitorName);
987 ptr += (lstrlenW(ptr)+1);
988
989 out->pDescription = ptr;
990 lstrcpyW(ptr, cache->pDescription);
991 ptr += (lstrlenW(ptr)+1);
992 out->fPortType = cache->fPortType;
993 out->Reserved = cache->Reserved;
994 }
995 pi_index++;
996 outindex++;
997 }
998 }
999 }
1000 }
1001 /* the temporary portinfo-buffer is no longer needed */
1002 heap_free(pi_buffer);
1003
1004 *lpreturned = numentries;
1005 TRACE("need %d byte for %d entries\n", needed, numentries);
1006 return needed;
1007 }
1008
1009
1010 /*****************************************************************************
1011 * open_driver_reg [internal]
1012 *
1013 * opens the registry for the printer drivers depending on the given input
1014 * variable pEnvironment
1015 *
1016 * RETURNS:
1017 * Success: the opened hkey
1018 * Failure: NULL
1019 */
1020 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1021 {
1022 HKEY retval = NULL;
1023 LPWSTR buffer;
1024 const printenv_t * env;
1025
1026 TRACE("(%s)\n", debugstr_w(pEnvironment));
1027
1028 env = validate_envW(pEnvironment);
1029 if (!env) return NULL;
1030
1031 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1032 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1033
1034 if (buffer) {
1035 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1036 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1037 HeapFree(GetProcessHeap(), 0, buffer);
1038 }
1039 return retval;
1040 }
1041
1042 /*****************************************************************************
1043 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1044 *
1045 * Return the PATH for the Printer-Drivers
1046 *
1047 * PARAMS
1048 * pName [I] Servername (NT only) or NULL (local Computer)
1049 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1050 * Level [I] Structure-Level (must be 1)
1051 * pDriverDirectory [O] PTR to Buffer that receives the Result
1052 * cbBuf [I] Size of Buffer at pDriverDirectory
1053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1054 * required for pDriverDirectory
1055 *
1056 * RETURNS
1057 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1058 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1059 * if cbBuf is too small
1060 *
1061 * Native Values returned in pDriverDirectory on Success:
1062 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1063 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1064 *| win9x(Windows 4.0): "%winsysdir%"
1065 *
1066 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1067 *
1068 */
1069 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1070 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1071 {
1072 DWORD needed;
1073 const printenv_t * env;
1074
1075 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1076 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1077
1078 if (pName != NULL && pName[0]) {
1079 FIXME("server %s not supported\n", debugstr_w(pName));
1080 SetLastError(ERROR_INVALID_PARAMETER);
1081 return FALSE;
1082 }
1083
1084 env = validate_envW(pEnvironment);
1085 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1086
1087
1088 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1089 needed = GetSystemDirectoryW(NULL, 0);
1090 /* add the Size for the Subdirectories */
1091 needed += lstrlenW(spooldriversW);
1092 needed += lstrlenW(env->subdir);
1093 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1094
1095 *pcbNeeded = needed;
1096
1097 if (needed > cbBuf) {
1098 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1099 return FALSE;
1100 }
1101
1102 if (pDriverDirectory == NULL) {
1103 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1104 SetLastError(ERROR_INVALID_USER_BUFFER);
1105 return FALSE;
1106 }
1107
1108 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1109 /* add the Subdirectories */
1110 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1111 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1112
1113 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1114 return TRUE;
1115 }
1116
1117 /******************************************************************
1118 * driver_load [internal]
1119 *
1120 * load a driver user interface dll
1121 *
1122 * On failure, NULL is returned
1123 *
1124 */
1125
1126 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1127 {
1128 WCHAR fullname[MAX_PATH];
1129 HMODULE hui;
1130 DWORD len;
1131
1132 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1133
1134 /* build the driverdir */
1135 len = sizeof(fullname) -
1136 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1137
1138 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1139 (LPBYTE) fullname, len, &len)) {
1140 /* Should never Fail */
1141 SetLastError(ERROR_BUFFER_OVERFLOW);
1142 return NULL;
1143 }
1144
1145 lstrcatW(fullname, env->versionsubdir);
1146 lstrcatW(fullname, backslashW);
1147 lstrcatW(fullname, dllname);
1148
1149 hui = LoadLibraryW(fullname);
1150 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1151
1152 return hui;
1153 }
1154
1155 /******************************************************************
1156 * printer_free
1157 * free the data pointer of an opened printer
1158 */
1159 static VOID printer_free(printer_t * printer)
1160 {
1161 if (printer->hXcv)
1162 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1163
1164 monitor_unload(printer->pm);
1165
1166 heap_free(printer->printername);
1167 heap_free(printer->name);
1168 heap_free(printer);
1169 }
1170
1171 /******************************************************************
1172 * printer_alloc_handle
1173 * alloc a printer handle and remember the data pointer in the printer handle table
1174 *
1175 */
1176 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1177 {
1178 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1179 printer_t *printer = NULL;
1180 LPCWSTR printername;
1181 HKEY hkeyPrinters;
1182 HKEY hkeyPrinter;
1183 DWORD len;
1184
1185 if (copy_servername_from_name(name, servername)) {
1186 FIXME("server %s not supported\n", debugstr_w(servername));
1187 SetLastError(ERROR_INVALID_PRINTER_NAME);
1188 return NULL;
1189 }
1190
1191 printername = get_basename_from_name(name);
1192 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1193
1194 /* an empty printername is invalid */
1195 if (printername && (!printername[0])) {
1196 SetLastError(ERROR_INVALID_PARAMETER);
1197 return NULL;
1198 }
1199
1200 printer = heap_alloc_zero(sizeof(printer_t));
1201 if (!printer) goto end;
1202
1203 /* clone the base name. This is NULL for the printserver */
1204 printer->printername = strdupW(printername);
1205
1206 /* clone the full name */
1207 printer->name = strdupW(name);
1208 if (name && (!printer->name)) {
1209 printer_free(printer);
1210 printer = NULL;
1211 }
1212 if (printername) {
1213 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1214 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1215 /* OpenPrinter(",XcvMonitor ", ...) detected */
1216 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1217 printer->pm = monitor_load(&printername[len], NULL);
1218 if (printer->pm == NULL) {
1219 printer_free(printer);
1220 SetLastError(ERROR_UNKNOWN_PORT);
1221 printer = NULL;
1222 goto end;
1223 }
1224 }
1225 else
1226 {
1227 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1228 if (strncmpW( printername, XcvPortW, len) == 0) {
1229 /* OpenPrinter(",XcvPort ", ...) detected */
1230 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1231 printer->pm = monitor_load_by_port(&printername[len]);
1232 if (printer->pm == NULL) {
1233 printer_free(printer);
1234 SetLastError(ERROR_UNKNOWN_PORT);
1235 printer = NULL;
1236 goto end;
1237 }
1238 }
1239 }
1240
1241 if (printer->pm) {
1242 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1243 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1244 pDefault ? pDefault->DesiredAccess : 0,
1245 &printer->hXcv);
1246 }
1247 if (printer->hXcv == NULL) {
1248 printer_free(printer);
1249 SetLastError(ERROR_INVALID_PARAMETER);
1250 printer = NULL;
1251 goto end;
1252 }
1253 }
1254 else
1255 {
1256 /* Does the Printer exist? */
1257 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1258 ERR("Can't create Printers key\n");
1259 printer_free(printer);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME);
1261 printer = NULL;
1262 goto end;
1263 }
1264 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1265 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1266 RegCloseKey(hkeyPrinters);
1267 printer_free(printer);
1268 SetLastError(ERROR_INVALID_PRINTER_NAME);
1269 printer = NULL;
1270 goto end;
1271 }
1272 RegCloseKey(hkeyPrinter);
1273 RegCloseKey(hkeyPrinters);
1274 }
1275 }
1276 else
1277 {
1278 TRACE("using the local printserver\n");
1279 }
1280
1281 end:
1282
1283 TRACE("==> %p\n", printer);
1284 return (HANDLE)printer;
1285 }
1286
1287
1288 /******************************************************************************
1289 * myAddPrinterDriverEx [internal]
1290 *
1291 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1292 * and a special mode with lazy error checking.
1293 *
1294 */
1295 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1296 {
1297 const printenv_t *env;
1298 apd_data_t apd;
1299 DRIVER_INFO_8W di;
1300 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1301 HMODULE hui;
1302 LPWSTR ptr;
1303 HKEY hroot;
1304 HKEY hdrv;
1305 DWORD disposition;
1306 DWORD len;
1307 LONG lres;
1308 BOOL res;
1309
1310 /* we need to set all entries in the Registry, independent from the Level of
1311 DRIVER_INFO, that the caller supplied */
1312
1313 ZeroMemory(&di, sizeof(di));
1314 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1315 memcpy(&di, pDriverInfo, di_sizeof[level]);
1316 }
1317
1318 /* dump the most used infos */
1319 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1320 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1321 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1322 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1323 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1324 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1325 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1326 /* dump only the first of the additional Files */
1327 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1328
1329
1330 /* check environment */
1331 env = validate_envW(di.pEnvironment);
1332 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1333
1334 /* fill the copy-data / get the driverdir */
1335 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1336 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1337 (LPBYTE) apd.src, len, &len)) {
1338 /* Should never Fail */
1339 return FALSE;
1340 }
1341 memcpy(apd.dst, apd.src, len);
1342 lstrcatW(apd.src, backslashW);
1343 apd.srclen = lstrlenW(apd.src);
1344 lstrcatW(apd.dst, env->versionsubdir);
1345 lstrcatW(apd.dst, backslashW);
1346 apd.dstlen = lstrlenW(apd.dst);
1347 apd.copyflags = dwFileCopyFlags;
1348 apd.lazy = lazy;
1349 CreateDirectoryW(apd.src, NULL);
1350 CreateDirectoryW(apd.dst, NULL);
1351
1352 hroot = open_driver_reg(env->envname);
1353 if (!hroot) {
1354 ERR("Can't create Drivers key\n");
1355 return FALSE;
1356 }
1357
1358 /* Fill the Registry for the Driver */
1359 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1360 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1361 &hdrv, &disposition)) != ERROR_SUCCESS) {
1362
1363 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1364 RegCloseKey(hroot);
1365 SetLastError(lres);
1366 return FALSE;
1367 }
1368 RegCloseKey(hroot);
1369
1370 if (disposition == REG_OPENED_EXISTING_KEY) {
1371 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1372 RegCloseKey(hdrv);
1373 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1374 return FALSE;
1375 }
1376
1377 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1378 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1379 sizeof(DWORD));
1380
1381 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1382 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1383 apd_copyfile(di.pDriverPath, &apd);
1384
1385 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1386 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1387 apd_copyfile(di.pDataFile, &apd);
1388
1389 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1390 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1391 apd_copyfile(di.pConfigFile, &apd);
1392
1393 /* settings for level 3 */
1394 if (di.pHelpFile)
1395 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1396 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1397 else
1398 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1399 apd_copyfile(di.pHelpFile, &apd);
1400
1401
1402 ptr = di.pDependentFiles;
1403 if (ptr)
1404 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1405 multi_sz_lenW(di.pDependentFiles));
1406 else
1407 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1408 while ((ptr != NULL) && (ptr[0])) {
1409 if (apd_copyfile(ptr, &apd)) {
1410 ptr += lstrlenW(ptr) + 1;
1411 }
1412 else
1413 {
1414 WARN("Failed to copy %s\n", debugstr_w(ptr));
1415 ptr = NULL;
1416 }
1417 }
1418 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1419 if (di.pMonitorName)
1420 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1421 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1422 else
1423 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1424
1425 if (di.pDefaultDataType)
1426 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1427 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1428 else
1429 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1430
1431 /* settings for level 4 */
1432 if (di.pszzPreviousNames)
1433 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1434 multi_sz_lenW(di.pszzPreviousNames));
1435 else
1436 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1437
1438 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1439
1440 RegCloseKey(hdrv);
1441 hui = driver_load(env, di.pConfigFile);
1442 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1443 if (hui && pDrvDriverEvent) {
1444
1445 /* Support for DrvDriverEvent is optional */
1446 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1447 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1448 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1449 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1450 }
1451 FreeLibrary(hui);
1452
1453 TRACE("=> TRUE with %u\n", GetLastError());
1454 return TRUE;
1455
1456 }
1457
1458 /******************************************************************************
1459 * fpAddMonitor [exported through PRINTPROVIDOR]
1460 *
1461 * Install a Printmonitor
1462 *
1463 * PARAMS
1464 * pName [I] Servername or NULL (local Computer)
1465 * Level [I] Structure-Level (Must be 2)
1466 * pMonitors [I] PTR to MONITOR_INFO_2
1467 *
1468 * RETURNS
1469 * Success: TRUE
1470 * Failure: FALSE
1471 *
1472 * NOTES
1473 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1474 *
1475 */
1476 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1477 {
1478 monitor_t * pm = NULL;
1479 LPMONITOR_INFO_2W mi2w;
1480 HKEY hroot = NULL;
1481 HKEY hentry = NULL;
1482 DWORD disposition;
1483 BOOL res = FALSE;
1484
1485 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1486 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1487 debugstr_w(mi2w ? mi2w->pName : NULL),
1488 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1489 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1490
1491 if (copy_servername_from_name(pName, NULL)) {
1492 FIXME("server %s not supported\n", debugstr_w(pName));
1493 SetLastError(ERROR_ACCESS_DENIED);
1494 return FALSE;
1495 }
1496
1497 if (!mi2w->pName || (! mi2w->pName[0])) {
1498 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1499 SetLastError(ERROR_INVALID_PARAMETER);
1500 return FALSE;
1501 }
1502 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1503 WARN("Environment %s requested (we support only %s)\n",
1504 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1505 SetLastError(ERROR_INVALID_ENVIRONMENT);
1506 return FALSE;
1507 }
1508
1509 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1510 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1511 SetLastError(ERROR_INVALID_PARAMETER);
1512 return FALSE;
1513 }
1514
1515 /* Load and initialize the monitor. SetLastError() is called on failure */
1516 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1517 return FALSE;
1518 }
1519 monitor_unload(pm);
1520
1521 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1523 return FALSE;
1524 }
1525
1526 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1527 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1528 &disposition) == ERROR_SUCCESS) {
1529
1530 /* Some installers set options for the port before calling AddMonitor.
1531 We query the "Driver" entry to verify that the monitor is installed,
1532 before we return an error.
1533 When a user installs two print monitors at the same time with the
1534 same name, a race condition is possible but silently ignored. */
1535
1536 DWORD namesize = 0;
1537
1538 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1539 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1540 &namesize) == ERROR_SUCCESS)) {
1541 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1542 /* 9x use ERROR_ALREADY_EXISTS */
1543 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1544 }
1545 else
1546 {
1547 INT len;
1548 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1549 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1550 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1551 }
1552 RegCloseKey(hentry);
1553 }
1554
1555 RegCloseKey(hroot);
1556 return (res);
1557 }
1558
1559 /******************************************************************************
1560 * fpAddPort [exported through PRINTPROVIDOR]
1561 *
1562 * Add a Port for a specific Monitor
1563 *
1564 * PARAMS
1565 * pName [I] Servername or NULL (local Computer)
1566 * hWnd [I] Handle to parent Window for the Dialog-Box
1567 * pMonitorName [I] Name of the Monitor that manage the Port
1568 *
1569 * RETURNS
1570 * Success: TRUE
1571 * Failure: FALSE
1572 *
1573 */
1574 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1575 {
1576 monitor_t * pm;
1577 monitor_t * pui;
1578 LONG lres;
1579 DWORD res;
1580
1581 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1582
1583 lres = copy_servername_from_name(pName, NULL);
1584 if (lres) {
1585 FIXME("server %s not supported\n", debugstr_w(pName));
1586 SetLastError(ERROR_INVALID_PARAMETER);
1587 return FALSE;
1588 }
1589
1590 /* an empty Monitorname is Invalid */
1591 if (!pMonitorName[0]) {
1592 SetLastError(ERROR_NOT_SUPPORTED);
1593 return FALSE;
1594 }
1595
1596 pm = monitor_load(pMonitorName, NULL);
1597 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
1598 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
1599 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1600 }
1601 else
1602 {
1603 pui = monitor_loadui(pm);
1604 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1605 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1606 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1607 }
1608 else
1609 {
1610 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1611 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1612 pui, debugstr_w(pui ? pui->dllname : NULL));
1613
1614 SetLastError(ERROR_NOT_SUPPORTED);
1615 res = FALSE;
1616 }
1617 monitor_unload(pui);
1618 }
1619 monitor_unload(pm);
1620
1621 TRACE("returning %d with %u\n", res, GetLastError());
1622 return res;
1623 }
1624
1625 /******************************************************************************
1626 * fpAddPortEx [exported through PRINTPROVIDOR]
1627 *
1628 * Add a Port for a specific Monitor, without presenting a user interface
1629 *
1630 * PARAMS
1631 * pName [I] Servername or NULL (local Computer)
1632 * level [I] Structure-Level (1 or 2) for pBuffer
1633 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1634 * pMonitorName [I] Name of the Monitor that manage the Port
1635 *
1636 * RETURNS
1637 * Success: TRUE
1638 * Failure: FALSE
1639 *
1640 */
1641 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1642 {
1643 PORT_INFO_2W * pi2;
1644 monitor_t * pm;
1645 DWORD lres;
1646 DWORD res;
1647
1648 pi2 = (PORT_INFO_2W *) pBuffer;
1649
1650 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1651 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1652 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1653 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1654
1655 lres = copy_servername_from_name(pName, NULL);
1656 if (lres) {
1657 FIXME("server %s not supported\n", debugstr_w(pName));
1658 SetLastError(ERROR_INVALID_PARAMETER);
1659 return FALSE;
1660 }
1661
1662 if ((level < 1) || (level > 2)) {
1663 SetLastError(ERROR_INVALID_LEVEL);
1664 return FALSE;
1665 }
1666
1667 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1668 SetLastError(ERROR_INVALID_PARAMETER);
1669 return FALSE;
1670 }
1671
1672 /* load the Monitor */
1673 pm = monitor_load(pMonitorName, NULL);
1674 if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
1675 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
1676 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1677 }
1678 else
1679 {
1680 FIXME("not implemented for %s (monitor %p: %s)\n",
1681 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : NULL);
1682 SetLastError(ERROR_INVALID_PARAMETER);
1683 res = FALSE;
1684 }
1685 monitor_unload(pm);
1686 return res;
1687 }
1688
1689 /******************************************************************************
1690 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1691 *
1692 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1693 *
1694 * PARAMS
1695 * pName [I] Servername or NULL (local Computer)
1696 * level [I] Level for the supplied DRIVER_INFO_*W struct
1697 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1698 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1699 *
1700 * RESULTS
1701 * Success: TRUE
1702 * Failure: FALSE
1703 *
1704 */
1705 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1706 {
1707 LONG lres;
1708
1709 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1710 lres = copy_servername_from_name(pName, NULL);
1711 if (lres) {
1712 FIXME("server %s not supported\n", debugstr_w(pName));
1713 SetLastError(ERROR_ACCESS_DENIED);
1714 return FALSE;
1715 }
1716
1717 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1718 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1719 }
1720
1721 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1722 }
1723
1724 /******************************************************************************
1725 * fpClosePrinter [exported through PRINTPROVIDOR]
1726 *
1727 * Close a printer handle and free associated resources
1728 *
1729 * PARAMS
1730 * hPrinter [I] Printerhandle to close
1731 *
1732 * RESULTS
1733 * Success: TRUE
1734 * Failure: FALSE
1735 *
1736 */
1737 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1738 {
1739 printer_t *printer = (printer_t *) hPrinter;
1740
1741 TRACE("(%p)\n", hPrinter);
1742
1743 if (printer) {
1744 printer_free(printer);
1745 return TRUE;
1746 }
1747 return FALSE;
1748 }
1749
1750 /******************************************************************************
1751 * fpConfigurePort [exported through PRINTPROVIDOR]
1752 *
1753 * Display the Configuration-Dialog for a specific Port
1754 *
1755 * PARAMS
1756 * pName [I] Servername or NULL (local Computer)
1757 * hWnd [I] Handle to parent Window for the Dialog-Box
1758 * pPortName [I] Name of the Port, that should be configured
1759 *
1760 * RETURNS
1761 * Success: TRUE
1762 * Failure: FALSE
1763 *
1764 */
1765 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1766 {
1767 monitor_t * pm;
1768 monitor_t * pui;
1769 LONG lres;
1770 DWORD res;
1771
1772 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1773
1774 lres = copy_servername_from_name(pName, NULL);
1775 if (lres) {
1776 FIXME("server %s not supported\n", debugstr_w(pName));
1777 SetLastError(ERROR_INVALID_NAME);
1778 return FALSE;
1779 }
1780
1781 /* an empty Portname is Invalid, but can popup a Dialog */
1782 if (!pPortName[0]) {
1783 SetLastError(ERROR_NOT_SUPPORTED);
1784 return FALSE;
1785 }
1786
1787 pm = monitor_load_by_port(pPortName);
1788 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1789 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1790 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1791 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1792 TRACE("got %d with %u\n", res, GetLastError());
1793 }
1794 else
1795 {
1796 pui = monitor_loadui(pm);
1797 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1798 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1799 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1800 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1801 TRACE("got %d with %u\n", res, GetLastError());
1802 }
1803 else
1804 {
1805 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1806 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1807 pui, debugstr_w(pui ? pui->dllname : NULL));
1808
1809 SetLastError(ERROR_NOT_SUPPORTED);
1810 res = FALSE;
1811 }
1812 monitor_unload(pui);
1813 }
1814 monitor_unload(pm);
1815
1816 TRACE("returning %d with %u\n", res, GetLastError());
1817 return res;
1818 }
1819
1820 /******************************************************************
1821 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1822 *
1823 * Delete a specific Printmonitor from a Printing-Environment
1824 *
1825 * PARAMS
1826 * pName [I] Servername or NULL (local Computer)
1827 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1828 * pMonitorName [I] Name of the Monitor, that should be deleted
1829 *
1830 * RETURNS
1831 * Success: TRUE
1832 * Failure: FALSE
1833 *
1834 * NOTES
1835 * pEnvironment is ignored in Windows for the local Computer.
1836 *
1837 */
1838
1839 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1840 {
1841 HKEY hroot = NULL;
1842 LONG lres;
1843
1844 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1845 debugstr_w(pMonitorName));
1846
1847 lres = copy_servername_from_name(pName, NULL);
1848 if (lres) {
1849 FIXME("server %s not supported\n", debugstr_w(pName));
1850 SetLastError(ERROR_INVALID_NAME);
1851 return FALSE;
1852 }
1853
1854 /* pEnvironment is ignored in Windows for the local Computer */
1855 if (!pMonitorName || !pMonitorName[0]) {
1856 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1857 SetLastError(ERROR_INVALID_PARAMETER);
1858 return FALSE;
1859 }
1860
1861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1862 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1863 return FALSE;
1864 }
1865
1866 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1867 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1868 RegCloseKey(hroot);
1869 return TRUE;
1870 }
1871
1872 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1873 RegCloseKey(hroot);
1874
1875 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1876 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1877 return FALSE;
1878 }
1879
1880 /*****************************************************************************
1881 * fpDeletePort [exported through PRINTPROVIDOR]
1882 *
1883 * Delete a specific Port
1884 *
1885 * PARAMS
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1889 *
1890 * RETURNS
1891 * Success: TRUE
1892 * Failure: FALSE
1893 *
1894 */
1895 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1896 {
1897 monitor_t * pm;
1898 monitor_t * pui;
1899 LONG lres;
1900 DWORD res;
1901
1902 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1903
1904 lres = copy_servername_from_name(pName, NULL);
1905 if (lres) {
1906 FIXME("server %s not supported\n", debugstr_w(pName));
1907 SetLastError(ERROR_INVALID_NAME);
1908 return FALSE;
1909 }
1910
1911 /* an empty Portname is Invalid */
1912 if (!pPortName[0]) {
1913 SetLastError(ERROR_NOT_SUPPORTED);
1914 return FALSE;
1915 }
1916
1917 pm = monitor_load_by_port(pPortName);
1918 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1919 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1920 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1921 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1922 TRACE("got %d with %u\n", res, GetLastError());
1923 }
1924 else
1925 {
1926 pui = monitor_loadui(pm);
1927 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1928 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1929 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1930 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1931 TRACE("got %d with %u\n", res, GetLastError());
1932 }
1933 else
1934 {
1935 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1936 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1937 pui, debugstr_w(pui ? pui->dllname : NULL));
1938
1939 SetLastError(ERROR_NOT_SUPPORTED);
1940 res = FALSE;
1941 }
1942 monitor_unload(pui);
1943 }
1944 monitor_unload(pm);
1945
1946 TRACE("returning %d with %u\n", res, GetLastError());
1947 return res;
1948 }
1949
1950 /*****************************************************************************
1951 * fpEnumMonitors [exported through PRINTPROVIDOR]
1952 *
1953 * Enumerate available Port-Monitors
1954 *
1955 * PARAMS
1956 * pName [I] Servername or NULL (local Computer)
1957 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1958 * pMonitors [O] PTR to Buffer that receives the Result
1959 * cbBuf [I] Size of Buffer at pMonitors
1960 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1961 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1962 *
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1966 *
1967 * NOTES
1968 * Windows reads the Registry once and cache the Results.
1969 *
1970 */
1971 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1972 LPDWORD pcbNeeded, LPDWORD pcReturned)
1973 {
1974 DWORD numentries = 0;
1975 DWORD needed = 0;
1976 LONG lres;
1977 BOOL res = FALSE;
1978
1979 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1980 cbBuf, pcbNeeded, pcReturned);
1981
1982 lres = copy_servername_from_name(pName, NULL);
1983 if (lres) {
1984 FIXME("server %s not supported\n", debugstr_w(pName));
1985 SetLastError(ERROR_INVALID_NAME);
1986 goto em_cleanup;
1987 }
1988
1989 if (!Level || (Level > 2)) {
1990 WARN("level (%d) is ignored in win9x\n", Level);
1991 SetLastError(ERROR_INVALID_LEVEL);
1992 return FALSE;
1993 }
1994
1995 /* Scan all Monitor-Keys */
1996 numentries = 0;
1997 needed = get_local_monitors(Level, NULL, 0, &numentries);
1998
1999 /* we calculated the needed buffersize. now do more error-checks */
2000 if (cbBuf < needed) {
2001 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2002 goto em_cleanup;
2003 }
2004
2005 /* fill the Buffer with the Monitor-Keys */
2006 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2007 res = TRUE;
2008
2009 em_cleanup:
2010 if (pcbNeeded) *pcbNeeded = needed;
2011 if (pcReturned) *pcReturned = numentries;
2012
2013 TRACE("returning %d with %d (%d byte for %d entries)\n",
2014 res, GetLastError(), needed, numentries);
2015
2016 return (res);
2017 }
2018
2019 /******************************************************************************
2020 * fpEnumPorts [exported through PRINTPROVIDOR]
2021 *
2022 * Enumerate available Ports
2023 *
2024 * PARAMS
2025 * pName [I] Servername or NULL (local Computer)
2026 * Level [I] Structure-Level (1 or 2)
2027 * pPorts [O] PTR to Buffer that receives the Result
2028 * cbBuf [I] Size of Buffer at pPorts
2029 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2030 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2031 *
2032 * RETURNS
2033 * Success: TRUE
2034 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2035 *
2036 */
2037 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2038 LPDWORD pcbNeeded, LPDWORD pcReturned)
2039 {
2040 DWORD needed = 0;
2041 DWORD numentries = 0;
2042 LONG lres;
2043 BOOL res = FALSE;
2044
2045 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2046 cbBuf, pcbNeeded, pcReturned);
2047
2048 lres = copy_servername_from_name(pName, NULL);
2049 if (lres) {
2050 FIXME("server %s not supported\n", debugstr_w(pName));
2051 SetLastError(ERROR_INVALID_NAME);
2052 goto emP_cleanup;
2053 }
2054
2055 if (!Level || (Level > 2)) {
2056 SetLastError(ERROR_INVALID_LEVEL);
2057 goto emP_cleanup;
2058 }
2059
2060 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2061 SetLastError(RPC_X_NULL_REF_POINTER);
2062 goto emP_cleanup;
2063 }
2064
2065 EnterCriticalSection(&monitor_handles_cs);
2066 monitor_loadall();
2067
2068 /* Scan all local Ports */
2069 numentries = 0;
2070 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2071
2072 /* we calculated the needed buffersize. now do the error-checks */
2073 if (cbBuf < needed) {
2074 monitor_unloadall();
2075 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2076 goto emP_cleanup_cs;
2077 }
2078 else if (!pPorts || !pcReturned) {
2079 monitor_unloadall();
2080 SetLastError(RPC_X_NULL_REF_POINTER);
2081 goto emP_cleanup_cs;
2082 }
2083
2084 /* Fill the Buffer */
2085 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2086 res = TRUE;
2087 monitor_unloadall();
2088
2089 emP_cleanup_cs:
2090 LeaveCriticalSection(&monitor_handles_cs);
2091
2092 emP_cleanup:
2093 if (pcbNeeded) *pcbNeeded = needed;
2094 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2095
2096 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2097 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2098
2099 return (res);
2100 }
2101
2102 /*****************************************************************************
2103 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2104 *
2105 * Enumerate available Print Processors
2106 *
2107 * PARAMS
2108 * pName [I] Servername or NULL (local Computer)
2109 * pEnvironment [I] Printing-Environment or NULL (Default)
2110 * Level [I] Structure-Level (Only 1 is allowed)
2111 * pPPInfo [O] PTR to Buffer that receives the Result
2112 * cbBuf [I] Size of Buffer at pMonitors
2113 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2114 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2115 *
2116 * RETURNS
2117 * Success: TRUE
2118 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2119 *
2120 */
2121 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2122 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2123 {
2124 const printenv_t * env;
2125 LPWSTR regpathW = NULL;
2126 DWORD numentries = 0;
2127 DWORD needed = 0;
2128 LONG lres;
2129 BOOL res = FALSE;
2130
2131 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2132 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2133
2134 lres = copy_servername_from_name(pName, NULL);
2135 if (lres) {
2136 FIXME("server %s not supported\n", debugstr_w(pName));
2137 SetLastError(ERROR_INVALID_NAME);
2138 goto epp_cleanup;
2139 }
2140
2141 if (Level != 1) {
2142 SetLastError(ERROR_INVALID_LEVEL);
2143 goto epp_cleanup;
2144 }
2145
2146 env = validate_envW(pEnvironment);
2147 if (!env)
2148 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2149
2150 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2151 (lstrlenW(env->envname) * sizeof(WCHAR)));
2152
2153 if (!regpathW)
2154 goto epp_cleanup;
2155
2156 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2157
2158 /* Scan all Printprocessor-Keys */
2159 numentries = 0;
2160 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2161
2162 /* we calculated the needed buffersize. now do more error-checks */
2163 if (cbBuf < needed) {
2164 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2165 goto epp_cleanup;
2166 }
2167
2168 /* fill the Buffer with the Printprocessor Infos */
2169 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2170 res = TRUE;
2171
2172 epp_cleanup:
2173 heap_free(regpathW);
2174 if (pcbNeeded) *pcbNeeded = needed;
2175 if (pcReturned) *pcReturned = numentries;
2176
2177 TRACE("returning %d with %d (%d byte for %d entries)\n",
2178 res, GetLastError(), needed, numentries);
2179
2180 return (res);
2181 }
2182
2183 /******************************************************************************
2184 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2185 *
2186 * Return the PATH for the Print-Processors
2187 *
2188 * PARAMS
2189 * pName [I] Servername or NULL (this computer)
2190 * pEnvironment [I] Printing-Environment or NULL (Default)
2191 * level [I] Structure-Level (must be 1)
2192 * pPPInfo [O] PTR to Buffer that receives the Result
2193 * cbBuf [I] Size of Buffer at pPPInfo
2194 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2195 *
2196 * RETURNS
2197 * Success: TRUE
2198 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2199 *
2200 * Native Values returned in pPPInfo on Success for this computer:
2201 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2202 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2203 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2204 *
2205 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2206 *
2207 */
2208 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2209 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2210 {
2211 const printenv_t * env;
2212 DWORD needed;
2213 LONG lres;
2214
2215 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2216 level, pPPInfo, cbBuf, pcbNeeded);
2217
2218 *pcbNeeded = 0;
2219 lres = copy_servername_from_name(pName, NULL);
2220 if (lres) {
2221 FIXME("server %s not supported\n", debugstr_w(pName));
2222 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2223 return FALSE;
2224 }
2225
2226 env = validate_envW(pEnvironment);
2227 if (!env)
2228 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2229
2230 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2231 needed = GetSystemDirectoryW(NULL, 0);
2232 /* add the Size for the Subdirectories */
2233 needed += lstrlenW(spoolprtprocsW);
2234 needed += lstrlenW(env->subdir);
2235 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2236
2237 *pcbNeeded = needed;
2238
2239 if (needed > cbBuf) {
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2241 return FALSE;
2242 }
2243
2244 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2245 /* add the Subdirectories */
2246 lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
2247 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2248 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2249 return TRUE;
2250 }
2251
2252 /******************************************************************************
2253 * fpOpenPrinter [exported through PRINTPROVIDOR]
2254 *
2255 * Open a Printer / Printserver or a Printer-Object
2256 *
2257 * PARAMS
2258 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2259 * pPrinter [O] The resulting Handle is stored here
2260 * pDefaults [I] PTR to Default Printer Settings or NULL
2261 *
2262 * RETURNS
2263 * Success: TRUE
2264 * Failure: FALSE
2265 *
2266 * NOTES
2267 * lpPrinterName is one of:
2268 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2269 *| Printer: "PrinterName"
2270 *| Printer-Object: "PrinterName,Job xxx"
2271 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2272 *| XcvPort: "Servername,XcvPort PortName"
2273 *
2274 *
2275 */
2276 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2277 LPPRINTER_DEFAULTSW pDefaults)
2278 {
2279
2280 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2281
2282 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2283
2284 return (*pPrinter != 0);
2285 }
2286
2287 /******************************************************************************
2288 * fpXcvData [exported through PRINTPROVIDOR]
2289 *
2290 * Execute commands in the Printmonitor DLL
2291 *
2292 * PARAMS
2293 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2294 * pszDataName [i] Name of the command to execute
2295 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2296 * cbInputData [i] Size in Bytes of Buffer at pInputData
2297 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2298 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2299 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2300 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2301 *
2302 * RETURNS
2303 * Success: TRUE
2304 * Failure: FALSE
2305 *
2306 * NOTES
2307 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2308 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2309 *
2310 * Minimal List of commands, that a Printmonitor DLL should support:
2311 *
2312 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2313 *| "AddPort" : Add a Port
2314 *| "DeletePort": Delete a Port
2315 *
2316 * Many Printmonitors support additional commands. Examples for localspl.dll:
2317 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2318 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2319 *
2320 */
2321 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2322 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2323 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2324 {
2325 printer_t *printer = (printer_t * ) hXcv;
2326
2327 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2328 pInputData, cbInputData, pOutputData,
2329 cbOutputData, pcbOutputNeeded, pdwStatus);
2330
2331 if (!printer || (!printer->hXcv)) {
2332 SetLastError(ERROR_INVALID_HANDLE);
2333 return FALSE;
2334 }
2335
2336 if (!pcbOutputNeeded) {
2337 SetLastError(ERROR_INVALID_PARAMETER);
2338 return FALSE;
2339 }
2340
2341 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2342 SetLastError(RPC_X_NULL_REF_POINTER);
2343 return FALSE;
2344 }
2345
2346 *pcbOutputNeeded = 0;
2347
2348 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
2349 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2350
2351 return TRUE;
2352 }
2353
2354 /*****************************************************
2355 * setup_provider [internal]
2356 */
2357 void setup_provider(void)
2358 {
2359 static const PRINTPROVIDOR backend = {
2360 fpOpenPrinter,
2361 NULL, /* fpSetJob */
2362 NULL, /* fpGetJob */
2363 NULL, /* fpEnumJobs */
2364 NULL, /* fpAddPrinter */
2365 NULL, /* fpDeletePrinter */
2366 NULL, /* fpSetPrinter */
2367 NULL, /* fpGetPrinter */
2368 NULL, /* fpEnumPrinters */
2369 NULL, /* fpAddPrinterDriver */
2370 NULL, /* fpEnumPrinterDrivers */
2371 NULL, /* fpGetPrinterDriver */
2372 fpGetPrinterDriverDirectory,
2373 NULL, /* fpDeletePrinterDriver */
2374 NULL, /* fpAddPrintProcessor */
2375 fpEnumPrintProcessors,
2376 fpGetPrintProcessorDirectory,
2377 NULL, /* fpDeletePrintProcessor */
2378 NULL, /* fpEnumPrintProcessorDatatypes */
2379 NULL, /* fpStartDocPrinter */
2380 NULL, /* fpStartPagePrinter */
2381 NULL, /* fpWritePrinter */
2382 NULL, /* fpEndPagePrinter */
2383 NULL, /* fpAbortPrinter */
2384 NULL, /* fpReadPrinter */
2385 NULL, /* fpEndDocPrinter */
2386 NULL, /* fpAddJob */
2387 NULL, /* fpScheduleJob */
2388 NULL, /* fpGetPrinterData */
2389 NULL, /* fpSetPrinterData */
2390 NULL, /* fpWaitForPrinterChange */
2391 fpClosePrinter,
2392 NULL, /* fpAddForm */
2393 NULL, /* fpDeleteForm */
2394 NULL, /* fpGetForm */
2395 NULL, /* fpSetForm */
2396 NULL, /* fpEnumForms */
2397 fpEnumMonitors,
2398 fpEnumPorts,
2399 fpAddPort,
2400 fpConfigurePort,
2401 fpDeletePort,
2402 NULL, /* fpCreatePrinterIC */
2403 NULL, /* fpPlayGdiScriptOnPrinterIC */
2404 NULL, /* fpDeletePrinterIC */
2405 NULL, /* fpAddPrinterConnection */
2406 NULL, /* fpDeletePrinterConnection */
2407 NULL, /* fpPrinterMessageBox */
2408 fpAddMonitor,
2409 fpDeleteMonitor,
2410 NULL, /* fpResetPrinter */
2411 NULL, /* fpGetPrinterDriverEx */
2412 NULL, /* fpFindFirstPrinterChangeNotification */
2413 NULL, /* fpFindClosePrinterChangeNotification */
2414 fpAddPortEx,
2415 NULL, /* fpShutDown */
2416 NULL, /* fpRefreshPrinterChangeNotification */
2417 NULL, /* fpOpenPrinterEx */
2418 NULL, /* fpAddPrinterEx */
2419 NULL, /* fpSetPort */
2420 NULL, /* fpEnumPrinterData */
2421 NULL, /* fpDeletePrinterData */
2422 NULL, /* fpClusterSplOpen */
2423 NULL, /* fpClusterSplClose */
2424 NULL, /* fpClusterSplIsAlive */
2425 NULL, /* fpSetPrinterDataEx */
2426 NULL, /* fpGetPrinterDataEx */
2427 NULL, /* fpEnumPrinterDataEx */
2428 NULL, /* fpEnumPrinterKey */
2429 NULL, /* fpDeletePrinterDataEx */
2430 NULL, /* fpDeletePrinterKey */
2431 NULL, /* fpSeekPrinter */
2432 NULL, /* fpDeletePrinterDriverEx */
2433 NULL, /* fpAddPerMachineConnection */
2434 NULL, /* fpDeletePerMachineConnection */
2435 NULL, /* fpEnumPerMachineConnections */
2436 fpXcvData,
2437 fpAddPrinterDriverEx,
2438 NULL, /* fpSplReadPrinter */
2439 NULL, /* fpDriverUnloadComplete */
2440 NULL, /* fpGetSpoolFileInfo */
2441 NULL, /* fpCommitSpoolData */
2442 NULL, /* fpCloseSpoolFileHandle */
2443 NULL, /* fpFlushPrinter */
2444 NULL, /* fpSendRecvBidiData */
2445 NULL /* fpAddDriverCatalog */
2446 };
2447 pprovider = &backend;
2448
2449 }
2450
2451 /*****************************************************
2452 * InitializePrintProvidor (localspl.@)
2453 *
2454 * Initialize the Printprovider
2455 *
2456 * PARAMS
2457 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2458 * cbPrintProvidor [I] Size of Buffer in Bytes
2459 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2460 *
2461 * RETURNS
2462 * Success: TRUE and pPrintProvidor filled
2463 * Failure: FALSE
2464 *
2465 * NOTES
2466 * The RegistryPath should be:
2467 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2468 * but this Parameter is ignored in "localspl.dll".
2469 *
2470 */
2471
2472 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2473 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2474 {
2475
2476 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2477 memcpy(pPrintProvidor, pprovider,
2478 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2479
2480 return TRUE;
2481 }