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-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs
;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
75 0, 0, &printer_handles_cs
,
76 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
77 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer
;
106 WCHAR
*document_title
;
116 LPCWSTR versionregpath
;
117 LPCWSTR versionsubdir
;
120 /* ############################### */
122 static opened_printer_t
**printer_handles
;
123 static UINT nb_printer_handles
;
124 static LONG next_job_id
= 1;
126 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
127 WORD fwCapability
, LPSTR lpszOutput
,
129 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
130 LPSTR lpszDevice
, LPSTR lpszPort
,
131 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
134 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
135 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
136 'c','o','n','t','r','o','l','\\',
137 'P','r','i','n','t','\\',
138 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
139 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
141 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
142 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
143 'C','o','n','t','r','o','l','\\',
144 'P','r','i','n','t','\\',
145 'P','r','i','n','t','e','r','s',0};
147 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
149 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
150 'M','i','c','r','o','s','o','f','t','\\',
151 'W','i','n','d','o','w','s',' ','N','T','\\',
152 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
153 'W','i','n','d','o','w','s',0};
155 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s',' ','N','T','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'D','e','v','i','c','e','s',0};
161 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s',' ','N','T','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'P','o','r','t','s',0};
167 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
168 'M','i','c','r','o','s','o','f','t','\\',
169 'W','i','n','d','o','w','s',' ','N','T','\\',
170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'P','r','i','n','t','e','r','P','o','r','t','s',0};
173 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
174 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
175 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
176 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
177 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
178 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
179 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
180 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
181 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
182 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
183 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
185 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
186 static const WCHAR backslashW
[] = {'\\',0};
187 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
188 'i','o','n',' ','F','i','l','e',0};
189 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
190 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
191 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
192 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
193 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
194 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
195 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
196 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
197 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
198 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
199 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
200 static const WCHAR NameW
[] = {'N','a','m','e',0};
201 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
202 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
203 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
204 static const WCHAR PortW
[] = {'P','o','r','t',0};
205 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
206 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
207 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
208 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
209 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
210 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
211 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
212 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
213 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
214 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
215 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
216 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
217 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
218 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
219 static WCHAR generic_ppdW
[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
220 static WCHAR rawW
[] = {'R','A','W',0};
221 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
222 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
223 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
224 static const WCHAR commaW
[] = {',',0};
225 static WCHAR emptyStringW
[] = {0};
227 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
229 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
230 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
231 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
233 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
234 'D','o','c','u','m','e','n','t',0};
236 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
237 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
238 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
239 0, sizeof(DRIVER_INFO_8W
)};
242 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
243 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
244 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
245 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
246 sizeof(PRINTER_INFO_9W
)};
248 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
249 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
250 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
252 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
258 * env [I] PTR to Environment-String or NULL
262 * Success: PTR to printenv_t
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t
* validate_envW(LPCWSTR env
)
272 const printenv_t
*result
= NULL
;
275 TRACE("testing %s\n", debugstr_w(env
));
278 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
280 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
282 result
= all_printenv
[i
];
287 if (result
== NULL
) {
288 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
289 SetLastError(ERROR_INVALID_ENVIRONMENT
);
291 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
295 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
297 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
303 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
304 if passed a NULL string. This returns NULLs to the result.
306 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
310 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
311 return usBufferPtr
->Buffer
;
313 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
317 static LPWSTR
strdupW(LPCWSTR p
)
323 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
324 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
329 static LPSTR
strdupWtoA( LPCWSTR str
)
334 if (!str
) return NULL
;
335 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
336 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
337 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
341 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
345 if (!dm
) return NULL
;
346 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
347 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
351 /******************************************************************
352 * verify, that the filename is a local file
355 static inline BOOL
is_local_file(LPWSTR name
)
357 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
360 /* ################################ */
362 static int multi_sz_lenA(const char *str
)
364 const char *ptr
= str
;
368 ptr
+= lstrlenA(ptr
) + 1;
371 return ptr
- str
+ 1;
375 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
378 /* If forcing, or no profile string entry for device yet, set the entry
380 * The always change entry if not WINEPS yet is discussable.
383 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
385 !strstr(qbuf
,"WINEPS.DRV")
387 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
390 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
391 WriteProfileStringA("windows","device",buf
);
392 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
393 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
396 HeapFree(GetProcessHeap(),0,buf
);
400 static BOOL
add_printer_driver(WCHAR
*name
)
404 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
407 di3
.pEnvironment
= envname_x86W
;
408 di3
.pDriverPath
= driver_nt
;
409 di3
.pDataFile
= generic_ppdW
;
410 di3
.pConfigFile
= driver_nt
;
411 di3
.pDefaultDataType
= rawW
;
413 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
414 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
417 di3
.pEnvironment
= envname_win40W
;
418 di3
.pDriverPath
= driver_9x
;
419 di3
.pConfigFile
= driver_9x
;
420 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
421 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
426 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
430 #ifdef SONAME_LIBCUPS
431 static typeof(cupsFreeDests
) *pcupsFreeDests
;
432 static typeof(cupsGetDests
) *pcupsGetDests
;
433 static typeof(cupsGetPPD
) *pcupsGetPPD
;
434 static typeof(cupsPrintFile
) *pcupsPrintFile
;
435 static void *cupshandle
;
437 static BOOL
CUPS_LoadPrinters(void)
440 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
444 HKEY hkeyPrinter
, hkeyPrinters
;
446 WCHAR nameW
[MAX_PATH
];
448 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
450 TRACE("%s\n", loaderror
);
453 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
456 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
457 if (!p##x) return FALSE;
459 DYNCUPS(cupsFreeDests
);
461 DYNCUPS(cupsGetDests
);
462 DYNCUPS(cupsPrintFile
);
465 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
467 ERR("Can't create Printers key\n");
471 nrofdests
= pcupsGetDests(&dests
);
472 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
473 for (i
=0;i
<nrofdests
;i
++) {
474 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
476 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
477 lstrcpyW(port
, CUPS_Port
);
478 lstrcatW(port
, nameW
);
480 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
481 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
482 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
484 TRACE("Printer already exists\n");
485 /* overwrite old LPR:* port */
486 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
487 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
488 RegCloseKey(hkeyPrinter
);
490 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
491 ' ','u','s','i','n','g',' ','C','U','P','S',0};
493 add_printer_driver(nameW
);
495 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
496 pi2
.pPrinterName
= nameW
;
497 pi2
.pDatatype
= rawW
;
498 pi2
.pPrintProcessor
= WinPrintW
;
499 pi2
.pDriverName
= nameW
;
500 pi2
.pComment
= comment_cups
;
501 pi2
.pLocation
= emptyStringW
;
502 pi2
.pPortName
= port
;
503 pi2
.pParameters
= emptyStringW
;
504 pi2
.pShareName
= emptyStringW
;
505 pi2
.pSepFile
= emptyStringW
;
507 if (!AddPrinterW(NULL
, 2, (LPBYTE
)&pi2
)) {
508 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
509 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError());
512 HeapFree(GetProcessHeap(),0,port
);
515 if (dests
[i
].is_default
) {
516 SetDefaultPrinterW(nameW
);
520 if (hadprinter
&& !haddefault
) {
521 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
522 SetDefaultPrinterW(nameW
);
524 pcupsFreeDests(nrofdests
, dests
);
525 RegCloseKey(hkeyPrinters
);
531 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
532 PRINTER_INFO_2A pinfo2a
;
535 char *e
,*s
,*name
,*prettyname
,*devname
;
536 BOOL ret
= FALSE
, set_default
= FALSE
;
537 char *port
= NULL
, *env_default
;
538 HKEY hkeyPrinter
, hkeyPrinters
;
539 WCHAR devnameW
[MAX_PATH
];
541 while (isspace(*pent
)) pent
++;
542 r
= strchr(pent
,':');
546 name_len
= strlen(pent
);
547 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
548 memcpy(name
, pent
, name_len
);
549 name
[name_len
] = '\0';
555 TRACE("name=%s entry=%s\n",name
, pent
);
557 if(ispunct(*name
)) { /* a tc entry, not a real printer */
558 TRACE("skipping tc entry\n");
562 if(strstr(pent
,":server")) { /* server only version so skip */
563 TRACE("skipping server entry\n");
567 /* Determine whether this is a postscript printer. */
570 env_default
= getenv("PRINTER");
572 /* Get longest name, usually the one at the right for later display. */
573 while((s
=strchr(prettyname
,'|'))) {
576 while(isspace(*--e
)) *e
= '\0';
577 TRACE("\t%s\n", debugstr_a(prettyname
));
578 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
579 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
582 e
= prettyname
+ strlen(prettyname
);
583 while(isspace(*--e
)) *e
= '\0';
584 TRACE("\t%s\n", debugstr_a(prettyname
));
585 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
587 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
588 * if it is too long, we use it as comment below. */
589 devname
= prettyname
;
590 if (strlen(devname
)>=CCHDEVICENAME
-1)
592 if (strlen(devname
)>=CCHDEVICENAME
-1) {
597 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
598 sprintf(port
,"LPR:%s",name
);
600 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
602 ERR("Can't create Printers key\n");
607 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
609 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
610 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
612 TRACE("Printer already exists\n");
613 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
614 RegCloseKey(hkeyPrinter
);
616 static CHAR data_type
[] = "RAW",
617 print_proc
[] = "WinPrint",
618 comment
[] = "WINEPS Printer using LPR",
619 params
[] = "<parameters?>",
620 share_name
[] = "<share name?>",
621 sep_file
[] = "<sep file?>";
623 add_printer_driver(devnameW
);
625 memset(&pinfo2a
,0,sizeof(pinfo2a
));
626 pinfo2a
.pPrinterName
= devname
;
627 pinfo2a
.pDatatype
= data_type
;
628 pinfo2a
.pPrintProcessor
= print_proc
;
629 pinfo2a
.pDriverName
= devname
;
630 pinfo2a
.pComment
= comment
;
631 pinfo2a
.pLocation
= prettyname
;
632 pinfo2a
.pPortName
= port
;
633 pinfo2a
.pParameters
= params
;
634 pinfo2a
.pShareName
= share_name
;
635 pinfo2a
.pSepFile
= sep_file
;
637 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
638 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
639 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
642 RegCloseKey(hkeyPrinters
);
644 if (isfirst
|| set_default
)
645 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
648 HeapFree(GetProcessHeap(), 0, port
);
649 HeapFree(GetProcessHeap(), 0, name
);
654 PRINTCAP_LoadPrinters(void) {
655 BOOL hadprinter
= FALSE
;
659 BOOL had_bash
= FALSE
;
661 f
= fopen("/etc/printcap","r");
665 while(fgets(buf
,sizeof(buf
),f
)) {
668 end
=strchr(buf
,'\n');
672 while(isspace(*start
)) start
++;
673 if(*start
== '#' || *start
== '\0')
676 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
677 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
678 HeapFree(GetProcessHeap(),0,pent
);
682 if (end
&& *--end
== '\\') {
689 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
692 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
698 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
699 HeapFree(GetProcessHeap(),0,pent
);
705 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
708 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
709 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
711 return ERROR_FILE_NOT_FOUND
;
714 /******************************************************************
715 * get_servername_from_name (internal)
717 * for an external server, a copy of the serverpart from the full name is returned
720 static LPWSTR
get_servername_from_name(LPCWSTR name
)
724 WCHAR buffer
[MAX_PATH
];
727 if (name
== NULL
) return NULL
;
728 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
730 server
= strdupW(&name
[2]); /* skip over both backslash */
731 if (server
== NULL
) return NULL
;
733 /* strip '\' and the printername */
734 ptr
= strchrW(server
, '\\');
735 if (ptr
) ptr
[0] = '\0';
737 TRACE("found %s\n", debugstr_w(server
));
739 len
= sizeof(buffer
)/sizeof(buffer
[0]);
740 if (GetComputerNameW(buffer
, &len
)) {
741 if (lstrcmpW(buffer
, server
) == 0) {
742 /* The requested Servername is our computername */
743 HeapFree(GetProcessHeap(), 0, server
);
750 /******************************************************************
751 * get_basename_from_name (internal)
753 * skip over the serverpart from the full name
756 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
758 if (name
== NULL
) return NULL
;
759 if ((name
[0] == '\\') && (name
[1] == '\\')) {
760 /* skip over the servername and search for the following '\' */
761 name
= strchrW(&name
[2], '\\');
762 if ((name
) && (name
[1])) {
763 /* found a separator ('\') followed by a name:
764 skip over the separator and return the rest */
769 /* no basename present (we found only a servername) */
776 /******************************************************************
777 * get_opened_printer_entry
778 * Get the first place empty in the opened printer table
781 * - pDefault is ignored
783 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
785 UINT_PTR handle
= nb_printer_handles
, i
;
786 jobqueue_t
*queue
= NULL
;
787 opened_printer_t
*printer
= NULL
;
791 if ((backend
== NULL
) && !load_backend()) return NULL
;
793 servername
= get_servername_from_name(name
);
795 FIXME("server %s not supported\n", debugstr_w(servername
));
796 HeapFree(GetProcessHeap(), 0, servername
);
797 SetLastError(ERROR_INVALID_PRINTER_NAME
);
801 printername
= get_basename_from_name(name
);
802 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
804 /* an empty printername is invalid */
805 if (printername
&& (!printername
[0])) {
806 SetLastError(ERROR_INVALID_PARAMETER
);
810 EnterCriticalSection(&printer_handles_cs
);
812 for (i
= 0; i
< nb_printer_handles
; i
++)
814 if (!printer_handles
[i
])
816 if(handle
== nb_printer_handles
)
821 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
822 queue
= printer_handles
[i
]->queue
;
826 if (handle
>= nb_printer_handles
)
828 opened_printer_t
**new_array
;
830 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
831 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
833 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
834 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
841 printer_handles
= new_array
;
842 nb_printer_handles
+= 16;
845 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
851 /* get a printer handle from the backend */
852 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
857 /* clone the base name. This is NULL for the printserver */
858 printer
->printername
= strdupW(printername
);
860 /* clone the full name */
861 printer
->name
= strdupW(name
);
862 if (name
&& (!printer
->name
)) {
868 printer
->queue
= queue
;
871 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
872 if (!printer
->queue
) {
876 list_init(&printer
->queue
->jobs
);
877 printer
->queue
->ref
= 0;
879 InterlockedIncrement(&printer
->queue
->ref
);
881 printer_handles
[handle
] = printer
;
884 LeaveCriticalSection(&printer_handles_cs
);
885 if (!handle
&& printer
) {
886 /* Something failed: Free all resources */
887 HeapFree(GetProcessHeap(), 0, printer
->printername
);
888 HeapFree(GetProcessHeap(), 0, printer
->name
);
889 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
890 HeapFree(GetProcessHeap(), 0, printer
);
893 return (HANDLE
)handle
;
896 /******************************************************************
898 * Get the pointer to the opened printer referred by the handle
900 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
902 UINT_PTR idx
= (UINT_PTR
)hprn
;
903 opened_printer_t
*ret
= NULL
;
905 EnterCriticalSection(&printer_handles_cs
);
907 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
908 ret
= printer_handles
[idx
- 1];
910 LeaveCriticalSection(&printer_handles_cs
);
914 /******************************************************************
915 * get_opened_printer_name
916 * Get the pointer to the opened printer name referred by the handle
918 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
920 opened_printer_t
*printer
= get_opened_printer(hprn
);
921 if(!printer
) return NULL
;
922 return printer
->name
;
925 /******************************************************************
926 * WINSPOOL_GetOpenedPrinterRegKey
929 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
931 LPCWSTR name
= get_opened_printer_name(hPrinter
);
935 if(!name
) return ERROR_INVALID_HANDLE
;
937 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
941 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
943 ERR("Can't find opened printer %s in registry\n",
945 RegCloseKey(hkeyPrinters
);
946 return ERROR_INVALID_PRINTER_NAME
; /* ? */
948 RegCloseKey(hkeyPrinters
);
949 return ERROR_SUCCESS
;
952 void WINSPOOL_LoadSystemPrinters(void)
954 HKEY hkey
, hkeyPrinters
;
956 DWORD needed
, num
, i
;
957 WCHAR PrinterName
[256];
960 /* This ensures that all printer entries have a valid Name value. If causes
961 problems later if they don't. If one is found to be missed we create one
962 and set it equal to the name of the key */
963 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
964 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
965 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
966 for(i
= 0; i
< num
; i
++) {
967 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
968 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
969 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
970 set_reg_szW(hkey
, NameW
, PrinterName
);
977 RegCloseKey(hkeyPrinters
);
980 /* We want to avoid calling AddPrinter on printers as much as
981 possible, because on cups printers this will (eventually) lead
982 to a call to cupsGetPPD which takes forever, even with non-cups
983 printers AddPrinter takes a while. So we'll tag all printers that
984 were automatically added last time around, if they still exist
985 we'll leave them be otherwise we'll delete them. */
986 if (EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
) && needed
) {
987 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
988 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
989 for(i
= 0; i
< num
; i
++) {
990 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
991 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
992 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
994 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1002 HeapFree(GetProcessHeap(), 0, pi
);
1006 #ifdef SONAME_LIBCUPS
1007 done
= CUPS_LoadPrinters();
1010 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1011 PRINTCAP_LoadPrinters();
1013 /* Now enumerate the list again and delete any printers that are still tagged */
1014 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1016 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1017 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1018 for(i
= 0; i
< num
; i
++) {
1019 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1020 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1021 BOOL delete_driver
= FALSE
;
1022 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1023 DWORD dw
, type
, size
= sizeof(dw
);
1024 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1025 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1026 DeletePrinter(hprn
);
1027 delete_driver
= TRUE
;
1033 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1038 HeapFree(GetProcessHeap(), 0, pi
);
1045 /******************************************************************
1048 * Get the pointer to the specified job.
1049 * Should hold the printer_handles_cs before calling.
1051 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1053 opened_printer_t
*printer
= get_opened_printer(hprn
);
1056 if(!printer
) return NULL
;
1057 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1059 if(job
->job_id
== JobId
)
1065 /***********************************************************
1068 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1071 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1074 Formname
= (dmA
->dmSize
> off_formname
);
1075 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1076 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1077 dmW
->dmDeviceName
, CCHDEVICENAME
);
1079 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1080 dmA
->dmSize
- CCHDEVICENAME
);
1082 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1083 off_formname
- CCHDEVICENAME
);
1084 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1085 dmW
->dmFormName
, CCHFORMNAME
);
1086 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1087 (off_formname
+ CCHFORMNAME
));
1090 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1091 dmA
->dmDriverExtra
);
1095 /***********************************************************
1097 * Creates an ansi copy of supplied devmode
1099 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1104 if (!dmW
) return NULL
;
1105 size
= dmW
->dmSize
- CCHDEVICENAME
-
1106 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1108 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1109 if (!dmA
) return NULL
;
1111 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1112 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1114 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1115 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1116 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1120 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1121 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1122 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1123 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1125 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1129 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1133 /******************************************************************
1134 * convert_printerinfo_W_to_A [internal]
1137 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1138 DWORD level
, DWORD outlen
, DWORD numentries
)
1144 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1146 len
= pi_sizeof
[level
] * numentries
;
1147 ptr
= (LPSTR
) out
+ len
;
1150 /* copy the numbers of all PRINTER_INFO_* first */
1151 memcpy(out
, pPrintersW
, len
);
1153 while (id
< numentries
) {
1157 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1158 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1160 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1161 if (piW
->pDescription
) {
1162 piA
->pDescription
= ptr
;
1163 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1164 ptr
, outlen
, NULL
, NULL
);
1170 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1171 ptr
, outlen
, NULL
, NULL
);
1175 if (piW
->pComment
) {
1176 piA
->pComment
= ptr
;
1177 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1178 ptr
, outlen
, NULL
, NULL
);
1187 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1188 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1191 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1192 if (piW
->pServerName
) {
1193 piA
->pServerName
= ptr
;
1194 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1195 ptr
, outlen
, NULL
, NULL
);
1199 if (piW
->pPrinterName
) {
1200 piA
->pPrinterName
= ptr
;
1201 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1202 ptr
, outlen
, NULL
, NULL
);
1206 if (piW
->pShareName
) {
1207 piA
->pShareName
= ptr
;
1208 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1209 ptr
, outlen
, NULL
, NULL
);
1213 if (piW
->pPortName
) {
1214 piA
->pPortName
= ptr
;
1215 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1216 ptr
, outlen
, NULL
, NULL
);
1220 if (piW
->pDriverName
) {
1221 piA
->pDriverName
= ptr
;
1222 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1223 ptr
, outlen
, NULL
, NULL
);
1227 if (piW
->pComment
) {
1228 piA
->pComment
= ptr
;
1229 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1230 ptr
, outlen
, NULL
, NULL
);
1234 if (piW
->pLocation
) {
1235 piA
->pLocation
= ptr
;
1236 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1237 ptr
, outlen
, NULL
, NULL
);
1242 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1244 /* align DEVMODEA to a DWORD boundary */
1245 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1249 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1250 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1251 memcpy(ptr
, dmA
, len
);
1252 HeapFree(GetProcessHeap(), 0, dmA
);
1258 if (piW
->pSepFile
) {
1259 piA
->pSepFile
= ptr
;
1260 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1261 ptr
, outlen
, NULL
, NULL
);
1265 if (piW
->pPrintProcessor
) {
1266 piA
->pPrintProcessor
= ptr
;
1267 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1268 ptr
, outlen
, NULL
, NULL
);
1272 if (piW
->pDatatype
) {
1273 piA
->pDatatype
= ptr
;
1274 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1275 ptr
, outlen
, NULL
, NULL
);
1279 if (piW
->pParameters
) {
1280 piA
->pParameters
= ptr
;
1281 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1282 ptr
, outlen
, NULL
, NULL
);
1286 if (piW
->pSecurityDescriptor
) {
1287 piA
->pSecurityDescriptor
= NULL
;
1288 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1295 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1296 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1298 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1300 if (piW
->pPrinterName
) {
1301 piA
->pPrinterName
= ptr
;
1302 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1303 ptr
, outlen
, NULL
, NULL
);
1307 if (piW
->pServerName
) {
1308 piA
->pServerName
= ptr
;
1309 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1310 ptr
, outlen
, NULL
, NULL
);
1319 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1320 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1322 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1324 if (piW
->pPrinterName
) {
1325 piA
->pPrinterName
= ptr
;
1326 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1327 ptr
, outlen
, NULL
, NULL
);
1331 if (piW
->pPortName
) {
1332 piA
->pPortName
= ptr
;
1333 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1334 ptr
, outlen
, NULL
, NULL
);
1341 case 6: /* 6A and 6W are the same structure */
1346 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1347 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1349 TRACE("(%u) #%u\n", level
, id
);
1350 if (piW
->pszObjectGUID
) {
1351 piA
->pszObjectGUID
= ptr
;
1352 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1353 ptr
, outlen
, NULL
, NULL
);
1362 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1363 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1366 TRACE("(%u) #%u\n", level
, id
);
1367 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1369 /* align DEVMODEA to a DWORD boundary */
1370 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1374 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1375 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1376 memcpy(ptr
, dmA
, len
);
1377 HeapFree(GetProcessHeap(), 0, dmA
);
1387 FIXME("for level %u\n", level
);
1389 pPrintersW
+= pi_sizeof
[level
];
1390 out
+= pi_sizeof
[level
];
1395 /******************************************************************
1396 * convert_driverinfo_W_to_A [internal]
1399 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1400 DWORD level
, DWORD outlen
, DWORD numentries
)
1406 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1408 len
= di_sizeof
[level
] * numentries
;
1409 ptr
= (LPSTR
) out
+ len
;
1412 /* copy the numbers of all PRINTER_INFO_* first */
1413 memcpy(out
, pDriversW
, len
);
1415 #define COPY_STRING(fld) \
1418 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1419 ptr += len; outlen -= len;\
1421 #define COPY_MULTIZ_STRING(fld) \
1422 { LPWSTR p = diW->fld; if (p){ \
1425 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1426 ptr += len; outlen -= len; p += len;\
1428 while(len > 1 && outlen > 0); \
1431 while (id
< numentries
)
1437 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1438 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1440 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1447 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1448 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1450 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1453 COPY_STRING(pEnvironment
);
1454 COPY_STRING(pDriverPath
);
1455 COPY_STRING(pDataFile
);
1456 COPY_STRING(pConfigFile
);
1461 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1462 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1464 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1467 COPY_STRING(pEnvironment
);
1468 COPY_STRING(pDriverPath
);
1469 COPY_STRING(pDataFile
);
1470 COPY_STRING(pConfigFile
);
1471 COPY_STRING(pHelpFile
);
1472 COPY_MULTIZ_STRING(pDependentFiles
);
1473 COPY_STRING(pMonitorName
);
1474 COPY_STRING(pDefaultDataType
);
1479 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1480 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1482 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1485 COPY_STRING(pEnvironment
);
1486 COPY_STRING(pDriverPath
);
1487 COPY_STRING(pDataFile
);
1488 COPY_STRING(pConfigFile
);
1489 COPY_STRING(pHelpFile
);
1490 COPY_MULTIZ_STRING(pDependentFiles
);
1491 COPY_STRING(pMonitorName
);
1492 COPY_STRING(pDefaultDataType
);
1493 COPY_MULTIZ_STRING(pszzPreviousNames
);
1498 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1499 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1501 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1504 COPY_STRING(pEnvironment
);
1505 COPY_STRING(pDriverPath
);
1506 COPY_STRING(pDataFile
);
1507 COPY_STRING(pConfigFile
);
1512 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1513 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1515 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1518 COPY_STRING(pEnvironment
);
1519 COPY_STRING(pDriverPath
);
1520 COPY_STRING(pDataFile
);
1521 COPY_STRING(pConfigFile
);
1522 COPY_STRING(pHelpFile
);
1523 COPY_MULTIZ_STRING(pDependentFiles
);
1524 COPY_STRING(pMonitorName
);
1525 COPY_STRING(pDefaultDataType
);
1526 COPY_MULTIZ_STRING(pszzPreviousNames
);
1527 COPY_STRING(pszMfgName
);
1528 COPY_STRING(pszOEMUrl
);
1529 COPY_STRING(pszHardwareID
);
1530 COPY_STRING(pszProvider
);
1535 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1536 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1538 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1541 COPY_STRING(pEnvironment
);
1542 COPY_STRING(pDriverPath
);
1543 COPY_STRING(pDataFile
);
1544 COPY_STRING(pConfigFile
);
1545 COPY_STRING(pHelpFile
);
1546 COPY_MULTIZ_STRING(pDependentFiles
);
1547 COPY_STRING(pMonitorName
);
1548 COPY_STRING(pDefaultDataType
);
1549 COPY_MULTIZ_STRING(pszzPreviousNames
);
1550 COPY_STRING(pszMfgName
);
1551 COPY_STRING(pszOEMUrl
);
1552 COPY_STRING(pszHardwareID
);
1553 COPY_STRING(pszProvider
);
1554 COPY_STRING(pszPrintProcessor
);
1555 COPY_STRING(pszVendorSetup
);
1556 COPY_MULTIZ_STRING(pszzColorProfiles
);
1557 COPY_STRING(pszInfPath
);
1558 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1564 FIXME("for level %u\n", level
);
1567 pDriversW
+= di_sizeof
[level
];
1568 out
+= di_sizeof
[level
];
1573 #undef COPY_MULTIZ_STRING
1577 /***********************************************************
1578 * PRINTER_INFO_2AtoW
1579 * Creates a unicode copy of PRINTER_INFO_2A on heap
1581 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1583 LPPRINTER_INFO_2W piW
;
1584 UNICODE_STRING usBuffer
;
1586 if(!piA
) return NULL
;
1587 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1588 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1590 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1591 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1592 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1593 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1594 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1595 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1596 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1597 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1598 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1599 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1600 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1601 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1605 /***********************************************************
1606 * FREE_PRINTER_INFO_2W
1607 * Free PRINTER_INFO_2W and all strings
1609 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1613 HeapFree(heap
,0,piW
->pServerName
);
1614 HeapFree(heap
,0,piW
->pPrinterName
);
1615 HeapFree(heap
,0,piW
->pShareName
);
1616 HeapFree(heap
,0,piW
->pPortName
);
1617 HeapFree(heap
,0,piW
->pDriverName
);
1618 HeapFree(heap
,0,piW
->pComment
);
1619 HeapFree(heap
,0,piW
->pLocation
);
1620 HeapFree(heap
,0,piW
->pDevMode
);
1621 HeapFree(heap
,0,piW
->pSepFile
);
1622 HeapFree(heap
,0,piW
->pPrintProcessor
);
1623 HeapFree(heap
,0,piW
->pDatatype
);
1624 HeapFree(heap
,0,piW
->pParameters
);
1625 HeapFree(heap
,0,piW
);
1629 /******************************************************************
1630 * DeviceCapabilities [WINSPOOL.@]
1631 * DeviceCapabilitiesA [WINSPOOL.@]
1634 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1635 LPSTR pOutput
, LPDEVMODEA lpdm
)
1639 if (!GDI_CallDeviceCapabilities16
)
1641 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1643 if (!GDI_CallDeviceCapabilities16
) return -1;
1645 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1647 /* If DC_PAPERSIZE map POINT16s to POINTs */
1648 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1649 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1650 POINT
*pt
= (POINT
*)pOutput
;
1652 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1653 for(i
= 0; i
< ret
; i
++, pt
++)
1658 HeapFree( GetProcessHeap(), 0, tmp
);
1664 /*****************************************************************************
1665 * DeviceCapabilitiesW [WINSPOOL.@]
1667 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1670 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1671 WORD fwCapability
, LPWSTR pOutput
,
1672 const DEVMODEW
*pDevMode
)
1674 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1675 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1676 LPSTR pPortA
= strdupWtoA(pPort
);
1679 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1680 fwCapability
== DC_FILEDEPENDENCIES
||
1681 fwCapability
== DC_PAPERNAMES
)) {
1682 /* These need A -> W translation */
1685 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1689 switch(fwCapability
) {
1694 case DC_FILEDEPENDENCIES
:
1698 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1699 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1701 for(i
= 0; i
< ret
; i
++)
1702 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1703 pOutput
+ (i
* size
), size
);
1704 HeapFree(GetProcessHeap(), 0, pOutputA
);
1706 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1707 (LPSTR
)pOutput
, dmA
);
1709 HeapFree(GetProcessHeap(),0,pPortA
);
1710 HeapFree(GetProcessHeap(),0,pDeviceA
);
1711 HeapFree(GetProcessHeap(),0,dmA
);
1715 /******************************************************************
1716 * DocumentPropertiesA [WINSPOOL.@]
1718 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1720 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1721 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1722 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1724 LPSTR lpName
= pDeviceName
;
1725 static CHAR port
[] = "LPT1:";
1728 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1729 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1733 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1735 ERR("no name from hPrinter?\n");
1736 SetLastError(ERROR_INVALID_HANDLE
);
1739 lpName
= strdupWtoA(lpNameW
);
1742 if (!GDI_CallExtDeviceMode16
)
1744 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1746 if (!GDI_CallExtDeviceMode16
) {
1747 ERR("No CallExtDeviceMode16?\n");
1751 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1752 pDevModeInput
, NULL
, fMode
);
1755 HeapFree(GetProcessHeap(),0,lpName
);
1760 /*****************************************************************************
1761 * DocumentPropertiesW (WINSPOOL.@)
1763 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1765 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1767 LPDEVMODEW pDevModeOutput
,
1768 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1771 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1772 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1773 LPDEVMODEA pDevModeOutputA
= NULL
;
1776 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1777 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1779 if(pDevModeOutput
) {
1780 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1781 if(ret
< 0) return ret
;
1782 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1784 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1785 pDevModeInputA
, fMode
);
1786 if(pDevModeOutput
) {
1787 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1788 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1790 if(fMode
== 0 && ret
> 0)
1791 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1792 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1793 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1797 /*****************************************************************************
1798 * IsValidDevmodeA [WINSPOOL.@]
1800 * Validate a DEVMODE structure and fix errors if possible.
1803 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1805 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1813 /*****************************************************************************
1814 * IsValidDevmodeW [WINSPOOL.@]
1816 * Validate a DEVMODE structure and fix errors if possible.
1819 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1821 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1829 /******************************************************************
1830 * OpenPrinterA [WINSPOOL.@]
1835 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1836 LPPRINTER_DEFAULTSA pDefault
)
1838 UNICODE_STRING lpPrinterNameW
;
1839 UNICODE_STRING usBuffer
;
1840 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1841 PWSTR pwstrPrinterNameW
;
1844 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1847 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1848 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1849 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1850 pDefaultW
= &DefaultW
;
1852 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1854 RtlFreeUnicodeString(&usBuffer
);
1855 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1857 RtlFreeUnicodeString(&lpPrinterNameW
);
1861 /******************************************************************
1862 * OpenPrinterW [WINSPOOL.@]
1864 * Open a Printer / Printserver or a Printer-Object
1867 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1868 * phPrinter [O] The resulting Handle is stored here
1869 * pDefault [I] PTR to Default Printer Settings or NULL
1876 * lpPrinterName is one of:
1877 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1878 *| Printer: "PrinterName"
1879 *| Printer-Object: "PrinterName,Job xxx"
1880 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1881 *| XcvPort: "Servername,XcvPort PortName"
1884 *| Printer-Object not supported
1885 *| pDefaults is ignored
1888 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1891 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1893 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1894 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1898 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1899 SetLastError(ERROR_INVALID_PARAMETER
);
1903 /* Get the unique handle of the printer or Printserver */
1904 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1905 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1906 return (*phPrinter
!= 0);
1909 /******************************************************************
1910 * AddMonitorA [WINSPOOL.@]
1915 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1917 LPWSTR nameW
= NULL
;
1920 LPMONITOR_INFO_2A mi2a
;
1921 MONITOR_INFO_2W mi2w
;
1923 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1924 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1925 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1926 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1927 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1930 SetLastError(ERROR_INVALID_LEVEL
);
1934 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1940 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1941 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1942 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1945 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1947 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1948 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1949 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1951 if (mi2a
->pEnvironment
) {
1952 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1953 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1954 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1956 if (mi2a
->pDLLName
) {
1957 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1958 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1959 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1962 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1964 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1965 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1966 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1968 HeapFree(GetProcessHeap(), 0, nameW
);
1972 /******************************************************************************
1973 * AddMonitorW [WINSPOOL.@]
1975 * Install a Printmonitor
1978 * pName [I] Servername or NULL (local Computer)
1979 * Level [I] Structure-Level (Must be 2)
1980 * pMonitors [I] PTR to MONITOR_INFO_2
1987 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1990 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1992 LPMONITOR_INFO_2W mi2w
;
1994 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1995 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1996 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1997 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1998 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2000 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2003 SetLastError(ERROR_INVALID_LEVEL
);
2007 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2012 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2015 /******************************************************************
2016 * DeletePrinterDriverA [WINSPOOL.@]
2019 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2021 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2024 /******************************************************************
2025 * DeletePrinterDriverW [WINSPOOL.@]
2028 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2030 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2033 /******************************************************************
2034 * DeleteMonitorA [WINSPOOL.@]
2036 * See DeleteMonitorW.
2039 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2041 LPWSTR nameW
= NULL
;
2042 LPWSTR EnvironmentW
= NULL
;
2043 LPWSTR MonitorNameW
= NULL
;
2048 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2049 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2050 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2054 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2055 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2056 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2059 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2060 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2061 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2064 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2066 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2067 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2068 HeapFree(GetProcessHeap(), 0, nameW
);
2072 /******************************************************************
2073 * DeleteMonitorW [WINSPOOL.@]
2075 * Delete a specific Printmonitor from a Printing-Environment
2078 * pName [I] Servername or NULL (local Computer)
2079 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2080 * pMonitorName [I] Name of the Monitor, that should be deleted
2087 * pEnvironment is ignored in Windows for the local Computer.
2090 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2093 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2094 debugstr_w(pMonitorName
));
2096 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2098 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2102 /******************************************************************
2103 * DeletePortA [WINSPOOL.@]
2108 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2110 LPWSTR nameW
= NULL
;
2111 LPWSTR portW
= NULL
;
2115 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2117 /* convert servername to unicode */
2119 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2120 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2121 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2124 /* convert portname to unicode */
2126 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2127 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2128 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2131 res
= DeletePortW(nameW
, hWnd
, portW
);
2132 HeapFree(GetProcessHeap(), 0, nameW
);
2133 HeapFree(GetProcessHeap(), 0, portW
);
2137 /******************************************************************
2138 * DeletePortW [WINSPOOL.@]
2140 * Delete a specific Port
2143 * pName [I] Servername or NULL (local Computer)
2144 * hWnd [I] Handle to parent Window for the Dialog-Box
2145 * pPortName [I] Name of the Port, that should be deleted
2152 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2154 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2156 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2159 SetLastError(RPC_X_NULL_REF_POINTER
);
2163 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2166 /******************************************************************************
2167 * SetPrinterW [WINSPOOL.@]
2169 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2171 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2172 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2176 /******************************************************************************
2177 * WritePrinter [WINSPOOL.@]
2179 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2181 opened_printer_t
*printer
;
2184 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2186 EnterCriticalSection(&printer_handles_cs
);
2187 printer
= get_opened_printer(hPrinter
);
2190 SetLastError(ERROR_INVALID_HANDLE
);
2196 SetLastError(ERROR_SPL_NO_STARTDOC
);
2200 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2202 LeaveCriticalSection(&printer_handles_cs
);
2206 /*****************************************************************************
2207 * AddFormA [WINSPOOL.@]
2209 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2211 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2215 /*****************************************************************************
2216 * AddFormW [WINSPOOL.@]
2218 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2220 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2224 /*****************************************************************************
2225 * AddJobA [WINSPOOL.@]
2227 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2230 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2234 SetLastError(ERROR_INVALID_LEVEL
);
2238 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2241 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2242 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2243 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2244 if(*pcbNeeded
> cbBuf
) {
2245 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2248 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2249 addjobA
->JobId
= addjobW
->JobId
;
2250 addjobA
->Path
= (char *)(addjobA
+ 1);
2251 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2257 /*****************************************************************************
2258 * AddJobW [WINSPOOL.@]
2260 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2262 opened_printer_t
*printer
;
2265 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2266 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2267 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2269 ADDJOB_INFO_1W
*addjob
;
2271 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2273 EnterCriticalSection(&printer_handles_cs
);
2275 printer
= get_opened_printer(hPrinter
);
2278 SetLastError(ERROR_INVALID_HANDLE
);
2283 SetLastError(ERROR_INVALID_LEVEL
);
2287 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2291 job
->job_id
= InterlockedIncrement(&next_job_id
);
2293 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2294 if(path
[len
- 1] != '\\')
2296 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2297 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2299 len
= strlenW(filename
);
2300 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2301 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2302 job
->document_title
= strdupW(default_doc_title
);
2303 job
->printer_name
= strdupW(printer
->name
);
2304 job
->devmode
= NULL
;
2305 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2307 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2308 if(*pcbNeeded
<= cbBuf
) {
2309 addjob
= (ADDJOB_INFO_1W
*)pData
;
2310 addjob
->JobId
= job
->job_id
;
2311 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2312 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2315 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2318 LeaveCriticalSection(&printer_handles_cs
);
2322 /*****************************************************************************
2323 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2325 * Return the PATH for the Print-Processors
2327 * See GetPrintProcessorDirectoryW.
2331 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2332 DWORD level
, LPBYTE Info
,
2333 DWORD cbBuf
, LPDWORD pcbNeeded
)
2335 LPWSTR serverW
= NULL
;
2340 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2341 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2345 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2346 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2347 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2351 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2352 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2353 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2356 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2357 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2359 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2362 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2363 cbBuf
, NULL
, NULL
) > 0;
2366 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2367 HeapFree(GetProcessHeap(), 0, envW
);
2368 HeapFree(GetProcessHeap(), 0, serverW
);
2372 /*****************************************************************************
2373 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2375 * Return the PATH for the Print-Processors
2378 * server [I] Servername (NT only) or NULL (local Computer)
2379 * env [I] Printing-Environment (see below) or NULL (Default)
2380 * level [I] Structure-Level (must be 1)
2381 * Info [O] PTR to Buffer that receives the Result
2382 * cbBuf [I] Size of Buffer at "Info"
2383 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2384 * required for the Buffer at "Info"
2387 * Success: TRUE and in pcbNeeded the Bytes used in Info
2388 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2389 * if cbBuf is too small
2391 * Native Values returned in Info on Success:
2392 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2393 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2394 *| win9x(Windows 4.0): "%winsysdir%"
2396 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2399 * Only NULL or "" is supported for server
2402 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2403 DWORD level
, LPBYTE Info
,
2404 DWORD cbBuf
, LPDWORD pcbNeeded
)
2407 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2408 Info
, cbBuf
, pcbNeeded
);
2410 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2413 /* (Level != 1) is ignored in win9x */
2414 SetLastError(ERROR_INVALID_LEVEL
);
2418 if (pcbNeeded
== NULL
) {
2419 /* (pcbNeeded == NULL) is ignored in win9x */
2420 SetLastError(RPC_X_NULL_REF_POINTER
);
2424 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2427 /*****************************************************************************
2428 * WINSPOOL_OpenDriverReg [internal]
2430 * opens the registry for the printer drivers depending on the given input
2431 * variable pEnvironment
2434 * the opened hkey on success
2437 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2441 const printenv_t
* env
;
2443 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2445 env
= validate_envW(pEnvironment
);
2446 if (!env
) return NULL
;
2448 buffer
= HeapAlloc( GetProcessHeap(), 0,
2449 (strlenW(DriversW
) + strlenW(env
->envname
) +
2450 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2452 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2453 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2454 HeapFree(GetProcessHeap(), 0, buffer
);
2459 /*****************************************************************************
2460 * set_devices_and_printerports [internal]
2462 * set the [Devices] and [PrinterPorts] entries for a printer.
2465 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2467 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2471 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2473 /* FIXME: the driver must change to "winspool" */
2474 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2476 lstrcpyW(devline
, driver_nt
);
2477 lstrcatW(devline
, commaW
);
2478 lstrcatW(devline
, pi
->pPortName
);
2480 TRACE("using %s\n", debugstr_w(devline
));
2481 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2482 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2483 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2484 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2488 lstrcatW(devline
, timeout_15_45
);
2489 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2490 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2491 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2492 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2495 HeapFree(GetProcessHeap(), 0, devline
);
2499 /*****************************************************************************
2500 * AddPrinterW [WINSPOOL.@]
2502 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2504 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2508 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2510 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2511 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2512 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2513 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2514 statusW
[] = {'S','t','a','t','u','s',0},
2515 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2517 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2520 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2521 SetLastError(ERROR_INVALID_PARAMETER
);
2525 ERR("Level = %d, unsupported!\n", Level
);
2526 SetLastError(ERROR_INVALID_LEVEL
);
2530 SetLastError(ERROR_INVALID_PARAMETER
);
2533 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2535 ERR("Can't create Printers key\n");
2538 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2539 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2540 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2541 RegCloseKey(hkeyPrinter
);
2542 RegCloseKey(hkeyPrinters
);
2545 RegCloseKey(hkeyPrinter
);
2547 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2549 ERR("Can't create Drivers key\n");
2550 RegCloseKey(hkeyPrinters
);
2553 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2555 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2556 RegCloseKey(hkeyPrinters
);
2557 RegCloseKey(hkeyDrivers
);
2558 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2561 RegCloseKey(hkeyDriver
);
2562 RegCloseKey(hkeyDrivers
);
2564 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2565 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2566 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2567 RegCloseKey(hkeyPrinters
);
2571 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2573 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2574 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2575 RegCloseKey(hkeyPrinters
);
2579 set_devices_and_printerports(pi
);
2580 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2581 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2582 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2584 /* See if we can load the driver. We may need the devmode structure anyway
2587 * Note that DocumentPropertiesW will briefly try to open the printer we
2588 * just create to find a DEVMODEA struct (it will use the WINEPS default
2589 * one in case it is not there, so we are ok).
2591 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2594 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2595 size
= sizeof(DEVMODEW
);
2601 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2603 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2605 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2606 HeapFree(GetProcessHeap(),0,dmW
);
2611 /* set devmode to printer name */
2612 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2616 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2617 and we support these drivers. NT writes DEVMODEW so somehow
2618 we'll need to distinguish between these when we support NT
2622 dmA
= DEVMODEdupWtoA(dmW
);
2623 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2624 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2625 HeapFree(GetProcessHeap(), 0, dmA
);
2627 HeapFree(GetProcessHeap(), 0, dmW
);
2629 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2630 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2631 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2632 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2634 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2635 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2636 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2637 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2638 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2639 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2640 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2641 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2642 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2643 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2644 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2645 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2646 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2648 RegCloseKey(hkeyPrinter
);
2649 RegCloseKey(hkeyPrinters
);
2650 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2651 ERR("OpenPrinter failing\n");
2657 /*****************************************************************************
2658 * AddPrinterA [WINSPOOL.@]
2660 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2662 UNICODE_STRING pNameW
;
2664 PRINTER_INFO_2W
*piW
;
2665 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2668 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2670 ERR("Level = %d, unsupported!\n", Level
);
2671 SetLastError(ERROR_INVALID_LEVEL
);
2674 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2675 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2677 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2679 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2680 RtlFreeUnicodeString(&pNameW
);
2685 /*****************************************************************************
2686 * ClosePrinter [WINSPOOL.@]
2688 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2690 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2691 opened_printer_t
*printer
= NULL
;
2694 TRACE("(%p)\n", hPrinter
);
2696 EnterCriticalSection(&printer_handles_cs
);
2698 if ((i
> 0) && (i
<= nb_printer_handles
))
2699 printer
= printer_handles
[i
- 1];
2704 struct list
*cursor
, *cursor2
;
2706 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2708 if (printer
->backend_printer
) {
2709 backend
->fpClosePrinter(printer
->backend_printer
);
2713 EndDocPrinter(hPrinter
);
2715 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2717 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2719 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2720 ScheduleJob(hPrinter
, job
->job_id
);
2722 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2725 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2726 HeapFree(GetProcessHeap(), 0, printer
->name
);
2727 HeapFree(GetProcessHeap(), 0, printer
);
2728 printer_handles
[i
- 1] = NULL
;
2731 LeaveCriticalSection(&printer_handles_cs
);
2735 /*****************************************************************************
2736 * DeleteFormA [WINSPOOL.@]
2738 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2740 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2744 /*****************************************************************************
2745 * DeleteFormW [WINSPOOL.@]
2747 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2749 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2753 /*****************************************************************************
2754 * DeletePrinter [WINSPOOL.@]
2756 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2758 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2759 HKEY hkeyPrinters
, hkey
;
2762 SetLastError(ERROR_INVALID_HANDLE
);
2765 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2766 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2767 RegCloseKey(hkeyPrinters
);
2769 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2770 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2772 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2773 RegDeleteValueW(hkey
, lpNameW
);
2777 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2778 RegDeleteValueW(hkey
, lpNameW
);
2784 /*****************************************************************************
2785 * SetPrinterA [WINSPOOL.@]
2787 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2790 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2794 /*****************************************************************************
2795 * SetJobA [WINSPOOL.@]
2797 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2798 LPBYTE pJob
, DWORD Command
)
2802 UNICODE_STRING usBuffer
;
2804 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2806 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2807 are all ignored by SetJob, so we don't bother copying them */
2815 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2816 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2818 JobW
= (LPBYTE
)info1W
;
2819 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2820 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2821 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2822 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2823 info1W
->Status
= info1A
->Status
;
2824 info1W
->Priority
= info1A
->Priority
;
2825 info1W
->Position
= info1A
->Position
;
2826 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2831 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2832 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2834 JobW
= (LPBYTE
)info2W
;
2835 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2836 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2837 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2838 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2839 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2840 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2841 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2842 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2843 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2844 info2W
->Status
= info2A
->Status
;
2845 info2W
->Priority
= info2A
->Priority
;
2846 info2W
->Position
= info2A
->Position
;
2847 info2W
->StartTime
= info2A
->StartTime
;
2848 info2W
->UntilTime
= info2A
->UntilTime
;
2849 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2853 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2854 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2857 SetLastError(ERROR_INVALID_LEVEL
);
2861 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2867 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2868 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2869 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2870 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2871 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2876 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2877 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2878 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2879 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2880 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2881 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2882 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2883 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2884 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2888 HeapFree(GetProcessHeap(), 0, JobW
);
2893 /*****************************************************************************
2894 * SetJobW [WINSPOOL.@]
2896 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2897 LPBYTE pJob
, DWORD Command
)
2902 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2903 FIXME("Ignoring everything other than document title\n");
2905 EnterCriticalSection(&printer_handles_cs
);
2906 job
= get_job(hPrinter
, JobId
);
2916 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2917 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2918 job
->document_title
= strdupW(info1
->pDocument
);
2923 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2924 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2925 job
->document_title
= strdupW(info2
->pDocument
);
2926 HeapFree(GetProcessHeap(), 0, job
->devmode
);
2927 job
->devmode
= dup_devmode( info2
->pDevMode
);
2933 SetLastError(ERROR_INVALID_LEVEL
);
2938 LeaveCriticalSection(&printer_handles_cs
);
2942 /*****************************************************************************
2943 * EndDocPrinter [WINSPOOL.@]
2945 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2947 opened_printer_t
*printer
;
2949 TRACE("(%p)\n", hPrinter
);
2951 EnterCriticalSection(&printer_handles_cs
);
2953 printer
= get_opened_printer(hPrinter
);
2956 SetLastError(ERROR_INVALID_HANDLE
);
2962 SetLastError(ERROR_SPL_NO_STARTDOC
);
2966 CloseHandle(printer
->doc
->hf
);
2967 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2968 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2969 printer
->doc
= NULL
;
2972 LeaveCriticalSection(&printer_handles_cs
);
2976 /*****************************************************************************
2977 * EndPagePrinter [WINSPOOL.@]
2979 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2981 FIXME("(%p): stub\n", hPrinter
);
2985 /*****************************************************************************
2986 * StartDocPrinterA [WINSPOOL.@]
2988 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2990 UNICODE_STRING usBuffer
;
2992 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2995 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2996 or one (DOC_INFO_3) extra DWORDs */
3000 doc2W
.JobId
= doc2
->JobId
;
3003 doc2W
.dwMode
= doc2
->dwMode
;
3006 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3007 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3008 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3012 SetLastError(ERROR_INVALID_LEVEL
);
3016 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3018 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3019 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3020 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3025 /*****************************************************************************
3026 * StartDocPrinterW [WINSPOOL.@]
3028 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3030 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3031 opened_printer_t
*printer
;
3032 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3033 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3034 JOB_INFO_1W job_info
;
3035 DWORD needed
, ret
= 0;
3040 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3041 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3042 debugstr_w(doc
->pDatatype
));
3044 if(Level
< 1 || Level
> 3)
3046 SetLastError(ERROR_INVALID_LEVEL
);
3050 EnterCriticalSection(&printer_handles_cs
);
3051 printer
= get_opened_printer(hPrinter
);
3054 SetLastError(ERROR_INVALID_HANDLE
);
3060 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3064 /* Even if we're printing to a file we still add a print job, we'll
3065 just ignore the spool file name */
3067 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3069 ERR("AddJob failed gle %u\n", GetLastError());
3073 /* use pOutputFile only, when it is a real filename */
3074 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3075 filename
= doc
->pOutputFile
;
3077 filename
= addjob
->Path
;
3079 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3080 if(hf
== INVALID_HANDLE_VALUE
)
3083 memset(&job_info
, 0, sizeof(job_info
));
3084 job_info
.pDocument
= doc
->pDocName
;
3085 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3087 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3088 printer
->doc
->hf
= hf
;
3089 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3090 job
= get_job(hPrinter
, ret
);
3091 job
->portname
= strdupW(doc
->pOutputFile
);
3094 LeaveCriticalSection(&printer_handles_cs
);
3099 /*****************************************************************************
3100 * StartPagePrinter [WINSPOOL.@]
3102 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3104 FIXME("(%p): stub\n", hPrinter
);
3108 /*****************************************************************************
3109 * GetFormA [WINSPOOL.@]
3111 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3112 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3114 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3115 Level
,pForm
,cbBuf
,pcbNeeded
);
3119 /*****************************************************************************
3120 * GetFormW [WINSPOOL.@]
3122 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3123 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3125 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3126 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3130 /*****************************************************************************
3131 * SetFormA [WINSPOOL.@]
3133 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3136 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3140 /*****************************************************************************
3141 * SetFormW [WINSPOOL.@]
3143 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3146 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3150 /*****************************************************************************
3151 * ReadPrinter [WINSPOOL.@]
3153 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3154 LPDWORD pNoBytesRead
)
3156 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3160 /*****************************************************************************
3161 * ResetPrinterA [WINSPOOL.@]
3163 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3165 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3169 /*****************************************************************************
3170 * ResetPrinterW [WINSPOOL.@]
3172 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3174 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3178 /*****************************************************************************
3179 * WINSPOOL_GetDWORDFromReg
3181 * Return DWORD associated with ValueName from hkey.
3183 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3185 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3188 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3190 if(ret
!= ERROR_SUCCESS
) {
3191 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3194 if(type
!= REG_DWORD
) {
3195 ERR("Got type %d\n", type
);
3202 /*****************************************************************************
3203 * get_filename_from_reg [internal]
3205 * Get ValueName from hkey storing result in out
3206 * when the Value in the registry has only a filename, use driverdir as prefix
3207 * outlen is space left in out
3208 * String is stored either as unicode or ascii
3212 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3213 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3215 WCHAR filename
[MAX_PATH
];
3219 LPWSTR buffer
= filename
;
3223 size
= sizeof(filename
);
3225 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3226 if (ret
== ERROR_MORE_DATA
) {
3227 TRACE("need dynamic buffer: %u\n", size
);
3228 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3230 /* No Memory is bad */
3234 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3237 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3238 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3244 /* do we have a full path ? */
3245 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3246 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3249 /* we must build the full Path */
3251 if ((out
) && (outlen
> dirlen
)) {
3252 lstrcpyW((LPWSTR
)out
, driverdir
);
3260 /* write the filename */
3261 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3262 if ((out
) && (outlen
>= size
)) {
3263 lstrcpyW((LPWSTR
)out
, ptr
);
3270 ptr
+= lstrlenW(ptr
)+1;
3271 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3274 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3276 /* write the multisz-termination */
3277 if (type
== REG_MULTI_SZ
) {
3278 size
= sizeof(WCHAR
);
3281 if (out
&& (outlen
>= size
)) {
3282 memset (out
, 0, size
);
3288 /*****************************************************************************
3289 * WINSPOOL_GetStringFromReg
3291 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3292 * String is stored as unicode.
3294 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3295 DWORD buflen
, DWORD
*needed
)
3297 DWORD sz
= buflen
, type
;
3300 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3301 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3302 WARN("Got ret = %d\n", ret
);
3306 /* add space for terminating '\0' */
3307 sz
+= sizeof(WCHAR
);
3311 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3316 /*****************************************************************************
3317 * WINSPOOL_GetDefaultDevMode
3319 * Get a default DevMode values for wineps.
3323 static void WINSPOOL_GetDefaultDevMode(
3325 DWORD buflen
, DWORD
*needed
)
3328 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3330 /* fill default DEVMODE - should be read from ppd... */
3331 ZeroMemory( &dm
, sizeof(dm
) );
3332 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3333 dm
.dmSpecVersion
= DM_SPECVERSION
;
3334 dm
.dmDriverVersion
= 1;
3335 dm
.dmSize
= sizeof(DEVMODEW
);
3336 dm
.dmDriverExtra
= 0;
3338 DM_ORIENTATION
| DM_PAPERSIZE
|
3339 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3342 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3343 DM_YRESOLUTION
| DM_TTOPTION
;
3345 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3346 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3347 dm
.u1
.s1
.dmPaperLength
= 2970;
3348 dm
.u1
.s1
.dmPaperWidth
= 2100;
3350 dm
.u1
.s1
.dmScale
= 100;
3351 dm
.u1
.s1
.dmCopies
= 1;
3352 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3353 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3356 dm
.dmYResolution
= 300; /* 300dpi */
3357 dm
.dmTTOption
= DMTT_BITMAP
;
3360 /* dm.dmLogPixels */
3361 /* dm.dmBitsPerPel */
3362 /* dm.dmPelsWidth */
3363 /* dm.dmPelsHeight */
3364 /* dm.u2.dmDisplayFlags */
3365 /* dm.dmDisplayFrequency */
3366 /* dm.dmICMMethod */
3367 /* dm.dmICMIntent */
3368 /* dm.dmMediaType */
3369 /* dm.dmDitherType */
3370 /* dm.dmReserved1 */
3371 /* dm.dmReserved2 */
3372 /* dm.dmPanningWidth */
3373 /* dm.dmPanningHeight */
3375 if(buflen
>= sizeof(DEVMODEW
))
3376 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3377 *needed
= sizeof(DEVMODEW
);
3380 /*****************************************************************************
3381 * WINSPOOL_GetDevModeFromReg
3383 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3384 * DevMode is stored either as unicode or ascii.
3386 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3388 DWORD buflen
, DWORD
*needed
)
3390 DWORD sz
= buflen
, type
;
3393 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3394 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3395 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3396 if (sz
< sizeof(DEVMODEA
))
3398 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3401 /* ensures that dmSize is not erratically bogus if registry is invalid */
3402 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3403 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3404 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3405 if (ptr
&& (buflen
>= sz
)) {
3406 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3407 memcpy(ptr
, dmW
, sz
);
3408 HeapFree(GetProcessHeap(),0,dmW
);
3414 /*********************************************************************
3415 * WINSPOOL_GetPrinter_1
3417 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3419 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3420 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3422 DWORD size
, left
= cbBuf
;
3423 BOOL space
= (cbBuf
> 0);
3428 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3429 if(space
&& size
<= left
) {
3430 pi1
->pName
= (LPWSTR
)ptr
;
3438 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3440 if(space
&& size
<= left
) {
3441 pi1
->pDescription
= (LPWSTR
)ptr
;
3449 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3450 if(space
&& size
<= left
) {
3451 pi1
->pComment
= (LPWSTR
)ptr
;
3459 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3461 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3462 memset(pi1
, 0, sizeof(*pi1
));
3466 /*********************************************************************
3467 * WINSPOOL_GetPrinter_2
3469 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3471 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3472 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3474 DWORD size
, left
= cbBuf
;
3475 BOOL space
= (cbBuf
> 0);
3480 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3481 if(space
&& size
<= left
) {
3482 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3490 if(space
&& size
<= left
) {
3491 pi2
->pShareName
= (LPWSTR
)ptr
;
3498 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3499 if(space
&& size
<= left
) {
3500 pi2
->pPortName
= (LPWSTR
)ptr
;
3507 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3508 if(space
&& size
<= left
) {
3509 pi2
->pDriverName
= (LPWSTR
)ptr
;
3516 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3517 if(space
&& size
<= left
) {
3518 pi2
->pComment
= (LPWSTR
)ptr
;
3525 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3526 if(space
&& size
<= left
) {
3527 pi2
->pLocation
= (LPWSTR
)ptr
;
3534 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3535 if(space
&& size
<= left
) {
3536 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3545 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3546 if(space
&& size
<= left
) {
3547 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3554 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3555 if(space
&& size
<= left
) {
3556 pi2
->pSepFile
= (LPWSTR
)ptr
;
3563 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3564 if(space
&& size
<= left
) {
3565 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3572 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3573 if(space
&& size
<= left
) {
3574 pi2
->pDatatype
= (LPWSTR
)ptr
;
3581 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3582 if(space
&& size
<= left
) {
3583 pi2
->pParameters
= (LPWSTR
)ptr
;
3591 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3592 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3593 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3594 "Default Priority");
3595 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3596 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3599 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3600 memset(pi2
, 0, sizeof(*pi2
));
3605 /*********************************************************************
3606 * WINSPOOL_GetPrinter_4
3608 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3610 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3611 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3613 DWORD size
, left
= cbBuf
;
3614 BOOL space
= (cbBuf
> 0);
3619 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3620 if(space
&& size
<= left
) {
3621 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3629 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3632 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3633 memset(pi4
, 0, sizeof(*pi4
));
3638 /*********************************************************************
3639 * WINSPOOL_GetPrinter_5
3641 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3643 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3644 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3646 DWORD size
, left
= cbBuf
;
3647 BOOL space
= (cbBuf
> 0);
3652 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3653 if(space
&& size
<= left
) {
3654 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3661 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3662 if(space
&& size
<= left
) {
3663 pi5
->pPortName
= (LPWSTR
)ptr
;
3671 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3672 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3674 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3678 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3679 memset(pi5
, 0, sizeof(*pi5
));
3684 /*********************************************************************
3685 * WINSPOOL_GetPrinter_7
3687 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3689 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3690 DWORD cbBuf
, LPDWORD pcbNeeded
)
3692 DWORD size
, left
= cbBuf
;
3693 BOOL space
= (cbBuf
> 0);
3698 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3701 size
= sizeof(pi7
->pszObjectGUID
);
3703 if (space
&& size
<= left
) {
3704 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3711 /* We do not have a Directory Service */
3712 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3715 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3716 memset(pi7
, 0, sizeof(*pi7
));
3721 /*********************************************************************
3722 * WINSPOOL_GetPrinter_9
3724 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3726 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3727 DWORD cbBuf
, LPDWORD pcbNeeded
)
3730 BOOL space
= (cbBuf
> 0);
3734 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3735 if(space
&& size
<= cbBuf
) {
3736 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3743 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3744 if(space
&& size
<= cbBuf
) {
3745 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3751 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3752 memset(pi9
, 0, sizeof(*pi9
));
3757 /*****************************************************************************
3758 * GetPrinterW [WINSPOOL.@]
3760 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3761 DWORD cbBuf
, LPDWORD pcbNeeded
)
3764 DWORD size
, needed
= 0;
3766 HKEY hkeyPrinter
, hkeyPrinters
;
3769 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3771 if (!(name
= get_opened_printer_name(hPrinter
))) {
3772 SetLastError(ERROR_INVALID_HANDLE
);
3776 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3778 ERR("Can't create Printers key\n");
3781 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3783 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3784 RegCloseKey(hkeyPrinters
);
3785 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3792 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3794 size
= sizeof(PRINTER_INFO_2W
);
3796 ptr
= pPrinter
+ size
;
3798 memset(pPrinter
, 0, size
);
3803 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3810 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3812 size
= sizeof(PRINTER_INFO_4W
);
3814 ptr
= pPrinter
+ size
;
3816 memset(pPrinter
, 0, size
);
3821 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3829 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3831 size
= sizeof(PRINTER_INFO_5W
);
3833 ptr
= pPrinter
+ size
;
3835 memset(pPrinter
, 0, size
);
3841 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3849 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3851 size
= sizeof(PRINTER_INFO_6
);
3852 if (size
<= cbBuf
) {
3853 /* FIXME: We do not update the status yet */
3854 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3866 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3868 size
= sizeof(PRINTER_INFO_7W
);
3869 if (size
<= cbBuf
) {
3870 ptr
= pPrinter
+ size
;
3872 memset(pPrinter
, 0, size
);
3878 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3886 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3888 size
= sizeof(PRINTER_INFO_9W
);
3890 ptr
= pPrinter
+ size
;
3892 memset(pPrinter
, 0, size
);
3898 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3905 FIXME("Unimplemented level %d\n", Level
);
3906 SetLastError(ERROR_INVALID_LEVEL
);
3907 RegCloseKey(hkeyPrinters
);
3908 RegCloseKey(hkeyPrinter
);
3912 RegCloseKey(hkeyPrinter
);
3913 RegCloseKey(hkeyPrinters
);
3915 TRACE("returning %d needed = %d\n", ret
, needed
);
3916 if(pcbNeeded
) *pcbNeeded
= needed
;
3918 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3922 /*****************************************************************************
3923 * GetPrinterA [WINSPOOL.@]
3925 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3926 DWORD cbBuf
, LPDWORD pcbNeeded
)
3932 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3934 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3936 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3937 HeapFree(GetProcessHeap(), 0, buf
);
3942 /*****************************************************************************
3943 * WINSPOOL_EnumPrintersW
3945 * Implementation of EnumPrintersW
3947 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3948 DWORD dwLevel
, LPBYTE lpbPrinters
,
3949 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3950 LPDWORD lpdwReturned
)
3953 HKEY hkeyPrinters
, hkeyPrinter
;
3954 WCHAR PrinterName
[255];
3955 DWORD needed
= 0, number
= 0;
3956 DWORD used
, i
, left
;
3960 memset(lpbPrinters
, 0, cbBuf
);
3966 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3967 if(dwType
== PRINTER_ENUM_DEFAULT
)
3970 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3971 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3972 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3974 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3980 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3981 FIXME("dwType = %08x\n", dwType
);
3982 SetLastError(ERROR_INVALID_FLAGS
);
3986 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3988 ERR("Can't create Printers key\n");
3992 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3993 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3994 RegCloseKey(hkeyPrinters
);
3995 ERR("Can't query Printers key\n");
3998 TRACE("Found %d printers\n", number
);
4002 used
= number
* sizeof(PRINTER_INFO_1W
);
4005 used
= number
* sizeof(PRINTER_INFO_2W
);
4008 used
= number
* sizeof(PRINTER_INFO_4W
);
4011 used
= number
* sizeof(PRINTER_INFO_5W
);
4015 SetLastError(ERROR_INVALID_LEVEL
);
4016 RegCloseKey(hkeyPrinters
);
4019 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4021 for(i
= 0; i
< number
; i
++) {
4022 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4024 ERR("Can't enum key number %d\n", i
);
4025 RegCloseKey(hkeyPrinters
);
4028 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4029 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4031 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4032 RegCloseKey(hkeyPrinters
);
4037 buf
= lpbPrinters
+ used
;
4038 left
= cbBuf
- used
;
4046 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4049 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4052 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4055 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4058 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4061 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4064 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4067 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4070 ERR("Shouldn't be here!\n");
4071 RegCloseKey(hkeyPrinter
);
4072 RegCloseKey(hkeyPrinters
);
4075 RegCloseKey(hkeyPrinter
);
4077 RegCloseKey(hkeyPrinters
);
4084 memset(lpbPrinters
, 0, cbBuf
);
4085 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4089 *lpdwReturned
= number
;
4090 SetLastError(ERROR_SUCCESS
);
4095 /******************************************************************
4096 * EnumPrintersW [WINSPOOL.@]
4098 * Enumerates the available printers, print servers and print
4099 * providers, depending on the specified flags, name and level.
4103 * If level is set to 1:
4104 * Returns an array of PRINTER_INFO_1 data structures in the
4105 * lpbPrinters buffer.
4107 * If level is set to 2:
4108 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4109 * Returns an array of PRINTER_INFO_2 data structures in the
4110 * lpbPrinters buffer. Note that according to MSDN also an
4111 * OpenPrinter should be performed on every remote printer.
4113 * If level is set to 4 (officially WinNT only):
4114 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4115 * Fast: Only the registry is queried to retrieve printer names,
4116 * no connection to the driver is made.
4117 * Returns an array of PRINTER_INFO_4 data structures in the
4118 * lpbPrinters buffer.
4120 * If level is set to 5 (officially WinNT4/Win9x only):
4121 * Fast: Only the registry is queried to retrieve printer names,
4122 * no connection to the driver is made.
4123 * Returns an array of PRINTER_INFO_5 data structures in the
4124 * lpbPrinters buffer.
4126 * If level set to 3 or 6+:
4127 * returns zero (failure!)
4129 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4133 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4134 * - Only levels 2, 4 and 5 are implemented at the moment.
4135 * - 16-bit printer drivers are not enumerated.
4136 * - Returned amount of bytes used/needed does not match the real Windoze
4137 * implementation (as in this implementation, all strings are part
4138 * of the buffer, whereas Win32 keeps them somewhere else)
4139 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4142 * - In a regular Wine installation, no registry settings for printers
4143 * exist, which makes this function return an empty list.
4145 BOOL WINAPI
EnumPrintersW(
4146 DWORD dwType
, /* [in] Types of print objects to enumerate */
4147 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4148 DWORD dwLevel
, /* [in] type of printer info structure */
4149 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4150 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4151 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4152 LPDWORD lpdwReturned
/* [out] number of entries returned */
4155 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4156 lpdwNeeded
, lpdwReturned
);
4159 /******************************************************************
4160 * EnumPrintersA [WINSPOOL.@]
4165 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4166 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4169 UNICODE_STRING pNameU
;
4173 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4174 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4176 pNameW
= asciitounicode(&pNameU
, pName
);
4178 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4179 MS Office need this */
4180 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4182 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4184 RtlFreeUnicodeString(&pNameU
);
4186 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4188 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4192 /*****************************************************************************
4193 * WINSPOOL_GetDriverInfoFromReg [internal]
4195 * Enters the information from the registry into the DRIVER_INFO struct
4198 * zero if the printer driver does not exist in the registry
4199 * (only if Level > 1) otherwise nonzero
4201 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4204 const printenv_t
* env
,
4206 LPBYTE ptr
, /* DRIVER_INFO */
4207 LPBYTE pDriverStrings
, /* strings buffer */
4208 DWORD cbBuf
, /* size of string buffer */
4209 LPDWORD pcbNeeded
) /* space needed for str. */
4213 WCHAR driverdir
[MAX_PATH
];
4215 LPBYTE strPtr
= pDriverStrings
;
4216 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4218 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4219 debugstr_w(DriverName
), env
,
4220 Level
, di
, pDriverStrings
, cbBuf
);
4222 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4224 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4225 if (*pcbNeeded
<= cbBuf
)
4226 strcpyW((LPWSTR
)strPtr
, DriverName
);
4228 /* pName for level 1 has a different offset! */
4230 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4234 /* .cVersion and .pName for level > 1 */
4236 di
->cVersion
= env
->driverversion
;
4237 di
->pName
= (LPWSTR
) strPtr
;
4238 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4241 /* Reserve Space for the largest subdir and a Backslash*/
4242 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4243 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4244 /* Should never Fail */
4247 lstrcatW(driverdir
, env
->versionsubdir
);
4248 lstrcatW(driverdir
, backslashW
);
4250 /* dirlen must not include the terminating zero */
4251 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4253 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4254 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4255 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4260 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4263 if (*pcbNeeded
<= cbBuf
) {
4264 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4265 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4266 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4269 /* .pDriverPath is the Graphics rendering engine.
4270 The full Path is required to avoid a crash in some apps */
4271 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4273 if (*pcbNeeded
<= cbBuf
)
4274 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4276 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4277 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4280 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4281 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4283 if (*pcbNeeded
<= cbBuf
)
4284 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4286 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4287 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4290 /* .pConfigFile is the Driver user Interface */
4291 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4293 if (*pcbNeeded
<= cbBuf
)
4294 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4296 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4297 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4301 RegCloseKey(hkeyDriver
);
4302 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4307 RegCloseKey(hkeyDriver
);
4308 FIXME("level 5: incomplete\n");
4313 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4315 if (*pcbNeeded
<= cbBuf
)
4316 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4318 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4319 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4322 /* .pDependentFiles */
4323 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4325 if (*pcbNeeded
<= cbBuf
)
4326 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4328 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4329 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4331 else if (GetVersion() & 0x80000000) {
4332 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4333 size
= 2 * sizeof(WCHAR
);
4335 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4337 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4338 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4341 /* .pMonitorName is the optional Language Monitor */
4342 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4344 if (*pcbNeeded
<= cbBuf
)
4345 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4347 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4348 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4351 /* .pDefaultDataType */
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4354 if(*pcbNeeded
<= cbBuf
)
4355 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4357 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4358 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4362 RegCloseKey(hkeyDriver
);
4363 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4367 /* .pszzPreviousNames */
4368 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4370 if(*pcbNeeded
<= cbBuf
)
4371 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4373 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4374 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4378 RegCloseKey(hkeyDriver
);
4379 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4383 /* support is missing, but not important enough for a FIXME */
4384 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4387 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4389 if(*pcbNeeded
<= cbBuf
)
4390 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4392 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4393 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4397 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4399 if(*pcbNeeded
<= cbBuf
)
4400 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4402 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4403 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4406 /* .pszHardwareID */
4407 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4409 if(*pcbNeeded
<= cbBuf
)
4410 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4412 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4413 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4417 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4419 if(*pcbNeeded
<= cbBuf
)
4420 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4422 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4423 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4427 RegCloseKey(hkeyDriver
);
4431 /* support is missing, but not important enough for a FIXME */
4432 TRACE("level 8: incomplete\n");
4434 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4435 RegCloseKey(hkeyDriver
);
4439 /*****************************************************************************
4440 * GetPrinterDriverW [WINSPOOL.@]
4442 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4443 DWORD Level
, LPBYTE pDriverInfo
,
4444 DWORD cbBuf
, LPDWORD pcbNeeded
)
4447 WCHAR DriverName
[100];
4448 DWORD ret
, type
, size
, needed
= 0;
4450 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4451 const printenv_t
* env
;
4453 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4454 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4457 ZeroMemory(pDriverInfo
, cbBuf
);
4459 if (!(name
= get_opened_printer_name(hPrinter
))) {
4460 SetLastError(ERROR_INVALID_HANDLE
);
4464 if (Level
< 1 || Level
== 7 || Level
> 8) {
4465 SetLastError(ERROR_INVALID_LEVEL
);
4469 env
= validate_envW(pEnvironment
);
4470 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4472 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4474 ERR("Can't create Printers key\n");
4477 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4479 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4480 RegCloseKey(hkeyPrinters
);
4481 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4484 size
= sizeof(DriverName
);
4486 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4487 (LPBYTE
)DriverName
, &size
);
4488 RegCloseKey(hkeyPrinter
);
4489 RegCloseKey(hkeyPrinters
);
4490 if(ret
!= ERROR_SUCCESS
) {
4491 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4495 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4497 ERR("Can't create Drivers key\n");
4501 size
= di_sizeof
[Level
];
4502 if ((size
<= cbBuf
) && pDriverInfo
)
4503 ptr
= pDriverInfo
+ size
;
4505 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4506 env
, Level
, pDriverInfo
, ptr
,
4507 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4509 RegCloseKey(hkeyDrivers
);
4513 RegCloseKey(hkeyDrivers
);
4515 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4516 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4517 if(cbBuf
>= size
+ needed
) return TRUE
;
4518 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4522 /*****************************************************************************
4523 * GetPrinterDriverA [WINSPOOL.@]
4525 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4526 DWORD Level
, LPBYTE pDriverInfo
,
4527 DWORD cbBuf
, LPDWORD pcbNeeded
)
4530 UNICODE_STRING pEnvW
;
4536 ZeroMemory(pDriverInfo
, cbBuf
);
4537 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4540 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4541 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4544 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4546 HeapFree(GetProcessHeap(), 0, buf
);
4548 RtlFreeUnicodeString(&pEnvW
);
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4583 DWORD Level
, LPBYTE pDriverDirectory
,
4584 DWORD cbBuf
, LPDWORD pcbNeeded
)
4586 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4587 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4589 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4592 /* (Level != 1) is ignored in win9x */
4593 SetLastError(ERROR_INVALID_LEVEL
);
4596 if (pcbNeeded
== NULL
) {
4597 /* (pcbNeeded == NULL) is ignored in win9x */
4598 SetLastError(RPC_X_NULL_REF_POINTER
);
4602 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4603 pDriverDirectory
, cbBuf
, pcbNeeded
);
4608 /*****************************************************************************
4609 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4611 * Return the PATH for the Printer-Drivers (ANSI)
4613 * See GetPrinterDriverDirectoryW.
4616 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4619 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4620 DWORD Level
, LPBYTE pDriverDirectory
,
4621 DWORD cbBuf
, LPDWORD pcbNeeded
)
4623 UNICODE_STRING nameW
, environmentW
;
4626 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4627 WCHAR
*driverDirectoryW
= NULL
;
4629 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4630 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4632 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4634 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4635 else nameW
.Buffer
= NULL
;
4636 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4637 else environmentW
.Buffer
= NULL
;
4639 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4640 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4643 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4644 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4646 *pcbNeeded
= needed
;
4647 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4649 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4651 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4653 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4654 RtlFreeUnicodeString(&environmentW
);
4655 RtlFreeUnicodeString(&nameW
);
4660 /*****************************************************************************
4661 * AddPrinterDriverA [WINSPOOL.@]
4663 * See AddPrinterDriverW.
4666 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4668 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4669 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4672 /******************************************************************************
4673 * AddPrinterDriverW (WINSPOOL.@)
4675 * Install a Printer Driver
4678 * pName [I] Servername or NULL (local Computer)
4679 * level [I] Level for the supplied DRIVER_INFO_*W struct
4680 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4687 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4689 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4690 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4693 /*****************************************************************************
4694 * AddPrintProcessorA [WINSPOOL.@]
4696 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4697 LPSTR pPrintProcessorName
)
4699 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4700 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4704 /*****************************************************************************
4705 * AddPrintProcessorW [WINSPOOL.@]
4707 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4708 LPWSTR pPrintProcessorName
)
4710 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4711 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4715 /*****************************************************************************
4716 * AddPrintProvidorA [WINSPOOL.@]
4718 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4720 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4724 /*****************************************************************************
4725 * AddPrintProvidorW [WINSPOOL.@]
4727 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4729 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4733 /*****************************************************************************
4734 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4736 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4737 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4739 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4740 pDevModeOutput
, pDevModeInput
);
4744 /*****************************************************************************
4745 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4747 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4748 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4750 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4751 pDevModeOutput
, pDevModeInput
);
4755 /*****************************************************************************
4756 * PrinterProperties [WINSPOOL.@]
4758 * Displays a dialog to set the properties of the printer.
4761 * nonzero on success or zero on failure
4764 * implemented as stub only
4766 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4767 HANDLE hPrinter
/* [in] handle to printer object */
4769 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4774 /*****************************************************************************
4775 * EnumJobsA [WINSPOOL.@]
4778 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4779 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4782 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4783 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4785 if(pcbNeeded
) *pcbNeeded
= 0;
4786 if(pcReturned
) *pcReturned
= 0;
4791 /*****************************************************************************
4792 * EnumJobsW [WINSPOOL.@]
4795 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4796 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4799 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4800 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4802 if(pcbNeeded
) *pcbNeeded
= 0;
4803 if(pcReturned
) *pcReturned
= 0;
4807 /*****************************************************************************
4808 * WINSPOOL_EnumPrinterDrivers [internal]
4810 * Delivers information about all printer drivers installed on the
4811 * localhost or a given server
4814 * nonzero on success or zero on failure. If the buffer for the returned
4815 * information is too small the function will return an error
4818 * - only implemented for localhost, foreign hosts will return an error
4820 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4821 DWORD Level
, LPBYTE pDriverInfo
,
4823 DWORD cbBuf
, LPDWORD pcbNeeded
,
4824 LPDWORD pcFound
, DWORD data_offset
)
4828 const printenv_t
* env
;
4830 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4831 debugstr_w(pName
), debugstr_w(pEnvironment
),
4832 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4834 env
= validate_envW(pEnvironment
);
4835 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4839 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4841 ERR("Can't open Drivers key\n");
4845 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4846 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4847 RegCloseKey(hkeyDrivers
);
4848 ERR("Can't query Drivers key\n");
4851 TRACE("Found %d Drivers\n", *pcFound
);
4853 /* get size of single struct
4854 * unicode and ascii structure have the same size
4856 size
= di_sizeof
[Level
];
4858 if (data_offset
== 0)
4859 data_offset
= size
* (*pcFound
);
4860 *pcbNeeded
= data_offset
;
4862 for( i
= 0; i
< *pcFound
; i
++) {
4863 WCHAR DriverNameW
[255];
4864 PBYTE table_ptr
= NULL
;
4865 PBYTE data_ptr
= NULL
;
4868 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4870 ERR("Can't enum key number %d\n", i
);
4871 RegCloseKey(hkeyDrivers
);
4875 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4876 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4877 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4878 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4880 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4881 env
, Level
, table_ptr
, data_ptr
,
4882 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4884 RegCloseKey(hkeyDrivers
);
4888 *pcbNeeded
+= needed
;
4891 RegCloseKey(hkeyDrivers
);
4893 if(cbBuf
< *pcbNeeded
){
4894 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4901 /*****************************************************************************
4902 * EnumPrinterDriversW [WINSPOOL.@]
4904 * see function EnumPrinterDrivers for RETURNS, BUGS
4906 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4907 LPBYTE pDriverInfo
, DWORD cbBuf
,
4908 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4910 static const WCHAR allW
[] = {'a','l','l',0};
4914 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4916 SetLastError(RPC_X_NULL_REF_POINTER
);
4920 /* check for local drivers */
4921 if((pName
) && (pName
[0])) {
4922 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4923 SetLastError(ERROR_ACCESS_DENIED
);
4927 /* check input parameter */
4928 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4929 SetLastError(ERROR_INVALID_LEVEL
);
4933 if(pDriverInfo
&& cbBuf
> 0)
4934 memset( pDriverInfo
, 0, cbBuf
);
4936 /* Exception: pull all printers */
4937 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4939 DWORD i
, needed
, bufsize
= cbBuf
;
4940 DWORD total_needed
= 0;
4941 DWORD total_found
= 0;
4944 /* Precompute the overall total; we need this to know
4945 where pointers end and data begins (i.e. data_offset) */
4946 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4949 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4950 NULL
, 0, 0, &needed
, &found
, 0);
4951 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4952 total_needed
+= needed
;
4953 total_found
+= found
;
4956 data_offset
= di_sizeof
[Level
] * total_found
;
4961 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4964 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4965 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4966 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4968 *pcReturned
+= found
;
4969 *pcbNeeded
= needed
;
4970 data_offset
= needed
;
4971 total_found
+= found
;
4976 /* Normal behavior */
4977 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4978 0, cbBuf
, pcbNeeded
, &found
, 0);
4980 *pcReturned
= found
;
4985 /*****************************************************************************
4986 * EnumPrinterDriversA [WINSPOOL.@]
4988 * see function EnumPrinterDrivers for RETURNS, BUGS
4990 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4991 LPBYTE pDriverInfo
, DWORD cbBuf
,
4992 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4995 UNICODE_STRING pNameW
, pEnvironmentW
;
4996 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5000 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5002 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5003 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5005 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5006 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5008 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5010 HeapFree(GetProcessHeap(), 0, buf
);
5012 RtlFreeUnicodeString(&pNameW
);
5013 RtlFreeUnicodeString(&pEnvironmentW
);
5018 /******************************************************************************
5019 * EnumPortsA (WINSPOOL.@)
5024 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5025 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5028 LPBYTE bufferW
= NULL
;
5029 LPWSTR nameW
= NULL
;
5031 DWORD numentries
= 0;
5034 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5035 cbBuf
, pcbNeeded
, pcReturned
);
5037 /* convert servername to unicode */
5039 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5040 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5041 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5043 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5044 needed
= cbBuf
* sizeof(WCHAR
);
5045 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5046 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5048 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5049 if (pcbNeeded
) needed
= *pcbNeeded
;
5050 /* HeapReAlloc return NULL, when bufferW was NULL */
5051 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5052 HeapAlloc(GetProcessHeap(), 0, needed
);
5054 /* Try again with the large Buffer */
5055 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5057 needed
= pcbNeeded
? *pcbNeeded
: 0;
5058 numentries
= pcReturned
? *pcReturned
: 0;
5061 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5062 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5065 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5066 DWORD entrysize
= 0;
5069 LPPORT_INFO_2W pi2w
;
5070 LPPORT_INFO_2A pi2a
;
5073 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5075 /* First pass: calculate the size for all Entries */
5076 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5077 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5079 while (index
< numentries
) {
5081 needed
+= entrysize
; /* PORT_INFO_?A */
5082 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5084 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5085 NULL
, 0, NULL
, NULL
);
5087 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5088 NULL
, 0, NULL
, NULL
);
5089 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5090 NULL
, 0, NULL
, NULL
);
5092 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5093 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5094 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5097 /* check for errors and quit on failure */
5098 if (cbBuf
< needed
) {
5099 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5103 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5104 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5105 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5106 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5107 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5109 /* Second Pass: Fill the User Buffer (if we have one) */
5110 while ((index
< numentries
) && pPorts
) {
5112 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5113 pi2a
->pPortName
= ptr
;
5114 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5115 ptr
, cbBuf
, NULL
, NULL
);
5119 pi2a
->pMonitorName
= ptr
;
5120 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5121 ptr
, cbBuf
, NULL
, NULL
);
5125 pi2a
->pDescription
= ptr
;
5126 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5127 ptr
, cbBuf
, NULL
, NULL
);
5131 pi2a
->fPortType
= pi2w
->fPortType
;
5132 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5135 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5136 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5137 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5142 if (pcbNeeded
) *pcbNeeded
= needed
;
5143 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5145 HeapFree(GetProcessHeap(), 0, nameW
);
5146 HeapFree(GetProcessHeap(), 0, bufferW
);
5148 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5149 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5155 /******************************************************************************
5156 * EnumPortsW (WINSPOOL.@)
5158 * Enumerate available Ports
5161 * pName [I] Servername or NULL (local Computer)
5162 * Level [I] Structure-Level (1 or 2)
5163 * pPorts [O] PTR to Buffer that receives the Result
5164 * cbBuf [I] Size of Buffer at pPorts
5165 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5166 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5170 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5173 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5176 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5177 cbBuf
, pcbNeeded
, pcReturned
);
5179 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5181 /* Level is not checked in win9x */
5182 if (!Level
|| (Level
> 2)) {
5183 WARN("level (%d) is ignored in win9x\n", Level
);
5184 SetLastError(ERROR_INVALID_LEVEL
);
5187 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5188 SetLastError(RPC_X_NULL_REF_POINTER
);
5192 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5195 /******************************************************************************
5196 * GetDefaultPrinterW (WINSPOOL.@)
5199 * This function must read the value from data 'device' of key
5200 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5202 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5206 WCHAR
*buffer
, *ptr
;
5210 SetLastError(ERROR_INVALID_PARAMETER
);
5214 /* make the buffer big enough for the stuff from the profile/registry,
5215 * the content must fit into the local buffer to compute the correct
5216 * size even if the extern buffer is too small or not given.
5217 * (20 for ,driver,port) */
5219 len
= max(100, (insize
+ 20));
5220 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5222 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5224 SetLastError (ERROR_FILE_NOT_FOUND
);
5228 TRACE("%s\n", debugstr_w(buffer
));
5230 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5232 SetLastError(ERROR_INVALID_NAME
);
5238 *namesize
= strlenW(buffer
) + 1;
5239 if(!name
|| (*namesize
> insize
))
5241 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5245 strcpyW(name
, buffer
);
5248 HeapFree( GetProcessHeap(), 0, buffer
);
5253 /******************************************************************************
5254 * GetDefaultPrinterA (WINSPOOL.@)
5256 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5260 WCHAR
*bufferW
= NULL
;
5264 SetLastError(ERROR_INVALID_PARAMETER
);
5268 if(name
&& *namesize
) {
5270 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5273 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5278 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5282 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5285 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5288 HeapFree( GetProcessHeap(), 0, bufferW
);
5293 /******************************************************************************
5294 * SetDefaultPrinterW (WINSPOOL.204)
5296 * Set the Name of the Default Printer
5299 * pszPrinter [I] Name of the Printer or NULL
5306 * When the Parameter is NULL or points to an Empty String and
5307 * a Default Printer was already present, then this Function changes nothing.
5308 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5309 * the First enumerated local Printer is used.
5312 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5314 WCHAR default_printer
[MAX_PATH
];
5315 LPWSTR buffer
= NULL
;
5321 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5322 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5324 default_printer
[0] = '\0';
5325 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5327 /* if we have a default Printer, do nothing. */
5328 if (GetDefaultPrinterW(default_printer
, &size
))
5332 /* we have no default Printer: search local Printers and use the first */
5333 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5335 default_printer
[0] = '\0';
5336 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5337 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5339 pszPrinter
= default_printer
;
5340 TRACE("using %s\n", debugstr_w(pszPrinter
));
5345 if (pszPrinter
== NULL
) {
5346 TRACE("no local printer found\n");
5347 SetLastError(ERROR_FILE_NOT_FOUND
);
5352 /* "pszPrinter" is never empty or NULL here. */
5353 namelen
= lstrlenW(pszPrinter
);
5354 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5355 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5357 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5358 HeapFree(GetProcessHeap(), 0, buffer
);
5359 SetLastError(ERROR_FILE_NOT_FOUND
);
5363 /* read the devices entry for the printer (driver,port) to build the string for the
5364 default device entry (printer,driver,port) */
5365 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5366 buffer
[namelen
] = ',';
5367 namelen
++; /* move index to the start of the driver */
5369 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5370 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5372 TRACE("set device to %s\n", debugstr_w(buffer
));
5374 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5375 TRACE("failed to set the device entry: %d\n", GetLastError());
5376 lres
= ERROR_INVALID_PRINTER_NAME
;
5379 /* remove the next section, when INIFileMapping is implemented */
5382 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5383 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5390 if (lres
!= ERROR_FILE_NOT_FOUND
)
5391 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5393 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5397 HeapFree(GetProcessHeap(), 0, buffer
);
5398 return (lres
== ERROR_SUCCESS
);
5401 /******************************************************************************
5402 * SetDefaultPrinterA (WINSPOOL.202)
5404 * See SetDefaultPrinterW.
5407 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5409 LPWSTR bufferW
= NULL
;
5412 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5414 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5415 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5416 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5418 res
= SetDefaultPrinterW(bufferW
);
5419 HeapFree(GetProcessHeap(), 0, bufferW
);
5423 /******************************************************************************
5424 * SetPrinterDataExA (WINSPOOL.@)
5426 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5427 LPCSTR pValueName
, DWORD Type
,
5428 LPBYTE pData
, DWORD cbData
)
5430 HKEY hkeyPrinter
, hkeySubkey
;
5433 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5434 debugstr_a(pValueName
), Type
, pData
, cbData
);
5436 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5440 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5442 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5443 RegCloseKey(hkeyPrinter
);
5446 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5447 RegCloseKey(hkeySubkey
);
5448 RegCloseKey(hkeyPrinter
);
5452 /******************************************************************************
5453 * SetPrinterDataExW (WINSPOOL.@)
5455 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5456 LPCWSTR pValueName
, DWORD Type
,
5457 LPBYTE pData
, DWORD cbData
)
5459 HKEY hkeyPrinter
, hkeySubkey
;
5462 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5463 debugstr_w(pValueName
), Type
, pData
, cbData
);
5465 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5469 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5471 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5472 RegCloseKey(hkeyPrinter
);
5475 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5476 RegCloseKey(hkeySubkey
);
5477 RegCloseKey(hkeyPrinter
);
5481 /******************************************************************************
5482 * SetPrinterDataA (WINSPOOL.@)
5484 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5485 LPBYTE pData
, DWORD cbData
)
5487 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5491 /******************************************************************************
5492 * SetPrinterDataW (WINSPOOL.@)
5494 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5495 LPBYTE pData
, DWORD cbData
)
5497 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5501 /******************************************************************************
5502 * GetPrinterDataExA (WINSPOOL.@)
5504 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5505 LPCSTR pValueName
, LPDWORD pType
,
5506 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5508 opened_printer_t
*printer
;
5509 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5512 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5513 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5515 printer
= get_opened_printer(hPrinter
);
5516 if(!printer
) return ERROR_INVALID_HANDLE
;
5518 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5519 if (ret
) return ret
;
5521 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5523 if (printer
->name
) {
5525 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5527 RegCloseKey(hkeyPrinters
);
5530 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5531 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5532 RegCloseKey(hkeyPrinter
);
5533 RegCloseKey(hkeyPrinters
);
5538 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5539 0, pType
, pData
, pcbNeeded
);
5541 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5543 RegCloseKey(hkeySubkey
);
5544 RegCloseKey(hkeyPrinter
);
5545 RegCloseKey(hkeyPrinters
);
5547 TRACE("--> %d\n", ret
);
5551 /******************************************************************************
5552 * GetPrinterDataExW (WINSPOOL.@)
5554 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5555 LPCWSTR pValueName
, LPDWORD pType
,
5556 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5558 opened_printer_t
*printer
;
5559 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5562 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5563 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5565 printer
= get_opened_printer(hPrinter
);
5566 if(!printer
) return ERROR_INVALID_HANDLE
;
5568 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5569 if (ret
) return ret
;
5571 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5573 if (printer
->name
) {
5575 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5577 RegCloseKey(hkeyPrinters
);
5580 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5581 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5582 RegCloseKey(hkeyPrinter
);
5583 RegCloseKey(hkeyPrinters
);
5588 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5589 0, pType
, pData
, pcbNeeded
);
5591 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5593 RegCloseKey(hkeySubkey
);
5594 RegCloseKey(hkeyPrinter
);
5595 RegCloseKey(hkeyPrinters
);
5597 TRACE("--> %d\n", ret
);
5601 /******************************************************************************
5602 * GetPrinterDataA (WINSPOOL.@)
5604 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5605 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5607 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5608 pData
, nSize
, pcbNeeded
);
5611 /******************************************************************************
5612 * GetPrinterDataW (WINSPOOL.@)
5614 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5615 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5617 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5618 pData
, nSize
, pcbNeeded
);
5621 /*******************************************************************************
5622 * EnumPrinterDataExW [WINSPOOL.@]
5624 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5625 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5626 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5628 HKEY hkPrinter
, hkSubKey
;
5629 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5630 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5635 PPRINTER_ENUM_VALUESW ppev
;
5637 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5639 if (pKeyName
== NULL
|| *pKeyName
== 0)
5640 return ERROR_INVALID_PARAMETER
;
5642 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5643 if (ret
!= ERROR_SUCCESS
)
5645 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5650 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5651 if (ret
!= ERROR_SUCCESS
)
5653 r
= RegCloseKey (hkPrinter
);
5654 if (r
!= ERROR_SUCCESS
)
5655 WARN ("RegCloseKey returned %i\n", r
);
5656 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5657 debugstr_w (pKeyName
), ret
);
5661 ret
= RegCloseKey (hkPrinter
);
5662 if (ret
!= ERROR_SUCCESS
)
5664 ERR ("RegCloseKey returned %i\n", ret
);
5665 r
= RegCloseKey (hkSubKey
);
5666 if (r
!= ERROR_SUCCESS
)
5667 WARN ("RegCloseKey returned %i\n", r
);
5671 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5672 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5673 if (ret
!= ERROR_SUCCESS
)
5675 r
= RegCloseKey (hkSubKey
);
5676 if (r
!= ERROR_SUCCESS
)
5677 WARN ("RegCloseKey returned %i\n", r
);
5678 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5682 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5683 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5685 if (cValues
== 0) /* empty key */
5687 r
= RegCloseKey (hkSubKey
);
5688 if (r
!= ERROR_SUCCESS
)
5689 WARN ("RegCloseKey returned %i\n", r
);
5690 *pcbEnumValues
= *pnEnumValues
= 0;
5691 return ERROR_SUCCESS
;
5694 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5696 hHeap
= GetProcessHeap ();
5699 ERR ("GetProcessHeap failed\n");
5700 r
= RegCloseKey (hkSubKey
);
5701 if (r
!= ERROR_SUCCESS
)
5702 WARN ("RegCloseKey returned %i\n", r
);
5703 return ERROR_OUTOFMEMORY
;
5706 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5707 if (lpValueName
== NULL
)
5709 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5710 r
= RegCloseKey (hkSubKey
);
5711 if (r
!= ERROR_SUCCESS
)
5712 WARN ("RegCloseKey returned %i\n", r
);
5713 return ERROR_OUTOFMEMORY
;
5716 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5717 if (lpValue
== NULL
)
5719 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5720 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5721 WARN ("HeapFree failed with code %i\n", GetLastError ());
5722 r
= RegCloseKey (hkSubKey
);
5723 if (r
!= ERROR_SUCCESS
)
5724 WARN ("RegCloseKey returned %i\n", r
);
5725 return ERROR_OUTOFMEMORY
;
5728 TRACE ("pass 1: calculating buffer required for all names and values\n");
5730 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5732 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5734 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5736 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5737 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5738 NULL
, NULL
, lpValue
, &cbValueLen
);
5739 if (ret
!= ERROR_SUCCESS
)
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 ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5752 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5753 debugstr_w (lpValueName
), dwIndex
,
5754 cbValueNameLen
+ 1, cbValueLen
);
5756 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5757 cbBufSize
+= cbValueLen
;
5760 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5762 *pcbEnumValues
= cbBufSize
;
5763 *pnEnumValues
= cValues
;
5765 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5767 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771 r
= RegCloseKey (hkSubKey
);
5772 if (r
!= ERROR_SUCCESS
)
5773 WARN ("RegCloseKey returned %i\n", r
);
5774 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5775 return ERROR_MORE_DATA
;
5778 TRACE ("pass 2: copying all names and values to buffer\n");
5780 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5781 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5783 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5785 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5786 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5787 NULL
, &dwType
, lpValue
, &cbValueLen
);
5788 if (ret
!= ERROR_SUCCESS
)
5790 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5793 WARN ("HeapFree failed with code %i\n", GetLastError ());
5794 r
= RegCloseKey (hkSubKey
);
5795 if (r
!= ERROR_SUCCESS
)
5796 WARN ("RegCloseKey returned %i\n", r
);
5797 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5801 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5802 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5803 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5804 pEnumValues
+= cbValueNameLen
;
5806 /* return # of *bytes* (including trailing \0), not # of chars */
5807 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5809 ppev
[dwIndex
].dwType
= dwType
;
5811 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5812 ppev
[dwIndex
].pData
= pEnumValues
;
5813 pEnumValues
+= cbValueLen
;
5815 ppev
[dwIndex
].cbData
= cbValueLen
;
5817 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5818 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5821 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5823 ret
= GetLastError ();
5824 ERR ("HeapFree failed with code %i\n", ret
);
5825 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 r
= RegCloseKey (hkSubKey
);
5828 if (r
!= ERROR_SUCCESS
)
5829 WARN ("RegCloseKey returned %i\n", r
);
5833 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5835 ret
= GetLastError ();
5836 ERR ("HeapFree failed with code %i\n", ret
);
5837 r
= RegCloseKey (hkSubKey
);
5838 if (r
!= ERROR_SUCCESS
)
5839 WARN ("RegCloseKey returned %i\n", r
);
5843 ret
= RegCloseKey (hkSubKey
);
5844 if (ret
!= ERROR_SUCCESS
)
5846 ERR ("RegCloseKey returned %i\n", ret
);
5850 return ERROR_SUCCESS
;
5853 /*******************************************************************************
5854 * EnumPrinterDataExA [WINSPOOL.@]
5856 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5857 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5858 * what Windows 2000 SP1 does.
5861 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5862 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5863 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5867 DWORD ret
, dwIndex
, dwBufSize
;
5871 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5873 if (pKeyName
== NULL
|| *pKeyName
== 0)
5874 return ERROR_INVALID_PARAMETER
;
5876 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5879 ret
= GetLastError ();
5880 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5884 hHeap
= GetProcessHeap ();
5887 ERR ("GetProcessHeap failed\n");
5888 return ERROR_OUTOFMEMORY
;
5891 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5892 if (pKeyNameW
== NULL
)
5894 ERR ("Failed to allocate %i bytes from process heap\n",
5895 (LONG
)(len
* sizeof (WCHAR
)));
5896 return ERROR_OUTOFMEMORY
;
5899 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5901 ret
= GetLastError ();
5902 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5903 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5909 pcbEnumValues
, pnEnumValues
);
5910 if (ret
!= ERROR_SUCCESS
)
5912 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5918 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5920 ret
= GetLastError ();
5921 ERR ("HeapFree failed with code %i\n", ret
);
5925 if (*pnEnumValues
== 0) /* empty key */
5926 return ERROR_SUCCESS
;
5929 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5931 PPRINTER_ENUM_VALUESW ppev
=
5932 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5934 if (dwBufSize
< ppev
->cbValueName
)
5935 dwBufSize
= ppev
->cbValueName
;
5937 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5938 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5939 dwBufSize
= ppev
->cbData
;
5942 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5944 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5945 if (pBuffer
== NULL
)
5947 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5948 return ERROR_OUTOFMEMORY
;
5951 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5953 PPRINTER_ENUM_VALUESW ppev
=
5954 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5956 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5957 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5961 ret
= GetLastError ();
5962 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5963 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5964 WARN ("HeapFree failed with code %i\n", GetLastError ());
5968 memcpy (ppev
->pValueName
, pBuffer
, len
);
5970 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5972 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5973 ppev
->dwType
!= REG_MULTI_SZ
)
5976 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5977 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5980 ret
= GetLastError ();
5981 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5982 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5983 WARN ("HeapFree failed with code %i\n", GetLastError ());
5987 memcpy (ppev
->pData
, pBuffer
, len
);
5989 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5990 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5993 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5995 ret
= GetLastError ();
5996 ERR ("HeapFree failed with code %i\n", ret
);
6000 return ERROR_SUCCESS
;
6003 /******************************************************************************
6004 * AbortPrinter (WINSPOOL.@)
6006 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6008 FIXME("(%p), stub!\n", hPrinter
);
6012 /******************************************************************************
6013 * AddPortA (WINSPOOL.@)
6018 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6020 LPWSTR nameW
= NULL
;
6021 LPWSTR monitorW
= NULL
;
6025 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6028 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6029 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6030 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6034 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6035 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6036 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6038 res
= AddPortW(nameW
, hWnd
, monitorW
);
6039 HeapFree(GetProcessHeap(), 0, nameW
);
6040 HeapFree(GetProcessHeap(), 0, monitorW
);
6044 /******************************************************************************
6045 * AddPortW (WINSPOOL.@)
6047 * Add a Port for a specific Monitor
6050 * pName [I] Servername or NULL (local Computer)
6051 * hWnd [I] Handle to parent Window for the Dialog-Box
6052 * pMonitorName [I] Name of the Monitor that manage the Port
6059 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6061 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6063 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6065 if (!pMonitorName
) {
6066 SetLastError(RPC_X_NULL_REF_POINTER
);
6070 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6073 /******************************************************************************
6074 * AddPortExA (WINSPOOL.@)
6079 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6082 PORT_INFO_2A
* pi2A
;
6083 LPWSTR nameW
= NULL
;
6084 LPWSTR monitorW
= NULL
;
6088 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6090 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6091 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6093 if ((level
< 1) || (level
> 2)) {
6094 SetLastError(ERROR_INVALID_LEVEL
);
6099 SetLastError(ERROR_INVALID_PARAMETER
);
6104 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6105 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6106 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6110 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6111 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6112 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6115 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6117 if (pi2A
->pPortName
) {
6118 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6119 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6120 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6124 if (pi2A
->pMonitorName
) {
6125 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6126 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6127 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6130 if (pi2A
->pDescription
) {
6131 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6132 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6133 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6135 pi2W
.fPortType
= pi2A
->fPortType
;
6136 pi2W
.Reserved
= pi2A
->Reserved
;
6139 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6141 HeapFree(GetProcessHeap(), 0, nameW
);
6142 HeapFree(GetProcessHeap(), 0, monitorW
);
6143 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6144 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6145 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6150 /******************************************************************************
6151 * AddPortExW (WINSPOOL.@)
6153 * Add a Port for a specific Monitor, without presenting a user interface
6156 * pName [I] Servername or NULL (local Computer)
6157 * level [I] Structure-Level (1 or 2) for pBuffer
6158 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6159 * pMonitorName [I] Name of the Monitor that manage the Port
6166 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6170 pi2
= (PORT_INFO_2W
*) pBuffer
;
6172 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6173 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6174 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6175 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6177 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6179 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6180 SetLastError(ERROR_INVALID_PARAMETER
);
6184 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6187 /******************************************************************************
6188 * AddPrinterConnectionA (WINSPOOL.@)
6190 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6192 FIXME("%s\n", debugstr_a(pName
));
6196 /******************************************************************************
6197 * AddPrinterConnectionW (WINSPOOL.@)
6199 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6201 FIXME("%s\n", debugstr_w(pName
));
6205 /******************************************************************************
6206 * AddPrinterDriverExW (WINSPOOL.@)
6208 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6211 * pName [I] Servername or NULL (local Computer)
6212 * level [I] Level for the supplied DRIVER_INFO_*W struct
6213 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6214 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6221 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6223 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6225 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6227 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6228 SetLastError(ERROR_INVALID_LEVEL
);
6233 SetLastError(ERROR_INVALID_PARAMETER
);
6237 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6240 /******************************************************************************
6241 * AddPrinterDriverExA (WINSPOOL.@)
6243 * See AddPrinterDriverExW.
6246 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6248 DRIVER_INFO_8A
*diA
;
6250 LPWSTR nameW
= NULL
;
6255 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6257 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6258 ZeroMemory(&diW
, sizeof(diW
));
6260 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6261 SetLastError(ERROR_INVALID_LEVEL
);
6266 SetLastError(ERROR_INVALID_PARAMETER
);
6270 /* convert servername to unicode */
6272 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6273 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6274 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6278 diW
.cVersion
= diA
->cVersion
;
6281 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6282 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6283 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6286 if (diA
->pEnvironment
) {
6287 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6288 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6289 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6292 if (diA
->pDriverPath
) {
6293 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6294 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6295 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6298 if (diA
->pDataFile
) {
6299 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6300 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6301 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6304 if (diA
->pConfigFile
) {
6305 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6306 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6307 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6310 if ((Level
> 2) && diA
->pDependentFiles
) {
6311 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6312 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6313 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6314 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6317 if ((Level
> 2) && diA
->pMonitorName
) {
6318 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6319 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6320 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6323 if ((Level
> 3) && diA
->pDefaultDataType
) {
6324 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6325 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6326 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6329 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6330 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6331 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6332 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6333 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6336 if ((Level
> 5) && diA
->pszMfgName
) {
6337 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6338 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6339 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6342 if ((Level
> 5) && diA
->pszOEMUrl
) {
6343 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6344 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6345 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6348 if ((Level
> 5) && diA
->pszHardwareID
) {
6349 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6350 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6351 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6354 if ((Level
> 5) && diA
->pszProvider
) {
6355 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6356 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6357 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6361 FIXME("level %u is incomplete\n", Level
);
6364 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6365 TRACE("got %u with %u\n", res
, GetLastError());
6366 HeapFree(GetProcessHeap(), 0, nameW
);
6367 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6368 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6369 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6370 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6371 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6372 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6373 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6374 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6375 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6376 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6377 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6378 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6379 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6381 TRACE("=> %u with %u\n", res
, GetLastError());
6385 /******************************************************************************
6386 * ConfigurePortA (WINSPOOL.@)
6388 * See ConfigurePortW.
6391 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6393 LPWSTR nameW
= NULL
;
6394 LPWSTR portW
= NULL
;
6398 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6400 /* convert servername to unicode */
6402 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6403 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6404 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6407 /* convert portname to unicode */
6409 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6410 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6411 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6414 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6415 HeapFree(GetProcessHeap(), 0, nameW
);
6416 HeapFree(GetProcessHeap(), 0, portW
);
6420 /******************************************************************************
6421 * ConfigurePortW (WINSPOOL.@)
6423 * Display the Configuration-Dialog for a specific Port
6426 * pName [I] Servername or NULL (local Computer)
6427 * hWnd [I] Handle to parent Window for the Dialog-Box
6428 * pPortName [I] Name of the Port, that should be configured
6435 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6438 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6440 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6443 SetLastError(RPC_X_NULL_REF_POINTER
);
6447 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6450 /******************************************************************************
6451 * ConnectToPrinterDlg (WINSPOOL.@)
6453 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6455 FIXME("%p %x\n", hWnd
, Flags
);
6459 /******************************************************************************
6460 * DeletePrinterConnectionA (WINSPOOL.@)
6462 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6464 FIXME("%s\n", debugstr_a(pName
));
6468 /******************************************************************************
6469 * DeletePrinterConnectionW (WINSPOOL.@)
6471 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6473 FIXME("%s\n", debugstr_w(pName
));
6477 /******************************************************************************
6478 * DeletePrinterDriverExW (WINSPOOL.@)
6480 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6481 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6486 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6487 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6489 if(pName
&& pName
[0])
6491 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6492 SetLastError(ERROR_INVALID_PARAMETER
);
6498 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6499 SetLastError(ERROR_INVALID_PARAMETER
);
6503 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6507 ERR("Can't open drivers key\n");
6511 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6514 RegCloseKey(hkey_drivers
);
6519 /******************************************************************************
6520 * DeletePrinterDriverExA (WINSPOOL.@)
6522 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6523 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6525 UNICODE_STRING NameW
, EnvW
, DriverW
;
6528 asciitounicode(&NameW
, pName
);
6529 asciitounicode(&EnvW
, pEnvironment
);
6530 asciitounicode(&DriverW
, pDriverName
);
6532 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6534 RtlFreeUnicodeString(&DriverW
);
6535 RtlFreeUnicodeString(&EnvW
);
6536 RtlFreeUnicodeString(&NameW
);
6541 /******************************************************************************
6542 * DeletePrinterDataExW (WINSPOOL.@)
6544 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6547 FIXME("%p %s %s\n", hPrinter
,
6548 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6549 return ERROR_INVALID_PARAMETER
;
6552 /******************************************************************************
6553 * DeletePrinterDataExA (WINSPOOL.@)
6555 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6558 FIXME("%p %s %s\n", hPrinter
,
6559 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6560 return ERROR_INVALID_PARAMETER
;
6563 /******************************************************************************
6564 * DeletePrintProcessorA (WINSPOOL.@)
6566 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6568 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6569 debugstr_a(pPrintProcessorName
));
6573 /******************************************************************************
6574 * DeletePrintProcessorW (WINSPOOL.@)
6576 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6578 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6579 debugstr_w(pPrintProcessorName
));
6583 /******************************************************************************
6584 * DeletePrintProvidorA (WINSPOOL.@)
6586 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6588 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6589 debugstr_a(pPrintProviderName
));
6593 /******************************************************************************
6594 * DeletePrintProvidorW (WINSPOOL.@)
6596 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6598 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6599 debugstr_w(pPrintProviderName
));
6603 /******************************************************************************
6604 * EnumFormsA (WINSPOOL.@)
6606 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6607 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6609 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6614 /******************************************************************************
6615 * EnumFormsW (WINSPOOL.@)
6617 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6618 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6620 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6621 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6625 /*****************************************************************************
6626 * EnumMonitorsA [WINSPOOL.@]
6628 * See EnumMonitorsW.
6631 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6632 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6635 LPBYTE bufferW
= NULL
;
6636 LPWSTR nameW
= NULL
;
6638 DWORD numentries
= 0;
6641 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6642 cbBuf
, pcbNeeded
, pcReturned
);
6644 /* convert servername to unicode */
6646 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6647 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6648 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6650 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6651 needed
= cbBuf
* sizeof(WCHAR
);
6652 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6653 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6655 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6656 if (pcbNeeded
) needed
= *pcbNeeded
;
6657 /* HeapReAlloc return NULL, when bufferW was NULL */
6658 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6659 HeapAlloc(GetProcessHeap(), 0, needed
);
6661 /* Try again with the large Buffer */
6662 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6664 numentries
= pcReturned
? *pcReturned
: 0;
6667 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6668 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6671 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6672 DWORD entrysize
= 0;
6675 LPMONITOR_INFO_2W mi2w
;
6676 LPMONITOR_INFO_2A mi2a
;
6678 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6679 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6681 /* First pass: calculate the size for all Entries */
6682 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6683 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6685 while (index
< numentries
) {
6687 needed
+= entrysize
; /* MONITOR_INFO_?A */
6688 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6690 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6691 NULL
, 0, NULL
, NULL
);
6693 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6694 NULL
, 0, NULL
, NULL
);
6695 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6696 NULL
, 0, NULL
, NULL
);
6698 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6699 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6700 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6703 /* check for errors and quit on failure */
6704 if (cbBuf
< needed
) {
6705 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6709 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6710 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6711 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6712 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6713 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6715 /* Second Pass: Fill the User Buffer (if we have one) */
6716 while ((index
< numentries
) && pMonitors
) {
6718 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6720 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6721 ptr
, cbBuf
, NULL
, NULL
);
6725 mi2a
->pEnvironment
= ptr
;
6726 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6727 ptr
, cbBuf
, NULL
, NULL
);
6731 mi2a
->pDLLName
= ptr
;
6732 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6733 ptr
, cbBuf
, NULL
, NULL
);
6737 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6738 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6739 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6743 if (pcbNeeded
) *pcbNeeded
= needed
;
6744 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6746 HeapFree(GetProcessHeap(), 0, nameW
);
6747 HeapFree(GetProcessHeap(), 0, bufferW
);
6749 TRACE("returning %d with %d (%d byte for %d entries)\n",
6750 (res
), GetLastError(), needed
, numentries
);
6756 /*****************************************************************************
6757 * EnumMonitorsW [WINSPOOL.@]
6759 * Enumerate available Port-Monitors
6762 * pName [I] Servername or NULL (local Computer)
6763 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6764 * pMonitors [O] PTR to Buffer that receives the Result
6765 * cbBuf [I] Size of Buffer at pMonitors
6766 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6767 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6771 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6774 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6775 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6778 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6779 cbBuf
, pcbNeeded
, pcReturned
);
6781 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6783 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6784 SetLastError(RPC_X_NULL_REF_POINTER
);
6788 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6791 /******************************************************************************
6792 * SpoolerInit (WINSPOOL.@)
6794 * Initialize the Spooler
6801 * The function fails on windows, when the spooler service is not running
6804 BOOL WINAPI
SpoolerInit(void)
6807 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6811 /******************************************************************************
6812 * XcvDataW (WINSPOOL.@)
6814 * Execute commands in the Printmonitor DLL
6817 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6818 * pszDataName [i] Name of the command to execute
6819 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6820 * cbInputData [i] Size in Bytes of Buffer at pInputData
6821 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6822 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6823 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6824 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6831 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6832 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6834 * Minimal List of commands, that a Printmonitor DLL should support:
6836 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6837 *| "AddPort" : Add a Port
6838 *| "DeletePort": Delete a Port
6840 * Many Printmonitors support additional commands. Examples for localspl.dll:
6841 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6842 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6845 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6846 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6847 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6849 opened_printer_t
*printer
;
6851 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6852 pInputData
, cbInputData
, pOutputData
,
6853 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6855 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6857 printer
= get_opened_printer(hXcv
);
6858 if (!printer
|| (!printer
->backend_printer
)) {
6859 SetLastError(ERROR_INVALID_HANDLE
);
6863 if (!pcbOutputNeeded
) {
6864 SetLastError(ERROR_INVALID_PARAMETER
);
6868 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6869 SetLastError(RPC_X_NULL_REF_POINTER
);
6873 *pcbOutputNeeded
= 0;
6875 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6876 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6880 /*****************************************************************************
6881 * EnumPrinterDataA [WINSPOOL.@]
6884 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6885 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6886 DWORD cbData
, LPDWORD pcbData
)
6888 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6889 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6890 return ERROR_NO_MORE_ITEMS
;
6893 /*****************************************************************************
6894 * EnumPrinterDataW [WINSPOOL.@]
6897 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6898 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6899 DWORD cbData
, LPDWORD pcbData
)
6901 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6902 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6903 return ERROR_NO_MORE_ITEMS
;
6906 /*****************************************************************************
6907 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6910 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6911 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6912 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6914 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6915 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6916 pcbNeeded
, pcReturned
);
6920 /*****************************************************************************
6921 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6924 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6925 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6926 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6928 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6929 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6930 pcbNeeded
, pcReturned
);
6934 /*****************************************************************************
6935 * EnumPrintProcessorsA [WINSPOOL.@]
6937 * See EnumPrintProcessorsW.
6940 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6941 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6944 LPBYTE bufferW
= NULL
;
6945 LPWSTR nameW
= NULL
;
6948 DWORD numentries
= 0;
6951 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6952 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6954 /* convert names to unicode */
6956 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6957 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6958 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6961 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6962 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6963 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6966 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6967 needed
= cbBuf
* sizeof(WCHAR
);
6968 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6969 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6971 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6972 if (pcbNeeded
) needed
= *pcbNeeded
;
6973 /* HeapReAlloc return NULL, when bufferW was NULL */
6974 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6975 HeapAlloc(GetProcessHeap(), 0, needed
);
6977 /* Try again with the large Buffer */
6978 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6980 numentries
= pcReturned
? *pcReturned
: 0;
6984 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6987 PPRINTPROCESSOR_INFO_1W ppiw
;
6988 PPRINTPROCESSOR_INFO_1A ppia
;
6990 /* First pass: calculate the size for all Entries */
6991 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6992 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6994 while (index
< numentries
) {
6996 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
6997 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
6999 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7000 NULL
, 0, NULL
, NULL
);
7002 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7003 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7006 /* check for errors and quit on failure */
7007 if (cbBuf
< needed
) {
7008 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7013 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7014 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7015 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7016 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7017 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7019 /* Second Pass: Fill the User Buffer (if we have one) */
7020 while ((index
< numentries
) && pPPInfo
) {
7022 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7024 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7025 ptr
, cbBuf
, NULL
, NULL
);
7029 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7030 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7035 if (pcbNeeded
) *pcbNeeded
= needed
;
7036 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7038 HeapFree(GetProcessHeap(), 0, nameW
);
7039 HeapFree(GetProcessHeap(), 0, envW
);
7040 HeapFree(GetProcessHeap(), 0, bufferW
);
7042 TRACE("returning %d with %d (%d byte for %d entries)\n",
7043 (res
), GetLastError(), needed
, numentries
);
7048 /*****************************************************************************
7049 * EnumPrintProcessorsW [WINSPOOL.@]
7051 * Enumerate available Print Processors
7054 * pName [I] Servername or NULL (local Computer)
7055 * pEnvironment [I] Printing-Environment or NULL (Default)
7056 * Level [I] Structure-Level (Only 1 is allowed)
7057 * pPPInfo [O] PTR to Buffer that receives the Result
7058 * cbBuf [I] Size of Buffer at pPPInfo
7059 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7060 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7064 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7067 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7068 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7071 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7072 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7074 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7076 if (!pcbNeeded
|| !pcReturned
) {
7077 SetLastError(RPC_X_NULL_REF_POINTER
);
7081 if (!pPPInfo
&& (cbBuf
> 0)) {
7082 SetLastError(ERROR_INVALID_USER_BUFFER
);
7086 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7087 cbBuf
, pcbNeeded
, pcReturned
);
7090 /*****************************************************************************
7091 * ExtDeviceMode [WINSPOOL.@]
7094 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7095 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7098 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7099 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7100 debugstr_a(pProfile
), fMode
);
7104 /*****************************************************************************
7105 * FindClosePrinterChangeNotification [WINSPOOL.@]
7108 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7110 FIXME("Stub: %p\n", hChange
);
7114 /*****************************************************************************
7115 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7118 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7119 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7121 FIXME("Stub: %p %x %x %p\n",
7122 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7123 return INVALID_HANDLE_VALUE
;
7126 /*****************************************************************************
7127 * FindNextPrinterChangeNotification [WINSPOOL.@]
7130 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7131 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7133 FIXME("Stub: %p %p %p %p\n",
7134 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7138 /*****************************************************************************
7139 * FreePrinterNotifyInfo [WINSPOOL.@]
7142 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7144 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7148 /*****************************************************************************
7151 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7152 * ansi depending on the unicode parameter.
7154 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7164 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7167 memcpy(ptr
, str
, *size
);
7174 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7177 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7184 /*****************************************************************************
7187 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7188 LPDWORD pcbNeeded
, BOOL unicode
)
7190 DWORD size
, left
= cbBuf
;
7191 BOOL space
= (cbBuf
> 0);
7198 ji1
->JobId
= job
->job_id
;
7201 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7202 if(space
&& size
<= left
)
7204 ji1
->pDocument
= (LPWSTR
)ptr
;
7212 if (job
->printer_name
)
7214 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7215 if(space
&& size
<= left
)
7217 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7229 /*****************************************************************************
7232 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7233 LPDWORD pcbNeeded
, BOOL unicode
)
7235 DWORD size
, left
= cbBuf
;
7237 BOOL space
= (cbBuf
> 0);
7239 LPDEVMODEA dmA
= NULL
;
7246 ji2
->JobId
= job
->job_id
;
7249 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7250 if(space
&& size
<= left
)
7252 ji2
->pDocument
= (LPWSTR
)ptr
;
7260 if (job
->printer_name
)
7262 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7263 if(space
&& size
<= left
)
7265 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7278 dmA
= DEVMODEdupWtoA(job
->devmode
);
7279 devmode
= (LPDEVMODEW
) dmA
;
7280 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7284 devmode
= job
->devmode
;
7285 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7289 FIXME("Can't convert DEVMODE W to A\n");
7292 /* align DEVMODE to a DWORD boundary */
7293 shift
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
7299 memcpy(ptr
, devmode
, size
-shift
);
7300 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7301 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7314 /*****************************************************************************
7317 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7318 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7321 DWORD needed
= 0, size
;
7325 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7327 EnterCriticalSection(&printer_handles_cs
);
7328 job
= get_job(hPrinter
, JobId
);
7335 size
= sizeof(JOB_INFO_1W
);
7340 memset(pJob
, 0, size
);
7344 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7349 size
= sizeof(JOB_INFO_2W
);
7354 memset(pJob
, 0, size
);
7358 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7363 size
= sizeof(JOB_INFO_3
);
7367 memset(pJob
, 0, size
);
7376 SetLastError(ERROR_INVALID_LEVEL
);
7380 *pcbNeeded
= needed
;
7382 LeaveCriticalSection(&printer_handles_cs
);
7386 /*****************************************************************************
7387 * GetJobA [WINSPOOL.@]
7390 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7391 DWORD cbBuf
, LPDWORD pcbNeeded
)
7393 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7396 /*****************************************************************************
7397 * GetJobW [WINSPOOL.@]
7400 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7401 DWORD cbBuf
, LPDWORD pcbNeeded
)
7403 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7406 /*****************************************************************************
7409 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7412 char *unixname
, *cmdA
;
7414 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7420 if(!(unixname
= wine_get_unix_file_name(filename
)))
7423 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7424 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7425 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7427 TRACE("printing with: %s\n", cmdA
);
7429 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7434 ERR("pipe() failed!\n");
7438 if ((pid
= fork()) == 0)
7444 /* reset signals that we previously set to SIG_IGN */
7445 signal(SIGPIPE
, SIG_DFL
);
7447 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7452 ERR("fork() failed!\n");
7456 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7457 write(fds
[1], buf
, no_read
);
7464 wret
= waitpid(pid
, &status
, 0);
7465 } while (wret
< 0 && errno
== EINTR
);
7468 ERR("waitpid() failed!\n");
7471 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7473 ERR("child process failed! %d\n", status
);
7480 if(file_fd
!= -1) close(file_fd
);
7481 if(fds
[0] != -1) close(fds
[0]);
7482 if(fds
[1] != -1) close(fds
[1]);
7484 HeapFree(GetProcessHeap(), 0, cmdA
);
7485 HeapFree(GetProcessHeap(), 0, unixname
);
7492 /*****************************************************************************
7495 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7498 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7501 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7502 sprintfW(cmd
, fmtW
, printer_name
);
7504 r
= schedule_pipe(cmd
, filename
);
7506 HeapFree(GetProcessHeap(), 0, cmd
);
7510 /*****************************************************************************
7513 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7515 #ifdef SONAME_LIBCUPS
7518 char *unixname
, *queue
, *unix_doc_title
;
7522 if(!(unixname
= wine_get_unix_file_name(filename
)))
7525 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7526 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7527 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7529 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7530 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7531 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7533 TRACE("printing via cups\n");
7534 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7535 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7536 HeapFree(GetProcessHeap(), 0, queue
);
7537 HeapFree(GetProcessHeap(), 0, unixname
);
7543 return schedule_lpr(printer_name
, filename
);
7547 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7554 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7558 if(HIWORD(wparam
) == BN_CLICKED
)
7560 if(LOWORD(wparam
) == IDOK
)
7563 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7566 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7567 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7569 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7571 WCHAR caption
[200], message
[200];
7574 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7575 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7576 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7577 if(mb_ret
== IDCANCEL
)
7579 HeapFree(GetProcessHeap(), 0, filename
);
7583 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7584 if(hf
== INVALID_HANDLE_VALUE
)
7586 WCHAR caption
[200], message
[200];
7588 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7589 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7590 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7591 HeapFree(GetProcessHeap(), 0, filename
);
7595 DeleteFileW(filename
);
7596 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7598 EndDialog(hwnd
, IDOK
);
7601 if(LOWORD(wparam
) == IDCANCEL
)
7603 EndDialog(hwnd
, IDCANCEL
);
7612 /*****************************************************************************
7615 static BOOL
get_filename(LPWSTR
*filename
)
7617 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7618 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7621 /*****************************************************************************
7624 static BOOL
schedule_file(LPCWSTR filename
)
7626 LPWSTR output
= NULL
;
7628 if(get_filename(&output
))
7631 TRACE("copy to %s\n", debugstr_w(output
));
7632 r
= CopyFileW(filename
, output
, FALSE
);
7633 HeapFree(GetProcessHeap(), 0, output
);
7639 /*****************************************************************************
7642 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7644 int in_fd
, out_fd
, no_read
;
7647 char *unixname
, *outputA
;
7650 if(!(unixname
= wine_get_unix_file_name(filename
)))
7653 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7654 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7655 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7657 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7658 in_fd
= open(unixname
, O_RDONLY
);
7659 if(out_fd
== -1 || in_fd
== -1)
7662 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7663 write(out_fd
, buf
, no_read
);
7667 if(in_fd
!= -1) close(in_fd
);
7668 if(out_fd
!= -1) close(out_fd
);
7669 HeapFree(GetProcessHeap(), 0, outputA
);
7670 HeapFree(GetProcessHeap(), 0, unixname
);
7674 /*****************************************************************************
7675 * ScheduleJob [WINSPOOL.@]
7678 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7680 opened_printer_t
*printer
;
7682 struct list
*cursor
, *cursor2
;
7684 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7685 EnterCriticalSection(&printer_handles_cs
);
7686 printer
= get_opened_printer(hPrinter
);
7690 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7692 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7695 if(job
->job_id
!= dwJobID
) continue;
7697 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7698 if(hf
!= INVALID_HANDLE_VALUE
)
7700 PRINTER_INFO_5W
*pi5
= NULL
;
7701 LPWSTR portname
= job
->portname
;
7705 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7706 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7710 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7711 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7712 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7713 portname
= pi5
->pPortName
;
7715 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7716 debugstr_w(portname
));
7720 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7721 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7723 DWORD type
, count
= sizeof(output
);
7724 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7727 if(output
[0] == '|')
7729 ret
= schedule_pipe(output
+ 1, job
->filename
);
7733 ret
= schedule_unixfile(output
, job
->filename
);
7735 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7737 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7739 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7741 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7743 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7745 ret
= schedule_file(job
->filename
);
7749 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7751 HeapFree(GetProcessHeap(), 0, pi5
);
7753 DeleteFileW(job
->filename
);
7755 list_remove(cursor
);
7756 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7757 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7758 HeapFree(GetProcessHeap(), 0, job
->portname
);
7759 HeapFree(GetProcessHeap(), 0, job
->filename
);
7760 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7761 HeapFree(GetProcessHeap(), 0, job
);
7765 LeaveCriticalSection(&printer_handles_cs
);
7769 /*****************************************************************************
7770 * StartDocDlgA [WINSPOOL.@]
7772 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7774 UNICODE_STRING usBuffer
;
7777 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7780 docW
.cbSize
= sizeof(docW
);
7781 if (doc
->lpszDocName
)
7783 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7784 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7786 if (doc
->lpszOutput
)
7788 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7789 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7791 if (doc
->lpszDatatype
)
7793 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7794 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7796 docW
.fwType
= doc
->fwType
;
7798 retW
= StartDocDlgW(hPrinter
, &docW
);
7802 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7803 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7804 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7805 HeapFree(GetProcessHeap(), 0, retW
);
7808 HeapFree(GetProcessHeap(), 0, datatypeW
);
7809 HeapFree(GetProcessHeap(), 0, outputW
);
7810 HeapFree(GetProcessHeap(), 0, docnameW
);
7815 /*****************************************************************************
7816 * StartDocDlgW [WINSPOOL.@]
7818 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7819 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7820 * port is "FILE:". Also returns the full path if passed a relative path.
7822 * The caller should free the returned string from the process heap.
7824 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7829 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7831 PRINTER_INFO_5W
*pi5
;
7832 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7833 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7835 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7836 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7837 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7839 HeapFree(GetProcessHeap(), 0, pi5
);
7842 HeapFree(GetProcessHeap(), 0, pi5
);
7845 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7849 if (get_filename(&name
))
7851 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7853 HeapFree(GetProcessHeap(), 0, name
);
7856 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7857 GetFullPathNameW(name
, len
, ret
, NULL
);
7858 HeapFree(GetProcessHeap(), 0, name
);
7863 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7866 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7867 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7869 attr
= GetFileAttributesW(ret
);
7870 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7872 HeapFree(GetProcessHeap(), 0, ret
);