~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/localspl/provider.c

Version: ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.