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
;
107 WCHAR
*document_title
;
117 LPCWSTR versionregpath
;
118 LPCWSTR versionsubdir
;
121 /* ############################### */
123 static opened_printer_t
**printer_handles
;
124 static UINT nb_printer_handles
;
125 static LONG next_job_id
= 1;
127 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
128 WORD fwCapability
, LPSTR lpszOutput
,
130 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
131 LPSTR lpszDevice
, LPSTR lpszPort
,
132 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
135 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
186 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW
[] = {'\\',0};
188 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW
[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW
[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW
[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW
[] = {'R','A','W',0};
222 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW
[] = {',',0};
226 static WCHAR emptyStringW
[] = {0};
228 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
238 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
239 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
240 0, sizeof(DRIVER_INFO_8W
)};
243 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
244 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
245 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
246 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
247 sizeof(PRINTER_INFO_9W
)};
249 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
250 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
251 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
253 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
259 * env [I] PTR to Environment-String or NULL
263 * Success: PTR to printenv_t
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t
* validate_envW(LPCWSTR env
)
273 const printenv_t
*result
= NULL
;
276 TRACE("testing %s\n", debugstr_w(env
));
279 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
281 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
283 result
= all_printenv
[i
];
288 if (result
== NULL
) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
290 SetLastError(ERROR_INVALID_ENVIRONMENT
);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
298 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
312 return usBufferPtr
->Buffer
;
314 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR
strdupW(LPCWSTR p
)
324 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
325 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
330 static LPSTR
strdupWtoA( LPCWSTR str
)
335 if (!str
) return NULL
;
336 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
337 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
338 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
342 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
346 if (!dm
) return NULL
;
347 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
348 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
352 /******************************************************************
353 * verify, that the filename is a local file
356 static inline BOOL
is_local_file(LPWSTR name
)
358 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
361 /* ################################ */
363 static int multi_sz_lenA(const char *str
)
365 const char *ptr
= str
;
369 ptr
+= lstrlenA(ptr
) + 1;
372 return ptr
- str
+ 1;
376 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
379 /* If forcing, or no profile string entry for device yet, set the entry
381 * The always change entry if not WINEPS yet is discussable.
384 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
386 !strstr(qbuf
,"WINEPS.DRV")
388 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
391 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
392 WriteProfileStringA("windows","device",buf
);
393 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
394 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
397 HeapFree(GetProcessHeap(),0,buf
);
401 static BOOL
add_printer_driver(WCHAR
*name
)
405 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
408 di3
.pEnvironment
= envname_x86W
;
409 di3
.pDriverPath
= driver_nt
;
410 di3
.pDataFile
= generic_ppdW
;
411 di3
.pConfigFile
= driver_nt
;
412 di3
.pDefaultDataType
= rawW
;
414 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
415 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
418 di3
.pEnvironment
= envname_win40W
;
419 di3
.pDriverPath
= driver_9x
;
420 di3
.pConfigFile
= driver_9x
;
421 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
422 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
427 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
431 #ifdef SONAME_LIBCUPS
432 static typeof(cupsFreeDests
) *pcupsFreeDests
;
433 static typeof(cupsGetDests
) *pcupsGetDests
;
434 static typeof(cupsGetPPD
) *pcupsGetPPD
;
435 static typeof(cupsPrintFile
) *pcupsPrintFile
;
436 static void *cupshandle
;
438 static BOOL
CUPS_LoadPrinters(void)
441 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
445 HKEY hkeyPrinter
, hkeyPrinters
;
447 WCHAR nameW
[MAX_PATH
];
449 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
451 TRACE("%s\n", loaderror
);
454 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
457 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
458 if (!p##x) return FALSE;
460 DYNCUPS(cupsFreeDests
);
462 DYNCUPS(cupsGetDests
);
463 DYNCUPS(cupsPrintFile
);
466 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
468 ERR("Can't create Printers key\n");
472 nrofdests
= pcupsGetDests(&dests
);
473 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
474 for (i
=0;i
<nrofdests
;i
++) {
475 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
477 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
478 lstrcpyW(port
, CUPS_Port
);
479 lstrcatW(port
, nameW
);
481 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
482 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
483 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
485 TRACE("Printer already exists\n");
486 /* overwrite old LPR:* port */
487 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
488 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
489 RegCloseKey(hkeyPrinter
);
491 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
492 ' ','u','s','i','n','g',' ','C','U','P','S',0};
494 add_printer_driver(nameW
);
496 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
497 pi2
.pPrinterName
= nameW
;
498 pi2
.pDatatype
= rawW
;
499 pi2
.pPrintProcessor
= WinPrintW
;
500 pi2
.pDriverName
= nameW
;
501 pi2
.pComment
= comment_cups
;
502 pi2
.pLocation
= emptyStringW
;
503 pi2
.pPortName
= port
;
504 pi2
.pParameters
= emptyStringW
;
505 pi2
.pShareName
= emptyStringW
;
506 pi2
.pSepFile
= emptyStringW
;
508 if (!AddPrinterW(NULL
, 2, (LPBYTE
)&pi2
)) {
509 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
510 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError());
513 HeapFree(GetProcessHeap(),0,port
);
516 if (dests
[i
].is_default
) {
517 SetDefaultPrinterW(nameW
);
521 if (hadprinter
&& !haddefault
) {
522 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
523 SetDefaultPrinterW(nameW
);
525 pcupsFreeDests(nrofdests
, dests
);
526 RegCloseKey(hkeyPrinters
);
532 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
533 PRINTER_INFO_2A pinfo2a
;
536 char *e
,*s
,*name
,*prettyname
,*devname
;
537 BOOL ret
= FALSE
, set_default
= FALSE
;
538 char *port
= NULL
, *env_default
;
539 HKEY hkeyPrinter
, hkeyPrinters
;
540 WCHAR devnameW
[MAX_PATH
];
542 while (isspace(*pent
)) pent
++;
543 r
= strchr(pent
,':');
547 name_len
= strlen(pent
);
548 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
549 memcpy(name
, pent
, name_len
);
550 name
[name_len
] = '\0';
556 TRACE("name=%s entry=%s\n",name
, pent
);
558 if(ispunct(*name
)) { /* a tc entry, not a real printer */
559 TRACE("skipping tc entry\n");
563 if(strstr(pent
,":server")) { /* server only version so skip */
564 TRACE("skipping server entry\n");
568 /* Determine whether this is a postscript printer. */
571 env_default
= getenv("PRINTER");
573 /* Get longest name, usually the one at the right for later display. */
574 while((s
=strchr(prettyname
,'|'))) {
577 while(isspace(*--e
)) *e
= '\0';
578 TRACE("\t%s\n", debugstr_a(prettyname
));
579 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
580 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
583 e
= prettyname
+ strlen(prettyname
);
584 while(isspace(*--e
)) *e
= '\0';
585 TRACE("\t%s\n", debugstr_a(prettyname
));
586 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
588 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
589 * if it is too long, we use it as comment below. */
590 devname
= prettyname
;
591 if (strlen(devname
)>=CCHDEVICENAME
-1)
593 if (strlen(devname
)>=CCHDEVICENAME
-1) {
598 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
599 sprintf(port
,"LPR:%s",name
);
601 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
603 ERR("Can't create Printers key\n");
608 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
610 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
611 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
613 TRACE("Printer already exists\n");
614 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
615 RegCloseKey(hkeyPrinter
);
617 static CHAR data_type
[] = "RAW",
618 print_proc
[] = "WinPrint",
619 comment
[] = "WINEPS Printer using LPR",
620 params
[] = "<parameters?>",
621 share_name
[] = "<share name?>",
622 sep_file
[] = "<sep file?>";
624 add_printer_driver(devnameW
);
626 memset(&pinfo2a
,0,sizeof(pinfo2a
));
627 pinfo2a
.pPrinterName
= devname
;
628 pinfo2a
.pDatatype
= data_type
;
629 pinfo2a
.pPrintProcessor
= print_proc
;
630 pinfo2a
.pDriverName
= devname
;
631 pinfo2a
.pComment
= comment
;
632 pinfo2a
.pLocation
= prettyname
;
633 pinfo2a
.pPortName
= port
;
634 pinfo2a
.pParameters
= params
;
635 pinfo2a
.pShareName
= share_name
;
636 pinfo2a
.pSepFile
= sep_file
;
638 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
639 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
640 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
643 RegCloseKey(hkeyPrinters
);
645 if (isfirst
|| set_default
)
646 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
649 HeapFree(GetProcessHeap(), 0, port
);
650 HeapFree(GetProcessHeap(), 0, name
);
655 PRINTCAP_LoadPrinters(void) {
656 BOOL hadprinter
= FALSE
;
660 BOOL had_bash
= FALSE
;
662 f
= fopen("/etc/printcap","r");
666 while(fgets(buf
,sizeof(buf
),f
)) {
669 end
=strchr(buf
,'\n');
673 while(isspace(*start
)) start
++;
674 if(*start
== '#' || *start
== '\0')
677 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
678 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
679 HeapFree(GetProcessHeap(),0,pent
);
683 if (end
&& *--end
== '\\') {
690 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
693 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
699 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
700 HeapFree(GetProcessHeap(),0,pent
);
706 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
709 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
710 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
712 return ERROR_FILE_NOT_FOUND
;
715 /******************************************************************
716 * get_servername_from_name (internal)
718 * for an external server, a copy of the serverpart from the full name is returned
721 static LPWSTR
get_servername_from_name(LPCWSTR name
)
725 WCHAR buffer
[MAX_PATH
];
728 if (name
== NULL
) return NULL
;
729 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
731 server
= strdupW(&name
[2]); /* skip over both backslash */
732 if (server
== NULL
) return NULL
;
734 /* strip '\' and the printername */
735 ptr
= strchrW(server
, '\\');
736 if (ptr
) ptr
[0] = '\0';
738 TRACE("found %s\n", debugstr_w(server
));
740 len
= sizeof(buffer
)/sizeof(buffer
[0]);
741 if (GetComputerNameW(buffer
, &len
)) {
742 if (lstrcmpW(buffer
, server
) == 0) {
743 /* The requested Servername is our computername */
744 HeapFree(GetProcessHeap(), 0, server
);
751 /******************************************************************
752 * get_basename_from_name (internal)
754 * skip over the serverpart from the full name
757 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
759 if (name
== NULL
) return NULL
;
760 if ((name
[0] == '\\') && (name
[1] == '\\')) {
761 /* skip over the servername and search for the following '\' */
762 name
= strchrW(&name
[2], '\\');
763 if ((name
) && (name
[1])) {
764 /* found a separator ('\') followed by a name:
765 skip over the separator and return the rest */
770 /* no basename present (we found only a servername) */
777 static void free_printer_entry( opened_printer_t
*printer
)
779 /* the queue is shared, so don't free that here */
780 HeapFree( GetProcessHeap(), 0, printer
->printername
);
781 HeapFree( GetProcessHeap(), 0, printer
->name
);
782 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
783 HeapFree( GetProcessHeap(), 0, printer
);
786 /******************************************************************
787 * get_opened_printer_entry
788 * Get the first place empty in the opened printer table
791 * - pDefault is ignored
793 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
795 UINT_PTR handle
= nb_printer_handles
, i
;
796 jobqueue_t
*queue
= NULL
;
797 opened_printer_t
*printer
= NULL
;
801 if ((backend
== NULL
) && !load_backend()) return NULL
;
803 servername
= get_servername_from_name(name
);
805 FIXME("server %s not supported\n", debugstr_w(servername
));
806 HeapFree(GetProcessHeap(), 0, servername
);
807 SetLastError(ERROR_INVALID_PRINTER_NAME
);
811 printername
= get_basename_from_name(name
);
812 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
814 /* an empty printername is invalid */
815 if (printername
&& (!printername
[0])) {
816 SetLastError(ERROR_INVALID_PARAMETER
);
820 EnterCriticalSection(&printer_handles_cs
);
822 for (i
= 0; i
< nb_printer_handles
; i
++)
824 if (!printer_handles
[i
])
826 if(handle
== nb_printer_handles
)
831 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
832 queue
= printer_handles
[i
]->queue
;
836 if (handle
>= nb_printer_handles
)
838 opened_printer_t
**new_array
;
840 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
841 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
843 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
844 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
851 printer_handles
= new_array
;
852 nb_printer_handles
+= 16;
855 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
861 /* get a printer handle from the backend */
862 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
867 /* clone the base name. This is NULL for the printserver */
868 printer
->printername
= strdupW(printername
);
870 /* clone the full name */
871 printer
->name
= strdupW(name
);
872 if (name
&& (!printer
->name
)) {
877 if (pDefault
&& pDefault
->pDevMode
)
878 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
881 printer
->queue
= queue
;
884 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
885 if (!printer
->queue
) {
889 list_init(&printer
->queue
->jobs
);
890 printer
->queue
->ref
= 0;
892 InterlockedIncrement(&printer
->queue
->ref
);
894 printer_handles
[handle
] = printer
;
897 LeaveCriticalSection(&printer_handles_cs
);
898 if (!handle
&& printer
) {
899 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
900 free_printer_entry( printer
);
903 return (HANDLE
)handle
;
906 /******************************************************************
908 * Get the pointer to the opened printer referred by the handle
910 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
912 UINT_PTR idx
= (UINT_PTR
)hprn
;
913 opened_printer_t
*ret
= NULL
;
915 EnterCriticalSection(&printer_handles_cs
);
917 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
918 ret
= printer_handles
[idx
- 1];
920 LeaveCriticalSection(&printer_handles_cs
);
924 /******************************************************************
925 * get_opened_printer_name
926 * Get the pointer to the opened printer name referred by the handle
928 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
930 opened_printer_t
*printer
= get_opened_printer(hprn
);
931 if(!printer
) return NULL
;
932 return printer
->name
;
935 /******************************************************************
936 * WINSPOOL_GetOpenedPrinterRegKey
939 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
941 LPCWSTR name
= get_opened_printer_name(hPrinter
);
945 if(!name
) return ERROR_INVALID_HANDLE
;
947 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
951 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
953 ERR("Can't find opened printer %s in registry\n",
955 RegCloseKey(hkeyPrinters
);
956 return ERROR_INVALID_PRINTER_NAME
; /* ? */
958 RegCloseKey(hkeyPrinters
);
959 return ERROR_SUCCESS
;
962 void WINSPOOL_LoadSystemPrinters(void)
964 HKEY hkey
, hkeyPrinters
;
966 DWORD needed
, num
, i
;
967 WCHAR PrinterName
[256];
970 /* This ensures that all printer entries have a valid Name value. If causes
971 problems later if they don't. If one is found to be missed we create one
972 and set it equal to the name of the key */
973 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
974 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
975 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
976 for(i
= 0; i
< num
; i
++) {
977 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
978 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
979 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
980 set_reg_szW(hkey
, NameW
, PrinterName
);
987 RegCloseKey(hkeyPrinters
);
990 /* We want to avoid calling AddPrinter on printers as much as
991 possible, because on cups printers this will (eventually) lead
992 to a call to cupsGetPPD which takes forever, even with non-cups
993 printers AddPrinter takes a while. So we'll tag all printers that
994 were automatically added last time around, if they still exist
995 we'll leave them be otherwise we'll delete them. */
996 if (EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
) && needed
) {
997 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
998 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
999 for(i
= 0; i
< num
; i
++) {
1000 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1001 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1002 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1004 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1012 HeapFree(GetProcessHeap(), 0, pi
);
1016 #ifdef SONAME_LIBCUPS
1017 done
= CUPS_LoadPrinters();
1020 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1021 PRINTCAP_LoadPrinters();
1023 /* Now enumerate the list again and delete any printers that are still tagged */
1024 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1026 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1027 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1028 for(i
= 0; i
< num
; i
++) {
1029 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1030 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1031 BOOL delete_driver
= FALSE
;
1032 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1033 DWORD dw
, type
, size
= sizeof(dw
);
1034 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1035 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1036 DeletePrinter(hprn
);
1037 delete_driver
= TRUE
;
1043 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1048 HeapFree(GetProcessHeap(), 0, pi
);
1055 /******************************************************************
1058 * Get the pointer to the specified job.
1059 * Should hold the printer_handles_cs before calling.
1061 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1063 opened_printer_t
*printer
= get_opened_printer(hprn
);
1066 if(!printer
) return NULL
;
1067 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1069 if(job
->job_id
== JobId
)
1075 /***********************************************************
1078 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1081 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1084 Formname
= (dmA
->dmSize
> off_formname
);
1085 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1086 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1087 dmW
->dmDeviceName
, CCHDEVICENAME
);
1089 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1090 dmA
->dmSize
- CCHDEVICENAME
);
1092 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1093 off_formname
- CCHDEVICENAME
);
1094 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1095 dmW
->dmFormName
, CCHFORMNAME
);
1096 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1097 (off_formname
+ CCHFORMNAME
));
1100 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1101 dmA
->dmDriverExtra
);
1105 /***********************************************************
1107 * Creates an ansi copy of supplied devmode
1109 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1114 if (!dmW
) return NULL
;
1115 size
= dmW
->dmSize
- CCHDEVICENAME
-
1116 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1118 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1119 if (!dmA
) return NULL
;
1121 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1122 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1124 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1125 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1126 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1130 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1131 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1132 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1133 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1135 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1139 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1143 /******************************************************************
1144 * convert_printerinfo_W_to_A [internal]
1147 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1148 DWORD level
, DWORD outlen
, DWORD numentries
)
1154 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1156 len
= pi_sizeof
[level
] * numentries
;
1157 ptr
= (LPSTR
) out
+ len
;
1160 /* copy the numbers of all PRINTER_INFO_* first */
1161 memcpy(out
, pPrintersW
, len
);
1163 while (id
< numentries
) {
1167 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1168 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1170 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1171 if (piW
->pDescription
) {
1172 piA
->pDescription
= ptr
;
1173 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1174 ptr
, outlen
, NULL
, NULL
);
1180 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1181 ptr
, outlen
, NULL
, NULL
);
1185 if (piW
->pComment
) {
1186 piA
->pComment
= ptr
;
1187 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1188 ptr
, outlen
, NULL
, NULL
);
1197 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1198 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1201 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1202 if (piW
->pServerName
) {
1203 piA
->pServerName
= ptr
;
1204 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1205 ptr
, outlen
, NULL
, NULL
);
1209 if (piW
->pPrinterName
) {
1210 piA
->pPrinterName
= ptr
;
1211 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1212 ptr
, outlen
, NULL
, NULL
);
1216 if (piW
->pShareName
) {
1217 piA
->pShareName
= ptr
;
1218 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1219 ptr
, outlen
, NULL
, NULL
);
1223 if (piW
->pPortName
) {
1224 piA
->pPortName
= ptr
;
1225 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1226 ptr
, outlen
, NULL
, NULL
);
1230 if (piW
->pDriverName
) {
1231 piA
->pDriverName
= ptr
;
1232 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1233 ptr
, outlen
, NULL
, NULL
);
1237 if (piW
->pComment
) {
1238 piA
->pComment
= ptr
;
1239 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1240 ptr
, outlen
, NULL
, NULL
);
1244 if (piW
->pLocation
) {
1245 piA
->pLocation
= ptr
;
1246 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1247 ptr
, outlen
, NULL
, NULL
);
1252 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1254 /* align DEVMODEA to a DWORD boundary */
1255 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1259 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1260 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1261 memcpy(ptr
, dmA
, len
);
1262 HeapFree(GetProcessHeap(), 0, dmA
);
1268 if (piW
->pSepFile
) {
1269 piA
->pSepFile
= ptr
;
1270 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1271 ptr
, outlen
, NULL
, NULL
);
1275 if (piW
->pPrintProcessor
) {
1276 piA
->pPrintProcessor
= ptr
;
1277 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1278 ptr
, outlen
, NULL
, NULL
);
1282 if (piW
->pDatatype
) {
1283 piA
->pDatatype
= ptr
;
1284 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1285 ptr
, outlen
, NULL
, NULL
);
1289 if (piW
->pParameters
) {
1290 piA
->pParameters
= ptr
;
1291 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1292 ptr
, outlen
, NULL
, NULL
);
1296 if (piW
->pSecurityDescriptor
) {
1297 piA
->pSecurityDescriptor
= NULL
;
1298 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1305 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1306 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1308 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1310 if (piW
->pPrinterName
) {
1311 piA
->pPrinterName
= ptr
;
1312 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1313 ptr
, outlen
, NULL
, NULL
);
1317 if (piW
->pServerName
) {
1318 piA
->pServerName
= ptr
;
1319 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1320 ptr
, outlen
, NULL
, NULL
);
1329 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1330 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1332 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1334 if (piW
->pPrinterName
) {
1335 piA
->pPrinterName
= ptr
;
1336 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1337 ptr
, outlen
, NULL
, NULL
);
1341 if (piW
->pPortName
) {
1342 piA
->pPortName
= ptr
;
1343 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1344 ptr
, outlen
, NULL
, NULL
);
1351 case 6: /* 6A and 6W are the same structure */
1356 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1357 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1359 TRACE("(%u) #%u\n", level
, id
);
1360 if (piW
->pszObjectGUID
) {
1361 piA
->pszObjectGUID
= ptr
;
1362 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1363 ptr
, outlen
, NULL
, NULL
);
1372 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1373 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1376 TRACE("(%u) #%u\n", level
, id
);
1377 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1379 /* align DEVMODEA to a DWORD boundary */
1380 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1384 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1385 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1386 memcpy(ptr
, dmA
, len
);
1387 HeapFree(GetProcessHeap(), 0, dmA
);
1397 FIXME("for level %u\n", level
);
1399 pPrintersW
+= pi_sizeof
[level
];
1400 out
+= pi_sizeof
[level
];
1405 /******************************************************************
1406 * convert_driverinfo_W_to_A [internal]
1409 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1410 DWORD level
, DWORD outlen
, DWORD numentries
)
1416 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1418 len
= di_sizeof
[level
] * numentries
;
1419 ptr
= (LPSTR
) out
+ len
;
1422 /* copy the numbers of all PRINTER_INFO_* first */
1423 memcpy(out
, pDriversW
, len
);
1425 #define COPY_STRING(fld) \
1428 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1429 ptr += len; outlen -= len;\
1431 #define COPY_MULTIZ_STRING(fld) \
1432 { LPWSTR p = diW->fld; if (p){ \
1435 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1436 ptr += len; outlen -= len; p += len;\
1438 while(len > 1 && outlen > 0); \
1441 while (id
< numentries
)
1447 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1448 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1450 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1457 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1458 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1460 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1463 COPY_STRING(pEnvironment
);
1464 COPY_STRING(pDriverPath
);
1465 COPY_STRING(pDataFile
);
1466 COPY_STRING(pConfigFile
);
1471 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1472 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1474 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1477 COPY_STRING(pEnvironment
);
1478 COPY_STRING(pDriverPath
);
1479 COPY_STRING(pDataFile
);
1480 COPY_STRING(pConfigFile
);
1481 COPY_STRING(pHelpFile
);
1482 COPY_MULTIZ_STRING(pDependentFiles
);
1483 COPY_STRING(pMonitorName
);
1484 COPY_STRING(pDefaultDataType
);
1489 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1490 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1492 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1495 COPY_STRING(pEnvironment
);
1496 COPY_STRING(pDriverPath
);
1497 COPY_STRING(pDataFile
);
1498 COPY_STRING(pConfigFile
);
1499 COPY_STRING(pHelpFile
);
1500 COPY_MULTIZ_STRING(pDependentFiles
);
1501 COPY_STRING(pMonitorName
);
1502 COPY_STRING(pDefaultDataType
);
1503 COPY_MULTIZ_STRING(pszzPreviousNames
);
1508 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1509 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1511 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1514 COPY_STRING(pEnvironment
);
1515 COPY_STRING(pDriverPath
);
1516 COPY_STRING(pDataFile
);
1517 COPY_STRING(pConfigFile
);
1522 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1523 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1525 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1528 COPY_STRING(pEnvironment
);
1529 COPY_STRING(pDriverPath
);
1530 COPY_STRING(pDataFile
);
1531 COPY_STRING(pConfigFile
);
1532 COPY_STRING(pHelpFile
);
1533 COPY_MULTIZ_STRING(pDependentFiles
);
1534 COPY_STRING(pMonitorName
);
1535 COPY_STRING(pDefaultDataType
);
1536 COPY_MULTIZ_STRING(pszzPreviousNames
);
1537 COPY_STRING(pszMfgName
);
1538 COPY_STRING(pszOEMUrl
);
1539 COPY_STRING(pszHardwareID
);
1540 COPY_STRING(pszProvider
);
1545 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1546 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1548 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1551 COPY_STRING(pEnvironment
);
1552 COPY_STRING(pDriverPath
);
1553 COPY_STRING(pDataFile
);
1554 COPY_STRING(pConfigFile
);
1555 COPY_STRING(pHelpFile
);
1556 COPY_MULTIZ_STRING(pDependentFiles
);
1557 COPY_STRING(pMonitorName
);
1558 COPY_STRING(pDefaultDataType
);
1559 COPY_MULTIZ_STRING(pszzPreviousNames
);
1560 COPY_STRING(pszMfgName
);
1561 COPY_STRING(pszOEMUrl
);
1562 COPY_STRING(pszHardwareID
);
1563 COPY_STRING(pszProvider
);
1564 COPY_STRING(pszPrintProcessor
);
1565 COPY_STRING(pszVendorSetup
);
1566 COPY_MULTIZ_STRING(pszzColorProfiles
);
1567 COPY_STRING(pszInfPath
);
1568 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1574 FIXME("for level %u\n", level
);
1577 pDriversW
+= di_sizeof
[level
];
1578 out
+= di_sizeof
[level
];
1583 #undef COPY_MULTIZ_STRING
1587 /***********************************************************
1588 * PRINTER_INFO_2AtoW
1589 * Creates a unicode copy of PRINTER_INFO_2A on heap
1591 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1593 LPPRINTER_INFO_2W piW
;
1594 UNICODE_STRING usBuffer
;
1596 if(!piA
) return NULL
;
1597 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1598 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1600 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1601 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1602 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1603 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1604 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1605 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1606 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1607 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1608 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1609 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1610 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1611 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1615 /***********************************************************
1616 * FREE_PRINTER_INFO_2W
1617 * Free PRINTER_INFO_2W and all strings
1619 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1623 HeapFree(heap
,0,piW
->pServerName
);
1624 HeapFree(heap
,0,piW
->pPrinterName
);
1625 HeapFree(heap
,0,piW
->pShareName
);
1626 HeapFree(heap
,0,piW
->pPortName
);
1627 HeapFree(heap
,0,piW
->pDriverName
);
1628 HeapFree(heap
,0,piW
->pComment
);
1629 HeapFree(heap
,0,piW
->pLocation
);
1630 HeapFree(heap
,0,piW
->pDevMode
);
1631 HeapFree(heap
,0,piW
->pSepFile
);
1632 HeapFree(heap
,0,piW
->pPrintProcessor
);
1633 HeapFree(heap
,0,piW
->pDatatype
);
1634 HeapFree(heap
,0,piW
->pParameters
);
1635 HeapFree(heap
,0,piW
);
1639 /******************************************************************
1640 * DeviceCapabilities [WINSPOOL.@]
1641 * DeviceCapabilitiesA [WINSPOOL.@]
1644 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1645 LPSTR pOutput
, LPDEVMODEA lpdm
)
1649 if (!GDI_CallDeviceCapabilities16
)
1651 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1653 if (!GDI_CallDeviceCapabilities16
) return -1;
1655 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1657 /* If DC_PAPERSIZE map POINT16s to POINTs */
1658 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1659 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1660 POINT
*pt
= (POINT
*)pOutput
;
1662 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1663 for(i
= 0; i
< ret
; i
++, pt
++)
1668 HeapFree( GetProcessHeap(), 0, tmp
);
1674 /*****************************************************************************
1675 * DeviceCapabilitiesW [WINSPOOL.@]
1677 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1680 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1681 WORD fwCapability
, LPWSTR pOutput
,
1682 const DEVMODEW
*pDevMode
)
1684 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1685 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1686 LPSTR pPortA
= strdupWtoA(pPort
);
1689 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1690 fwCapability
== DC_FILEDEPENDENCIES
||
1691 fwCapability
== DC_PAPERNAMES
)) {
1692 /* These need A -> W translation */
1695 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1699 switch(fwCapability
) {
1704 case DC_FILEDEPENDENCIES
:
1708 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1709 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1711 for(i
= 0; i
< ret
; i
++)
1712 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1713 pOutput
+ (i
* size
), size
);
1714 HeapFree(GetProcessHeap(), 0, pOutputA
);
1716 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1717 (LPSTR
)pOutput
, dmA
);
1719 HeapFree(GetProcessHeap(),0,pPortA
);
1720 HeapFree(GetProcessHeap(),0,pDeviceA
);
1721 HeapFree(GetProcessHeap(),0,dmA
);
1725 /******************************************************************
1726 * DocumentPropertiesA [WINSPOOL.@]
1728 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1730 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1731 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1732 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1734 LPSTR lpName
= pDeviceName
;
1735 static CHAR port
[] = "LPT1:";
1738 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1739 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1743 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1745 ERR("no name from hPrinter?\n");
1746 SetLastError(ERROR_INVALID_HANDLE
);
1749 lpName
= strdupWtoA(lpNameW
);
1752 if (!GDI_CallExtDeviceMode16
)
1754 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1756 if (!GDI_CallExtDeviceMode16
) {
1757 ERR("No CallExtDeviceMode16?\n");
1761 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1762 pDevModeInput
, NULL
, fMode
);
1765 HeapFree(GetProcessHeap(),0,lpName
);
1770 /*****************************************************************************
1771 * DocumentPropertiesW (WINSPOOL.@)
1773 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1775 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1777 LPDEVMODEW pDevModeOutput
,
1778 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1781 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1782 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1783 LPDEVMODEA pDevModeOutputA
= NULL
;
1786 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1787 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1789 if(pDevModeOutput
) {
1790 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1791 if(ret
< 0) return ret
;
1792 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1794 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1795 pDevModeInputA
, fMode
);
1796 if(pDevModeOutput
) {
1797 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1798 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1800 if(fMode
== 0 && ret
> 0)
1801 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1802 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1803 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1807 /*****************************************************************************
1808 * IsValidDevmodeA [WINSPOOL.@]
1810 * Validate a DEVMODE structure and fix errors if possible.
1813 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1815 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1823 /*****************************************************************************
1824 * IsValidDevmodeW [WINSPOOL.@]
1826 * Validate a DEVMODE structure and fix errors if possible.
1829 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1831 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1839 /******************************************************************
1840 * OpenPrinterA [WINSPOOL.@]
1845 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1846 LPPRINTER_DEFAULTSA pDefault
)
1848 UNICODE_STRING lpPrinterNameW
;
1849 UNICODE_STRING usBuffer
;
1850 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1851 PWSTR pwstrPrinterNameW
;
1854 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1857 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1858 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1859 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1860 pDefaultW
= &DefaultW
;
1862 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1864 RtlFreeUnicodeString(&usBuffer
);
1865 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1867 RtlFreeUnicodeString(&lpPrinterNameW
);
1871 /******************************************************************
1872 * OpenPrinterW [WINSPOOL.@]
1874 * Open a Printer / Printserver or a Printer-Object
1877 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1878 * phPrinter [O] The resulting Handle is stored here
1879 * pDefault [I] PTR to Default Printer Settings or NULL
1886 * lpPrinterName is one of:
1887 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1888 *| Printer: "PrinterName"
1889 *| Printer-Object: "PrinterName,Job xxx"
1890 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1891 *| XcvPort: "Servername,XcvPort PortName"
1894 *| Printer-Object not supported
1895 *| pDefaults is ignored
1898 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1901 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1904 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1905 SetLastError(ERROR_INVALID_PARAMETER
);
1909 /* Get the unique handle of the printer or Printserver */
1910 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1911 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1912 return (*phPrinter
!= 0);
1915 /******************************************************************
1916 * AddMonitorA [WINSPOOL.@]
1921 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1923 LPWSTR nameW
= NULL
;
1926 LPMONITOR_INFO_2A mi2a
;
1927 MONITOR_INFO_2W mi2w
;
1929 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1930 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1931 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1932 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1933 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1936 SetLastError(ERROR_INVALID_LEVEL
);
1940 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1946 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1947 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1948 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1951 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1953 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1954 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1955 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1957 if (mi2a
->pEnvironment
) {
1958 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1959 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1960 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1962 if (mi2a
->pDLLName
) {
1963 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1964 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1965 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1968 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1970 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1971 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1972 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1974 HeapFree(GetProcessHeap(), 0, nameW
);
1978 /******************************************************************************
1979 * AddMonitorW [WINSPOOL.@]
1981 * Install a Printmonitor
1984 * pName [I] Servername or NULL (local Computer)
1985 * Level [I] Structure-Level (Must be 2)
1986 * pMonitors [I] PTR to MONITOR_INFO_2
1993 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1996 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1998 LPMONITOR_INFO_2W mi2w
;
2000 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2001 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2002 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2003 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2004 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2006 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2009 SetLastError(ERROR_INVALID_LEVEL
);
2013 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2018 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2021 /******************************************************************
2022 * DeletePrinterDriverA [WINSPOOL.@]
2025 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2027 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2030 /******************************************************************
2031 * DeletePrinterDriverW [WINSPOOL.@]
2034 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2036 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2039 /******************************************************************
2040 * DeleteMonitorA [WINSPOOL.@]
2042 * See DeleteMonitorW.
2045 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2047 LPWSTR nameW
= NULL
;
2048 LPWSTR EnvironmentW
= NULL
;
2049 LPWSTR MonitorNameW
= NULL
;
2054 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2055 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2056 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2060 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2061 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2062 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2065 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2066 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2067 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2070 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2072 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2073 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2074 HeapFree(GetProcessHeap(), 0, nameW
);
2078 /******************************************************************
2079 * DeleteMonitorW [WINSPOOL.@]
2081 * Delete a specific Printmonitor from a Printing-Environment
2084 * pName [I] Servername or NULL (local Computer)
2085 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2086 * pMonitorName [I] Name of the Monitor, that should be deleted
2093 * pEnvironment is ignored in Windows for the local Computer.
2096 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2099 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2100 debugstr_w(pMonitorName
));
2102 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2104 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2108 /******************************************************************
2109 * DeletePortA [WINSPOOL.@]
2114 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2116 LPWSTR nameW
= NULL
;
2117 LPWSTR portW
= NULL
;
2121 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2123 /* convert servername to unicode */
2125 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2126 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2127 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2130 /* convert portname to unicode */
2132 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2133 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2134 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2137 res
= DeletePortW(nameW
, hWnd
, portW
);
2138 HeapFree(GetProcessHeap(), 0, nameW
);
2139 HeapFree(GetProcessHeap(), 0, portW
);
2143 /******************************************************************
2144 * DeletePortW [WINSPOOL.@]
2146 * Delete a specific Port
2149 * pName [I] Servername or NULL (local Computer)
2150 * hWnd [I] Handle to parent Window for the Dialog-Box
2151 * pPortName [I] Name of the Port, that should be deleted
2158 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2160 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2162 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2165 SetLastError(RPC_X_NULL_REF_POINTER
);
2169 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2172 /******************************************************************************
2173 * SetPrinterW [WINSPOOL.@]
2175 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2177 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2182 /******************************************************************************
2183 * WritePrinter [WINSPOOL.@]
2185 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2187 opened_printer_t
*printer
;
2190 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2192 EnterCriticalSection(&printer_handles_cs
);
2193 printer
= get_opened_printer(hPrinter
);
2196 SetLastError(ERROR_INVALID_HANDLE
);
2202 SetLastError(ERROR_SPL_NO_STARTDOC
);
2206 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2208 LeaveCriticalSection(&printer_handles_cs
);
2212 /*****************************************************************************
2213 * AddFormA [WINSPOOL.@]
2215 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2217 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2221 /*****************************************************************************
2222 * AddFormW [WINSPOOL.@]
2224 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2226 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2230 /*****************************************************************************
2231 * AddJobA [WINSPOOL.@]
2233 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2236 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2240 SetLastError(ERROR_INVALID_LEVEL
);
2244 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2247 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2248 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2249 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2250 if(*pcbNeeded
> cbBuf
) {
2251 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2254 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2255 addjobA
->JobId
= addjobW
->JobId
;
2256 addjobA
->Path
= (char *)(addjobA
+ 1);
2257 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2263 /*****************************************************************************
2264 * AddJobW [WINSPOOL.@]
2266 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2268 opened_printer_t
*printer
;
2271 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2272 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2273 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2275 ADDJOB_INFO_1W
*addjob
;
2277 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2279 EnterCriticalSection(&printer_handles_cs
);
2281 printer
= get_opened_printer(hPrinter
);
2284 SetLastError(ERROR_INVALID_HANDLE
);
2289 SetLastError(ERROR_INVALID_LEVEL
);
2293 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2297 job
->job_id
= InterlockedIncrement(&next_job_id
);
2299 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2300 if(path
[len
- 1] != '\\')
2302 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2303 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2305 len
= strlenW(filename
);
2306 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2307 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2308 job
->portname
= NULL
;
2309 job
->document_title
= strdupW(default_doc_title
);
2310 job
->printer_name
= strdupW(printer
->name
);
2311 job
->devmode
= dup_devmode( printer
->devmode
);
2312 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2314 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2315 if(*pcbNeeded
<= cbBuf
) {
2316 addjob
= (ADDJOB_INFO_1W
*)pData
;
2317 addjob
->JobId
= job
->job_id
;
2318 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2319 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2322 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2325 LeaveCriticalSection(&printer_handles_cs
);
2329 /*****************************************************************************
2330 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2332 * Return the PATH for the Print-Processors
2334 * See GetPrintProcessorDirectoryW.
2338 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2339 DWORD level
, LPBYTE Info
,
2340 DWORD cbBuf
, LPDWORD pcbNeeded
)
2342 LPWSTR serverW
= NULL
;
2347 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2348 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2352 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2353 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2354 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2358 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2359 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2360 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2363 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2364 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2366 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2369 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2370 cbBuf
, NULL
, NULL
) > 0;
2373 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2374 HeapFree(GetProcessHeap(), 0, envW
);
2375 HeapFree(GetProcessHeap(), 0, serverW
);
2379 /*****************************************************************************
2380 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2382 * Return the PATH for the Print-Processors
2385 * server [I] Servername (NT only) or NULL (local Computer)
2386 * env [I] Printing-Environment (see below) or NULL (Default)
2387 * level [I] Structure-Level (must be 1)
2388 * Info [O] PTR to Buffer that receives the Result
2389 * cbBuf [I] Size of Buffer at "Info"
2390 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2391 * required for the Buffer at "Info"
2394 * Success: TRUE and in pcbNeeded the Bytes used in Info
2395 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2396 * if cbBuf is too small
2398 * Native Values returned in Info on Success:
2399 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2400 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2401 *| win9x(Windows 4.0): "%winsysdir%"
2403 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2406 * Only NULL or "" is supported for server
2409 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2410 DWORD level
, LPBYTE Info
,
2411 DWORD cbBuf
, LPDWORD pcbNeeded
)
2414 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2415 Info
, cbBuf
, pcbNeeded
);
2417 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2420 /* (Level != 1) is ignored in win9x */
2421 SetLastError(ERROR_INVALID_LEVEL
);
2425 if (pcbNeeded
== NULL
) {
2426 /* (pcbNeeded == NULL) is ignored in win9x */
2427 SetLastError(RPC_X_NULL_REF_POINTER
);
2431 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2434 /*****************************************************************************
2435 * WINSPOOL_OpenDriverReg [internal]
2437 * opens the registry for the printer drivers depending on the given input
2438 * variable pEnvironment
2441 * the opened hkey on success
2444 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2448 const printenv_t
* env
;
2450 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2452 env
= validate_envW(pEnvironment
);
2453 if (!env
) return NULL
;
2455 buffer
= HeapAlloc( GetProcessHeap(), 0,
2456 (strlenW(DriversW
) + strlenW(env
->envname
) +
2457 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2459 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2460 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2461 HeapFree(GetProcessHeap(), 0, buffer
);
2466 /*****************************************************************************
2467 * set_devices_and_printerports [internal]
2469 * set the [Devices] and [PrinterPorts] entries for a printer.
2472 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2474 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2478 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2480 /* FIXME: the driver must change to "winspool" */
2481 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2483 lstrcpyW(devline
, driver_nt
);
2484 lstrcatW(devline
, commaW
);
2485 lstrcatW(devline
, pi
->pPortName
);
2487 TRACE("using %s\n", debugstr_w(devline
));
2488 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2489 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2490 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2491 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2495 lstrcatW(devline
, timeout_15_45
);
2496 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2497 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2498 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2499 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2502 HeapFree(GetProcessHeap(), 0, devline
);
2506 /*****************************************************************************
2507 * AddPrinterW [WINSPOOL.@]
2509 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2511 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2515 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2517 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2518 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2519 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2520 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2521 statusW
[] = {'S','t','a','t','u','s',0},
2522 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2524 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2527 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2528 SetLastError(ERROR_INVALID_PARAMETER
);
2532 ERR("Level = %d, unsupported!\n", Level
);
2533 SetLastError(ERROR_INVALID_LEVEL
);
2537 SetLastError(ERROR_INVALID_PARAMETER
);
2540 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2542 ERR("Can't create Printers key\n");
2545 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2546 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2547 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2548 RegCloseKey(hkeyPrinter
);
2549 RegCloseKey(hkeyPrinters
);
2552 RegCloseKey(hkeyPrinter
);
2554 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2556 ERR("Can't create Drivers key\n");
2557 RegCloseKey(hkeyPrinters
);
2560 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2562 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2563 RegCloseKey(hkeyPrinters
);
2564 RegCloseKey(hkeyDrivers
);
2565 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2568 RegCloseKey(hkeyDriver
);
2569 RegCloseKey(hkeyDrivers
);
2571 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2572 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2573 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2574 RegCloseKey(hkeyPrinters
);
2578 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2580 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2581 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2582 RegCloseKey(hkeyPrinters
);
2586 set_devices_and_printerports(pi
);
2587 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2588 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2589 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2591 /* See if we can load the driver. We may need the devmode structure anyway
2594 * Note that DocumentPropertiesW will briefly try to open the printer we
2595 * just create to find a DEVMODEA struct (it will use the WINEPS default
2596 * one in case it is not there, so we are ok).
2598 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2601 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2602 size
= sizeof(DEVMODEW
);
2608 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2610 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2612 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2613 HeapFree(GetProcessHeap(),0,dmW
);
2618 /* set devmode to printer name */
2619 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2623 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2624 and we support these drivers. NT writes DEVMODEW so somehow
2625 we'll need to distinguish between these when we support NT
2629 dmA
= DEVMODEdupWtoA(dmW
);
2630 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2631 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2632 HeapFree(GetProcessHeap(), 0, dmA
);
2634 HeapFree(GetProcessHeap(), 0, dmW
);
2636 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2637 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2638 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2639 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2641 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2642 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2643 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2644 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2645 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2646 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2647 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2648 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2649 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2650 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2651 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2652 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2653 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2655 RegCloseKey(hkeyPrinter
);
2656 RegCloseKey(hkeyPrinters
);
2657 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2658 ERR("OpenPrinter failing\n");
2664 /*****************************************************************************
2665 * AddPrinterA [WINSPOOL.@]
2667 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2669 UNICODE_STRING pNameW
;
2671 PRINTER_INFO_2W
*piW
;
2672 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2675 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2677 ERR("Level = %d, unsupported!\n", Level
);
2678 SetLastError(ERROR_INVALID_LEVEL
);
2681 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2682 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2684 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2686 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2687 RtlFreeUnicodeString(&pNameW
);
2692 /*****************************************************************************
2693 * ClosePrinter [WINSPOOL.@]
2695 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2697 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2698 opened_printer_t
*printer
= NULL
;
2701 TRACE("(%p)\n", hPrinter
);
2703 EnterCriticalSection(&printer_handles_cs
);
2705 if ((i
> 0) && (i
<= nb_printer_handles
))
2706 printer
= printer_handles
[i
- 1];
2711 struct list
*cursor
, *cursor2
;
2713 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2715 if (printer
->backend_printer
) {
2716 backend
->fpClosePrinter(printer
->backend_printer
);
2720 EndDocPrinter(hPrinter
);
2722 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2724 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2726 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2727 ScheduleJob(hPrinter
, job
->job_id
);
2729 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2732 free_printer_entry( printer
);
2733 printer_handles
[i
- 1] = NULL
;
2736 LeaveCriticalSection(&printer_handles_cs
);
2740 /*****************************************************************************
2741 * DeleteFormA [WINSPOOL.@]
2743 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2745 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2749 /*****************************************************************************
2750 * DeleteFormW [WINSPOOL.@]
2752 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2754 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2758 /*****************************************************************************
2759 * DeletePrinter [WINSPOOL.@]
2761 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2763 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2764 HKEY hkeyPrinters
, hkey
;
2767 SetLastError(ERROR_INVALID_HANDLE
);
2770 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2771 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2772 RegCloseKey(hkeyPrinters
);
2774 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2775 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2777 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2778 RegDeleteValueW(hkey
, lpNameW
);
2782 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2783 RegDeleteValueW(hkey
, lpNameW
);
2789 /*****************************************************************************
2790 * SetPrinterA [WINSPOOL.@]
2792 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2795 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2799 /*****************************************************************************
2800 * SetJobA [WINSPOOL.@]
2802 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2803 LPBYTE pJob
, DWORD Command
)
2807 UNICODE_STRING usBuffer
;
2809 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2811 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2812 are all ignored by SetJob, so we don't bother copying them */
2820 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2821 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2823 JobW
= (LPBYTE
)info1W
;
2824 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2825 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2826 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2827 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2828 info1W
->Status
= info1A
->Status
;
2829 info1W
->Priority
= info1A
->Priority
;
2830 info1W
->Position
= info1A
->Position
;
2831 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2836 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2837 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2839 JobW
= (LPBYTE
)info2W
;
2840 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2841 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2842 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2843 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2844 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2845 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2846 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2847 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2848 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2849 info2W
->Status
= info2A
->Status
;
2850 info2W
->Priority
= info2A
->Priority
;
2851 info2W
->Position
= info2A
->Position
;
2852 info2W
->StartTime
= info2A
->StartTime
;
2853 info2W
->UntilTime
= info2A
->UntilTime
;
2854 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2858 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2859 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2862 SetLastError(ERROR_INVALID_LEVEL
);
2866 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2872 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2873 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2874 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2875 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2876 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2881 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2882 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2883 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2884 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2885 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2886 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2887 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2888 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2889 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2893 HeapFree(GetProcessHeap(), 0, JobW
);
2898 /*****************************************************************************
2899 * SetJobW [WINSPOOL.@]
2901 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2902 LPBYTE pJob
, DWORD Command
)
2907 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2908 FIXME("Ignoring everything other than document title\n");
2910 EnterCriticalSection(&printer_handles_cs
);
2911 job
= get_job(hPrinter
, JobId
);
2921 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2922 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2923 job
->document_title
= strdupW(info1
->pDocument
);
2928 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2929 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2930 job
->document_title
= strdupW(info2
->pDocument
);
2931 HeapFree(GetProcessHeap(), 0, job
->devmode
);
2932 job
->devmode
= dup_devmode( info2
->pDevMode
);
2938 SetLastError(ERROR_INVALID_LEVEL
);
2943 LeaveCriticalSection(&printer_handles_cs
);
2947 /*****************************************************************************
2948 * EndDocPrinter [WINSPOOL.@]
2950 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2952 opened_printer_t
*printer
;
2954 TRACE("(%p)\n", hPrinter
);
2956 EnterCriticalSection(&printer_handles_cs
);
2958 printer
= get_opened_printer(hPrinter
);
2961 SetLastError(ERROR_INVALID_HANDLE
);
2967 SetLastError(ERROR_SPL_NO_STARTDOC
);
2971 CloseHandle(printer
->doc
->hf
);
2972 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2973 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2974 printer
->doc
= NULL
;
2977 LeaveCriticalSection(&printer_handles_cs
);
2981 /*****************************************************************************
2982 * EndPagePrinter [WINSPOOL.@]
2984 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2986 FIXME("(%p): stub\n", hPrinter
);
2990 /*****************************************************************************
2991 * StartDocPrinterA [WINSPOOL.@]
2993 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2995 UNICODE_STRING usBuffer
;
2997 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3000 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3001 or one (DOC_INFO_3) extra DWORDs */
3005 doc2W
.JobId
= doc2
->JobId
;
3008 doc2W
.dwMode
= doc2
->dwMode
;
3011 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3012 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3013 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3017 SetLastError(ERROR_INVALID_LEVEL
);
3021 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3023 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3024 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3025 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3030 /*****************************************************************************
3031 * StartDocPrinterW [WINSPOOL.@]
3033 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3035 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3036 opened_printer_t
*printer
;
3037 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3038 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3039 JOB_INFO_1W job_info
;
3040 DWORD needed
, ret
= 0;
3045 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3046 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3047 debugstr_w(doc
->pDatatype
));
3049 if(Level
< 1 || Level
> 3)
3051 SetLastError(ERROR_INVALID_LEVEL
);
3055 EnterCriticalSection(&printer_handles_cs
);
3056 printer
= get_opened_printer(hPrinter
);
3059 SetLastError(ERROR_INVALID_HANDLE
);
3065 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3069 /* Even if we're printing to a file we still add a print job, we'll
3070 just ignore the spool file name */
3072 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3074 ERR("AddJob failed gle %u\n", GetLastError());
3078 /* use pOutputFile only, when it is a real filename */
3079 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3080 filename
= doc
->pOutputFile
;
3082 filename
= addjob
->Path
;
3084 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3085 if(hf
== INVALID_HANDLE_VALUE
)
3088 memset(&job_info
, 0, sizeof(job_info
));
3089 job_info
.pDocument
= doc
->pDocName
;
3090 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3092 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3093 printer
->doc
->hf
= hf
;
3094 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3095 job
= get_job(hPrinter
, ret
);
3096 job
->portname
= strdupW(doc
->pOutputFile
);
3099 LeaveCriticalSection(&printer_handles_cs
);
3104 /*****************************************************************************
3105 * StartPagePrinter [WINSPOOL.@]
3107 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3109 FIXME("(%p): stub\n", hPrinter
);
3113 /*****************************************************************************
3114 * GetFormA [WINSPOOL.@]
3116 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3117 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3119 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3120 Level
,pForm
,cbBuf
,pcbNeeded
);
3124 /*****************************************************************************
3125 * GetFormW [WINSPOOL.@]
3127 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3128 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3130 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3131 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3135 /*****************************************************************************
3136 * SetFormA [WINSPOOL.@]
3138 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3141 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3145 /*****************************************************************************
3146 * SetFormW [WINSPOOL.@]
3148 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3151 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3155 /*****************************************************************************
3156 * ReadPrinter [WINSPOOL.@]
3158 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3159 LPDWORD pNoBytesRead
)
3161 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3165 /*****************************************************************************
3166 * ResetPrinterA [WINSPOOL.@]
3168 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3170 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3174 /*****************************************************************************
3175 * ResetPrinterW [WINSPOOL.@]
3177 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3179 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3183 /*****************************************************************************
3184 * WINSPOOL_GetDWORDFromReg
3186 * Return DWORD associated with ValueName from hkey.
3188 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3190 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3193 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3195 if(ret
!= ERROR_SUCCESS
) {
3196 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3199 if(type
!= REG_DWORD
) {
3200 ERR("Got type %d\n", type
);
3207 /*****************************************************************************
3208 * get_filename_from_reg [internal]
3210 * Get ValueName from hkey storing result in out
3211 * when the Value in the registry has only a filename, use driverdir as prefix
3212 * outlen is space left in out
3213 * String is stored either as unicode or ascii
3217 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3218 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3220 WCHAR filename
[MAX_PATH
];
3224 LPWSTR buffer
= filename
;
3228 size
= sizeof(filename
);
3230 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3231 if (ret
== ERROR_MORE_DATA
) {
3232 TRACE("need dynamic buffer: %u\n", size
);
3233 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3235 /* No Memory is bad */
3239 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3242 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3243 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3249 /* do we have a full path ? */
3250 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3251 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3254 /* we must build the full Path */
3256 if ((out
) && (outlen
> dirlen
)) {
3257 lstrcpyW((LPWSTR
)out
, driverdir
);
3265 /* write the filename */
3266 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3267 if ((out
) && (outlen
>= size
)) {
3268 lstrcpyW((LPWSTR
)out
, ptr
);
3275 ptr
+= lstrlenW(ptr
)+1;
3276 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3279 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3281 /* write the multisz-termination */
3282 if (type
== REG_MULTI_SZ
) {
3283 size
= sizeof(WCHAR
);
3286 if (out
&& (outlen
>= size
)) {
3287 memset (out
, 0, size
);
3293 /*****************************************************************************
3294 * WINSPOOL_GetStringFromReg
3296 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3297 * String is stored as unicode.
3299 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3300 DWORD buflen
, DWORD
*needed
)
3302 DWORD sz
= buflen
, type
;
3305 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3306 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3307 WARN("Got ret = %d\n", ret
);
3311 /* add space for terminating '\0' */
3312 sz
+= sizeof(WCHAR
);
3316 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3321 /*****************************************************************************
3322 * WINSPOOL_GetDefaultDevMode
3324 * Get a default DevMode values for wineps.
3328 static void WINSPOOL_GetDefaultDevMode(
3330 DWORD buflen
, DWORD
*needed
)
3333 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3335 /* fill default DEVMODE - should be read from ppd... */
3336 ZeroMemory( &dm
, sizeof(dm
) );
3337 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3338 dm
.dmSpecVersion
= DM_SPECVERSION
;
3339 dm
.dmDriverVersion
= 1;
3340 dm
.dmSize
= sizeof(DEVMODEW
);
3341 dm
.dmDriverExtra
= 0;
3343 DM_ORIENTATION
| DM_PAPERSIZE
|
3344 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3347 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3348 DM_YRESOLUTION
| DM_TTOPTION
;
3350 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3351 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3352 dm
.u1
.s1
.dmPaperLength
= 2970;
3353 dm
.u1
.s1
.dmPaperWidth
= 2100;
3355 dm
.u1
.s1
.dmScale
= 100;
3356 dm
.u1
.s1
.dmCopies
= 1;
3357 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3358 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3361 dm
.dmYResolution
= 300; /* 300dpi */
3362 dm
.dmTTOption
= DMTT_BITMAP
;
3365 /* dm.dmLogPixels */
3366 /* dm.dmBitsPerPel */
3367 /* dm.dmPelsWidth */
3368 /* dm.dmPelsHeight */
3369 /* dm.u2.dmDisplayFlags */
3370 /* dm.dmDisplayFrequency */
3371 /* dm.dmICMMethod */
3372 /* dm.dmICMIntent */
3373 /* dm.dmMediaType */
3374 /* dm.dmDitherType */
3375 /* dm.dmReserved1 */
3376 /* dm.dmReserved2 */
3377 /* dm.dmPanningWidth */
3378 /* dm.dmPanningHeight */
3380 if(buflen
>= sizeof(DEVMODEW
))
3381 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3382 *needed
= sizeof(DEVMODEW
);
3385 /*****************************************************************************
3386 * WINSPOOL_GetDevModeFromReg
3388 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3389 * DevMode is stored either as unicode or ascii.
3391 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3393 DWORD buflen
, DWORD
*needed
)
3395 DWORD sz
= buflen
, type
;
3398 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3399 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3400 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3401 if (sz
< sizeof(DEVMODEA
))
3403 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3406 /* ensures that dmSize is not erratically bogus if registry is invalid */
3407 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3408 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3409 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3410 if (ptr
&& (buflen
>= sz
)) {
3411 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3412 memcpy(ptr
, dmW
, sz
);
3413 HeapFree(GetProcessHeap(),0,dmW
);
3419 /*********************************************************************
3420 * WINSPOOL_GetPrinter_1
3422 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3424 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3425 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3427 DWORD size
, left
= cbBuf
;
3428 BOOL space
= (cbBuf
> 0);
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3434 if(space
&& size
<= left
) {
3435 pi1
->pName
= (LPWSTR
)ptr
;
3443 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3444 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3445 if(space
&& size
<= left
) {
3446 pi1
->pDescription
= (LPWSTR
)ptr
;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3455 if(space
&& size
<= left
) {
3456 pi1
->pComment
= (LPWSTR
)ptr
;
3464 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3466 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3467 memset(pi1
, 0, sizeof(*pi1
));
3471 /*********************************************************************
3472 * WINSPOOL_GetPrinter_2
3474 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3476 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3477 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3479 DWORD size
, left
= cbBuf
;
3480 BOOL space
= (cbBuf
> 0);
3485 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3486 if(space
&& size
<= left
) {
3487 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3494 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3495 if(space
&& size
<= left
) {
3496 pi2
->pShareName
= (LPWSTR
)ptr
;
3503 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3504 if(space
&& size
<= left
) {
3505 pi2
->pPortName
= (LPWSTR
)ptr
;
3512 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3513 if(space
&& size
<= left
) {
3514 pi2
->pDriverName
= (LPWSTR
)ptr
;
3521 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3522 if(space
&& size
<= left
) {
3523 pi2
->pComment
= (LPWSTR
)ptr
;
3530 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3531 if(space
&& size
<= left
) {
3532 pi2
->pLocation
= (LPWSTR
)ptr
;
3539 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3540 if(space
&& size
<= left
) {
3541 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3550 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3551 if(space
&& size
<= left
) {
3552 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3559 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3560 if(space
&& size
<= left
) {
3561 pi2
->pSepFile
= (LPWSTR
)ptr
;
3568 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3569 if(space
&& size
<= left
) {
3570 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3577 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3578 if(space
&& size
<= left
) {
3579 pi2
->pDatatype
= (LPWSTR
)ptr
;
3586 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3587 if(space
&& size
<= left
) {
3588 pi2
->pParameters
= (LPWSTR
)ptr
;
3596 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3597 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3598 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3599 "Default Priority");
3600 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3601 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3604 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3605 memset(pi2
, 0, sizeof(*pi2
));
3610 /*********************************************************************
3611 * WINSPOOL_GetPrinter_4
3613 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3615 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3616 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3618 DWORD size
, left
= cbBuf
;
3619 BOOL space
= (cbBuf
> 0);
3624 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3625 if(space
&& size
<= left
) {
3626 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3634 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3637 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3638 memset(pi4
, 0, sizeof(*pi4
));
3643 /*********************************************************************
3644 * WINSPOOL_GetPrinter_5
3646 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3648 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3649 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3651 DWORD size
, left
= cbBuf
;
3652 BOOL space
= (cbBuf
> 0);
3657 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3658 if(space
&& size
<= left
) {
3659 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3666 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3667 if(space
&& size
<= left
) {
3668 pi5
->pPortName
= (LPWSTR
)ptr
;
3676 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3677 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3679 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3683 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3684 memset(pi5
, 0, sizeof(*pi5
));
3689 /*********************************************************************
3690 * WINSPOOL_GetPrinter_7
3692 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3694 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3695 DWORD cbBuf
, LPDWORD pcbNeeded
)
3697 DWORD size
, left
= cbBuf
;
3698 BOOL space
= (cbBuf
> 0);
3703 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3706 size
= sizeof(pi7
->pszObjectGUID
);
3708 if (space
&& size
<= left
) {
3709 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3716 /* We do not have a Directory Service */
3717 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3720 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3721 memset(pi7
, 0, sizeof(*pi7
));
3726 /*********************************************************************
3727 * WINSPOOL_GetPrinter_9
3729 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3731 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3732 DWORD cbBuf
, LPDWORD pcbNeeded
)
3735 BOOL space
= (cbBuf
> 0);
3739 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3740 if(space
&& size
<= cbBuf
) {
3741 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3748 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3749 if(space
&& size
<= cbBuf
) {
3750 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3756 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3757 memset(pi9
, 0, sizeof(*pi9
));
3762 /*****************************************************************************
3763 * GetPrinterW [WINSPOOL.@]
3765 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3766 DWORD cbBuf
, LPDWORD pcbNeeded
)
3769 DWORD size
, needed
= 0;
3771 HKEY hkeyPrinter
, hkeyPrinters
;
3774 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3776 if (!(name
= get_opened_printer_name(hPrinter
))) {
3777 SetLastError(ERROR_INVALID_HANDLE
);
3781 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3783 ERR("Can't create Printers key\n");
3786 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3788 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3789 RegCloseKey(hkeyPrinters
);
3790 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3797 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3799 size
= sizeof(PRINTER_INFO_2W
);
3801 ptr
= pPrinter
+ size
;
3803 memset(pPrinter
, 0, size
);
3808 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3815 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3817 size
= sizeof(PRINTER_INFO_4W
);
3819 ptr
= pPrinter
+ size
;
3821 memset(pPrinter
, 0, size
);
3826 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3834 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3836 size
= sizeof(PRINTER_INFO_5W
);
3838 ptr
= pPrinter
+ size
;
3840 memset(pPrinter
, 0, size
);
3846 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3854 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3856 size
= sizeof(PRINTER_INFO_6
);
3857 if (size
<= cbBuf
) {
3858 /* FIXME: We do not update the status yet */
3859 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3871 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3873 size
= sizeof(PRINTER_INFO_7W
);
3874 if (size
<= cbBuf
) {
3875 ptr
= pPrinter
+ size
;
3877 memset(pPrinter
, 0, size
);
3883 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3891 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3893 size
= sizeof(PRINTER_INFO_9W
);
3895 ptr
= pPrinter
+ size
;
3897 memset(pPrinter
, 0, size
);
3903 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3910 FIXME("Unimplemented level %d\n", Level
);
3911 SetLastError(ERROR_INVALID_LEVEL
);
3912 RegCloseKey(hkeyPrinters
);
3913 RegCloseKey(hkeyPrinter
);
3917 RegCloseKey(hkeyPrinter
);
3918 RegCloseKey(hkeyPrinters
);
3920 TRACE("returning %d needed = %d\n", ret
, needed
);
3921 if(pcbNeeded
) *pcbNeeded
= needed
;
3923 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3927 /*****************************************************************************
3928 * GetPrinterA [WINSPOOL.@]
3930 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3931 DWORD cbBuf
, LPDWORD pcbNeeded
)
3937 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3939 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3941 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3942 HeapFree(GetProcessHeap(), 0, buf
);
3947 /*****************************************************************************
3948 * WINSPOOL_EnumPrintersW
3950 * Implementation of EnumPrintersW
3952 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3953 DWORD dwLevel
, LPBYTE lpbPrinters
,
3954 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3955 LPDWORD lpdwReturned
)
3958 HKEY hkeyPrinters
, hkeyPrinter
;
3959 WCHAR PrinterName
[255];
3960 DWORD needed
= 0, number
= 0;
3961 DWORD used
, i
, left
;
3965 memset(lpbPrinters
, 0, cbBuf
);
3971 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3972 if(dwType
== PRINTER_ENUM_DEFAULT
)
3975 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3976 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3977 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3979 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3985 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3986 FIXME("dwType = %08x\n", dwType
);
3987 SetLastError(ERROR_INVALID_FLAGS
);
3991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3993 ERR("Can't create Printers key\n");
3997 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3998 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3999 RegCloseKey(hkeyPrinters
);
4000 ERR("Can't query Printers key\n");
4003 TRACE("Found %d printers\n", number
);
4007 used
= number
* sizeof(PRINTER_INFO_1W
);
4010 used
= number
* sizeof(PRINTER_INFO_2W
);
4013 used
= number
* sizeof(PRINTER_INFO_4W
);
4016 used
= number
* sizeof(PRINTER_INFO_5W
);
4020 SetLastError(ERROR_INVALID_LEVEL
);
4021 RegCloseKey(hkeyPrinters
);
4024 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4026 for(i
= 0; i
< number
; i
++) {
4027 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4029 ERR("Can't enum key number %d\n", i
);
4030 RegCloseKey(hkeyPrinters
);
4033 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4034 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4036 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4037 RegCloseKey(hkeyPrinters
);
4042 buf
= lpbPrinters
+ used
;
4043 left
= cbBuf
- used
;
4051 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4054 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4057 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4060 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4063 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4066 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4069 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4072 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4075 ERR("Shouldn't be here!\n");
4076 RegCloseKey(hkeyPrinter
);
4077 RegCloseKey(hkeyPrinters
);
4080 RegCloseKey(hkeyPrinter
);
4082 RegCloseKey(hkeyPrinters
);
4089 memset(lpbPrinters
, 0, cbBuf
);
4090 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4094 *lpdwReturned
= number
;
4095 SetLastError(ERROR_SUCCESS
);
4100 /******************************************************************
4101 * EnumPrintersW [WINSPOOL.@]
4103 * Enumerates the available printers, print servers and print
4104 * providers, depending on the specified flags, name and level.
4108 * If level is set to 1:
4109 * Returns an array of PRINTER_INFO_1 data structures in the
4110 * lpbPrinters buffer.
4112 * If level is set to 2:
4113 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4114 * Returns an array of PRINTER_INFO_2 data structures in the
4115 * lpbPrinters buffer. Note that according to MSDN also an
4116 * OpenPrinter should be performed on every remote printer.
4118 * If level is set to 4 (officially WinNT only):
4119 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4120 * Fast: Only the registry is queried to retrieve printer names,
4121 * no connection to the driver is made.
4122 * Returns an array of PRINTER_INFO_4 data structures in the
4123 * lpbPrinters buffer.
4125 * If level is set to 5 (officially WinNT4/Win9x only):
4126 * Fast: Only the registry is queried to retrieve printer names,
4127 * no connection to the driver is made.
4128 * Returns an array of PRINTER_INFO_5 data structures in the
4129 * lpbPrinters buffer.
4131 * If level set to 3 or 6+:
4132 * returns zero (failure!)
4134 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4138 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4139 * - Only levels 2, 4 and 5 are implemented at the moment.
4140 * - 16-bit printer drivers are not enumerated.
4141 * - Returned amount of bytes used/needed does not match the real Windoze
4142 * implementation (as in this implementation, all strings are part
4143 * of the buffer, whereas Win32 keeps them somewhere else)
4144 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4147 * - In a regular Wine installation, no registry settings for printers
4148 * exist, which makes this function return an empty list.
4150 BOOL WINAPI
EnumPrintersW(
4151 DWORD dwType
, /* [in] Types of print objects to enumerate */
4152 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4153 DWORD dwLevel
, /* [in] type of printer info structure */
4154 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4155 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4156 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4157 LPDWORD lpdwReturned
/* [out] number of entries returned */
4160 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4161 lpdwNeeded
, lpdwReturned
);
4164 /******************************************************************
4165 * EnumPrintersA [WINSPOOL.@]
4170 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4171 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4174 UNICODE_STRING pNameU
;
4178 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4179 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4181 pNameW
= asciitounicode(&pNameU
, pName
);
4183 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4184 MS Office need this */
4185 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4187 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4189 RtlFreeUnicodeString(&pNameU
);
4191 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4193 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4197 /*****************************************************************************
4198 * WINSPOOL_GetDriverInfoFromReg [internal]
4200 * Enters the information from the registry into the DRIVER_INFO struct
4203 * zero if the printer driver does not exist in the registry
4204 * (only if Level > 1) otherwise nonzero
4206 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4209 const printenv_t
* env
,
4211 LPBYTE ptr
, /* DRIVER_INFO */
4212 LPBYTE pDriverStrings
, /* strings buffer */
4213 DWORD cbBuf
, /* size of string buffer */
4214 LPDWORD pcbNeeded
) /* space needed for str. */
4218 WCHAR driverdir
[MAX_PATH
];
4220 LPBYTE strPtr
= pDriverStrings
;
4221 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4223 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4224 debugstr_w(DriverName
), env
,
4225 Level
, di
, pDriverStrings
, cbBuf
);
4227 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4229 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4230 if (*pcbNeeded
<= cbBuf
)
4231 strcpyW((LPWSTR
)strPtr
, DriverName
);
4233 /* pName for level 1 has a different offset! */
4235 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4239 /* .cVersion and .pName for level > 1 */
4241 di
->cVersion
= env
->driverversion
;
4242 di
->pName
= (LPWSTR
) strPtr
;
4243 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4246 /* Reserve Space for the largest subdir and a Backslash*/
4247 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4248 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4249 /* Should never Fail */
4252 lstrcatW(driverdir
, env
->versionsubdir
);
4253 lstrcatW(driverdir
, backslashW
);
4255 /* dirlen must not include the terminating zero */
4256 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4258 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4259 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4260 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4265 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4268 if (*pcbNeeded
<= cbBuf
) {
4269 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4270 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4271 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4274 /* .pDriverPath is the Graphics rendering engine.
4275 The full Path is required to avoid a crash in some apps */
4276 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4278 if (*pcbNeeded
<= cbBuf
)
4279 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4281 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4282 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4285 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4286 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4288 if (*pcbNeeded
<= cbBuf
)
4289 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4291 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4292 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4295 /* .pConfigFile is the Driver user Interface */
4296 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4298 if (*pcbNeeded
<= cbBuf
)
4299 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4301 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4302 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4306 RegCloseKey(hkeyDriver
);
4307 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4312 RegCloseKey(hkeyDriver
);
4313 FIXME("level 5: incomplete\n");
4318 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4320 if (*pcbNeeded
<= cbBuf
)
4321 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4323 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4324 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4327 /* .pDependentFiles */
4328 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4330 if (*pcbNeeded
<= cbBuf
)
4331 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4333 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4334 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4336 else if (GetVersion() & 0x80000000) {
4337 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4338 size
= 2 * sizeof(WCHAR
);
4340 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4342 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4343 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4346 /* .pMonitorName is the optional Language Monitor */
4347 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4349 if (*pcbNeeded
<= cbBuf
)
4350 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4352 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4353 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4356 /* .pDefaultDataType */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4359 if(*pcbNeeded
<= cbBuf
)
4360 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4362 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4363 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4367 RegCloseKey(hkeyDriver
);
4368 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4372 /* .pszzPreviousNames */
4373 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4375 if(*pcbNeeded
<= cbBuf
)
4376 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4378 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4379 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4383 RegCloseKey(hkeyDriver
);
4384 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4388 /* support is missing, but not important enough for a FIXME */
4389 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4392 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4394 if(*pcbNeeded
<= cbBuf
)
4395 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4397 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4398 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4402 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4404 if(*pcbNeeded
<= cbBuf
)
4405 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4407 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4408 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4411 /* .pszHardwareID */
4412 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4414 if(*pcbNeeded
<= cbBuf
)
4415 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4417 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4418 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4422 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4424 if(*pcbNeeded
<= cbBuf
)
4425 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4427 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4428 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4432 RegCloseKey(hkeyDriver
);
4436 /* support is missing, but not important enough for a FIXME */
4437 TRACE("level 8: incomplete\n");
4439 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4440 RegCloseKey(hkeyDriver
);
4444 /*****************************************************************************
4445 * GetPrinterDriverW [WINSPOOL.@]
4447 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4448 DWORD Level
, LPBYTE pDriverInfo
,
4449 DWORD cbBuf
, LPDWORD pcbNeeded
)
4452 WCHAR DriverName
[100];
4453 DWORD ret
, type
, size
, needed
= 0;
4455 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4456 const printenv_t
* env
;
4458 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4459 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4462 ZeroMemory(pDriverInfo
, cbBuf
);
4464 if (!(name
= get_opened_printer_name(hPrinter
))) {
4465 SetLastError(ERROR_INVALID_HANDLE
);
4469 if (Level
< 1 || Level
== 7 || Level
> 8) {
4470 SetLastError(ERROR_INVALID_LEVEL
);
4474 env
= validate_envW(pEnvironment
);
4475 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4479 ERR("Can't create Printers key\n");
4482 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4484 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4485 RegCloseKey(hkeyPrinters
);
4486 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4489 size
= sizeof(DriverName
);
4491 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4492 (LPBYTE
)DriverName
, &size
);
4493 RegCloseKey(hkeyPrinter
);
4494 RegCloseKey(hkeyPrinters
);
4495 if(ret
!= ERROR_SUCCESS
) {
4496 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4500 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4502 ERR("Can't create Drivers key\n");
4506 size
= di_sizeof
[Level
];
4507 if ((size
<= cbBuf
) && pDriverInfo
)
4508 ptr
= pDriverInfo
+ size
;
4510 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4511 env
, Level
, pDriverInfo
, ptr
,
4512 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4514 RegCloseKey(hkeyDrivers
);
4518 RegCloseKey(hkeyDrivers
);
4520 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4521 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4522 if(cbBuf
>= size
+ needed
) return TRUE
;
4523 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4527 /*****************************************************************************
4528 * GetPrinterDriverA [WINSPOOL.@]
4530 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4531 DWORD Level
, LPBYTE pDriverInfo
,
4532 DWORD cbBuf
, LPDWORD pcbNeeded
)
4535 UNICODE_STRING pEnvW
;
4541 ZeroMemory(pDriverInfo
, cbBuf
);
4542 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4545 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4546 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4549 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4551 HeapFree(GetProcessHeap(), 0, buf
);
4553 RtlFreeUnicodeString(&pEnvW
);
4557 /*****************************************************************************
4558 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4560 * Return the PATH for the Printer-Drivers (UNICODE)
4563 * pName [I] Servername (NT only) or NULL (local Computer)
4564 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4565 * Level [I] Structure-Level (must be 1)
4566 * pDriverDirectory [O] PTR to Buffer that receives the Result
4567 * cbBuf [I] Size of Buffer at pDriverDirectory
4568 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4569 * required for pDriverDirectory
4572 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4573 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4574 * if cbBuf is too small
4576 * Native Values returned in pDriverDirectory on Success:
4577 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4578 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4579 *| win9x(Windows 4.0): "%winsysdir%"
4581 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4584 *- Only NULL or "" is supported for pName
4587 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4588 DWORD Level
, LPBYTE pDriverDirectory
,
4589 DWORD cbBuf
, LPDWORD pcbNeeded
)
4591 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4592 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4594 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4597 /* (Level != 1) is ignored in win9x */
4598 SetLastError(ERROR_INVALID_LEVEL
);
4601 if (pcbNeeded
== NULL
) {
4602 /* (pcbNeeded == NULL) is ignored in win9x */
4603 SetLastError(RPC_X_NULL_REF_POINTER
);
4607 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4608 pDriverDirectory
, cbBuf
, pcbNeeded
);
4613 /*****************************************************************************
4614 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4616 * Return the PATH for the Printer-Drivers (ANSI)
4618 * See GetPrinterDriverDirectoryW.
4621 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4624 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4625 DWORD Level
, LPBYTE pDriverDirectory
,
4626 DWORD cbBuf
, LPDWORD pcbNeeded
)
4628 UNICODE_STRING nameW
, environmentW
;
4631 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4632 WCHAR
*driverDirectoryW
= NULL
;
4634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4635 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4637 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4639 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4640 else nameW
.Buffer
= NULL
;
4641 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4642 else environmentW
.Buffer
= NULL
;
4644 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4645 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4648 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4649 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4651 *pcbNeeded
= needed
;
4652 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4654 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4656 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4658 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4659 RtlFreeUnicodeString(&environmentW
);
4660 RtlFreeUnicodeString(&nameW
);
4665 /*****************************************************************************
4666 * AddPrinterDriverA [WINSPOOL.@]
4668 * See AddPrinterDriverW.
4671 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4673 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4674 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4677 /******************************************************************************
4678 * AddPrinterDriverW (WINSPOOL.@)
4680 * Install a Printer Driver
4683 * pName [I] Servername or NULL (local Computer)
4684 * level [I] Level for the supplied DRIVER_INFO_*W struct
4685 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4692 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4694 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4695 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4698 /*****************************************************************************
4699 * AddPrintProcessorA [WINSPOOL.@]
4701 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4702 LPSTR pPrintProcessorName
)
4704 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4705 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4709 /*****************************************************************************
4710 * AddPrintProcessorW [WINSPOOL.@]
4712 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4713 LPWSTR pPrintProcessorName
)
4715 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4716 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4720 /*****************************************************************************
4721 * AddPrintProvidorA [WINSPOOL.@]
4723 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4725 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4729 /*****************************************************************************
4730 * AddPrintProvidorW [WINSPOOL.@]
4732 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4734 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4738 /*****************************************************************************
4739 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4741 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4742 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4744 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4745 pDevModeOutput
, pDevModeInput
);
4749 /*****************************************************************************
4750 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4752 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4753 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4755 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4756 pDevModeOutput
, pDevModeInput
);
4760 /*****************************************************************************
4761 * PrinterProperties [WINSPOOL.@]
4763 * Displays a dialog to set the properties of the printer.
4766 * nonzero on success or zero on failure
4769 * implemented as stub only
4771 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4772 HANDLE hPrinter
/* [in] handle to printer object */
4774 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4775 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4779 /*****************************************************************************
4780 * EnumJobsA [WINSPOOL.@]
4783 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4784 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4787 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4788 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4790 if(pcbNeeded
) *pcbNeeded
= 0;
4791 if(pcReturned
) *pcReturned
= 0;
4796 /*****************************************************************************
4797 * EnumJobsW [WINSPOOL.@]
4800 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4801 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4804 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4805 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4807 if(pcbNeeded
) *pcbNeeded
= 0;
4808 if(pcReturned
) *pcReturned
= 0;
4812 /*****************************************************************************
4813 * WINSPOOL_EnumPrinterDrivers [internal]
4815 * Delivers information about all printer drivers installed on the
4816 * localhost or a given server
4819 * nonzero on success or zero on failure. If the buffer for the returned
4820 * information is too small the function will return an error
4823 * - only implemented for localhost, foreign hosts will return an error
4825 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4826 DWORD Level
, LPBYTE pDriverInfo
,
4828 DWORD cbBuf
, LPDWORD pcbNeeded
,
4829 LPDWORD pcFound
, DWORD data_offset
)
4833 const printenv_t
* env
;
4835 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4836 debugstr_w(pName
), debugstr_w(pEnvironment
),
4837 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4839 env
= validate_envW(pEnvironment
);
4840 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4844 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4846 ERR("Can't open Drivers key\n");
4850 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4851 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4852 RegCloseKey(hkeyDrivers
);
4853 ERR("Can't query Drivers key\n");
4856 TRACE("Found %d Drivers\n", *pcFound
);
4858 /* get size of single struct
4859 * unicode and ascii structure have the same size
4861 size
= di_sizeof
[Level
];
4863 if (data_offset
== 0)
4864 data_offset
= size
* (*pcFound
);
4865 *pcbNeeded
= data_offset
;
4867 for( i
= 0; i
< *pcFound
; i
++) {
4868 WCHAR DriverNameW
[255];
4869 PBYTE table_ptr
= NULL
;
4870 PBYTE data_ptr
= NULL
;
4873 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4875 ERR("Can't enum key number %d\n", i
);
4876 RegCloseKey(hkeyDrivers
);
4880 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4881 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4882 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4883 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4885 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4886 env
, Level
, table_ptr
, data_ptr
,
4887 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4889 RegCloseKey(hkeyDrivers
);
4893 *pcbNeeded
+= needed
;
4896 RegCloseKey(hkeyDrivers
);
4898 if(cbBuf
< *pcbNeeded
){
4899 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4906 /*****************************************************************************
4907 * EnumPrinterDriversW [WINSPOOL.@]
4909 * see function EnumPrinterDrivers for RETURNS, BUGS
4911 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4912 LPBYTE pDriverInfo
, DWORD cbBuf
,
4913 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4915 static const WCHAR allW
[] = {'a','l','l',0};
4919 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4921 SetLastError(RPC_X_NULL_REF_POINTER
);
4925 /* check for local drivers */
4926 if((pName
) && (pName
[0])) {
4927 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4928 SetLastError(ERROR_ACCESS_DENIED
);
4932 /* check input parameter */
4933 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4934 SetLastError(ERROR_INVALID_LEVEL
);
4938 if(pDriverInfo
&& cbBuf
> 0)
4939 memset( pDriverInfo
, 0, cbBuf
);
4941 /* Exception: pull all printers */
4942 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4944 DWORD i
, needed
, bufsize
= cbBuf
;
4945 DWORD total_needed
= 0;
4946 DWORD total_found
= 0;
4949 /* Precompute the overall total; we need this to know
4950 where pointers end and data begins (i.e. data_offset) */
4951 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4954 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4955 NULL
, 0, 0, &needed
, &found
, 0);
4956 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4957 total_needed
+= needed
;
4958 total_found
+= found
;
4961 data_offset
= di_sizeof
[Level
] * total_found
;
4966 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4969 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4970 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4971 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4973 *pcReturned
+= found
;
4974 *pcbNeeded
= needed
;
4975 data_offset
= needed
;
4976 total_found
+= found
;
4981 /* Normal behavior */
4982 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4983 0, cbBuf
, pcbNeeded
, &found
, 0);
4985 *pcReturned
= found
;
4990 /*****************************************************************************
4991 * EnumPrinterDriversA [WINSPOOL.@]
4993 * see function EnumPrinterDrivers for RETURNS, BUGS
4995 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4996 LPBYTE pDriverInfo
, DWORD cbBuf
,
4997 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5000 UNICODE_STRING pNameW
, pEnvironmentW
;
5001 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5005 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5007 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5008 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5010 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5011 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5013 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5015 HeapFree(GetProcessHeap(), 0, buf
);
5017 RtlFreeUnicodeString(&pNameW
);
5018 RtlFreeUnicodeString(&pEnvironmentW
);
5023 /******************************************************************************
5024 * EnumPortsA (WINSPOOL.@)
5029 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5030 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5033 LPBYTE bufferW
= NULL
;
5034 LPWSTR nameW
= NULL
;
5036 DWORD numentries
= 0;
5039 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5040 cbBuf
, pcbNeeded
, pcReturned
);
5042 /* convert servername to unicode */
5044 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5045 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5046 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5048 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5049 needed
= cbBuf
* sizeof(WCHAR
);
5050 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5051 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5053 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5054 if (pcbNeeded
) needed
= *pcbNeeded
;
5055 /* HeapReAlloc return NULL, when bufferW was NULL */
5056 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5057 HeapAlloc(GetProcessHeap(), 0, needed
);
5059 /* Try again with the large Buffer */
5060 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5062 needed
= pcbNeeded
? *pcbNeeded
: 0;
5063 numentries
= pcReturned
? *pcReturned
: 0;
5066 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5067 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5070 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5071 DWORD entrysize
= 0;
5074 LPPORT_INFO_2W pi2w
;
5075 LPPORT_INFO_2A pi2a
;
5078 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5080 /* First pass: calculate the size for all Entries */
5081 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5082 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5084 while (index
< numentries
) {
5086 needed
+= entrysize
; /* PORT_INFO_?A */
5087 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5089 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5090 NULL
, 0, NULL
, NULL
);
5092 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5093 NULL
, 0, NULL
, NULL
);
5094 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5095 NULL
, 0, NULL
, NULL
);
5097 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5098 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5099 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5102 /* check for errors and quit on failure */
5103 if (cbBuf
< needed
) {
5104 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5108 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5109 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5110 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5111 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5112 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5114 /* Second Pass: Fill the User Buffer (if we have one) */
5115 while ((index
< numentries
) && pPorts
) {
5117 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5118 pi2a
->pPortName
= ptr
;
5119 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5120 ptr
, cbBuf
, NULL
, NULL
);
5124 pi2a
->pMonitorName
= ptr
;
5125 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5126 ptr
, cbBuf
, NULL
, NULL
);
5130 pi2a
->pDescription
= ptr
;
5131 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5132 ptr
, cbBuf
, NULL
, NULL
);
5136 pi2a
->fPortType
= pi2w
->fPortType
;
5137 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5140 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5141 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5142 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5147 if (pcbNeeded
) *pcbNeeded
= needed
;
5148 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5150 HeapFree(GetProcessHeap(), 0, nameW
);
5151 HeapFree(GetProcessHeap(), 0, bufferW
);
5153 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5154 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5160 /******************************************************************************
5161 * EnumPortsW (WINSPOOL.@)
5163 * Enumerate available Ports
5166 * pName [I] Servername or NULL (local Computer)
5167 * Level [I] Structure-Level (1 or 2)
5168 * pPorts [O] PTR to Buffer that receives the Result
5169 * cbBuf [I] Size of Buffer at pPorts
5170 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5171 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5175 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5178 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5181 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5182 cbBuf
, pcbNeeded
, pcReturned
);
5184 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5186 /* Level is not checked in win9x */
5187 if (!Level
|| (Level
> 2)) {
5188 WARN("level (%d) is ignored in win9x\n", Level
);
5189 SetLastError(ERROR_INVALID_LEVEL
);
5192 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5193 SetLastError(RPC_X_NULL_REF_POINTER
);
5197 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5200 /******************************************************************************
5201 * GetDefaultPrinterW (WINSPOOL.@)
5204 * This function must read the value from data 'device' of key
5205 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5207 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5211 WCHAR
*buffer
, *ptr
;
5215 SetLastError(ERROR_INVALID_PARAMETER
);
5219 /* make the buffer big enough for the stuff from the profile/registry,
5220 * the content must fit into the local buffer to compute the correct
5221 * size even if the extern buffer is too small or not given.
5222 * (20 for ,driver,port) */
5224 len
= max(100, (insize
+ 20));
5225 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5227 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5229 SetLastError (ERROR_FILE_NOT_FOUND
);
5233 TRACE("%s\n", debugstr_w(buffer
));
5235 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5237 SetLastError(ERROR_INVALID_NAME
);
5243 *namesize
= strlenW(buffer
) + 1;
5244 if(!name
|| (*namesize
> insize
))
5246 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5250 strcpyW(name
, buffer
);
5253 HeapFree( GetProcessHeap(), 0, buffer
);
5258 /******************************************************************************
5259 * GetDefaultPrinterA (WINSPOOL.@)
5261 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5265 WCHAR
*bufferW
= NULL
;
5269 SetLastError(ERROR_INVALID_PARAMETER
);
5273 if(name
&& *namesize
) {
5275 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5278 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5283 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5287 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5290 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5293 HeapFree( GetProcessHeap(), 0, bufferW
);
5298 /******************************************************************************
5299 * SetDefaultPrinterW (WINSPOOL.204)
5301 * Set the Name of the Default Printer
5304 * pszPrinter [I] Name of the Printer or NULL
5311 * When the Parameter is NULL or points to an Empty String and
5312 * a Default Printer was already present, then this Function changes nothing.
5313 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5314 * the First enumerated local Printer is used.
5317 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5319 WCHAR default_printer
[MAX_PATH
];
5320 LPWSTR buffer
= NULL
;
5326 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5327 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5329 default_printer
[0] = '\0';
5330 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5332 /* if we have a default Printer, do nothing. */
5333 if (GetDefaultPrinterW(default_printer
, &size
))
5337 /* we have no default Printer: search local Printers and use the first */
5338 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5340 default_printer
[0] = '\0';
5341 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5342 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5344 pszPrinter
= default_printer
;
5345 TRACE("using %s\n", debugstr_w(pszPrinter
));
5350 if (pszPrinter
== NULL
) {
5351 TRACE("no local printer found\n");
5352 SetLastError(ERROR_FILE_NOT_FOUND
);
5357 /* "pszPrinter" is never empty or NULL here. */
5358 namelen
= lstrlenW(pszPrinter
);
5359 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5360 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5362 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5363 HeapFree(GetProcessHeap(), 0, buffer
);
5364 SetLastError(ERROR_FILE_NOT_FOUND
);
5368 /* read the devices entry for the printer (driver,port) to build the string for the
5369 default device entry (printer,driver,port) */
5370 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5371 buffer
[namelen
] = ',';
5372 namelen
++; /* move index to the start of the driver */
5374 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5375 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5377 TRACE("set device to %s\n", debugstr_w(buffer
));
5379 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5380 TRACE("failed to set the device entry: %d\n", GetLastError());
5381 lres
= ERROR_INVALID_PRINTER_NAME
;
5384 /* remove the next section, when INIFileMapping is implemented */
5387 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5388 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5395 if (lres
!= ERROR_FILE_NOT_FOUND
)
5396 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5398 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5402 HeapFree(GetProcessHeap(), 0, buffer
);
5403 return (lres
== ERROR_SUCCESS
);
5406 /******************************************************************************
5407 * SetDefaultPrinterA (WINSPOOL.202)
5409 * See SetDefaultPrinterW.
5412 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5414 LPWSTR bufferW
= NULL
;
5417 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5419 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5420 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5421 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5423 res
= SetDefaultPrinterW(bufferW
);
5424 HeapFree(GetProcessHeap(), 0, bufferW
);
5428 /******************************************************************************
5429 * SetPrinterDataExA (WINSPOOL.@)
5431 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5432 LPCSTR pValueName
, DWORD Type
,
5433 LPBYTE pData
, DWORD cbData
)
5435 HKEY hkeyPrinter
, hkeySubkey
;
5438 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5439 debugstr_a(pValueName
), Type
, pData
, cbData
);
5441 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5445 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5447 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5448 RegCloseKey(hkeyPrinter
);
5451 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5452 RegCloseKey(hkeySubkey
);
5453 RegCloseKey(hkeyPrinter
);
5457 /******************************************************************************
5458 * SetPrinterDataExW (WINSPOOL.@)
5460 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5461 LPCWSTR pValueName
, DWORD Type
,
5462 LPBYTE pData
, DWORD cbData
)
5464 HKEY hkeyPrinter
, hkeySubkey
;
5467 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5468 debugstr_w(pValueName
), Type
, pData
, cbData
);
5470 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5474 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5476 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5477 RegCloseKey(hkeyPrinter
);
5480 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5481 RegCloseKey(hkeySubkey
);
5482 RegCloseKey(hkeyPrinter
);
5486 /******************************************************************************
5487 * SetPrinterDataA (WINSPOOL.@)
5489 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5490 LPBYTE pData
, DWORD cbData
)
5492 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5496 /******************************************************************************
5497 * SetPrinterDataW (WINSPOOL.@)
5499 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5500 LPBYTE pData
, DWORD cbData
)
5502 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5506 /******************************************************************************
5507 * GetPrinterDataExA (WINSPOOL.@)
5509 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5510 LPCSTR pValueName
, LPDWORD pType
,
5511 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5513 opened_printer_t
*printer
;
5514 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5517 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5518 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5520 printer
= get_opened_printer(hPrinter
);
5521 if(!printer
) return ERROR_INVALID_HANDLE
;
5523 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5524 if (ret
) return ret
;
5526 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5528 if (printer
->name
) {
5530 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5532 RegCloseKey(hkeyPrinters
);
5535 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5536 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5537 RegCloseKey(hkeyPrinter
);
5538 RegCloseKey(hkeyPrinters
);
5543 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5544 0, pType
, pData
, pcbNeeded
);
5546 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5548 RegCloseKey(hkeySubkey
);
5549 RegCloseKey(hkeyPrinter
);
5550 RegCloseKey(hkeyPrinters
);
5552 TRACE("--> %d\n", ret
);
5556 /******************************************************************************
5557 * GetPrinterDataExW (WINSPOOL.@)
5559 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5560 LPCWSTR pValueName
, LPDWORD pType
,
5561 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5563 opened_printer_t
*printer
;
5564 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5567 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5568 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5570 printer
= get_opened_printer(hPrinter
);
5571 if(!printer
) return ERROR_INVALID_HANDLE
;
5573 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5574 if (ret
) return ret
;
5576 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5578 if (printer
->name
) {
5580 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5582 RegCloseKey(hkeyPrinters
);
5585 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5586 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5587 RegCloseKey(hkeyPrinter
);
5588 RegCloseKey(hkeyPrinters
);
5593 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5594 0, pType
, pData
, pcbNeeded
);
5596 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5598 RegCloseKey(hkeySubkey
);
5599 RegCloseKey(hkeyPrinter
);
5600 RegCloseKey(hkeyPrinters
);
5602 TRACE("--> %d\n", ret
);
5606 /******************************************************************************
5607 * GetPrinterDataA (WINSPOOL.@)
5609 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5610 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5612 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5613 pData
, nSize
, pcbNeeded
);
5616 /******************************************************************************
5617 * GetPrinterDataW (WINSPOOL.@)
5619 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5620 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5622 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5623 pData
, nSize
, pcbNeeded
);
5626 /*******************************************************************************
5627 * EnumPrinterDataExW [WINSPOOL.@]
5629 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5630 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5631 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5633 HKEY hkPrinter
, hkSubKey
;
5634 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5635 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5640 PPRINTER_ENUM_VALUESW ppev
;
5642 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5644 if (pKeyName
== NULL
|| *pKeyName
== 0)
5645 return ERROR_INVALID_PARAMETER
;
5647 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5648 if (ret
!= ERROR_SUCCESS
)
5650 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5655 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5656 if (ret
!= ERROR_SUCCESS
)
5658 r
= RegCloseKey (hkPrinter
);
5659 if (r
!= ERROR_SUCCESS
)
5660 WARN ("RegCloseKey returned %i\n", r
);
5661 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5662 debugstr_w (pKeyName
), ret
);
5666 ret
= RegCloseKey (hkPrinter
);
5667 if (ret
!= ERROR_SUCCESS
)
5669 ERR ("RegCloseKey returned %i\n", ret
);
5670 r
= RegCloseKey (hkSubKey
);
5671 if (r
!= ERROR_SUCCESS
)
5672 WARN ("RegCloseKey returned %i\n", r
);
5676 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5677 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5678 if (ret
!= ERROR_SUCCESS
)
5680 r
= RegCloseKey (hkSubKey
);
5681 if (r
!= ERROR_SUCCESS
)
5682 WARN ("RegCloseKey returned %i\n", r
);
5683 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5687 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5688 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5690 if (cValues
== 0) /* empty key */
5692 r
= RegCloseKey (hkSubKey
);
5693 if (r
!= ERROR_SUCCESS
)
5694 WARN ("RegCloseKey returned %i\n", r
);
5695 *pcbEnumValues
= *pnEnumValues
= 0;
5696 return ERROR_SUCCESS
;
5699 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5701 hHeap
= GetProcessHeap ();
5704 ERR ("GetProcessHeap failed\n");
5705 r
= RegCloseKey (hkSubKey
);
5706 if (r
!= ERROR_SUCCESS
)
5707 WARN ("RegCloseKey returned %i\n", r
);
5708 return ERROR_OUTOFMEMORY
;
5711 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5712 if (lpValueName
== NULL
)
5714 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5715 r
= RegCloseKey (hkSubKey
);
5716 if (r
!= ERROR_SUCCESS
)
5717 WARN ("RegCloseKey returned %i\n", r
);
5718 return ERROR_OUTOFMEMORY
;
5721 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5722 if (lpValue
== NULL
)
5724 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5725 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 r
= RegCloseKey (hkSubKey
);
5728 if (r
!= ERROR_SUCCESS
)
5729 WARN ("RegCloseKey returned %i\n", r
);
5730 return ERROR_OUTOFMEMORY
;
5733 TRACE ("pass 1: calculating buffer required for all names and values\n");
5735 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5737 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5739 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5741 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5742 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5743 NULL
, NULL
, lpValue
, &cbValueLen
);
5744 if (ret
!= ERROR_SUCCESS
)
5746 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5747 WARN ("HeapFree failed with code %i\n", GetLastError ());
5748 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5749 WARN ("HeapFree failed with code %i\n", GetLastError ());
5750 r
= RegCloseKey (hkSubKey
);
5751 if (r
!= ERROR_SUCCESS
)
5752 WARN ("RegCloseKey returned %i\n", r
);
5753 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5757 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5758 debugstr_w (lpValueName
), dwIndex
,
5759 cbValueNameLen
+ 1, cbValueLen
);
5761 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5762 cbBufSize
+= cbValueLen
;
5765 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5767 *pcbEnumValues
= cbBufSize
;
5768 *pnEnumValues
= cValues
;
5770 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5772 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5775 WARN ("HeapFree failed with code %i\n", GetLastError ());
5776 r
= RegCloseKey (hkSubKey
);
5777 if (r
!= ERROR_SUCCESS
)
5778 WARN ("RegCloseKey returned %i\n", r
);
5779 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5780 return ERROR_MORE_DATA
;
5783 TRACE ("pass 2: copying all names and values to buffer\n");
5785 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5786 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5788 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5790 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5791 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5792 NULL
, &dwType
, lpValue
, &cbValueLen
);
5793 if (ret
!= ERROR_SUCCESS
)
5795 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5796 WARN ("HeapFree failed with code %i\n", GetLastError ());
5797 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5798 WARN ("HeapFree failed with code %i\n", GetLastError ());
5799 r
= RegCloseKey (hkSubKey
);
5800 if (r
!= ERROR_SUCCESS
)
5801 WARN ("RegCloseKey returned %i\n", r
);
5802 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5806 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5807 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5808 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5809 pEnumValues
+= cbValueNameLen
;
5811 /* return # of *bytes* (including trailing \0), not # of chars */
5812 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5814 ppev
[dwIndex
].dwType
= dwType
;
5816 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5817 ppev
[dwIndex
].pData
= pEnumValues
;
5818 pEnumValues
+= cbValueLen
;
5820 ppev
[dwIndex
].cbData
= cbValueLen
;
5822 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5823 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5826 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5828 ret
= GetLastError ();
5829 ERR ("HeapFree failed with code %i\n", ret
);
5830 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5831 WARN ("HeapFree failed with code %i\n", GetLastError ());
5832 r
= RegCloseKey (hkSubKey
);
5833 if (r
!= ERROR_SUCCESS
)
5834 WARN ("RegCloseKey returned %i\n", r
);
5838 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5840 ret
= GetLastError ();
5841 ERR ("HeapFree failed with code %i\n", ret
);
5842 r
= RegCloseKey (hkSubKey
);
5843 if (r
!= ERROR_SUCCESS
)
5844 WARN ("RegCloseKey returned %i\n", r
);
5848 ret
= RegCloseKey (hkSubKey
);
5849 if (ret
!= ERROR_SUCCESS
)
5851 ERR ("RegCloseKey returned %i\n", ret
);
5855 return ERROR_SUCCESS
;
5858 /*******************************************************************************
5859 * EnumPrinterDataExA [WINSPOOL.@]
5861 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5862 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5863 * what Windows 2000 SP1 does.
5866 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5867 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5868 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5872 DWORD ret
, dwIndex
, dwBufSize
;
5876 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5878 if (pKeyName
== NULL
|| *pKeyName
== 0)
5879 return ERROR_INVALID_PARAMETER
;
5881 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5884 ret
= GetLastError ();
5885 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5889 hHeap
= GetProcessHeap ();
5892 ERR ("GetProcessHeap failed\n");
5893 return ERROR_OUTOFMEMORY
;
5896 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5897 if (pKeyNameW
== NULL
)
5899 ERR ("Failed to allocate %i bytes from process heap\n",
5900 (LONG
)(len
* sizeof (WCHAR
)));
5901 return ERROR_OUTOFMEMORY
;
5904 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5906 ret
= GetLastError ();
5907 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5908 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5909 WARN ("HeapFree failed with code %i\n", GetLastError ());
5913 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5914 pcbEnumValues
, pnEnumValues
);
5915 if (ret
!= ERROR_SUCCESS
)
5917 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5918 WARN ("HeapFree failed with code %i\n", GetLastError ());
5919 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5923 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5925 ret
= GetLastError ();
5926 ERR ("HeapFree failed with code %i\n", ret
);
5930 if (*pnEnumValues
== 0) /* empty key */
5931 return ERROR_SUCCESS
;
5934 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5936 PPRINTER_ENUM_VALUESW ppev
=
5937 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5939 if (dwBufSize
< ppev
->cbValueName
)
5940 dwBufSize
= ppev
->cbValueName
;
5942 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5943 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5944 dwBufSize
= ppev
->cbData
;
5947 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5949 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5950 if (pBuffer
== NULL
)
5952 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5953 return ERROR_OUTOFMEMORY
;
5956 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5958 PPRINTER_ENUM_VALUESW ppev
=
5959 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5961 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5962 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5966 ret
= GetLastError ();
5967 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5968 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5969 WARN ("HeapFree failed with code %i\n", GetLastError ());
5973 memcpy (ppev
->pValueName
, pBuffer
, len
);
5975 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5977 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5978 ppev
->dwType
!= REG_MULTI_SZ
)
5981 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5982 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5985 ret
= GetLastError ();
5986 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5987 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5988 WARN ("HeapFree failed with code %i\n", GetLastError ());
5992 memcpy (ppev
->pData
, pBuffer
, len
);
5994 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5995 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5998 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6000 ret
= GetLastError ();
6001 ERR ("HeapFree failed with code %i\n", ret
);
6005 return ERROR_SUCCESS
;
6008 /******************************************************************************
6009 * AbortPrinter (WINSPOOL.@)
6011 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6013 FIXME("(%p), stub!\n", hPrinter
);
6017 /******************************************************************************
6018 * AddPortA (WINSPOOL.@)
6023 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6025 LPWSTR nameW
= NULL
;
6026 LPWSTR monitorW
= NULL
;
6030 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6033 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6034 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6035 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6039 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6040 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6041 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6043 res
= AddPortW(nameW
, hWnd
, monitorW
);
6044 HeapFree(GetProcessHeap(), 0, nameW
);
6045 HeapFree(GetProcessHeap(), 0, monitorW
);
6049 /******************************************************************************
6050 * AddPortW (WINSPOOL.@)
6052 * Add a Port for a specific Monitor
6055 * pName [I] Servername or NULL (local Computer)
6056 * hWnd [I] Handle to parent Window for the Dialog-Box
6057 * pMonitorName [I] Name of the Monitor that manage the Port
6064 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6066 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6068 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6070 if (!pMonitorName
) {
6071 SetLastError(RPC_X_NULL_REF_POINTER
);
6075 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6078 /******************************************************************************
6079 * AddPortExA (WINSPOOL.@)
6084 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6087 PORT_INFO_2A
* pi2A
;
6088 LPWSTR nameW
= NULL
;
6089 LPWSTR monitorW
= NULL
;
6093 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6095 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6096 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6098 if ((level
< 1) || (level
> 2)) {
6099 SetLastError(ERROR_INVALID_LEVEL
);
6104 SetLastError(ERROR_INVALID_PARAMETER
);
6109 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6110 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6111 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6115 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6116 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6117 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6120 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6122 if (pi2A
->pPortName
) {
6123 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6124 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6125 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6129 if (pi2A
->pMonitorName
) {
6130 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6131 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6132 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6135 if (pi2A
->pDescription
) {
6136 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6137 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6138 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6140 pi2W
.fPortType
= pi2A
->fPortType
;
6141 pi2W
.Reserved
= pi2A
->Reserved
;
6144 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6146 HeapFree(GetProcessHeap(), 0, nameW
);
6147 HeapFree(GetProcessHeap(), 0, monitorW
);
6148 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6149 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6150 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6155 /******************************************************************************
6156 * AddPortExW (WINSPOOL.@)
6158 * Add a Port for a specific Monitor, without presenting a user interface
6161 * pName [I] Servername or NULL (local Computer)
6162 * level [I] Structure-Level (1 or 2) for pBuffer
6163 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6164 * pMonitorName [I] Name of the Monitor that manage the Port
6171 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6175 pi2
= (PORT_INFO_2W
*) pBuffer
;
6177 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6178 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6179 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6180 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6182 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6184 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6185 SetLastError(ERROR_INVALID_PARAMETER
);
6189 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6192 /******************************************************************************
6193 * AddPrinterConnectionA (WINSPOOL.@)
6195 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6197 FIXME("%s\n", debugstr_a(pName
));
6201 /******************************************************************************
6202 * AddPrinterConnectionW (WINSPOOL.@)
6204 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6206 FIXME("%s\n", debugstr_w(pName
));
6210 /******************************************************************************
6211 * AddPrinterDriverExW (WINSPOOL.@)
6213 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6216 * pName [I] Servername or NULL (local Computer)
6217 * level [I] Level for the supplied DRIVER_INFO_*W struct
6218 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6219 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6226 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6228 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6230 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6232 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6233 SetLastError(ERROR_INVALID_LEVEL
);
6238 SetLastError(ERROR_INVALID_PARAMETER
);
6242 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6245 /******************************************************************************
6246 * AddPrinterDriverExA (WINSPOOL.@)
6248 * See AddPrinterDriverExW.
6251 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6253 DRIVER_INFO_8A
*diA
;
6255 LPWSTR nameW
= NULL
;
6260 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6262 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6263 ZeroMemory(&diW
, sizeof(diW
));
6265 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6266 SetLastError(ERROR_INVALID_LEVEL
);
6271 SetLastError(ERROR_INVALID_PARAMETER
);
6275 /* convert servername to unicode */
6277 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6278 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6279 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6283 diW
.cVersion
= diA
->cVersion
;
6286 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6287 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6288 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6291 if (diA
->pEnvironment
) {
6292 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6293 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6294 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6297 if (diA
->pDriverPath
) {
6298 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6299 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6300 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6303 if (diA
->pDataFile
) {
6304 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6305 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6306 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6309 if (diA
->pConfigFile
) {
6310 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6311 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6312 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6315 if ((Level
> 2) && diA
->pDependentFiles
) {
6316 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6317 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6318 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6319 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6322 if ((Level
> 2) && diA
->pMonitorName
) {
6323 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6324 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6325 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6328 if ((Level
> 3) && diA
->pDefaultDataType
) {
6329 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6330 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6331 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6334 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6335 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6336 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6337 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6338 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6341 if ((Level
> 5) && diA
->pszMfgName
) {
6342 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6343 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6344 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6347 if ((Level
> 5) && diA
->pszOEMUrl
) {
6348 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6349 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6350 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6353 if ((Level
> 5) && diA
->pszHardwareID
) {
6354 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6355 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6356 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6359 if ((Level
> 5) && diA
->pszProvider
) {
6360 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6361 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6362 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6366 FIXME("level %u is incomplete\n", Level
);
6369 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6370 TRACE("got %u with %u\n", res
, GetLastError());
6371 HeapFree(GetProcessHeap(), 0, nameW
);
6372 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6373 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6374 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6375 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6376 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6377 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6378 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6379 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6380 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6381 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6382 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6383 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6384 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6386 TRACE("=> %u with %u\n", res
, GetLastError());
6390 /******************************************************************************
6391 * ConfigurePortA (WINSPOOL.@)
6393 * See ConfigurePortW.
6396 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6398 LPWSTR nameW
= NULL
;
6399 LPWSTR portW
= NULL
;
6403 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6405 /* convert servername to unicode */
6407 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6408 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6409 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6412 /* convert portname to unicode */
6414 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6415 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6416 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6419 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6420 HeapFree(GetProcessHeap(), 0, nameW
);
6421 HeapFree(GetProcessHeap(), 0, portW
);
6425 /******************************************************************************
6426 * ConfigurePortW (WINSPOOL.@)
6428 * Display the Configuration-Dialog for a specific Port
6431 * pName [I] Servername or NULL (local Computer)
6432 * hWnd [I] Handle to parent Window for the Dialog-Box
6433 * pPortName [I] Name of the Port, that should be configured
6440 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6443 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6445 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6448 SetLastError(RPC_X_NULL_REF_POINTER
);
6452 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6455 /******************************************************************************
6456 * ConnectToPrinterDlg (WINSPOOL.@)
6458 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6460 FIXME("%p %x\n", hWnd
, Flags
);
6464 /******************************************************************************
6465 * DeletePrinterConnectionA (WINSPOOL.@)
6467 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6469 FIXME("%s\n", debugstr_a(pName
));
6473 /******************************************************************************
6474 * DeletePrinterConnectionW (WINSPOOL.@)
6476 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6478 FIXME("%s\n", debugstr_w(pName
));
6482 /******************************************************************************
6483 * DeletePrinterDriverExW (WINSPOOL.@)
6485 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6486 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6491 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6492 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6494 if(pName
&& pName
[0])
6496 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6497 SetLastError(ERROR_INVALID_PARAMETER
);
6503 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6504 SetLastError(ERROR_INVALID_PARAMETER
);
6508 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6512 ERR("Can't open drivers key\n");
6516 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6519 RegCloseKey(hkey_drivers
);
6524 /******************************************************************************
6525 * DeletePrinterDriverExA (WINSPOOL.@)
6527 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6528 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6530 UNICODE_STRING NameW
, EnvW
, DriverW
;
6533 asciitounicode(&NameW
, pName
);
6534 asciitounicode(&EnvW
, pEnvironment
);
6535 asciitounicode(&DriverW
, pDriverName
);
6537 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6539 RtlFreeUnicodeString(&DriverW
);
6540 RtlFreeUnicodeString(&EnvW
);
6541 RtlFreeUnicodeString(&NameW
);
6546 /******************************************************************************
6547 * DeletePrinterDataExW (WINSPOOL.@)
6549 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6552 FIXME("%p %s %s\n", hPrinter
,
6553 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6554 return ERROR_INVALID_PARAMETER
;
6557 /******************************************************************************
6558 * DeletePrinterDataExA (WINSPOOL.@)
6560 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6563 FIXME("%p %s %s\n", hPrinter
,
6564 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6565 return ERROR_INVALID_PARAMETER
;
6568 /******************************************************************************
6569 * DeletePrintProcessorA (WINSPOOL.@)
6571 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6573 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6574 debugstr_a(pPrintProcessorName
));
6578 /******************************************************************************
6579 * DeletePrintProcessorW (WINSPOOL.@)
6581 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6583 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6584 debugstr_w(pPrintProcessorName
));
6588 /******************************************************************************
6589 * DeletePrintProvidorA (WINSPOOL.@)
6591 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6593 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6594 debugstr_a(pPrintProviderName
));
6598 /******************************************************************************
6599 * DeletePrintProvidorW (WINSPOOL.@)
6601 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6603 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6604 debugstr_w(pPrintProviderName
));
6608 /******************************************************************************
6609 * EnumFormsA (WINSPOOL.@)
6611 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6612 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6614 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6615 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6619 /******************************************************************************
6620 * EnumFormsW (WINSPOOL.@)
6622 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6623 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6625 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6626 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6630 /*****************************************************************************
6631 * EnumMonitorsA [WINSPOOL.@]
6633 * See EnumMonitorsW.
6636 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6637 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6640 LPBYTE bufferW
= NULL
;
6641 LPWSTR nameW
= NULL
;
6643 DWORD numentries
= 0;
6646 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6647 cbBuf
, pcbNeeded
, pcReturned
);
6649 /* convert servername to unicode */
6651 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6652 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6653 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6655 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6656 needed
= cbBuf
* sizeof(WCHAR
);
6657 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6658 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6660 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6661 if (pcbNeeded
) needed
= *pcbNeeded
;
6662 /* HeapReAlloc return NULL, when bufferW was NULL */
6663 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6664 HeapAlloc(GetProcessHeap(), 0, needed
);
6666 /* Try again with the large Buffer */
6667 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6669 numentries
= pcReturned
? *pcReturned
: 0;
6672 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6673 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6676 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6677 DWORD entrysize
= 0;
6680 LPMONITOR_INFO_2W mi2w
;
6681 LPMONITOR_INFO_2A mi2a
;
6683 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6684 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6686 /* First pass: calculate the size for all Entries */
6687 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6688 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6690 while (index
< numentries
) {
6692 needed
+= entrysize
; /* MONITOR_INFO_?A */
6693 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6695 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6696 NULL
, 0, NULL
, NULL
);
6698 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6699 NULL
, 0, NULL
, NULL
);
6700 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6701 NULL
, 0, NULL
, NULL
);
6703 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6704 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6705 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6708 /* check for errors and quit on failure */
6709 if (cbBuf
< needed
) {
6710 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6714 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6715 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6716 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6717 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6718 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6720 /* Second Pass: Fill the User Buffer (if we have one) */
6721 while ((index
< numentries
) && pMonitors
) {
6723 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6725 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6726 ptr
, cbBuf
, NULL
, NULL
);
6730 mi2a
->pEnvironment
= ptr
;
6731 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6732 ptr
, cbBuf
, NULL
, NULL
);
6736 mi2a
->pDLLName
= ptr
;
6737 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6738 ptr
, cbBuf
, NULL
, NULL
);
6742 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6743 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6744 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6748 if (pcbNeeded
) *pcbNeeded
= needed
;
6749 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6751 HeapFree(GetProcessHeap(), 0, nameW
);
6752 HeapFree(GetProcessHeap(), 0, bufferW
);
6754 TRACE("returning %d with %d (%d byte for %d entries)\n",
6755 (res
), GetLastError(), needed
, numentries
);
6761 /*****************************************************************************
6762 * EnumMonitorsW [WINSPOOL.@]
6764 * Enumerate available Port-Monitors
6767 * pName [I] Servername or NULL (local Computer)
6768 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6769 * pMonitors [O] PTR to Buffer that receives the Result
6770 * cbBuf [I] Size of Buffer at pMonitors
6771 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6772 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6776 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6779 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6780 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6783 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6784 cbBuf
, pcbNeeded
, pcReturned
);
6786 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6788 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6789 SetLastError(RPC_X_NULL_REF_POINTER
);
6793 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6796 /******************************************************************************
6797 * SpoolerInit (WINSPOOL.@)
6799 * Initialize the Spooler
6806 * The function fails on windows, when the spooler service is not running
6809 BOOL WINAPI
SpoolerInit(void)
6812 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6816 /******************************************************************************
6817 * XcvDataW (WINSPOOL.@)
6819 * Execute commands in the Printmonitor DLL
6822 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6823 * pszDataName [i] Name of the command to execute
6824 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6825 * cbInputData [i] Size in Bytes of Buffer at pInputData
6826 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6827 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6828 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6829 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6836 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6837 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6839 * Minimal List of commands, that a Printmonitor DLL should support:
6841 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6842 *| "AddPort" : Add a Port
6843 *| "DeletePort": Delete a Port
6845 * Many Printmonitors support additional commands. Examples for localspl.dll:
6846 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6847 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6850 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6851 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6852 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6854 opened_printer_t
*printer
;
6856 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6857 pInputData
, cbInputData
, pOutputData
,
6858 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6860 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6862 printer
= get_opened_printer(hXcv
);
6863 if (!printer
|| (!printer
->backend_printer
)) {
6864 SetLastError(ERROR_INVALID_HANDLE
);
6868 if (!pcbOutputNeeded
) {
6869 SetLastError(ERROR_INVALID_PARAMETER
);
6873 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6874 SetLastError(RPC_X_NULL_REF_POINTER
);
6878 *pcbOutputNeeded
= 0;
6880 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6881 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6885 /*****************************************************************************
6886 * EnumPrinterDataA [WINSPOOL.@]
6889 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6890 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6891 DWORD cbData
, LPDWORD pcbData
)
6893 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6894 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6895 return ERROR_NO_MORE_ITEMS
;
6898 /*****************************************************************************
6899 * EnumPrinterDataW [WINSPOOL.@]
6902 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6903 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6904 DWORD cbData
, LPDWORD pcbData
)
6906 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6907 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6908 return ERROR_NO_MORE_ITEMS
;
6911 /*****************************************************************************
6912 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6915 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6916 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6917 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6919 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6920 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6921 pcbNeeded
, pcReturned
);
6925 /*****************************************************************************
6926 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6929 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6930 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6931 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6933 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6934 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6935 pcbNeeded
, pcReturned
);
6939 /*****************************************************************************
6940 * EnumPrintProcessorsA [WINSPOOL.@]
6942 * See EnumPrintProcessorsW.
6945 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6946 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6949 LPBYTE bufferW
= NULL
;
6950 LPWSTR nameW
= NULL
;
6953 DWORD numentries
= 0;
6956 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6957 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6959 /* convert names to unicode */
6961 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6962 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6963 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6966 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6967 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6968 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6971 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6972 needed
= cbBuf
* sizeof(WCHAR
);
6973 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6974 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6976 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6977 if (pcbNeeded
) needed
= *pcbNeeded
;
6978 /* HeapReAlloc return NULL, when bufferW was NULL */
6979 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6980 HeapAlloc(GetProcessHeap(), 0, needed
);
6982 /* Try again with the large Buffer */
6983 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6985 numentries
= pcReturned
? *pcReturned
: 0;
6989 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6992 PPRINTPROCESSOR_INFO_1W ppiw
;
6993 PPRINTPROCESSOR_INFO_1A ppia
;
6995 /* First pass: calculate the size for all Entries */
6996 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6997 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6999 while (index
< numentries
) {
7001 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7002 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7004 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7005 NULL
, 0, NULL
, NULL
);
7007 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7008 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7011 /* check for errors and quit on failure */
7012 if (cbBuf
< needed
) {
7013 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7018 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7019 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7020 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7021 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7022 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7024 /* Second Pass: Fill the User Buffer (if we have one) */
7025 while ((index
< numentries
) && pPPInfo
) {
7027 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7029 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7030 ptr
, cbBuf
, NULL
, NULL
);
7034 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7035 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7040 if (pcbNeeded
) *pcbNeeded
= needed
;
7041 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7043 HeapFree(GetProcessHeap(), 0, nameW
);
7044 HeapFree(GetProcessHeap(), 0, envW
);
7045 HeapFree(GetProcessHeap(), 0, bufferW
);
7047 TRACE("returning %d with %d (%d byte for %d entries)\n",
7048 (res
), GetLastError(), needed
, numentries
);
7053 /*****************************************************************************
7054 * EnumPrintProcessorsW [WINSPOOL.@]
7056 * Enumerate available Print Processors
7059 * pName [I] Servername or NULL (local Computer)
7060 * pEnvironment [I] Printing-Environment or NULL (Default)
7061 * Level [I] Structure-Level (Only 1 is allowed)
7062 * pPPInfo [O] PTR to Buffer that receives the Result
7063 * cbBuf [I] Size of Buffer at pPPInfo
7064 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7065 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7069 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7072 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7073 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7076 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7077 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7079 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7081 if (!pcbNeeded
|| !pcReturned
) {
7082 SetLastError(RPC_X_NULL_REF_POINTER
);
7086 if (!pPPInfo
&& (cbBuf
> 0)) {
7087 SetLastError(ERROR_INVALID_USER_BUFFER
);
7091 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7092 cbBuf
, pcbNeeded
, pcReturned
);
7095 /*****************************************************************************
7096 * ExtDeviceMode [WINSPOOL.@]
7099 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7100 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7103 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7104 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7105 debugstr_a(pProfile
), fMode
);
7109 /*****************************************************************************
7110 * FindClosePrinterChangeNotification [WINSPOOL.@]
7113 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7115 FIXME("Stub: %p\n", hChange
);
7119 /*****************************************************************************
7120 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7123 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7124 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7126 FIXME("Stub: %p %x %x %p\n",
7127 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7128 return INVALID_HANDLE_VALUE
;
7131 /*****************************************************************************
7132 * FindNextPrinterChangeNotification [WINSPOOL.@]
7135 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7136 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7138 FIXME("Stub: %p %p %p %p\n",
7139 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7143 /*****************************************************************************
7144 * FreePrinterNotifyInfo [WINSPOOL.@]
7147 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7149 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7153 /*****************************************************************************
7156 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7157 * ansi depending on the unicode parameter.
7159 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7169 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7172 memcpy(ptr
, str
, *size
);
7179 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7182 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7189 /*****************************************************************************
7192 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7193 LPDWORD pcbNeeded
, BOOL unicode
)
7195 DWORD size
, left
= cbBuf
;
7196 BOOL space
= (cbBuf
> 0);
7203 ji1
->JobId
= job
->job_id
;
7206 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7207 if(space
&& size
<= left
)
7209 ji1
->pDocument
= (LPWSTR
)ptr
;
7217 if (job
->printer_name
)
7219 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7220 if(space
&& size
<= left
)
7222 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7234 /*****************************************************************************
7237 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7238 LPDWORD pcbNeeded
, BOOL unicode
)
7240 DWORD size
, left
= cbBuf
;
7242 BOOL space
= (cbBuf
> 0);
7244 LPDEVMODEA dmA
= NULL
;
7251 ji2
->JobId
= job
->job_id
;
7254 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7255 if(space
&& size
<= left
)
7257 ji2
->pDocument
= (LPWSTR
)ptr
;
7265 if (job
->printer_name
)
7267 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7268 if(space
&& size
<= left
)
7270 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7283 dmA
= DEVMODEdupWtoA(job
->devmode
);
7284 devmode
= (LPDEVMODEW
) dmA
;
7285 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7289 devmode
= job
->devmode
;
7290 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7294 FIXME("Can't convert DEVMODE W to A\n");
7297 /* align DEVMODE to a DWORD boundary */
7298 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7304 memcpy(ptr
, devmode
, size
-shift
);
7305 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7306 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7319 /*****************************************************************************
7322 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7323 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7326 DWORD needed
= 0, size
;
7330 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7332 EnterCriticalSection(&printer_handles_cs
);
7333 job
= get_job(hPrinter
, JobId
);
7340 size
= sizeof(JOB_INFO_1W
);
7345 memset(pJob
, 0, size
);
7349 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7354 size
= sizeof(JOB_INFO_2W
);
7359 memset(pJob
, 0, size
);
7363 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7368 size
= sizeof(JOB_INFO_3
);
7372 memset(pJob
, 0, size
);
7381 SetLastError(ERROR_INVALID_LEVEL
);
7385 *pcbNeeded
= needed
;
7387 LeaveCriticalSection(&printer_handles_cs
);
7391 /*****************************************************************************
7392 * GetJobA [WINSPOOL.@]
7395 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7396 DWORD cbBuf
, LPDWORD pcbNeeded
)
7398 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7401 /*****************************************************************************
7402 * GetJobW [WINSPOOL.@]
7405 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7406 DWORD cbBuf
, LPDWORD pcbNeeded
)
7408 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7411 /*****************************************************************************
7414 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7417 char *unixname
, *cmdA
;
7419 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7425 if(!(unixname
= wine_get_unix_file_name(filename
)))
7428 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7429 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7430 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7432 TRACE("printing with: %s\n", cmdA
);
7434 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7439 ERR("pipe() failed!\n");
7443 if ((pid
= fork()) == 0)
7449 /* reset signals that we previously set to SIG_IGN */
7450 signal(SIGPIPE
, SIG_DFL
);
7452 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7457 ERR("fork() failed!\n");
7461 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7462 write(fds
[1], buf
, no_read
);
7469 wret
= waitpid(pid
, &status
, 0);
7470 } while (wret
< 0 && errno
== EINTR
);
7473 ERR("waitpid() failed!\n");
7476 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7478 ERR("child process failed! %d\n", status
);
7485 if(file_fd
!= -1) close(file_fd
);
7486 if(fds
[0] != -1) close(fds
[0]);
7487 if(fds
[1] != -1) close(fds
[1]);
7489 HeapFree(GetProcessHeap(), 0, cmdA
);
7490 HeapFree(GetProcessHeap(), 0, unixname
);
7497 /*****************************************************************************
7500 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7503 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7506 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7507 sprintfW(cmd
, fmtW
, printer_name
);
7509 r
= schedule_pipe(cmd
, filename
);
7511 HeapFree(GetProcessHeap(), 0, cmd
);
7515 /*****************************************************************************
7518 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7520 #ifdef SONAME_LIBCUPS
7523 char *unixname
, *queue
, *unix_doc_title
;
7527 if(!(unixname
= wine_get_unix_file_name(filename
)))
7530 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7531 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7532 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7534 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7535 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7536 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7538 TRACE("printing via cups\n");
7539 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7540 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7541 HeapFree(GetProcessHeap(), 0, queue
);
7542 HeapFree(GetProcessHeap(), 0, unixname
);
7548 return schedule_lpr(printer_name
, filename
);
7552 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7559 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7563 if(HIWORD(wparam
) == BN_CLICKED
)
7565 if(LOWORD(wparam
) == IDOK
)
7568 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7571 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7572 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7574 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7576 WCHAR caption
[200], message
[200];
7579 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7580 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7581 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7582 if(mb_ret
== IDCANCEL
)
7584 HeapFree(GetProcessHeap(), 0, filename
);
7588 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7589 if(hf
== INVALID_HANDLE_VALUE
)
7591 WCHAR caption
[200], message
[200];
7593 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7594 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7595 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7596 HeapFree(GetProcessHeap(), 0, filename
);
7600 DeleteFileW(filename
);
7601 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7603 EndDialog(hwnd
, IDOK
);
7606 if(LOWORD(wparam
) == IDCANCEL
)
7608 EndDialog(hwnd
, IDCANCEL
);
7617 /*****************************************************************************
7620 static BOOL
get_filename(LPWSTR
*filename
)
7622 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7623 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7626 /*****************************************************************************
7629 static BOOL
schedule_file(LPCWSTR filename
)
7631 LPWSTR output
= NULL
;
7633 if(get_filename(&output
))
7636 TRACE("copy to %s\n", debugstr_w(output
));
7637 r
= CopyFileW(filename
, output
, FALSE
);
7638 HeapFree(GetProcessHeap(), 0, output
);
7644 /*****************************************************************************
7647 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7649 int in_fd
, out_fd
, no_read
;
7652 char *unixname
, *outputA
;
7655 if(!(unixname
= wine_get_unix_file_name(filename
)))
7658 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7659 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7660 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7662 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7663 in_fd
= open(unixname
, O_RDONLY
);
7664 if(out_fd
== -1 || in_fd
== -1)
7667 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7668 write(out_fd
, buf
, no_read
);
7672 if(in_fd
!= -1) close(in_fd
);
7673 if(out_fd
!= -1) close(out_fd
);
7674 HeapFree(GetProcessHeap(), 0, outputA
);
7675 HeapFree(GetProcessHeap(), 0, unixname
);
7679 /*****************************************************************************
7680 * ScheduleJob [WINSPOOL.@]
7683 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7685 opened_printer_t
*printer
;
7687 struct list
*cursor
, *cursor2
;
7689 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7690 EnterCriticalSection(&printer_handles_cs
);
7691 printer
= get_opened_printer(hPrinter
);
7695 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7697 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7700 if(job
->job_id
!= dwJobID
) continue;
7702 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7703 if(hf
!= INVALID_HANDLE_VALUE
)
7705 PRINTER_INFO_5W
*pi5
= NULL
;
7706 LPWSTR portname
= job
->portname
;
7710 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7711 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7715 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7716 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7717 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7718 portname
= pi5
->pPortName
;
7720 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7721 debugstr_w(portname
));
7725 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7726 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7728 DWORD type
, count
= sizeof(output
);
7729 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7732 if(output
[0] == '|')
7734 ret
= schedule_pipe(output
+ 1, job
->filename
);
7738 ret
= schedule_unixfile(output
, job
->filename
);
7740 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7742 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7744 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7746 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7748 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7750 ret
= schedule_file(job
->filename
);
7754 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7756 HeapFree(GetProcessHeap(), 0, pi5
);
7758 DeleteFileW(job
->filename
);
7760 list_remove(cursor
);
7761 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7762 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7763 HeapFree(GetProcessHeap(), 0, job
->portname
);
7764 HeapFree(GetProcessHeap(), 0, job
->filename
);
7765 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7766 HeapFree(GetProcessHeap(), 0, job
);
7770 LeaveCriticalSection(&printer_handles_cs
);
7774 /*****************************************************************************
7775 * StartDocDlgA [WINSPOOL.@]
7777 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7779 UNICODE_STRING usBuffer
;
7782 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7785 docW
.cbSize
= sizeof(docW
);
7786 if (doc
->lpszDocName
)
7788 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7789 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7791 if (doc
->lpszOutput
)
7793 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7794 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7796 if (doc
->lpszDatatype
)
7798 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7799 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7801 docW
.fwType
= doc
->fwType
;
7803 retW
= StartDocDlgW(hPrinter
, &docW
);
7807 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7808 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7809 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7810 HeapFree(GetProcessHeap(), 0, retW
);
7813 HeapFree(GetProcessHeap(), 0, datatypeW
);
7814 HeapFree(GetProcessHeap(), 0, outputW
);
7815 HeapFree(GetProcessHeap(), 0, docnameW
);
7820 /*****************************************************************************
7821 * StartDocDlgW [WINSPOOL.@]
7823 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7824 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7825 * port is "FILE:". Also returns the full path if passed a relative path.
7827 * The caller should free the returned string from the process heap.
7829 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7834 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7836 PRINTER_INFO_5W
*pi5
;
7837 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7838 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7840 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7841 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7842 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7844 HeapFree(GetProcessHeap(), 0, pi5
);
7847 HeapFree(GetProcessHeap(), 0, pi5
);
7850 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7854 if (get_filename(&name
))
7856 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7858 HeapFree(GetProcessHeap(), 0, name
);
7861 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7862 GetFullPathNameW(name
, len
, ret
, NULL
);
7863 HeapFree(GetProcessHeap(), 0, name
);
7868 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7871 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7872 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7874 attr
= GetFileAttributesW(ret
);
7875 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7877 HeapFree(GetProcessHeap(), 0, ret
);