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 /******************************************************************
342 * verify, that the filename is a local file
345 static inline BOOL
is_local_file(LPWSTR name
)
347 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
350 /* ################################ */
352 static int multi_sz_lenA(const char *str
)
354 const char *ptr
= str
;
358 ptr
+= lstrlenA(ptr
) + 1;
361 return ptr
- str
+ 1;
365 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
368 /* If forcing, or no profile string entry for device yet, set the entry
370 * The always change entry if not WINEPS yet is discussable.
373 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
375 !strstr(qbuf
,"WINEPS.DRV")
377 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
380 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
381 WriteProfileStringA("windows","device",buf
);
382 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
383 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
386 HeapFree(GetProcessHeap(),0,buf
);
390 static BOOL
add_printer_driver(WCHAR
*name
)
394 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
397 di3
.pEnvironment
= envname_x86W
;
398 di3
.pDriverPath
= driver_nt
;
399 di3
.pDataFile
= generic_ppdW
;
400 di3
.pConfigFile
= driver_nt
;
401 di3
.pDefaultDataType
= rawW
;
403 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
404 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
407 di3
.pEnvironment
= envname_win40W
;
408 di3
.pDriverPath
= driver_9x
;
409 di3
.pConfigFile
= driver_9x
;
410 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
411 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
416 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
420 #ifdef SONAME_LIBCUPS
421 static typeof(cupsFreeDests
) *pcupsFreeDests
;
422 static typeof(cupsGetDests
) *pcupsGetDests
;
423 static typeof(cupsGetPPD
) *pcupsGetPPD
;
424 static typeof(cupsPrintFile
) *pcupsPrintFile
;
425 static void *cupshandle
;
427 static BOOL
CUPS_LoadPrinters(void)
430 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
434 HKEY hkeyPrinter
, hkeyPrinters
;
436 WCHAR nameW
[MAX_PATH
];
438 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
440 TRACE("%s\n", loaderror
);
443 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
446 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
447 if (!p##x) return FALSE;
449 DYNCUPS(cupsFreeDests
);
451 DYNCUPS(cupsGetDests
);
452 DYNCUPS(cupsPrintFile
);
455 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
457 ERR("Can't create Printers key\n");
461 nrofdests
= pcupsGetDests(&dests
);
462 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
463 for (i
=0;i
<nrofdests
;i
++) {
464 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
466 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
467 lstrcpyW(port
, CUPS_Port
);
468 lstrcatW(port
, nameW
);
470 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
471 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
472 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
474 TRACE("Printer already exists\n");
475 /* overwrite old LPR:* port */
476 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
477 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
478 RegCloseKey(hkeyPrinter
);
480 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
481 ' ','u','s','i','n','g',' ','C','U','P','S',0};
483 add_printer_driver(nameW
);
485 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
486 pi2
.pPrinterName
= nameW
;
487 pi2
.pDatatype
= rawW
;
488 pi2
.pPrintProcessor
= WinPrintW
;
489 pi2
.pDriverName
= nameW
;
490 pi2
.pComment
= comment_cups
;
491 pi2
.pLocation
= emptyStringW
;
492 pi2
.pPortName
= port
;
493 pi2
.pParameters
= emptyStringW
;
494 pi2
.pShareName
= emptyStringW
;
495 pi2
.pSepFile
= emptyStringW
;
497 if (!AddPrinterW(NULL
, 2, (LPBYTE
)&pi2
)) {
498 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
499 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError());
502 HeapFree(GetProcessHeap(),0,port
);
505 if (dests
[i
].is_default
) {
506 SetDefaultPrinterW(nameW
);
510 if (hadprinter
&& !haddefault
) {
511 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
512 SetDefaultPrinterW(nameW
);
514 pcupsFreeDests(nrofdests
, dests
);
515 RegCloseKey(hkeyPrinters
);
521 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
522 PRINTER_INFO_2A pinfo2a
;
525 char *e
,*s
,*name
,*prettyname
,*devname
;
526 BOOL ret
= FALSE
, set_default
= FALSE
;
527 char *port
= NULL
, *env_default
;
528 HKEY hkeyPrinter
, hkeyPrinters
;
529 WCHAR devnameW
[MAX_PATH
];
531 while (isspace(*pent
)) pent
++;
532 r
= strchr(pent
,':');
536 name_len
= strlen(pent
);
537 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
538 memcpy(name
, pent
, name_len
);
539 name
[name_len
] = '\0';
545 TRACE("name=%s entry=%s\n",name
, pent
);
547 if(ispunct(*name
)) { /* a tc entry, not a real printer */
548 TRACE("skipping tc entry\n");
552 if(strstr(pent
,":server")) { /* server only version so skip */
553 TRACE("skipping server entry\n");
557 /* Determine whether this is a postscript printer. */
560 env_default
= getenv("PRINTER");
562 /* Get longest name, usually the one at the right for later display. */
563 while((s
=strchr(prettyname
,'|'))) {
566 while(isspace(*--e
)) *e
= '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname
));
568 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
569 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
572 e
= prettyname
+ strlen(prettyname
);
573 while(isspace(*--e
)) *e
= '\0';
574 TRACE("\t%s\n", debugstr_a(prettyname
));
575 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
577 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
578 * if it is too long, we use it as comment below. */
579 devname
= prettyname
;
580 if (strlen(devname
)>=CCHDEVICENAME
-1)
582 if (strlen(devname
)>=CCHDEVICENAME
-1) {
587 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
588 sprintf(port
,"LPR:%s",name
);
590 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
592 ERR("Can't create Printers key\n");
597 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
599 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
600 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
602 TRACE("Printer already exists\n");
603 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
604 RegCloseKey(hkeyPrinter
);
606 static CHAR data_type
[] = "RAW",
607 print_proc
[] = "WinPrint",
608 comment
[] = "WINEPS Printer using LPR",
609 params
[] = "<parameters?>",
610 share_name
[] = "<share name?>",
611 sep_file
[] = "<sep file?>";
613 add_printer_driver(devnameW
);
615 memset(&pinfo2a
,0,sizeof(pinfo2a
));
616 pinfo2a
.pPrinterName
= devname
;
617 pinfo2a
.pDatatype
= data_type
;
618 pinfo2a
.pPrintProcessor
= print_proc
;
619 pinfo2a
.pDriverName
= devname
;
620 pinfo2a
.pComment
= comment
;
621 pinfo2a
.pLocation
= prettyname
;
622 pinfo2a
.pPortName
= port
;
623 pinfo2a
.pParameters
= params
;
624 pinfo2a
.pShareName
= share_name
;
625 pinfo2a
.pSepFile
= sep_file
;
627 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
628 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
629 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
632 RegCloseKey(hkeyPrinters
);
634 if (isfirst
|| set_default
)
635 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
638 HeapFree(GetProcessHeap(), 0, port
);
639 HeapFree(GetProcessHeap(), 0, name
);
644 PRINTCAP_LoadPrinters(void) {
645 BOOL hadprinter
= FALSE
;
649 BOOL had_bash
= FALSE
;
651 f
= fopen("/etc/printcap","r");
655 while(fgets(buf
,sizeof(buf
),f
)) {
658 end
=strchr(buf
,'\n');
662 while(isspace(*start
)) start
++;
663 if(*start
== '#' || *start
== '\0')
666 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
667 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
668 HeapFree(GetProcessHeap(),0,pent
);
672 if (end
&& *--end
== '\\') {
679 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
682 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
688 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
689 HeapFree(GetProcessHeap(),0,pent
);
695 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
698 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
699 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
701 return ERROR_FILE_NOT_FOUND
;
704 /******************************************************************
705 * get_servername_from_name (internal)
707 * for an external server, a copy of the serverpart from the full name is returned
710 static LPWSTR
get_servername_from_name(LPCWSTR name
)
714 WCHAR buffer
[MAX_PATH
];
717 if (name
== NULL
) return NULL
;
718 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
720 server
= strdupW(&name
[2]); /* skip over both backslash */
721 if (server
== NULL
) return NULL
;
723 /* strip '\' and the printername */
724 ptr
= strchrW(server
, '\\');
725 if (ptr
) ptr
[0] = '\0';
727 TRACE("found %s\n", debugstr_w(server
));
729 len
= sizeof(buffer
)/sizeof(buffer
[0]);
730 if (GetComputerNameW(buffer
, &len
)) {
731 if (lstrcmpW(buffer
, server
) == 0) {
732 /* The requested Servername is our computername */
733 HeapFree(GetProcessHeap(), 0, server
);
740 /******************************************************************
741 * get_basename_from_name (internal)
743 * skip over the serverpart from the full name
746 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
748 if (name
== NULL
) return NULL
;
749 if ((name
[0] == '\\') && (name
[1] == '\\')) {
750 /* skip over the servername and search for the following '\' */
751 name
= strchrW(&name
[2], '\\');
752 if ((name
) && (name
[1])) {
753 /* found a separator ('\') followed by a name:
754 skip over the separator and return the rest */
759 /* no basename present (we found only a servername) */
766 /******************************************************************
767 * get_opened_printer_entry
768 * Get the first place empty in the opened printer table
771 * - pDefault is ignored
773 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
775 UINT_PTR handle
= nb_printer_handles
, i
;
776 jobqueue_t
*queue
= NULL
;
777 opened_printer_t
*printer
= NULL
;
781 if ((backend
== NULL
) && !load_backend()) return NULL
;
783 servername
= get_servername_from_name(name
);
785 FIXME("server %s not supported\n", debugstr_w(servername
));
786 HeapFree(GetProcessHeap(), 0, servername
);
787 SetLastError(ERROR_INVALID_PRINTER_NAME
);
791 printername
= get_basename_from_name(name
);
792 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
794 /* an empty printername is invalid */
795 if (printername
&& (!printername
[0])) {
796 SetLastError(ERROR_INVALID_PARAMETER
);
800 EnterCriticalSection(&printer_handles_cs
);
802 for (i
= 0; i
< nb_printer_handles
; i
++)
804 if (!printer_handles
[i
])
806 if(handle
== nb_printer_handles
)
811 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
812 queue
= printer_handles
[i
]->queue
;
816 if (handle
>= nb_printer_handles
)
818 opened_printer_t
**new_array
;
820 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
821 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
823 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
824 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
831 printer_handles
= new_array
;
832 nb_printer_handles
+= 16;
835 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
841 /* get a printer handle from the backend */
842 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
847 /* clone the base name. This is NULL for the printserver */
848 printer
->printername
= strdupW(printername
);
850 /* clone the full name */
851 printer
->name
= strdupW(name
);
852 if (name
&& (!printer
->name
)) {
858 printer
->queue
= queue
;
861 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
862 if (!printer
->queue
) {
866 list_init(&printer
->queue
->jobs
);
867 printer
->queue
->ref
= 0;
869 InterlockedIncrement(&printer
->queue
->ref
);
871 printer_handles
[handle
] = printer
;
874 LeaveCriticalSection(&printer_handles_cs
);
875 if (!handle
&& printer
) {
876 /* Something failed: Free all resources */
877 HeapFree(GetProcessHeap(), 0, printer
->printername
);
878 HeapFree(GetProcessHeap(), 0, printer
->name
);
879 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
880 HeapFree(GetProcessHeap(), 0, printer
);
883 return (HANDLE
)handle
;
886 /******************************************************************
888 * Get the pointer to the opened printer referred by the handle
890 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
892 UINT_PTR idx
= (UINT_PTR
)hprn
;
893 opened_printer_t
*ret
= NULL
;
895 EnterCriticalSection(&printer_handles_cs
);
897 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
898 ret
= printer_handles
[idx
- 1];
900 LeaveCriticalSection(&printer_handles_cs
);
904 /******************************************************************
905 * get_opened_printer_name
906 * Get the pointer to the opened printer name referred by the handle
908 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
910 opened_printer_t
*printer
= get_opened_printer(hprn
);
911 if(!printer
) return NULL
;
912 return printer
->name
;
915 /******************************************************************
916 * WINSPOOL_GetOpenedPrinterRegKey
919 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
921 LPCWSTR name
= get_opened_printer_name(hPrinter
);
925 if(!name
) return ERROR_INVALID_HANDLE
;
927 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
931 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
933 ERR("Can't find opened printer %s in registry\n",
935 RegCloseKey(hkeyPrinters
);
936 return ERROR_INVALID_PRINTER_NAME
; /* ? */
938 RegCloseKey(hkeyPrinters
);
939 return ERROR_SUCCESS
;
942 void WINSPOOL_LoadSystemPrinters(void)
944 HKEY hkey
, hkeyPrinters
;
946 DWORD needed
, num
, i
;
947 WCHAR PrinterName
[256];
950 /* This ensures that all printer entries have a valid Name value. If causes
951 problems later if they don't. If one is found to be missed we create one
952 and set it equal to the name of the key */
953 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
954 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
955 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
956 for(i
= 0; i
< num
; i
++) {
957 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
958 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
959 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
960 set_reg_szW(hkey
, NameW
, PrinterName
);
967 RegCloseKey(hkeyPrinters
);
970 /* We want to avoid calling AddPrinter on printers as much as
971 possible, because on cups printers this will (eventually) lead
972 to a call to cupsGetPPD which takes forever, even with non-cups
973 printers AddPrinter takes a while. So we'll tag all printers that
974 were automatically added last time around, if they still exist
975 we'll leave them be otherwise we'll delete them. */
976 if (EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
) && needed
) {
977 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
978 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
979 for(i
= 0; i
< num
; i
++) {
980 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
981 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
982 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
984 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
992 HeapFree(GetProcessHeap(), 0, pi
);
996 #ifdef SONAME_LIBCUPS
997 done
= CUPS_LoadPrinters();
1000 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1001 PRINTCAP_LoadPrinters();
1003 /* Now enumerate the list again and delete any printers that are still tagged */
1004 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1006 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1007 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1008 for(i
= 0; i
< num
; i
++) {
1009 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1010 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1011 BOOL delete_driver
= FALSE
;
1012 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1013 DWORD dw
, type
, size
= sizeof(dw
);
1014 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1015 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1016 DeletePrinter(hprn
);
1017 delete_driver
= TRUE
;
1023 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1028 HeapFree(GetProcessHeap(), 0, pi
);
1035 /******************************************************************
1038 * Get the pointer to the specified job.
1039 * Should hold the printer_handles_cs before calling.
1041 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1043 opened_printer_t
*printer
= get_opened_printer(hprn
);
1046 if(!printer
) return NULL
;
1047 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1049 if(job
->job_id
== JobId
)
1055 /***********************************************************
1058 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1061 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1064 Formname
= (dmA
->dmSize
> off_formname
);
1065 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1066 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1067 dmW
->dmDeviceName
, CCHDEVICENAME
);
1069 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1070 dmA
->dmSize
- CCHDEVICENAME
);
1072 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1073 off_formname
- CCHDEVICENAME
);
1074 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1075 dmW
->dmFormName
, CCHFORMNAME
);
1076 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1077 (off_formname
+ CCHFORMNAME
));
1080 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1081 dmA
->dmDriverExtra
);
1085 /***********************************************************
1087 * Creates an ansi copy of supplied devmode
1089 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1094 if (!dmW
) return NULL
;
1095 size
= dmW
->dmSize
- CCHDEVICENAME
-
1096 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1098 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1099 if (!dmA
) return NULL
;
1101 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1102 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1104 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1105 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1106 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1110 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1111 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1112 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1113 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1115 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1119 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1123 /******************************************************************
1124 * convert_printerinfo_W_to_A [internal]
1127 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1128 DWORD level
, DWORD outlen
, DWORD numentries
)
1134 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1136 len
= pi_sizeof
[level
] * numentries
;
1137 ptr
= (LPSTR
) out
+ len
;
1140 /* copy the numbers of all PRINTER_INFO_* first */
1141 memcpy(out
, pPrintersW
, len
);
1143 while (id
< numentries
) {
1147 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1148 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1150 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1151 if (piW
->pDescription
) {
1152 piA
->pDescription
= ptr
;
1153 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1154 ptr
, outlen
, NULL
, NULL
);
1160 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1161 ptr
, outlen
, NULL
, NULL
);
1165 if (piW
->pComment
) {
1166 piA
->pComment
= ptr
;
1167 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1168 ptr
, outlen
, NULL
, NULL
);
1177 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1178 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1181 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1182 if (piW
->pServerName
) {
1183 piA
->pServerName
= ptr
;
1184 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1185 ptr
, outlen
, NULL
, NULL
);
1189 if (piW
->pPrinterName
) {
1190 piA
->pPrinterName
= ptr
;
1191 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1192 ptr
, outlen
, NULL
, NULL
);
1196 if (piW
->pShareName
) {
1197 piA
->pShareName
= ptr
;
1198 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1199 ptr
, outlen
, NULL
, NULL
);
1203 if (piW
->pPortName
) {
1204 piA
->pPortName
= ptr
;
1205 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1206 ptr
, outlen
, NULL
, NULL
);
1210 if (piW
->pDriverName
) {
1211 piA
->pDriverName
= ptr
;
1212 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1213 ptr
, outlen
, NULL
, NULL
);
1217 if (piW
->pComment
) {
1218 piA
->pComment
= ptr
;
1219 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1220 ptr
, outlen
, NULL
, NULL
);
1224 if (piW
->pLocation
) {
1225 piA
->pLocation
= ptr
;
1226 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1227 ptr
, outlen
, NULL
, NULL
);
1232 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1234 /* align DEVMODEA to a DWORD boundary */
1235 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1239 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1240 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1241 memcpy(ptr
, dmA
, len
);
1242 HeapFree(GetProcessHeap(), 0, dmA
);
1248 if (piW
->pSepFile
) {
1249 piA
->pSepFile
= ptr
;
1250 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1251 ptr
, outlen
, NULL
, NULL
);
1255 if (piW
->pPrintProcessor
) {
1256 piA
->pPrintProcessor
= ptr
;
1257 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1258 ptr
, outlen
, NULL
, NULL
);
1262 if (piW
->pDatatype
) {
1263 piA
->pDatatype
= ptr
;
1264 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1265 ptr
, outlen
, NULL
, NULL
);
1269 if (piW
->pParameters
) {
1270 piA
->pParameters
= ptr
;
1271 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1272 ptr
, outlen
, NULL
, NULL
);
1276 if (piW
->pSecurityDescriptor
) {
1277 piA
->pSecurityDescriptor
= NULL
;
1278 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1285 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1286 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1288 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1290 if (piW
->pPrinterName
) {
1291 piA
->pPrinterName
= ptr
;
1292 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1293 ptr
, outlen
, NULL
, NULL
);
1297 if (piW
->pServerName
) {
1298 piA
->pServerName
= ptr
;
1299 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1300 ptr
, outlen
, NULL
, NULL
);
1309 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1310 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1312 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1314 if (piW
->pPrinterName
) {
1315 piA
->pPrinterName
= ptr
;
1316 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1317 ptr
, outlen
, NULL
, NULL
);
1321 if (piW
->pPortName
) {
1322 piA
->pPortName
= ptr
;
1323 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1324 ptr
, outlen
, NULL
, NULL
);
1331 case 6: /* 6A and 6W are the same structure */
1336 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1337 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1339 TRACE("(%u) #%u\n", level
, id
);
1340 if (piW
->pszObjectGUID
) {
1341 piA
->pszObjectGUID
= ptr
;
1342 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1343 ptr
, outlen
, NULL
, NULL
);
1352 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1353 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1356 TRACE("(%u) #%u\n", level
, id
);
1357 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1359 /* align DEVMODEA to a DWORD boundary */
1360 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1364 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1365 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1366 memcpy(ptr
, dmA
, len
);
1367 HeapFree(GetProcessHeap(), 0, dmA
);
1377 FIXME("for level %u\n", level
);
1379 pPrintersW
+= pi_sizeof
[level
];
1380 out
+= pi_sizeof
[level
];
1385 /******************************************************************
1386 * convert_driverinfo_W_to_A [internal]
1389 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1390 DWORD level
, DWORD outlen
, DWORD numentries
)
1396 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1398 len
= di_sizeof
[level
] * numentries
;
1399 ptr
= (LPSTR
) out
+ len
;
1402 /* copy the numbers of all PRINTER_INFO_* first */
1403 memcpy(out
, pDriversW
, len
);
1405 #define COPY_STRING(fld) \
1408 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1409 ptr += len; outlen -= len;\
1411 #define COPY_MULTIZ_STRING(fld) \
1412 { LPWSTR p = diW->fld; if (p){ \
1415 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1416 ptr += len; outlen -= len; p += len;\
1418 while(len > 1 && outlen > 0); \
1421 while (id
< numentries
)
1427 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1428 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1430 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1437 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1438 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1440 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1443 COPY_STRING(pEnvironment
);
1444 COPY_STRING(pDriverPath
);
1445 COPY_STRING(pDataFile
);
1446 COPY_STRING(pConfigFile
);
1451 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1452 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1454 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1457 COPY_STRING(pEnvironment
);
1458 COPY_STRING(pDriverPath
);
1459 COPY_STRING(pDataFile
);
1460 COPY_STRING(pConfigFile
);
1461 COPY_STRING(pHelpFile
);
1462 COPY_MULTIZ_STRING(pDependentFiles
);
1463 COPY_STRING(pMonitorName
);
1464 COPY_STRING(pDefaultDataType
);
1469 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1470 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1472 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1475 COPY_STRING(pEnvironment
);
1476 COPY_STRING(pDriverPath
);
1477 COPY_STRING(pDataFile
);
1478 COPY_STRING(pConfigFile
);
1479 COPY_STRING(pHelpFile
);
1480 COPY_MULTIZ_STRING(pDependentFiles
);
1481 COPY_STRING(pMonitorName
);
1482 COPY_STRING(pDefaultDataType
);
1483 COPY_MULTIZ_STRING(pszzPreviousNames
);
1488 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1489 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1491 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1494 COPY_STRING(pEnvironment
);
1495 COPY_STRING(pDriverPath
);
1496 COPY_STRING(pDataFile
);
1497 COPY_STRING(pConfigFile
);
1502 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1503 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1505 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1508 COPY_STRING(pEnvironment
);
1509 COPY_STRING(pDriverPath
);
1510 COPY_STRING(pDataFile
);
1511 COPY_STRING(pConfigFile
);
1512 COPY_STRING(pHelpFile
);
1513 COPY_MULTIZ_STRING(pDependentFiles
);
1514 COPY_STRING(pMonitorName
);
1515 COPY_STRING(pDefaultDataType
);
1516 COPY_MULTIZ_STRING(pszzPreviousNames
);
1517 COPY_STRING(pszMfgName
);
1518 COPY_STRING(pszOEMUrl
);
1519 COPY_STRING(pszHardwareID
);
1520 COPY_STRING(pszProvider
);
1525 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1526 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1528 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1531 COPY_STRING(pEnvironment
);
1532 COPY_STRING(pDriverPath
);
1533 COPY_STRING(pDataFile
);
1534 COPY_STRING(pConfigFile
);
1535 COPY_STRING(pHelpFile
);
1536 COPY_MULTIZ_STRING(pDependentFiles
);
1537 COPY_STRING(pMonitorName
);
1538 COPY_STRING(pDefaultDataType
);
1539 COPY_MULTIZ_STRING(pszzPreviousNames
);
1540 COPY_STRING(pszMfgName
);
1541 COPY_STRING(pszOEMUrl
);
1542 COPY_STRING(pszHardwareID
);
1543 COPY_STRING(pszProvider
);
1544 COPY_STRING(pszPrintProcessor
);
1545 COPY_STRING(pszVendorSetup
);
1546 COPY_MULTIZ_STRING(pszzColorProfiles
);
1547 COPY_STRING(pszInfPath
);
1548 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1554 FIXME("for level %u\n", level
);
1557 pDriversW
+= di_sizeof
[level
];
1558 out
+= di_sizeof
[level
];
1563 #undef COPY_MULTIZ_STRING
1567 /***********************************************************
1568 * PRINTER_INFO_2AtoW
1569 * Creates a unicode copy of PRINTER_INFO_2A on heap
1571 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1573 LPPRINTER_INFO_2W piW
;
1574 UNICODE_STRING usBuffer
;
1576 if(!piA
) return NULL
;
1577 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1578 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1580 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1581 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1582 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1583 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1584 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1585 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1586 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1587 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1588 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1589 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1590 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1591 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1595 /***********************************************************
1596 * FREE_PRINTER_INFO_2W
1597 * Free PRINTER_INFO_2W and all strings
1599 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1603 HeapFree(heap
,0,piW
->pServerName
);
1604 HeapFree(heap
,0,piW
->pPrinterName
);
1605 HeapFree(heap
,0,piW
->pShareName
);
1606 HeapFree(heap
,0,piW
->pPortName
);
1607 HeapFree(heap
,0,piW
->pDriverName
);
1608 HeapFree(heap
,0,piW
->pComment
);
1609 HeapFree(heap
,0,piW
->pLocation
);
1610 HeapFree(heap
,0,piW
->pDevMode
);
1611 HeapFree(heap
,0,piW
->pSepFile
);
1612 HeapFree(heap
,0,piW
->pPrintProcessor
);
1613 HeapFree(heap
,0,piW
->pDatatype
);
1614 HeapFree(heap
,0,piW
->pParameters
);
1615 HeapFree(heap
,0,piW
);
1619 /******************************************************************
1620 * DeviceCapabilities [WINSPOOL.@]
1621 * DeviceCapabilitiesA [WINSPOOL.@]
1624 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1625 LPSTR pOutput
, LPDEVMODEA lpdm
)
1629 if (!GDI_CallDeviceCapabilities16
)
1631 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1633 if (!GDI_CallDeviceCapabilities16
) return -1;
1635 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1637 /* If DC_PAPERSIZE map POINT16s to POINTs */
1638 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1639 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1640 POINT
*pt
= (POINT
*)pOutput
;
1642 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1643 for(i
= 0; i
< ret
; i
++, pt
++)
1648 HeapFree( GetProcessHeap(), 0, tmp
);
1654 /*****************************************************************************
1655 * DeviceCapabilitiesW [WINSPOOL.@]
1657 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1660 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1661 WORD fwCapability
, LPWSTR pOutput
,
1662 const DEVMODEW
*pDevMode
)
1664 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1665 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1666 LPSTR pPortA
= strdupWtoA(pPort
);
1669 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1670 fwCapability
== DC_FILEDEPENDENCIES
||
1671 fwCapability
== DC_PAPERNAMES
)) {
1672 /* These need A -> W translation */
1675 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1679 switch(fwCapability
) {
1684 case DC_FILEDEPENDENCIES
:
1688 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1689 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1691 for(i
= 0; i
< ret
; i
++)
1692 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1693 pOutput
+ (i
* size
), size
);
1694 HeapFree(GetProcessHeap(), 0, pOutputA
);
1696 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1697 (LPSTR
)pOutput
, dmA
);
1699 HeapFree(GetProcessHeap(),0,pPortA
);
1700 HeapFree(GetProcessHeap(),0,pDeviceA
);
1701 HeapFree(GetProcessHeap(),0,dmA
);
1705 /******************************************************************
1706 * DocumentPropertiesA [WINSPOOL.@]
1708 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1710 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1711 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1712 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1714 LPSTR lpName
= pDeviceName
;
1715 static CHAR port
[] = "LPT1:";
1718 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1719 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1723 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1725 ERR("no name from hPrinter?\n");
1726 SetLastError(ERROR_INVALID_HANDLE
);
1729 lpName
= strdupWtoA(lpNameW
);
1732 if (!GDI_CallExtDeviceMode16
)
1734 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1736 if (!GDI_CallExtDeviceMode16
) {
1737 ERR("No CallExtDeviceMode16?\n");
1741 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1742 pDevModeInput
, NULL
, fMode
);
1745 HeapFree(GetProcessHeap(),0,lpName
);
1750 /*****************************************************************************
1751 * DocumentPropertiesW (WINSPOOL.@)
1753 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1755 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1757 LPDEVMODEW pDevModeOutput
,
1758 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1761 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1762 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1763 LPDEVMODEA pDevModeOutputA
= NULL
;
1766 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1767 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1769 if(pDevModeOutput
) {
1770 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1771 if(ret
< 0) return ret
;
1772 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1774 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1775 pDevModeInputA
, fMode
);
1776 if(pDevModeOutput
) {
1777 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1778 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1780 if(fMode
== 0 && ret
> 0)
1781 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1782 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1783 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1787 /*****************************************************************************
1788 * IsValidDevmodeA [WINSPOOL.@]
1790 * Validate a DEVMODE structure and fix errors if possible.
1793 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1795 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1803 /*****************************************************************************
1804 * IsValidDevmodeW [WINSPOOL.@]
1806 * Validate a DEVMODE structure and fix errors if possible.
1809 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1811 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1819 /******************************************************************
1820 * OpenPrinterA [WINSPOOL.@]
1825 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1826 LPPRINTER_DEFAULTSA pDefault
)
1828 UNICODE_STRING lpPrinterNameW
;
1829 UNICODE_STRING usBuffer
;
1830 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1831 PWSTR pwstrPrinterNameW
;
1834 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1837 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1838 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1839 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1840 pDefaultW
= &DefaultW
;
1842 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1844 RtlFreeUnicodeString(&usBuffer
);
1845 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1847 RtlFreeUnicodeString(&lpPrinterNameW
);
1851 /******************************************************************
1852 * OpenPrinterW [WINSPOOL.@]
1854 * Open a Printer / Printserver or a Printer-Object
1857 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1858 * phPrinter [O] The resulting Handle is stored here
1859 * pDefault [I] PTR to Default Printer Settings or NULL
1866 * lpPrinterName is one of:
1867 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1868 *| Printer: "PrinterName"
1869 *| Printer-Object: "PrinterName,Job xxx"
1870 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1871 *| XcvPort: "Servername,XcvPort PortName"
1874 *| Printer-Object not supported
1875 *| pDefaults is ignored
1878 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1881 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1883 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1884 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1888 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1889 SetLastError(ERROR_INVALID_PARAMETER
);
1893 /* Get the unique handle of the printer or Printserver */
1894 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1895 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1896 return (*phPrinter
!= 0);
1899 /******************************************************************
1900 * AddMonitorA [WINSPOOL.@]
1905 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1907 LPWSTR nameW
= NULL
;
1910 LPMONITOR_INFO_2A mi2a
;
1911 MONITOR_INFO_2W mi2w
;
1913 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1914 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1915 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1916 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1917 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1920 SetLastError(ERROR_INVALID_LEVEL
);
1924 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1930 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1931 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1932 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1935 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1937 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1938 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1939 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1941 if (mi2a
->pEnvironment
) {
1942 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1943 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1944 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1946 if (mi2a
->pDLLName
) {
1947 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1948 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1949 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1952 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1954 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1955 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1956 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1958 HeapFree(GetProcessHeap(), 0, nameW
);
1962 /******************************************************************************
1963 * AddMonitorW [WINSPOOL.@]
1965 * Install a Printmonitor
1968 * pName [I] Servername or NULL (local Computer)
1969 * Level [I] Structure-Level (Must be 2)
1970 * pMonitors [I] PTR to MONITOR_INFO_2
1977 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1980 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1982 LPMONITOR_INFO_2W mi2w
;
1984 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1985 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1986 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1987 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1988 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1990 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1993 SetLastError(ERROR_INVALID_LEVEL
);
1997 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2002 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2005 /******************************************************************
2006 * DeletePrinterDriverA [WINSPOOL.@]
2009 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2011 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2014 /******************************************************************
2015 * DeletePrinterDriverW [WINSPOOL.@]
2018 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2020 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2023 /******************************************************************
2024 * DeleteMonitorA [WINSPOOL.@]
2026 * See DeleteMonitorW.
2029 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2031 LPWSTR nameW
= NULL
;
2032 LPWSTR EnvironmentW
= NULL
;
2033 LPWSTR MonitorNameW
= NULL
;
2038 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2039 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2040 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2044 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2045 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2046 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2049 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2050 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2051 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2054 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2056 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2057 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2058 HeapFree(GetProcessHeap(), 0, nameW
);
2062 /******************************************************************
2063 * DeleteMonitorW [WINSPOOL.@]
2065 * Delete a specific Printmonitor from a Printing-Environment
2068 * pName [I] Servername or NULL (local Computer)
2069 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2070 * pMonitorName [I] Name of the Monitor, that should be deleted
2077 * pEnvironment is ignored in Windows for the local Computer.
2080 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2083 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2084 debugstr_w(pMonitorName
));
2086 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2088 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2092 /******************************************************************
2093 * DeletePortA [WINSPOOL.@]
2098 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2100 LPWSTR nameW
= NULL
;
2101 LPWSTR portW
= NULL
;
2105 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2107 /* convert servername to unicode */
2109 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2110 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2111 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2114 /* convert portname to unicode */
2116 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2117 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2118 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2121 res
= DeletePortW(nameW
, hWnd
, portW
);
2122 HeapFree(GetProcessHeap(), 0, nameW
);
2123 HeapFree(GetProcessHeap(), 0, portW
);
2127 /******************************************************************
2128 * DeletePortW [WINSPOOL.@]
2130 * Delete a specific Port
2133 * pName [I] Servername or NULL (local Computer)
2134 * hWnd [I] Handle to parent Window for the Dialog-Box
2135 * pPortName [I] Name of the Port, that should be deleted
2142 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2144 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2146 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2149 SetLastError(RPC_X_NULL_REF_POINTER
);
2153 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2156 /******************************************************************************
2157 * SetPrinterW [WINSPOOL.@]
2159 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2161 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2162 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2166 /******************************************************************************
2167 * WritePrinter [WINSPOOL.@]
2169 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2171 opened_printer_t
*printer
;
2174 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2176 EnterCriticalSection(&printer_handles_cs
);
2177 printer
= get_opened_printer(hPrinter
);
2180 SetLastError(ERROR_INVALID_HANDLE
);
2186 SetLastError(ERROR_SPL_NO_STARTDOC
);
2190 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2192 LeaveCriticalSection(&printer_handles_cs
);
2196 /*****************************************************************************
2197 * AddFormA [WINSPOOL.@]
2199 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2205 /*****************************************************************************
2206 * AddFormW [WINSPOOL.@]
2208 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2210 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2214 /*****************************************************************************
2215 * AddJobA [WINSPOOL.@]
2217 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2220 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2224 SetLastError(ERROR_INVALID_LEVEL
);
2228 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2231 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2232 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2233 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2234 if(*pcbNeeded
> cbBuf
) {
2235 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2238 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2239 addjobA
->JobId
= addjobW
->JobId
;
2240 addjobA
->Path
= (char *)(addjobA
+ 1);
2241 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2247 /*****************************************************************************
2248 * AddJobW [WINSPOOL.@]
2250 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2252 opened_printer_t
*printer
;
2255 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2256 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2257 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2259 ADDJOB_INFO_1W
*addjob
;
2261 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2263 EnterCriticalSection(&printer_handles_cs
);
2265 printer
= get_opened_printer(hPrinter
);
2268 SetLastError(ERROR_INVALID_HANDLE
);
2273 SetLastError(ERROR_INVALID_LEVEL
);
2277 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2281 job
->job_id
= InterlockedIncrement(&next_job_id
);
2283 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2284 if(path
[len
- 1] != '\\')
2286 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2287 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2289 len
= strlenW(filename
);
2290 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2291 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2292 job
->document_title
= strdupW(default_doc_title
);
2293 job
->printer_name
= strdupW(printer
->name
);
2294 job
->devmode
= NULL
;
2295 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2297 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2298 if(*pcbNeeded
<= cbBuf
) {
2299 addjob
= (ADDJOB_INFO_1W
*)pData
;
2300 addjob
->JobId
= job
->job_id
;
2301 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2302 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2305 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2308 LeaveCriticalSection(&printer_handles_cs
);
2312 /*****************************************************************************
2313 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2315 * Return the PATH for the Print-Processors
2317 * See GetPrintProcessorDirectoryW.
2321 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2322 DWORD level
, LPBYTE Info
,
2323 DWORD cbBuf
, LPDWORD pcbNeeded
)
2325 LPWSTR serverW
= NULL
;
2330 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2331 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2335 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2336 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2337 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2341 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2342 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2343 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2346 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2347 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2349 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2352 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2353 cbBuf
, NULL
, NULL
) > 0;
2356 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2357 HeapFree(GetProcessHeap(), 0, envW
);
2358 HeapFree(GetProcessHeap(), 0, serverW
);
2362 /*****************************************************************************
2363 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2365 * Return the PATH for the Print-Processors
2368 * server [I] Servername (NT only) or NULL (local Computer)
2369 * env [I] Printing-Environment (see below) or NULL (Default)
2370 * level [I] Structure-Level (must be 1)
2371 * Info [O] PTR to Buffer that receives the Result
2372 * cbBuf [I] Size of Buffer at "Info"
2373 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2374 * required for the Buffer at "Info"
2377 * Success: TRUE and in pcbNeeded the Bytes used in Info
2378 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2379 * if cbBuf is too small
2381 * Native Values returned in Info on Success:
2382 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2383 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2384 *| win9x(Windows 4.0): "%winsysdir%"
2386 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2389 * Only NULL or "" is supported for server
2392 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2393 DWORD level
, LPBYTE Info
,
2394 DWORD cbBuf
, LPDWORD pcbNeeded
)
2397 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2398 Info
, cbBuf
, pcbNeeded
);
2400 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2403 /* (Level != 1) is ignored in win9x */
2404 SetLastError(ERROR_INVALID_LEVEL
);
2408 if (pcbNeeded
== NULL
) {
2409 /* (pcbNeeded == NULL) is ignored in win9x */
2410 SetLastError(RPC_X_NULL_REF_POINTER
);
2414 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2417 /*****************************************************************************
2418 * WINSPOOL_OpenDriverReg [internal]
2420 * opens the registry for the printer drivers depending on the given input
2421 * variable pEnvironment
2424 * the opened hkey on success
2427 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2431 const printenv_t
* env
;
2433 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2435 env
= validate_envW(pEnvironment
);
2436 if (!env
) return NULL
;
2438 buffer
= HeapAlloc( GetProcessHeap(), 0,
2439 (strlenW(DriversW
) + strlenW(env
->envname
) +
2440 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2442 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2443 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2444 HeapFree(GetProcessHeap(), 0, buffer
);
2449 /*****************************************************************************
2450 * set_devices_and_printerports [internal]
2452 * set the [Devices] and [PrinterPorts] entries for a printer.
2455 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2457 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2461 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2463 /* FIXME: the driver must change to "winspool" */
2464 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2466 lstrcpyW(devline
, driver_nt
);
2467 lstrcatW(devline
, commaW
);
2468 lstrcatW(devline
, pi
->pPortName
);
2470 TRACE("using %s\n", debugstr_w(devline
));
2471 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2472 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2473 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2474 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2478 lstrcatW(devline
, timeout_15_45
);
2479 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2480 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2481 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2482 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2485 HeapFree(GetProcessHeap(), 0, devline
);
2489 /*****************************************************************************
2490 * AddPrinterW [WINSPOOL.@]
2492 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2494 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2498 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2500 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2501 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2502 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2503 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2504 statusW
[] = {'S','t','a','t','u','s',0},
2505 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2507 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2510 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2511 SetLastError(ERROR_INVALID_PARAMETER
);
2515 ERR("Level = %d, unsupported!\n", Level
);
2516 SetLastError(ERROR_INVALID_LEVEL
);
2520 SetLastError(ERROR_INVALID_PARAMETER
);
2523 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2525 ERR("Can't create Printers key\n");
2528 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2529 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2530 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2531 RegCloseKey(hkeyPrinter
);
2532 RegCloseKey(hkeyPrinters
);
2535 RegCloseKey(hkeyPrinter
);
2537 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2539 ERR("Can't create Drivers key\n");
2540 RegCloseKey(hkeyPrinters
);
2543 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2545 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2546 RegCloseKey(hkeyPrinters
);
2547 RegCloseKey(hkeyDrivers
);
2548 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2551 RegCloseKey(hkeyDriver
);
2552 RegCloseKey(hkeyDrivers
);
2554 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2555 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2556 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2557 RegCloseKey(hkeyPrinters
);
2561 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2563 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2564 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2565 RegCloseKey(hkeyPrinters
);
2569 set_devices_and_printerports(pi
);
2570 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2571 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2572 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2574 /* See if we can load the driver. We may need the devmode structure anyway
2577 * Note that DocumentPropertiesW will briefly try to open the printer we
2578 * just create to find a DEVMODEA struct (it will use the WINEPS default
2579 * one in case it is not there, so we are ok).
2581 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2584 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2585 size
= sizeof(DEVMODEW
);
2591 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2593 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2595 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2596 HeapFree(GetProcessHeap(),0,dmW
);
2601 /* set devmode to printer name */
2602 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2606 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2607 and we support these drivers. NT writes DEVMODEW so somehow
2608 we'll need to distinguish between these when we support NT
2612 dmA
= DEVMODEdupWtoA(dmW
);
2613 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2614 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2615 HeapFree(GetProcessHeap(), 0, dmA
);
2617 HeapFree(GetProcessHeap(), 0, dmW
);
2619 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2620 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2621 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2622 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2624 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2625 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2626 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2627 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2628 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2629 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2630 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2631 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2632 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2633 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2634 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2635 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2636 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2638 RegCloseKey(hkeyPrinter
);
2639 RegCloseKey(hkeyPrinters
);
2640 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2641 ERR("OpenPrinter failing\n");
2647 /*****************************************************************************
2648 * AddPrinterA [WINSPOOL.@]
2650 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2652 UNICODE_STRING pNameW
;
2654 PRINTER_INFO_2W
*piW
;
2655 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2658 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2660 ERR("Level = %d, unsupported!\n", Level
);
2661 SetLastError(ERROR_INVALID_LEVEL
);
2664 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2665 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2667 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2669 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2670 RtlFreeUnicodeString(&pNameW
);
2675 /*****************************************************************************
2676 * ClosePrinter [WINSPOOL.@]
2678 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2680 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2681 opened_printer_t
*printer
= NULL
;
2684 TRACE("(%p)\n", hPrinter
);
2686 EnterCriticalSection(&printer_handles_cs
);
2688 if ((i
> 0) && (i
<= nb_printer_handles
))
2689 printer
= printer_handles
[i
- 1];
2694 struct list
*cursor
, *cursor2
;
2696 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2698 if (printer
->backend_printer
) {
2699 backend
->fpClosePrinter(printer
->backend_printer
);
2703 EndDocPrinter(hPrinter
);
2705 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2707 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2709 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2710 ScheduleJob(hPrinter
, job
->job_id
);
2712 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2715 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2716 HeapFree(GetProcessHeap(), 0, printer
->name
);
2717 HeapFree(GetProcessHeap(), 0, printer
);
2718 printer_handles
[i
- 1] = NULL
;
2721 LeaveCriticalSection(&printer_handles_cs
);
2725 /*****************************************************************************
2726 * DeleteFormA [WINSPOOL.@]
2728 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2730 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2734 /*****************************************************************************
2735 * DeleteFormW [WINSPOOL.@]
2737 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2739 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2743 /*****************************************************************************
2744 * DeletePrinter [WINSPOOL.@]
2746 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2748 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2749 HKEY hkeyPrinters
, hkey
;
2752 SetLastError(ERROR_INVALID_HANDLE
);
2755 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2756 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2757 RegCloseKey(hkeyPrinters
);
2759 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2760 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2762 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2763 RegDeleteValueW(hkey
, lpNameW
);
2767 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2768 RegDeleteValueW(hkey
, lpNameW
);
2774 /*****************************************************************************
2775 * SetPrinterA [WINSPOOL.@]
2777 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2780 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2784 /*****************************************************************************
2785 * SetJobA [WINSPOOL.@]
2787 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2788 LPBYTE pJob
, DWORD Command
)
2792 UNICODE_STRING usBuffer
;
2794 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2796 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2797 are all ignored by SetJob, so we don't bother copying them */
2805 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2806 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2808 JobW
= (LPBYTE
)info1W
;
2809 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2810 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2811 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2812 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2813 info1W
->Status
= info1A
->Status
;
2814 info1W
->Priority
= info1A
->Priority
;
2815 info1W
->Position
= info1A
->Position
;
2816 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2821 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2822 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2824 JobW
= (LPBYTE
)info2W
;
2825 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2826 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2827 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2828 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2829 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2830 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2831 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2832 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2833 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2834 info2W
->Status
= info2A
->Status
;
2835 info2W
->Priority
= info2A
->Priority
;
2836 info2W
->Position
= info2A
->Position
;
2837 info2W
->StartTime
= info2A
->StartTime
;
2838 info2W
->UntilTime
= info2A
->UntilTime
;
2839 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2843 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2844 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2847 SetLastError(ERROR_INVALID_LEVEL
);
2851 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2857 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2858 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2859 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2860 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2861 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2866 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2867 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2868 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2869 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2870 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2871 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2872 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2873 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2874 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2878 HeapFree(GetProcessHeap(), 0, JobW
);
2883 /*****************************************************************************
2884 * SetJobW [WINSPOOL.@]
2886 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2887 LPBYTE pJob
, DWORD Command
)
2893 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2894 FIXME("Ignoring everything other than document title\n");
2896 EnterCriticalSection(&printer_handles_cs
);
2897 job
= get_job(hPrinter
, JobId
);
2907 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2908 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2909 job
->document_title
= strdupW(info1
->pDocument
);
2914 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2915 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2916 job
->document_title
= strdupW(info2
->pDocument
);
2917 HeapFree(GetProcessHeap(), 0, job
->devmode
);
2918 if (info2
->pDevMode
)
2920 size
= info2
->pDevMode
->dmSize
+ info2
->pDevMode
->dmDriverExtra
;
2921 job
->devmode
= HeapAlloc(GetProcessHeap(), 0, size
);
2922 memcpy(job
->devmode
, info2
->pDevMode
, size
);
2925 job
->devmode
= NULL
;
2931 SetLastError(ERROR_INVALID_LEVEL
);
2936 LeaveCriticalSection(&printer_handles_cs
);
2940 /*****************************************************************************
2941 * EndDocPrinter [WINSPOOL.@]
2943 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2945 opened_printer_t
*printer
;
2947 TRACE("(%p)\n", hPrinter
);
2949 EnterCriticalSection(&printer_handles_cs
);
2951 printer
= get_opened_printer(hPrinter
);
2954 SetLastError(ERROR_INVALID_HANDLE
);
2960 SetLastError(ERROR_SPL_NO_STARTDOC
);
2964 CloseHandle(printer
->doc
->hf
);
2965 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2966 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2967 printer
->doc
= NULL
;
2970 LeaveCriticalSection(&printer_handles_cs
);
2974 /*****************************************************************************
2975 * EndPagePrinter [WINSPOOL.@]
2977 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2979 FIXME("(%p): stub\n", hPrinter
);
2983 /*****************************************************************************
2984 * StartDocPrinterA [WINSPOOL.@]
2986 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2988 UNICODE_STRING usBuffer
;
2990 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2993 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2994 or one (DOC_INFO_3) extra DWORDs */
2998 doc2W
.JobId
= doc2
->JobId
;
3001 doc2W
.dwMode
= doc2
->dwMode
;
3004 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3005 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3006 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3010 SetLastError(ERROR_INVALID_LEVEL
);
3014 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3016 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3017 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3018 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3023 /*****************************************************************************
3024 * StartDocPrinterW [WINSPOOL.@]
3026 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3028 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3029 opened_printer_t
*printer
;
3030 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3031 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3032 JOB_INFO_1W job_info
;
3033 DWORD needed
, ret
= 0;
3038 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3039 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3040 debugstr_w(doc
->pDatatype
));
3042 if(Level
< 1 || Level
> 3)
3044 SetLastError(ERROR_INVALID_LEVEL
);
3048 EnterCriticalSection(&printer_handles_cs
);
3049 printer
= get_opened_printer(hPrinter
);
3052 SetLastError(ERROR_INVALID_HANDLE
);
3058 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3062 /* Even if we're printing to a file we still add a print job, we'll
3063 just ignore the spool file name */
3065 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3067 ERR("AddJob failed gle %u\n", GetLastError());
3071 /* use pOutputFile only, when it is a real filename */
3072 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3073 filename
= doc
->pOutputFile
;
3075 filename
= addjob
->Path
;
3077 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3078 if(hf
== INVALID_HANDLE_VALUE
)
3081 memset(&job_info
, 0, sizeof(job_info
));
3082 job_info
.pDocument
= doc
->pDocName
;
3083 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3085 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3086 printer
->doc
->hf
= hf
;
3087 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3088 job
= get_job(hPrinter
, ret
);
3089 job
->portname
= strdupW(doc
->pOutputFile
);
3092 LeaveCriticalSection(&printer_handles_cs
);
3097 /*****************************************************************************
3098 * StartPagePrinter [WINSPOOL.@]
3100 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3102 FIXME("(%p): stub\n", hPrinter
);
3106 /*****************************************************************************
3107 * GetFormA [WINSPOOL.@]
3109 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3110 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3112 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3113 Level
,pForm
,cbBuf
,pcbNeeded
);
3117 /*****************************************************************************
3118 * GetFormW [WINSPOOL.@]
3120 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3121 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3123 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3124 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3128 /*****************************************************************************
3129 * SetFormA [WINSPOOL.@]
3131 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3134 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3138 /*****************************************************************************
3139 * SetFormW [WINSPOOL.@]
3141 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3144 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3148 /*****************************************************************************
3149 * ReadPrinter [WINSPOOL.@]
3151 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3152 LPDWORD pNoBytesRead
)
3154 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3158 /*****************************************************************************
3159 * ResetPrinterA [WINSPOOL.@]
3161 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3163 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3167 /*****************************************************************************
3168 * ResetPrinterW [WINSPOOL.@]
3170 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3172 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3176 /*****************************************************************************
3177 * WINSPOOL_GetDWORDFromReg
3179 * Return DWORD associated with ValueName from hkey.
3181 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3183 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3186 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3188 if(ret
!= ERROR_SUCCESS
) {
3189 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3192 if(type
!= REG_DWORD
) {
3193 ERR("Got type %d\n", type
);
3200 /*****************************************************************************
3201 * get_filename_from_reg [internal]
3203 * Get ValueName from hkey storing result in out
3204 * when the Value in the registry has only a filename, use driverdir as prefix
3205 * outlen is space left in out
3206 * String is stored either as unicode or ascii
3210 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3211 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3213 WCHAR filename
[MAX_PATH
];
3217 LPWSTR buffer
= filename
;
3221 size
= sizeof(filename
);
3223 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3224 if (ret
== ERROR_MORE_DATA
) {
3225 TRACE("need dynamic buffer: %u\n", size
);
3226 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3228 /* No Memory is bad */
3232 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3235 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3236 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3242 /* do we have a full path ? */
3243 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3244 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3247 /* we must build the full Path */
3249 if ((out
) && (outlen
> dirlen
)) {
3250 lstrcpyW((LPWSTR
)out
, driverdir
);
3258 /* write the filename */
3259 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3260 if ((out
) && (outlen
>= size
)) {
3261 lstrcpyW((LPWSTR
)out
, ptr
);
3268 ptr
+= lstrlenW(ptr
)+1;
3269 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3272 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3274 /* write the multisz-termination */
3275 if (type
== REG_MULTI_SZ
) {
3276 size
= sizeof(WCHAR
);
3279 if (out
&& (outlen
>= size
)) {
3280 memset (out
, 0, size
);
3286 /*****************************************************************************
3287 * WINSPOOL_GetStringFromReg
3289 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3290 * String is stored as unicode.
3292 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3293 DWORD buflen
, DWORD
*needed
)
3295 DWORD sz
= buflen
, type
;
3298 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3299 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3300 WARN("Got ret = %d\n", ret
);
3304 /* add space for terminating '\0' */
3305 sz
+= sizeof(WCHAR
);
3309 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3314 /*****************************************************************************
3315 * WINSPOOL_GetDefaultDevMode
3317 * Get a default DevMode values for wineps.
3321 static void WINSPOOL_GetDefaultDevMode(
3323 DWORD buflen
, DWORD
*needed
)
3326 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3328 /* fill default DEVMODE - should be read from ppd... */
3329 ZeroMemory( &dm
, sizeof(dm
) );
3330 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3331 dm
.dmSpecVersion
= DM_SPECVERSION
;
3332 dm
.dmDriverVersion
= 1;
3333 dm
.dmSize
= sizeof(DEVMODEW
);
3334 dm
.dmDriverExtra
= 0;
3336 DM_ORIENTATION
| DM_PAPERSIZE
|
3337 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3340 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3341 DM_YRESOLUTION
| DM_TTOPTION
;
3343 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3344 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3345 dm
.u1
.s1
.dmPaperLength
= 2970;
3346 dm
.u1
.s1
.dmPaperWidth
= 2100;
3348 dm
.u1
.s1
.dmScale
= 100;
3349 dm
.u1
.s1
.dmCopies
= 1;
3350 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3351 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3354 dm
.dmYResolution
= 300; /* 300dpi */
3355 dm
.dmTTOption
= DMTT_BITMAP
;
3358 /* dm.dmLogPixels */
3359 /* dm.dmBitsPerPel */
3360 /* dm.dmPelsWidth */
3361 /* dm.dmPelsHeight */
3362 /* dm.u2.dmDisplayFlags */
3363 /* dm.dmDisplayFrequency */
3364 /* dm.dmICMMethod */
3365 /* dm.dmICMIntent */
3366 /* dm.dmMediaType */
3367 /* dm.dmDitherType */
3368 /* dm.dmReserved1 */
3369 /* dm.dmReserved2 */
3370 /* dm.dmPanningWidth */
3371 /* dm.dmPanningHeight */
3373 if(buflen
>= sizeof(DEVMODEW
))
3374 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3375 *needed
= sizeof(DEVMODEW
);
3378 /*****************************************************************************
3379 * WINSPOOL_GetDevModeFromReg
3381 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3382 * DevMode is stored either as unicode or ascii.
3384 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3386 DWORD buflen
, DWORD
*needed
)
3388 DWORD sz
= buflen
, type
;
3391 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3392 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3393 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3394 if (sz
< sizeof(DEVMODEA
))
3396 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3399 /* ensures that dmSize is not erratically bogus if registry is invalid */
3400 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3401 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3402 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3403 if (ptr
&& (buflen
>= sz
)) {
3404 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3405 memcpy(ptr
, dmW
, sz
);
3406 HeapFree(GetProcessHeap(),0,dmW
);
3412 /*********************************************************************
3413 * WINSPOOL_GetPrinter_1
3415 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3417 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3418 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3420 DWORD size
, left
= cbBuf
;
3421 BOOL space
= (cbBuf
> 0);
3426 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3427 if(space
&& size
<= left
) {
3428 pi1
->pName
= (LPWSTR
)ptr
;
3436 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3437 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3438 if(space
&& size
<= left
) {
3439 pi1
->pDescription
= (LPWSTR
)ptr
;
3447 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3448 if(space
&& size
<= left
) {
3449 pi1
->pComment
= (LPWSTR
)ptr
;
3457 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3459 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3460 memset(pi1
, 0, sizeof(*pi1
));
3464 /*********************************************************************
3465 * WINSPOOL_GetPrinter_2
3467 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3469 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3470 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3472 DWORD size
, left
= cbBuf
;
3473 BOOL space
= (cbBuf
> 0);
3478 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3479 if(space
&& size
<= left
) {
3480 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3487 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3488 if(space
&& size
<= left
) {
3489 pi2
->pShareName
= (LPWSTR
)ptr
;
3496 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3497 if(space
&& size
<= left
) {
3498 pi2
->pPortName
= (LPWSTR
)ptr
;
3505 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3506 if(space
&& size
<= left
) {
3507 pi2
->pDriverName
= (LPWSTR
)ptr
;
3514 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3515 if(space
&& size
<= left
) {
3516 pi2
->pComment
= (LPWSTR
)ptr
;
3523 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3524 if(space
&& size
<= left
) {
3525 pi2
->pLocation
= (LPWSTR
)ptr
;
3532 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3533 if(space
&& size
<= left
) {
3534 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3543 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3544 if(space
&& size
<= left
) {
3545 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3552 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3553 if(space
&& size
<= left
) {
3554 pi2
->pSepFile
= (LPWSTR
)ptr
;
3561 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3562 if(space
&& size
<= left
) {
3563 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3571 if(space
&& size
<= left
) {
3572 pi2
->pDatatype
= (LPWSTR
)ptr
;
3579 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3580 if(space
&& size
<= left
) {
3581 pi2
->pParameters
= (LPWSTR
)ptr
;
3589 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3590 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3591 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3592 "Default Priority");
3593 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3594 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3597 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3598 memset(pi2
, 0, sizeof(*pi2
));
3603 /*********************************************************************
3604 * WINSPOOL_GetPrinter_4
3606 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3608 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3609 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3611 DWORD size
, left
= cbBuf
;
3612 BOOL space
= (cbBuf
> 0);
3617 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3618 if(space
&& size
<= left
) {
3619 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3627 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3630 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3631 memset(pi4
, 0, sizeof(*pi4
));
3636 /*********************************************************************
3637 * WINSPOOL_GetPrinter_5
3639 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3641 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3642 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3644 DWORD size
, left
= cbBuf
;
3645 BOOL space
= (cbBuf
> 0);
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3651 if(space
&& size
<= left
) {
3652 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3660 if(space
&& size
<= left
) {
3661 pi5
->pPortName
= (LPWSTR
)ptr
;
3669 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3670 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3672 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3676 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3677 memset(pi5
, 0, sizeof(*pi5
));
3682 /*********************************************************************
3683 * WINSPOOL_GetPrinter_7
3685 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3687 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3688 DWORD cbBuf
, LPDWORD pcbNeeded
)
3690 DWORD size
, left
= cbBuf
;
3691 BOOL space
= (cbBuf
> 0);
3696 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3699 size
= sizeof(pi7
->pszObjectGUID
);
3701 if (space
&& size
<= left
) {
3702 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3709 /* We do not have a Directory Service */
3710 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3713 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3714 memset(pi7
, 0, sizeof(*pi7
));
3719 /*********************************************************************
3720 * WINSPOOL_GetPrinter_9
3722 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3724 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3725 DWORD cbBuf
, LPDWORD pcbNeeded
)
3728 BOOL space
= (cbBuf
> 0);
3732 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3733 if(space
&& size
<= cbBuf
) {
3734 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3741 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3742 if(space
&& size
<= cbBuf
) {
3743 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3749 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3750 memset(pi9
, 0, sizeof(*pi9
));
3755 /*****************************************************************************
3756 * GetPrinterW [WINSPOOL.@]
3758 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3759 DWORD cbBuf
, LPDWORD pcbNeeded
)
3762 DWORD size
, needed
= 0;
3764 HKEY hkeyPrinter
, hkeyPrinters
;
3767 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3769 if (!(name
= get_opened_printer_name(hPrinter
))) {
3770 SetLastError(ERROR_INVALID_HANDLE
);
3774 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3776 ERR("Can't create Printers key\n");
3779 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3781 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3782 RegCloseKey(hkeyPrinters
);
3783 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3790 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3792 size
= sizeof(PRINTER_INFO_2W
);
3794 ptr
= pPrinter
+ size
;
3796 memset(pPrinter
, 0, size
);
3801 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3808 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3810 size
= sizeof(PRINTER_INFO_4W
);
3812 ptr
= pPrinter
+ size
;
3814 memset(pPrinter
, 0, size
);
3819 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3827 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3829 size
= sizeof(PRINTER_INFO_5W
);
3831 ptr
= pPrinter
+ size
;
3833 memset(pPrinter
, 0, size
);
3839 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3847 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3849 size
= sizeof(PRINTER_INFO_6
);
3850 if (size
<= cbBuf
) {
3851 /* FIXME: We do not update the status yet */
3852 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3864 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3866 size
= sizeof(PRINTER_INFO_7W
);
3867 if (size
<= cbBuf
) {
3868 ptr
= pPrinter
+ size
;
3870 memset(pPrinter
, 0, size
);
3876 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3884 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3886 size
= sizeof(PRINTER_INFO_9W
);
3888 ptr
= pPrinter
+ size
;
3890 memset(pPrinter
, 0, size
);
3896 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3903 FIXME("Unimplemented level %d\n", Level
);
3904 SetLastError(ERROR_INVALID_LEVEL
);
3905 RegCloseKey(hkeyPrinters
);
3906 RegCloseKey(hkeyPrinter
);
3910 RegCloseKey(hkeyPrinter
);
3911 RegCloseKey(hkeyPrinters
);
3913 TRACE("returning %d needed = %d\n", ret
, needed
);
3914 if(pcbNeeded
) *pcbNeeded
= needed
;
3916 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3920 /*****************************************************************************
3921 * GetPrinterA [WINSPOOL.@]
3923 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3924 DWORD cbBuf
, LPDWORD pcbNeeded
)
3930 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3932 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3934 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3935 HeapFree(GetProcessHeap(), 0, buf
);
3940 /*****************************************************************************
3941 * WINSPOOL_EnumPrintersW
3943 * Implementation of EnumPrintersW
3945 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3946 DWORD dwLevel
, LPBYTE lpbPrinters
,
3947 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3948 LPDWORD lpdwReturned
)
3951 HKEY hkeyPrinters
, hkeyPrinter
;
3952 WCHAR PrinterName
[255];
3953 DWORD needed
= 0, number
= 0;
3954 DWORD used
, i
, left
;
3958 memset(lpbPrinters
, 0, cbBuf
);
3964 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3965 if(dwType
== PRINTER_ENUM_DEFAULT
)
3968 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3969 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3970 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3972 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3978 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3979 FIXME("dwType = %08x\n", dwType
);
3980 SetLastError(ERROR_INVALID_FLAGS
);
3984 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3986 ERR("Can't create Printers key\n");
3990 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3991 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3992 RegCloseKey(hkeyPrinters
);
3993 ERR("Can't query Printers key\n");
3996 TRACE("Found %d printers\n", number
);
4000 used
= number
* sizeof(PRINTER_INFO_1W
);
4003 used
= number
* sizeof(PRINTER_INFO_2W
);
4006 used
= number
* sizeof(PRINTER_INFO_4W
);
4009 used
= number
* sizeof(PRINTER_INFO_5W
);
4013 SetLastError(ERROR_INVALID_LEVEL
);
4014 RegCloseKey(hkeyPrinters
);
4017 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4019 for(i
= 0; i
< number
; i
++) {
4020 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4022 ERR("Can't enum key number %d\n", i
);
4023 RegCloseKey(hkeyPrinters
);
4026 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4027 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4029 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4030 RegCloseKey(hkeyPrinters
);
4035 buf
= lpbPrinters
+ used
;
4036 left
= cbBuf
- used
;
4044 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4047 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4050 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4053 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4056 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4059 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4062 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4065 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4068 ERR("Shouldn't be here!\n");
4069 RegCloseKey(hkeyPrinter
);
4070 RegCloseKey(hkeyPrinters
);
4073 RegCloseKey(hkeyPrinter
);
4075 RegCloseKey(hkeyPrinters
);
4082 memset(lpbPrinters
, 0, cbBuf
);
4083 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4087 *lpdwReturned
= number
;
4088 SetLastError(ERROR_SUCCESS
);
4093 /******************************************************************
4094 * EnumPrintersW [WINSPOOL.@]
4096 * Enumerates the available printers, print servers and print
4097 * providers, depending on the specified flags, name and level.
4101 * If level is set to 1:
4102 * Returns an array of PRINTER_INFO_1 data structures in the
4103 * lpbPrinters buffer.
4105 * If level is set to 2:
4106 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4107 * Returns an array of PRINTER_INFO_2 data structures in the
4108 * lpbPrinters buffer. Note that according to MSDN also an
4109 * OpenPrinter should be performed on every remote printer.
4111 * If level is set to 4 (officially WinNT only):
4112 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4113 * Fast: Only the registry is queried to retrieve printer names,
4114 * no connection to the driver is made.
4115 * Returns an array of PRINTER_INFO_4 data structures in the
4116 * lpbPrinters buffer.
4118 * If level is set to 5 (officially WinNT4/Win9x only):
4119 * Fast: Only the registry is queried to retrieve printer names,
4120 * no connection to the driver is made.
4121 * Returns an array of PRINTER_INFO_5 data structures in the
4122 * lpbPrinters buffer.
4124 * If level set to 3 or 6+:
4125 * returns zero (failure!)
4127 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4131 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4132 * - Only levels 2, 4 and 5 are implemented at the moment.
4133 * - 16-bit printer drivers are not enumerated.
4134 * - Returned amount of bytes used/needed does not match the real Windoze
4135 * implementation (as in this implementation, all strings are part
4136 * of the buffer, whereas Win32 keeps them somewhere else)
4137 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4140 * - In a regular Wine installation, no registry settings for printers
4141 * exist, which makes this function return an empty list.
4143 BOOL WINAPI
EnumPrintersW(
4144 DWORD dwType
, /* [in] Types of print objects to enumerate */
4145 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4146 DWORD dwLevel
, /* [in] type of printer info structure */
4147 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4148 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4149 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4150 LPDWORD lpdwReturned
/* [out] number of entries returned */
4153 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4154 lpdwNeeded
, lpdwReturned
);
4157 /******************************************************************
4158 * EnumPrintersA [WINSPOOL.@]
4163 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4164 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4167 UNICODE_STRING pNameU
;
4171 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4172 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4174 pNameW
= asciitounicode(&pNameU
, pName
);
4176 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4177 MS Office need this */
4178 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4180 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4182 RtlFreeUnicodeString(&pNameU
);
4184 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4186 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4190 /*****************************************************************************
4191 * WINSPOOL_GetDriverInfoFromReg [internal]
4193 * Enters the information from the registry into the DRIVER_INFO struct
4196 * zero if the printer driver does not exist in the registry
4197 * (only if Level > 1) otherwise nonzero
4199 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4202 const printenv_t
* env
,
4204 LPBYTE ptr
, /* DRIVER_INFO */
4205 LPBYTE pDriverStrings
, /* strings buffer */
4206 DWORD cbBuf
, /* size of string buffer */
4207 LPDWORD pcbNeeded
) /* space needed for str. */
4211 WCHAR driverdir
[MAX_PATH
];
4213 LPBYTE strPtr
= pDriverStrings
;
4214 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4216 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4217 debugstr_w(DriverName
), env
,
4218 Level
, di
, pDriverStrings
, cbBuf
);
4220 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4222 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4223 if (*pcbNeeded
<= cbBuf
)
4224 strcpyW((LPWSTR
)strPtr
, DriverName
);
4226 /* pName for level 1 has a different offset! */
4228 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4232 /* .cVersion and .pName for level > 1 */
4234 di
->cVersion
= env
->driverversion
;
4235 di
->pName
= (LPWSTR
) strPtr
;
4236 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4239 /* Reserve Space for the largest subdir and a Backslash*/
4240 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4241 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4242 /* Should never Fail */
4245 lstrcatW(driverdir
, env
->versionsubdir
);
4246 lstrcatW(driverdir
, backslashW
);
4248 /* dirlen must not include the terminating zero */
4249 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4251 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4252 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4253 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4258 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4261 if (*pcbNeeded
<= cbBuf
) {
4262 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4263 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4264 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4267 /* .pDriverPath is the Graphics rendering engine.
4268 The full Path is required to avoid a crash in some apps */
4269 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4271 if (*pcbNeeded
<= cbBuf
)
4272 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4274 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4275 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4278 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4279 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4281 if (*pcbNeeded
<= cbBuf
)
4282 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4284 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4285 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4288 /* .pConfigFile is the Driver user Interface */
4289 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4291 if (*pcbNeeded
<= cbBuf
)
4292 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4294 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4295 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4299 RegCloseKey(hkeyDriver
);
4300 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4305 RegCloseKey(hkeyDriver
);
4306 FIXME("level 5: incomplete\n");
4311 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4313 if (*pcbNeeded
<= cbBuf
)
4314 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4316 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4317 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4320 /* .pDependentFiles */
4321 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4323 if (*pcbNeeded
<= cbBuf
)
4324 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4326 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4327 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4329 else if (GetVersion() & 0x80000000) {
4330 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4331 size
= 2 * sizeof(WCHAR
);
4333 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4335 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4336 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4339 /* .pMonitorName is the optional Language Monitor */
4340 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4342 if (*pcbNeeded
<= cbBuf
)
4343 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4345 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4346 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4349 /* .pDefaultDataType */
4350 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4352 if(*pcbNeeded
<= cbBuf
)
4353 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4355 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4356 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4360 RegCloseKey(hkeyDriver
);
4361 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4365 /* .pszzPreviousNames */
4366 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4368 if(*pcbNeeded
<= cbBuf
)
4369 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4371 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4372 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4376 RegCloseKey(hkeyDriver
);
4377 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4381 /* support is missing, but not important enough for a FIXME */
4382 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4385 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4387 if(*pcbNeeded
<= cbBuf
)
4388 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4390 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4391 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4395 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4397 if(*pcbNeeded
<= cbBuf
)
4398 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4400 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4401 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4404 /* .pszHardwareID */
4405 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4407 if(*pcbNeeded
<= cbBuf
)
4408 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4410 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4411 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4415 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4417 if(*pcbNeeded
<= cbBuf
)
4418 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4420 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4421 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4425 RegCloseKey(hkeyDriver
);
4429 /* support is missing, but not important enough for a FIXME */
4430 TRACE("level 8: incomplete\n");
4432 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4433 RegCloseKey(hkeyDriver
);
4437 /*****************************************************************************
4438 * GetPrinterDriverW [WINSPOOL.@]
4440 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4441 DWORD Level
, LPBYTE pDriverInfo
,
4442 DWORD cbBuf
, LPDWORD pcbNeeded
)
4445 WCHAR DriverName
[100];
4446 DWORD ret
, type
, size
, needed
= 0;
4448 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4449 const printenv_t
* env
;
4451 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4452 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4455 ZeroMemory(pDriverInfo
, cbBuf
);
4457 if (!(name
= get_opened_printer_name(hPrinter
))) {
4458 SetLastError(ERROR_INVALID_HANDLE
);
4462 if (Level
< 1 || Level
== 7 || Level
> 8) {
4463 SetLastError(ERROR_INVALID_LEVEL
);
4467 env
= validate_envW(pEnvironment
);
4468 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4470 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4472 ERR("Can't create Printers key\n");
4475 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4477 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4478 RegCloseKey(hkeyPrinters
);
4479 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4482 size
= sizeof(DriverName
);
4484 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4485 (LPBYTE
)DriverName
, &size
);
4486 RegCloseKey(hkeyPrinter
);
4487 RegCloseKey(hkeyPrinters
);
4488 if(ret
!= ERROR_SUCCESS
) {
4489 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4493 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4495 ERR("Can't create Drivers key\n");
4499 size
= di_sizeof
[Level
];
4500 if ((size
<= cbBuf
) && pDriverInfo
)
4501 ptr
= pDriverInfo
+ size
;
4503 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4504 env
, Level
, pDriverInfo
, ptr
,
4505 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4507 RegCloseKey(hkeyDrivers
);
4511 RegCloseKey(hkeyDrivers
);
4513 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4514 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4515 if(cbBuf
>= size
+ needed
) return TRUE
;
4516 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4520 /*****************************************************************************
4521 * GetPrinterDriverA [WINSPOOL.@]
4523 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4524 DWORD Level
, LPBYTE pDriverInfo
,
4525 DWORD cbBuf
, LPDWORD pcbNeeded
)
4528 UNICODE_STRING pEnvW
;
4534 ZeroMemory(pDriverInfo
, cbBuf
);
4535 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4538 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4539 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4542 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4544 HeapFree(GetProcessHeap(), 0, buf
);
4546 RtlFreeUnicodeString(&pEnvW
);
4550 /*****************************************************************************
4551 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4553 * Return the PATH for the Printer-Drivers (UNICODE)
4556 * pName [I] Servername (NT only) or NULL (local Computer)
4557 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4558 * Level [I] Structure-Level (must be 1)
4559 * pDriverDirectory [O] PTR to Buffer that receives the Result
4560 * cbBuf [I] Size of Buffer at pDriverDirectory
4561 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4562 * required for pDriverDirectory
4565 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4566 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4567 * if cbBuf is too small
4569 * Native Values returned in pDriverDirectory on Success:
4570 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4571 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4572 *| win9x(Windows 4.0): "%winsysdir%"
4574 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4577 *- Only NULL or "" is supported for pName
4580 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4581 DWORD Level
, LPBYTE pDriverDirectory
,
4582 DWORD cbBuf
, LPDWORD pcbNeeded
)
4584 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4585 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4587 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4590 /* (Level != 1) is ignored in win9x */
4591 SetLastError(ERROR_INVALID_LEVEL
);
4594 if (pcbNeeded
== NULL
) {
4595 /* (pcbNeeded == NULL) is ignored in win9x */
4596 SetLastError(RPC_X_NULL_REF_POINTER
);
4600 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4601 pDriverDirectory
, cbBuf
, pcbNeeded
);
4606 /*****************************************************************************
4607 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4609 * Return the PATH for the Printer-Drivers (ANSI)
4611 * See GetPrinterDriverDirectoryW.
4614 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4617 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4618 DWORD Level
, LPBYTE pDriverDirectory
,
4619 DWORD cbBuf
, LPDWORD pcbNeeded
)
4621 UNICODE_STRING nameW
, environmentW
;
4624 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4625 WCHAR
*driverDirectoryW
= NULL
;
4627 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4628 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4630 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4632 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4633 else nameW
.Buffer
= NULL
;
4634 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4635 else environmentW
.Buffer
= NULL
;
4637 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4638 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4641 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4642 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4644 *pcbNeeded
= needed
;
4645 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4647 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4649 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4651 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4652 RtlFreeUnicodeString(&environmentW
);
4653 RtlFreeUnicodeString(&nameW
);
4658 /*****************************************************************************
4659 * AddPrinterDriverA [WINSPOOL.@]
4661 * See AddPrinterDriverW.
4664 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4666 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4667 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4670 /******************************************************************************
4671 * AddPrinterDriverW (WINSPOOL.@)
4673 * Install a Printer Driver
4676 * pName [I] Servername or NULL (local Computer)
4677 * level [I] Level for the supplied DRIVER_INFO_*W struct
4678 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4685 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4687 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4688 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4691 /*****************************************************************************
4692 * AddPrintProcessorA [WINSPOOL.@]
4694 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4695 LPSTR pPrintProcessorName
)
4697 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4698 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4702 /*****************************************************************************
4703 * AddPrintProcessorW [WINSPOOL.@]
4705 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4706 LPWSTR pPrintProcessorName
)
4708 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4709 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4713 /*****************************************************************************
4714 * AddPrintProvidorA [WINSPOOL.@]
4716 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4718 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4722 /*****************************************************************************
4723 * AddPrintProvidorW [WINSPOOL.@]
4725 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4727 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4731 /*****************************************************************************
4732 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4734 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4735 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4737 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4738 pDevModeOutput
, pDevModeInput
);
4742 /*****************************************************************************
4743 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4745 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4746 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4748 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4749 pDevModeOutput
, pDevModeInput
);
4753 /*****************************************************************************
4754 * PrinterProperties [WINSPOOL.@]
4756 * Displays a dialog to set the properties of the printer.
4759 * nonzero on success or zero on failure
4762 * implemented as stub only
4764 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4765 HANDLE hPrinter
/* [in] handle to printer object */
4767 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4768 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4772 /*****************************************************************************
4773 * EnumJobsA [WINSPOOL.@]
4776 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4777 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4780 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4781 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4783 if(pcbNeeded
) *pcbNeeded
= 0;
4784 if(pcReturned
) *pcReturned
= 0;
4789 /*****************************************************************************
4790 * EnumJobsW [WINSPOOL.@]
4793 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4794 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4797 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4798 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4800 if(pcbNeeded
) *pcbNeeded
= 0;
4801 if(pcReturned
) *pcReturned
= 0;
4805 /*****************************************************************************
4806 * WINSPOOL_EnumPrinterDrivers [internal]
4808 * Delivers information about all printer drivers installed on the
4809 * localhost or a given server
4812 * nonzero on success or zero on failure. If the buffer for the returned
4813 * information is too small the function will return an error
4816 * - only implemented for localhost, foreign hosts will return an error
4818 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4819 DWORD Level
, LPBYTE pDriverInfo
,
4821 DWORD cbBuf
, LPDWORD pcbNeeded
,
4822 LPDWORD pcFound
, DWORD data_offset
)
4826 const printenv_t
* env
;
4828 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4829 debugstr_w(pName
), debugstr_w(pEnvironment
),
4830 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4832 env
= validate_envW(pEnvironment
);
4833 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4837 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4839 ERR("Can't open Drivers key\n");
4843 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4844 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4845 RegCloseKey(hkeyDrivers
);
4846 ERR("Can't query Drivers key\n");
4849 TRACE("Found %d Drivers\n", *pcFound
);
4851 /* get size of single struct
4852 * unicode and ascii structure have the same size
4854 size
= di_sizeof
[Level
];
4856 if (data_offset
== 0)
4857 data_offset
= size
* (*pcFound
);
4858 *pcbNeeded
= data_offset
;
4860 for( i
= 0; i
< *pcFound
; i
++) {
4861 WCHAR DriverNameW
[255];
4862 PBYTE table_ptr
= NULL
;
4863 PBYTE data_ptr
= NULL
;
4866 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4868 ERR("Can't enum key number %d\n", i
);
4869 RegCloseKey(hkeyDrivers
);
4873 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4874 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4875 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4876 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4878 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4879 env
, Level
, table_ptr
, data_ptr
,
4880 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4882 RegCloseKey(hkeyDrivers
);
4886 *pcbNeeded
+= needed
;
4889 RegCloseKey(hkeyDrivers
);
4891 if(cbBuf
< *pcbNeeded
){
4892 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4899 /*****************************************************************************
4900 * EnumPrinterDriversW [WINSPOOL.@]
4902 * see function EnumPrinterDrivers for RETURNS, BUGS
4904 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4905 LPBYTE pDriverInfo
, DWORD cbBuf
,
4906 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4908 static const WCHAR allW
[] = {'a','l','l',0};
4912 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4914 SetLastError(RPC_X_NULL_REF_POINTER
);
4918 /* check for local drivers */
4919 if((pName
) && (pName
[0])) {
4920 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4921 SetLastError(ERROR_ACCESS_DENIED
);
4925 /* check input parameter */
4926 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4927 SetLastError(ERROR_INVALID_LEVEL
);
4931 if(pDriverInfo
&& cbBuf
> 0)
4932 memset( pDriverInfo
, 0, cbBuf
);
4934 /* Exception: pull all printers */
4935 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4937 DWORD i
, needed
, bufsize
= cbBuf
;
4938 DWORD total_needed
= 0;
4939 DWORD total_found
= 0;
4942 /* Precompute the overall total; we need this to know
4943 where pointers end and data begins (i.e. data_offset) */
4944 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4947 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4948 NULL
, 0, 0, &needed
, &found
, 0);
4949 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4950 total_needed
+= needed
;
4951 total_found
+= found
;
4954 data_offset
= di_sizeof
[Level
] * total_found
;
4959 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4962 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4963 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4964 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4966 *pcReturned
+= found
;
4967 *pcbNeeded
= needed
;
4968 data_offset
= needed
;
4969 total_found
+= found
;
4974 /* Normal behavior */
4975 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4976 0, cbBuf
, pcbNeeded
, &found
, 0);
4978 *pcReturned
= found
;
4983 /*****************************************************************************
4984 * EnumPrinterDriversA [WINSPOOL.@]
4986 * see function EnumPrinterDrivers for RETURNS, BUGS
4988 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4989 LPBYTE pDriverInfo
, DWORD cbBuf
,
4990 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4993 UNICODE_STRING pNameW
, pEnvironmentW
;
4994 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4998 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5000 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5001 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5003 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5004 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5006 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5008 HeapFree(GetProcessHeap(), 0, buf
);
5010 RtlFreeUnicodeString(&pNameW
);
5011 RtlFreeUnicodeString(&pEnvironmentW
);
5016 /******************************************************************************
5017 * EnumPortsA (WINSPOOL.@)
5022 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5023 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5026 LPBYTE bufferW
= NULL
;
5027 LPWSTR nameW
= NULL
;
5029 DWORD numentries
= 0;
5032 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5033 cbBuf
, pcbNeeded
, pcReturned
);
5035 /* convert servername to unicode */
5037 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5038 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5039 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5041 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5042 needed
= cbBuf
* sizeof(WCHAR
);
5043 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5044 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5046 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5047 if (pcbNeeded
) needed
= *pcbNeeded
;
5048 /* HeapReAlloc return NULL, when bufferW was NULL */
5049 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5050 HeapAlloc(GetProcessHeap(), 0, needed
);
5052 /* Try again with the large Buffer */
5053 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5055 needed
= pcbNeeded
? *pcbNeeded
: 0;
5056 numentries
= pcReturned
? *pcReturned
: 0;
5059 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5060 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5063 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5064 DWORD entrysize
= 0;
5067 LPPORT_INFO_2W pi2w
;
5068 LPPORT_INFO_2A pi2a
;
5071 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5073 /* First pass: calculate the size for all Entries */
5074 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5075 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5077 while (index
< numentries
) {
5079 needed
+= entrysize
; /* PORT_INFO_?A */
5080 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5082 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5083 NULL
, 0, NULL
, NULL
);
5085 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5086 NULL
, 0, NULL
, NULL
);
5087 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5088 NULL
, 0, NULL
, NULL
);
5090 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5091 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5092 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5095 /* check for errors and quit on failure */
5096 if (cbBuf
< needed
) {
5097 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5101 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5102 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5103 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5104 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5105 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5107 /* Second Pass: Fill the User Buffer (if we have one) */
5108 while ((index
< numentries
) && pPorts
) {
5110 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5111 pi2a
->pPortName
= ptr
;
5112 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5113 ptr
, cbBuf
, NULL
, NULL
);
5117 pi2a
->pMonitorName
= ptr
;
5118 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5119 ptr
, cbBuf
, NULL
, NULL
);
5123 pi2a
->pDescription
= ptr
;
5124 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5125 ptr
, cbBuf
, NULL
, NULL
);
5129 pi2a
->fPortType
= pi2w
->fPortType
;
5130 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5133 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5134 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5135 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5140 if (pcbNeeded
) *pcbNeeded
= needed
;
5141 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5143 HeapFree(GetProcessHeap(), 0, nameW
);
5144 HeapFree(GetProcessHeap(), 0, bufferW
);
5146 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5147 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5153 /******************************************************************************
5154 * EnumPortsW (WINSPOOL.@)
5156 * Enumerate available Ports
5159 * pName [I] Servername or NULL (local Computer)
5160 * Level [I] Structure-Level (1 or 2)
5161 * pPorts [O] PTR to Buffer that receives the Result
5162 * cbBuf [I] Size of Buffer at pPorts
5163 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5164 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5168 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5171 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5174 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5175 cbBuf
, pcbNeeded
, pcReturned
);
5177 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5179 /* Level is not checked in win9x */
5180 if (!Level
|| (Level
> 2)) {
5181 WARN("level (%d) is ignored in win9x\n", Level
);
5182 SetLastError(ERROR_INVALID_LEVEL
);
5185 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5186 SetLastError(RPC_X_NULL_REF_POINTER
);
5190 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5193 /******************************************************************************
5194 * GetDefaultPrinterW (WINSPOOL.@)
5197 * This function must read the value from data 'device' of key
5198 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5200 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5204 WCHAR
*buffer
, *ptr
;
5208 SetLastError(ERROR_INVALID_PARAMETER
);
5212 /* make the buffer big enough for the stuff from the profile/registry,
5213 * the content must fit into the local buffer to compute the correct
5214 * size even if the extern buffer is too small or not given.
5215 * (20 for ,driver,port) */
5217 len
= max(100, (insize
+ 20));
5218 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5220 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5222 SetLastError (ERROR_FILE_NOT_FOUND
);
5226 TRACE("%s\n", debugstr_w(buffer
));
5228 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5230 SetLastError(ERROR_INVALID_NAME
);
5236 *namesize
= strlenW(buffer
) + 1;
5237 if(!name
|| (*namesize
> insize
))
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5243 strcpyW(name
, buffer
);
5246 HeapFree( GetProcessHeap(), 0, buffer
);
5251 /******************************************************************************
5252 * GetDefaultPrinterA (WINSPOOL.@)
5254 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5258 WCHAR
*bufferW
= NULL
;
5262 SetLastError(ERROR_INVALID_PARAMETER
);
5266 if(name
&& *namesize
) {
5268 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5271 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5276 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5280 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5283 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5286 HeapFree( GetProcessHeap(), 0, bufferW
);
5291 /******************************************************************************
5292 * SetDefaultPrinterW (WINSPOOL.204)
5294 * Set the Name of the Default Printer
5297 * pszPrinter [I] Name of the Printer or NULL
5304 * When the Parameter is NULL or points to an Empty String and
5305 * a Default Printer was already present, then this Function changes nothing.
5306 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5307 * the First enumerated local Printer is used.
5310 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5312 WCHAR default_printer
[MAX_PATH
];
5313 LPWSTR buffer
= NULL
;
5319 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5320 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5322 default_printer
[0] = '\0';
5323 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5325 /* if we have a default Printer, do nothing. */
5326 if (GetDefaultPrinterW(default_printer
, &size
))
5330 /* we have no default Printer: search local Printers and use the first */
5331 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5333 default_printer
[0] = '\0';
5334 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5335 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5337 pszPrinter
= default_printer
;
5338 TRACE("using %s\n", debugstr_w(pszPrinter
));
5343 if (pszPrinter
== NULL
) {
5344 TRACE("no local printer found\n");
5345 SetLastError(ERROR_FILE_NOT_FOUND
);
5350 /* "pszPrinter" is never empty or NULL here. */
5351 namelen
= lstrlenW(pszPrinter
);
5352 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5353 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5355 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5356 HeapFree(GetProcessHeap(), 0, buffer
);
5357 SetLastError(ERROR_FILE_NOT_FOUND
);
5361 /* read the devices entry for the printer (driver,port) to build the string for the
5362 default device entry (printer,driver,port) */
5363 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5364 buffer
[namelen
] = ',';
5365 namelen
++; /* move index to the start of the driver */
5367 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5368 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5370 TRACE("set device to %s\n", debugstr_w(buffer
));
5372 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5373 TRACE("failed to set the device entry: %d\n", GetLastError());
5374 lres
= ERROR_INVALID_PRINTER_NAME
;
5377 /* remove the next section, when INIFileMapping is implemented */
5380 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5381 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5388 if (lres
!= ERROR_FILE_NOT_FOUND
)
5389 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5391 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5395 HeapFree(GetProcessHeap(), 0, buffer
);
5396 return (lres
== ERROR_SUCCESS
);
5399 /******************************************************************************
5400 * SetDefaultPrinterA (WINSPOOL.202)
5402 * See SetDefaultPrinterW.
5405 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5407 LPWSTR bufferW
= NULL
;
5410 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5412 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5413 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5414 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5416 res
= SetDefaultPrinterW(bufferW
);
5417 HeapFree(GetProcessHeap(), 0, bufferW
);
5421 /******************************************************************************
5422 * SetPrinterDataExA (WINSPOOL.@)
5424 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5425 LPCSTR pValueName
, DWORD Type
,
5426 LPBYTE pData
, DWORD cbData
)
5428 HKEY hkeyPrinter
, hkeySubkey
;
5431 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5432 debugstr_a(pValueName
), Type
, pData
, cbData
);
5434 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5438 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5440 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5441 RegCloseKey(hkeyPrinter
);
5444 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5445 RegCloseKey(hkeySubkey
);
5446 RegCloseKey(hkeyPrinter
);
5450 /******************************************************************************
5451 * SetPrinterDataExW (WINSPOOL.@)
5453 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5454 LPCWSTR pValueName
, DWORD Type
,
5455 LPBYTE pData
, DWORD cbData
)
5457 HKEY hkeyPrinter
, hkeySubkey
;
5460 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5461 debugstr_w(pValueName
), Type
, pData
, cbData
);
5463 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5467 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5469 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5470 RegCloseKey(hkeyPrinter
);
5473 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5474 RegCloseKey(hkeySubkey
);
5475 RegCloseKey(hkeyPrinter
);
5479 /******************************************************************************
5480 * SetPrinterDataA (WINSPOOL.@)
5482 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5483 LPBYTE pData
, DWORD cbData
)
5485 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5489 /******************************************************************************
5490 * SetPrinterDataW (WINSPOOL.@)
5492 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5493 LPBYTE pData
, DWORD cbData
)
5495 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5499 /******************************************************************************
5500 * GetPrinterDataExA (WINSPOOL.@)
5502 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5503 LPCSTR pValueName
, LPDWORD pType
,
5504 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5506 opened_printer_t
*printer
;
5507 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5510 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5511 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5513 printer
= get_opened_printer(hPrinter
);
5514 if(!printer
) return ERROR_INVALID_HANDLE
;
5516 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5517 if (ret
) return ret
;
5519 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5521 if (printer
->name
) {
5523 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5525 RegCloseKey(hkeyPrinters
);
5528 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5529 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5530 RegCloseKey(hkeyPrinter
);
5531 RegCloseKey(hkeyPrinters
);
5536 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5537 0, pType
, pData
, pcbNeeded
);
5539 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5541 RegCloseKey(hkeySubkey
);
5542 RegCloseKey(hkeyPrinter
);
5543 RegCloseKey(hkeyPrinters
);
5545 TRACE("--> %d\n", ret
);
5549 /******************************************************************************
5550 * GetPrinterDataExW (WINSPOOL.@)
5552 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5553 LPCWSTR pValueName
, LPDWORD pType
,
5554 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5556 opened_printer_t
*printer
;
5557 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5560 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5561 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5563 printer
= get_opened_printer(hPrinter
);
5564 if(!printer
) return ERROR_INVALID_HANDLE
;
5566 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5567 if (ret
) return ret
;
5569 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5571 if (printer
->name
) {
5573 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5575 RegCloseKey(hkeyPrinters
);
5578 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5579 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5580 RegCloseKey(hkeyPrinter
);
5581 RegCloseKey(hkeyPrinters
);
5586 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5587 0, pType
, pData
, pcbNeeded
);
5589 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5591 RegCloseKey(hkeySubkey
);
5592 RegCloseKey(hkeyPrinter
);
5593 RegCloseKey(hkeyPrinters
);
5595 TRACE("--> %d\n", ret
);
5599 /******************************************************************************
5600 * GetPrinterDataA (WINSPOOL.@)
5602 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5603 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5605 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5606 pData
, nSize
, pcbNeeded
);
5609 /******************************************************************************
5610 * GetPrinterDataW (WINSPOOL.@)
5612 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5613 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5615 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5616 pData
, nSize
, pcbNeeded
);
5619 /*******************************************************************************
5620 * EnumPrinterDataExW [WINSPOOL.@]
5622 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5623 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5624 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5626 HKEY hkPrinter
, hkSubKey
;
5627 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5628 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5633 PPRINTER_ENUM_VALUESW ppev
;
5635 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5637 if (pKeyName
== NULL
|| *pKeyName
== 0)
5638 return ERROR_INVALID_PARAMETER
;
5640 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5641 if (ret
!= ERROR_SUCCESS
)
5643 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5648 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5649 if (ret
!= ERROR_SUCCESS
)
5651 r
= RegCloseKey (hkPrinter
);
5652 if (r
!= ERROR_SUCCESS
)
5653 WARN ("RegCloseKey returned %i\n", r
);
5654 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5655 debugstr_w (pKeyName
), ret
);
5659 ret
= RegCloseKey (hkPrinter
);
5660 if (ret
!= ERROR_SUCCESS
)
5662 ERR ("RegCloseKey returned %i\n", ret
);
5663 r
= RegCloseKey (hkSubKey
);
5664 if (r
!= ERROR_SUCCESS
)
5665 WARN ("RegCloseKey returned %i\n", r
);
5669 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5670 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5671 if (ret
!= ERROR_SUCCESS
)
5673 r
= RegCloseKey (hkSubKey
);
5674 if (r
!= ERROR_SUCCESS
)
5675 WARN ("RegCloseKey returned %i\n", r
);
5676 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5680 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5681 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5683 if (cValues
== 0) /* empty key */
5685 r
= RegCloseKey (hkSubKey
);
5686 if (r
!= ERROR_SUCCESS
)
5687 WARN ("RegCloseKey returned %i\n", r
);
5688 *pcbEnumValues
= *pnEnumValues
= 0;
5689 return ERROR_SUCCESS
;
5692 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5694 hHeap
= GetProcessHeap ();
5697 ERR ("GetProcessHeap failed\n");
5698 r
= RegCloseKey (hkSubKey
);
5699 if (r
!= ERROR_SUCCESS
)
5700 WARN ("RegCloseKey returned %i\n", r
);
5701 return ERROR_OUTOFMEMORY
;
5704 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5705 if (lpValueName
== NULL
)
5707 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5708 r
= RegCloseKey (hkSubKey
);
5709 if (r
!= ERROR_SUCCESS
)
5710 WARN ("RegCloseKey returned %i\n", r
);
5711 return ERROR_OUTOFMEMORY
;
5714 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5715 if (lpValue
== NULL
)
5717 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5718 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5719 WARN ("HeapFree failed with code %i\n", GetLastError ());
5720 r
= RegCloseKey (hkSubKey
);
5721 if (r
!= ERROR_SUCCESS
)
5722 WARN ("RegCloseKey returned %i\n", r
);
5723 return ERROR_OUTOFMEMORY
;
5726 TRACE ("pass 1: calculating buffer required for all names and values\n");
5728 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5730 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5732 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5734 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5735 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5736 NULL
, NULL
, lpValue
, &cbValueLen
);
5737 if (ret
!= ERROR_SUCCESS
)
5739 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 r
= RegCloseKey (hkSubKey
);
5744 if (r
!= ERROR_SUCCESS
)
5745 WARN ("RegCloseKey returned %i\n", r
);
5746 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5750 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5751 debugstr_w (lpValueName
), dwIndex
,
5752 cbValueNameLen
+ 1, cbValueLen
);
5754 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5755 cbBufSize
+= cbValueLen
;
5758 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5760 *pcbEnumValues
= cbBufSize
;
5761 *pnEnumValues
= cValues
;
5763 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5765 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5766 WARN ("HeapFree failed with code %i\n", GetLastError ());
5767 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 r
= RegCloseKey (hkSubKey
);
5770 if (r
!= ERROR_SUCCESS
)
5771 WARN ("RegCloseKey returned %i\n", r
);
5772 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5773 return ERROR_MORE_DATA
;
5776 TRACE ("pass 2: copying all names and values to buffer\n");
5778 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5779 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5781 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5783 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5784 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5785 NULL
, &dwType
, lpValue
, &cbValueLen
);
5786 if (ret
!= ERROR_SUCCESS
)
5788 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5789 WARN ("HeapFree failed with code %i\n", GetLastError ());
5790 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 r
= RegCloseKey (hkSubKey
);
5793 if (r
!= ERROR_SUCCESS
)
5794 WARN ("RegCloseKey returned %i\n", r
);
5795 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5799 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5800 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5801 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5802 pEnumValues
+= cbValueNameLen
;
5804 /* return # of *bytes* (including trailing \0), not # of chars */
5805 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5807 ppev
[dwIndex
].dwType
= dwType
;
5809 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5810 ppev
[dwIndex
].pData
= pEnumValues
;
5811 pEnumValues
+= cbValueLen
;
5813 ppev
[dwIndex
].cbData
= cbValueLen
;
5815 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5816 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5819 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5821 ret
= GetLastError ();
5822 ERR ("HeapFree failed with code %i\n", ret
);
5823 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5824 WARN ("HeapFree failed with code %i\n", GetLastError ());
5825 r
= RegCloseKey (hkSubKey
);
5826 if (r
!= ERROR_SUCCESS
)
5827 WARN ("RegCloseKey returned %i\n", r
);
5831 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5833 ret
= GetLastError ();
5834 ERR ("HeapFree failed with code %i\n", ret
);
5835 r
= RegCloseKey (hkSubKey
);
5836 if (r
!= ERROR_SUCCESS
)
5837 WARN ("RegCloseKey returned %i\n", r
);
5841 ret
= RegCloseKey (hkSubKey
);
5842 if (ret
!= ERROR_SUCCESS
)
5844 ERR ("RegCloseKey returned %i\n", ret
);
5848 return ERROR_SUCCESS
;
5851 /*******************************************************************************
5852 * EnumPrinterDataExA [WINSPOOL.@]
5854 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5855 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5856 * what Windows 2000 SP1 does.
5859 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5860 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5861 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5865 DWORD ret
, dwIndex
, dwBufSize
;
5869 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5871 if (pKeyName
== NULL
|| *pKeyName
== 0)
5872 return ERROR_INVALID_PARAMETER
;
5874 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5877 ret
= GetLastError ();
5878 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5882 hHeap
= GetProcessHeap ();
5885 ERR ("GetProcessHeap failed\n");
5886 return ERROR_OUTOFMEMORY
;
5889 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5890 if (pKeyNameW
== NULL
)
5892 ERR ("Failed to allocate %i bytes from process heap\n",
5893 (LONG
)(len
* sizeof (WCHAR
)));
5894 return ERROR_OUTOFMEMORY
;
5897 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5899 ret
= GetLastError ();
5900 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5901 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5906 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5907 pcbEnumValues
, pnEnumValues
);
5908 if (ret
!= ERROR_SUCCESS
)
5910 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5912 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5916 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5918 ret
= GetLastError ();
5919 ERR ("HeapFree failed with code %i\n", ret
);
5923 if (*pnEnumValues
== 0) /* empty key */
5924 return ERROR_SUCCESS
;
5927 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5929 PPRINTER_ENUM_VALUESW ppev
=
5930 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5932 if (dwBufSize
< ppev
->cbValueName
)
5933 dwBufSize
= ppev
->cbValueName
;
5935 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5936 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5937 dwBufSize
= ppev
->cbData
;
5940 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5942 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5943 if (pBuffer
== NULL
)
5945 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5946 return ERROR_OUTOFMEMORY
;
5949 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5951 PPRINTER_ENUM_VALUESW ppev
=
5952 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5954 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5955 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5959 ret
= GetLastError ();
5960 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5961 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5966 memcpy (ppev
->pValueName
, pBuffer
, len
);
5968 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5970 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5971 ppev
->dwType
!= REG_MULTI_SZ
)
5974 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5975 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5978 ret
= GetLastError ();
5979 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5980 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5981 WARN ("HeapFree failed with code %i\n", GetLastError ());
5985 memcpy (ppev
->pData
, pBuffer
, len
);
5987 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5988 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5991 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5993 ret
= GetLastError ();
5994 ERR ("HeapFree failed with code %i\n", ret
);
5998 return ERROR_SUCCESS
;
6001 /******************************************************************************
6002 * AbortPrinter (WINSPOOL.@)
6004 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6006 FIXME("(%p), stub!\n", hPrinter
);
6010 /******************************************************************************
6011 * AddPortA (WINSPOOL.@)
6016 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6018 LPWSTR nameW
= NULL
;
6019 LPWSTR monitorW
= NULL
;
6023 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6026 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6027 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6028 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6032 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6033 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6034 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6036 res
= AddPortW(nameW
, hWnd
, monitorW
);
6037 HeapFree(GetProcessHeap(), 0, nameW
);
6038 HeapFree(GetProcessHeap(), 0, monitorW
);
6042 /******************************************************************************
6043 * AddPortW (WINSPOOL.@)
6045 * Add a Port for a specific Monitor
6048 * pName [I] Servername or NULL (local Computer)
6049 * hWnd [I] Handle to parent Window for the Dialog-Box
6050 * pMonitorName [I] Name of the Monitor that manage the Port
6057 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6059 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6061 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6063 if (!pMonitorName
) {
6064 SetLastError(RPC_X_NULL_REF_POINTER
);
6068 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6071 /******************************************************************************
6072 * AddPortExA (WINSPOOL.@)
6077 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6080 PORT_INFO_2A
* pi2A
;
6081 LPWSTR nameW
= NULL
;
6082 LPWSTR monitorW
= NULL
;
6086 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6088 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6089 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6091 if ((level
< 1) || (level
> 2)) {
6092 SetLastError(ERROR_INVALID_LEVEL
);
6097 SetLastError(ERROR_INVALID_PARAMETER
);
6102 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6103 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6104 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6108 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6109 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6110 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6113 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6115 if (pi2A
->pPortName
) {
6116 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6117 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6118 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6122 if (pi2A
->pMonitorName
) {
6123 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6124 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6125 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6128 if (pi2A
->pDescription
) {
6129 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6130 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6131 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6133 pi2W
.fPortType
= pi2A
->fPortType
;
6134 pi2W
.Reserved
= pi2A
->Reserved
;
6137 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6139 HeapFree(GetProcessHeap(), 0, nameW
);
6140 HeapFree(GetProcessHeap(), 0, monitorW
);
6141 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6142 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6143 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6148 /******************************************************************************
6149 * AddPortExW (WINSPOOL.@)
6151 * Add a Port for a specific Monitor, without presenting a user interface
6154 * pName [I] Servername or NULL (local Computer)
6155 * level [I] Structure-Level (1 or 2) for pBuffer
6156 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6157 * pMonitorName [I] Name of the Monitor that manage the Port
6164 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6168 pi2
= (PORT_INFO_2W
*) pBuffer
;
6170 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6171 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6172 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6173 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6175 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6177 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6178 SetLastError(ERROR_INVALID_PARAMETER
);
6182 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6185 /******************************************************************************
6186 * AddPrinterConnectionA (WINSPOOL.@)
6188 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6190 FIXME("%s\n", debugstr_a(pName
));
6194 /******************************************************************************
6195 * AddPrinterConnectionW (WINSPOOL.@)
6197 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6199 FIXME("%s\n", debugstr_w(pName
));
6203 /******************************************************************************
6204 * AddPrinterDriverExW (WINSPOOL.@)
6206 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6209 * pName [I] Servername or NULL (local Computer)
6210 * level [I] Level for the supplied DRIVER_INFO_*W struct
6211 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6212 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6219 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6221 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6223 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6225 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6226 SetLastError(ERROR_INVALID_LEVEL
);
6231 SetLastError(ERROR_INVALID_PARAMETER
);
6235 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6238 /******************************************************************************
6239 * AddPrinterDriverExA (WINSPOOL.@)
6241 * See AddPrinterDriverExW.
6244 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6246 DRIVER_INFO_8A
*diA
;
6248 LPWSTR nameW
= NULL
;
6253 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6255 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6256 ZeroMemory(&diW
, sizeof(diW
));
6258 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6259 SetLastError(ERROR_INVALID_LEVEL
);
6264 SetLastError(ERROR_INVALID_PARAMETER
);
6268 /* convert servername to unicode */
6270 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6271 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6272 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6276 diW
.cVersion
= diA
->cVersion
;
6279 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6280 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6281 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6284 if (diA
->pEnvironment
) {
6285 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6286 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6287 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6290 if (diA
->pDriverPath
) {
6291 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6292 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6293 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6296 if (diA
->pDataFile
) {
6297 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6298 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6299 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6302 if (diA
->pConfigFile
) {
6303 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6304 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6305 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6308 if ((Level
> 2) && diA
->pDependentFiles
) {
6309 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6310 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6311 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6312 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6315 if ((Level
> 2) && diA
->pMonitorName
) {
6316 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6317 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6318 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6321 if ((Level
> 3) && diA
->pDefaultDataType
) {
6322 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6323 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6324 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6327 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6328 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6329 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6330 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6331 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6334 if ((Level
> 5) && diA
->pszMfgName
) {
6335 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6336 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6337 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6340 if ((Level
> 5) && diA
->pszOEMUrl
) {
6341 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6342 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6343 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6346 if ((Level
> 5) && diA
->pszHardwareID
) {
6347 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6348 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6349 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6352 if ((Level
> 5) && diA
->pszProvider
) {
6353 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6354 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6355 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6359 FIXME("level %u is incomplete\n", Level
);
6362 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6363 TRACE("got %u with %u\n", res
, GetLastError());
6364 HeapFree(GetProcessHeap(), 0, nameW
);
6365 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6366 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6367 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6368 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6369 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6370 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6371 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6372 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6373 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6374 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6375 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6376 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6377 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6379 TRACE("=> %u with %u\n", res
, GetLastError());
6383 /******************************************************************************
6384 * ConfigurePortA (WINSPOOL.@)
6386 * See ConfigurePortW.
6389 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6391 LPWSTR nameW
= NULL
;
6392 LPWSTR portW
= NULL
;
6396 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6398 /* convert servername to unicode */
6400 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6401 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6402 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6405 /* convert portname to unicode */
6407 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6408 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6409 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6412 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6413 HeapFree(GetProcessHeap(), 0, nameW
);
6414 HeapFree(GetProcessHeap(), 0, portW
);
6418 /******************************************************************************
6419 * ConfigurePortW (WINSPOOL.@)
6421 * Display the Configuration-Dialog for a specific Port
6424 * pName [I] Servername or NULL (local Computer)
6425 * hWnd [I] Handle to parent Window for the Dialog-Box
6426 * pPortName [I] Name of the Port, that should be configured
6433 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6436 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6438 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6441 SetLastError(RPC_X_NULL_REF_POINTER
);
6445 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6448 /******************************************************************************
6449 * ConnectToPrinterDlg (WINSPOOL.@)
6451 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6453 FIXME("%p %x\n", hWnd
, Flags
);
6457 /******************************************************************************
6458 * DeletePrinterConnectionA (WINSPOOL.@)
6460 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6462 FIXME("%s\n", debugstr_a(pName
));
6466 /******************************************************************************
6467 * DeletePrinterConnectionW (WINSPOOL.@)
6469 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6471 FIXME("%s\n", debugstr_w(pName
));
6475 /******************************************************************************
6476 * DeletePrinterDriverExW (WINSPOOL.@)
6478 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6479 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6484 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6485 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6487 if(pName
&& pName
[0])
6489 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6490 SetLastError(ERROR_INVALID_PARAMETER
);
6496 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6497 SetLastError(ERROR_INVALID_PARAMETER
);
6501 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6505 ERR("Can't open drivers key\n");
6509 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6512 RegCloseKey(hkey_drivers
);
6517 /******************************************************************************
6518 * DeletePrinterDriverExA (WINSPOOL.@)
6520 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6521 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6523 UNICODE_STRING NameW
, EnvW
, DriverW
;
6526 asciitounicode(&NameW
, pName
);
6527 asciitounicode(&EnvW
, pEnvironment
);
6528 asciitounicode(&DriverW
, pDriverName
);
6530 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6532 RtlFreeUnicodeString(&DriverW
);
6533 RtlFreeUnicodeString(&EnvW
);
6534 RtlFreeUnicodeString(&NameW
);
6539 /******************************************************************************
6540 * DeletePrinterDataExW (WINSPOOL.@)
6542 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6545 FIXME("%p %s %s\n", hPrinter
,
6546 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6547 return ERROR_INVALID_PARAMETER
;
6550 /******************************************************************************
6551 * DeletePrinterDataExA (WINSPOOL.@)
6553 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6556 FIXME("%p %s %s\n", hPrinter
,
6557 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6558 return ERROR_INVALID_PARAMETER
;
6561 /******************************************************************************
6562 * DeletePrintProcessorA (WINSPOOL.@)
6564 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6566 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6567 debugstr_a(pPrintProcessorName
));
6571 /******************************************************************************
6572 * DeletePrintProcessorW (WINSPOOL.@)
6574 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6576 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6577 debugstr_w(pPrintProcessorName
));
6581 /******************************************************************************
6582 * DeletePrintProvidorA (WINSPOOL.@)
6584 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6586 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6587 debugstr_a(pPrintProviderName
));
6591 /******************************************************************************
6592 * DeletePrintProvidorW (WINSPOOL.@)
6594 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6596 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6597 debugstr_w(pPrintProviderName
));
6601 /******************************************************************************
6602 * EnumFormsA (WINSPOOL.@)
6604 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6605 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6607 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6608 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6612 /******************************************************************************
6613 * EnumFormsW (WINSPOOL.@)
6615 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6616 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6618 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6619 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6623 /*****************************************************************************
6624 * EnumMonitorsA [WINSPOOL.@]
6626 * See EnumMonitorsW.
6629 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6630 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6633 LPBYTE bufferW
= NULL
;
6634 LPWSTR nameW
= NULL
;
6636 DWORD numentries
= 0;
6639 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6640 cbBuf
, pcbNeeded
, pcReturned
);
6642 /* convert servername to unicode */
6644 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6645 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6646 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6648 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6649 needed
= cbBuf
* sizeof(WCHAR
);
6650 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6651 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6653 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6654 if (pcbNeeded
) needed
= *pcbNeeded
;
6655 /* HeapReAlloc return NULL, when bufferW was NULL */
6656 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6657 HeapAlloc(GetProcessHeap(), 0, needed
);
6659 /* Try again with the large Buffer */
6660 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6662 numentries
= pcReturned
? *pcReturned
: 0;
6665 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6666 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6669 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6670 DWORD entrysize
= 0;
6673 LPMONITOR_INFO_2W mi2w
;
6674 LPMONITOR_INFO_2A mi2a
;
6676 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6677 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6679 /* First pass: calculate the size for all Entries */
6680 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6681 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6683 while (index
< numentries
) {
6685 needed
+= entrysize
; /* MONITOR_INFO_?A */
6686 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6688 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6689 NULL
, 0, NULL
, NULL
);
6691 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6692 NULL
, 0, NULL
, NULL
);
6693 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6694 NULL
, 0, NULL
, NULL
);
6696 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6697 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6698 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6701 /* check for errors and quit on failure */
6702 if (cbBuf
< needed
) {
6703 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6707 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6708 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6709 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6710 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6711 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6713 /* Second Pass: Fill the User Buffer (if we have one) */
6714 while ((index
< numentries
) && pMonitors
) {
6716 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6718 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6719 ptr
, cbBuf
, NULL
, NULL
);
6723 mi2a
->pEnvironment
= ptr
;
6724 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6725 ptr
, cbBuf
, NULL
, NULL
);
6729 mi2a
->pDLLName
= ptr
;
6730 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6731 ptr
, cbBuf
, NULL
, NULL
);
6735 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6736 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6737 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6741 if (pcbNeeded
) *pcbNeeded
= needed
;
6742 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6744 HeapFree(GetProcessHeap(), 0, nameW
);
6745 HeapFree(GetProcessHeap(), 0, bufferW
);
6747 TRACE("returning %d with %d (%d byte for %d entries)\n",
6748 (res
), GetLastError(), needed
, numentries
);
6754 /*****************************************************************************
6755 * EnumMonitorsW [WINSPOOL.@]
6757 * Enumerate available Port-Monitors
6760 * pName [I] Servername or NULL (local Computer)
6761 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6762 * pMonitors [O] PTR to Buffer that receives the Result
6763 * cbBuf [I] Size of Buffer at pMonitors
6764 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6765 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6769 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6772 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6773 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6776 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6777 cbBuf
, pcbNeeded
, pcReturned
);
6779 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6781 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6782 SetLastError(RPC_X_NULL_REF_POINTER
);
6786 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6789 /******************************************************************************
6790 * SpoolerInit (WINSPOOL.@)
6792 * Initialize the Spooler
6799 * The function fails on windows, when the spooler service is not running
6802 BOOL WINAPI
SpoolerInit(void)
6805 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6809 /******************************************************************************
6810 * XcvDataW (WINSPOOL.@)
6812 * Execute commands in the Printmonitor DLL
6815 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6816 * pszDataName [i] Name of the command to execute
6817 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6818 * cbInputData [i] Size in Bytes of Buffer at pInputData
6819 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6820 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6821 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6822 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6829 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6830 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6832 * Minimal List of commands, that a Printmonitor DLL should support:
6834 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6835 *| "AddPort" : Add a Port
6836 *| "DeletePort": Delete a Port
6838 * Many Printmonitors support additional commands. Examples for localspl.dll:
6839 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6840 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6843 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6844 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6845 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6847 opened_printer_t
*printer
;
6849 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6850 pInputData
, cbInputData
, pOutputData
,
6851 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6853 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6855 printer
= get_opened_printer(hXcv
);
6856 if (!printer
|| (!printer
->backend_printer
)) {
6857 SetLastError(ERROR_INVALID_HANDLE
);
6861 if (!pcbOutputNeeded
) {
6862 SetLastError(ERROR_INVALID_PARAMETER
);
6866 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6867 SetLastError(RPC_X_NULL_REF_POINTER
);
6871 *pcbOutputNeeded
= 0;
6873 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6874 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6878 /*****************************************************************************
6879 * EnumPrinterDataA [WINSPOOL.@]
6882 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6883 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6884 DWORD cbData
, LPDWORD pcbData
)
6886 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6887 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6888 return ERROR_NO_MORE_ITEMS
;
6891 /*****************************************************************************
6892 * EnumPrinterDataW [WINSPOOL.@]
6895 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6896 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6897 DWORD cbData
, LPDWORD pcbData
)
6899 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6900 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6901 return ERROR_NO_MORE_ITEMS
;
6904 /*****************************************************************************
6905 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6908 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6909 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6910 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6912 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6913 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6914 pcbNeeded
, pcReturned
);
6918 /*****************************************************************************
6919 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6922 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6923 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6924 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6926 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6927 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6928 pcbNeeded
, pcReturned
);
6932 /*****************************************************************************
6933 * EnumPrintProcessorsA [WINSPOOL.@]
6935 * See EnumPrintProcessorsW.
6938 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6939 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6942 LPBYTE bufferW
= NULL
;
6943 LPWSTR nameW
= NULL
;
6946 DWORD numentries
= 0;
6949 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6950 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6952 /* convert names to unicode */
6954 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6955 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6956 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6959 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6960 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6961 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6964 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6965 needed
= cbBuf
* sizeof(WCHAR
);
6966 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6967 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6969 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6970 if (pcbNeeded
) needed
= *pcbNeeded
;
6971 /* HeapReAlloc return NULL, when bufferW was NULL */
6972 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6973 HeapAlloc(GetProcessHeap(), 0, needed
);
6975 /* Try again with the large Buffer */
6976 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6978 numentries
= pcReturned
? *pcReturned
: 0;
6982 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6985 PPRINTPROCESSOR_INFO_1W ppiw
;
6986 PPRINTPROCESSOR_INFO_1A ppia
;
6988 /* First pass: calculate the size for all Entries */
6989 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6990 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6992 while (index
< numentries
) {
6994 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
6995 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
6997 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6998 NULL
, 0, NULL
, NULL
);
7000 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7001 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7004 /* check for errors and quit on failure */
7005 if (cbBuf
< needed
) {
7006 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7011 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7012 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7013 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7014 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7015 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7017 /* Second Pass: Fill the User Buffer (if we have one) */
7018 while ((index
< numentries
) && pPPInfo
) {
7020 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7022 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7023 ptr
, cbBuf
, NULL
, NULL
);
7027 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7028 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7033 if (pcbNeeded
) *pcbNeeded
= needed
;
7034 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7036 HeapFree(GetProcessHeap(), 0, nameW
);
7037 HeapFree(GetProcessHeap(), 0, envW
);
7038 HeapFree(GetProcessHeap(), 0, bufferW
);
7040 TRACE("returning %d with %d (%d byte for %d entries)\n",
7041 (res
), GetLastError(), needed
, numentries
);
7046 /*****************************************************************************
7047 * EnumPrintProcessorsW [WINSPOOL.@]
7049 * Enumerate available Print Processors
7052 * pName [I] Servername or NULL (local Computer)
7053 * pEnvironment [I] Printing-Environment or NULL (Default)
7054 * Level [I] Structure-Level (Only 1 is allowed)
7055 * pPPInfo [O] PTR to Buffer that receives the Result
7056 * cbBuf [I] Size of Buffer at pPPInfo
7057 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7058 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7062 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7065 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7066 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7069 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7070 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7072 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7074 if (!pcbNeeded
|| !pcReturned
) {
7075 SetLastError(RPC_X_NULL_REF_POINTER
);
7079 if (!pPPInfo
&& (cbBuf
> 0)) {
7080 SetLastError(ERROR_INVALID_USER_BUFFER
);
7084 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7085 cbBuf
, pcbNeeded
, pcReturned
);
7088 /*****************************************************************************
7089 * ExtDeviceMode [WINSPOOL.@]
7092 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7093 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7096 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7097 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7098 debugstr_a(pProfile
), fMode
);
7102 /*****************************************************************************
7103 * FindClosePrinterChangeNotification [WINSPOOL.@]
7106 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7108 FIXME("Stub: %p\n", hChange
);
7112 /*****************************************************************************
7113 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7116 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7117 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7119 FIXME("Stub: %p %x %x %p\n",
7120 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7121 return INVALID_HANDLE_VALUE
;
7124 /*****************************************************************************
7125 * FindNextPrinterChangeNotification [WINSPOOL.@]
7128 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7129 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7131 FIXME("Stub: %p %p %p %p\n",
7132 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7136 /*****************************************************************************
7137 * FreePrinterNotifyInfo [WINSPOOL.@]
7140 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7142 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7146 /*****************************************************************************
7149 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7150 * ansi depending on the unicode parameter.
7152 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7162 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7165 memcpy(ptr
, str
, *size
);
7172 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7175 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7182 /*****************************************************************************
7185 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7186 LPDWORD pcbNeeded
, BOOL unicode
)
7188 DWORD size
, left
= cbBuf
;
7189 BOOL space
= (cbBuf
> 0);
7196 ji1
->JobId
= job
->job_id
;
7199 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7200 if(space
&& size
<= left
)
7202 ji1
->pDocument
= (LPWSTR
)ptr
;
7210 if (job
->printer_name
)
7212 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7213 if(space
&& size
<= left
)
7215 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7227 /*****************************************************************************
7230 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7231 LPDWORD pcbNeeded
, BOOL unicode
)
7233 DWORD size
, left
= cbBuf
;
7235 BOOL space
= (cbBuf
> 0);
7237 LPDEVMODEA dmA
= NULL
;
7244 ji2
->JobId
= job
->job_id
;
7247 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7248 if(space
&& size
<= left
)
7250 ji2
->pDocument
= (LPWSTR
)ptr
;
7258 if (job
->printer_name
)
7260 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7261 if(space
&& size
<= left
)
7263 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7276 dmA
= DEVMODEdupWtoA(job
->devmode
);
7277 devmode
= (LPDEVMODEW
) dmA
;
7278 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7282 devmode
= job
->devmode
;
7283 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7287 FIXME("Can't convert DEVMODE W to A\n");
7290 /* align DEVMODE to a DWORD boundary */
7291 shift
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
7297 memcpy(ptr
, devmode
, size
-shift
);
7298 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7299 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7312 /*****************************************************************************
7315 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7316 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7319 DWORD needed
= 0, size
;
7323 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7325 EnterCriticalSection(&printer_handles_cs
);
7326 job
= get_job(hPrinter
, JobId
);
7333 size
= sizeof(JOB_INFO_1W
);
7338 memset(pJob
, 0, size
);
7342 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7347 size
= sizeof(JOB_INFO_2W
);
7352 memset(pJob
, 0, size
);
7356 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7361 size
= sizeof(JOB_INFO_3
);
7365 memset(pJob
, 0, size
);
7374 SetLastError(ERROR_INVALID_LEVEL
);
7378 *pcbNeeded
= needed
;
7380 LeaveCriticalSection(&printer_handles_cs
);
7384 /*****************************************************************************
7385 * GetJobA [WINSPOOL.@]
7388 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7389 DWORD cbBuf
, LPDWORD pcbNeeded
)
7391 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7394 /*****************************************************************************
7395 * GetJobW [WINSPOOL.@]
7398 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7399 DWORD cbBuf
, LPDWORD pcbNeeded
)
7401 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7404 /*****************************************************************************
7407 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7410 char *unixname
, *cmdA
;
7412 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7418 if(!(unixname
= wine_get_unix_file_name(filename
)))
7421 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7422 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7423 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7425 TRACE("printing with: %s\n", cmdA
);
7427 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7432 ERR("pipe() failed!\n");
7436 if ((pid
= fork()) == 0)
7442 /* reset signals that we previously set to SIG_IGN */
7443 signal(SIGPIPE
, SIG_DFL
);
7445 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7450 ERR("fork() failed!\n");
7454 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7455 write(fds
[1], buf
, no_read
);
7462 wret
= waitpid(pid
, &status
, 0);
7463 } while (wret
< 0 && errno
== EINTR
);
7466 ERR("waitpid() failed!\n");
7469 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7471 ERR("child process failed! %d\n", status
);
7478 if(file_fd
!= -1) close(file_fd
);
7479 if(fds
[0] != -1) close(fds
[0]);
7480 if(fds
[1] != -1) close(fds
[1]);
7482 HeapFree(GetProcessHeap(), 0, cmdA
);
7483 HeapFree(GetProcessHeap(), 0, unixname
);
7490 /*****************************************************************************
7493 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7496 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7499 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7500 sprintfW(cmd
, fmtW
, printer_name
);
7502 r
= schedule_pipe(cmd
, filename
);
7504 HeapFree(GetProcessHeap(), 0, cmd
);
7508 /*****************************************************************************
7511 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7513 #ifdef SONAME_LIBCUPS
7516 char *unixname
, *queue
, *unix_doc_title
;
7520 if(!(unixname
= wine_get_unix_file_name(filename
)))
7523 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7524 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7525 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7527 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7528 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7529 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7531 TRACE("printing via cups\n");
7532 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7533 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7534 HeapFree(GetProcessHeap(), 0, queue
);
7535 HeapFree(GetProcessHeap(), 0, unixname
);
7541 return schedule_lpr(printer_name
, filename
);
7545 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7552 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7556 if(HIWORD(wparam
) == BN_CLICKED
)
7558 if(LOWORD(wparam
) == IDOK
)
7561 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7564 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7565 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7567 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7569 WCHAR caption
[200], message
[200];
7572 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7573 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7574 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7575 if(mb_ret
== IDCANCEL
)
7577 HeapFree(GetProcessHeap(), 0, filename
);
7581 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7582 if(hf
== INVALID_HANDLE_VALUE
)
7584 WCHAR caption
[200], message
[200];
7586 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7587 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7588 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7589 HeapFree(GetProcessHeap(), 0, filename
);
7593 DeleteFileW(filename
);
7594 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7596 EndDialog(hwnd
, IDOK
);
7599 if(LOWORD(wparam
) == IDCANCEL
)
7601 EndDialog(hwnd
, IDCANCEL
);
7610 /*****************************************************************************
7613 static BOOL
get_filename(LPWSTR
*filename
)
7615 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7616 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7619 /*****************************************************************************
7622 static BOOL
schedule_file(LPCWSTR filename
)
7624 LPWSTR output
= NULL
;
7626 if(get_filename(&output
))
7629 TRACE("copy to %s\n", debugstr_w(output
));
7630 r
= CopyFileW(filename
, output
, FALSE
);
7631 HeapFree(GetProcessHeap(), 0, output
);
7637 /*****************************************************************************
7640 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7642 int in_fd
, out_fd
, no_read
;
7645 char *unixname
, *outputA
;
7648 if(!(unixname
= wine_get_unix_file_name(filename
)))
7651 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7652 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7653 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7655 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7656 in_fd
= open(unixname
, O_RDONLY
);
7657 if(out_fd
== -1 || in_fd
== -1)
7660 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7661 write(out_fd
, buf
, no_read
);
7665 if(in_fd
!= -1) close(in_fd
);
7666 if(out_fd
!= -1) close(out_fd
);
7667 HeapFree(GetProcessHeap(), 0, outputA
);
7668 HeapFree(GetProcessHeap(), 0, unixname
);
7672 /*****************************************************************************
7673 * ScheduleJob [WINSPOOL.@]
7676 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7678 opened_printer_t
*printer
;
7680 struct list
*cursor
, *cursor2
;
7682 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7683 EnterCriticalSection(&printer_handles_cs
);
7684 printer
= get_opened_printer(hPrinter
);
7688 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7690 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7693 if(job
->job_id
!= dwJobID
) continue;
7695 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7696 if(hf
!= INVALID_HANDLE_VALUE
)
7698 PRINTER_INFO_5W
*pi5
= NULL
;
7699 LPWSTR portname
= job
->portname
;
7703 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7704 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7708 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7709 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7710 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7711 portname
= pi5
->pPortName
;
7713 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7714 debugstr_w(portname
));
7718 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7719 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7721 DWORD type
, count
= sizeof(output
);
7722 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7725 if(output
[0] == '|')
7727 ret
= schedule_pipe(output
+ 1, job
->filename
);
7731 ret
= schedule_unixfile(output
, job
->filename
);
7733 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7735 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7737 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7739 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7741 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7743 ret
= schedule_file(job
->filename
);
7747 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7749 HeapFree(GetProcessHeap(), 0, pi5
);
7751 DeleteFileW(job
->filename
);
7753 list_remove(cursor
);
7754 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7755 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7756 HeapFree(GetProcessHeap(), 0, job
->portname
);
7757 HeapFree(GetProcessHeap(), 0, job
->filename
);
7758 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7759 HeapFree(GetProcessHeap(), 0, job
);
7763 LeaveCriticalSection(&printer_handles_cs
);
7767 /*****************************************************************************
7768 * StartDocDlgA [WINSPOOL.@]
7770 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7772 UNICODE_STRING usBuffer
;
7775 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7778 docW
.cbSize
= sizeof(docW
);
7779 if (doc
->lpszDocName
)
7781 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7782 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7784 if (doc
->lpszOutput
)
7786 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7787 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7789 if (doc
->lpszDatatype
)
7791 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7792 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7794 docW
.fwType
= doc
->fwType
;
7796 retW
= StartDocDlgW(hPrinter
, &docW
);
7800 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7801 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7802 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7803 HeapFree(GetProcessHeap(), 0, retW
);
7806 HeapFree(GetProcessHeap(), 0, datatypeW
);
7807 HeapFree(GetProcessHeap(), 0, outputW
);
7808 HeapFree(GetProcessHeap(), 0, docnameW
);
7813 /*****************************************************************************
7814 * StartDocDlgW [WINSPOOL.@]
7816 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7817 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7818 * port is "FILE:". Also returns the full path if passed a relative path.
7820 * The caller should free the returned string from the process heap.
7822 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7827 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7829 PRINTER_INFO_5W
*pi5
;
7830 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7831 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7833 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7834 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7835 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7837 HeapFree(GetProcessHeap(), 0, pi5
);
7840 HeapFree(GetProcessHeap(), 0, pi5
);
7843 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7847 if (get_filename(&name
))
7849 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7851 HeapFree(GetProcessHeap(), 0, name
);
7854 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7855 GetFullPathNameW(name
, len
, ret
, NULL
);
7856 HeapFree(GetProcessHeap(), 0, name
);
7861 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7864 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7865 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7867 attr
= GetFileAttributesW(ret
);
7868 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7870 HeapFree(GetProcessHeap(), 0, ret
);