4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
63 #include "ddk/winsplp.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs
;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
73 0, 0, &monitor_handles_cs
,
74 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
75 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs
;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
83 0, 0, &printer_handles_cs
,
84 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
85 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
89 /* ############################### */
125 WCHAR
*document_title
;
133 LPCWSTR versionregpath
;
134 LPCWSTR versionsubdir
;
137 /* ############################### */
139 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
140 static monitor_t
* pm_localport
;
142 static opened_printer_t
**printer_handles
;
143 static int nb_printer_handles
;
144 static LONG next_job_id
= 1;
146 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
147 WORD fwCapability
, LPSTR lpszOutput
,
149 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
150 LPSTR lpszDevice
, LPSTR lpszPort
,
151 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
154 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
155 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
156 'c','o','n','t','r','o','l','\\',
157 'P','r','i','n','t','\\',
158 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
159 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
161 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
162 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
163 'C','o','n','t','r','o','l','\\',
164 'P','r','i','n','t','\\',
165 'M','o','n','i','t','o','r','s','\\',0};
167 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
168 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
169 'C','o','n','t','r','o','l','\\',
170 'P','r','i','n','t','\\',
171 'P','r','i','n','t','e','r','s',0};
173 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
175 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
176 'M','i','c','r','o','s','o','f','t','\\',
177 'W','i','n','d','o','w','s',' ','N','T','\\',
178 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
179 'W','i','n','d','o','w','s',0};
181 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
182 'M','i','c','r','o','s','o','f','t','\\',
183 'W','i','n','d','o','w','s',' ','N','T','\\',
184 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
185 'D','e','v','i','c','e','s',0};
187 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
188 'M','i','c','r','o','s','o','f','t','\\',
189 'W','i','n','d','o','w','s',' ','N','T','\\',
190 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
191 'P','o','r','t','s',0};
193 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
194 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
195 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
196 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
197 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
198 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
199 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
201 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
202 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
204 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
210 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
212 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
213 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
214 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
215 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
216 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW
[] = {'N','a','m','e',0};
219 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW
[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
224 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
226 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
230 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW
[] = {0};
236 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
237 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
239 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
241 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
242 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
243 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
245 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
246 'D','o','c','u','m','e','n','t',0};
249 /*****************************************************************************
250 * WINSPOOL_SHRegDeleteKey
252 * Recursively delete subkeys.
253 * Cut & paste from shlwapi.
256 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
258 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
259 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
262 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
265 /* Find how many subkeys there are */
266 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
267 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
271 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
272 /* Name too big: alloc a buffer for it */
273 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
276 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
279 /* Recursively delete all the subkeys */
280 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
282 dwSize
= dwMaxSubkeyLen
;
283 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
285 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
288 if (lpszName
!= szNameBuf
)
289 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
293 RegCloseKey(hSubKey
);
295 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
301 /******************************************************************
302 * validate the user-supplied printing-environment [internal]
305 * env [I] PTR to Environment-String or NULL
309 * Success: PTR to printenv_t
312 * An empty string is handled the same way as NULL.
313 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
317 static const printenv_t
* validate_envW(LPCWSTR env
)
319 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
320 3, Version3_RegPathW
, Version3_SubdirW
};
321 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
322 0, emptyStringW
, emptyStringW
};
323 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
325 const printenv_t
*result
= NULL
;
328 TRACE("testing %s\n", debugstr_w(env
));
331 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
333 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
335 result
= all_printenv
[i
];
340 if (result
== NULL
) {
341 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
342 SetLastError(ERROR_INVALID_ENVIRONMENT
);
344 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
348 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
350 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
356 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
357 if passed a NULL string. This returns NULLs to the result.
359 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
363 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
364 return usBufferPtr
->Buffer
;
366 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
370 static LPWSTR
strdupW(LPCWSTR p
)
376 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
377 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
382 static LPSTR
strdupWtoA( LPCWSTR str
)
387 if (!str
) return NULL
;
388 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
389 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
390 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
394 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
395 The result includes all \0s (specifically the last two). */
396 static int multi_sz_lenA(const char *str
)
398 const char *ptr
= str
;
402 ptr
+= lstrlenA(ptr
) + 1;
405 return ptr
- str
+ 1;
409 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
412 /* If forcing, or no profile string entry for device yet, set the entry
414 * The always change entry if not WINEPS yet is discussable.
417 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
419 !strstr(qbuf
,"WINEPS.DRV")
421 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
424 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
425 WriteProfileStringA("windows","device",buf
);
426 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
427 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
430 HeapFree(GetProcessHeap(),0,buf
);
434 static BOOL
add_printer_driver(const char *name
)
438 static char driver_path
[] = "wineps16",
439 data_file
[] = "<datafile?>",
440 config_file
[] = "wineps16",
441 help_file
[] = "<helpfile?>",
442 dep_file
[] = "<dependent files?>\0",
443 monitor_name
[] = "<monitor name?>",
444 default_data_type
[] = "RAW";
446 di3a
.cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
447 di3a
.pName
= (char *)name
;
448 di3a
.pEnvironment
= NULL
; /* NULL means auto */
449 di3a
.pDriverPath
= driver_path
;
450 di3a
.pDataFile
= data_file
;
451 di3a
.pConfigFile
= config_file
;
452 di3a
.pHelpFile
= help_file
;
453 di3a
.pDependentFiles
= dep_file
;
454 di3a
.pMonitorName
= monitor_name
;
455 di3a
.pDefaultDataType
= default_data_type
;
457 if (!AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
459 ERR("Failed adding driver (%d)\n", GetLastError());
465 #ifdef HAVE_CUPS_CUPS_H
466 static typeof(cupsGetDests
) *pcupsGetDests
;
467 static typeof(cupsGetPPD
) *pcupsGetPPD
;
468 static typeof(cupsPrintFile
) *pcupsPrintFile
;
469 static void *cupshandle
;
471 static BOOL
CUPS_LoadPrinters(void)
474 BOOL hadprinter
= FALSE
;
476 PRINTER_INFO_2A pinfo2a
;
478 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
480 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
483 TRACE("loaded %s\n", SONAME_LIBCUPS
);
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
490 DYNCUPS(cupsGetDests
);
491 DYNCUPS(cupsPrintFile
);
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
496 ERR("Can't create Printers key\n");
500 nrofdests
= pcupsGetDests(&dests
);
501 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
502 for (i
=0;i
<nrofdests
;i
++) {
503 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
504 sprintf(port
,"LPR:%s",dests
[i
].name
);
505 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
506 sprintf(devline
,"WINEPS.DRV,%s",port
);
507 WriteProfileStringA("devices",dests
[i
].name
,devline
);
508 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
509 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
512 HeapFree(GetProcessHeap(),0,devline
);
514 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
515 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
516 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
518 TRACE("Printer already exists\n");
519 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
520 RegCloseKey(hkeyPrinter
);
522 static CHAR data_type
[] = "RAW",
523 print_proc
[] = "WinPrint",
524 comment
[] = "WINEPS Printer using CUPS",
525 location
[] = "<physical location of printer>",
526 params
[] = "<parameters?>",
527 share_name
[] = "<share name?>",
528 sep_file
[] = "<sep file?>";
530 add_printer_driver(dests
[i
].name
);
532 memset(&pinfo2a
,0,sizeof(pinfo2a
));
533 pinfo2a
.pPrinterName
= dests
[i
].name
;
534 pinfo2a
.pDatatype
= data_type
;
535 pinfo2a
.pPrintProcessor
= print_proc
;
536 pinfo2a
.pDriverName
= dests
[i
].name
;
537 pinfo2a
.pComment
= comment
;
538 pinfo2a
.pLocation
= location
;
539 pinfo2a
.pPortName
= port
;
540 pinfo2a
.pParameters
= params
;
541 pinfo2a
.pShareName
= share_name
;
542 pinfo2a
.pSepFile
= sep_file
;
544 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
545 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
546 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
549 HeapFree(GetProcessHeap(),0,port
);
552 if (dests
[i
].is_default
)
553 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
555 RegCloseKey(hkeyPrinters
);
561 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
562 PRINTER_INFO_2A pinfo2a
;
563 char *e
,*s
,*name
,*prettyname
,*devname
;
564 BOOL ret
= FALSE
, set_default
= FALSE
;
565 char *port
,*devline
,*env_default
;
566 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
568 while (isspace(*pent
)) pent
++;
569 s
= strchr(pent
,':');
571 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
579 TRACE("name=%s entry=%s\n",name
, pent
);
581 if(ispunct(*name
)) { /* a tc entry, not a real printer */
582 TRACE("skipping tc entry\n");
586 if(strstr(pent
,":server")) { /* server only version so skip */
587 TRACE("skipping server entry\n");
591 /* Determine whether this is a postscript printer. */
594 env_default
= getenv("PRINTER");
596 /* Get longest name, usually the one at the right for later display. */
597 while((s
=strchr(prettyname
,'|'))) {
600 while(isspace(*--e
)) *e
= '\0';
601 TRACE("\t%s\n", debugstr_a(prettyname
));
602 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
603 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
606 e
= prettyname
+ strlen(prettyname
);
607 while(isspace(*--e
)) *e
= '\0';
608 TRACE("\t%s\n", debugstr_a(prettyname
));
609 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
611 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
612 * if it is too long, we use it as comment below. */
613 devname
= prettyname
;
614 if (strlen(devname
)>=CCHDEVICENAME
-1)
616 if (strlen(devname
)>=CCHDEVICENAME
-1) {
621 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
622 sprintf(port
,"LPR:%s",name
);
624 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
625 sprintf(devline
,"WINEPS.DRV,%s",port
);
626 WriteProfileStringA("devices",devname
,devline
);
627 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
628 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
631 HeapFree(GetProcessHeap(),0,devline
);
633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
635 ERR("Can't create Printers key\n");
639 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
640 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
642 TRACE("Printer already exists\n");
643 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
644 RegCloseKey(hkeyPrinter
);
646 static CHAR data_type
[] = "RAW",
647 print_proc
[] = "WinPrint",
648 comment
[] = "WINEPS Printer using LPR",
649 params
[] = "<parameters?>",
650 share_name
[] = "<share name?>",
651 sep_file
[] = "<sep file?>";
653 add_printer_driver(devname
);
655 memset(&pinfo2a
,0,sizeof(pinfo2a
));
656 pinfo2a
.pPrinterName
= devname
;
657 pinfo2a
.pDatatype
= data_type
;
658 pinfo2a
.pPrintProcessor
= print_proc
;
659 pinfo2a
.pDriverName
= devname
;
660 pinfo2a
.pComment
= comment
;
661 pinfo2a
.pLocation
= prettyname
;
662 pinfo2a
.pPortName
= port
;
663 pinfo2a
.pParameters
= params
;
664 pinfo2a
.pShareName
= share_name
;
665 pinfo2a
.pSepFile
= sep_file
;
667 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
668 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
669 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
672 RegCloseKey(hkeyPrinters
);
674 if (isfirst
|| set_default
)
675 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
677 HeapFree(GetProcessHeap(), 0, port
);
679 HeapFree(GetProcessHeap(), 0, name
);
684 PRINTCAP_LoadPrinters(void) {
685 BOOL hadprinter
= FALSE
;
689 BOOL had_bash
= FALSE
;
691 f
= fopen("/etc/printcap","r");
695 while(fgets(buf
,sizeof(buf
),f
)) {
698 end
=strchr(buf
,'\n');
702 while(isspace(*start
)) start
++;
703 if(*start
== '#' || *start
== '\0')
706 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
707 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
708 HeapFree(GetProcessHeap(),0,pent
);
712 if (end
&& *--end
== '\\') {
719 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
722 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
728 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
729 HeapFree(GetProcessHeap(),0,pent
);
735 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
738 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
739 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
741 return ERROR_FILE_NOT_FOUND
;
744 /*****************************************************************************
745 * enumerate the local monitors (INTERNAL)
747 * returns the needed size (in bytes) for pMonitors
748 * and *lpreturned is set to number of entries returned in pMonitors
751 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
756 LPMONITOR_INFO_2W mi
;
757 WCHAR buffer
[MAX_PATH
];
758 WCHAR dllname
[MAX_PATH
];
766 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
768 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
769 len
= entrysize
* numentries
;
770 ptr
= (LPWSTR
) &pMonitors
[len
];
773 len
= sizeof(buffer
);
776 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
777 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
778 /* Scan all Monitor-Registry-Keys */
779 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
780 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
781 dllsize
= sizeof(dllname
);
784 /* The Monitor must have a Driver-DLL */
785 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
786 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
787 /* We found a valid DLL for this Monitor. */
788 TRACE("using Driver: %s\n", debugstr_w(dllname
));
793 /* Windows returns only Port-Monitors here, but to simplify our code,
794 we do no filtering for Language-Monitors */
798 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
800 /* we install and return only monitors for "Windows NT x86" */
801 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
805 /* required size is calculated. Now fill the user-buffer */
806 if (pMonitors
&& (cbBuf
>= needed
)){
807 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
808 pMonitors
+= entrysize
;
810 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
812 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
813 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
815 mi
->pEnvironment
= ptr
;
816 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
817 ptr
+= (lstrlenW(envname_x86W
)+1);
820 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
821 ptr
+= (dllsize
/ sizeof(WCHAR
));
826 len
= sizeof(buffer
);
831 *lpreturned
= numentries
;
832 TRACE("need %d byte for %d entries\n", needed
, numentries
);
836 /******************************************************************
837 * monitor_unload [internal]
839 * release a printmonitor and unload it from memory, when needed
842 static void monitor_unload(monitor_t
* pm
)
844 if (pm
== NULL
) return;
845 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
847 EnterCriticalSection(&monitor_handles_cs
);
849 if (pm
->refcount
) pm
->refcount
--;
851 if (pm
->refcount
== 0) {
852 list_remove(&pm
->entry
);
853 FreeLibrary(pm
->hdll
);
854 HeapFree(GetProcessHeap(), 0, pm
->name
);
855 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
856 HeapFree(GetProcessHeap(), 0, pm
);
858 LeaveCriticalSection(&monitor_handles_cs
);
861 /******************************************************************
862 * monitor_unloadall [internal]
864 * release all printmonitors and unload them from memory, when needed
867 static void monitor_unloadall(void)
872 EnterCriticalSection(&monitor_handles_cs
);
873 /* iterate through the list, with safety against removal */
874 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
878 LeaveCriticalSection(&monitor_handles_cs
);
881 /******************************************************************
882 * monitor_load [internal]
884 * load a printmonitor, get the dllname from the registry, when needed
885 * initialize the monitor and dump found function-pointers
887 * On failure, SetLastError() is called and NULL is returned
890 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
892 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
893 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
894 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
895 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
896 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
898 monitor_t
* pm
= NULL
;
900 LPWSTR regroot
= NULL
;
901 LPWSTR driver
= dllname
;
903 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
904 /* Is the Monitor already loaded? */
905 EnterCriticalSection(&monitor_handles_cs
);
908 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
910 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
918 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
919 if (pm
== NULL
) goto cleanup
;
920 list_add_tail(&monitor_handles
, &pm
->entry
);
924 if (pm
->name
== NULL
) {
925 /* Load the monitor */
926 LPMONITOREX pmonitorEx
;
930 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
931 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
935 lstrcpyW(regroot
, MonitorsW
);
936 lstrcatW(regroot
, name
);
937 /* Get the Driver from the Registry */
938 if (driver
== NULL
) {
941 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
942 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
943 &namesize
) == ERROR_SUCCESS
) {
944 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
945 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
952 pm
->name
= strdupW(name
);
953 pm
->dllname
= strdupW(driver
);
955 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
957 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
962 pm
->hdll
= LoadLibraryW(driver
);
963 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
965 if (pm
->hdll
== NULL
) {
967 SetLastError(ERROR_MOD_NOT_FOUND
);
972 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
973 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
974 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
975 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
976 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
979 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
980 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
981 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
982 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
983 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
985 if (pInitializePrintMonitorUI
!= NULL
) {
986 pm
->monitorUI
= pInitializePrintMonitorUI();
987 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
989 TRACE( "0x%08x: dwMonitorSize (%d)\n",
990 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
995 if (pInitializePrintMonitor
&& regroot
) {
996 pmonitorEx
= pInitializePrintMonitor(regroot
);
997 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
998 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
1001 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
1002 pm
->monitor
= &(pmonitorEx
->Monitor
);
1007 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
1011 if (!pm
->monitor
&& regroot
) {
1012 if (pInitializePrintMonitor2
!= NULL
) {
1013 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1015 if (pInitializeMonitorEx
!= NULL
) {
1016 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1018 if (pInitializeMonitor
!= NULL
) {
1019 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1022 if (!pm
->monitor
&& !pm
->monitorUI
) {
1024 SetLastError(ERROR_PROC_NOT_FOUND
);
1029 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1033 LeaveCriticalSection(&monitor_handles_cs
);
1034 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1035 HeapFree(GetProcessHeap(), 0, regroot
);
1036 TRACE("=> %p\n", pm
);
1040 /******************************************************************
1041 * monitor_loadall [internal]
1043 * Load all registered monitors
1046 static DWORD
monitor_loadall(void)
1049 DWORD registered
= 0;
1052 WCHAR buffer
[MAX_PATH
];
1055 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1056 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1057 NULL
, NULL
, NULL
, NULL
, NULL
);
1059 TRACE("%d monitors registered\n", registered
);
1061 EnterCriticalSection(&monitor_handles_cs
);
1062 while (id
< registered
) {
1064 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1065 pm
= monitor_load(buffer
, NULL
);
1069 LeaveCriticalSection(&monitor_handles_cs
);
1070 RegCloseKey(hmonitors
);
1072 TRACE("%d monitors loaded\n", loaded
);
1076 /******************************************************************
1077 * monitor_loadui [internal]
1079 * load the userinterface-dll for a given portmonitor
1081 * On failure, NULL is returned
1084 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1086 monitor_t
* pui
= NULL
;
1087 LPWSTR buffer
[MAX_PATH
];
1092 if (pm
== NULL
) return NULL
;
1093 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1095 /* Try the Portmonitor first; works for many monitors */
1096 if (pm
->monitorUI
) {
1097 EnterCriticalSection(&monitor_handles_cs
);
1099 LeaveCriticalSection(&monitor_handles_cs
);
1103 /* query the userinterface-dllname from the Portmonitor */
1104 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1105 /* building (",XcvMonitor %s",pm->name) not needed yet */
1106 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1107 TRACE("got %u with %p\n", res
, hXcv
);
1109 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1110 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1111 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1112 pm
->monitor
->pfnXcvClosePort(hXcv
);
1119 /******************************************************************
1120 * monitor_load_by_port [internal]
1122 * load a printmonitor for a given port
1124 * On failure, NULL is returned
1127 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1132 monitor_t
* pm
= NULL
;
1133 DWORD registered
= 0;
1137 TRACE("(%s)\n", debugstr_w(portname
));
1139 /* Try the Local Monitor first */
1140 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1141 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1142 /* found the portname */
1144 return monitor_load(LocalPortW
, NULL
);
1149 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1150 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1151 if (buffer
== NULL
) return NULL
;
1153 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1154 EnterCriticalSection(&monitor_handles_cs
);
1155 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1157 while ((pm
== NULL
) && (id
< registered
)) {
1159 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1160 TRACE("testing %s\n", debugstr_w(buffer
));
1161 len
= lstrlenW(buffer
);
1162 lstrcatW(buffer
, bs_Ports_bsW
);
1163 lstrcatW(buffer
, portname
);
1164 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1166 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1167 pm
= monitor_load(buffer
, NULL
);
1171 LeaveCriticalSection(&monitor_handles_cs
);
1174 HeapFree(GetProcessHeap(), 0, buffer
);
1178 /******************************************************************
1179 * enumerate the local Ports from all loaded monitors (internal)
1181 * returns the needed size (in bytes) for pPorts
1182 * and *lpreturned is set to number of entries returned in pPorts
1185 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1189 LPPORT_INFO_2W cache
;
1191 LPBYTE pi_buffer
= NULL
;
1192 DWORD pi_allocated
= 0;
1203 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1204 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1206 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1207 needed
= entrysize
* numentries
;
1208 ptr
= (LPWSTR
) &pPorts
[needed
];
1213 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1215 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1218 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1219 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1220 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1221 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1222 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1223 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1224 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1226 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1227 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1229 numentries
+= pi_returned
;
1230 needed
+= pi_needed
;
1232 /* fill the output-buffer (pPorts), if we have one */
1233 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1235 while (pi_returned
> pi_index
) {
1236 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1237 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1238 out
->pPortName
= ptr
;
1239 lstrcpyW(ptr
, cache
->pPortName
);
1240 ptr
+= (lstrlenW(ptr
)+1);
1242 out
->pMonitorName
= ptr
;
1243 lstrcpyW(ptr
, cache
->pMonitorName
);
1244 ptr
+= (lstrlenW(ptr
)+1);
1246 out
->pDescription
= ptr
;
1247 lstrcpyW(ptr
, cache
->pDescription
);
1248 ptr
+= (lstrlenW(ptr
)+1);
1249 out
->fPortType
= cache
->fPortType
;
1250 out
->Reserved
= cache
->Reserved
;
1258 /* the temporary portinfo-buffer is no longer needed */
1259 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1261 *lpreturned
= numentries
;
1262 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1266 /******************************************************************
1267 * get_servername_from_name (internal)
1269 * for an external server, a copy of the serverpart from the full name is returned
1272 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1276 WCHAR buffer
[MAX_PATH
];
1279 if (name
== NULL
) return NULL
;
1280 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1282 server
= strdupW(&name
[2]); /* skip over both backslash */
1283 if (server
== NULL
) return NULL
;
1285 /* strip '\' and the printername */
1286 ptr
= strchrW(server
, '\\');
1287 if (ptr
) ptr
[0] = '\0';
1289 TRACE("found %s\n", debugstr_w(server
));
1291 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1292 if (GetComputerNameW(buffer
, &len
)) {
1293 if (lstrcmpW(buffer
, server
) == 0) {
1294 /* The requested Servername is our computername */
1295 HeapFree(GetProcessHeap(), 0, server
);
1302 /******************************************************************
1303 * get_basename_from_name (internal)
1305 * skip over the serverpart from the full name
1308 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1310 if (name
== NULL
) return NULL
;
1311 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1312 /* skip over the servername and search for the following '\' */
1313 name
= strchrW(&name
[2], '\\');
1314 if ((name
) && (name
[1])) {
1315 /* found a separator ('\') followed by a name:
1316 skip over the separator and return the rest */
1321 /* no basename present (we found only a servername) */
1328 /******************************************************************
1329 * get_opened_printer_entry
1330 * Get the first place empty in the opened printer table
1333 * - pDefault is ignored
1335 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1337 UINT_PTR handle
= nb_printer_handles
, i
;
1338 jobqueue_t
*queue
= NULL
;
1339 opened_printer_t
*printer
= NULL
;
1341 LPCWSTR printername
;
1346 servername
= get_servername_from_name(name
);
1348 FIXME("server %s not supported\n", debugstr_w(servername
));
1349 HeapFree(GetProcessHeap(), 0, servername
);
1350 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1354 printername
= get_basename_from_name(name
);
1355 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1357 /* an empty printername is invalid */
1358 if (printername
&& (!printername
[0])) {
1359 SetLastError(ERROR_INVALID_PARAMETER
);
1363 EnterCriticalSection(&printer_handles_cs
);
1365 for (i
= 0; i
< nb_printer_handles
; i
++)
1367 if (!printer_handles
[i
])
1369 if(handle
== nb_printer_handles
)
1374 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1375 queue
= printer_handles
[i
]->queue
;
1379 if (handle
>= nb_printer_handles
)
1381 opened_printer_t
**new_array
;
1382 if (printer_handles
)
1383 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1384 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1386 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1387 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1394 printer_handles
= new_array
;
1395 nb_printer_handles
+= 16;
1398 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1405 /* clone the base name. This is NULL for the printserver */
1406 printer
->printername
= strdupW(printername
);
1408 /* clone the full name */
1409 printer
->name
= strdupW(name
);
1410 if (name
&& (!printer
->name
)) {
1416 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1417 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1418 /* OpenPrinter(",XcvMonitor " detected */
1419 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1420 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1421 if (printer
->pm
== NULL
) {
1422 SetLastError(ERROR_UNKNOWN_PORT
);
1429 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1430 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1431 /* OpenPrinter(",XcvPort " detected */
1432 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1433 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1434 if (printer
->pm
== NULL
) {
1435 SetLastError(ERROR_UNKNOWN_PORT
);
1443 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1444 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1445 pDefault
? pDefault
->DesiredAccess
: 0,
1448 if (printer
->hXcv
== NULL
) {
1449 SetLastError(ERROR_INVALID_PARAMETER
);
1456 /* Does the Printer exist? */
1457 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1458 ERR("Can't create Printers key\n");
1462 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1463 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1464 RegCloseKey(hkeyPrinters
);
1465 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1469 RegCloseKey(hkeyPrinter
);
1470 RegCloseKey(hkeyPrinters
);
1475 TRACE("using the local printserver\n");
1479 printer
->queue
= queue
;
1482 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1483 if (!printer
->queue
) {
1487 list_init(&printer
->queue
->jobs
);
1488 printer
->queue
->ref
= 0;
1490 InterlockedIncrement(&printer
->queue
->ref
);
1492 printer_handles
[handle
] = printer
;
1495 LeaveCriticalSection(&printer_handles_cs
);
1496 if (!handle
&& printer
) {
1497 /* Something failed: Free all resources */
1498 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1499 monitor_unload(printer
->pm
);
1500 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1501 HeapFree(GetProcessHeap(), 0, printer
->name
);
1502 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1503 HeapFree(GetProcessHeap(), 0, printer
);
1506 return (HANDLE
)handle
;
1509 /******************************************************************
1510 * get_opened_printer
1511 * Get the pointer to the opened printer referred by the handle
1513 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1515 UINT_PTR idx
= (UINT_PTR
)hprn
;
1516 opened_printer_t
*ret
= NULL
;
1518 EnterCriticalSection(&printer_handles_cs
);
1520 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1523 ret
= printer_handles
[idx
- 1];
1525 LeaveCriticalSection(&printer_handles_cs
);
1529 /******************************************************************
1530 * get_opened_printer_name
1531 * Get the pointer to the opened printer name referred by the handle
1533 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1535 opened_printer_t
*printer
= get_opened_printer(hprn
);
1536 if(!printer
) return NULL
;
1537 return printer
->name
;
1540 /******************************************************************
1541 * WINSPOOL_GetOpenedPrinterRegKey
1544 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1546 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1550 if(!name
) return ERROR_INVALID_HANDLE
;
1552 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1556 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1558 ERR("Can't find opened printer %s in registry\n",
1560 RegCloseKey(hkeyPrinters
);
1561 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1563 RegCloseKey(hkeyPrinters
);
1564 return ERROR_SUCCESS
;
1567 void WINSPOOL_LoadSystemPrinters(void)
1569 HKEY hkey
, hkeyPrinters
;
1571 DWORD needed
, num
, i
;
1572 WCHAR PrinterName
[256];
1575 /* This ensures that all printer entries have a valid Name value. If causes
1576 problems later if they don't. If one is found to be missed we create one
1577 and set it equal to the name of the key */
1578 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1579 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1580 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1581 for(i
= 0; i
< num
; i
++) {
1582 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1583 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1584 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1585 set_reg_szW(hkey
, NameW
, PrinterName
);
1592 RegCloseKey(hkeyPrinters
);
1595 /* We want to avoid calling AddPrinter on printers as much as
1596 possible, because on cups printers this will (eventually) lead
1597 to a call to cupsGetPPD which takes forever, even with non-cups
1598 printers AddPrinter takes a while. So we'll tag all printers that
1599 were automatically added last time around, if they still exist
1600 we'll leave them be otherwise we'll delete them. */
1601 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1603 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1604 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1605 for(i
= 0; i
< num
; i
++) {
1606 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1607 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1608 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1610 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1618 HeapFree(GetProcessHeap(), 0, pi
);
1622 #ifdef HAVE_CUPS_CUPS_H
1623 done
= CUPS_LoadPrinters();
1626 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1627 PRINTCAP_LoadPrinters();
1629 /* Now enumerate the list again and delete any printers that a still tagged */
1630 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1632 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1633 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1634 for(i
= 0; i
< num
; i
++) {
1635 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1636 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1637 BOOL delete_driver
= FALSE
;
1638 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1639 DWORD dw
, type
, size
= sizeof(dw
);
1640 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1641 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1642 DeletePrinter(hprn
);
1643 delete_driver
= TRUE
;
1649 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1654 HeapFree(GetProcessHeap(), 0, pi
);
1661 /******************************************************************
1664 * Get the pointer to the specified job.
1665 * Should hold the printer_handles_cs before calling.
1667 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1669 opened_printer_t
*printer
= get_opened_printer(hprn
);
1672 if(!printer
) return NULL
;
1673 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1675 if(job
->job_id
== JobId
)
1681 /***********************************************************
1684 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1687 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1690 Formname
= (dmA
->dmSize
> off_formname
);
1691 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1692 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1693 dmW
->dmDeviceName
, CCHDEVICENAME
);
1695 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1696 dmA
->dmSize
- CCHDEVICENAME
);
1698 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1699 off_formname
- CCHDEVICENAME
);
1700 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1701 dmW
->dmFormName
, CCHFORMNAME
);
1702 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1703 (off_formname
+ CCHFORMNAME
));
1706 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1707 dmA
->dmDriverExtra
);
1711 /***********************************************************
1713 * Creates an ascii copy of supplied devmode on heap
1715 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1720 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1722 if(!dmW
) return NULL
;
1723 Formname
= (dmW
->dmSize
> off_formname
);
1724 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1725 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1726 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1727 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1729 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1730 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1732 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1733 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1734 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1735 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1736 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1737 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1740 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1741 dmW
->dmDriverExtra
);
1745 /***********************************************************
1746 * PRINTER_INFO_2AtoW
1747 * Creates a unicode copy of PRINTER_INFO_2A on heap
1749 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1751 LPPRINTER_INFO_2W piW
;
1752 UNICODE_STRING usBuffer
;
1754 if(!piA
) return NULL
;
1755 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1756 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1758 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1759 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1760 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1761 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1762 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1763 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1764 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1765 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1766 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1767 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1768 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1769 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1773 /***********************************************************
1774 * FREE_PRINTER_INFO_2W
1775 * Free PRINTER_INFO_2W and all strings
1777 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1781 HeapFree(heap
,0,piW
->pServerName
);
1782 HeapFree(heap
,0,piW
->pPrinterName
);
1783 HeapFree(heap
,0,piW
->pShareName
);
1784 HeapFree(heap
,0,piW
->pPortName
);
1785 HeapFree(heap
,0,piW
->pDriverName
);
1786 HeapFree(heap
,0,piW
->pComment
);
1787 HeapFree(heap
,0,piW
->pLocation
);
1788 HeapFree(heap
,0,piW
->pDevMode
);
1789 HeapFree(heap
,0,piW
->pSepFile
);
1790 HeapFree(heap
,0,piW
->pPrintProcessor
);
1791 HeapFree(heap
,0,piW
->pDatatype
);
1792 HeapFree(heap
,0,piW
->pParameters
);
1793 HeapFree(heap
,0,piW
);
1797 /******************************************************************
1798 * DeviceCapabilities [WINSPOOL.@]
1799 * DeviceCapabilitiesA [WINSPOOL.@]
1802 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1803 LPSTR pOutput
, LPDEVMODEA lpdm
)
1807 if (!GDI_CallDeviceCapabilities16
)
1809 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1811 if (!GDI_CallDeviceCapabilities16
) return -1;
1813 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1815 /* If DC_PAPERSIZE map POINT16s to POINTs */
1816 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1817 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1818 POINT
*pt
= (POINT
*)pOutput
;
1820 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1821 for(i
= 0; i
< ret
; i
++, pt
++)
1826 HeapFree( GetProcessHeap(), 0, tmp
);
1832 /*****************************************************************************
1833 * DeviceCapabilitiesW [WINSPOOL.@]
1835 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1838 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1839 WORD fwCapability
, LPWSTR pOutput
,
1840 const DEVMODEW
*pDevMode
)
1842 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1843 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1844 LPSTR pPortA
= strdupWtoA(pPort
);
1847 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1848 fwCapability
== DC_FILEDEPENDENCIES
||
1849 fwCapability
== DC_PAPERNAMES
)) {
1850 /* These need A -> W translation */
1853 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1857 switch(fwCapability
) {
1862 case DC_FILEDEPENDENCIES
:
1866 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1867 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1869 for(i
= 0; i
< ret
; i
++)
1870 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1871 pOutput
+ (i
* size
), size
);
1872 HeapFree(GetProcessHeap(), 0, pOutputA
);
1874 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1875 (LPSTR
)pOutput
, dmA
);
1877 HeapFree(GetProcessHeap(),0,pPortA
);
1878 HeapFree(GetProcessHeap(),0,pDeviceA
);
1879 HeapFree(GetProcessHeap(),0,dmA
);
1883 /******************************************************************
1884 * DocumentPropertiesA [WINSPOOL.@]
1886 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1888 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1889 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1890 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1892 LPSTR lpName
= pDeviceName
;
1893 static CHAR port
[] = "LPT1:";
1896 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1897 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1901 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1903 ERR("no name from hPrinter?\n");
1904 SetLastError(ERROR_INVALID_HANDLE
);
1907 lpName
= strdupWtoA(lpNameW
);
1910 if (!GDI_CallExtDeviceMode16
)
1912 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1914 if (!GDI_CallExtDeviceMode16
) {
1915 ERR("No CallExtDeviceMode16?\n");
1919 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1920 pDevModeInput
, NULL
, fMode
);
1923 HeapFree(GetProcessHeap(),0,lpName
);
1928 /*****************************************************************************
1929 * DocumentPropertiesW (WINSPOOL.@)
1931 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1933 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1935 LPDEVMODEW pDevModeOutput
,
1936 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1939 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1940 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1941 LPDEVMODEA pDevModeOutputA
= NULL
;
1944 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1945 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1947 if(pDevModeOutput
) {
1948 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1949 if(ret
< 0) return ret
;
1950 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1952 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1953 pDevModeInputA
, fMode
);
1954 if(pDevModeOutput
) {
1955 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1956 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1958 if(fMode
== 0 && ret
> 0)
1959 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1960 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1961 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1965 /******************************************************************
1966 * OpenPrinterA [WINSPOOL.@]
1971 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1972 LPPRINTER_DEFAULTSA pDefault
)
1974 UNICODE_STRING lpPrinterNameW
;
1975 UNICODE_STRING usBuffer
;
1976 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1977 PWSTR pwstrPrinterNameW
;
1980 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1983 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1984 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1985 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1986 pDefaultW
= &DefaultW
;
1988 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1990 RtlFreeUnicodeString(&usBuffer
);
1991 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1993 RtlFreeUnicodeString(&lpPrinterNameW
);
1997 /******************************************************************
1998 * OpenPrinterW [WINSPOOL.@]
2000 * Open a Printer / Printserver or a Printer-Object
2003 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2004 * phPrinter [O] The resulting Handle is stored here
2005 * pDefault [I] PTR to Default Printer Settings or NULL
2012 * lpPrinterName is one of:
2013 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2014 *| Printer: "PrinterName"
2015 *| Printer-Object: "PrinterName,Job xxx"
2016 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2017 *| XcvPort: "Servername,XcvPort PortName"
2020 *| Printer-Object not supported
2021 *| pDefaults is ignored
2024 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2027 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2029 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2030 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2034 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2035 SetLastError(ERROR_INVALID_PARAMETER
);
2039 /* Get the unique handle of the printer or Printserver */
2040 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2041 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2042 return (*phPrinter
!= 0);
2045 /******************************************************************
2046 * AddMonitorA [WINSPOOL.@]
2051 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2053 LPWSTR nameW
= NULL
;
2056 LPMONITOR_INFO_2A mi2a
;
2057 MONITOR_INFO_2W mi2w
;
2059 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2060 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2061 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2062 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2063 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2066 SetLastError(ERROR_INVALID_LEVEL
);
2070 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2076 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2077 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2078 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2081 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2083 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2084 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2085 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2087 if (mi2a
->pEnvironment
) {
2088 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2089 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2090 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2092 if (mi2a
->pDLLName
) {
2093 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2094 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2095 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2098 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2100 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2101 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2102 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2104 HeapFree(GetProcessHeap(), 0, nameW
);
2108 /******************************************************************************
2109 * AddMonitorW [WINSPOOL.@]
2111 * Install a Printmonitor
2114 * pName [I] Servername or NULL (local Computer)
2115 * Level [I] Structure-Level (Must be 2)
2116 * pMonitors [I] PTR to MONITOR_INFO_2
2123 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2126 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2128 monitor_t
* pm
= NULL
;
2129 LPMONITOR_INFO_2W mi2w
;
2135 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2136 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2137 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2138 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2139 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2142 SetLastError(ERROR_INVALID_LEVEL
);
2146 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2151 if (pName
&& (pName
[0])) {
2152 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2153 SetLastError(ERROR_ACCESS_DENIED
);
2158 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2159 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2160 SetLastError(ERROR_INVALID_PARAMETER
);
2163 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2164 WARN("Environment %s requested (we support only %s)\n",
2165 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2166 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2170 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2171 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2172 SetLastError(ERROR_INVALID_PARAMETER
);
2176 /* Load and initialize the monitor. SetLastError() is called on failure */
2177 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2182 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2183 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2187 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2188 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2189 &disposition
) == ERROR_SUCCESS
) {
2191 /* Some installers set options for the port before calling AddMonitor.
2192 We query the "Driver" entry to verify that the monitor is installed,
2193 before we return an error.
2194 When a user installs two print monitors at the same time with the
2195 same name but with a different driver DLL and a task switch comes
2196 between RegQueryValueExW and RegSetValueExW, a race condition
2197 is possible but silently ignored. */
2201 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2202 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2203 &namesize
) == ERROR_SUCCESS
)) {
2204 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2205 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2206 9x: ERROR_ALREADY_EXISTS (183) */
2207 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2212 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2213 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2214 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2216 RegCloseKey(hentry
);
2223 /******************************************************************
2224 * DeletePrinterDriverA [WINSPOOL.@]
2227 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2229 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2232 /******************************************************************
2233 * DeletePrinterDriverW [WINSPOOL.@]
2236 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2238 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2241 /******************************************************************
2242 * DeleteMonitorA [WINSPOOL.@]
2244 * See DeleteMonitorW.
2247 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2249 LPWSTR nameW
= NULL
;
2250 LPWSTR EnvironmentW
= NULL
;
2251 LPWSTR MonitorNameW
= NULL
;
2256 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2257 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2258 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2262 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2263 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2264 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2267 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2268 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2269 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2272 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2274 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2275 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2276 HeapFree(GetProcessHeap(), 0, nameW
);
2280 /******************************************************************
2281 * DeleteMonitorW [WINSPOOL.@]
2283 * Delete a specific Printmonitor from a Printing-Environment
2286 * pName [I] Servername or NULL (local Computer)
2287 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2288 * pMonitorName [I] Name of the Monitor, that should be deleted
2295 * pEnvironment is ignored in Windows for the local Computer.
2299 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2303 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2304 debugstr_w(pMonitorName
));
2306 if (pName
&& (pName
[0])) {
2307 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2308 SetLastError(ERROR_ACCESS_DENIED
);
2312 /* pEnvironment is ignored in Windows for the local Computer */
2314 if (!pMonitorName
|| !pMonitorName
[0]) {
2315 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2316 SetLastError(ERROR_INVALID_PARAMETER
);
2320 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2321 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2325 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2326 if(WINSPOOL_SHDeleteKeyW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2327 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2332 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2335 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2336 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2340 /******************************************************************
2341 * DeletePortA [WINSPOOL.@]
2346 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2348 LPWSTR nameW
= NULL
;
2349 LPWSTR portW
= NULL
;
2353 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2355 /* convert servername to unicode */
2357 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2358 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2359 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2362 /* convert portname to unicode */
2364 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2365 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2366 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2369 res
= DeletePortW(nameW
, hWnd
, portW
);
2370 HeapFree(GetProcessHeap(), 0, nameW
);
2371 HeapFree(GetProcessHeap(), 0, portW
);
2375 /******************************************************************
2376 * DeletePortW [WINSPOOL.@]
2378 * Delete a specific Port
2381 * pName [I] Servername or NULL (local Computer)
2382 * hWnd [I] Handle to parent Window for the Dialog-Box
2383 * pPortName [I] Name of the Port, that should be deleted
2390 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2396 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2398 if (pName
&& pName
[0]) {
2399 SetLastError(ERROR_INVALID_PARAMETER
);
2404 SetLastError(RPC_X_NULL_REF_POINTER
);
2408 /* an empty Portname is Invalid */
2409 if (!pPortName
[0]) {
2410 SetLastError(ERROR_NOT_SUPPORTED
);
2414 pm
= monitor_load_by_port(pPortName
);
2415 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2416 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2417 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2418 TRACE("got %d with %u\n", res
, GetLastError());
2422 pui
= monitor_loadui(pm
);
2423 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2424 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2425 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2426 TRACE("got %d with %u\n", res
, GetLastError());
2430 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2431 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2433 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2434 SetLastError(ERROR_NOT_SUPPORTED
);
2437 monitor_unload(pui
);
2441 TRACE("returning %d with %u\n", res
, GetLastError());
2445 /******************************************************************************
2446 * SetPrinterW [WINSPOOL.@]
2448 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2450 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2451 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2455 /******************************************************************************
2456 * WritePrinter [WINSPOOL.@]
2458 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2460 opened_printer_t
*printer
;
2463 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2465 EnterCriticalSection(&printer_handles_cs
);
2466 printer
= get_opened_printer(hPrinter
);
2469 SetLastError(ERROR_INVALID_HANDLE
);
2475 SetLastError(ERROR_SPL_NO_STARTDOC
);
2479 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2481 LeaveCriticalSection(&printer_handles_cs
);
2485 /*****************************************************************************
2486 * AddFormA [WINSPOOL.@]
2488 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2490 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2494 /*****************************************************************************
2495 * AddFormW [WINSPOOL.@]
2497 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2499 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2503 /*****************************************************************************
2504 * AddJobA [WINSPOOL.@]
2506 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2509 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2513 SetLastError(ERROR_INVALID_LEVEL
);
2517 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2520 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2521 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2522 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2523 if(*pcbNeeded
> cbBuf
) {
2524 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2527 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2528 addjobA
->JobId
= addjobW
->JobId
;
2529 addjobA
->Path
= (char *)(addjobA
+ 1);
2530 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2536 /*****************************************************************************
2537 * AddJobW [WINSPOOL.@]
2539 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2541 opened_printer_t
*printer
;
2544 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2545 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2546 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2548 ADDJOB_INFO_1W
*addjob
;
2550 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2552 EnterCriticalSection(&printer_handles_cs
);
2554 printer
= get_opened_printer(hPrinter
);
2557 SetLastError(ERROR_INVALID_HANDLE
);
2562 SetLastError(ERROR_INVALID_LEVEL
);
2566 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2570 job
->job_id
= InterlockedIncrement(&next_job_id
);
2572 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2573 if(path
[len
- 1] != '\\')
2575 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2576 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2578 len
= strlenW(filename
);
2579 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2580 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2581 job
->document_title
= strdupW(default_doc_title
);
2582 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2584 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2585 if(*pcbNeeded
<= cbBuf
) {
2586 addjob
= (ADDJOB_INFO_1W
*)pData
;
2587 addjob
->JobId
= job
->job_id
;
2588 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2589 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2592 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2595 LeaveCriticalSection(&printer_handles_cs
);
2599 /*****************************************************************************
2600 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2602 * Return the PATH for the Print-Processors
2604 * See GetPrintProcessorDirectoryW.
2608 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2609 DWORD level
, LPBYTE Info
,
2610 DWORD cbBuf
, LPDWORD pcbNeeded
)
2612 LPWSTR serverW
= NULL
;
2617 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2618 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2622 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2623 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2624 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2628 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2629 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2630 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2633 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2634 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2636 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2639 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2640 cbBuf
, NULL
, NULL
) > 0;
2643 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2644 HeapFree(GetProcessHeap(), 0, envW
);
2645 HeapFree(GetProcessHeap(), 0, serverW
);
2649 /*****************************************************************************
2650 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2652 * Return the PATH for the Print-Processors
2655 * server [I] Servername (NT only) or NULL (local Computer)
2656 * env [I] Printing-Environment (see below) or NULL (Default)
2657 * level [I] Structure-Level (must be 1)
2658 * Info [O] PTR to Buffer that receives the Result
2659 * cbBuf [I] Size of Buffer at "Info"
2660 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2661 * required for the Buffer at "Info"
2664 * Success: TRUE and in pcbNeeded the Bytes used in Info
2665 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2666 * if cbBuf is too small
2668 * Native Values returned in Info on Success:
2669 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2670 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2671 *| win9x(Windows 4.0): "%winsysdir%"
2673 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2676 * Only NULL or "" is supported for server
2679 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2680 DWORD level
, LPBYTE Info
,
2681 DWORD cbBuf
, LPDWORD pcbNeeded
)
2684 const printenv_t
* env_t
;
2686 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2687 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2689 if(server
!= NULL
&& server
[0]) {
2690 FIXME("server not supported: %s\n", debugstr_w(server
));
2691 SetLastError(ERROR_INVALID_PARAMETER
);
2695 env_t
= validate_envW(env
);
2696 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2699 WARN("(Level: %d) is ignored in win9x\n", level
);
2700 SetLastError(ERROR_INVALID_LEVEL
);
2704 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2705 needed
= GetSystemDirectoryW(NULL
, 0);
2706 /* add the Size for the Subdirectories */
2707 needed
+= lstrlenW(spoolprtprocsW
);
2708 needed
+= lstrlenW(env_t
->subdir
);
2709 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2711 if(pcbNeeded
) *pcbNeeded
= needed
;
2712 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2713 if (needed
> cbBuf
) {
2714 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2717 if(pcbNeeded
== NULL
) {
2718 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2719 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2720 SetLastError(RPC_X_NULL_REF_POINTER
);
2724 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2725 SetLastError(RPC_X_NULL_REF_POINTER
);
2729 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2730 /* add the Subdirectories */
2731 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2732 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2733 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2737 /*****************************************************************************
2738 * WINSPOOL_OpenDriverReg [internal]
2740 * opens the registry for the printer drivers depending on the given input
2741 * variable pEnvironment
2744 * the opened hkey on success
2747 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2751 const printenv_t
* env
;
2754 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2756 if (!pEnvironment
|| unicode
) {
2757 /* pEnvironment was NULL or an Unicode-String: use it direct */
2758 env
= validate_envW(pEnvironment
);
2762 /* pEnvironment was an ANSI-String: convert to unicode first */
2764 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2765 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2766 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2767 env
= validate_envW(buffer
);
2768 HeapFree(GetProcessHeap(), 0, buffer
);
2770 if (!env
) return NULL
;
2772 buffer
= HeapAlloc( GetProcessHeap(), 0,
2773 (strlenW(DriversW
) + strlenW(env
->envname
) +
2774 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2776 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2777 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2778 HeapFree(GetProcessHeap(), 0, buffer
);
2783 /*****************************************************************************
2784 * AddPrinterW [WINSPOOL.@]
2786 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2788 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2792 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2794 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2795 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2796 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2797 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2798 statusW
[] = {'S','t','a','t','u','s',0},
2799 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2801 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2804 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2805 SetLastError(ERROR_INVALID_PARAMETER
);
2809 ERR("Level = %d, unsupported!\n", Level
);
2810 SetLastError(ERROR_INVALID_LEVEL
);
2814 SetLastError(ERROR_INVALID_PARAMETER
);
2817 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2819 ERR("Can't create Printers key\n");
2822 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2823 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2824 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2825 RegCloseKey(hkeyPrinter
);
2826 RegCloseKey(hkeyPrinters
);
2829 RegCloseKey(hkeyPrinter
);
2831 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2833 ERR("Can't create Drivers key\n");
2834 RegCloseKey(hkeyPrinters
);
2837 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2839 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2840 RegCloseKey(hkeyPrinters
);
2841 RegCloseKey(hkeyDrivers
);
2842 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2845 RegCloseKey(hkeyDriver
);
2846 RegCloseKey(hkeyDrivers
);
2848 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2849 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2850 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2851 RegCloseKey(hkeyPrinters
);
2855 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2857 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2858 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2859 RegCloseKey(hkeyPrinters
);
2862 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2863 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2864 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2866 /* See if we can load the driver. We may need the devmode structure anyway
2869 * Note that DocumentPropertiesW will briefly try to open the printer we
2870 * just create to find a DEVMODEA struct (it will use the WINEPS default
2871 * one in case it is not there, so we are ok).
2873 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2876 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2877 size
= sizeof(DEVMODEW
);
2883 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2885 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2887 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2888 HeapFree(GetProcessHeap(),0,dmW
);
2893 /* set devmode to printer name */
2894 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2898 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2899 and we support these drivers. NT writes DEVMODEW so somehow
2900 we'll need to distinguish between these when we support NT
2904 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2905 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2906 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2907 HeapFree(GetProcessHeap(), 0, dmA
);
2909 HeapFree(GetProcessHeap(), 0, dmW
);
2911 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2912 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2913 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2914 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2916 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2917 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2918 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2919 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2920 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2921 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2922 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2923 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2924 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2925 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2926 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2927 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2928 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2930 RegCloseKey(hkeyPrinter
);
2931 RegCloseKey(hkeyPrinters
);
2932 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2933 ERR("OpenPrinter failing\n");
2939 /*****************************************************************************
2940 * AddPrinterA [WINSPOOL.@]
2942 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2944 UNICODE_STRING pNameW
;
2946 PRINTER_INFO_2W
*piW
;
2947 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2950 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2952 ERR("Level = %d, unsupported!\n", Level
);
2953 SetLastError(ERROR_INVALID_LEVEL
);
2956 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2957 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2959 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2961 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2962 RtlFreeUnicodeString(&pNameW
);
2967 /*****************************************************************************
2968 * ClosePrinter [WINSPOOL.@]
2970 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2972 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2973 opened_printer_t
*printer
= NULL
;
2976 TRACE("(%p)\n", hPrinter
);
2978 EnterCriticalSection(&printer_handles_cs
);
2980 if ((i
> 0) && (i
<= nb_printer_handles
))
2981 printer
= printer_handles
[i
- 1];
2986 struct list
*cursor
, *cursor2
;
2988 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2989 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2990 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2993 EndDocPrinter(hPrinter
);
2995 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2997 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2999 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3000 ScheduleJob(hPrinter
, job
->job_id
);
3002 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3004 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
3005 monitor_unload(printer
->pm
);
3006 HeapFree(GetProcessHeap(), 0, printer
->printername
);
3007 HeapFree(GetProcessHeap(), 0, printer
->name
);
3008 HeapFree(GetProcessHeap(), 0, printer
);
3009 printer_handles
[i
- 1] = NULL
;
3012 LeaveCriticalSection(&printer_handles_cs
);
3016 /*****************************************************************************
3017 * DeleteFormA [WINSPOOL.@]
3019 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3021 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3025 /*****************************************************************************
3026 * DeleteFormW [WINSPOOL.@]
3028 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3030 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3034 /*****************************************************************************
3035 * DeletePrinter [WINSPOOL.@]
3037 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3039 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3040 HKEY hkeyPrinters
, hkey
;
3043 SetLastError(ERROR_INVALID_HANDLE
);
3046 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3047 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
3048 RegCloseKey(hkeyPrinters
);
3050 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3051 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3052 RegDeleteValueW(hkey
, lpNameW
);
3058 /*****************************************************************************
3059 * SetPrinterA [WINSPOOL.@]
3061 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3064 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3068 /*****************************************************************************
3069 * SetJobA [WINSPOOL.@]
3071 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3072 LPBYTE pJob
, DWORD Command
)
3076 UNICODE_STRING usBuffer
;
3078 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3080 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3081 are all ignored by SetJob, so we don't bother copying them */
3089 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3090 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3092 JobW
= (LPBYTE
)info1W
;
3093 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3094 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3095 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3096 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3097 info1W
->Status
= info1A
->Status
;
3098 info1W
->Priority
= info1A
->Priority
;
3099 info1W
->Position
= info1A
->Position
;
3100 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3105 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3106 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3108 JobW
= (LPBYTE
)info2W
;
3109 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3110 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3111 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3112 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3113 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3114 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3115 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3116 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3117 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3118 info2W
->Status
= info2A
->Status
;
3119 info2W
->Priority
= info2A
->Priority
;
3120 info2W
->Position
= info2A
->Position
;
3121 info2W
->StartTime
= info2A
->StartTime
;
3122 info2W
->UntilTime
= info2A
->UntilTime
;
3123 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3127 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3128 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3131 SetLastError(ERROR_INVALID_LEVEL
);
3135 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3141 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3142 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3143 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3144 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3145 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3150 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3151 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3152 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3153 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3154 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3155 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3156 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3157 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3158 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3162 HeapFree(GetProcessHeap(), 0, JobW
);
3167 /*****************************************************************************
3168 * SetJobW [WINSPOOL.@]
3170 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3171 LPBYTE pJob
, DWORD Command
)
3176 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3177 FIXME("Ignoring everything other than document title\n");
3179 EnterCriticalSection(&printer_handles_cs
);
3180 job
= get_job(hPrinter
, JobId
);
3190 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3191 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3192 job
->document_title
= strdupW(info1
->pDocument
);
3197 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3198 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3199 job
->document_title
= strdupW(info2
->pDocument
);
3205 SetLastError(ERROR_INVALID_LEVEL
);
3210 LeaveCriticalSection(&printer_handles_cs
);
3214 /*****************************************************************************
3215 * EndDocPrinter [WINSPOOL.@]
3217 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3219 opened_printer_t
*printer
;
3221 TRACE("(%p)\n", hPrinter
);
3223 EnterCriticalSection(&printer_handles_cs
);
3225 printer
= get_opened_printer(hPrinter
);
3228 SetLastError(ERROR_INVALID_HANDLE
);
3234 SetLastError(ERROR_SPL_NO_STARTDOC
);
3238 CloseHandle(printer
->doc
->hf
);
3239 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3240 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3241 printer
->doc
= NULL
;
3244 LeaveCriticalSection(&printer_handles_cs
);
3248 /*****************************************************************************
3249 * EndPagePrinter [WINSPOOL.@]
3251 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3253 FIXME("(%p): stub\n", hPrinter
);
3257 /*****************************************************************************
3258 * StartDocPrinterA [WINSPOOL.@]
3260 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3262 UNICODE_STRING usBuffer
;
3264 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3267 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3268 or one (DOC_INFO_3) extra DWORDs */
3272 doc2W
.JobId
= doc2
->JobId
;
3275 doc2W
.dwMode
= doc2
->dwMode
;
3278 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3279 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3280 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3284 SetLastError(ERROR_INVALID_LEVEL
);
3288 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3290 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3291 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3292 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3297 /*****************************************************************************
3298 * StartDocPrinterW [WINSPOOL.@]
3300 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3302 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3303 opened_printer_t
*printer
;
3304 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3305 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3306 JOB_INFO_1W job_info
;
3307 DWORD needed
, ret
= 0;
3311 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3312 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3313 debugstr_w(doc
->pDatatype
));
3315 if(Level
< 1 || Level
> 3)
3317 SetLastError(ERROR_INVALID_LEVEL
);
3321 EnterCriticalSection(&printer_handles_cs
);
3322 printer
= get_opened_printer(hPrinter
);
3325 SetLastError(ERROR_INVALID_HANDLE
);
3331 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3335 /* Even if we're printing to a file we still add a print job, we'll
3336 just ignore the spool file name */
3338 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3340 ERR("AddJob failed gle %u\n", GetLastError());
3344 if(doc
->pOutputFile
)
3345 filename
= doc
->pOutputFile
;
3347 filename
= addjob
->Path
;
3349 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3350 if(hf
== INVALID_HANDLE_VALUE
)
3353 memset(&job_info
, 0, sizeof(job_info
));
3354 job_info
.pDocument
= doc
->pDocName
;
3355 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3357 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3358 printer
->doc
->hf
= hf
;
3359 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3361 LeaveCriticalSection(&printer_handles_cs
);
3366 /*****************************************************************************
3367 * StartPagePrinter [WINSPOOL.@]
3369 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3371 FIXME("(%p): stub\n", hPrinter
);
3375 /*****************************************************************************
3376 * GetFormA [WINSPOOL.@]
3378 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3379 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3381 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3382 Level
,pForm
,cbBuf
,pcbNeeded
);
3386 /*****************************************************************************
3387 * GetFormW [WINSPOOL.@]
3389 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3390 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3392 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3393 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3397 /*****************************************************************************
3398 * SetFormA [WINSPOOL.@]
3400 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3403 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3407 /*****************************************************************************
3408 * SetFormW [WINSPOOL.@]
3410 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3413 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3417 /*****************************************************************************
3418 * ReadPrinter [WINSPOOL.@]
3420 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3421 LPDWORD pNoBytesRead
)
3423 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3427 /*****************************************************************************
3428 * ResetPrinterA [WINSPOOL.@]
3430 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3432 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3436 /*****************************************************************************
3437 * ResetPrinterW [WINSPOOL.@]
3439 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3441 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3445 /*****************************************************************************
3446 * WINSPOOL_GetDWORDFromReg
3448 * Return DWORD associated with ValueName from hkey.
3450 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3452 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3455 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3457 if(ret
!= ERROR_SUCCESS
) {
3458 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3461 if(type
!= REG_DWORD
) {
3462 ERR("Got type %d\n", type
);
3468 /*****************************************************************************
3469 * WINSPOOL_GetStringFromReg
3471 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3472 * String is stored either as unicode or ascii.
3473 * Bit of a hack here to get the ValueName if we want ascii.
3475 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3476 DWORD buflen
, DWORD
*needed
,
3479 DWORD sz
= buflen
, type
;
3483 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3485 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3486 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3487 HeapFree(GetProcessHeap(),0,ValueNameA
);
3489 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3490 WARN("Got ret = %d\n", ret
);
3494 /* add space for terminating '\0' */
3495 sz
+= unicode
? sizeof(WCHAR
) : 1;
3499 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3504 /*****************************************************************************
3505 * WINSPOOL_GetDefaultDevMode
3507 * Get a default DevMode values for wineps.
3511 static void WINSPOOL_GetDefaultDevMode(
3513 DWORD buflen
, DWORD
*needed
,
3517 static const char szwps
[] = "wineps.drv";
3519 /* fill default DEVMODE - should be read from ppd... */
3520 ZeroMemory( &dm
, sizeof(dm
) );
3521 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3522 dm
.dmSpecVersion
= DM_SPECVERSION
;
3523 dm
.dmDriverVersion
= 1;
3524 dm
.dmSize
= sizeof(DEVMODEA
);
3525 dm
.dmDriverExtra
= 0;
3527 DM_ORIENTATION
| DM_PAPERSIZE
|
3528 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3531 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3532 DM_YRESOLUTION
| DM_TTOPTION
;
3534 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3535 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3536 dm
.u1
.s1
.dmPaperLength
= 2970;
3537 dm
.u1
.s1
.dmPaperWidth
= 2100;
3541 dm
.dmDefaultSource
= DMBIN_AUTO
;
3542 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3545 dm
.dmYResolution
= 300; /* 300dpi */
3546 dm
.dmTTOption
= DMTT_BITMAP
;
3549 /* dm.dmLogPixels */
3550 /* dm.dmBitsPerPel */
3551 /* dm.dmPelsWidth */
3552 /* dm.dmPelsHeight */
3553 /* dm.dmDisplayFlags */
3554 /* dm.dmDisplayFrequency */
3555 /* dm.dmICMMethod */
3556 /* dm.dmICMIntent */
3557 /* dm.dmMediaType */
3558 /* dm.dmDitherType */
3559 /* dm.dmReserved1 */
3560 /* dm.dmReserved2 */
3561 /* dm.dmPanningWidth */
3562 /* dm.dmPanningHeight */
3565 if(buflen
>= sizeof(DEVMODEW
)) {
3566 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3567 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3568 HeapFree(GetProcessHeap(),0,pdmW
);
3570 *needed
= sizeof(DEVMODEW
);
3574 if(buflen
>= sizeof(DEVMODEA
)) {
3575 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3577 *needed
= sizeof(DEVMODEA
);
3581 /*****************************************************************************
3582 * WINSPOOL_GetDevModeFromReg
3584 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3585 * DevMode is stored either as unicode or ascii.
3587 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3589 DWORD buflen
, DWORD
*needed
,
3592 DWORD sz
= buflen
, type
;
3595 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3596 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3597 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3598 if (sz
< sizeof(DEVMODEA
))
3600 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3603 /* ensures that dmSize is not erratically bogus if registry is invalid */
3604 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3605 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3607 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3609 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3610 memcpy(ptr
, dmW
, sz
);
3611 HeapFree(GetProcessHeap(),0,dmW
);
3618 /*********************************************************************
3619 * WINSPOOL_GetPrinter_1
3621 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3622 * The strings are either stored as unicode or ascii.
3624 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3625 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3628 DWORD size
, left
= cbBuf
;
3629 BOOL space
= (cbBuf
> 0);
3634 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3636 if(space
&& size
<= left
) {
3637 pi1
->pName
= (LPWSTR
)ptr
;
3645 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3646 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3648 if(space
&& size
<= left
) {
3649 pi1
->pDescription
= (LPWSTR
)ptr
;
3657 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3659 if(space
&& size
<= left
) {
3660 pi1
->pComment
= (LPWSTR
)ptr
;
3668 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3670 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3671 memset(pi1
, 0, sizeof(*pi1
));
3675 /*********************************************************************
3676 * WINSPOOL_GetPrinter_2
3678 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3679 * The strings are either stored as unicode or ascii.
3681 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3682 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3685 DWORD size
, left
= cbBuf
;
3686 BOOL space
= (cbBuf
> 0);
3691 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3693 if(space
&& size
<= left
) {
3694 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3701 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3703 if(space
&& size
<= left
) {
3704 pi2
->pShareName
= (LPWSTR
)ptr
;
3711 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3713 if(space
&& size
<= left
) {
3714 pi2
->pPortName
= (LPWSTR
)ptr
;
3721 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3723 if(space
&& size
<= left
) {
3724 pi2
->pDriverName
= (LPWSTR
)ptr
;
3731 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3733 if(space
&& size
<= left
) {
3734 pi2
->pComment
= (LPWSTR
)ptr
;
3741 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3743 if(space
&& size
<= left
) {
3744 pi2
->pLocation
= (LPWSTR
)ptr
;
3751 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3753 if(space
&& size
<= left
) {
3754 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3763 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3764 if(space
&& size
<= left
) {
3765 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3772 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3774 if(space
&& size
<= left
) {
3775 pi2
->pSepFile
= (LPWSTR
)ptr
;
3782 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3784 if(space
&& size
<= left
) {
3785 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3794 if(space
&& size
<= left
) {
3795 pi2
->pDatatype
= (LPWSTR
)ptr
;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3804 if(space
&& size
<= left
) {
3805 pi2
->pParameters
= (LPWSTR
)ptr
;
3813 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3814 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3815 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3816 "Default Priority");
3817 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3818 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3821 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3822 memset(pi2
, 0, sizeof(*pi2
));
3827 /*********************************************************************
3828 * WINSPOOL_GetPrinter_4
3830 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3832 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3833 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3836 DWORD size
, left
= cbBuf
;
3837 BOOL space
= (cbBuf
> 0);
3842 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3844 if(space
&& size
<= left
) {
3845 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3853 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3856 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3857 memset(pi4
, 0, sizeof(*pi4
));
3862 /*********************************************************************
3863 * WINSPOOL_GetPrinter_5
3865 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3867 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3868 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3871 DWORD size
, left
= cbBuf
;
3872 BOOL space
= (cbBuf
> 0);
3877 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3879 if(space
&& size
<= left
) {
3880 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3887 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3889 if(space
&& size
<= left
) {
3890 pi5
->pPortName
= (LPWSTR
)ptr
;
3898 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3899 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3901 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3905 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3906 memset(pi5
, 0, sizeof(*pi5
));
3911 /*****************************************************************************
3912 * WINSPOOL_GetPrinter
3914 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3915 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3916 * just a collection of pointers to strings.
3918 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3919 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3922 DWORD size
, needed
= 0;
3924 HKEY hkeyPrinter
, hkeyPrinters
;
3927 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3929 if (!(name
= get_opened_printer_name(hPrinter
))) {
3930 SetLastError(ERROR_INVALID_HANDLE
);
3934 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3936 ERR("Can't create Printers key\n");
3939 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3941 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3942 RegCloseKey(hkeyPrinters
);
3943 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3950 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3952 size
= sizeof(PRINTER_INFO_2W
);
3954 ptr
= pPrinter
+ size
;
3956 memset(pPrinter
, 0, size
);
3961 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3969 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3971 size
= sizeof(PRINTER_INFO_4W
);
3973 ptr
= pPrinter
+ size
;
3975 memset(pPrinter
, 0, size
);
3980 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3989 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3991 size
= sizeof(PRINTER_INFO_5W
);
3993 ptr
= pPrinter
+ size
;
3995 memset(pPrinter
, 0, size
);
4001 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4008 FIXME("Unimplemented level %d\n", Level
);
4009 SetLastError(ERROR_INVALID_LEVEL
);
4010 RegCloseKey(hkeyPrinters
);
4011 RegCloseKey(hkeyPrinter
);
4015 RegCloseKey(hkeyPrinter
);
4016 RegCloseKey(hkeyPrinters
);
4018 TRACE("returning %d needed = %d\n", ret
, needed
);
4019 if(pcbNeeded
) *pcbNeeded
= needed
;
4021 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4025 /*****************************************************************************
4026 * GetPrinterW [WINSPOOL.@]
4028 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4029 DWORD cbBuf
, LPDWORD pcbNeeded
)
4031 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4035 /*****************************************************************************
4036 * GetPrinterA [WINSPOOL.@]
4038 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4039 DWORD cbBuf
, LPDWORD pcbNeeded
)
4041 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4045 /*****************************************************************************
4046 * WINSPOOL_EnumPrinters
4048 * Implementation of EnumPrintersA|W
4050 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4051 DWORD dwLevel
, LPBYTE lpbPrinters
,
4052 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4053 LPDWORD lpdwReturned
, BOOL unicode
)
4056 HKEY hkeyPrinters
, hkeyPrinter
;
4057 WCHAR PrinterName
[255];
4058 DWORD needed
= 0, number
= 0;
4059 DWORD used
, i
, left
;
4063 memset(lpbPrinters
, 0, cbBuf
);
4069 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4070 if(dwType
== PRINTER_ENUM_DEFAULT
)
4073 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4074 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4075 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4077 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4085 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4086 FIXME("dwType = %08x\n", dwType
);
4087 SetLastError(ERROR_INVALID_FLAGS
);
4091 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4093 ERR("Can't create Printers key\n");
4097 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4098 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4099 RegCloseKey(hkeyPrinters
);
4100 ERR("Can't query Printers key\n");
4103 TRACE("Found %d printers\n", number
);
4107 used
= number
* sizeof(PRINTER_INFO_1W
);
4110 used
= number
* sizeof(PRINTER_INFO_2W
);
4113 used
= number
* sizeof(PRINTER_INFO_4W
);
4116 used
= number
* sizeof(PRINTER_INFO_5W
);
4120 SetLastError(ERROR_INVALID_LEVEL
);
4121 RegCloseKey(hkeyPrinters
);
4124 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4126 for(i
= 0; i
< number
; i
++) {
4127 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4129 ERR("Can't enum key number %d\n", i
);
4130 RegCloseKey(hkeyPrinters
);
4133 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4134 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4136 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4137 RegCloseKey(hkeyPrinters
);
4142 buf
= lpbPrinters
+ used
;
4143 left
= cbBuf
- used
;
4151 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4152 left
, &needed
, unicode
);
4154 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4157 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4158 left
, &needed
, unicode
);
4160 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4163 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4164 left
, &needed
, unicode
);
4166 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4169 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4170 left
, &needed
, unicode
);
4172 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4175 ERR("Shouldn't be here!\n");
4176 RegCloseKey(hkeyPrinter
);
4177 RegCloseKey(hkeyPrinters
);
4180 RegCloseKey(hkeyPrinter
);
4182 RegCloseKey(hkeyPrinters
);
4189 memset(lpbPrinters
, 0, cbBuf
);
4190 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4194 *lpdwReturned
= number
;
4195 SetLastError(ERROR_SUCCESS
);
4200 /******************************************************************
4201 * EnumPrintersW [WINSPOOL.@]
4203 * Enumerates the available printers, print servers and print
4204 * providers, depending on the specified flags, name and level.
4208 * If level is set to 1:
4209 * Returns an array of PRINTER_INFO_1 data structures in the
4210 * lpbPrinters buffer.
4212 * If level is set to 2:
4213 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4214 * Returns an array of PRINTER_INFO_2 data structures in the
4215 * lpbPrinters buffer. Note that according to MSDN also an
4216 * OpenPrinter should be performed on every remote printer.
4218 * If level is set to 4 (officially WinNT only):
4219 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4220 * Fast: Only the registry is queried to retrieve printer names,
4221 * no connection to the driver is made.
4222 * Returns an array of PRINTER_INFO_4 data structures in the
4223 * lpbPrinters buffer.
4225 * If level is set to 5 (officially WinNT4/Win9x only):
4226 * Fast: Only the registry is queried to retrieve printer names,
4227 * no connection to the driver is made.
4228 * Returns an array of PRINTER_INFO_5 data structures in the
4229 * lpbPrinters buffer.
4231 * If level set to 3 or 6+:
4232 * returns zero (failure!)
4234 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4238 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4239 * - Only levels 2, 4 and 5 are implemented at the moment.
4240 * - 16-bit printer drivers are not enumerated.
4241 * - Returned amount of bytes used/needed does not match the real Windoze
4242 * implementation (as in this implementation, all strings are part
4243 * of the buffer, whereas Win32 keeps them somewhere else)
4244 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4247 * - In a regular Wine installation, no registry settings for printers
4248 * exist, which makes this function return an empty list.
4250 BOOL WINAPI
EnumPrintersW(
4251 DWORD dwType
, /* [in] Types of print objects to enumerate */
4252 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4253 DWORD dwLevel
, /* [in] type of printer info structure */
4254 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4255 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4256 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4257 LPDWORD lpdwReturned
/* [out] number of entries returned */
4260 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4261 lpdwNeeded
, lpdwReturned
, TRUE
);
4264 /******************************************************************
4265 * EnumPrintersA [WINSPOOL.@]
4268 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4269 DWORD dwLevel
, LPBYTE lpbPrinters
,
4270 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4271 LPDWORD lpdwReturned
)
4273 BOOL ret
, unicode
= FALSE
;
4274 UNICODE_STRING lpszNameW
;
4277 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4278 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4279 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4280 lpdwNeeded
, lpdwReturned
, unicode
);
4281 RtlFreeUnicodeString(&lpszNameW
);
4285 /*****************************************************************************
4286 * WINSPOOL_GetDriverInfoFromReg [internal]
4288 * Enters the information from the registry into the DRIVER_INFO struct
4291 * zero if the printer driver does not exist in the registry
4292 * (only if Level > 1) otherwise nonzero
4294 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4297 LPCWSTR pEnvironment
,
4299 LPBYTE ptr
, /* DRIVER_INFO */
4300 LPBYTE pDriverStrings
, /* strings buffer */
4301 DWORD cbBuf
, /* size of string buffer */
4302 LPDWORD pcbNeeded
, /* space needed for str. */
4303 BOOL unicode
) /* type of strings */
4307 LPBYTE strPtr
= pDriverStrings
;
4309 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4310 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
4311 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
4314 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4315 if (*pcbNeeded
<= cbBuf
)
4316 strcpyW((LPWSTR
)strPtr
, DriverName
);
4318 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
4320 if(*pcbNeeded
<= cbBuf
)
4321 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
4322 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4326 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4330 ((PDRIVER_INFO_2W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4331 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4334 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4335 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4336 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4341 ((PDRIVER_INFO_2A
) ptr
)->cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4344 pEnvironment
= DefaultEnvironmentW
;
4346 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
4348 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
4351 if(*pcbNeeded
<= cbBuf
) {
4353 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
4355 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
4356 (LPSTR
)strPtr
, size
, NULL
, NULL
);
4358 ((PDRIVER_INFO_2W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
4359 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4362 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
4365 if(*pcbNeeded
<= cbBuf
)
4366 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
4369 ((PDRIVER_INFO_2W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
4370 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4373 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
4376 if(*pcbNeeded
<= cbBuf
)
4377 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
4380 ((PDRIVER_INFO_2W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
4381 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4384 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4385 0, &size
, unicode
)) {
4387 if(*pcbNeeded
<= cbBuf
)
4388 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4389 size
, &tmp
, unicode
);
4391 ((PDRIVER_INFO_2W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
4392 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4396 RegCloseKey(hkeyDriver
);
4397 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4401 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
4404 if(*pcbNeeded
<= cbBuf
)
4405 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
4406 size
, &tmp
, unicode
);
4408 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
4409 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4412 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
4415 if(*pcbNeeded
<= cbBuf
)
4416 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
4417 size
, &tmp
, unicode
);
4419 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
4420 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4423 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
4426 if(*pcbNeeded
<= cbBuf
)
4427 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
4428 size
, &tmp
, unicode
);
4430 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
4431 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4434 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
4437 if(*pcbNeeded
<= cbBuf
)
4438 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
4439 size
, &tmp
, unicode
);
4441 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
4442 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4445 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4446 RegCloseKey(hkeyDriver
);
4450 /*****************************************************************************
4451 * WINSPOOL_GetPrinterDriver
4453 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4454 DWORD Level
, LPBYTE pDriverInfo
,
4455 DWORD cbBuf
, LPDWORD pcbNeeded
,
4459 WCHAR DriverName
[100];
4460 DWORD ret
, type
, size
, needed
= 0;
4462 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4464 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4465 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4467 ZeroMemory(pDriverInfo
, cbBuf
);
4469 if (!(name
= get_opened_printer_name(hPrinter
))) {
4470 SetLastError(ERROR_INVALID_HANDLE
);
4473 if(Level
< 1 || Level
> 6) {
4474 SetLastError(ERROR_INVALID_LEVEL
);
4477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4479 ERR("Can't create Printers key\n");
4482 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4484 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4485 RegCloseKey(hkeyPrinters
);
4486 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4489 size
= sizeof(DriverName
);
4491 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4492 (LPBYTE
)DriverName
, &size
);
4493 RegCloseKey(hkeyPrinter
);
4494 RegCloseKey(hkeyPrinters
);
4495 if(ret
!= ERROR_SUCCESS
) {
4496 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4500 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4502 ERR("Can't create Drivers key\n");
4508 size
= sizeof(DRIVER_INFO_1W
);
4511 size
= sizeof(DRIVER_INFO_2W
);
4514 size
= sizeof(DRIVER_INFO_3W
);
4517 size
= sizeof(DRIVER_INFO_4W
);
4520 size
= sizeof(DRIVER_INFO_5W
);
4523 size
= sizeof(DRIVER_INFO_6W
);
4526 ERR("Invalid level\n");
4531 ptr
= pDriverInfo
+ size
;
4533 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4534 pEnvironment
, Level
, pDriverInfo
,
4535 (cbBuf
< size
) ? NULL
: ptr
,
4536 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4537 &needed
, unicode
)) {
4538 RegCloseKey(hkeyDrivers
);
4542 RegCloseKey(hkeyDrivers
);
4544 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4545 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4546 if(cbBuf
>= needed
) return TRUE
;
4547 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4551 /*****************************************************************************
4552 * GetPrinterDriverA [WINSPOOL.@]
4554 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4555 DWORD Level
, LPBYTE pDriverInfo
,
4556 DWORD cbBuf
, LPDWORD pcbNeeded
)
4559 UNICODE_STRING pEnvW
;
4562 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4563 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4564 cbBuf
, pcbNeeded
, FALSE
);
4565 RtlFreeUnicodeString(&pEnvW
);
4568 /*****************************************************************************
4569 * GetPrinterDriverW [WINSPOOL.@]
4571 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4572 DWORD Level
, LPBYTE pDriverInfo
,
4573 DWORD cbBuf
, LPDWORD pcbNeeded
)
4575 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4576 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4579 /*****************************************************************************
4580 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4582 * Return the PATH for the Printer-Drivers (UNICODE)
4585 * pName [I] Servername (NT only) or NULL (local Computer)
4586 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4587 * Level [I] Structure-Level (must be 1)
4588 * pDriverDirectory [O] PTR to Buffer that receives the Result
4589 * cbBuf [I] Size of Buffer at pDriverDirectory
4590 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4591 * required for pDriverDirectory
4594 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4595 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4596 * if cbBuf is too small
4598 * Native Values returned in pDriverDirectory on Success:
4599 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4600 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4601 *| win9x(Windows 4.0): "%winsysdir%"
4603 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4606 *- Only NULL or "" is supported for pName
4609 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4610 DWORD Level
, LPBYTE pDriverDirectory
,
4611 DWORD cbBuf
, LPDWORD pcbNeeded
)
4614 const printenv_t
* env
;
4616 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4617 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4618 if(pName
!= NULL
&& pName
[0]) {
4619 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4620 SetLastError(ERROR_INVALID_PARAMETER
);
4624 env
= validate_envW(pEnvironment
);
4625 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4628 WARN("(Level: %d) is ignored in win9x\n", Level
);
4629 SetLastError(ERROR_INVALID_LEVEL
);
4633 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4634 needed
= GetSystemDirectoryW(NULL
, 0);
4635 /* add the Size for the Subdirectories */
4636 needed
+= lstrlenW(spooldriversW
);
4637 needed
+= lstrlenW(env
->subdir
);
4638 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4641 *pcbNeeded
= needed
;
4642 TRACE("required: 0x%x/%d\n", needed
, needed
);
4643 if(needed
> cbBuf
) {
4644 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4647 if(pcbNeeded
== NULL
) {
4648 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4649 SetLastError(RPC_X_NULL_REF_POINTER
);
4652 if(pDriverDirectory
== NULL
) {
4653 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4654 SetLastError(ERROR_INVALID_USER_BUFFER
);
4658 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4659 /* add the Subdirectories */
4660 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4661 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4662 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4667 /*****************************************************************************
4668 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4670 * Return the PATH for the Printer-Drivers (ANSI)
4672 * See GetPrinterDriverDirectoryW.
4675 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4678 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4679 DWORD Level
, LPBYTE pDriverDirectory
,
4680 DWORD cbBuf
, LPDWORD pcbNeeded
)
4682 UNICODE_STRING nameW
, environmentW
;
4685 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4686 WCHAR
*driverDirectoryW
= NULL
;
4688 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4689 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4691 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4693 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4694 else nameW
.Buffer
= NULL
;
4695 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4696 else environmentW
.Buffer
= NULL
;
4698 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4699 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4702 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4703 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4705 *pcbNeeded
= needed
;
4706 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4708 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4710 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4712 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4713 RtlFreeUnicodeString(&environmentW
);
4714 RtlFreeUnicodeString(&nameW
);
4719 /*****************************************************************************
4720 * AddPrinterDriverA [WINSPOOL.@]
4722 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4725 HKEY hkeyDrivers
, hkeyName
;
4726 static CHAR empty
[] = "",
4729 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4731 if(level
!= 2 && level
!= 3) {
4732 SetLastError(ERROR_INVALID_LEVEL
);
4735 if ((pName
) && (pName
[0])) {
4736 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4737 SetLastError(ERROR_INVALID_PARAMETER
);
4741 WARN("pDriverInfo == NULL\n");
4742 SetLastError(ERROR_INVALID_PARAMETER
);
4747 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4749 memset(&di3
, 0, sizeof(di3
));
4750 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4753 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4755 SetLastError(ERROR_INVALID_PARAMETER
);
4759 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4760 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4761 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4762 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4764 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4767 ERR("Can't create Drivers key\n");
4771 if(level
== 2) { /* apparently can't overwrite with level2 */
4772 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4773 RegCloseKey(hkeyName
);
4774 RegCloseKey(hkeyDrivers
);
4775 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4776 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4780 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4781 RegCloseKey(hkeyDrivers
);
4782 ERR("Can't create Name key\n");
4785 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4786 lstrlenA(di3
.pConfigFile
) + 1);
4787 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4788 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4789 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4791 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4792 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4793 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4794 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4795 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4796 RegCloseKey(hkeyName
);
4797 RegCloseKey(hkeyDrivers
);
4802 /*****************************************************************************
4803 * AddPrinterDriverW [WINSPOOL.@]
4805 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4808 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4813 /*****************************************************************************
4814 * AddPrintProcessorA [WINSPOOL.@]
4816 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4817 LPSTR pPrintProcessorName
)
4819 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4820 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4824 /*****************************************************************************
4825 * AddPrintProcessorW [WINSPOOL.@]
4827 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4828 LPWSTR pPrintProcessorName
)
4830 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4831 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4835 /*****************************************************************************
4836 * AddPrintProvidorA [WINSPOOL.@]
4838 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4840 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4844 /*****************************************************************************
4845 * AddPrintProvidorW [WINSPOOL.@]
4847 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4849 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4853 /*****************************************************************************
4854 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4856 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4857 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4859 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4860 pDevModeOutput
, pDevModeInput
);
4864 /*****************************************************************************
4865 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4867 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4868 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4870 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4871 pDevModeOutput
, pDevModeInput
);
4875 /*****************************************************************************
4876 * PrinterProperties [WINSPOOL.@]
4878 * Displays a dialog to set the properties of the printer.
4881 * nonzero on success or zero on failure
4884 * implemented as stub only
4886 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4887 HANDLE hPrinter
/* [in] handle to printer object */
4889 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4890 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4894 /*****************************************************************************
4895 * EnumJobsA [WINSPOOL.@]
4898 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4899 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4902 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4903 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4905 if(pcbNeeded
) *pcbNeeded
= 0;
4906 if(pcReturned
) *pcReturned
= 0;
4911 /*****************************************************************************
4912 * EnumJobsW [WINSPOOL.@]
4915 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4916 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4919 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4920 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4922 if(pcbNeeded
) *pcbNeeded
= 0;
4923 if(pcReturned
) *pcReturned
= 0;
4927 /*****************************************************************************
4928 * WINSPOOL_EnumPrinterDrivers [internal]
4930 * Delivers information about all printer drivers installed on the
4931 * localhost or a given server
4934 * nonzero on success or zero on failure. If the buffer for the returned
4935 * information is too small the function will return an error
4938 * - only implemented for localhost, foreign hosts will return an error
4940 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4941 DWORD Level
, LPBYTE pDriverInfo
,
4942 DWORD cbBuf
, LPDWORD pcbNeeded
,
4943 LPDWORD pcReturned
, BOOL unicode
)
4946 DWORD i
, needed
, number
= 0, size
= 0;
4947 WCHAR DriverNameW
[255];
4950 TRACE("%s,%s,%d,%p,%d,%d\n",
4951 debugstr_w(pName
), debugstr_w(pEnvironment
),
4952 Level
, pDriverInfo
, cbBuf
, unicode
);
4954 /* check for local drivers */
4955 if((pName
) && (pName
[0])) {
4956 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4957 SetLastError(ERROR_ACCESS_DENIED
);
4961 /* check input parameter */
4962 if((Level
< 1) || (Level
> 3)) {
4963 ERR("unsupported level %d\n", Level
);
4964 SetLastError(ERROR_INVALID_LEVEL
);
4968 /* initialize return values */
4970 memset( pDriverInfo
, 0, cbBuf
);
4974 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4976 ERR("Can't open Drivers key\n");
4980 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4981 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4982 RegCloseKey(hkeyDrivers
);
4983 ERR("Can't query Drivers key\n");
4986 TRACE("Found %d Drivers\n", number
);
4988 /* get size of single struct
4989 * unicode and ascii structure have the same size
4993 size
= sizeof(DRIVER_INFO_1A
);
4996 size
= sizeof(DRIVER_INFO_2A
);
4999 size
= sizeof(DRIVER_INFO_3A
);
5003 /* calculate required buffer size */
5004 *pcbNeeded
= size
* number
;
5006 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5008 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5009 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
5011 ERR("Can't enum key number %d\n", i
);
5012 RegCloseKey(hkeyDrivers
);
5015 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5016 pEnvironment
, Level
, ptr
,
5017 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5018 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5019 &needed
, unicode
)) {
5020 RegCloseKey(hkeyDrivers
);
5023 (*pcbNeeded
) += needed
;
5026 RegCloseKey(hkeyDrivers
);
5028 if(cbBuf
< *pcbNeeded
){
5029 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5033 *pcReturned
= number
;
5037 /*****************************************************************************
5038 * EnumPrinterDriversW [WINSPOOL.@]
5040 * see function EnumPrinterDrivers for RETURNS, BUGS
5042 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5043 LPBYTE pDriverInfo
, DWORD cbBuf
,
5044 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5046 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5047 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5050 /*****************************************************************************
5051 * EnumPrinterDriversA [WINSPOOL.@]
5053 * see function EnumPrinterDrivers for RETURNS, BUGS
5055 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5056 LPBYTE pDriverInfo
, DWORD cbBuf
,
5057 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5059 UNICODE_STRING pNameW
, pEnvironmentW
;
5060 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5062 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5063 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5065 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5066 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5068 RtlFreeUnicodeString(&pNameW
);
5069 RtlFreeUnicodeString(&pEnvironmentW
);
5074 /******************************************************************************
5075 * EnumPortsA (WINSPOOL.@)
5080 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5081 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5084 LPBYTE bufferW
= NULL
;
5085 LPWSTR nameW
= NULL
;
5087 DWORD numentries
= 0;
5090 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5091 cbBuf
, pcbNeeded
, pcReturned
);
5093 /* convert servername to unicode */
5095 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5096 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5097 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5099 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5100 needed
= cbBuf
* sizeof(WCHAR
);
5101 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5102 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5104 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5105 if (pcbNeeded
) needed
= *pcbNeeded
;
5106 /* HeapReAlloc return NULL, when bufferW was NULL */
5107 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5108 HeapAlloc(GetProcessHeap(), 0, needed
);
5110 /* Try again with the large Buffer */
5111 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5113 needed
= pcbNeeded
? *pcbNeeded
: 0;
5114 numentries
= pcReturned
? *pcReturned
: 0;
5117 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5118 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5121 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5122 DWORD entrysize
= 0;
5125 LPPORT_INFO_2W pi2w
;
5126 LPPORT_INFO_2A pi2a
;
5129 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5131 /* First pass: calculate the size for all Entries */
5132 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5133 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5135 while (index
< numentries
) {
5137 needed
+= entrysize
; /* PORT_INFO_?A */
5138 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5140 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5141 NULL
, 0, NULL
, NULL
);
5143 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5144 NULL
, 0, NULL
, NULL
);
5145 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5146 NULL
, 0, NULL
, NULL
);
5148 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5149 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5150 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5153 /* check for errors and quit on failure */
5154 if (cbBuf
< needed
) {
5155 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5159 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5160 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5161 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5162 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5163 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5165 /* Second Pass: Fill the User Buffer (if we have one) */
5166 while ((index
< numentries
) && pPorts
) {
5168 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5169 pi2a
->pPortName
= ptr
;
5170 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5171 ptr
, cbBuf
, NULL
, NULL
);
5175 pi2a
->pMonitorName
= ptr
;
5176 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5177 ptr
, cbBuf
, NULL
, NULL
);
5181 pi2a
->pDescription
= ptr
;
5182 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5183 ptr
, cbBuf
, NULL
, NULL
);
5187 pi2a
->fPortType
= pi2w
->fPortType
;
5188 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5191 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5192 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5193 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5198 if (pcbNeeded
) *pcbNeeded
= needed
;
5199 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5201 HeapFree(GetProcessHeap(), 0, nameW
);
5202 HeapFree(GetProcessHeap(), 0, bufferW
);
5204 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5205 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5211 /******************************************************************************
5212 * EnumPortsW (WINSPOOL.@)
5214 * Enumerate available Ports
5217 * name [I] Servername or NULL (local Computer)
5218 * level [I] Structure-Level (1 or 2)
5219 * buffer [O] PTR to Buffer that receives the Result
5220 * bufsize [I] Size of Buffer at buffer
5221 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5222 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5226 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5230 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5233 DWORD numentries
= 0;
5236 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5237 cbBuf
, pcbNeeded
, pcReturned
);
5239 if (pName
&& (pName
[0])) {
5240 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5241 SetLastError(ERROR_ACCESS_DENIED
);
5245 /* Level is not checked in win9x */
5246 if (!Level
|| (Level
> 2)) {
5247 WARN("level (%d) is ignored in win9x\n", Level
);
5248 SetLastError(ERROR_INVALID_LEVEL
);
5252 SetLastError(RPC_X_NULL_REF_POINTER
);
5256 EnterCriticalSection(&monitor_handles_cs
);
5259 /* Scan all local Ports */
5261 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5263 /* we calculated the needed buffersize. now do the error-checks */
5264 if (cbBuf
< needed
) {
5265 monitor_unloadall();
5266 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5267 goto emP_cleanup_cs
;
5269 else if (!pPorts
|| !pcReturned
) {
5270 monitor_unloadall();
5271 SetLastError(RPC_X_NULL_REF_POINTER
);
5272 goto emP_cleanup_cs
;
5275 /* Fill the Buffer */
5276 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5278 monitor_unloadall();
5281 LeaveCriticalSection(&monitor_handles_cs
);
5284 if (pcbNeeded
) *pcbNeeded
= needed
;
5285 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5287 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5288 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5293 /******************************************************************************
5294 * GetDefaultPrinterW (WINSPOOL.@)
5297 * This function must read the value from data 'device' of key
5298 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5300 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5304 WCHAR
*buffer
, *ptr
;
5308 SetLastError(ERROR_INVALID_PARAMETER
);
5312 /* make the buffer big enough for the stuff from the profile/registry,
5313 * the content must fit into the local buffer to compute the correct
5314 * size even if the extern buffer is too small or not given.
5315 * (20 for ,driver,port) */
5317 len
= max(100, (insize
+ 20));
5318 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5320 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5322 SetLastError (ERROR_FILE_NOT_FOUND
);
5326 TRACE("%s\n", debugstr_w(buffer
));
5328 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5330 SetLastError(ERROR_INVALID_NAME
);
5336 *namesize
= strlenW(buffer
) + 1;
5337 if(!name
|| (*namesize
> insize
))
5339 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5343 strcpyW(name
, buffer
);
5346 HeapFree( GetProcessHeap(), 0, buffer
);
5351 /******************************************************************************
5352 * GetDefaultPrinterA (WINSPOOL.@)
5354 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5358 WCHAR
*bufferW
= NULL
;
5362 SetLastError(ERROR_INVALID_PARAMETER
);
5366 if(name
&& *namesize
) {
5368 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5371 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5376 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5380 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5383 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5386 HeapFree( GetProcessHeap(), 0, bufferW
);
5391 /******************************************************************************
5392 * SetDefaultPrinterW (WINSPOOL.204)
5394 * Set the Name of the Default Printer
5397 * pszPrinter [I] Name of the Printer or NULL
5404 * When the Parameter is NULL or points to an Empty String and
5405 * a Default Printer was already present, then this Function changes nothing.
5406 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5407 * the First enumerated local Printer is used.
5410 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5413 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5415 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5419 /******************************************************************************
5420 * SetDefaultPrinterA (WINSPOOL.202)
5422 * See SetDefaultPrinterW.
5425 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5428 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5430 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5435 /******************************************************************************
5436 * SetPrinterDataExA (WINSPOOL.@)
5438 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5439 LPCSTR pValueName
, DWORD Type
,
5440 LPBYTE pData
, DWORD cbData
)
5442 HKEY hkeyPrinter
, hkeySubkey
;
5445 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5446 debugstr_a(pValueName
), Type
, pData
, cbData
);
5448 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5452 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5454 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5455 RegCloseKey(hkeyPrinter
);
5458 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5459 RegCloseKey(hkeySubkey
);
5460 RegCloseKey(hkeyPrinter
);
5464 /******************************************************************************
5465 * SetPrinterDataExW (WINSPOOL.@)
5467 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5468 LPCWSTR pValueName
, DWORD Type
,
5469 LPBYTE pData
, DWORD cbData
)
5471 HKEY hkeyPrinter
, hkeySubkey
;
5474 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5475 debugstr_w(pValueName
), Type
, pData
, cbData
);
5477 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5481 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5483 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5484 RegCloseKey(hkeyPrinter
);
5487 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5488 RegCloseKey(hkeySubkey
);
5489 RegCloseKey(hkeyPrinter
);
5493 /******************************************************************************
5494 * SetPrinterDataA (WINSPOOL.@)
5496 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5497 LPBYTE pData
, DWORD cbData
)
5499 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5503 /******************************************************************************
5504 * SetPrinterDataW (WINSPOOL.@)
5506 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5507 LPBYTE pData
, DWORD cbData
)
5509 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5513 /******************************************************************************
5514 * GetPrinterDataExA (WINSPOOL.@)
5516 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5517 LPCSTR pValueName
, LPDWORD pType
,
5518 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5520 HKEY hkeyPrinter
, hkeySubkey
;
5523 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5524 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5527 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5531 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5533 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5534 RegCloseKey(hkeyPrinter
);
5538 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5539 RegCloseKey(hkeySubkey
);
5540 RegCloseKey(hkeyPrinter
);
5544 /******************************************************************************
5545 * GetPrinterDataExW (WINSPOOL.@)
5547 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5548 LPCWSTR pValueName
, LPDWORD pType
,
5549 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5551 HKEY hkeyPrinter
, hkeySubkey
;
5554 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5555 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5558 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5562 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5564 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5565 RegCloseKey(hkeyPrinter
);
5569 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5570 RegCloseKey(hkeySubkey
);
5571 RegCloseKey(hkeyPrinter
);
5575 /******************************************************************************
5576 * GetPrinterDataA (WINSPOOL.@)
5578 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5579 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5581 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5582 pData
, nSize
, pcbNeeded
);
5585 /******************************************************************************
5586 * GetPrinterDataW (WINSPOOL.@)
5588 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5589 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5591 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5592 pData
, nSize
, pcbNeeded
);
5595 /*******************************************************************************
5596 * EnumPrinterDataExW [WINSPOOL.@]
5598 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5599 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5600 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5602 HKEY hkPrinter
, hkSubKey
;
5603 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5604 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5609 PPRINTER_ENUM_VALUESW ppev
;
5611 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5613 if (pKeyName
== NULL
|| *pKeyName
== 0)
5614 return ERROR_INVALID_PARAMETER
;
5616 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5617 if (ret
!= ERROR_SUCCESS
)
5619 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5624 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5625 if (ret
!= ERROR_SUCCESS
)
5627 r
= RegCloseKey (hkPrinter
);
5628 if (r
!= ERROR_SUCCESS
)
5629 WARN ("RegCloseKey returned %i\n", r
);
5630 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5631 debugstr_w (pKeyName
), ret
);
5635 ret
= RegCloseKey (hkPrinter
);
5636 if (ret
!= ERROR_SUCCESS
)
5638 ERR ("RegCloseKey returned %i\n", ret
);
5639 r
= RegCloseKey (hkSubKey
);
5640 if (r
!= ERROR_SUCCESS
)
5641 WARN ("RegCloseKey returned %i\n", r
);
5645 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5646 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5647 if (ret
!= ERROR_SUCCESS
)
5649 r
= RegCloseKey (hkSubKey
);
5650 if (r
!= ERROR_SUCCESS
)
5651 WARN ("RegCloseKey returned %i\n", r
);
5652 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5656 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5657 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5659 if (cValues
== 0) /* empty key */
5661 r
= RegCloseKey (hkSubKey
);
5662 if (r
!= ERROR_SUCCESS
)
5663 WARN ("RegCloseKey returned %i\n", r
);
5664 *pcbEnumValues
= *pnEnumValues
= 0;
5665 return ERROR_SUCCESS
;
5668 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5670 hHeap
= GetProcessHeap ();
5673 ERR ("GetProcessHeap failed\n");
5674 r
= RegCloseKey (hkSubKey
);
5675 if (r
!= ERROR_SUCCESS
)
5676 WARN ("RegCloseKey returned %i\n", r
);
5677 return ERROR_OUTOFMEMORY
;
5680 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5681 if (lpValueName
== NULL
)
5683 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5684 r
= RegCloseKey (hkSubKey
);
5685 if (r
!= ERROR_SUCCESS
)
5686 WARN ("RegCloseKey returned %i\n", r
);
5687 return ERROR_OUTOFMEMORY
;
5690 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5691 if (lpValue
== NULL
)
5693 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5694 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5695 WARN ("HeapFree failed with code %i\n", GetLastError ());
5696 r
= RegCloseKey (hkSubKey
);
5697 if (r
!= ERROR_SUCCESS
)
5698 WARN ("RegCloseKey returned %i\n", r
);
5699 return ERROR_OUTOFMEMORY
;
5702 TRACE ("pass 1: calculating buffer required for all names and values\n");
5704 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5706 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5708 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5710 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5711 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5712 NULL
, NULL
, lpValue
, &cbValueLen
);
5713 if (ret
!= ERROR_SUCCESS
)
5715 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5716 WARN ("HeapFree failed with code %i\n", GetLastError ());
5717 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5718 WARN ("HeapFree failed with code %i\n", GetLastError ());
5719 r
= RegCloseKey (hkSubKey
);
5720 if (r
!= ERROR_SUCCESS
)
5721 WARN ("RegCloseKey returned %i\n", r
);
5722 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5726 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5727 debugstr_w (lpValueName
), dwIndex
,
5728 cbValueNameLen
+ 1, cbValueLen
);
5730 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5731 cbBufSize
+= cbValueLen
;
5734 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5736 *pcbEnumValues
= cbBufSize
;
5737 *pnEnumValues
= cValues
;
5739 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5741 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5744 WARN ("HeapFree failed with code %i\n", GetLastError ());
5745 r
= RegCloseKey (hkSubKey
);
5746 if (r
!= ERROR_SUCCESS
)
5747 WARN ("RegCloseKey returned %i\n", r
);
5748 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5749 return ERROR_MORE_DATA
;
5752 TRACE ("pass 2: copying all names and values to buffer\n");
5754 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5755 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5757 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5759 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5760 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5761 NULL
, &dwType
, lpValue
, &cbValueLen
);
5762 if (ret
!= ERROR_SUCCESS
)
5764 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5765 WARN ("HeapFree failed with code %i\n", GetLastError ());
5766 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5767 WARN ("HeapFree failed with code %i\n", GetLastError ());
5768 r
= RegCloseKey (hkSubKey
);
5769 if (r
!= ERROR_SUCCESS
)
5770 WARN ("RegCloseKey returned %i\n", r
);
5771 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5775 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5776 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5777 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5778 pEnumValues
+= cbValueNameLen
;
5780 /* return # of *bytes* (including trailing \0), not # of chars */
5781 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5783 ppev
[dwIndex
].dwType
= dwType
;
5785 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5786 ppev
[dwIndex
].pData
= pEnumValues
;
5787 pEnumValues
+= cbValueLen
;
5789 ppev
[dwIndex
].cbData
= cbValueLen
;
5791 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5792 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5795 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5797 ret
= GetLastError ();
5798 ERR ("HeapFree failed with code %i\n", ret
);
5799 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5800 WARN ("HeapFree failed with code %i\n", GetLastError ());
5801 r
= RegCloseKey (hkSubKey
);
5802 if (r
!= ERROR_SUCCESS
)
5803 WARN ("RegCloseKey returned %i\n", r
);
5807 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5809 ret
= GetLastError ();
5810 ERR ("HeapFree failed with code %i\n", ret
);
5811 r
= RegCloseKey (hkSubKey
);
5812 if (r
!= ERROR_SUCCESS
)
5813 WARN ("RegCloseKey returned %i\n", r
);
5817 ret
= RegCloseKey (hkSubKey
);
5818 if (ret
!= ERROR_SUCCESS
)
5820 ERR ("RegCloseKey returned %i\n", ret
);
5824 return ERROR_SUCCESS
;
5827 /*******************************************************************************
5828 * EnumPrinterDataExA [WINSPOOL.@]
5830 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5831 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5832 * what Windows 2000 SP1 does.
5835 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5836 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5837 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5841 DWORD ret
, dwIndex
, dwBufSize
;
5845 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5847 if (pKeyName
== NULL
|| *pKeyName
== 0)
5848 return ERROR_INVALID_PARAMETER
;
5850 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5853 ret
= GetLastError ();
5854 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5858 hHeap
= GetProcessHeap ();
5861 ERR ("GetProcessHeap failed\n");
5862 return ERROR_OUTOFMEMORY
;
5865 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5866 if (pKeyNameW
== NULL
)
5868 ERR ("Failed to allocate %i bytes from process heap\n",
5869 (LONG
)(len
* sizeof (WCHAR
)));
5870 return ERROR_OUTOFMEMORY
;
5873 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5875 ret
= GetLastError ();
5876 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5877 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5878 WARN ("HeapFree failed with code %i\n", GetLastError ());
5882 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5883 pcbEnumValues
, pnEnumValues
);
5884 if (ret
!= ERROR_SUCCESS
)
5886 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5887 WARN ("HeapFree failed with code %i\n", GetLastError ());
5888 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5892 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5894 ret
= GetLastError ();
5895 ERR ("HeapFree failed with code %i\n", ret
);
5899 if (*pnEnumValues
== 0) /* empty key */
5900 return ERROR_SUCCESS
;
5903 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5905 PPRINTER_ENUM_VALUESW ppev
=
5906 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5908 if (dwBufSize
< ppev
->cbValueName
)
5909 dwBufSize
= ppev
->cbValueName
;
5911 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5912 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5913 dwBufSize
= ppev
->cbData
;
5916 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5918 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5919 if (pBuffer
== NULL
)
5921 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5922 return ERROR_OUTOFMEMORY
;
5925 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5927 PPRINTER_ENUM_VALUESW ppev
=
5928 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5930 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5931 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5935 ret
= GetLastError ();
5936 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5937 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5938 WARN ("HeapFree failed with code %i\n", GetLastError ());
5942 memcpy (ppev
->pValueName
, pBuffer
, len
);
5944 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5946 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5947 ppev
->dwType
!= REG_MULTI_SZ
)
5950 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5951 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5954 ret
= GetLastError ();
5955 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5956 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5957 WARN ("HeapFree failed with code %i\n", GetLastError ());
5961 memcpy (ppev
->pData
, pBuffer
, len
);
5963 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5964 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5967 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5969 ret
= GetLastError ();
5970 ERR ("HeapFree failed with code %i\n", ret
);
5974 return ERROR_SUCCESS
;
5977 /******************************************************************************
5978 * AbortPrinter (WINSPOOL.@)
5980 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5982 FIXME("(%p), stub!\n", hPrinter
);
5986 /******************************************************************************
5987 * AddPortA (WINSPOOL.@)
5992 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5994 LPWSTR nameW
= NULL
;
5995 LPWSTR monitorW
= NULL
;
5999 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6002 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6003 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6004 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6008 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6009 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6010 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6012 res
= AddPortW(nameW
, hWnd
, monitorW
);
6013 HeapFree(GetProcessHeap(), 0, nameW
);
6014 HeapFree(GetProcessHeap(), 0, monitorW
);
6018 /******************************************************************************
6019 * AddPortW (WINSPOOL.@)
6021 * Add a Port for a specific Monitor
6024 * pName [I] Servername or NULL (local Computer)
6025 * hWnd [I] Handle to parent Window for the Dialog-Box
6026 * pMonitorName [I] Name of the Monitor that manage the Port
6033 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6039 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6041 if (pName
&& pName
[0]) {
6042 SetLastError(ERROR_INVALID_PARAMETER
);
6046 if (!pMonitorName
) {
6047 SetLastError(RPC_X_NULL_REF_POINTER
);
6051 /* an empty Monitorname is Invalid */
6052 if (!pMonitorName
[0]) {
6053 SetLastError(ERROR_NOT_SUPPORTED
);
6057 pm
= monitor_load(pMonitorName
, NULL
);
6058 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6059 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6060 TRACE("got %d with %u\n", res
, GetLastError());
6065 pui
= monitor_loadui(pm
);
6066 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6067 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6068 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6069 TRACE("got %d with %u\n", res
, GetLastError());
6074 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6075 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6077 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6078 SetLastError(ERROR_NOT_SUPPORTED
);
6081 monitor_unload(pui
);
6084 TRACE("returning %d with %u\n", res
, GetLastError());
6088 /******************************************************************************
6089 * AddPortExA (WINSPOOL.@)
6094 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
6096 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
6097 lpBuffer
, debugstr_a(lpMonitorName
));
6101 /******************************************************************************
6102 * AddPortExW (WINSPOOL.@)
6104 * Add a Port for a specific Monitor, without presenting a user interface
6107 * hMonitor [I] Handle from InitializePrintMonitor2()
6108 * pName [I] Servername or NULL (local Computer)
6109 * Level [I] Structure-Level (1 or 2) for lpBuffer
6110 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6111 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6121 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
6123 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
6124 lpBuffer
, debugstr_w(lpMonitorName
));
6128 /******************************************************************************
6129 * AddPrinterConnectionA (WINSPOOL.@)
6131 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6133 FIXME("%s\n", debugstr_a(pName
));
6137 /******************************************************************************
6138 * AddPrinterConnectionW (WINSPOOL.@)
6140 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6142 FIXME("%s\n", debugstr_w(pName
));
6146 /******************************************************************************
6147 * AddPrinterDriverExW (WINSPOOL.@)
6149 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6150 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6152 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6153 Level
, pDriverInfo
, dwFileCopyFlags
);
6154 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6158 /******************************************************************************
6159 * AddPrinterDriverExA (WINSPOOL.@)
6161 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6162 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6164 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6165 Level
, pDriverInfo
, dwFileCopyFlags
);
6166 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6170 /******************************************************************************
6171 * ConfigurePortA (WINSPOOL.@)
6173 * See ConfigurePortW.
6176 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6178 LPWSTR nameW
= NULL
;
6179 LPWSTR portW
= NULL
;
6183 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6185 /* convert servername to unicode */
6187 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6188 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6189 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6192 /* convert portname to unicode */
6194 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6195 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6196 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6199 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6200 HeapFree(GetProcessHeap(), 0, nameW
);
6201 HeapFree(GetProcessHeap(), 0, portW
);
6205 /******************************************************************************
6206 * ConfigurePortW (WINSPOOL.@)
6208 * Display the Configuration-Dialog for a specific Port
6211 * pName [I] Servername or NULL (local Computer)
6212 * hWnd [I] Handle to parent Window for the Dialog-Box
6213 * pPortName [I] Name of the Port, that should be configured
6220 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6226 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6228 if (pName
&& pName
[0]) {
6229 SetLastError(ERROR_INVALID_PARAMETER
);
6234 SetLastError(RPC_X_NULL_REF_POINTER
);
6238 /* an empty Portname is Invalid, but can popup a Dialog */
6239 if (!pPortName
[0]) {
6240 SetLastError(ERROR_NOT_SUPPORTED
);
6244 pm
= monitor_load_by_port(pPortName
);
6245 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6246 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6247 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6248 TRACE("got %d with %u\n", res
, GetLastError());
6252 pui
= monitor_loadui(pm
);
6253 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6254 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6255 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6256 TRACE("got %d with %u\n", res
, GetLastError());
6260 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6261 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6263 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6264 SetLastError(ERROR_NOT_SUPPORTED
);
6267 monitor_unload(pui
);
6271 TRACE("returning %d with %u\n", res
, GetLastError());
6275 /******************************************************************************
6276 * ConnectToPrinterDlg (WINSPOOL.@)
6278 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6280 FIXME("%p %x\n", hWnd
, Flags
);
6284 /******************************************************************************
6285 * DeletePrinterConnectionA (WINSPOOL.@)
6287 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6289 FIXME("%s\n", debugstr_a(pName
));
6293 /******************************************************************************
6294 * DeletePrinterConnectionW (WINSPOOL.@)
6296 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6298 FIXME("%s\n", debugstr_w(pName
));
6302 /******************************************************************************
6303 * DeletePrinterDriverExW (WINSPOOL.@)
6305 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6306 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6311 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6312 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6314 if(pName
&& pName
[0])
6316 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6317 SetLastError(ERROR_INVALID_PARAMETER
);
6323 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6324 SetLastError(ERROR_INVALID_PARAMETER
);
6328 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6332 ERR("Can't open drivers key\n");
6336 if(WINSPOOL_SHDeleteKeyW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6339 RegCloseKey(hkey_drivers
);
6344 /******************************************************************************
6345 * DeletePrinterDriverExA (WINSPOOL.@)
6347 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6348 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6350 UNICODE_STRING NameW
, EnvW
, DriverW
;
6353 asciitounicode(&NameW
, pName
);
6354 asciitounicode(&EnvW
, pEnvironment
);
6355 asciitounicode(&DriverW
, pDriverName
);
6357 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6359 RtlFreeUnicodeString(&DriverW
);
6360 RtlFreeUnicodeString(&EnvW
);
6361 RtlFreeUnicodeString(&NameW
);
6366 /******************************************************************************
6367 * DeletePrinterDataExW (WINSPOOL.@)
6369 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6372 FIXME("%p %s %s\n", hPrinter
,
6373 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6374 return ERROR_INVALID_PARAMETER
;
6377 /******************************************************************************
6378 * DeletePrinterDataExA (WINSPOOL.@)
6380 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6383 FIXME("%p %s %s\n", hPrinter
,
6384 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6385 return ERROR_INVALID_PARAMETER
;
6388 /******************************************************************************
6389 * DeletePrintProcessorA (WINSPOOL.@)
6391 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6393 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6394 debugstr_a(pPrintProcessorName
));
6398 /******************************************************************************
6399 * DeletePrintProcessorW (WINSPOOL.@)
6401 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6403 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6404 debugstr_w(pPrintProcessorName
));
6408 /******************************************************************************
6409 * DeletePrintProvidorA (WINSPOOL.@)
6411 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6413 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6414 debugstr_a(pPrintProviderName
));
6418 /******************************************************************************
6419 * DeletePrintProvidorW (WINSPOOL.@)
6421 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6423 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6424 debugstr_w(pPrintProviderName
));
6428 /******************************************************************************
6429 * EnumFormsA (WINSPOOL.@)
6431 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6432 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6434 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6435 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6439 /******************************************************************************
6440 * EnumFormsW (WINSPOOL.@)
6442 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6443 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6445 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6446 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6450 /*****************************************************************************
6451 * EnumMonitorsA [WINSPOOL.@]
6453 * See EnumMonitorsW.
6456 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6457 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6460 LPBYTE bufferW
= NULL
;
6461 LPWSTR nameW
= NULL
;
6463 DWORD numentries
= 0;
6466 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6467 cbBuf
, pcbNeeded
, pcReturned
);
6469 /* convert servername to unicode */
6471 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6472 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6473 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6475 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6476 needed
= cbBuf
* sizeof(WCHAR
);
6477 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6478 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6480 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6481 if (pcbNeeded
) needed
= *pcbNeeded
;
6482 /* HeapReAlloc return NULL, when bufferW was NULL */
6483 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6484 HeapAlloc(GetProcessHeap(), 0, needed
);
6486 /* Try again with the large Buffer */
6487 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6489 numentries
= pcReturned
? *pcReturned
: 0;
6492 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6493 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6496 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6497 DWORD entrysize
= 0;
6500 LPMONITOR_INFO_2W mi2w
;
6501 LPMONITOR_INFO_2A mi2a
;
6503 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6504 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6506 /* First pass: calculate the size for all Entries */
6507 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6508 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6510 while (index
< numentries
) {
6512 needed
+= entrysize
; /* MONITOR_INFO_?A */
6513 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6515 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6516 NULL
, 0, NULL
, NULL
);
6518 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6519 NULL
, 0, NULL
, NULL
);
6520 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6521 NULL
, 0, NULL
, NULL
);
6523 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6524 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6525 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6528 /* check for errors and quit on failure */
6529 if (cbBuf
< needed
) {
6530 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6534 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6535 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6536 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6537 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6538 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6540 /* Second Pass: Fill the User Buffer (if we have one) */
6541 while ((index
< numentries
) && pMonitors
) {
6543 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6545 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6546 ptr
, cbBuf
, NULL
, NULL
);
6550 mi2a
->pEnvironment
= ptr
;
6551 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6552 ptr
, cbBuf
, NULL
, NULL
);
6556 mi2a
->pDLLName
= ptr
;
6557 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6558 ptr
, cbBuf
, NULL
, NULL
);
6562 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6563 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6564 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6568 if (pcbNeeded
) *pcbNeeded
= needed
;
6569 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6571 HeapFree(GetProcessHeap(), 0, nameW
);
6572 HeapFree(GetProcessHeap(), 0, bufferW
);
6574 TRACE("returning %d with %d (%d byte for %d entries)\n",
6575 (res
), GetLastError(), needed
, numentries
);
6581 /*****************************************************************************
6582 * EnumMonitorsW [WINSPOOL.@]
6584 * Enumerate available Port-Monitors
6587 * pName [I] Servername or NULL (local Computer)
6588 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6589 * pMonitors [O] PTR to Buffer that receives the Result
6590 * cbBuf [I] Size of Buffer at pMonitors
6591 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6592 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6596 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6599 * Windows reads the Registry once and cache the Results.
6601 *| Language-Monitors are also installed in the same Registry-Location but
6602 *| they are filtered in Windows (not returned by EnumMonitors).
6603 *| We do no filtering to simplify our Code.
6606 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6607 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6610 DWORD numentries
= 0;
6613 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6614 cbBuf
, pcbNeeded
, pcReturned
);
6616 if (pName
&& (lstrlenW(pName
))) {
6617 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6618 SetLastError(ERROR_ACCESS_DENIED
);
6622 /* Level is not checked in win9x */
6623 if (!Level
|| (Level
> 2)) {
6624 WARN("level (%d) is ignored in win9x\n", Level
);
6625 SetLastError(ERROR_INVALID_LEVEL
);
6629 SetLastError(RPC_X_NULL_REF_POINTER
);
6633 /* Scan all Monitor-Keys */
6635 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6637 /* we calculated the needed buffersize. now do the error-checks */
6638 if (cbBuf
< needed
) {
6639 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6642 else if (!pMonitors
|| !pcReturned
) {
6643 SetLastError(RPC_X_NULL_REF_POINTER
);
6647 /* fill the Buffer with the Monitor-Keys */
6648 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6652 if (pcbNeeded
) *pcbNeeded
= needed
;
6653 if (pcReturned
) *pcReturned
= numentries
;
6655 TRACE("returning %d with %d (%d byte for %d entries)\n",
6656 res
, GetLastError(), needed
, numentries
);
6661 /******************************************************************************
6662 * XcvDataW (WINSPOOL.@)
6664 * Execute commands in the Printmonitor DLL
6667 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6668 * pszDataName [i] Name of the command to execute
6669 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6670 * cbInputData [i] Size in Bytes of Buffer at pInputData
6671 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6672 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6673 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6674 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6681 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6682 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6684 * Minimal List of commands, that a Printmonitor DLL should support:
6686 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6687 *| "AddPort" : Add a Port
6688 *| "DeletePort": Delete a Port
6690 * Many Printmonitors support additional commands. Examples for localspl.dll:
6691 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6692 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6695 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6696 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6697 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6699 opened_printer_t
*printer
;
6701 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6702 pInputData
, cbInputData
, pOutputData
,
6703 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6705 printer
= get_opened_printer(hXcv
);
6706 if (!printer
|| (!printer
->hXcv
)) {
6707 SetLastError(ERROR_INVALID_HANDLE
);
6711 if (!pcbOutputNeeded
) {
6712 SetLastError(ERROR_INVALID_PARAMETER
);
6716 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6717 SetLastError(RPC_X_NULL_REF_POINTER
);
6721 *pcbOutputNeeded
= 0;
6723 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6724 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6729 /*****************************************************************************
6730 * EnumPrinterDataA [WINSPOOL.@]
6733 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6734 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6735 DWORD cbData
, LPDWORD pcbData
)
6737 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6738 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6739 return ERROR_NO_MORE_ITEMS
;
6742 /*****************************************************************************
6743 * EnumPrinterDataW [WINSPOOL.@]
6746 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6747 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6748 DWORD cbData
, LPDWORD pcbData
)
6750 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6751 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6752 return ERROR_NO_MORE_ITEMS
;
6755 /*****************************************************************************
6756 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6759 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6760 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6761 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6763 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6764 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6765 pcbNeeded
, pcReturned
);
6769 /*****************************************************************************
6770 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6773 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6774 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6775 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6777 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6778 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6779 pcbNeeded
, pcReturned
);
6783 /*****************************************************************************
6784 * EnumPrintProcessorsA [WINSPOOL.@]
6787 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6788 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6790 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6791 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6795 /*****************************************************************************
6796 * EnumPrintProcessorsW [WINSPOOL.@]
6799 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6800 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6802 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6803 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6804 cbBuf
, pcbNeeded
, pcbReturned
);
6808 /*****************************************************************************
6809 * ExtDeviceMode [WINSPOOL.@]
6812 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6813 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6816 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6817 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6818 debugstr_a(pProfile
), fMode
);
6822 /*****************************************************************************
6823 * FindClosePrinterChangeNotification [WINSPOOL.@]
6826 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6828 FIXME("Stub: %p\n", hChange
);
6832 /*****************************************************************************
6833 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6836 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6837 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6839 FIXME("Stub: %p %x %x %p\n",
6840 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6841 return INVALID_HANDLE_VALUE
;
6844 /*****************************************************************************
6845 * FindNextPrinterChangeNotification [WINSPOOL.@]
6848 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6849 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6851 FIXME("Stub: %p %p %p %p\n",
6852 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6856 /*****************************************************************************
6857 * FreePrinterNotifyInfo [WINSPOOL.@]
6860 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6862 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6866 /*****************************************************************************
6869 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6870 * ansi depending on the unicode parameter.
6872 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6882 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6885 memcpy(ptr
, str
, *size
);
6892 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6895 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6902 /*****************************************************************************
6905 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6906 LPDWORD pcbNeeded
, BOOL unicode
)
6908 DWORD size
, left
= cbBuf
;
6909 BOOL space
= (cbBuf
> 0);
6916 ji1
->JobId
= job
->job_id
;
6919 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6920 if(space
&& size
<= left
)
6922 ji1
->pDocument
= (LPWSTR
)ptr
;
6933 /*****************************************************************************
6936 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6937 LPDWORD pcbNeeded
, BOOL unicode
)
6939 DWORD size
, left
= cbBuf
;
6940 BOOL space
= (cbBuf
> 0);
6947 ji2
->JobId
= job
->job_id
;
6950 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6951 if(space
&& size
<= left
)
6953 ji2
->pDocument
= (LPWSTR
)ptr
;
6964 /*****************************************************************************
6967 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
6968 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
6971 DWORD needed
= 0, size
;
6975 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
6977 EnterCriticalSection(&printer_handles_cs
);
6978 job
= get_job(hPrinter
, JobId
);
6985 size
= sizeof(JOB_INFO_1W
);
6990 memset(pJob
, 0, size
);
6994 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
6999 size
= sizeof(JOB_INFO_2W
);
7004 memset(pJob
, 0, size
);
7008 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7013 size
= sizeof(JOB_INFO_3
);
7017 memset(pJob
, 0, size
);
7026 SetLastError(ERROR_INVALID_LEVEL
);
7030 *pcbNeeded
= needed
;
7032 LeaveCriticalSection(&printer_handles_cs
);
7036 /*****************************************************************************
7037 * GetJobA [WINSPOOL.@]
7040 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7041 DWORD cbBuf
, LPDWORD pcbNeeded
)
7043 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7046 /*****************************************************************************
7047 * GetJobW [WINSPOOL.@]
7050 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7051 DWORD cbBuf
, LPDWORD pcbNeeded
)
7053 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7056 /*****************************************************************************
7059 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7061 char *unixname
, *queue
, *cmd
;
7062 char fmt
[] = "lpr -P%s %s";
7065 if(!(unixname
= wine_get_unix_file_name(filename
)))
7068 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7069 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7070 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7072 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7073 sprintf(cmd
, fmt
, queue
, unixname
);
7075 TRACE("printing with: %s\n", cmd
);
7078 HeapFree(GetProcessHeap(), 0, cmd
);
7079 HeapFree(GetProcessHeap(), 0, queue
);
7080 HeapFree(GetProcessHeap(), 0, unixname
);
7084 /*****************************************************************************
7087 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7089 #if HAVE_CUPS_CUPS_H
7092 char *unixname
, *queue
, *doc_titleA
;
7096 if(!(unixname
= wine_get_unix_file_name(filename
)))
7099 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7100 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7101 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7103 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7104 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7105 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7107 TRACE("printing via cups\n");
7108 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7109 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7110 HeapFree(GetProcessHeap(), 0, queue
);
7111 HeapFree(GetProcessHeap(), 0, unixname
);
7117 return schedule_lpr(printer_name
, filename
);
7121 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7128 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7132 if(HIWORD(wparam
) == BN_CLICKED
)
7134 if(LOWORD(wparam
) == IDOK
)
7137 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7140 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7141 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7143 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7145 WCHAR caption
[200], message
[200];
7148 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7149 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7150 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7151 if(mb_ret
== IDCANCEL
)
7153 HeapFree(GetProcessHeap(), 0, filename
);
7157 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7158 if(hf
== INVALID_HANDLE_VALUE
)
7160 WCHAR caption
[200], message
[200];
7162 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7163 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7164 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7165 HeapFree(GetProcessHeap(), 0, filename
);
7169 DeleteFileW(filename
);
7170 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7172 EndDialog(hwnd
, IDOK
);
7175 if(LOWORD(wparam
) == IDCANCEL
)
7177 EndDialog(hwnd
, IDCANCEL
);
7186 /*****************************************************************************
7189 static BOOL
get_filename(LPWSTR
*filename
)
7191 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7192 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7195 /*****************************************************************************
7198 static BOOL
schedule_file(LPCWSTR filename
)
7200 LPWSTR output
= NULL
;
7202 if(get_filename(&output
))
7204 TRACE("copy to %s\n", debugstr_w(output
));
7205 CopyFileW(filename
, output
, FALSE
);
7206 HeapFree(GetProcessHeap(), 0, output
);
7212 /*****************************************************************************
7215 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7218 char *unixname
, *cmdA
;
7220 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7224 if(!(unixname
= wine_get_unix_file_name(filename
)))
7227 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7228 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7229 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7231 TRACE("printing with: %s\n", cmdA
);
7233 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7238 ERR("pipe() failed!\n");
7248 /* reset signals that we previously set to SIG_IGN */
7249 signal(SIGPIPE
, SIG_DFL
);
7250 signal(SIGCHLD
, SIG_DFL
);
7252 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7256 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7257 write(fds
[1], buf
, no_read
);
7262 if(file_fd
!= -1) close(file_fd
);
7263 if(fds
[0] != -1) close(fds
[0]);
7264 if(fds
[1] != -1) close(fds
[1]);
7266 HeapFree(GetProcessHeap(), 0, cmdA
);
7267 HeapFree(GetProcessHeap(), 0, unixname
);
7274 /*****************************************************************************
7277 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7279 int in_fd
, out_fd
, no_read
;
7282 char *unixname
, *outputA
;
7285 if(!(unixname
= wine_get_unix_file_name(filename
)))
7288 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7289 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7290 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7292 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7293 in_fd
= open(unixname
, O_RDONLY
);
7294 if(out_fd
== -1 || in_fd
== -1)
7297 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7298 write(out_fd
, buf
, no_read
);
7302 if(in_fd
!= -1) close(in_fd
);
7303 if(out_fd
!= -1) close(out_fd
);
7304 HeapFree(GetProcessHeap(), 0, outputA
);
7305 HeapFree(GetProcessHeap(), 0, unixname
);
7309 /*****************************************************************************
7310 * ScheduleJob [WINSPOOL.@]
7313 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7315 opened_printer_t
*printer
;
7317 struct list
*cursor
, *cursor2
;
7319 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7320 EnterCriticalSection(&printer_handles_cs
);
7321 printer
= get_opened_printer(hPrinter
);
7325 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7327 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7330 if(job
->job_id
!= dwJobID
) continue;
7332 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7333 if(hf
!= INVALID_HANDLE_VALUE
)
7335 PRINTER_INFO_5W
*pi5
;
7339 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7340 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7342 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7343 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7344 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7345 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7346 debugstr_w(pi5
->pPortName
));
7350 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7351 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7353 DWORD type
, count
= sizeof(output
);
7354 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7357 if(output
[0] == '|')
7359 schedule_pipe(output
+ 1, job
->filename
);
7363 schedule_unixfile(output
, job
->filename
);
7365 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7367 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7369 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7371 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7373 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7375 schedule_file(job
->filename
);
7379 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7381 HeapFree(GetProcessHeap(), 0, pi5
);
7383 DeleteFileW(job
->filename
);
7385 list_remove(cursor
);
7386 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7387 HeapFree(GetProcessHeap(), 0, job
->filename
);
7388 HeapFree(GetProcessHeap(), 0, job
);
7393 LeaveCriticalSection(&printer_handles_cs
);
7397 /*****************************************************************************
7398 * StartDocDlgA [WINSPOOL.@]
7400 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7402 UNICODE_STRING usBuffer
;
7405 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7408 docW
.cbSize
= sizeof(docW
);
7409 if (doc
->lpszDocName
)
7411 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7412 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7414 if (doc
->lpszOutput
)
7416 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7417 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7419 if (doc
->lpszDatatype
)
7421 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7422 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7424 docW
.fwType
= doc
->fwType
;
7426 retW
= StartDocDlgW(hPrinter
, &docW
);
7430 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7431 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7432 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7433 HeapFree(GetProcessHeap(), 0, retW
);
7436 HeapFree(GetProcessHeap(), 0, datatypeW
);
7437 HeapFree(GetProcessHeap(), 0, outputW
);
7438 HeapFree(GetProcessHeap(), 0, docnameW
);
7443 /*****************************************************************************
7444 * StartDocDlgW [WINSPOOL.@]
7446 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7447 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7448 * port is "FILE:". Also returns the full path if passed a relative path.
7450 * The caller should free the returned string from the process heap.
7452 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7457 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7459 PRINTER_INFO_5W
*pi5
;
7460 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7461 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7463 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7464 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7465 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7467 HeapFree(GetProcessHeap(), 0, pi5
);
7470 HeapFree(GetProcessHeap(), 0, pi5
);
7473 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7477 if (get_filename(&name
))
7479 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7481 HeapFree(GetProcessHeap(), 0, name
);
7484 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7485 GetFullPathNameW(name
, len
, ret
, NULL
);
7486 HeapFree(GetProcessHeap(), 0, name
);
7491 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7494 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7495 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7497 attr
= GetFileAttributesW(ret
);
7498 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7500 HeapFree(GetProcessHeap(), 0, ret
);