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