ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

provider.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of the Local Printprovider
00003  *
00004  * Copyright 2006-2009 Detlef Riekenberg
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 
00023 #define COBJMACROS
00024 #define NONAMELESSUNION
00025 
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "wingdi.h"
00029 #include "winreg.h"
00030 #include "winspool.h"
00031 #include "winuser.h"
00032 #include "ddk/winddiui.h"
00033 #include "ddk/winsplp.h"
00034 
00035 #include "wine/list.h"
00036 #include "wine/debug.h"
00037 #include "wine/unicode.h"
00038 #include "localspl_private.h"
00039 
00040 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
00041 
00042 /* ############################### */
00043 
00044 static CRITICAL_SECTION monitor_handles_cs;
00045 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
00046 {
00047     0, 0, &monitor_handles_cs,
00048     { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
00049       0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
00050 };
00051 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
00052 
00053 /* ############################### */
00054 
00055 typedef struct {
00056     WCHAR   src[MAX_PATH+MAX_PATH];
00057     WCHAR   dst[MAX_PATH+MAX_PATH];
00058     DWORD   srclen;
00059     DWORD   dstlen;
00060     DWORD   copyflags;
00061     BOOL    lazy;
00062 } apd_data_t;
00063 
00064 typedef struct {
00065     struct list     entry;
00066     LPWSTR          name;
00067     LPWSTR          dllname;
00068     PMONITORUI      monitorUI;
00069     LPMONITOR       monitor;
00070     HMODULE         hdll;
00071     DWORD           refcount;
00072     DWORD           dwMonitorSize;
00073 } monitor_t;
00074 
00075 typedef struct {
00076     LPCWSTR  envname;
00077     LPCWSTR  subdir;
00078     DWORD    driverversion;
00079     LPCWSTR  versionregpath;
00080     LPCWSTR  versionsubdir;
00081 } printenv_t;
00082 
00083 typedef struct {
00084     LPWSTR name;
00085     LPWSTR printername;
00086     monitor_t * pm;
00087     HANDLE hXcv;
00088 } printer_t;
00089 
00090 /* ############################### */
00091 
00092 static struct list monitor_handles = LIST_INIT( monitor_handles );
00093 static monitor_t * pm_localport;
00094 
00095 static const PRINTPROVIDOR * pprovider = NULL;
00096 
00097 static const WCHAR backslashW[] = {'\\',0};
00098 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
00099 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
00100 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
00101 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
00102 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
00103 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
00104 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
00105 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
00106 static const WCHAR emptyW[] = {0};
00107 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
00108                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00109                                   'c','o','n','t','r','o','l','\\',
00110                                   'P','r','i','n','t','\\',
00111                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\',
00112                                   '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
00113 static const WCHAR fmt_printprocessorsW[] = { 'S','y','s','t','e','m','\\',
00114                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00115                                   'C','o','n','t','r','o','l','\\',
00116                                   'P','r','i','n','t','\\',
00117                                   'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
00118                                   'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
00119 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
00120 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
00121 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
00122 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
00123 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
00124 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
00125 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
00126 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
00127 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
00128                                 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00129                                 'C','o','n','t','r','o','l','\\',
00130                                 'P','r','i','n','t','\\',
00131                                 'M','o','n','i','t','o','r','s','\\',0};
00132 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
00133 static const WCHAR nameW[] = {'N','a','m','e',0};
00134 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
00135 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
00136 static const WCHAR portW[] = {'P','o','r','t',0};
00137 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
00138 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
00139                                   'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00140                                   'C','o','n','t','r','o','l','\\',
00141                                   'P','r','i','n','t','\\',
00142                                   'P','r','i','n','t','e','r','s',0};
00143 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
00144 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
00145 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
00146 static const WCHAR version0_subdirW[] = {'\\','0',0};
00147 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
00148 static const WCHAR version3_subdirW[] = {'\\','3',0};
00149 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
00150 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
00151 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
00152 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
00153                                         'M','i','c','r','o','s','o','f','t','\\',
00154                                         'W','i','n','d','o','w','s',' ','N','T','\\',
00155                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
00156                                         'P','o','r','t','s',0};
00157 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
00158 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
00159 static const WCHAR x64_subdirW[] = {'x','6','4',0};
00160 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
00161 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
00162 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
00163 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
00164 
00165 
00166 static const printenv_t env_ia64 =  {ia64_envnameW, ia64_subdirW, 3,
00167                                      version3_regpathW, version3_subdirW};
00168 
00169 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
00170                                      version3_regpathW, version3_subdirW};
00171 
00172 static const printenv_t env_x64 =   {x64_envnameW, x64_subdirW, 3,
00173                                      version3_regpathW, version3_subdirW};
00174 
00175 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
00176                                      version0_regpathW, version0_subdirW};
00177 
00178 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
00179 
00180 
00181 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
00182                                      sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
00183                                      sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
00184                                   0, sizeof(DRIVER_INFO_8W)};
00185 
00186 
00187 /******************************************************************
00188  * strdupW [internal]
00189  *
00190  * create a copy of a unicode-string
00191  *
00192  */
00193 static LPWSTR strdupW(LPCWSTR p)
00194 {
00195     LPWSTR ret;
00196     DWORD len;
00197 
00198     if(!p) return NULL;
00199     len = (lstrlenW(p) + 1) * sizeof(WCHAR);
00200     ret = heap_alloc(len);
00201     if (ret) memcpy(ret, p, len);
00202     return ret;
00203 }
00204 
00205 /******************************************************************
00206  *  apd_copyfile [internal]
00207  *
00208  * Copy a file from the driverdirectory to the versioned directory
00209  *
00210  * RETURNS
00211  *  Success: TRUE
00212  *  Failure: FALSE
00213  *
00214  */
00215 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
00216 {
00217     LPWSTR  ptr;
00218     LPWSTR  srcname;
00219     DWORD   res;
00220 
00221     apd->src[apd->srclen] = '\0';
00222     apd->dst[apd->dstlen] = '\0';
00223 
00224     if (!filename || !filename[0]) {
00225         /* nothing to copy */
00226         return TRUE;
00227     }
00228 
00229     ptr = strrchrW(filename, '\\');
00230     if (ptr) {
00231         ptr++;
00232     }
00233     else
00234     {
00235         ptr = filename;
00236     }
00237 
00238     if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
00239         /* we have an absolute Path */
00240         srcname = filename;
00241     }
00242     else
00243     {
00244         srcname = apd->src;
00245         lstrcatW(srcname, ptr);
00246     }
00247     lstrcatW(apd->dst, ptr);
00248 
00249     TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
00250 
00251     /* FIXME: handle APD_COPY_NEW_FILES */
00252     res = CopyFileW(srcname, apd->dst, FALSE);
00253     TRACE("got %u with %u\n", res, GetLastError());
00254 
00255     return (apd->lazy) ? TRUE : res;
00256 }
00257 
00258 /******************************************************************
00259  * copy_servername_from_name  (internal)
00260  *
00261  * for an external server, the serverpart from the name is copied.
00262  *
00263  * RETURNS
00264  *  the length (in WCHAR) of the serverpart (0 for the local computer)
00265  *  (-length), when the name is to long
00266  *
00267  */
00268 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
00269 {
00270     LPCWSTR server;
00271     LPWSTR  ptr;
00272     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
00273     DWORD   len;
00274     DWORD   serverlen;
00275 
00276     if (target) *target = '\0';
00277 
00278     if (name == NULL) return 0;
00279     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
00280 
00281     server = &name[2];
00282     /* skip over both backslash, find separator '\' */
00283     ptr = strchrW(server, '\\');
00284     serverlen = (ptr) ? ptr - server : lstrlenW(server);
00285 
00286     /* servername is empty */
00287     if (serverlen == 0) return 0;
00288 
00289     TRACE("found %s\n", debugstr_wn(server, serverlen));
00290 
00291     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
00292 
00293     if (target) {
00294         memcpy(target, server, serverlen * sizeof(WCHAR));
00295         target[serverlen] = '\0';
00296     }
00297 
00298     len = sizeof(buffer) / sizeof(buffer[0]);
00299     if (GetComputerNameW(buffer, &len)) {
00300         if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
00301             /* The requested Servername is our computername */
00302             return 0;
00303         }
00304     }
00305     return serverlen;
00306 }
00307 
00308 /******************************************************************
00309  * get_basename_from_name  (internal)
00310  *
00311  * skip over the serverpart from the full name
00312  *
00313  */
00314 static LPCWSTR get_basename_from_name(LPCWSTR name)
00315 {
00316     if (name == NULL)  return NULL;
00317     if ((name[0] == '\\') && (name[1] == '\\')) {
00318         /* skip over the servername and search for the following '\'  */
00319         name = strchrW(&name[2], '\\');
00320         if ((name) && (name[1])) {
00321             /* found a separator ('\') followed by a name:
00322                skip over the separator and return the rest */
00323             name++;
00324         }
00325         else
00326         {
00327             /* no basename present (we found only a servername) */
00328             return NULL;
00329         }
00330     }
00331     return name;
00332 }
00333 
00334 /******************************************************************
00335  * monitor_unload [internal]
00336  *
00337  * release a printmonitor and unload it from memory, when needed
00338  *
00339  */
00340 static void monitor_unload(monitor_t * pm)
00341 {
00342     if (pm == NULL) return;
00343     TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
00344 
00345     EnterCriticalSection(&monitor_handles_cs);
00346 
00347     if (pm->refcount) pm->refcount--;
00348 
00349     if (pm->refcount == 0) {
00350         list_remove(&pm->entry);
00351         FreeLibrary(pm->hdll);
00352         heap_free(pm->name);
00353         heap_free(pm->dllname);
00354         heap_free(pm);
00355     }
00356     LeaveCriticalSection(&monitor_handles_cs);
00357 }
00358 
00359 /******************************************************************
00360  * monitor_unloadall [internal]
00361  *
00362  * release all registered printmonitors and unload them from memory, when needed
00363  *
00364  */
00365 
00366 static void monitor_unloadall(void)
00367 {
00368     monitor_t * pm;
00369     monitor_t * next;
00370 
00371     EnterCriticalSection(&monitor_handles_cs);
00372     /* iterate through the list, with safety against removal */
00373     LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
00374     {
00375         /* skip monitorui dlls */
00376         if (pm->monitor) monitor_unload(pm);
00377     }
00378     LeaveCriticalSection(&monitor_handles_cs);
00379 }
00380 
00381 /******************************************************************
00382  * monitor_load [internal]
00383  *
00384  * load a printmonitor, get the dllname from the registry, when needed
00385  * initialize the monitor and dump found function-pointers
00386  *
00387  * On failure, SetLastError() is called and NULL is returned
00388  */
00389 
00390 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
00391 {
00392     LPMONITOR2  (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
00393     PMONITORUI  (WINAPI *pInitializePrintMonitorUI)(VOID);
00394     LPMONITOREX (WINAPI *pInitializePrintMonitor)  (LPWSTR);
00395     DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
00396     DWORD (WINAPI *pInitializeMonitor)  (LPWSTR);
00397 
00398     monitor_t * pm = NULL;
00399     monitor_t * cursor;
00400     LPWSTR  regroot = NULL;
00401     LPWSTR  driver = dllname;
00402 
00403     TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
00404     /* Is the Monitor already loaded? */
00405     EnterCriticalSection(&monitor_handles_cs);
00406 
00407     if (name) {
00408         LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
00409         {
00410             if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
00411                 pm = cursor;
00412                 break;
00413             }
00414         }
00415     }
00416 
00417     if (pm == NULL) {
00418         pm = heap_alloc_zero(sizeof(monitor_t));
00419         if (pm == NULL) goto cleanup;
00420         list_add_tail(&monitor_handles, &pm->entry);
00421     }
00422     pm->refcount++;
00423 
00424     if (pm->name == NULL) {
00425         /* Load the monitor */
00426         LPMONITOREX pmonitorEx;
00427         DWORD   len;
00428 
00429         if (name) {
00430             len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
00431             regroot = heap_alloc(len * sizeof(WCHAR));
00432         }
00433 
00434         if (regroot) {
00435             lstrcpyW(regroot, monitorsW);
00436             lstrcatW(regroot, name);
00437             /* Get the Driver from the Registry */
00438             if (driver == NULL) {
00439                 HKEY    hroot;
00440                 DWORD   namesize;
00441                 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
00442                     if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
00443                                         &namesize) == ERROR_SUCCESS) {
00444                         driver = heap_alloc(namesize);
00445                         RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
00446                     }
00447                     RegCloseKey(hroot);
00448                 }
00449             }
00450         }
00451 
00452         pm->name = strdupW(name);
00453         pm->dllname = strdupW(driver);
00454 
00455         if ((name && (!regroot || !pm->name)) || !pm->dllname) {
00456             monitor_unload(pm);
00457             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00458             pm = NULL;
00459             goto cleanup;
00460         }
00461 
00462         pm->hdll = LoadLibraryW(driver);
00463         TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
00464 
00465         if (pm->hdll == NULL) {
00466             monitor_unload(pm);
00467             SetLastError(ERROR_MOD_NOT_FOUND);
00468             pm = NULL;
00469             goto cleanup;
00470         }
00471 
00472         pInitializePrintMonitor2  = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
00473         pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
00474         pInitializePrintMonitor   = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
00475         pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
00476         pInitializeMonitor   = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
00477 
00478 
00479         TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
00480         TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
00481         TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
00482         TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
00483         TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
00484 
00485         if (pInitializePrintMonitorUI  != NULL) {
00486             pm->monitorUI = pInitializePrintMonitorUI();
00487             TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
00488             if (pm->monitorUI) {
00489                 TRACE("0x%08x: dwMonitorSize (%d)\n",
00490                         pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
00491 
00492             }
00493         }
00494 
00495         if (pInitializePrintMonitor && regroot) {
00496             pmonitorEx = pInitializePrintMonitor(regroot);
00497             TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
00498                     pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
00499 
00500             if (pmonitorEx) {
00501                 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
00502                 pm->monitor = &(pmonitorEx->Monitor);
00503             }
00504         }
00505 
00506         if (pm->monitor) {
00507             TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
00508 
00509         }
00510 
00511         if (!pm->monitor && regroot) {
00512             if (pInitializePrintMonitor2 != NULL) {
00513                 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
00514             }
00515             if (pInitializeMonitorEx != NULL) {
00516                 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
00517             }
00518             if (pInitializeMonitor != NULL) {
00519                 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
00520             }
00521         }
00522         if (!pm->monitor && !pm->monitorUI) {
00523             monitor_unload(pm);
00524             SetLastError(ERROR_PROC_NOT_FOUND);
00525             pm = NULL;
00526         }
00527     }
00528 cleanup:
00529     if ((pm_localport ==  NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
00530         pm->refcount++;
00531         pm_localport = pm;
00532     }
00533     LeaveCriticalSection(&monitor_handles_cs);
00534     if (driver != dllname) heap_free(driver);
00535     heap_free(regroot);
00536     TRACE("=> %p\n", pm);
00537     return pm;
00538 }
00539 
00540 /******************************************************************
00541  * monitor_loadall [internal]
00542  *
00543  * Load all registered monitors
00544  *
00545  */
00546 static DWORD monitor_loadall(void)
00547 {
00548     monitor_t * pm;
00549     DWORD   registered = 0;
00550     DWORD   loaded = 0;
00551     HKEY    hmonitors;
00552     WCHAR   buffer[MAX_PATH];
00553     DWORD   id = 0;
00554 
00555     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
00556         RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
00557                         NULL, NULL, NULL, NULL, NULL);
00558 
00559         TRACE("%d monitors registered\n", registered);
00560 
00561         while (id < registered) {
00562             buffer[0] = '\0';
00563             RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
00564             pm = monitor_load(buffer, NULL);
00565             if (pm) loaded++;
00566             id++;
00567         }
00568         RegCloseKey(hmonitors);
00569     }
00570     TRACE("%d monitors loaded\n", loaded);
00571     return loaded;
00572 }
00573 
00574 /******************************************************************
00575  * monitor_loadui [internal]
00576  *
00577  * load the userinterface-dll for a given portmonitor
00578  *
00579  * On failure, NULL is returned
00580  */
00581 static monitor_t * monitor_loadui(monitor_t * pm)
00582 {
00583     monitor_t * pui = NULL;
00584     WCHAR   buffer[MAX_PATH];
00585     HANDLE  hXcv;
00586     DWORD   len;
00587     DWORD   res;
00588 
00589     if (pm == NULL) return NULL;
00590     TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
00591 
00592     /* Try the Portmonitor first; works for many monitors */
00593     if (pm->monitorUI) {
00594         EnterCriticalSection(&monitor_handles_cs);
00595         pm->refcount++;
00596         LeaveCriticalSection(&monitor_handles_cs);
00597         return pm;
00598     }
00599 
00600     /* query the userinterface-dllname from the Portmonitor */
00601     if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
00602         /* building (",XcvMonitor %s",pm->name) not needed yet */
00603         res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
00604         TRACE("got %u with %p\n", res, hXcv);
00605         if (res) {
00606             res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
00607             TRACE("got %u with %s\n", res, debugstr_w(buffer));
00608             if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
00609             pm->monitor->pfnXcvClosePort(hXcv);
00610         }
00611     }
00612     return pui;
00613 }
00614 
00615 /******************************************************************
00616  * monitor_load_by_port [internal]
00617  *
00618  * load a printmonitor for a given port
00619  *
00620  * On failure, NULL is returned
00621  */
00622 
00623 static monitor_t * monitor_load_by_port(LPCWSTR portname)
00624 {
00625     HKEY    hroot;
00626     HKEY    hport;
00627     LPWSTR  buffer;
00628     monitor_t * pm = NULL;
00629     DWORD   registered = 0;
00630     DWORD   id = 0;
00631     DWORD   len;
00632 
00633     TRACE("(%s)\n", debugstr_w(portname));
00634 
00635     /* Try the Local Monitor first */
00636     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
00637         if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
00638             /* found the portname */
00639             RegCloseKey(hroot);
00640             return monitor_load(localportW, NULL);
00641         }
00642         RegCloseKey(hroot);
00643     }
00644 
00645     len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
00646     buffer = heap_alloc(len * sizeof(WCHAR));
00647     if (buffer == NULL) return NULL;
00648 
00649     if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
00650         EnterCriticalSection(&monitor_handles_cs);
00651         RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
00652 
00653         while ((pm == NULL) && (id < registered)) {
00654             buffer[0] = '\0';
00655             RegEnumKeyW(hroot, id, buffer, MAX_PATH);
00656             TRACE("testing %s\n", debugstr_w(buffer));
00657             len = lstrlenW(buffer);
00658             lstrcatW(buffer, bs_ports_bsW);
00659             lstrcatW(buffer, portname);
00660             if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
00661                 RegCloseKey(hport);
00662                 buffer[len] = '\0';             /* use only the Monitor-Name */
00663                 pm = monitor_load(buffer, NULL);
00664             }
00665             id++;
00666         }
00667         LeaveCriticalSection(&monitor_handles_cs);
00668         RegCloseKey(hroot);
00669     }
00670     heap_free(buffer);
00671     return pm;
00672 }
00673 
00674 /******************************************************************
00675  * Return the number of bytes for an multi_sz string.
00676  * The result includes all \0s
00677  * (specifically the extra \0, that is needed as multi_sz terminator).
00678  */
00679 static int multi_sz_lenW(const WCHAR *str)
00680 {
00681     const WCHAR *ptr = str;
00682     if (!str) return 0;
00683     do
00684     {
00685         ptr += lstrlenW(ptr) + 1;
00686     } while (*ptr);
00687 
00688     return (ptr - str + 1) * sizeof(WCHAR);
00689 }
00690 
00691 /******************************************************************
00692  * validate_envW [internal]
00693  *
00694  * validate the user-supplied printing-environment
00695  *
00696  * PARAMS
00697  *  env  [I] PTR to Environment-String or NULL
00698  *
00699  * RETURNS
00700  *  Success:  PTR to printenv_t
00701  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
00702  *
00703  * NOTES
00704  *  An empty string is handled the same way as NULL.
00705  *
00706  */
00707 
00708 static const  printenv_t * validate_envW(LPCWSTR env)
00709 {
00710     const printenv_t *result = NULL;
00711     unsigned int i;
00712 
00713     TRACE("(%s)\n", debugstr_w(env));
00714     if (env && env[0])
00715     {
00716         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
00717         {
00718             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
00719             {
00720                 result = all_printenv[i];
00721                 break;
00722             }
00723         }
00724         if (result == NULL) {
00725             FIXME("unsupported Environment: %s\n", debugstr_w(env));
00726             SetLastError(ERROR_INVALID_ENVIRONMENT);
00727         }
00728         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
00729     }
00730     else
00731     {
00732         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
00733     }
00734 
00735     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
00736     return result;
00737 }
00738 
00739 /*****************************************************************************
00740  * enumerate the local monitors (INTERNAL)
00741  *
00742  * returns the needed size (in bytes) for pMonitors
00743  * and  *lpreturned is set to number of entries returned in pMonitors
00744  *
00745  * Language-Monitors are also installed in the same Registry-Location but
00746  * they are filtered in Windows (not returned by EnumMonitors).
00747  * We do no filtering to simplify our Code.
00748  *
00749  */
00750 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
00751 {
00752     HKEY    hroot = NULL;
00753     HKEY    hentry = NULL;
00754     LPWSTR  ptr;
00755     LPMONITOR_INFO_2W mi;
00756     WCHAR   buffer[MAX_PATH];
00757     WCHAR   dllname[MAX_PATH];
00758     DWORD   dllsize;
00759     DWORD   len;
00760     DWORD   index = 0;
00761     DWORD   needed = 0;
00762     DWORD   numentries;
00763     DWORD   entrysize;
00764 
00765     entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
00766 
00767     numentries = *lpreturned;       /* this is 0, when we scan the registry */
00768     len = entrysize * numentries;
00769     ptr = (LPWSTR) &pMonitors[len];
00770 
00771     numentries = 0;
00772     len = sizeof(buffer)/sizeof(buffer[0]);
00773     buffer[0] = '\0';
00774 
00775     /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
00776     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
00777         /* Scan all Monitor-Registry-Keys */
00778         while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
00779             TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
00780             dllsize = sizeof(dllname);
00781             dllname[0] = '\0';
00782 
00783             /* The Monitor must have a Driver-DLL */
00784             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
00785                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
00786                     /* We found a valid DLL for this Monitor. */
00787                     TRACE("using Driver: %s\n", debugstr_w(dllname));
00788                 }
00789                 RegCloseKey(hentry);
00790             }
00791 
00792             /* Windows returns only Port-Monitors here, but to simplify our code,
00793                we do no filtering for Language-Monitors */
00794             if (dllname[0]) {
00795                 numentries++;
00796                 needed += entrysize;
00797                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(monitorname) */
00798                 if (level > 1) {
00799                     /* we install and return only monitors for "Windows NT x86" */
00800                     needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
00801                     needed += dllsize;
00802                 }
00803 
00804                 /* required size is calculated. Now fill the user-buffer */
00805                 if (pMonitors && (cbBuf >= needed)){
00806                     mi = (LPMONITOR_INFO_2W) pMonitors;
00807                     pMonitors += entrysize;
00808 
00809                     TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
00810                     mi->pName = ptr;
00811                     lstrcpyW(ptr, buffer);      /* Name of the Monitor */
00812                     ptr += (len+1);               /* len is lstrlenW(monitorname) */
00813                     if (level > 1) {
00814                         mi->pEnvironment = ptr;
00815                         lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
00816                         ptr += (lstrlenW(x86_envnameW)+1);
00817 
00818                         mi->pDLLName = ptr;
00819                         lstrcpyW(ptr, dllname);         /* Name of the Driver-DLL */
00820                         ptr += (dllsize / sizeof(WCHAR));
00821                     }
00822                 }
00823             }
00824             index++;
00825             len = sizeof(buffer)/sizeof(buffer[0]);
00826             buffer[0] = '\0';
00827         }
00828         RegCloseKey(hroot);
00829     }
00830     *lpreturned = numentries;
00831     TRACE("need %d byte for %d entries\n", needed, numentries);
00832     return needed;
00833 }
00834 
00835 /*****************************************************************************
00836  * enumerate the local print processors (INTERNAL)
00837  *
00838  * returns the needed size (in bytes) for pPPInfo
00839  * and  *lpreturned is set to number of entries returned in pPPInfo
00840  *
00841  */
00842 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
00843 {
00844     HKEY    hroot = NULL;
00845     HKEY    hentry = NULL;
00846     LPWSTR  ptr;
00847     PPRINTPROCESSOR_INFO_1W ppi;
00848     WCHAR   buffer[MAX_PATH];
00849     WCHAR   dllname[MAX_PATH];
00850     DWORD   dllsize;
00851     DWORD   len;
00852     DWORD   index = 0;
00853     DWORD   needed = 0;
00854     DWORD   numentries;
00855 
00856     numentries = *lpreturned;       /* this is 0, when we scan the registry */
00857     len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
00858     ptr = (LPWSTR) &pPPInfo[len];
00859 
00860     numentries = 0;
00861     len = sizeof(buffer)/sizeof(buffer[0]);
00862     buffer[0] = '\0';
00863 
00864     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
00865         /* add "winprint" first */
00866         numentries++;
00867         needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
00868         if (pPPInfo && (cbBuf >= needed)){
00869             ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
00870             pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
00871 
00872             TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
00873             ppi->pName = ptr;
00874             lstrcpyW(ptr, winprintW);      /* Name of the Print Processor */
00875             ptr += sizeof(winprintW) / sizeof(WCHAR);
00876         }
00877 
00878         /* Scan all Printprocessor Keys */
00879         while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
00880             (lstrcmpiW(buffer, winprintW) != 0)) {
00881             TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
00882             dllsize = sizeof(dllname);
00883             dllname[0] = '\0';
00884 
00885             /* The Print Processor must have a Driver-DLL */
00886             if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
00887                 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
00888                     /* We found a valid DLL for this Print Processor */
00889                     TRACE("using Driver: %s\n", debugstr_w(dllname));
00890                 }
00891                 RegCloseKey(hentry);
00892             }
00893 
00894             if (dllname[0]) {
00895                 numentries++;
00896                 needed += sizeof(PRINTPROCESSOR_INFO_1W);
00897                 needed += (len+1) * sizeof(WCHAR);  /* len is lstrlenW(printprocessor name) */
00898 
00899                 /* required size is calculated. Now fill the user-buffer */
00900                 if (pPPInfo && (cbBuf >= needed)){
00901                     ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
00902                     pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
00903 
00904                     TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
00905                     ppi->pName = ptr;
00906                     lstrcpyW(ptr, buffer);      /* Name of the Print Processor */
00907                     ptr += (len+1);             /* len is lstrlenW(printprosessor name) */
00908                 }
00909             }
00910             index++;
00911             len = sizeof(buffer)/sizeof(buffer[0]);
00912             buffer[0] = '\0';
00913         }
00914         RegCloseKey(hroot);
00915     }
00916     *lpreturned = numentries;
00917     TRACE("need %d byte for %d entries\n", needed, numentries);
00918     return needed;
00919 }
00920 
00921 /******************************************************************
00922  * enumerate the local Ports from all loaded monitors (internal)
00923  *
00924  * returns the needed size (in bytes) for pPorts
00925  * and  *lpreturned is set to number of entries returned in pPorts
00926  *
00927  */
00928 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
00929 {
00930     monitor_t * pm;
00931     LPWSTR      ptr;
00932     LPPORT_INFO_2W cache;
00933     LPPORT_INFO_2W out;
00934     LPBYTE  pi_buffer = NULL;
00935     DWORD   pi_allocated = 0;
00936     DWORD   pi_needed;
00937     DWORD   pi_index;
00938     DWORD   pi_returned;
00939     DWORD   res;
00940     DWORD   outindex = 0;
00941     DWORD   needed;
00942     DWORD   numentries;
00943     DWORD   entrysize;
00944 
00945 
00946     TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
00947     entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
00948 
00949     numentries = *lpreturned;       /* this is 0, when we scan the registry */
00950     needed = entrysize * numentries;
00951     ptr = (LPWSTR) &pPorts[needed];
00952 
00953     numentries = 0;
00954     needed = 0;
00955 
00956     LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
00957     {
00958         if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
00959             pi_needed = 0;
00960             pi_returned = 0;
00961             res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
00962             if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
00963                 /* Do not use heap_realloc (we do not need the old data in the buffer) */
00964                 heap_free(pi_buffer);
00965                 pi_buffer = heap_alloc(pi_needed);
00966                 pi_allocated = (pi_buffer) ? pi_needed : 0;
00967                 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
00968             }
00969             TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
00970                   debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
00971 
00972             numentries += pi_returned;
00973             needed += pi_needed;
00974 
00975             /* fill the output-buffer (pPorts), if we have one */
00976             if (pPorts && (cbBuf >= needed ) && pi_buffer) {
00977                 pi_index = 0;
00978                 while (pi_returned > pi_index) {
00979                     cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
00980                     out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
00981                     out->pPortName = ptr;
00982                     lstrcpyW(ptr, cache->pPortName);
00983                     ptr += (lstrlenW(ptr)+1);
00984                     if (level > 1) {
00985                         out->pMonitorName = ptr;
00986                         lstrcpyW(ptr,  cache->pMonitorName);
00987                         ptr += (lstrlenW(ptr)+1);
00988 
00989                         out->pDescription = ptr;
00990                         lstrcpyW(ptr,  cache->pDescription);
00991                         ptr += (lstrlenW(ptr)+1);
00992                         out->fPortType = cache->fPortType;
00993                         out->Reserved = cache->Reserved;
00994                     }
00995                     pi_index++;
00996                     outindex++;
00997                 }
00998             }
00999         }
01000     }
01001     /* the temporary portinfo-buffer is no longer needed */
01002     heap_free(pi_buffer);
01003 
01004     *lpreturned = numentries;
01005     TRACE("need %d byte for %d entries\n", needed, numentries);
01006     return needed;
01007 }
01008 
01009 
01010 /*****************************************************************************
01011  * open_driver_reg [internal]
01012  *
01013  * opens the registry for the printer drivers depending on the given input
01014  * variable pEnvironment
01015  *
01016  * RETURNS:
01017  *    Success: the opened hkey
01018  *    Failure: NULL
01019  */
01020 static HKEY open_driver_reg(LPCWSTR pEnvironment)
01021 {
01022     HKEY  retval = NULL;
01023     LPWSTR buffer;
01024     const printenv_t * env;
01025 
01026     TRACE("(%s)\n", debugstr_w(pEnvironment));
01027 
01028     env = validate_envW(pEnvironment);
01029     if (!env) return NULL;
01030 
01031     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
01032                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
01033 
01034     if (buffer) {
01035         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
01036         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
01037         HeapFree(GetProcessHeap(), 0, buffer);
01038     }
01039     return retval;
01040 }
01041 
01042 /*****************************************************************************
01043  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
01044  *
01045  * Return the PATH for the Printer-Drivers
01046  *
01047  * PARAMS
01048  *   pName            [I] Servername (NT only) or NULL (local Computer)
01049  *   pEnvironment     [I] Printing-Environment (see below) or NULL (Default)
01050  *   Level            [I] Structure-Level (must be 1)
01051  *   pDriverDirectory [O] PTR to Buffer that receives the Result
01052  *   cbBuf            [I] Size of Buffer at pDriverDirectory
01053  *   pcbNeeded        [O] PTR to DWORD that receives the size in Bytes used /
01054  *                        required for pDriverDirectory
01055  *
01056  * RETURNS
01057  *   Success: TRUE  and in pcbNeeded the Bytes used in pDriverDirectory
01058  *   Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
01059  *            if cbBuf is too small
01060  *
01061  *   Native Values returned in pDriverDirectory on Success:
01062  *|  NT(Windows NT x86):  "%winsysdir%\\spool\\DRIVERS\\w32x86"
01063  *|  NT(Windows 4.0):     "%winsysdir%\\spool\\DRIVERS\\win40"
01064  *|  win9x(Windows 4.0):  "%winsysdir%"
01065  *
01066  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
01067  *
01068  */
01069 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
01070             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
01071 {
01072     DWORD needed;
01073     const printenv_t * env;
01074 
01075     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
01076           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
01077 
01078     if (pName != NULL && pName[0]) {
01079         FIXME("server %s not supported\n", debugstr_w(pName));
01080         SetLastError(ERROR_INVALID_PARAMETER);
01081         return FALSE;
01082     }
01083 
01084     env = validate_envW(pEnvironment);
01085     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
01086 
01087 
01088     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
01089     needed = GetSystemDirectoryW(NULL, 0);
01090     /* add the Size for the Subdirectories */
01091     needed += lstrlenW(spooldriversW);
01092     needed += lstrlenW(env->subdir);
01093     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
01094 
01095     *pcbNeeded = needed;
01096 
01097     if (needed > cbBuf) {
01098         SetLastError(ERROR_INSUFFICIENT_BUFFER);
01099         return FALSE;
01100     }
01101 
01102     if (pDriverDirectory == NULL) {
01103         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
01104         SetLastError(ERROR_INVALID_USER_BUFFER);
01105         return FALSE;
01106     }
01107 
01108     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
01109     /* add the Subdirectories */
01110     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
01111     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
01112 
01113     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
01114     return TRUE;
01115 }
01116 
01117 /******************************************************************
01118  * driver_load [internal]
01119  *
01120  * load a driver user interface dll
01121  *
01122  * On failure, NULL is returned
01123  *
01124  */
01125 
01126 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
01127 {
01128     WCHAR fullname[MAX_PATH];
01129     HMODULE hui;
01130     DWORD len;
01131 
01132     TRACE("(%p, %s)\n", env, debugstr_w(dllname));
01133 
01134     /* build the driverdir */
01135     len = sizeof(fullname) -
01136           (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
01137 
01138     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
01139                                      (LPBYTE) fullname, len, &len)) {
01140         /* Should never Fail */
01141         SetLastError(ERROR_BUFFER_OVERFLOW);
01142         return NULL;
01143     }
01144 
01145     lstrcatW(fullname, env->versionsubdir);
01146     lstrcatW(fullname, backslashW);
01147     lstrcatW(fullname, dllname);
01148 
01149     hui = LoadLibraryW(fullname);
01150     TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
01151 
01152     return hui;
01153 }
01154 
01155 /******************************************************************
01156  *  printer_free
01157  *  free the data pointer of an opened printer
01158  */
01159 static VOID printer_free(printer_t * printer)
01160 {
01161     if (printer->hXcv)
01162         printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
01163 
01164     monitor_unload(printer->pm);
01165 
01166     heap_free(printer->printername);
01167     heap_free(printer->name);
01168     heap_free(printer);
01169 }
01170 
01171 /******************************************************************
01172  *  printer_alloc_handle
01173  *  alloc a printer handle and remember the data pointer in the printer handle table
01174  *
01175  */
01176 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
01177 {
01178     WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
01179     printer_t *printer = NULL;
01180     LPCWSTR printername;
01181     HKEY    hkeyPrinters;
01182     HKEY    hkeyPrinter;
01183     DWORD   len;
01184 
01185     if (copy_servername_from_name(name, servername)) {
01186         FIXME("server %s not supported\n", debugstr_w(servername));
01187         SetLastError(ERROR_INVALID_PRINTER_NAME);
01188         return NULL;
01189     }
01190 
01191     printername = get_basename_from_name(name);
01192     if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
01193 
01194     /* an empty printername is invalid */
01195     if (printername && (!printername[0])) {
01196         SetLastError(ERROR_INVALID_PARAMETER);
01197         return NULL;
01198     }
01199 
01200     printer = heap_alloc_zero(sizeof(printer_t));
01201     if (!printer) goto end;
01202 
01203     /* clone the base name. This is NULL for the printserver */
01204     printer->printername = strdupW(printername);
01205 
01206     /* clone the full name */
01207     printer->name = strdupW(name);
01208     if (name && (!printer->name)) {
01209         printer_free(printer);
01210         printer = NULL;
01211     }
01212     if (printername) {
01213         len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
01214         if (strncmpW(printername, XcvMonitorW, len) == 0) {
01215             /* OpenPrinter(",XcvMonitor ", ...) detected */
01216             TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
01217             printer->pm = monitor_load(&printername[len], NULL);
01218             if (printer->pm == NULL) {
01219                 printer_free(printer);
01220                 SetLastError(ERROR_UNKNOWN_PORT);
01221                 printer = NULL;
01222                 goto end;
01223             }
01224         }
01225         else
01226         {
01227             len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
01228             if (strncmpW( printername, XcvPortW, len) == 0) {
01229                 /* OpenPrinter(",XcvPort ", ...) detected */
01230                 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
01231                 printer->pm = monitor_load_by_port(&printername[len]);
01232                 if (printer->pm == NULL) {
01233                     printer_free(printer);
01234                     SetLastError(ERROR_UNKNOWN_PORT);
01235                     printer = NULL;
01236                     goto end;
01237                 }
01238             }
01239         }
01240 
01241         if (printer->pm) {
01242             if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
01243                 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
01244                                                     pDefault ? pDefault->DesiredAccess : 0,
01245                                                     &printer->hXcv);
01246             }
01247             if (printer->hXcv == NULL) {
01248                 printer_free(printer);
01249                 SetLastError(ERROR_INVALID_PARAMETER);
01250                 printer = NULL;
01251                 goto end;
01252             }
01253         }
01254         else
01255         {
01256             /* Does the Printer exist? */
01257             if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
01258                 ERR("Can't create Printers key\n");
01259                 printer_free(printer);
01260                 SetLastError(ERROR_INVALID_PRINTER_NAME);
01261                 printer = NULL;
01262                 goto end;
01263             }
01264             if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
01265                 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
01266                 RegCloseKey(hkeyPrinters);
01267                 printer_free(printer);
01268                 SetLastError(ERROR_INVALID_PRINTER_NAME);
01269                 printer = NULL;
01270                 goto end;
01271             }
01272             RegCloseKey(hkeyPrinter);
01273             RegCloseKey(hkeyPrinters);
01274         }
01275     }
01276     else
01277     {
01278         TRACE("using the local printserver\n");
01279     }
01280 
01281 end:
01282 
01283     TRACE("==> %p\n", printer);
01284     return (HANDLE)printer;
01285 }
01286 
01287 
01288 /******************************************************************************
01289  *  myAddPrinterDriverEx [internal]
01290  *
01291  * Install a Printer Driver with the Option to upgrade / downgrade the Files
01292  * and a special mode with lazy error checking.
01293  *
01294  */
01295 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
01296 {
01297     const printenv_t *env;
01298     apd_data_t apd;
01299     DRIVER_INFO_8W di;
01300     BOOL    (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
01301     HMODULE hui;
01302     LPWSTR  ptr;
01303     HKEY    hroot;
01304     HKEY    hdrv;
01305     DWORD   disposition;
01306     DWORD   len;
01307     LONG    lres;
01308     BOOL    res;
01309 
01310     /* we need to set all entries in the Registry, independent from the Level of
01311        DRIVER_INFO, that the caller supplied */
01312 
01313     ZeroMemory(&di, sizeof(di));
01314     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
01315         memcpy(&di, pDriverInfo, di_sizeof[level]);
01316     }
01317 
01318     /* dump the most used infos */
01319     TRACE("%p: .cVersion    : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
01320     TRACE("%p: .pName       : %s\n", di.pName, debugstr_w(di.pName));
01321     TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
01322     TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
01323     TRACE("%p: .pDataFile   : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
01324     TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
01325     TRACE("%p: .pHelpFile   : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
01326     /* dump only the first of the additional Files */
01327     TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
01328 
01329 
01330     /* check environment */
01331     env = validate_envW(di.pEnvironment);
01332     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
01333 
01334     /* fill the copy-data / get the driverdir */
01335     len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
01336     if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
01337                                     (LPBYTE) apd.src, len, &len)) {
01338         /* Should never Fail */
01339         return FALSE;
01340     }
01341     memcpy(apd.dst, apd.src, len);
01342     lstrcatW(apd.src, backslashW);
01343     apd.srclen = lstrlenW(apd.src);
01344     lstrcatW(apd.dst, env->versionsubdir);
01345     lstrcatW(apd.dst, backslashW);
01346     apd.dstlen = lstrlenW(apd.dst);
01347     apd.copyflags = dwFileCopyFlags;
01348     apd.lazy = lazy;
01349     CreateDirectoryW(apd.src, NULL);
01350     CreateDirectoryW(apd.dst, NULL);
01351 
01352     hroot = open_driver_reg(env->envname);
01353     if (!hroot) {
01354         ERR("Can't create Drivers key\n");
01355         return FALSE;
01356     }
01357 
01358     /* Fill the Registry for the Driver */
01359     if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
01360                                 KEY_WRITE | KEY_QUERY_VALUE, NULL,
01361                                 &hdrv, &disposition)) != ERROR_SUCCESS) {
01362 
01363         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
01364         RegCloseKey(hroot);
01365         SetLastError(lres);
01366         return FALSE;
01367     }
01368     RegCloseKey(hroot);
01369 
01370     if (disposition == REG_OPENED_EXISTING_KEY) {
01371         TRACE("driver %s already installed\n", debugstr_w(di.pName));
01372         RegCloseKey(hdrv);
01373         SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
01374         return FALSE;
01375     }
01376 
01377     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
01378     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
01379                    sizeof(DWORD));
01380 
01381     RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
01382                    (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
01383     apd_copyfile(di.pDriverPath, &apd);
01384 
01385     RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
01386                    (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
01387     apd_copyfile(di.pDataFile, &apd);
01388 
01389     RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
01390                    (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
01391     apd_copyfile(di.pConfigFile, &apd);
01392 
01393     /* settings for level 3 */
01394     if (di.pHelpFile)
01395         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
01396                        (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
01397     else
01398         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
01399     apd_copyfile(di.pHelpFile, &apd);
01400 
01401 
01402     ptr = di.pDependentFiles;
01403     if (ptr)
01404         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
01405                        multi_sz_lenW(di.pDependentFiles));
01406     else
01407         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
01408     while ((ptr != NULL) && (ptr[0])) {
01409         if (apd_copyfile(ptr, &apd)) {
01410             ptr += lstrlenW(ptr) + 1;
01411         }
01412         else
01413         {
01414             WARN("Failed to copy %s\n", debugstr_w(ptr));
01415             ptr = NULL;
01416         }
01417     }
01418     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
01419     if (di.pMonitorName)
01420         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
01421                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
01422     else
01423         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
01424 
01425     if (di.pDefaultDataType)
01426         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
01427                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
01428     else
01429         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
01430 
01431     /* settings for level 4 */
01432     if (di.pszzPreviousNames)
01433         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
01434                        multi_sz_lenW(di.pszzPreviousNames));
01435     else
01436         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
01437 
01438     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
01439 
01440     RegCloseKey(hdrv);
01441     hui = driver_load(env, di.pConfigFile);
01442     pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
01443     if (hui && pDrvDriverEvent) {
01444 
01445         /* Support for DrvDriverEvent is optional */
01446         TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
01447         /* MSDN: level for DRIVER_INFO is 1 to 3 */
01448         res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
01449         TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
01450     }
01451     FreeLibrary(hui);
01452 
01453     TRACE("=> TRUE with %u\n", GetLastError());
01454     return TRUE;
01455 
01456 }
01457 
01458 /******************************************************************************
01459  * fpAddMonitor [exported through PRINTPROVIDOR]
01460  *
01461  * Install a Printmonitor
01462  *
01463  * PARAMS
01464  *  pName       [I] Servername or NULL (local Computer)
01465  *  Level       [I] Structure-Level (Must be 2)
01466  *  pMonitors   [I] PTR to MONITOR_INFO_2
01467  *
01468  * RETURNS
01469  *  Success: TRUE
01470  *  Failure: FALSE
01471  *
01472  * NOTES
01473  *  All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
01474  *
01475  */
01476 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
01477 {
01478     monitor_t * pm = NULL;
01479     LPMONITOR_INFO_2W mi2w;
01480     HKEY    hroot = NULL;
01481     HKEY    hentry = NULL;
01482     DWORD   disposition;
01483     BOOL    res = FALSE;
01484 
01485     mi2w = (LPMONITOR_INFO_2W) pMonitors;
01486     TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
01487             debugstr_w(mi2w ? mi2w->pName : NULL),
01488             debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
01489             debugstr_w(mi2w ? mi2w->pDLLName : NULL));
01490 
01491     if (copy_servername_from_name(pName, NULL)) {
01492         FIXME("server %s not supported\n", debugstr_w(pName));
01493         SetLastError(ERROR_ACCESS_DENIED);
01494         return FALSE;
01495     }
01496 
01497     if (!mi2w->pName || (! mi2w->pName[0])) {
01498         WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
01499         SetLastError(ERROR_INVALID_PARAMETER);
01500         return FALSE;
01501     }
01502     if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
01503         WARN("Environment %s requested (we support only %s)\n",
01504                 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
01505         SetLastError(ERROR_INVALID_ENVIRONMENT);
01506         return FALSE;
01507     }
01508 
01509     if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
01510         WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
01511         SetLastError(ERROR_INVALID_PARAMETER);
01512         return FALSE;
01513     }
01514 
01515     /* Load and initialize the monitor. SetLastError() is called on failure */
01516     if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
01517         return FALSE;
01518     }
01519     monitor_unload(pm);
01520 
01521     if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
01522         ERR("unable to create key %s\n", debugstr_w(monitorsW));
01523         return FALSE;
01524     }
01525 
01526     if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
01527                         KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
01528                         &disposition) == ERROR_SUCCESS) {
01529 
01530         /* Some installers set options for the port before calling AddMonitor.
01531            We query the "Driver" entry to verify that the monitor is installed,
01532            before we return an error.
01533            When a user installs two print monitors at the same time with the
01534            same name, a race condition is possible but silently ignored. */
01535 
01536         DWORD   namesize = 0;
01537 
01538         if ((disposition == REG_OPENED_EXISTING_KEY) &&
01539             (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
01540                               &namesize) == ERROR_SUCCESS)) {
01541             TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
01542             /* 9x use ERROR_ALREADY_EXISTS */
01543             SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
01544         }
01545         else
01546         {
01547             INT len;
01548             len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
01549             res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
01550                     (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
01551         }
01552         RegCloseKey(hentry);
01553     }
01554 
01555     RegCloseKey(hroot);
01556     return (res);
01557 }
01558 
01559 /******************************************************************************
01560  * fpAddPort [exported through PRINTPROVIDOR]
01561  *
01562  * Add a Port for a specific Monitor
01563  *
01564  * PARAMS
01565  *  pName        [I] Servername or NULL (local Computer)
01566  *  hWnd         [I] Handle to parent Window for the Dialog-Box
01567  *  pMonitorName [I] Name of the Monitor that manage the Port
01568  *
01569  * RETURNS
01570  *  Success: TRUE
01571  *  Failure: FALSE
01572  *
01573  */
01574 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
01575 {
01576     monitor_t * pm;
01577     monitor_t * pui;
01578     LONG        lres;
01579     DWORD       res;
01580 
01581     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
01582 
01583     lres = copy_servername_from_name(pName, NULL);
01584     if (lres) {
01585         FIXME("server %s not supported\n", debugstr_w(pName));
01586         SetLastError(ERROR_INVALID_PARAMETER);
01587         return FALSE;
01588     }
01589 
01590     /* an empty Monitorname is Invalid */
01591     if (!pMonitorName[0]) {
01592         SetLastError(ERROR_NOT_SUPPORTED);
01593         return FALSE;
01594     }
01595 
01596     pm = monitor_load(pMonitorName, NULL);
01597     if (pm && pm->monitor && pm->monitor->pfnAddPort) {
01598         res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
01599         TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
01600     }
01601     else
01602     {
01603         pui = monitor_loadui(pm);
01604         if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
01605             res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
01606             TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
01607         }
01608         else
01609         {
01610             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
01611                     debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
01612                     pui, debugstr_w(pui ? pui->dllname : NULL));
01613 
01614             SetLastError(ERROR_NOT_SUPPORTED);
01615             res = FALSE;
01616         }
01617         monitor_unload(pui);
01618     }
01619     monitor_unload(pm);
01620 
01621     TRACE("returning %d with %u\n", res, GetLastError());
01622     return res;
01623 }
01624 
01625 /******************************************************************************
01626  * fpAddPortEx [exported through PRINTPROVIDOR]
01627  *
01628  * Add a Port for a specific Monitor, without presenting a user interface
01629  *
01630  * PARAMS
01631  *  pName         [I] Servername or NULL (local Computer)
01632  *  level         [I] Structure-Level (1 or 2) for pBuffer
01633  *  pBuffer       [I] PTR to: PORT_INFO_1 or PORT_INFO_2
01634  *  pMonitorName  [I] Name of the Monitor that manage the Port
01635  *
01636  * RETURNS
01637  *  Success: TRUE
01638  *  Failure: FALSE
01639  *
01640  */
01641 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
01642 {
01643     PORT_INFO_2W * pi2;
01644     monitor_t * pm;
01645     DWORD lres;
01646     DWORD res;
01647 
01648     pi2 = (PORT_INFO_2W *) pBuffer;
01649 
01650     TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
01651             debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
01652             debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
01653             debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
01654 
01655     lres = copy_servername_from_name(pName, NULL);
01656     if (lres) {
01657         FIXME("server %s not supported\n", debugstr_w(pName));
01658         SetLastError(ERROR_INVALID_PARAMETER);
01659         return FALSE;
01660     }
01661 
01662     if ((level < 1) || (level > 2)) {
01663         SetLastError(ERROR_INVALID_LEVEL);
01664         return FALSE;
01665     }
01666 
01667     if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
01668         SetLastError(ERROR_INVALID_PARAMETER);
01669         return FALSE;
01670     }
01671 
01672     /* load the Monitor */
01673     pm = monitor_load(pMonitorName, NULL);
01674     if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
01675         res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
01676         TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
01677     }
01678     else
01679     {
01680         FIXME("not implemented for %s (monitor %p: %s)\n",
01681             debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : NULL);
01682             SetLastError(ERROR_INVALID_PARAMETER);
01683             res = FALSE;
01684     }
01685     monitor_unload(pm);
01686     return res;
01687 }
01688 
01689 /******************************************************************************
01690  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
01691  *
01692  * Install a Printer Driver with the Option to upgrade / downgrade the Files
01693  *
01694  * PARAMS
01695  *  pName           [I] Servername or NULL (local Computer)
01696  *  level           [I] Level for the supplied DRIVER_INFO_*W struct
01697  *  pDriverInfo     [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
01698  *  dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
01699  *
01700  * RESULTS
01701  *  Success: TRUE
01702  *  Failure: FALSE
01703  *
01704  */
01705 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
01706 {
01707     LONG lres;
01708 
01709     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
01710     lres = copy_servername_from_name(pName, NULL);
01711     if (lres) {
01712         FIXME("server %s not supported\n", debugstr_w(pName));
01713         SetLastError(ERROR_ACCESS_DENIED);
01714         return FALSE;
01715     }
01716 
01717     if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
01718         TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
01719     }
01720 
01721     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
01722 }
01723 
01724 /******************************************************************************
01725  * fpClosePrinter [exported through PRINTPROVIDOR]
01726  *
01727  * Close a printer handle and free associated resources
01728  *
01729  * PARAMS
01730  *  hPrinter [I] Printerhandle to close
01731  *
01732  * RESULTS
01733  *  Success: TRUE
01734  *  Failure: FALSE
01735  *
01736  */
01737 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
01738 {
01739     printer_t *printer = (printer_t *) hPrinter;
01740 
01741     TRACE("(%p)\n", hPrinter);
01742 
01743     if (printer) {
01744         printer_free(printer);
01745         return TRUE;
01746     }
01747     return FALSE;
01748 }
01749 
01750 /******************************************************************************
01751  * fpConfigurePort [exported through PRINTPROVIDOR]
01752  *
01753  * Display the Configuration-Dialog for a specific Port
01754  *
01755  * PARAMS
01756  *  pName     [I] Servername or NULL (local Computer)
01757  *  hWnd      [I] Handle to parent Window for the Dialog-Box
01758  *  pPortName [I] Name of the Port, that should be configured
01759  *
01760  * RETURNS
01761  *  Success: TRUE
01762  *  Failure: FALSE
01763  *
01764  */
01765 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
01766 {
01767     monitor_t * pm;
01768     monitor_t * pui;
01769     LONG        lres;
01770     DWORD       res;
01771 
01772     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
01773 
01774     lres = copy_servername_from_name(pName, NULL);
01775     if (lres) {
01776         FIXME("server %s not supported\n", debugstr_w(pName));
01777         SetLastError(ERROR_INVALID_NAME);
01778         return FALSE;
01779     }
01780 
01781     /* an empty Portname is Invalid, but can popup a Dialog */
01782     if (!pPortName[0]) {
01783         SetLastError(ERROR_NOT_SUPPORTED);
01784         return FALSE;
01785     }
01786 
01787     pm = monitor_load_by_port(pPortName);
01788     if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
01789         TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
01790                 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
01791         res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
01792         TRACE("got %d with %u\n", res, GetLastError());
01793     }
01794     else
01795     {
01796         pui = monitor_loadui(pm);
01797         if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
01798             TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
01799                         debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
01800             res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
01801             TRACE("got %d with %u\n", res, GetLastError());
01802         }
01803         else
01804         {
01805             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
01806                     debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
01807                     pui, debugstr_w(pui ? pui->dllname : NULL));
01808 
01809             SetLastError(ERROR_NOT_SUPPORTED);
01810             res = FALSE;
01811         }
01812         monitor_unload(pui);
01813     }
01814     monitor_unload(pm);
01815 
01816     TRACE("returning %d with %u\n", res, GetLastError());
01817     return res;
01818 }
01819 
01820 /******************************************************************
01821  * fpDeleteMonitor [exported through PRINTPROVIDOR]
01822  *
01823  * Delete a specific Printmonitor from a Printing-Environment
01824  *
01825  * PARAMS
01826  *  pName        [I] Servername or NULL (local Computer)
01827  *  pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
01828  *  pMonitorName [I] Name of the Monitor, that should be deleted
01829  *
01830  * RETURNS
01831  *  Success: TRUE
01832  *  Failure: FALSE
01833  *
01834  * NOTES
01835  *  pEnvironment is ignored in Windows for the local Computer.
01836  *
01837  */
01838 
01839 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
01840 {
01841     HKEY    hroot = NULL;
01842     LONG    lres;
01843 
01844     TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
01845            debugstr_w(pMonitorName));
01846 
01847     lres = copy_servername_from_name(pName, NULL);
01848     if (lres) {
01849         FIXME("server %s not supported\n", debugstr_w(pName));
01850         SetLastError(ERROR_INVALID_NAME);
01851         return FALSE;
01852     }
01853 
01854     /*  pEnvironment is ignored in Windows for the local Computer */
01855     if (!pMonitorName || !pMonitorName[0]) {
01856         TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
01857         SetLastError(ERROR_INVALID_PARAMETER);
01858         return FALSE;
01859     }
01860 
01861     if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
01862         ERR("unable to create key %s\n", debugstr_w(monitorsW));
01863         return FALSE;
01864     }
01865 
01866     if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
01867         TRACE("%s deleted\n", debugstr_w(pMonitorName));
01868         RegCloseKey(hroot);
01869         return TRUE;
01870     }
01871 
01872     TRACE("%s does not exist\n", debugstr_w(pMonitorName));
01873     RegCloseKey(hroot);
01874 
01875     /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
01876     SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
01877     return FALSE;
01878 }
01879 
01880 /*****************************************************************************
01881  * fpDeletePort [exported through PRINTPROVIDOR]
01882  *
01883  * Delete a specific Port
01884  *
01885  * PARAMS
01886  *  pName     [I] Servername or NULL (local Computer)
01887  *  hWnd      [I] Handle to parent Window for the Dialog-Box
01888  *  pPortName [I] Name of the Port, that should be deleted
01889  *
01890  * RETURNS
01891  *  Success: TRUE
01892  *  Failure: FALSE
01893  *
01894  */
01895 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
01896 {
01897     monitor_t * pm;
01898     monitor_t * pui;
01899     LONG        lres;
01900     DWORD       res;
01901 
01902     TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
01903 
01904     lres = copy_servername_from_name(pName, NULL);
01905     if (lres) {
01906         FIXME("server %s not supported\n", debugstr_w(pName));
01907         SetLastError(ERROR_INVALID_NAME);
01908         return FALSE;
01909     }
01910 
01911     /* an empty Portname is Invalid */
01912     if (!pPortName[0]) {
01913         SetLastError(ERROR_NOT_SUPPORTED);
01914         return FALSE;
01915     }
01916 
01917     pm = monitor_load_by_port(pPortName);
01918     if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
01919         TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
01920                 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
01921         res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
01922         TRACE("got %d with %u\n", res, GetLastError());
01923     }
01924     else
01925     {
01926         pui = monitor_loadui(pm);
01927         if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
01928             TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
01929                         debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
01930             res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
01931             TRACE("got %d with %u\n", res, GetLastError());
01932         }
01933         else
01934         {
01935             FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
01936                     debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
01937                     pui, debugstr_w(pui ? pui->dllname : NULL));
01938 
01939             SetLastError(ERROR_NOT_SUPPORTED);
01940             res = FALSE;
01941         }
01942         monitor_unload(pui);
01943     }
01944     monitor_unload(pm);
01945 
01946     TRACE("returning %d with %u\n", res, GetLastError());
01947     return res;
01948 }
01949 
01950 /*****************************************************************************
01951  * fpEnumMonitors [exported through PRINTPROVIDOR]
01952  *
01953  * Enumerate available Port-Monitors
01954  *
01955  * PARAMS
01956  *  pName      [I] Servername or NULL (local Computer)
01957  *  Level      [I] Structure-Level (1:Win9x+NT or 2:NT only)
01958  *  pMonitors  [O] PTR to Buffer that receives the Result
01959  *  cbBuf      [I] Size of Buffer at pMonitors
01960  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
01961  *  pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
01962  *
01963  * RETURNS
01964  *  Success: TRUE
01965  *  Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
01966  *
01967  * NOTES
01968  *  Windows reads the Registry once and cache the Results.
01969  *
01970  */
01971 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
01972                                   LPDWORD pcbNeeded, LPDWORD pcReturned)
01973 {
01974     DWORD   numentries = 0;
01975     DWORD   needed = 0;
01976     LONG    lres;
01977     BOOL    res = FALSE;
01978 
01979     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
01980           cbBuf, pcbNeeded, pcReturned);
01981 
01982     lres = copy_servername_from_name(pName, NULL);
01983     if (lres) {
01984         FIXME("server %s not supported\n", debugstr_w(pName));
01985         SetLastError(ERROR_INVALID_NAME);
01986         goto em_cleanup;
01987     }
01988 
01989     if (!Level || (Level > 2)) {
01990         WARN("level (%d) is ignored in win9x\n", Level);
01991         SetLastError(ERROR_INVALID_LEVEL);
01992         return FALSE;
01993     }
01994 
01995     /* Scan all Monitor-Keys */
01996     numentries = 0;
01997     needed = get_local_monitors(Level, NULL, 0, &numentries);
01998 
01999     /* we calculated the needed buffersize. now do more error-checks */
02000     if (cbBuf < needed) {
02001         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02002         goto em_cleanup;
02003     }
02004 
02005     /* fill the Buffer with the Monitor-Keys */
02006     needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
02007     res = TRUE;
02008 
02009 em_cleanup:
02010     if (pcbNeeded)  *pcbNeeded = needed;
02011     if (pcReturned) *pcReturned = numentries;
02012 
02013     TRACE("returning %d with %d (%d byte for %d entries)\n",
02014             res, GetLastError(), needed, numentries);
02015 
02016     return (res);
02017 }
02018 
02019 /******************************************************************************
02020  * fpEnumPorts [exported through PRINTPROVIDOR]
02021  *
02022  * Enumerate available Ports
02023  *
02024  * PARAMS
02025  *  pName      [I] Servername or NULL (local Computer)
02026  *  Level      [I] Structure-Level (1 or 2)
02027  *  pPorts     [O] PTR to Buffer that receives the Result
02028  *  cbBuf      [I] Size of Buffer at pPorts
02029  *  pcbNeeded  [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
02030  *  pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
02031  *
02032  * RETURNS
02033  *  Success: TRUE
02034  *  Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
02035  *
02036  */
02037 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
02038                                LPDWORD pcbNeeded, LPDWORD pcReturned)
02039 {
02040     DWORD   needed = 0;
02041     DWORD   numentries = 0;
02042     LONG    lres;
02043     BOOL    res = FALSE;
02044 
02045     TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
02046           cbBuf, pcbNeeded, pcReturned);
02047 
02048     lres = copy_servername_from_name(pName, NULL);
02049     if (lres) {
02050         FIXME("server %s not supported\n", debugstr_w(pName));
02051         SetLastError(ERROR_INVALID_NAME);
02052         goto emP_cleanup;
02053     }
02054 
02055     if (!Level || (Level > 2)) {
02056         SetLastError(ERROR_INVALID_LEVEL);
02057         goto emP_cleanup;
02058     }
02059 
02060     if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
02061         SetLastError(RPC_X_NULL_REF_POINTER);
02062         goto emP_cleanup;
02063     }
02064 
02065     EnterCriticalSection(&monitor_handles_cs);
02066     monitor_loadall();
02067 
02068     /* Scan all local Ports */
02069     numentries = 0;
02070     needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
02071 
02072     /* we calculated the needed buffersize. now do the error-checks */
02073     if (cbBuf < needed) {
02074         monitor_unloadall();
02075         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02076         goto emP_cleanup_cs;
02077     }
02078     else if (!pPorts || !pcReturned) {
02079         monitor_unloadall();
02080         SetLastError(RPC_X_NULL_REF_POINTER);
02081         goto emP_cleanup_cs;
02082     }
02083 
02084     /* Fill the Buffer */
02085     needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
02086     res = TRUE;
02087     monitor_unloadall();
02088 
02089 emP_cleanup_cs:
02090     LeaveCriticalSection(&monitor_handles_cs);
02091 
02092 emP_cleanup:
02093     if (pcbNeeded)  *pcbNeeded = needed;
02094     if (pcReturned) *pcReturned = (res) ? numentries : 0;
02095 
02096     TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
02097           (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
02098 
02099     return (res);
02100 }
02101 
02102 /*****************************************************************************
02103  * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
02104  *
02105  * Enumerate available Print Processors
02106  *
02107  * PARAMS
02108  *  pName        [I] Servername or NULL (local Computer)
02109  *  pEnvironment [I] Printing-Environment or NULL (Default)
02110  *  Level        [I] Structure-Level (Only 1 is allowed)
02111  *  pPPInfo      [O] PTR to Buffer that receives the Result
02112  *  cbBuf        [I] Size of Buffer at pMonitors
02113  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
02114  *  pcReturned   [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
02115  *
02116  * RETURNS
02117  *  Success: TRUE
02118  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
02119  *
02120  */
02121 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
02122                             LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
02123 {
02124     const printenv_t * env;
02125     LPWSTR  regpathW = NULL;
02126     DWORD   numentries = 0;
02127     DWORD   needed = 0;
02128     LONG    lres;
02129     BOOL    res = FALSE;
02130 
02131     TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
02132                                 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
02133 
02134     lres = copy_servername_from_name(pName, NULL);
02135     if (lres) {
02136         FIXME("server %s not supported\n", debugstr_w(pName));
02137         SetLastError(ERROR_INVALID_NAME);
02138         goto epp_cleanup;
02139     }
02140 
02141     if (Level != 1) {
02142         SetLastError(ERROR_INVALID_LEVEL);
02143         goto epp_cleanup;
02144     }
02145 
02146     env = validate_envW(pEnvironment);
02147     if (!env)
02148         goto epp_cleanup;   /* ERROR_INVALID_ENVIRONMENT */
02149 
02150     regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
02151                             (lstrlenW(env->envname) * sizeof(WCHAR)));
02152 
02153     if (!regpathW)
02154         goto epp_cleanup;
02155 
02156     wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
02157 
02158     /* Scan all Printprocessor-Keys */
02159     numentries = 0;
02160     needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
02161 
02162     /* we calculated the needed buffersize. now do more error-checks */
02163     if (cbBuf < needed) {
02164         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02165         goto epp_cleanup;
02166     }
02167 
02168     /* fill the Buffer with the Printprocessor Infos */
02169     needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
02170     res = TRUE;
02171 
02172 epp_cleanup:
02173     heap_free(regpathW);
02174     if (pcbNeeded)  *pcbNeeded = needed;
02175     if (pcReturned) *pcReturned = numentries;
02176 
02177     TRACE("returning %d with %d (%d byte for %d entries)\n",
02178             res, GetLastError(), needed, numentries);
02179 
02180     return (res);
02181 }
02182 
02183 /******************************************************************************
02184  * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
02185  *
02186  * Return the PATH for the Print-Processors
02187  *
02188  * PARAMS
02189  *  pName        [I] Servername or NULL (this computer)
02190  *  pEnvironment [I] Printing-Environment or NULL (Default)
02191  *  level        [I] Structure-Level (must be 1)
02192  *  pPPInfo      [O] PTR to Buffer that receives the Result
02193  *  cbBuf        [I] Size of Buffer at pPPInfo
02194  *  pcbNeeded    [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
02195  *
02196  * RETURNS
02197  *  Success: TRUE
02198  *  Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
02199  *
02200  *  Native Values returned in pPPInfo on Success for this computer:
02201  *| NT(Windows x64):    "%winsysdir%\\spool\\PRTPROCS\\x64"
02202  *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
02203  *| NT(Windows 4.0):    "%winsysdir%\\spool\\PRTPROCS\\win40"
02204  *
02205  *  "%winsysdir%" is the Value from GetSystemDirectoryW()
02206  *
02207  */
02208 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
02209                                                 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
02210 {
02211     const printenv_t * env;
02212     DWORD needed;
02213     LONG  lres;
02214 
02215     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
02216                                         level, pPPInfo, cbBuf, pcbNeeded);
02217 
02218     *pcbNeeded = 0;
02219     lres = copy_servername_from_name(pName, NULL);
02220     if (lres) {
02221         FIXME("server %s not supported\n", debugstr_w(pName));
02222         SetLastError(RPC_S_SERVER_UNAVAILABLE);
02223         return FALSE;
02224     }
02225 
02226     env = validate_envW(pEnvironment);
02227     if (!env)
02228         return FALSE;   /* ERROR_INVALID_ENVIRONMENT */
02229 
02230     /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
02231     needed = GetSystemDirectoryW(NULL, 0);
02232     /* add the Size for the Subdirectories */
02233     needed += lstrlenW(spoolprtprocsW);
02234     needed += lstrlenW(env->subdir);
02235     needed *= sizeof(WCHAR);  /* return-value is size in Bytes */
02236 
02237     *pcbNeeded = needed;
02238 
02239     if (needed > cbBuf) {
02240         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02241         return FALSE;
02242     }
02243 
02244     GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
02245     /* add the Subdirectories */
02246     lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
02247     lstrcatW((LPWSTR) pPPInfo, env->subdir);
02248     TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
02249     return TRUE;
02250 }
02251 
02252 /******************************************************************************
02253  * fpOpenPrinter [exported through PRINTPROVIDOR]
02254  *
02255  * Open a Printer / Printserver or a Printer-Object
02256  *
02257  * PARAMS
02258  *  lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
02259  *  pPrinter      [O] The resulting Handle is stored here
02260  *  pDefaults     [I] PTR to Default Printer Settings or NULL
02261  *
02262  * RETURNS
02263  *  Success: TRUE
02264  *  Failure: FALSE
02265  *
02266  * NOTES
02267  *  lpPrinterName is one of:
02268  *|  Printserver (NT only): "Servername" or NULL for the local Printserver
02269  *|  Printer: "PrinterName"
02270  *|  Printer-Object: "PrinterName,Job xxx"
02271  *|  XcvMonitor: "Servername,XcvMonitor MonitorName"
02272  *|  XcvPort: "Servername,XcvPort PortName"
02273  *
02274  *
02275  */
02276 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
02277                                  LPPRINTER_DEFAULTSW pDefaults)
02278 {
02279 
02280     TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
02281 
02282     *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
02283 
02284     return (*pPrinter != 0);
02285 }
02286 
02287 /******************************************************************************
02288  * fpXcvData [exported through PRINTPROVIDOR]
02289  *
02290  * Execute commands in the Printmonitor DLL
02291  *
02292  * PARAMS
02293  *  hXcv            [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
02294  *  pszDataName     [i] Name of the command to execute
02295  *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
02296  *  cbInputData     [i] Size in Bytes of Buffer at pInputData
02297  *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
02298  *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
02299  *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
02300  *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
02301  *
02302  * RETURNS
02303  *  Success: TRUE
02304  *  Failure: FALSE
02305  *
02306  * NOTES
02307  *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
02308  *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
02309  *
02310  *  Minimal List of commands, that a Printmonitor DLL should support:
02311  *
02312  *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
02313  *| "AddPort"   : Add a Port
02314  *| "DeletePort": Delete a Port
02315  *
02316  *  Many Printmonitors support additional commands. Examples for localspl.dll:
02317  *  "GetDefaultCommConfig", "SetDefaultCommConfig",
02318  *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
02319  *
02320  */
02321 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
02322                     DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
02323                     PDWORD pcbOutputNeeded, PDWORD pdwStatus)
02324 {
02325     printer_t *printer = (printer_t * ) hXcv;
02326 
02327     TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
02328           pInputData, cbInputData, pOutputData,
02329           cbOutputData, pcbOutputNeeded, pdwStatus);
02330 
02331     if (!printer || (!printer->hXcv)) {
02332         SetLastError(ERROR_INVALID_HANDLE);
02333         return FALSE;
02334     }
02335 
02336     if (!pcbOutputNeeded) {
02337         SetLastError(ERROR_INVALID_PARAMETER);
02338         return FALSE;
02339     }
02340 
02341     if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
02342         SetLastError(RPC_X_NULL_REF_POINTER);
02343         return FALSE;
02344     }
02345 
02346     *pcbOutputNeeded = 0;
02347 
02348     *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
02349             pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
02350 
02351     return TRUE;
02352 }
02353 
02354 /*****************************************************
02355  *  setup_provider [internal]
02356  */
02357 void setup_provider(void)
02358 {
02359     static const PRINTPROVIDOR backend = {
02360         fpOpenPrinter,
02361         NULL,   /* fpSetJob */
02362         NULL,   /* fpGetJob */
02363         NULL,   /* fpEnumJobs */
02364         NULL,   /* fpAddPrinter */
02365         NULL,   /* fpDeletePrinter */
02366         NULL,   /* fpSetPrinter */
02367         NULL,   /* fpGetPrinter */
02368         NULL,   /* fpEnumPrinters */
02369         NULL,   /* fpAddPrinterDriver */
02370         NULL,   /* fpEnumPrinterDrivers */
02371         NULL,   /* fpGetPrinterDriver */
02372         fpGetPrinterDriverDirectory,
02373         NULL,   /* fpDeletePrinterDriver */
02374         NULL,   /* fpAddPrintProcessor */
02375         fpEnumPrintProcessors,
02376         fpGetPrintProcessorDirectory,
02377         NULL,   /* fpDeletePrintProcessor */
02378         NULL,   /* fpEnumPrintProcessorDatatypes */
02379         NULL,   /* fpStartDocPrinter */
02380         NULL,   /* fpStartPagePrinter */
02381         NULL,   /* fpWritePrinter */
02382         NULL,   /* fpEndPagePrinter */
02383         NULL,   /* fpAbortPrinter */
02384         NULL,   /* fpReadPrinter */
02385         NULL,   /* fpEndDocPrinter */
02386         NULL,   /* fpAddJob */
02387         NULL,   /* fpScheduleJob */
02388         NULL,   /* fpGetPrinterData */
02389         NULL,   /* fpSetPrinterData */
02390         NULL,   /* fpWaitForPrinterChange */
02391         fpClosePrinter,
02392         NULL,   /* fpAddForm */
02393         NULL,   /* fpDeleteForm */
02394         NULL,   /* fpGetForm */
02395         NULL,   /* fpSetForm */
02396         NULL,   /* fpEnumForms */
02397         fpEnumMonitors,
02398         fpEnumPorts,
02399         fpAddPort,
02400         fpConfigurePort,
02401         fpDeletePort,
02402         NULL,   /* fpCreatePrinterIC */
02403         NULL,   /* fpPlayGdiScriptOnPrinterIC */
02404         NULL,   /* fpDeletePrinterIC */
02405         NULL,   /* fpAddPrinterConnection */
02406         NULL,   /* fpDeletePrinterConnection */
02407         NULL,   /* fpPrinterMessageBox */
02408         fpAddMonitor,
02409         fpDeleteMonitor,
02410         NULL,   /* fpResetPrinter */
02411         NULL,   /* fpGetPrinterDriverEx */
02412         NULL,   /* fpFindFirstPrinterChangeNotification */
02413         NULL,   /* fpFindClosePrinterChangeNotification */
02414         fpAddPortEx,
02415         NULL,   /* fpShutDown */
02416         NULL,   /* fpRefreshPrinterChangeNotification */
02417         NULL,   /* fpOpenPrinterEx */
02418         NULL,   /* fpAddPrinterEx */
02419         NULL,   /* fpSetPort */
02420         NULL,   /* fpEnumPrinterData */
02421         NULL,   /* fpDeletePrinterData */
02422         NULL,   /* fpClusterSplOpen */
02423         NULL,   /* fpClusterSplClose */
02424         NULL,   /* fpClusterSplIsAlive */
02425         NULL,   /* fpSetPrinterDataEx */
02426         NULL,   /* fpGetPrinterDataEx */
02427         NULL,   /* fpEnumPrinterDataEx */
02428         NULL,   /* fpEnumPrinterKey */
02429         NULL,   /* fpDeletePrinterDataEx */
02430         NULL,   /* fpDeletePrinterKey */
02431         NULL,   /* fpSeekPrinter */
02432         NULL,   /* fpDeletePrinterDriverEx */
02433         NULL,   /* fpAddPerMachineConnection */
02434         NULL,   /* fpDeletePerMachineConnection */
02435         NULL,   /* fpEnumPerMachineConnections */
02436         fpXcvData,
02437         fpAddPrinterDriverEx,
02438         NULL,   /* fpSplReadPrinter */
02439         NULL,   /* fpDriverUnloadComplete */
02440         NULL,   /* fpGetSpoolFileInfo */
02441         NULL,   /* fpCommitSpoolData */
02442         NULL,   /* fpCloseSpoolFileHandle */
02443         NULL,   /* fpFlushPrinter */
02444         NULL,   /* fpSendRecvBidiData */
02445         NULL    /* fpAddDriverCatalog */
02446     };
02447     pprovider = &backend;
02448 
02449 }
02450 
02451 /*****************************************************
02452  * InitializePrintProvidor     (localspl.@)
02453  *
02454  * Initialize the Printprovider
02455  *
02456  * PARAMS
02457  *  pPrintProvidor    [I] Buffer to fill with a struct PRINTPROVIDOR
02458  *  cbPrintProvidor   [I] Size of Buffer in Bytes
02459  *  pFullRegistryPath [I] Registry-Path for the Printprovidor
02460  *
02461  * RETURNS
02462  *  Success: TRUE and pPrintProvidor filled
02463  *  Failure: FALSE
02464  *
02465  * NOTES
02466  *  The RegistryPath should be:
02467  *  "System\CurrentControlSet\Control\Print\Providers<providername>",
02468  *  but this Parameter is ignored in "localspl.dll".
02469  *
02470  */
02471 
02472 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
02473                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
02474 {
02475 
02476     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
02477     memcpy(pPrintProvidor, pprovider,
02478           (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
02479 
02480     return TRUE;
02481 }

Generated on Fri May 25 2012 04:19:42 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.