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
);
1903 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1904 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1908 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1909 SetLastError(ERROR_INVALID_PARAMETER
);
1913 /* Get the unique handle of the printer or Printserver */
1914 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1915 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1916 return (*phPrinter
!= 0);
1919 /******************************************************************
1920 * AddMonitorA [WINSPOOL.@]
1925 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1927 LPWSTR nameW
= NULL
;
1930 LPMONITOR_INFO_2A mi2a
;
1931 MONITOR_INFO_2W mi2w
;
1933 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1934 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1935 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1936 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1937 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1940 SetLastError(ERROR_INVALID_LEVEL
);
1944 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1950 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1951 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1952 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1955 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1957 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1958 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1959 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1961 if (mi2a
->pEnvironment
) {
1962 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1963 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1964 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1966 if (mi2a
->pDLLName
) {
1967 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1968 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1969 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1972 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1974 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1975 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1976 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1978 HeapFree(GetProcessHeap(), 0, nameW
);
1982 /******************************************************************************
1983 * AddMonitorW [WINSPOOL.@]
1985 * Install a Printmonitor
1988 * pName [I] Servername or NULL (local Computer)
1989 * Level [I] Structure-Level (Must be 2)
1990 * pMonitors [I] PTR to MONITOR_INFO_2
1997 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2000 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2002 LPMONITOR_INFO_2W mi2w
;
2004 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2005 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2006 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2007 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2008 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2010 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2013 SetLastError(ERROR_INVALID_LEVEL
);
2017 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2022 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2025 /******************************************************************
2026 * DeletePrinterDriverA [WINSPOOL.@]
2029 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2031 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2034 /******************************************************************
2035 * DeletePrinterDriverW [WINSPOOL.@]
2038 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2040 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2043 /******************************************************************
2044 * DeleteMonitorA [WINSPOOL.@]
2046 * See DeleteMonitorW.
2049 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2051 LPWSTR nameW
= NULL
;
2052 LPWSTR EnvironmentW
= NULL
;
2053 LPWSTR MonitorNameW
= NULL
;
2058 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2059 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2060 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2064 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2065 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2066 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2069 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2070 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2071 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2074 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2076 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2077 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2078 HeapFree(GetProcessHeap(), 0, nameW
);
2082 /******************************************************************
2083 * DeleteMonitorW [WINSPOOL.@]
2085 * Delete a specific Printmonitor from a Printing-Environment
2088 * pName [I] Servername or NULL (local Computer)
2089 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2090 * pMonitorName [I] Name of the Monitor, that should be deleted
2097 * pEnvironment is ignored in Windows for the local Computer.
2100 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2103 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2104 debugstr_w(pMonitorName
));
2106 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2108 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2112 /******************************************************************
2113 * DeletePortA [WINSPOOL.@]
2118 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2120 LPWSTR nameW
= NULL
;
2121 LPWSTR portW
= NULL
;
2125 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2127 /* convert servername to unicode */
2129 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2130 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2131 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2134 /* convert portname to unicode */
2136 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2137 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2138 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2141 res
= DeletePortW(nameW
, hWnd
, portW
);
2142 HeapFree(GetProcessHeap(), 0, nameW
);
2143 HeapFree(GetProcessHeap(), 0, portW
);
2147 /******************************************************************
2148 * DeletePortW [WINSPOOL.@]
2150 * Delete a specific Port
2153 * pName [I] Servername or NULL (local Computer)
2154 * hWnd [I] Handle to parent Window for the Dialog-Box
2155 * pPortName [I] Name of the Port, that should be deleted
2162 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2164 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2166 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2169 SetLastError(RPC_X_NULL_REF_POINTER
);
2173 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2176 /******************************************************************************
2177 * SetPrinterW [WINSPOOL.@]
2179 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2181 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2186 /******************************************************************************
2187 * WritePrinter [WINSPOOL.@]
2189 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2191 opened_printer_t
*printer
;
2194 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2196 EnterCriticalSection(&printer_handles_cs
);
2197 printer
= get_opened_printer(hPrinter
);
2200 SetLastError(ERROR_INVALID_HANDLE
);
2206 SetLastError(ERROR_SPL_NO_STARTDOC
);
2210 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2212 LeaveCriticalSection(&printer_handles_cs
);
2216 /*****************************************************************************
2217 * AddFormA [WINSPOOL.@]
2219 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2221 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2225 /*****************************************************************************
2226 * AddFormW [WINSPOOL.@]
2228 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2230 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2234 /*****************************************************************************
2235 * AddJobA [WINSPOOL.@]
2237 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2240 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2244 SetLastError(ERROR_INVALID_LEVEL
);
2248 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2251 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2252 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2253 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2254 if(*pcbNeeded
> cbBuf
) {
2255 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2258 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2259 addjobA
->JobId
= addjobW
->JobId
;
2260 addjobA
->Path
= (char *)(addjobA
+ 1);
2261 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2267 /*****************************************************************************
2268 * AddJobW [WINSPOOL.@]
2270 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2272 opened_printer_t
*printer
;
2275 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2276 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2277 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2279 ADDJOB_INFO_1W
*addjob
;
2281 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2283 EnterCriticalSection(&printer_handles_cs
);
2285 printer
= get_opened_printer(hPrinter
);
2288 SetLastError(ERROR_INVALID_HANDLE
);
2293 SetLastError(ERROR_INVALID_LEVEL
);
2297 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2301 job
->job_id
= InterlockedIncrement(&next_job_id
);
2303 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2304 if(path
[len
- 1] != '\\')
2306 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2307 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2309 len
= strlenW(filename
);
2310 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2311 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2312 job
->document_title
= strdupW(default_doc_title
);
2313 job
->printer_name
= strdupW(printer
->name
);
2314 job
->devmode
= NULL
;
2315 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2317 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2318 if(*pcbNeeded
<= cbBuf
) {
2319 addjob
= (ADDJOB_INFO_1W
*)pData
;
2320 addjob
->JobId
= job
->job_id
;
2321 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2322 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2325 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2328 LeaveCriticalSection(&printer_handles_cs
);
2332 /*****************************************************************************
2333 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2335 * Return the PATH for the Print-Processors
2337 * See GetPrintProcessorDirectoryW.
2341 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2342 DWORD level
, LPBYTE Info
,
2343 DWORD cbBuf
, LPDWORD pcbNeeded
)
2345 LPWSTR serverW
= NULL
;
2350 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2351 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2355 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2356 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2357 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2361 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2362 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2363 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2366 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2367 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2369 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2372 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2373 cbBuf
, NULL
, NULL
) > 0;
2376 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2377 HeapFree(GetProcessHeap(), 0, envW
);
2378 HeapFree(GetProcessHeap(), 0, serverW
);
2382 /*****************************************************************************
2383 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2385 * Return the PATH for the Print-Processors
2388 * server [I] Servername (NT only) or NULL (local Computer)
2389 * env [I] Printing-Environment (see below) or NULL (Default)
2390 * level [I] Structure-Level (must be 1)
2391 * Info [O] PTR to Buffer that receives the Result
2392 * cbBuf [I] Size of Buffer at "Info"
2393 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2394 * required for the Buffer at "Info"
2397 * Success: TRUE and in pcbNeeded the Bytes used in Info
2398 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2399 * if cbBuf is too small
2401 * Native Values returned in Info on Success:
2402 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2403 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2404 *| win9x(Windows 4.0): "%winsysdir%"
2406 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2409 * Only NULL or "" is supported for server
2412 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2413 DWORD level
, LPBYTE Info
,
2414 DWORD cbBuf
, LPDWORD pcbNeeded
)
2417 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2418 Info
, cbBuf
, pcbNeeded
);
2420 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2423 /* (Level != 1) is ignored in win9x */
2424 SetLastError(ERROR_INVALID_LEVEL
);
2428 if (pcbNeeded
== NULL
) {
2429 /* (pcbNeeded == NULL) is ignored in win9x */
2430 SetLastError(RPC_X_NULL_REF_POINTER
);
2434 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2437 /*****************************************************************************
2438 * WINSPOOL_OpenDriverReg [internal]
2440 * opens the registry for the printer drivers depending on the given input
2441 * variable pEnvironment
2444 * the opened hkey on success
2447 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2451 const printenv_t
* env
;
2453 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2455 env
= validate_envW(pEnvironment
);
2456 if (!env
) return NULL
;
2458 buffer
= HeapAlloc( GetProcessHeap(), 0,
2459 (strlenW(DriversW
) + strlenW(env
->envname
) +
2460 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2462 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2463 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2464 HeapFree(GetProcessHeap(), 0, buffer
);
2469 /*****************************************************************************
2470 * set_devices_and_printerports [internal]
2472 * set the [Devices] and [PrinterPorts] entries for a printer.
2475 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2477 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2481 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2483 /* FIXME: the driver must change to "winspool" */
2484 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2486 lstrcpyW(devline
, driver_nt
);
2487 lstrcatW(devline
, commaW
);
2488 lstrcatW(devline
, pi
->pPortName
);
2490 TRACE("using %s\n", debugstr_w(devline
));
2491 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2492 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2493 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2494 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2498 lstrcatW(devline
, timeout_15_45
);
2499 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2500 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2501 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2502 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2505 HeapFree(GetProcessHeap(), 0, devline
);
2509 /*****************************************************************************
2510 * AddPrinterW [WINSPOOL.@]
2512 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2514 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2518 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2520 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2521 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2522 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2523 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2524 statusW
[] = {'S','t','a','t','u','s',0},
2525 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2527 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2530 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2531 SetLastError(ERROR_INVALID_PARAMETER
);
2535 ERR("Level = %d, unsupported!\n", Level
);
2536 SetLastError(ERROR_INVALID_LEVEL
);
2540 SetLastError(ERROR_INVALID_PARAMETER
);
2543 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2545 ERR("Can't create Printers key\n");
2548 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2549 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2550 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2551 RegCloseKey(hkeyPrinter
);
2552 RegCloseKey(hkeyPrinters
);
2555 RegCloseKey(hkeyPrinter
);
2557 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2559 ERR("Can't create Drivers key\n");
2560 RegCloseKey(hkeyPrinters
);
2563 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2565 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2566 RegCloseKey(hkeyPrinters
);
2567 RegCloseKey(hkeyDrivers
);
2568 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2571 RegCloseKey(hkeyDriver
);
2572 RegCloseKey(hkeyDrivers
);
2574 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2575 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2576 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2577 RegCloseKey(hkeyPrinters
);
2581 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2583 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2584 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2585 RegCloseKey(hkeyPrinters
);
2589 set_devices_and_printerports(pi
);
2590 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2591 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2592 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2594 /* See if we can load the driver. We may need the devmode structure anyway
2597 * Note that DocumentPropertiesW will briefly try to open the printer we
2598 * just create to find a DEVMODEA struct (it will use the WINEPS default
2599 * one in case it is not there, so we are ok).
2601 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2604 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2605 size
= sizeof(DEVMODEW
);
2611 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2613 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2615 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2616 HeapFree(GetProcessHeap(),0,dmW
);
2621 /* set devmode to printer name */
2622 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2626 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2627 and we support these drivers. NT writes DEVMODEW so somehow
2628 we'll need to distinguish between these when we support NT
2632 dmA
= DEVMODEdupWtoA(dmW
);
2633 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2634 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2635 HeapFree(GetProcessHeap(), 0, dmA
);
2637 HeapFree(GetProcessHeap(), 0, dmW
);
2639 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2640 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2641 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2642 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2644 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2645 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2646 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2647 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2648 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2649 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2650 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2651 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2652 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2653 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2654 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2655 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2656 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2658 RegCloseKey(hkeyPrinter
);
2659 RegCloseKey(hkeyPrinters
);
2660 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2661 ERR("OpenPrinter failing\n");
2667 /*****************************************************************************
2668 * AddPrinterA [WINSPOOL.@]
2670 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2672 UNICODE_STRING pNameW
;
2674 PRINTER_INFO_2W
*piW
;
2675 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2678 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2680 ERR("Level = %d, unsupported!\n", Level
);
2681 SetLastError(ERROR_INVALID_LEVEL
);
2684 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2685 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2687 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2689 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2690 RtlFreeUnicodeString(&pNameW
);
2695 /*****************************************************************************
2696 * ClosePrinter [WINSPOOL.@]
2698 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2700 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2701 opened_printer_t
*printer
= NULL
;
2704 TRACE("(%p)\n", hPrinter
);
2706 EnterCriticalSection(&printer_handles_cs
);
2708 if ((i
> 0) && (i
<= nb_printer_handles
))
2709 printer
= printer_handles
[i
- 1];
2714 struct list
*cursor
, *cursor2
;
2716 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2718 if (printer
->backend_printer
) {
2719 backend
->fpClosePrinter(printer
->backend_printer
);
2723 EndDocPrinter(hPrinter
);
2725 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2727 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2729 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2730 ScheduleJob(hPrinter
, job
->job_id
);
2732 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2735 free_printer_entry( printer
);
2736 printer_handles
[i
- 1] = NULL
;
2739 LeaveCriticalSection(&printer_handles_cs
);
2743 /*****************************************************************************
2744 * DeleteFormA [WINSPOOL.@]
2746 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2748 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2752 /*****************************************************************************
2753 * DeleteFormW [WINSPOOL.@]
2755 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2757 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2761 /*****************************************************************************
2762 * DeletePrinter [WINSPOOL.@]
2764 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2766 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2767 HKEY hkeyPrinters
, hkey
;
2770 SetLastError(ERROR_INVALID_HANDLE
);
2773 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2774 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2775 RegCloseKey(hkeyPrinters
);
2777 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2778 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2780 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2781 RegDeleteValueW(hkey
, lpNameW
);
2785 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2786 RegDeleteValueW(hkey
, lpNameW
);
2792 /*****************************************************************************
2793 * SetPrinterA [WINSPOOL.@]
2795 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2798 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2802 /*****************************************************************************
2803 * SetJobA [WINSPOOL.@]
2805 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2806 LPBYTE pJob
, DWORD Command
)
2810 UNICODE_STRING usBuffer
;
2812 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2814 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2815 are all ignored by SetJob, so we don't bother copying them */
2823 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2824 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2826 JobW
= (LPBYTE
)info1W
;
2827 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2828 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2829 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2830 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2831 info1W
->Status
= info1A
->Status
;
2832 info1W
->Priority
= info1A
->Priority
;
2833 info1W
->Position
= info1A
->Position
;
2834 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2839 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2840 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2842 JobW
= (LPBYTE
)info2W
;
2843 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2844 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2845 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2846 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2847 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2848 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2849 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2850 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2851 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2852 info2W
->Status
= info2A
->Status
;
2853 info2W
->Priority
= info2A
->Priority
;
2854 info2W
->Position
= info2A
->Position
;
2855 info2W
->StartTime
= info2A
->StartTime
;
2856 info2W
->UntilTime
= info2A
->UntilTime
;
2857 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2861 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2862 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2865 SetLastError(ERROR_INVALID_LEVEL
);
2869 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2875 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2876 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2877 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2878 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2879 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2884 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2885 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2886 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2887 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2888 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2889 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2890 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2891 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2892 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2896 HeapFree(GetProcessHeap(), 0, JobW
);
2901 /*****************************************************************************
2902 * SetJobW [WINSPOOL.@]
2904 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2905 LPBYTE pJob
, DWORD Command
)
2910 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2911 FIXME("Ignoring everything other than document title\n");
2913 EnterCriticalSection(&printer_handles_cs
);
2914 job
= get_job(hPrinter
, JobId
);
2924 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2925 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2926 job
->document_title
= strdupW(info1
->pDocument
);
2931 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2932 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2933 job
->document_title
= strdupW(info2
->pDocument
);
2934 HeapFree(GetProcessHeap(), 0, job
->devmode
);
2935 job
->devmode
= dup_devmode( info2
->pDevMode
);
2941 SetLastError(ERROR_INVALID_LEVEL
);
2946 LeaveCriticalSection(&printer_handles_cs
);
2950 /*****************************************************************************
2951 * EndDocPrinter [WINSPOOL.@]
2953 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2955 opened_printer_t
*printer
;
2957 TRACE("(%p)\n", hPrinter
);
2959 EnterCriticalSection(&printer_handles_cs
);
2961 printer
= get_opened_printer(hPrinter
);
2964 SetLastError(ERROR_INVALID_HANDLE
);
2970 SetLastError(ERROR_SPL_NO_STARTDOC
);
2974 CloseHandle(printer
->doc
->hf
);
2975 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2976 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2977 printer
->doc
= NULL
;
2980 LeaveCriticalSection(&printer_handles_cs
);
2984 /*****************************************************************************
2985 * EndPagePrinter [WINSPOOL.@]
2987 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2989 FIXME("(%p): stub\n", hPrinter
);
2993 /*****************************************************************************
2994 * StartDocPrinterA [WINSPOOL.@]
2996 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2998 UNICODE_STRING usBuffer
;
3000 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3003 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3004 or one (DOC_INFO_3) extra DWORDs */
3008 doc2W
.JobId
= doc2
->JobId
;
3011 doc2W
.dwMode
= doc2
->dwMode
;
3014 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3015 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3016 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3020 SetLastError(ERROR_INVALID_LEVEL
);
3024 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3026 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3027 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3028 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3033 /*****************************************************************************
3034 * StartDocPrinterW [WINSPOOL.@]
3036 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3038 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3039 opened_printer_t
*printer
;
3040 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3041 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3042 JOB_INFO_1W job_info
;
3043 DWORD needed
, ret
= 0;
3048 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3049 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3050 debugstr_w(doc
->pDatatype
));
3052 if(Level
< 1 || Level
> 3)
3054 SetLastError(ERROR_INVALID_LEVEL
);
3058 EnterCriticalSection(&printer_handles_cs
);
3059 printer
= get_opened_printer(hPrinter
);
3062 SetLastError(ERROR_INVALID_HANDLE
);
3068 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3072 /* Even if we're printing to a file we still add a print job, we'll
3073 just ignore the spool file name */
3075 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3077 ERR("AddJob failed gle %u\n", GetLastError());
3081 /* use pOutputFile only, when it is a real filename */
3082 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3083 filename
= doc
->pOutputFile
;
3085 filename
= addjob
->Path
;
3087 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3088 if(hf
== INVALID_HANDLE_VALUE
)
3091 memset(&job_info
, 0, sizeof(job_info
));
3092 job_info
.pDocument
= doc
->pDocName
;
3093 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3095 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3096 printer
->doc
->hf
= hf
;
3097 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3098 job
= get_job(hPrinter
, ret
);
3099 job
->portname
= strdupW(doc
->pOutputFile
);
3102 LeaveCriticalSection(&printer_handles_cs
);
3107 /*****************************************************************************
3108 * StartPagePrinter [WINSPOOL.@]
3110 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3112 FIXME("(%p): stub\n", hPrinter
);
3116 /*****************************************************************************
3117 * GetFormA [WINSPOOL.@]
3119 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3120 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3122 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3123 Level
,pForm
,cbBuf
,pcbNeeded
);
3127 /*****************************************************************************
3128 * GetFormW [WINSPOOL.@]
3130 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3131 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3133 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3134 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3138 /*****************************************************************************
3139 * SetFormA [WINSPOOL.@]
3141 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3144 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3148 /*****************************************************************************
3149 * SetFormW [WINSPOOL.@]
3151 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3154 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3158 /*****************************************************************************
3159 * ReadPrinter [WINSPOOL.@]
3161 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3162 LPDWORD pNoBytesRead
)
3164 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3168 /*****************************************************************************
3169 * ResetPrinterA [WINSPOOL.@]
3171 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3173 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3177 /*****************************************************************************
3178 * ResetPrinterW [WINSPOOL.@]
3180 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3182 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3186 /*****************************************************************************
3187 * WINSPOOL_GetDWORDFromReg
3189 * Return DWORD associated with ValueName from hkey.
3191 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3193 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3196 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3198 if(ret
!= ERROR_SUCCESS
) {
3199 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3202 if(type
!= REG_DWORD
) {
3203 ERR("Got type %d\n", type
);
3210 /*****************************************************************************
3211 * get_filename_from_reg [internal]
3213 * Get ValueName from hkey storing result in out
3214 * when the Value in the registry has only a filename, use driverdir as prefix
3215 * outlen is space left in out
3216 * String is stored either as unicode or ascii
3220 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3221 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3223 WCHAR filename
[MAX_PATH
];
3227 LPWSTR buffer
= filename
;
3231 size
= sizeof(filename
);
3233 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3234 if (ret
== ERROR_MORE_DATA
) {
3235 TRACE("need dynamic buffer: %u\n", size
);
3236 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3238 /* No Memory is bad */
3242 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3245 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3246 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3252 /* do we have a full path ? */
3253 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3254 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3257 /* we must build the full Path */
3259 if ((out
) && (outlen
> dirlen
)) {
3260 lstrcpyW((LPWSTR
)out
, driverdir
);
3268 /* write the filename */
3269 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3270 if ((out
) && (outlen
>= size
)) {
3271 lstrcpyW((LPWSTR
)out
, ptr
);
3278 ptr
+= lstrlenW(ptr
)+1;
3279 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3282 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3284 /* write the multisz-termination */
3285 if (type
== REG_MULTI_SZ
) {
3286 size
= sizeof(WCHAR
);
3289 if (out
&& (outlen
>= size
)) {
3290 memset (out
, 0, size
);
3296 /*****************************************************************************
3297 * WINSPOOL_GetStringFromReg
3299 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3300 * String is stored as unicode.
3302 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3303 DWORD buflen
, DWORD
*needed
)
3305 DWORD sz
= buflen
, type
;
3308 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3309 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3310 WARN("Got ret = %d\n", ret
);
3314 /* add space for terminating '\0' */
3315 sz
+= sizeof(WCHAR
);
3319 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3324 /*****************************************************************************
3325 * WINSPOOL_GetDefaultDevMode
3327 * Get a default DevMode values for wineps.
3331 static void WINSPOOL_GetDefaultDevMode(
3333 DWORD buflen
, DWORD
*needed
)
3336 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3338 /* fill default DEVMODE - should be read from ppd... */
3339 ZeroMemory( &dm
, sizeof(dm
) );
3340 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3341 dm
.dmSpecVersion
= DM_SPECVERSION
;
3342 dm
.dmDriverVersion
= 1;
3343 dm
.dmSize
= sizeof(DEVMODEW
);
3344 dm
.dmDriverExtra
= 0;
3346 DM_ORIENTATION
| DM_PAPERSIZE
|
3347 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3350 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3351 DM_YRESOLUTION
| DM_TTOPTION
;
3353 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3354 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3355 dm
.u1
.s1
.dmPaperLength
= 2970;
3356 dm
.u1
.s1
.dmPaperWidth
= 2100;
3358 dm
.u1
.s1
.dmScale
= 100;
3359 dm
.u1
.s1
.dmCopies
= 1;
3360 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3361 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3364 dm
.dmYResolution
= 300; /* 300dpi */
3365 dm
.dmTTOption
= DMTT_BITMAP
;
3368 /* dm.dmLogPixels */
3369 /* dm.dmBitsPerPel */
3370 /* dm.dmPelsWidth */
3371 /* dm.dmPelsHeight */
3372 /* dm.u2.dmDisplayFlags */
3373 /* dm.dmDisplayFrequency */
3374 /* dm.dmICMMethod */
3375 /* dm.dmICMIntent */
3376 /* dm.dmMediaType */
3377 /* dm.dmDitherType */
3378 /* dm.dmReserved1 */
3379 /* dm.dmReserved2 */
3380 /* dm.dmPanningWidth */
3381 /* dm.dmPanningHeight */
3383 if(buflen
>= sizeof(DEVMODEW
))
3384 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3385 *needed
= sizeof(DEVMODEW
);
3388 /*****************************************************************************
3389 * WINSPOOL_GetDevModeFromReg
3391 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3392 * DevMode is stored either as unicode or ascii.
3394 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3396 DWORD buflen
, DWORD
*needed
)
3398 DWORD sz
= buflen
, type
;
3401 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3402 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3403 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3404 if (sz
< sizeof(DEVMODEA
))
3406 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3409 /* ensures that dmSize is not erratically bogus if registry is invalid */
3410 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3411 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3412 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3413 if (ptr
&& (buflen
>= sz
)) {
3414 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3415 memcpy(ptr
, dmW
, sz
);
3416 HeapFree(GetProcessHeap(),0,dmW
);
3422 /*********************************************************************
3423 * WINSPOOL_GetPrinter_1
3425 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3427 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3428 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3430 DWORD size
, left
= cbBuf
;
3431 BOOL space
= (cbBuf
> 0);
3436 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3437 if(space
&& size
<= left
) {
3438 pi1
->pName
= (LPWSTR
)ptr
;
3446 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3447 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3448 if(space
&& size
<= left
) {
3449 pi1
->pDescription
= (LPWSTR
)ptr
;
3457 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3458 if(space
&& size
<= left
) {
3459 pi1
->pComment
= (LPWSTR
)ptr
;
3467 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3469 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3470 memset(pi1
, 0, sizeof(*pi1
));
3474 /*********************************************************************
3475 * WINSPOOL_GetPrinter_2
3477 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3479 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3480 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3482 DWORD size
, left
= cbBuf
;
3483 BOOL space
= (cbBuf
> 0);
3488 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3489 if(space
&& size
<= left
) {
3490 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3497 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3498 if(space
&& size
<= left
) {
3499 pi2
->pShareName
= (LPWSTR
)ptr
;
3506 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3507 if(space
&& size
<= left
) {
3508 pi2
->pPortName
= (LPWSTR
)ptr
;
3515 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3516 if(space
&& size
<= left
) {
3517 pi2
->pDriverName
= (LPWSTR
)ptr
;
3524 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3525 if(space
&& size
<= left
) {
3526 pi2
->pComment
= (LPWSTR
)ptr
;
3533 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3534 if(space
&& size
<= left
) {
3535 pi2
->pLocation
= (LPWSTR
)ptr
;
3542 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3543 if(space
&& size
<= left
) {
3544 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3553 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3554 if(space
&& size
<= left
) {
3555 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3562 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3563 if(space
&& size
<= left
) {
3564 pi2
->pSepFile
= (LPWSTR
)ptr
;
3571 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3572 if(space
&& size
<= left
) {
3573 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3580 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3581 if(space
&& size
<= left
) {
3582 pi2
->pDatatype
= (LPWSTR
)ptr
;
3589 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3590 if(space
&& size
<= left
) {
3591 pi2
->pParameters
= (LPWSTR
)ptr
;
3599 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3600 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3601 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3602 "Default Priority");
3603 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3604 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3607 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3608 memset(pi2
, 0, sizeof(*pi2
));
3613 /*********************************************************************
3614 * WINSPOOL_GetPrinter_4
3616 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3618 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3619 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3621 DWORD size
, left
= cbBuf
;
3622 BOOL space
= (cbBuf
> 0);
3627 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3628 if(space
&& size
<= left
) {
3629 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3637 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3640 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3641 memset(pi4
, 0, sizeof(*pi4
));
3646 /*********************************************************************
3647 * WINSPOOL_GetPrinter_5
3649 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3651 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3652 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3654 DWORD size
, left
= cbBuf
;
3655 BOOL space
= (cbBuf
> 0);
3660 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3661 if(space
&& size
<= left
) {
3662 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3670 if(space
&& size
<= left
) {
3671 pi5
->pPortName
= (LPWSTR
)ptr
;
3679 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3680 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3682 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3686 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3687 memset(pi5
, 0, sizeof(*pi5
));
3692 /*********************************************************************
3693 * WINSPOOL_GetPrinter_7
3695 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3697 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3698 DWORD cbBuf
, LPDWORD pcbNeeded
)
3700 DWORD size
, left
= cbBuf
;
3701 BOOL space
= (cbBuf
> 0);
3706 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3709 size
= sizeof(pi7
->pszObjectGUID
);
3711 if (space
&& size
<= left
) {
3712 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3719 /* We do not have a Directory Service */
3720 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3723 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3724 memset(pi7
, 0, sizeof(*pi7
));
3729 /*********************************************************************
3730 * WINSPOOL_GetPrinter_9
3732 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3734 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3735 DWORD cbBuf
, LPDWORD pcbNeeded
)
3738 BOOL space
= (cbBuf
> 0);
3742 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3743 if(space
&& size
<= cbBuf
) {
3744 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3751 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3752 if(space
&& size
<= cbBuf
) {
3753 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3759 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3760 memset(pi9
, 0, sizeof(*pi9
));
3765 /*****************************************************************************
3766 * GetPrinterW [WINSPOOL.@]
3768 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3769 DWORD cbBuf
, LPDWORD pcbNeeded
)
3772 DWORD size
, needed
= 0;
3774 HKEY hkeyPrinter
, hkeyPrinters
;
3777 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3779 if (!(name
= get_opened_printer_name(hPrinter
))) {
3780 SetLastError(ERROR_INVALID_HANDLE
);
3784 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3786 ERR("Can't create Printers key\n");
3789 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3791 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3792 RegCloseKey(hkeyPrinters
);
3793 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3800 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3802 size
= sizeof(PRINTER_INFO_2W
);
3804 ptr
= pPrinter
+ size
;
3806 memset(pPrinter
, 0, size
);
3811 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3818 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3820 size
= sizeof(PRINTER_INFO_4W
);
3822 ptr
= pPrinter
+ size
;
3824 memset(pPrinter
, 0, size
);
3829 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3837 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3839 size
= sizeof(PRINTER_INFO_5W
);
3841 ptr
= pPrinter
+ size
;
3843 memset(pPrinter
, 0, size
);
3849 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3857 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3859 size
= sizeof(PRINTER_INFO_6
);
3860 if (size
<= cbBuf
) {
3861 /* FIXME: We do not update the status yet */
3862 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3874 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3876 size
= sizeof(PRINTER_INFO_7W
);
3877 if (size
<= cbBuf
) {
3878 ptr
= pPrinter
+ size
;
3880 memset(pPrinter
, 0, size
);
3886 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3894 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3896 size
= sizeof(PRINTER_INFO_9W
);
3898 ptr
= pPrinter
+ size
;
3900 memset(pPrinter
, 0, size
);
3906 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3913 FIXME("Unimplemented level %d\n", Level
);
3914 SetLastError(ERROR_INVALID_LEVEL
);
3915 RegCloseKey(hkeyPrinters
);
3916 RegCloseKey(hkeyPrinter
);
3920 RegCloseKey(hkeyPrinter
);
3921 RegCloseKey(hkeyPrinters
);
3923 TRACE("returning %d needed = %d\n", ret
, needed
);
3924 if(pcbNeeded
) *pcbNeeded
= needed
;
3926 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3930 /*****************************************************************************
3931 * GetPrinterA [WINSPOOL.@]
3933 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3934 DWORD cbBuf
, LPDWORD pcbNeeded
)
3940 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3942 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3944 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3945 HeapFree(GetProcessHeap(), 0, buf
);
3950 /*****************************************************************************
3951 * WINSPOOL_EnumPrintersW
3953 * Implementation of EnumPrintersW
3955 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3956 DWORD dwLevel
, LPBYTE lpbPrinters
,
3957 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3958 LPDWORD lpdwReturned
)
3961 HKEY hkeyPrinters
, hkeyPrinter
;
3962 WCHAR PrinterName
[255];
3963 DWORD needed
= 0, number
= 0;
3964 DWORD used
, i
, left
;
3968 memset(lpbPrinters
, 0, cbBuf
);
3974 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3975 if(dwType
== PRINTER_ENUM_DEFAULT
)
3978 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3979 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3980 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3982 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3988 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3989 FIXME("dwType = %08x\n", dwType
);
3990 SetLastError(ERROR_INVALID_FLAGS
);
3994 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3996 ERR("Can't create Printers key\n");
4000 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4001 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4002 RegCloseKey(hkeyPrinters
);
4003 ERR("Can't query Printers key\n");
4006 TRACE("Found %d printers\n", number
);
4010 used
= number
* sizeof(PRINTER_INFO_1W
);
4013 used
= number
* sizeof(PRINTER_INFO_2W
);
4016 used
= number
* sizeof(PRINTER_INFO_4W
);
4019 used
= number
* sizeof(PRINTER_INFO_5W
);
4023 SetLastError(ERROR_INVALID_LEVEL
);
4024 RegCloseKey(hkeyPrinters
);
4027 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4029 for(i
= 0; i
< number
; i
++) {
4030 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4032 ERR("Can't enum key number %d\n", i
);
4033 RegCloseKey(hkeyPrinters
);
4036 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4037 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4039 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4040 RegCloseKey(hkeyPrinters
);
4045 buf
= lpbPrinters
+ used
;
4046 left
= cbBuf
- used
;
4054 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4057 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4060 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4063 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4066 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4069 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4072 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4075 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4078 ERR("Shouldn't be here!\n");
4079 RegCloseKey(hkeyPrinter
);
4080 RegCloseKey(hkeyPrinters
);
4083 RegCloseKey(hkeyPrinter
);
4085 RegCloseKey(hkeyPrinters
);
4092 memset(lpbPrinters
, 0, cbBuf
);
4093 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4097 *lpdwReturned
= number
;
4098 SetLastError(ERROR_SUCCESS
);
4103 /******************************************************************
4104 * EnumPrintersW [WINSPOOL.@]
4106 * Enumerates the available printers, print servers and print
4107 * providers, depending on the specified flags, name and level.
4111 * If level is set to 1:
4112 * Returns an array of PRINTER_INFO_1 data structures in the
4113 * lpbPrinters buffer.
4115 * If level is set to 2:
4116 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4117 * Returns an array of PRINTER_INFO_2 data structures in the
4118 * lpbPrinters buffer. Note that according to MSDN also an
4119 * OpenPrinter should be performed on every remote printer.
4121 * If level is set to 4 (officially WinNT only):
4122 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4123 * Fast: Only the registry is queried to retrieve printer names,
4124 * no connection to the driver is made.
4125 * Returns an array of PRINTER_INFO_4 data structures in the
4126 * lpbPrinters buffer.
4128 * If level is set to 5 (officially WinNT4/Win9x only):
4129 * Fast: Only the registry is queried to retrieve printer names,
4130 * no connection to the driver is made.
4131 * Returns an array of PRINTER_INFO_5 data structures in the
4132 * lpbPrinters buffer.
4134 * If level set to 3 or 6+:
4135 * returns zero (failure!)
4137 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4141 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4142 * - Only levels 2, 4 and 5 are implemented at the moment.
4143 * - 16-bit printer drivers are not enumerated.
4144 * - Returned amount of bytes used/needed does not match the real Windoze
4145 * implementation (as in this implementation, all strings are part
4146 * of the buffer, whereas Win32 keeps them somewhere else)
4147 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4150 * - In a regular Wine installation, no registry settings for printers
4151 * exist, which makes this function return an empty list.
4153 BOOL WINAPI
EnumPrintersW(
4154 DWORD dwType
, /* [in] Types of print objects to enumerate */
4155 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4156 DWORD dwLevel
, /* [in] type of printer info structure */
4157 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4158 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4159 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4160 LPDWORD lpdwReturned
/* [out] number of entries returned */
4163 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4164 lpdwNeeded
, lpdwReturned
);
4167 /******************************************************************
4168 * EnumPrintersA [WINSPOOL.@]
4173 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4174 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4177 UNICODE_STRING pNameU
;
4181 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4182 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4184 pNameW
= asciitounicode(&pNameU
, pName
);
4186 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4187 MS Office need this */
4188 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4190 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4192 RtlFreeUnicodeString(&pNameU
);
4194 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4196 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4200 /*****************************************************************************
4201 * WINSPOOL_GetDriverInfoFromReg [internal]
4203 * Enters the information from the registry into the DRIVER_INFO struct
4206 * zero if the printer driver does not exist in the registry
4207 * (only if Level > 1) otherwise nonzero
4209 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4212 const printenv_t
* env
,
4214 LPBYTE ptr
, /* DRIVER_INFO */
4215 LPBYTE pDriverStrings
, /* strings buffer */
4216 DWORD cbBuf
, /* size of string buffer */
4217 LPDWORD pcbNeeded
) /* space needed for str. */
4221 WCHAR driverdir
[MAX_PATH
];
4223 LPBYTE strPtr
= pDriverStrings
;
4224 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4226 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4227 debugstr_w(DriverName
), env
,
4228 Level
, di
, pDriverStrings
, cbBuf
);
4230 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4232 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4233 if (*pcbNeeded
<= cbBuf
)
4234 strcpyW((LPWSTR
)strPtr
, DriverName
);
4236 /* pName for level 1 has a different offset! */
4238 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4242 /* .cVersion and .pName for level > 1 */
4244 di
->cVersion
= env
->driverversion
;
4245 di
->pName
= (LPWSTR
) strPtr
;
4246 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4249 /* Reserve Space for the largest subdir and a Backslash*/
4250 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4251 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4252 /* Should never Fail */
4255 lstrcatW(driverdir
, env
->versionsubdir
);
4256 lstrcatW(driverdir
, backslashW
);
4258 /* dirlen must not include the terminating zero */
4259 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4261 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4262 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4263 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4268 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4271 if (*pcbNeeded
<= cbBuf
) {
4272 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4273 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4274 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4277 /* .pDriverPath is the Graphics rendering engine.
4278 The full Path is required to avoid a crash in some apps */
4279 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4281 if (*pcbNeeded
<= cbBuf
)
4282 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4284 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4285 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4288 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4289 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4291 if (*pcbNeeded
<= cbBuf
)
4292 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4294 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4295 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4298 /* .pConfigFile is the Driver user Interface */
4299 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4301 if (*pcbNeeded
<= cbBuf
)
4302 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4304 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4305 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4309 RegCloseKey(hkeyDriver
);
4310 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4315 RegCloseKey(hkeyDriver
);
4316 FIXME("level 5: incomplete\n");
4321 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4323 if (*pcbNeeded
<= cbBuf
)
4324 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4326 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4327 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4330 /* .pDependentFiles */
4331 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4333 if (*pcbNeeded
<= cbBuf
)
4334 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4336 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4337 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4339 else if (GetVersion() & 0x80000000) {
4340 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4341 size
= 2 * sizeof(WCHAR
);
4343 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4345 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4346 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4349 /* .pMonitorName is the optional Language Monitor */
4350 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4352 if (*pcbNeeded
<= cbBuf
)
4353 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4355 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4356 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4359 /* .pDefaultDataType */
4360 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4362 if(*pcbNeeded
<= cbBuf
)
4363 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4365 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4366 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4370 RegCloseKey(hkeyDriver
);
4371 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4375 /* .pszzPreviousNames */
4376 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4378 if(*pcbNeeded
<= cbBuf
)
4379 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4381 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4382 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4386 RegCloseKey(hkeyDriver
);
4387 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4391 /* support is missing, but not important enough for a FIXME */
4392 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4395 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4397 if(*pcbNeeded
<= cbBuf
)
4398 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4400 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4401 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4405 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4407 if(*pcbNeeded
<= cbBuf
)
4408 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4410 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4411 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4414 /* .pszHardwareID */
4415 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4417 if(*pcbNeeded
<= cbBuf
)
4418 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4420 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4421 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4425 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4427 if(*pcbNeeded
<= cbBuf
)
4428 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4430 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4431 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4435 RegCloseKey(hkeyDriver
);
4439 /* support is missing, but not important enough for a FIXME */
4440 TRACE("level 8: incomplete\n");
4442 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4443 RegCloseKey(hkeyDriver
);
4447 /*****************************************************************************
4448 * GetPrinterDriverW [WINSPOOL.@]
4450 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4451 DWORD Level
, LPBYTE pDriverInfo
,
4452 DWORD cbBuf
, LPDWORD pcbNeeded
)
4455 WCHAR DriverName
[100];
4456 DWORD ret
, type
, size
, needed
= 0;
4458 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4459 const printenv_t
* env
;
4461 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4462 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4465 ZeroMemory(pDriverInfo
, cbBuf
);
4467 if (!(name
= get_opened_printer_name(hPrinter
))) {
4468 SetLastError(ERROR_INVALID_HANDLE
);
4472 if (Level
< 1 || Level
== 7 || Level
> 8) {
4473 SetLastError(ERROR_INVALID_LEVEL
);
4477 env
= validate_envW(pEnvironment
);
4478 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4480 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4482 ERR("Can't create Printers key\n");
4485 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4487 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4488 RegCloseKey(hkeyPrinters
);
4489 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4492 size
= sizeof(DriverName
);
4494 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4495 (LPBYTE
)DriverName
, &size
);
4496 RegCloseKey(hkeyPrinter
);
4497 RegCloseKey(hkeyPrinters
);
4498 if(ret
!= ERROR_SUCCESS
) {
4499 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4503 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4505 ERR("Can't create Drivers key\n");
4509 size
= di_sizeof
[Level
];
4510 if ((size
<= cbBuf
) && pDriverInfo
)
4511 ptr
= pDriverInfo
+ size
;
4513 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4514 env
, Level
, pDriverInfo
, ptr
,
4515 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4517 RegCloseKey(hkeyDrivers
);
4521 RegCloseKey(hkeyDrivers
);
4523 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4524 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4525 if(cbBuf
>= size
+ needed
) return TRUE
;
4526 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4530 /*****************************************************************************
4531 * GetPrinterDriverA [WINSPOOL.@]
4533 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4534 DWORD Level
, LPBYTE pDriverInfo
,
4535 DWORD cbBuf
, LPDWORD pcbNeeded
)
4538 UNICODE_STRING pEnvW
;
4544 ZeroMemory(pDriverInfo
, cbBuf
);
4545 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4548 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4549 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4552 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4554 HeapFree(GetProcessHeap(), 0, buf
);
4556 RtlFreeUnicodeString(&pEnvW
);
4560 /*****************************************************************************
4561 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4563 * Return the PATH for the Printer-Drivers (UNICODE)
4566 * pName [I] Servername (NT only) or NULL (local Computer)
4567 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4568 * Level [I] Structure-Level (must be 1)
4569 * pDriverDirectory [O] PTR to Buffer that receives the Result
4570 * cbBuf [I] Size of Buffer at pDriverDirectory
4571 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4572 * required for pDriverDirectory
4575 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4576 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4577 * if cbBuf is too small
4579 * Native Values returned in pDriverDirectory on Success:
4580 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4581 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4582 *| win9x(Windows 4.0): "%winsysdir%"
4584 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4587 *- Only NULL or "" is supported for pName
4590 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4591 DWORD Level
, LPBYTE pDriverDirectory
,
4592 DWORD cbBuf
, LPDWORD pcbNeeded
)
4594 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4595 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4597 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4600 /* (Level != 1) is ignored in win9x */
4601 SetLastError(ERROR_INVALID_LEVEL
);
4604 if (pcbNeeded
== NULL
) {
4605 /* (pcbNeeded == NULL) is ignored in win9x */
4606 SetLastError(RPC_X_NULL_REF_POINTER
);
4610 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4611 pDriverDirectory
, cbBuf
, pcbNeeded
);
4616 /*****************************************************************************
4617 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4619 * Return the PATH for the Printer-Drivers (ANSI)
4621 * See GetPrinterDriverDirectoryW.
4624 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4627 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4628 DWORD Level
, LPBYTE pDriverDirectory
,
4629 DWORD cbBuf
, LPDWORD pcbNeeded
)
4631 UNICODE_STRING nameW
, environmentW
;
4634 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4635 WCHAR
*driverDirectoryW
= NULL
;
4637 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4638 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4640 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4642 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4643 else nameW
.Buffer
= NULL
;
4644 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4645 else environmentW
.Buffer
= NULL
;
4647 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4648 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4651 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4652 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4654 *pcbNeeded
= needed
;
4655 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4657 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4659 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4661 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4662 RtlFreeUnicodeString(&environmentW
);
4663 RtlFreeUnicodeString(&nameW
);
4668 /*****************************************************************************
4669 * AddPrinterDriverA [WINSPOOL.@]
4671 * See AddPrinterDriverW.
4674 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4676 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4677 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4680 /******************************************************************************
4681 * AddPrinterDriverW (WINSPOOL.@)
4683 * Install a Printer Driver
4686 * pName [I] Servername or NULL (local Computer)
4687 * level [I] Level for the supplied DRIVER_INFO_*W struct
4688 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4695 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4697 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4698 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4701 /*****************************************************************************
4702 * AddPrintProcessorA [WINSPOOL.@]
4704 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4705 LPSTR pPrintProcessorName
)
4707 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4708 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4712 /*****************************************************************************
4713 * AddPrintProcessorW [WINSPOOL.@]
4715 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4716 LPWSTR pPrintProcessorName
)
4718 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4719 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4723 /*****************************************************************************
4724 * AddPrintProvidorA [WINSPOOL.@]
4726 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4728 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4732 /*****************************************************************************
4733 * AddPrintProvidorW [WINSPOOL.@]
4735 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4737 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4741 /*****************************************************************************
4742 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4744 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4745 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4747 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4748 pDevModeOutput
, pDevModeInput
);
4752 /*****************************************************************************
4753 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4755 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4756 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4758 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4759 pDevModeOutput
, pDevModeInput
);
4763 /*****************************************************************************
4764 * PrinterProperties [WINSPOOL.@]
4766 * Displays a dialog to set the properties of the printer.
4769 * nonzero on success or zero on failure
4772 * implemented as stub only
4774 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4775 HANDLE hPrinter
/* [in] handle to printer object */
4777 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4778 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4782 /*****************************************************************************
4783 * EnumJobsA [WINSPOOL.@]
4786 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4787 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4790 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4791 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4793 if(pcbNeeded
) *pcbNeeded
= 0;
4794 if(pcReturned
) *pcReturned
= 0;
4799 /*****************************************************************************
4800 * EnumJobsW [WINSPOOL.@]
4803 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4804 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4807 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4808 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4810 if(pcbNeeded
) *pcbNeeded
= 0;
4811 if(pcReturned
) *pcReturned
= 0;
4815 /*****************************************************************************
4816 * WINSPOOL_EnumPrinterDrivers [internal]
4818 * Delivers information about all printer drivers installed on the
4819 * localhost or a given server
4822 * nonzero on success or zero on failure. If the buffer for the returned
4823 * information is too small the function will return an error
4826 * - only implemented for localhost, foreign hosts will return an error
4828 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4829 DWORD Level
, LPBYTE pDriverInfo
,
4831 DWORD cbBuf
, LPDWORD pcbNeeded
,
4832 LPDWORD pcFound
, DWORD data_offset
)
4836 const printenv_t
* env
;
4838 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4839 debugstr_w(pName
), debugstr_w(pEnvironment
),
4840 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4842 env
= validate_envW(pEnvironment
);
4843 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4847 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4849 ERR("Can't open Drivers key\n");
4853 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4854 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4855 RegCloseKey(hkeyDrivers
);
4856 ERR("Can't query Drivers key\n");
4859 TRACE("Found %d Drivers\n", *pcFound
);
4861 /* get size of single struct
4862 * unicode and ascii structure have the same size
4864 size
= di_sizeof
[Level
];
4866 if (data_offset
== 0)
4867 data_offset
= size
* (*pcFound
);
4868 *pcbNeeded
= data_offset
;
4870 for( i
= 0; i
< *pcFound
; i
++) {
4871 WCHAR DriverNameW
[255];
4872 PBYTE table_ptr
= NULL
;
4873 PBYTE data_ptr
= NULL
;
4876 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4878 ERR("Can't enum key number %d\n", i
);
4879 RegCloseKey(hkeyDrivers
);
4883 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4884 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4885 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4886 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4888 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4889 env
, Level
, table_ptr
, data_ptr
,
4890 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4892 RegCloseKey(hkeyDrivers
);
4896 *pcbNeeded
+= needed
;
4899 RegCloseKey(hkeyDrivers
);
4901 if(cbBuf
< *pcbNeeded
){
4902 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4909 /*****************************************************************************
4910 * EnumPrinterDriversW [WINSPOOL.@]
4912 * see function EnumPrinterDrivers for RETURNS, BUGS
4914 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4915 LPBYTE pDriverInfo
, DWORD cbBuf
,
4916 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4918 static const WCHAR allW
[] = {'a','l','l',0};
4922 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4924 SetLastError(RPC_X_NULL_REF_POINTER
);
4928 /* check for local drivers */
4929 if((pName
) && (pName
[0])) {
4930 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4931 SetLastError(ERROR_ACCESS_DENIED
);
4935 /* check input parameter */
4936 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4937 SetLastError(ERROR_INVALID_LEVEL
);
4941 if(pDriverInfo
&& cbBuf
> 0)
4942 memset( pDriverInfo
, 0, cbBuf
);
4944 /* Exception: pull all printers */
4945 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4947 DWORD i
, needed
, bufsize
= cbBuf
;
4948 DWORD total_needed
= 0;
4949 DWORD total_found
= 0;
4952 /* Precompute the overall total; we need this to know
4953 where pointers end and data begins (i.e. data_offset) */
4954 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4957 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4958 NULL
, 0, 0, &needed
, &found
, 0);
4959 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4960 total_needed
+= needed
;
4961 total_found
+= found
;
4964 data_offset
= di_sizeof
[Level
] * total_found
;
4969 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4972 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4973 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4974 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4976 *pcReturned
+= found
;
4977 *pcbNeeded
= needed
;
4978 data_offset
= needed
;
4979 total_found
+= found
;
4984 /* Normal behavior */
4985 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4986 0, cbBuf
, pcbNeeded
, &found
, 0);
4988 *pcReturned
= found
;
4993 /*****************************************************************************
4994 * EnumPrinterDriversA [WINSPOOL.@]
4996 * see function EnumPrinterDrivers for RETURNS, BUGS
4998 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4999 LPBYTE pDriverInfo
, DWORD cbBuf
,
5000 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5003 UNICODE_STRING pNameW
, pEnvironmentW
;
5004 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5008 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5010 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5011 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5013 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5014 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5016 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5018 HeapFree(GetProcessHeap(), 0, buf
);
5020 RtlFreeUnicodeString(&pNameW
);
5021 RtlFreeUnicodeString(&pEnvironmentW
);
5026 /******************************************************************************
5027 * EnumPortsA (WINSPOOL.@)
5032 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5033 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5036 LPBYTE bufferW
= NULL
;
5037 LPWSTR nameW
= NULL
;
5039 DWORD numentries
= 0;
5042 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5043 cbBuf
, pcbNeeded
, pcReturned
);
5045 /* convert servername to unicode */
5047 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5048 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5049 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5051 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5052 needed
= cbBuf
* sizeof(WCHAR
);
5053 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5054 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5056 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5057 if (pcbNeeded
) needed
= *pcbNeeded
;
5058 /* HeapReAlloc return NULL, when bufferW was NULL */
5059 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5060 HeapAlloc(GetProcessHeap(), 0, needed
);
5062 /* Try again with the large Buffer */
5063 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5065 needed
= pcbNeeded
? *pcbNeeded
: 0;
5066 numentries
= pcReturned
? *pcReturned
: 0;
5069 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5070 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5073 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5074 DWORD entrysize
= 0;
5077 LPPORT_INFO_2W pi2w
;
5078 LPPORT_INFO_2A pi2a
;
5081 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5083 /* First pass: calculate the size for all Entries */
5084 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5085 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5087 while (index
< numentries
) {
5089 needed
+= entrysize
; /* PORT_INFO_?A */
5090 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5092 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5093 NULL
, 0, NULL
, NULL
);
5095 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5096 NULL
, 0, NULL
, NULL
);
5097 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5098 NULL
, 0, NULL
, NULL
);
5100 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5101 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5102 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5105 /* check for errors and quit on failure */
5106 if (cbBuf
< needed
) {
5107 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5111 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5112 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5113 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5114 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5115 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5117 /* Second Pass: Fill the User Buffer (if we have one) */
5118 while ((index
< numentries
) && pPorts
) {
5120 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5121 pi2a
->pPortName
= ptr
;
5122 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5123 ptr
, cbBuf
, NULL
, NULL
);
5127 pi2a
->pMonitorName
= ptr
;
5128 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5129 ptr
, cbBuf
, NULL
, NULL
);
5133 pi2a
->pDescription
= ptr
;
5134 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5135 ptr
, cbBuf
, NULL
, NULL
);
5139 pi2a
->fPortType
= pi2w
->fPortType
;
5140 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5143 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5144 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5145 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5150 if (pcbNeeded
) *pcbNeeded
= needed
;
5151 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5153 HeapFree(GetProcessHeap(), 0, nameW
);
5154 HeapFree(GetProcessHeap(), 0, bufferW
);
5156 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5157 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5163 /******************************************************************************
5164 * EnumPortsW (WINSPOOL.@)
5166 * Enumerate available Ports
5169 * pName [I] Servername or NULL (local Computer)
5170 * Level [I] Structure-Level (1 or 2)
5171 * pPorts [O] PTR to Buffer that receives the Result
5172 * cbBuf [I] Size of Buffer at pPorts
5173 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5174 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5178 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5181 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5184 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5185 cbBuf
, pcbNeeded
, pcReturned
);
5187 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5189 /* Level is not checked in win9x */
5190 if (!Level
|| (Level
> 2)) {
5191 WARN("level (%d) is ignored in win9x\n", Level
);
5192 SetLastError(ERROR_INVALID_LEVEL
);
5195 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5196 SetLastError(RPC_X_NULL_REF_POINTER
);
5200 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5203 /******************************************************************************
5204 * GetDefaultPrinterW (WINSPOOL.@)
5207 * This function must read the value from data 'device' of key
5208 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5210 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5214 WCHAR
*buffer
, *ptr
;
5218 SetLastError(ERROR_INVALID_PARAMETER
);
5222 /* make the buffer big enough for the stuff from the profile/registry,
5223 * the content must fit into the local buffer to compute the correct
5224 * size even if the extern buffer is too small or not given.
5225 * (20 for ,driver,port) */
5227 len
= max(100, (insize
+ 20));
5228 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5230 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5232 SetLastError (ERROR_FILE_NOT_FOUND
);
5236 TRACE("%s\n", debugstr_w(buffer
));
5238 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5240 SetLastError(ERROR_INVALID_NAME
);
5246 *namesize
= strlenW(buffer
) + 1;
5247 if(!name
|| (*namesize
> insize
))
5249 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5253 strcpyW(name
, buffer
);
5256 HeapFree( GetProcessHeap(), 0, buffer
);
5261 /******************************************************************************
5262 * GetDefaultPrinterA (WINSPOOL.@)
5264 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5268 WCHAR
*bufferW
= NULL
;
5272 SetLastError(ERROR_INVALID_PARAMETER
);
5276 if(name
&& *namesize
) {
5278 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5281 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5286 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5290 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5293 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5296 HeapFree( GetProcessHeap(), 0, bufferW
);
5301 /******************************************************************************
5302 * SetDefaultPrinterW (WINSPOOL.204)
5304 * Set the Name of the Default Printer
5307 * pszPrinter [I] Name of the Printer or NULL
5314 * When the Parameter is NULL or points to an Empty String and
5315 * a Default Printer was already present, then this Function changes nothing.
5316 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5317 * the First enumerated local Printer is used.
5320 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5322 WCHAR default_printer
[MAX_PATH
];
5323 LPWSTR buffer
= NULL
;
5329 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5330 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5332 default_printer
[0] = '\0';
5333 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5335 /* if we have a default Printer, do nothing. */
5336 if (GetDefaultPrinterW(default_printer
, &size
))
5340 /* we have no default Printer: search local Printers and use the first */
5341 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5343 default_printer
[0] = '\0';
5344 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5345 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5347 pszPrinter
= default_printer
;
5348 TRACE("using %s\n", debugstr_w(pszPrinter
));
5353 if (pszPrinter
== NULL
) {
5354 TRACE("no local printer found\n");
5355 SetLastError(ERROR_FILE_NOT_FOUND
);
5360 /* "pszPrinter" is never empty or NULL here. */
5361 namelen
= lstrlenW(pszPrinter
);
5362 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5363 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5365 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5366 HeapFree(GetProcessHeap(), 0, buffer
);
5367 SetLastError(ERROR_FILE_NOT_FOUND
);
5371 /* read the devices entry for the printer (driver,port) to build the string for the
5372 default device entry (printer,driver,port) */
5373 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5374 buffer
[namelen
] = ',';
5375 namelen
++; /* move index to the start of the driver */
5377 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5378 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5380 TRACE("set device to %s\n", debugstr_w(buffer
));
5382 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5383 TRACE("failed to set the device entry: %d\n", GetLastError());
5384 lres
= ERROR_INVALID_PRINTER_NAME
;
5387 /* remove the next section, when INIFileMapping is implemented */
5390 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5391 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5398 if (lres
!= ERROR_FILE_NOT_FOUND
)
5399 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5401 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5405 HeapFree(GetProcessHeap(), 0, buffer
);
5406 return (lres
== ERROR_SUCCESS
);
5409 /******************************************************************************
5410 * SetDefaultPrinterA (WINSPOOL.202)
5412 * See SetDefaultPrinterW.
5415 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5417 LPWSTR bufferW
= NULL
;
5420 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5422 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5423 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5424 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5426 res
= SetDefaultPrinterW(bufferW
);
5427 HeapFree(GetProcessHeap(), 0, bufferW
);
5431 /******************************************************************************
5432 * SetPrinterDataExA (WINSPOOL.@)
5434 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5435 LPCSTR pValueName
, DWORD Type
,
5436 LPBYTE pData
, DWORD cbData
)
5438 HKEY hkeyPrinter
, hkeySubkey
;
5441 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5442 debugstr_a(pValueName
), Type
, pData
, cbData
);
5444 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5448 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5450 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5451 RegCloseKey(hkeyPrinter
);
5454 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5455 RegCloseKey(hkeySubkey
);
5456 RegCloseKey(hkeyPrinter
);
5460 /******************************************************************************
5461 * SetPrinterDataExW (WINSPOOL.@)
5463 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5464 LPCWSTR pValueName
, DWORD Type
,
5465 LPBYTE pData
, DWORD cbData
)
5467 HKEY hkeyPrinter
, hkeySubkey
;
5470 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5471 debugstr_w(pValueName
), Type
, pData
, cbData
);
5473 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5477 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5479 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5480 RegCloseKey(hkeyPrinter
);
5483 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5484 RegCloseKey(hkeySubkey
);
5485 RegCloseKey(hkeyPrinter
);
5489 /******************************************************************************
5490 * SetPrinterDataA (WINSPOOL.@)
5492 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5493 LPBYTE pData
, DWORD cbData
)
5495 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5499 /******************************************************************************
5500 * SetPrinterDataW (WINSPOOL.@)
5502 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5503 LPBYTE pData
, DWORD cbData
)
5505 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5509 /******************************************************************************
5510 * GetPrinterDataExA (WINSPOOL.@)
5512 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5513 LPCSTR pValueName
, LPDWORD pType
,
5514 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5516 opened_printer_t
*printer
;
5517 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5520 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5521 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5523 printer
= get_opened_printer(hPrinter
);
5524 if(!printer
) return ERROR_INVALID_HANDLE
;
5526 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5527 if (ret
) return ret
;
5529 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5531 if (printer
->name
) {
5533 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5535 RegCloseKey(hkeyPrinters
);
5538 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5539 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5540 RegCloseKey(hkeyPrinter
);
5541 RegCloseKey(hkeyPrinters
);
5546 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5547 0, pType
, pData
, pcbNeeded
);
5549 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5551 RegCloseKey(hkeySubkey
);
5552 RegCloseKey(hkeyPrinter
);
5553 RegCloseKey(hkeyPrinters
);
5555 TRACE("--> %d\n", ret
);
5559 /******************************************************************************
5560 * GetPrinterDataExW (WINSPOOL.@)
5562 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5563 LPCWSTR pValueName
, LPDWORD pType
,
5564 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5566 opened_printer_t
*printer
;
5567 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5570 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5571 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5573 printer
= get_opened_printer(hPrinter
);
5574 if(!printer
) return ERROR_INVALID_HANDLE
;
5576 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5577 if (ret
) return ret
;
5579 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5581 if (printer
->name
) {
5583 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5585 RegCloseKey(hkeyPrinters
);
5588 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5589 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5590 RegCloseKey(hkeyPrinter
);
5591 RegCloseKey(hkeyPrinters
);
5596 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5597 0, pType
, pData
, pcbNeeded
);
5599 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5601 RegCloseKey(hkeySubkey
);
5602 RegCloseKey(hkeyPrinter
);
5603 RegCloseKey(hkeyPrinters
);
5605 TRACE("--> %d\n", ret
);
5609 /******************************************************************************
5610 * GetPrinterDataA (WINSPOOL.@)
5612 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5613 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5615 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5616 pData
, nSize
, pcbNeeded
);
5619 /******************************************************************************
5620 * GetPrinterDataW (WINSPOOL.@)
5622 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5623 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5625 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5626 pData
, nSize
, pcbNeeded
);
5629 /*******************************************************************************
5630 * EnumPrinterDataExW [WINSPOOL.@]
5632 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5633 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5634 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5636 HKEY hkPrinter
, hkSubKey
;
5637 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5638 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5643 PPRINTER_ENUM_VALUESW ppev
;
5645 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5647 if (pKeyName
== NULL
|| *pKeyName
== 0)
5648 return ERROR_INVALID_PARAMETER
;
5650 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5651 if (ret
!= ERROR_SUCCESS
)
5653 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5658 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5659 if (ret
!= ERROR_SUCCESS
)
5661 r
= RegCloseKey (hkPrinter
);
5662 if (r
!= ERROR_SUCCESS
)
5663 WARN ("RegCloseKey returned %i\n", r
);
5664 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5665 debugstr_w (pKeyName
), ret
);
5669 ret
= RegCloseKey (hkPrinter
);
5670 if (ret
!= ERROR_SUCCESS
)
5672 ERR ("RegCloseKey returned %i\n", ret
);
5673 r
= RegCloseKey (hkSubKey
);
5674 if (r
!= ERROR_SUCCESS
)
5675 WARN ("RegCloseKey returned %i\n", r
);
5679 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5680 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5681 if (ret
!= ERROR_SUCCESS
)
5683 r
= RegCloseKey (hkSubKey
);
5684 if (r
!= ERROR_SUCCESS
)
5685 WARN ("RegCloseKey returned %i\n", r
);
5686 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5690 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5691 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5693 if (cValues
== 0) /* empty key */
5695 r
= RegCloseKey (hkSubKey
);
5696 if (r
!= ERROR_SUCCESS
)
5697 WARN ("RegCloseKey returned %i\n", r
);
5698 *pcbEnumValues
= *pnEnumValues
= 0;
5699 return ERROR_SUCCESS
;
5702 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5704 hHeap
= GetProcessHeap ();
5707 ERR ("GetProcessHeap failed\n");
5708 r
= RegCloseKey (hkSubKey
);
5709 if (r
!= ERROR_SUCCESS
)
5710 WARN ("RegCloseKey returned %i\n", r
);
5711 return ERROR_OUTOFMEMORY
;
5714 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5715 if (lpValueName
== NULL
)
5717 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5718 r
= RegCloseKey (hkSubKey
);
5719 if (r
!= ERROR_SUCCESS
)
5720 WARN ("RegCloseKey returned %i\n", r
);
5721 return ERROR_OUTOFMEMORY
;
5724 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5725 if (lpValue
== NULL
)
5727 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5728 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5729 WARN ("HeapFree failed with code %i\n", GetLastError ());
5730 r
= RegCloseKey (hkSubKey
);
5731 if (r
!= ERROR_SUCCESS
)
5732 WARN ("RegCloseKey returned %i\n", r
);
5733 return ERROR_OUTOFMEMORY
;
5736 TRACE ("pass 1: calculating buffer required for all names and values\n");
5738 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5740 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5742 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5744 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5745 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5746 NULL
, NULL
, lpValue
, &cbValueLen
);
5747 if (ret
!= ERROR_SUCCESS
)
5749 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5750 WARN ("HeapFree failed with code %i\n", GetLastError ());
5751 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5752 WARN ("HeapFree failed with code %i\n", GetLastError ());
5753 r
= RegCloseKey (hkSubKey
);
5754 if (r
!= ERROR_SUCCESS
)
5755 WARN ("RegCloseKey returned %i\n", r
);
5756 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5760 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5761 debugstr_w (lpValueName
), dwIndex
,
5762 cbValueNameLen
+ 1, cbValueLen
);
5764 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5765 cbBufSize
+= cbValueLen
;
5768 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5770 *pcbEnumValues
= cbBufSize
;
5771 *pnEnumValues
= cValues
;
5773 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5775 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5776 WARN ("HeapFree failed with code %i\n", GetLastError ());
5777 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5778 WARN ("HeapFree failed with code %i\n", GetLastError ());
5779 r
= RegCloseKey (hkSubKey
);
5780 if (r
!= ERROR_SUCCESS
)
5781 WARN ("RegCloseKey returned %i\n", r
);
5782 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5783 return ERROR_MORE_DATA
;
5786 TRACE ("pass 2: copying all names and values to buffer\n");
5788 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5789 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5791 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5793 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5794 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5795 NULL
, &dwType
, lpValue
, &cbValueLen
);
5796 if (ret
!= ERROR_SUCCESS
)
5798 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5799 WARN ("HeapFree failed with code %i\n", GetLastError ());
5800 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5801 WARN ("HeapFree failed with code %i\n", GetLastError ());
5802 r
= RegCloseKey (hkSubKey
);
5803 if (r
!= ERROR_SUCCESS
)
5804 WARN ("RegCloseKey returned %i\n", r
);
5805 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5809 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5810 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5811 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5812 pEnumValues
+= cbValueNameLen
;
5814 /* return # of *bytes* (including trailing \0), not # of chars */
5815 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5817 ppev
[dwIndex
].dwType
= dwType
;
5819 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5820 ppev
[dwIndex
].pData
= pEnumValues
;
5821 pEnumValues
+= cbValueLen
;
5823 ppev
[dwIndex
].cbData
= cbValueLen
;
5825 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5826 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5829 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5831 ret
= GetLastError ();
5832 ERR ("HeapFree failed with code %i\n", ret
);
5833 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5834 WARN ("HeapFree failed with code %i\n", GetLastError ());
5835 r
= RegCloseKey (hkSubKey
);
5836 if (r
!= ERROR_SUCCESS
)
5837 WARN ("RegCloseKey returned %i\n", r
);
5841 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5843 ret
= GetLastError ();
5844 ERR ("HeapFree failed with code %i\n", ret
);
5845 r
= RegCloseKey (hkSubKey
);
5846 if (r
!= ERROR_SUCCESS
)
5847 WARN ("RegCloseKey returned %i\n", r
);
5851 ret
= RegCloseKey (hkSubKey
);
5852 if (ret
!= ERROR_SUCCESS
)
5854 ERR ("RegCloseKey returned %i\n", ret
);
5858 return ERROR_SUCCESS
;
5861 /*******************************************************************************
5862 * EnumPrinterDataExA [WINSPOOL.@]
5864 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5865 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5866 * what Windows 2000 SP1 does.
5869 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5870 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5871 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5875 DWORD ret
, dwIndex
, dwBufSize
;
5879 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5881 if (pKeyName
== NULL
|| *pKeyName
== 0)
5882 return ERROR_INVALID_PARAMETER
;
5884 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5887 ret
= GetLastError ();
5888 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5892 hHeap
= GetProcessHeap ();
5895 ERR ("GetProcessHeap failed\n");
5896 return ERROR_OUTOFMEMORY
;
5899 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5900 if (pKeyNameW
== NULL
)
5902 ERR ("Failed to allocate %i bytes from process heap\n",
5903 (LONG
)(len
* sizeof (WCHAR
)));
5904 return ERROR_OUTOFMEMORY
;
5907 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5909 ret
= GetLastError ();
5910 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5911 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5912 WARN ("HeapFree failed with code %i\n", GetLastError ());
5916 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5917 pcbEnumValues
, pnEnumValues
);
5918 if (ret
!= ERROR_SUCCESS
)
5920 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5921 WARN ("HeapFree failed with code %i\n", GetLastError ());
5922 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5926 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5928 ret
= GetLastError ();
5929 ERR ("HeapFree failed with code %i\n", ret
);
5933 if (*pnEnumValues
== 0) /* empty key */
5934 return ERROR_SUCCESS
;
5937 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5939 PPRINTER_ENUM_VALUESW ppev
=
5940 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5942 if (dwBufSize
< ppev
->cbValueName
)
5943 dwBufSize
= ppev
->cbValueName
;
5945 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5946 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5947 dwBufSize
= ppev
->cbData
;
5950 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5952 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5953 if (pBuffer
== NULL
)
5955 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5956 return ERROR_OUTOFMEMORY
;
5959 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5961 PPRINTER_ENUM_VALUESW ppev
=
5962 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5964 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5965 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5969 ret
= GetLastError ();
5970 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5971 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5972 WARN ("HeapFree failed with code %i\n", GetLastError ());
5976 memcpy (ppev
->pValueName
, pBuffer
, len
);
5978 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5980 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5981 ppev
->dwType
!= REG_MULTI_SZ
)
5984 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5985 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5988 ret
= GetLastError ();
5989 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5990 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5991 WARN ("HeapFree failed with code %i\n", GetLastError ());
5995 memcpy (ppev
->pData
, pBuffer
, len
);
5997 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5998 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6001 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6003 ret
= GetLastError ();
6004 ERR ("HeapFree failed with code %i\n", ret
);
6008 return ERROR_SUCCESS
;
6011 /******************************************************************************
6012 * AbortPrinter (WINSPOOL.@)
6014 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6016 FIXME("(%p), stub!\n", hPrinter
);
6020 /******************************************************************************
6021 * AddPortA (WINSPOOL.@)
6026 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6028 LPWSTR nameW
= NULL
;
6029 LPWSTR monitorW
= NULL
;
6033 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6036 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6037 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6038 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6042 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6043 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6044 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6046 res
= AddPortW(nameW
, hWnd
, monitorW
);
6047 HeapFree(GetProcessHeap(), 0, nameW
);
6048 HeapFree(GetProcessHeap(), 0, monitorW
);
6052 /******************************************************************************
6053 * AddPortW (WINSPOOL.@)
6055 * Add a Port for a specific Monitor
6058 * pName [I] Servername or NULL (local Computer)
6059 * hWnd [I] Handle to parent Window for the Dialog-Box
6060 * pMonitorName [I] Name of the Monitor that manage the Port
6067 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6069 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6071 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6073 if (!pMonitorName
) {
6074 SetLastError(RPC_X_NULL_REF_POINTER
);
6078 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6081 /******************************************************************************
6082 * AddPortExA (WINSPOOL.@)
6087 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6090 PORT_INFO_2A
* pi2A
;
6091 LPWSTR nameW
= NULL
;
6092 LPWSTR monitorW
= NULL
;
6096 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6098 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6099 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6101 if ((level
< 1) || (level
> 2)) {
6102 SetLastError(ERROR_INVALID_LEVEL
);
6107 SetLastError(ERROR_INVALID_PARAMETER
);
6112 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6113 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6114 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6118 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6119 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6120 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6123 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6125 if (pi2A
->pPortName
) {
6126 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6127 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6128 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6132 if (pi2A
->pMonitorName
) {
6133 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6134 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6135 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6138 if (pi2A
->pDescription
) {
6139 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6140 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6141 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6143 pi2W
.fPortType
= pi2A
->fPortType
;
6144 pi2W
.Reserved
= pi2A
->Reserved
;
6147 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6149 HeapFree(GetProcessHeap(), 0, nameW
);
6150 HeapFree(GetProcessHeap(), 0, monitorW
);
6151 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6152 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6153 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6158 /******************************************************************************
6159 * AddPortExW (WINSPOOL.@)
6161 * Add a Port for a specific Monitor, without presenting a user interface
6164 * pName [I] Servername or NULL (local Computer)
6165 * level [I] Structure-Level (1 or 2) for pBuffer
6166 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6167 * pMonitorName [I] Name of the Monitor that manage the Port
6174 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6178 pi2
= (PORT_INFO_2W
*) pBuffer
;
6180 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6181 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6182 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6183 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6185 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6187 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6188 SetLastError(ERROR_INVALID_PARAMETER
);
6192 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6195 /******************************************************************************
6196 * AddPrinterConnectionA (WINSPOOL.@)
6198 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6200 FIXME("%s\n", debugstr_a(pName
));
6204 /******************************************************************************
6205 * AddPrinterConnectionW (WINSPOOL.@)
6207 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6209 FIXME("%s\n", debugstr_w(pName
));
6213 /******************************************************************************
6214 * AddPrinterDriverExW (WINSPOOL.@)
6216 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6219 * pName [I] Servername or NULL (local Computer)
6220 * level [I] Level for the supplied DRIVER_INFO_*W struct
6221 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6222 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6229 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6231 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6233 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6235 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6236 SetLastError(ERROR_INVALID_LEVEL
);
6241 SetLastError(ERROR_INVALID_PARAMETER
);
6245 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6248 /******************************************************************************
6249 * AddPrinterDriverExA (WINSPOOL.@)
6251 * See AddPrinterDriverExW.
6254 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6256 DRIVER_INFO_8A
*diA
;
6258 LPWSTR nameW
= NULL
;
6263 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6265 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6266 ZeroMemory(&diW
, sizeof(diW
));
6268 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6269 SetLastError(ERROR_INVALID_LEVEL
);
6274 SetLastError(ERROR_INVALID_PARAMETER
);
6278 /* convert servername to unicode */
6280 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6281 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6282 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6286 diW
.cVersion
= diA
->cVersion
;
6289 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6290 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6291 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6294 if (diA
->pEnvironment
) {
6295 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6296 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6297 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6300 if (diA
->pDriverPath
) {
6301 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6302 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6303 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6306 if (diA
->pDataFile
) {
6307 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6308 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6309 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6312 if (diA
->pConfigFile
) {
6313 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6314 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6315 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6318 if ((Level
> 2) && diA
->pDependentFiles
) {
6319 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6320 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6321 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6322 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6325 if ((Level
> 2) && diA
->pMonitorName
) {
6326 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6327 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6328 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6331 if ((Level
> 3) && diA
->pDefaultDataType
) {
6332 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6333 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6334 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6337 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6338 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6339 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6340 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6341 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6344 if ((Level
> 5) && diA
->pszMfgName
) {
6345 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6346 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6347 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6350 if ((Level
> 5) && diA
->pszOEMUrl
) {
6351 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6352 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6353 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6356 if ((Level
> 5) && diA
->pszHardwareID
) {
6357 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6358 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6359 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6362 if ((Level
> 5) && diA
->pszProvider
) {
6363 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6364 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6365 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6369 FIXME("level %u is incomplete\n", Level
);
6372 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6373 TRACE("got %u with %u\n", res
, GetLastError());
6374 HeapFree(GetProcessHeap(), 0, nameW
);
6375 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6376 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6377 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6378 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6379 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6380 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6381 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6382 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6383 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6384 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6385 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6386 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6387 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6389 TRACE("=> %u with %u\n", res
, GetLastError());
6393 /******************************************************************************
6394 * ConfigurePortA (WINSPOOL.@)
6396 * See ConfigurePortW.
6399 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6401 LPWSTR nameW
= NULL
;
6402 LPWSTR portW
= NULL
;
6406 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6408 /* convert servername to unicode */
6410 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6411 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6412 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6415 /* convert portname to unicode */
6417 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6418 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6419 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6422 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6423 HeapFree(GetProcessHeap(), 0, nameW
);
6424 HeapFree(GetProcessHeap(), 0, portW
);
6428 /******************************************************************************
6429 * ConfigurePortW (WINSPOOL.@)
6431 * Display the Configuration-Dialog for a specific Port
6434 * pName [I] Servername or NULL (local Computer)
6435 * hWnd [I] Handle to parent Window for the Dialog-Box
6436 * pPortName [I] Name of the Port, that should be configured
6443 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6446 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6448 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6451 SetLastError(RPC_X_NULL_REF_POINTER
);
6455 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6458 /******************************************************************************
6459 * ConnectToPrinterDlg (WINSPOOL.@)
6461 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6463 FIXME("%p %x\n", hWnd
, Flags
);
6467 /******************************************************************************
6468 * DeletePrinterConnectionA (WINSPOOL.@)
6470 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6472 FIXME("%s\n", debugstr_a(pName
));
6476 /******************************************************************************
6477 * DeletePrinterConnectionW (WINSPOOL.@)
6479 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6481 FIXME("%s\n", debugstr_w(pName
));
6485 /******************************************************************************
6486 * DeletePrinterDriverExW (WINSPOOL.@)
6488 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6489 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6494 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6495 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6497 if(pName
&& pName
[0])
6499 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6500 SetLastError(ERROR_INVALID_PARAMETER
);
6506 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6507 SetLastError(ERROR_INVALID_PARAMETER
);
6511 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6515 ERR("Can't open drivers key\n");
6519 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6522 RegCloseKey(hkey_drivers
);
6527 /******************************************************************************
6528 * DeletePrinterDriverExA (WINSPOOL.@)
6530 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6531 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6533 UNICODE_STRING NameW
, EnvW
, DriverW
;
6536 asciitounicode(&NameW
, pName
);
6537 asciitounicode(&EnvW
, pEnvironment
);
6538 asciitounicode(&DriverW
, pDriverName
);
6540 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6542 RtlFreeUnicodeString(&DriverW
);
6543 RtlFreeUnicodeString(&EnvW
);
6544 RtlFreeUnicodeString(&NameW
);
6549 /******************************************************************************
6550 * DeletePrinterDataExW (WINSPOOL.@)
6552 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6555 FIXME("%p %s %s\n", hPrinter
,
6556 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6557 return ERROR_INVALID_PARAMETER
;
6560 /******************************************************************************
6561 * DeletePrinterDataExA (WINSPOOL.@)
6563 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6566 FIXME("%p %s %s\n", hPrinter
,
6567 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6568 return ERROR_INVALID_PARAMETER
;
6571 /******************************************************************************
6572 * DeletePrintProcessorA (WINSPOOL.@)
6574 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6576 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6577 debugstr_a(pPrintProcessorName
));
6581 /******************************************************************************
6582 * DeletePrintProcessorW (WINSPOOL.@)
6584 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6586 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6587 debugstr_w(pPrintProcessorName
));
6591 /******************************************************************************
6592 * DeletePrintProvidorA (WINSPOOL.@)
6594 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6596 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6597 debugstr_a(pPrintProviderName
));
6601 /******************************************************************************
6602 * DeletePrintProvidorW (WINSPOOL.@)
6604 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6606 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6607 debugstr_w(pPrintProviderName
));
6611 /******************************************************************************
6612 * EnumFormsA (WINSPOOL.@)
6614 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6615 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6617 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6622 /******************************************************************************
6623 * EnumFormsW (WINSPOOL.@)
6625 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6626 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6628 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6629 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6633 /*****************************************************************************
6634 * EnumMonitorsA [WINSPOOL.@]
6636 * See EnumMonitorsW.
6639 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6640 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6643 LPBYTE bufferW
= NULL
;
6644 LPWSTR nameW
= NULL
;
6646 DWORD numentries
= 0;
6649 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6650 cbBuf
, pcbNeeded
, pcReturned
);
6652 /* convert servername to unicode */
6654 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6655 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6656 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6658 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6659 needed
= cbBuf
* sizeof(WCHAR
);
6660 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6661 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6663 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6664 if (pcbNeeded
) needed
= *pcbNeeded
;
6665 /* HeapReAlloc return NULL, when bufferW was NULL */
6666 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6667 HeapAlloc(GetProcessHeap(), 0, needed
);
6669 /* Try again with the large Buffer */
6670 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6672 numentries
= pcReturned
? *pcReturned
: 0;
6675 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6676 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6679 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6680 DWORD entrysize
= 0;
6683 LPMONITOR_INFO_2W mi2w
;
6684 LPMONITOR_INFO_2A mi2a
;
6686 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6687 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6689 /* First pass: calculate the size for all Entries */
6690 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6691 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6693 while (index
< numentries
) {
6695 needed
+= entrysize
; /* MONITOR_INFO_?A */
6696 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6698 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6699 NULL
, 0, NULL
, NULL
);
6701 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6702 NULL
, 0, NULL
, NULL
);
6703 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6704 NULL
, 0, NULL
, NULL
);
6706 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6707 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6708 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6711 /* check for errors and quit on failure */
6712 if (cbBuf
< needed
) {
6713 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6717 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6718 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6719 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6720 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6721 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6723 /* Second Pass: Fill the User Buffer (if we have one) */
6724 while ((index
< numentries
) && pMonitors
) {
6726 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6728 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6729 ptr
, cbBuf
, NULL
, NULL
);
6733 mi2a
->pEnvironment
= ptr
;
6734 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6735 ptr
, cbBuf
, NULL
, NULL
);
6739 mi2a
->pDLLName
= ptr
;
6740 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6741 ptr
, cbBuf
, NULL
, NULL
);
6745 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6746 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6747 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6751 if (pcbNeeded
) *pcbNeeded
= needed
;
6752 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6754 HeapFree(GetProcessHeap(), 0, nameW
);
6755 HeapFree(GetProcessHeap(), 0, bufferW
);
6757 TRACE("returning %d with %d (%d byte for %d entries)\n",
6758 (res
), GetLastError(), needed
, numentries
);
6764 /*****************************************************************************
6765 * EnumMonitorsW [WINSPOOL.@]
6767 * Enumerate available Port-Monitors
6770 * pName [I] Servername or NULL (local Computer)
6771 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6772 * pMonitors [O] PTR to Buffer that receives the Result
6773 * cbBuf [I] Size of Buffer at pMonitors
6774 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6775 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6779 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6782 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6783 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6786 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6787 cbBuf
, pcbNeeded
, pcReturned
);
6789 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6791 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6792 SetLastError(RPC_X_NULL_REF_POINTER
);
6796 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6799 /******************************************************************************
6800 * SpoolerInit (WINSPOOL.@)
6802 * Initialize the Spooler
6809 * The function fails on windows, when the spooler service is not running
6812 BOOL WINAPI
SpoolerInit(void)
6815 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6819 /******************************************************************************
6820 * XcvDataW (WINSPOOL.@)
6822 * Execute commands in the Printmonitor DLL
6825 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6826 * pszDataName [i] Name of the command to execute
6827 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6828 * cbInputData [i] Size in Bytes of Buffer at pInputData
6829 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6830 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6831 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6832 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6839 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6840 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6842 * Minimal List of commands, that a Printmonitor DLL should support:
6844 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6845 *| "AddPort" : Add a Port
6846 *| "DeletePort": Delete a Port
6848 * Many Printmonitors support additional commands. Examples for localspl.dll:
6849 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6850 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6853 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6854 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6855 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6857 opened_printer_t
*printer
;
6859 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6860 pInputData
, cbInputData
, pOutputData
,
6861 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6863 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6865 printer
= get_opened_printer(hXcv
);
6866 if (!printer
|| (!printer
->backend_printer
)) {
6867 SetLastError(ERROR_INVALID_HANDLE
);
6871 if (!pcbOutputNeeded
) {
6872 SetLastError(ERROR_INVALID_PARAMETER
);
6876 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6877 SetLastError(RPC_X_NULL_REF_POINTER
);
6881 *pcbOutputNeeded
= 0;
6883 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6884 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6888 /*****************************************************************************
6889 * EnumPrinterDataA [WINSPOOL.@]
6892 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6893 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6894 DWORD cbData
, LPDWORD pcbData
)
6896 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6897 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6898 return ERROR_NO_MORE_ITEMS
;
6901 /*****************************************************************************
6902 * EnumPrinterDataW [WINSPOOL.@]
6905 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6906 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6907 DWORD cbData
, LPDWORD pcbData
)
6909 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6910 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6911 return ERROR_NO_MORE_ITEMS
;
6914 /*****************************************************************************
6915 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6918 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6919 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6920 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6922 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6923 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6924 pcbNeeded
, pcReturned
);
6928 /*****************************************************************************
6929 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6932 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6933 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6934 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6936 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6937 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6938 pcbNeeded
, pcReturned
);
6942 /*****************************************************************************
6943 * EnumPrintProcessorsA [WINSPOOL.@]
6945 * See EnumPrintProcessorsW.
6948 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6949 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6952 LPBYTE bufferW
= NULL
;
6953 LPWSTR nameW
= NULL
;
6956 DWORD numentries
= 0;
6959 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6960 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6962 /* convert names to unicode */
6964 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6965 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6966 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6969 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6970 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6971 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6974 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6975 needed
= cbBuf
* sizeof(WCHAR
);
6976 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6977 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6979 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6980 if (pcbNeeded
) needed
= *pcbNeeded
;
6981 /* HeapReAlloc return NULL, when bufferW was NULL */
6982 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6983 HeapAlloc(GetProcessHeap(), 0, needed
);
6985 /* Try again with the large Buffer */
6986 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6988 numentries
= pcReturned
? *pcReturned
: 0;
6992 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6995 PPRINTPROCESSOR_INFO_1W ppiw
;
6996 PPRINTPROCESSOR_INFO_1A ppia
;
6998 /* First pass: calculate the size for all Entries */
6999 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7000 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7002 while (index
< numentries
) {
7004 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7005 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7007 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7008 NULL
, 0, NULL
, NULL
);
7010 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7011 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7014 /* check for errors and quit on failure */
7015 if (cbBuf
< needed
) {
7016 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7021 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7022 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7023 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7024 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7025 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7027 /* Second Pass: Fill the User Buffer (if we have one) */
7028 while ((index
< numentries
) && pPPInfo
) {
7030 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7032 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7033 ptr
, cbBuf
, NULL
, NULL
);
7037 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7038 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7043 if (pcbNeeded
) *pcbNeeded
= needed
;
7044 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7046 HeapFree(GetProcessHeap(), 0, nameW
);
7047 HeapFree(GetProcessHeap(), 0, envW
);
7048 HeapFree(GetProcessHeap(), 0, bufferW
);
7050 TRACE("returning %d with %d (%d byte for %d entries)\n",
7051 (res
), GetLastError(), needed
, numentries
);
7056 /*****************************************************************************
7057 * EnumPrintProcessorsW [WINSPOOL.@]
7059 * Enumerate available Print Processors
7062 * pName [I] Servername or NULL (local Computer)
7063 * pEnvironment [I] Printing-Environment or NULL (Default)
7064 * Level [I] Structure-Level (Only 1 is allowed)
7065 * pPPInfo [O] PTR to Buffer that receives the Result
7066 * cbBuf [I] Size of Buffer at pPPInfo
7067 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7068 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7072 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7075 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7076 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7079 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7080 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7082 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7084 if (!pcbNeeded
|| !pcReturned
) {
7085 SetLastError(RPC_X_NULL_REF_POINTER
);
7089 if (!pPPInfo
&& (cbBuf
> 0)) {
7090 SetLastError(ERROR_INVALID_USER_BUFFER
);
7094 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7095 cbBuf
, pcbNeeded
, pcReturned
);
7098 /*****************************************************************************
7099 * ExtDeviceMode [WINSPOOL.@]
7102 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7103 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7106 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7107 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7108 debugstr_a(pProfile
), fMode
);
7112 /*****************************************************************************
7113 * FindClosePrinterChangeNotification [WINSPOOL.@]
7116 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7118 FIXME("Stub: %p\n", hChange
);
7122 /*****************************************************************************
7123 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7126 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7127 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7129 FIXME("Stub: %p %x %x %p\n",
7130 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7131 return INVALID_HANDLE_VALUE
;
7134 /*****************************************************************************
7135 * FindNextPrinterChangeNotification [WINSPOOL.@]
7138 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7139 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7141 FIXME("Stub: %p %p %p %p\n",
7142 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7146 /*****************************************************************************
7147 * FreePrinterNotifyInfo [WINSPOOL.@]
7150 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7152 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7156 /*****************************************************************************
7159 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7160 * ansi depending on the unicode parameter.
7162 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7172 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7175 memcpy(ptr
, str
, *size
);
7182 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7185 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7192 /*****************************************************************************
7195 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7196 LPDWORD pcbNeeded
, BOOL unicode
)
7198 DWORD size
, left
= cbBuf
;
7199 BOOL space
= (cbBuf
> 0);
7206 ji1
->JobId
= job
->job_id
;
7209 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7210 if(space
&& size
<= left
)
7212 ji1
->pDocument
= (LPWSTR
)ptr
;
7220 if (job
->printer_name
)
7222 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7223 if(space
&& size
<= left
)
7225 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7237 /*****************************************************************************
7240 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7241 LPDWORD pcbNeeded
, BOOL unicode
)
7243 DWORD size
, left
= cbBuf
;
7245 BOOL space
= (cbBuf
> 0);
7247 LPDEVMODEA dmA
= NULL
;
7254 ji2
->JobId
= job
->job_id
;
7257 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7258 if(space
&& size
<= left
)
7260 ji2
->pDocument
= (LPWSTR
)ptr
;
7268 if (job
->printer_name
)
7270 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7271 if(space
&& size
<= left
)
7273 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7286 dmA
= DEVMODEdupWtoA(job
->devmode
);
7287 devmode
= (LPDEVMODEW
) dmA
;
7288 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7292 devmode
= job
->devmode
;
7293 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7297 FIXME("Can't convert DEVMODE W to A\n");
7300 /* align DEVMODE to a DWORD boundary */
7301 shift
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
7307 memcpy(ptr
, devmode
, size
-shift
);
7308 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7309 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7322 /*****************************************************************************
7325 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7326 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7329 DWORD needed
= 0, size
;
7333 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7335 EnterCriticalSection(&printer_handles_cs
);
7336 job
= get_job(hPrinter
, JobId
);
7343 size
= sizeof(JOB_INFO_1W
);
7348 memset(pJob
, 0, size
);
7352 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7357 size
= sizeof(JOB_INFO_2W
);
7362 memset(pJob
, 0, size
);
7366 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7371 size
= sizeof(JOB_INFO_3
);
7375 memset(pJob
, 0, size
);
7384 SetLastError(ERROR_INVALID_LEVEL
);
7388 *pcbNeeded
= needed
;
7390 LeaveCriticalSection(&printer_handles_cs
);
7394 /*****************************************************************************
7395 * GetJobA [WINSPOOL.@]
7398 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7399 DWORD cbBuf
, LPDWORD pcbNeeded
)
7401 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7404 /*****************************************************************************
7405 * GetJobW [WINSPOOL.@]
7408 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7409 DWORD cbBuf
, LPDWORD pcbNeeded
)
7411 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7414 /*****************************************************************************
7417 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7420 char *unixname
, *cmdA
;
7422 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7428 if(!(unixname
= wine_get_unix_file_name(filename
)))
7431 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7432 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7433 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7435 TRACE("printing with: %s\n", cmdA
);
7437 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7442 ERR("pipe() failed!\n");
7446 if ((pid
= fork()) == 0)
7452 /* reset signals that we previously set to SIG_IGN */
7453 signal(SIGPIPE
, SIG_DFL
);
7455 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7460 ERR("fork() failed!\n");
7464 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7465 write(fds
[1], buf
, no_read
);
7472 wret
= waitpid(pid
, &status
, 0);
7473 } while (wret
< 0 && errno
== EINTR
);
7476 ERR("waitpid() failed!\n");
7479 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7481 ERR("child process failed! %d\n", status
);
7488 if(file_fd
!= -1) close(file_fd
);
7489 if(fds
[0] != -1) close(fds
[0]);
7490 if(fds
[1] != -1) close(fds
[1]);
7492 HeapFree(GetProcessHeap(), 0, cmdA
);
7493 HeapFree(GetProcessHeap(), 0, unixname
);
7500 /*****************************************************************************
7503 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7506 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7509 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7510 sprintfW(cmd
, fmtW
, printer_name
);
7512 r
= schedule_pipe(cmd
, filename
);
7514 HeapFree(GetProcessHeap(), 0, cmd
);
7518 /*****************************************************************************
7521 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7523 #ifdef SONAME_LIBCUPS
7526 char *unixname
, *queue
, *unix_doc_title
;
7530 if(!(unixname
= wine_get_unix_file_name(filename
)))
7533 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7534 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7535 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7537 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7538 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7539 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7541 TRACE("printing via cups\n");
7542 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7543 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7544 HeapFree(GetProcessHeap(), 0, queue
);
7545 HeapFree(GetProcessHeap(), 0, unixname
);
7551 return schedule_lpr(printer_name
, filename
);
7555 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7562 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7566 if(HIWORD(wparam
) == BN_CLICKED
)
7568 if(LOWORD(wparam
) == IDOK
)
7571 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7574 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7575 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7577 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7579 WCHAR caption
[200], message
[200];
7582 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7583 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7584 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7585 if(mb_ret
== IDCANCEL
)
7587 HeapFree(GetProcessHeap(), 0, filename
);
7591 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7592 if(hf
== INVALID_HANDLE_VALUE
)
7594 WCHAR caption
[200], message
[200];
7596 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7597 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7598 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7599 HeapFree(GetProcessHeap(), 0, filename
);
7603 DeleteFileW(filename
);
7604 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7606 EndDialog(hwnd
, IDOK
);
7609 if(LOWORD(wparam
) == IDCANCEL
)
7611 EndDialog(hwnd
, IDCANCEL
);
7620 /*****************************************************************************
7623 static BOOL
get_filename(LPWSTR
*filename
)
7625 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7626 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7629 /*****************************************************************************
7632 static BOOL
schedule_file(LPCWSTR filename
)
7634 LPWSTR output
= NULL
;
7636 if(get_filename(&output
))
7639 TRACE("copy to %s\n", debugstr_w(output
));
7640 r
= CopyFileW(filename
, output
, FALSE
);
7641 HeapFree(GetProcessHeap(), 0, output
);
7647 /*****************************************************************************
7650 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7652 int in_fd
, out_fd
, no_read
;
7655 char *unixname
, *outputA
;
7658 if(!(unixname
= wine_get_unix_file_name(filename
)))
7661 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7662 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7663 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7665 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7666 in_fd
= open(unixname
, O_RDONLY
);
7667 if(out_fd
== -1 || in_fd
== -1)
7670 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7671 write(out_fd
, buf
, no_read
);
7675 if(in_fd
!= -1) close(in_fd
);
7676 if(out_fd
!= -1) close(out_fd
);
7677 HeapFree(GetProcessHeap(), 0, outputA
);
7678 HeapFree(GetProcessHeap(), 0, unixname
);
7682 /*****************************************************************************
7683 * ScheduleJob [WINSPOOL.@]
7686 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7688 opened_printer_t
*printer
;
7690 struct list
*cursor
, *cursor2
;
7692 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7693 EnterCriticalSection(&printer_handles_cs
);
7694 printer
= get_opened_printer(hPrinter
);
7698 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7700 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7703 if(job
->job_id
!= dwJobID
) continue;
7705 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7706 if(hf
!= INVALID_HANDLE_VALUE
)
7708 PRINTER_INFO_5W
*pi5
= NULL
;
7709 LPWSTR portname
= job
->portname
;
7713 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7714 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7718 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7719 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7720 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7721 portname
= pi5
->pPortName
;
7723 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7724 debugstr_w(portname
));
7728 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7729 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7731 DWORD type
, count
= sizeof(output
);
7732 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7735 if(output
[0] == '|')
7737 ret
= schedule_pipe(output
+ 1, job
->filename
);
7741 ret
= schedule_unixfile(output
, job
->filename
);
7743 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7745 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7747 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7749 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7751 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7753 ret
= schedule_file(job
->filename
);
7757 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7759 HeapFree(GetProcessHeap(), 0, pi5
);
7761 DeleteFileW(job
->filename
);
7763 list_remove(cursor
);
7764 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7765 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7766 HeapFree(GetProcessHeap(), 0, job
->portname
);
7767 HeapFree(GetProcessHeap(), 0, job
->filename
);
7768 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7769 HeapFree(GetProcessHeap(), 0, job
);
7773 LeaveCriticalSection(&printer_handles_cs
);
7777 /*****************************************************************************
7778 * StartDocDlgA [WINSPOOL.@]
7780 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7782 UNICODE_STRING usBuffer
;
7785 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7788 docW
.cbSize
= sizeof(docW
);
7789 if (doc
->lpszDocName
)
7791 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7792 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7794 if (doc
->lpszOutput
)
7796 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7797 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7799 if (doc
->lpszDatatype
)
7801 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7802 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7804 docW
.fwType
= doc
->fwType
;
7806 retW
= StartDocDlgW(hPrinter
, &docW
);
7810 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7811 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7812 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7813 HeapFree(GetProcessHeap(), 0, retW
);
7816 HeapFree(GetProcessHeap(), 0, datatypeW
);
7817 HeapFree(GetProcessHeap(), 0, outputW
);
7818 HeapFree(GetProcessHeap(), 0, docnameW
);
7823 /*****************************************************************************
7824 * StartDocDlgW [WINSPOOL.@]
7826 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7827 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7828 * port is "FILE:". Also returns the full path if passed a relative path.
7830 * The caller should free the returned string from the process heap.
7832 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7837 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7839 PRINTER_INFO_5W
*pi5
;
7840 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7841 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7843 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7844 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7845 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7847 HeapFree(GetProcessHeap(), 0, pi5
);
7850 HeapFree(GetProcessHeap(), 0, pi5
);
7853 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7857 if (get_filename(&name
))
7859 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7861 HeapFree(GetProcessHeap(), 0, name
);
7864 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7865 GetFullPathNameW(name
, len
, ret
, NULL
);
7866 HeapFree(GetProcessHeap(), 0, name
);
7871 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7874 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7875 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7877 attr
= GetFileAttributesW(ret
);
7878 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7880 HeapFree(GetProcessHeap(), 0, ret
);