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