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"
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
61 #include "ddk/winsplp.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs
;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
71 0, 0, &printer_handles_cs
,
72 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
73 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 /* ############################### */
92 HANDLE backend_printer
;
102 WCHAR
*document_title
;
112 LPCWSTR versionregpath
;
113 LPCWSTR versionsubdir
;
116 /* ############################### */
118 static opened_printer_t
**printer_handles
;
119 static UINT nb_printer_handles
;
120 static LONG next_job_id
= 1;
122 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
123 WORD fwCapability
, LPSTR lpszOutput
,
125 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
126 LPSTR lpszDevice
, LPSTR lpszPort
,
127 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
130 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
170 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
181 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW
[] = {'\\',0};
183 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW
[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW
[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
211 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
215 static WCHAR generic_ppdW
[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
216 static WCHAR rawW
[] = {'R','A','W',0};
217 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
218 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
219 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
220 static const WCHAR commaW
[] = {',',0};
221 static WCHAR emptyStringW
[] = {0};
223 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
225 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
226 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
227 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
229 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
230 'D','o','c','u','m','e','n','t',0};
232 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
233 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
234 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
235 0, sizeof(DRIVER_INFO_8W
)};
238 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
239 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
240 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
241 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
242 sizeof(PRINTER_INFO_9W
)};
244 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
245 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
246 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
248 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
250 /******************************************************************
251 * validate the user-supplied printing-environment [internal]
254 * env [I] PTR to Environment-String or NULL
258 * Success: PTR to printenv_t
261 * An empty string is handled the same way as NULL.
262 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
266 static const printenv_t
* validate_envW(LPCWSTR env
)
268 const printenv_t
*result
= NULL
;
271 TRACE("testing %s\n", debugstr_w(env
));
274 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
276 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
278 result
= all_printenv
[i
];
283 if (result
== NULL
) {
284 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
285 SetLastError(ERROR_INVALID_ENVIRONMENT
);
287 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
291 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
293 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
299 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
300 if passed a NULL string. This returns NULLs to the result.
302 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
306 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
307 return usBufferPtr
->Buffer
;
309 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
313 static LPWSTR
strdupW(LPCWSTR p
)
319 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
320 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
325 static LPSTR
strdupWtoA( LPCWSTR str
)
330 if (!str
) return NULL
;
331 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
332 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
333 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
337 /******************************************************************
338 * verify, that the filename is a local file
341 static inline BOOL
is_local_file(LPWSTR name
)
343 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
346 /* ################################ */
348 static int multi_sz_lenA(const char *str
)
350 const char *ptr
= str
;
354 ptr
+= lstrlenA(ptr
) + 1;
357 return ptr
- str
+ 1;
361 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
369 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
371 !strstr(qbuf
,"WINEPS.DRV")
373 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
376 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
377 WriteProfileStringA("windows","device",buf
);
378 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
379 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
382 HeapFree(GetProcessHeap(),0,buf
);
386 static BOOL
add_printer_driver(WCHAR
*name
)
390 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
393 di3
.pEnvironment
= envname_x86W
;
394 di3
.pDriverPath
= driver_nt
;
395 di3
.pDataFile
= generic_ppdW
;
396 di3
.pConfigFile
= driver_nt
;
397 di3
.pDefaultDataType
= rawW
;
399 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
400 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
403 di3
.pEnvironment
= envname_win40W
;
404 di3
.pDriverPath
= driver_9x
;
405 di3
.pConfigFile
= driver_9x
;
406 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
407 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
412 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
416 #ifdef SONAME_LIBCUPS
417 static typeof(cupsFreeDests
) *pcupsFreeDests
;
418 static typeof(cupsGetDests
) *pcupsGetDests
;
419 static typeof(cupsGetPPD
) *pcupsGetPPD
;
420 static typeof(cupsPrintFile
) *pcupsPrintFile
;
421 static void *cupshandle
;
423 static BOOL
CUPS_LoadPrinters(void)
426 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
430 HKEY hkeyPrinter
, hkeyPrinters
;
432 WCHAR nameW
[MAX_PATH
];
434 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
436 TRACE("%s\n", loaderror
);
439 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
442 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
443 if (!p##x) return FALSE;
445 DYNCUPS(cupsFreeDests
);
447 DYNCUPS(cupsGetDests
);
448 DYNCUPS(cupsPrintFile
);
451 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
453 ERR("Can't create Printers key\n");
457 nrofdests
= pcupsGetDests(&dests
);
458 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
459 for (i
=0;i
<nrofdests
;i
++) {
460 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
462 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
463 lstrcpyW(port
, CUPS_Port
);
464 lstrcatW(port
, nameW
);
466 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
467 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
470 TRACE("Printer already exists\n");
471 /* overwrite old LPR:* port */
472 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
473 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
474 RegCloseKey(hkeyPrinter
);
476 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
477 ' ','u','s','i','n','g',' ','C','U','P','S',0};
479 add_printer_driver(nameW
);
481 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
482 pi2
.pPrinterName
= nameW
;
483 pi2
.pDatatype
= rawW
;
484 pi2
.pPrintProcessor
= WinPrintW
;
485 pi2
.pDriverName
= nameW
;
486 pi2
.pComment
= comment_cups
;
487 pi2
.pLocation
= emptyStringW
;
488 pi2
.pPortName
= port
;
489 pi2
.pParameters
= emptyStringW
;
490 pi2
.pShareName
= emptyStringW
;
491 pi2
.pSepFile
= emptyStringW
;
493 if (!AddPrinterW(NULL
, 2, (LPBYTE
)&pi2
)) {
494 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
495 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError());
498 HeapFree(GetProcessHeap(),0,port
);
501 if (dests
[i
].is_default
) {
502 SetDefaultPrinterW(nameW
);
506 if (hadprinter
&& !haddefault
) {
507 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
508 SetDefaultPrinterW(nameW
);
510 pcupsFreeDests(nrofdests
, dests
);
511 RegCloseKey(hkeyPrinters
);
517 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
518 PRINTER_INFO_2A pinfo2a
;
519 char *e
,*s
,*name
,*prettyname
,*devname
;
520 BOOL ret
= FALSE
, set_default
= FALSE
;
521 char *port
= NULL
, *env_default
;
522 HKEY hkeyPrinter
, hkeyPrinters
;
523 WCHAR devnameW
[MAX_PATH
];
525 while (isspace(*pent
)) pent
++;
526 s
= strchr(pent
,':');
528 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
536 TRACE("name=%s entry=%s\n",name
, pent
);
538 if(ispunct(*name
)) { /* a tc entry, not a real printer */
539 TRACE("skipping tc entry\n");
543 if(strstr(pent
,":server")) { /* server only version so skip */
544 TRACE("skipping server entry\n");
548 /* Determine whether this is a postscript printer. */
551 env_default
= getenv("PRINTER");
553 /* Get longest name, usually the one at the right for later display. */
554 while((s
=strchr(prettyname
,'|'))) {
557 while(isspace(*--e
)) *e
= '\0';
558 TRACE("\t%s\n", debugstr_a(prettyname
));
559 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
560 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
563 e
= prettyname
+ strlen(prettyname
);
564 while(isspace(*--e
)) *e
= '\0';
565 TRACE("\t%s\n", debugstr_a(prettyname
));
566 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
568 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
569 * if it is too long, we use it as comment below. */
570 devname
= prettyname
;
571 if (strlen(devname
)>=CCHDEVICENAME
-1)
573 if (strlen(devname
)>=CCHDEVICENAME
-1) {
578 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
579 sprintf(port
,"LPR:%s",name
);
581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
583 ERR("Can't create Printers key\n");
588 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
590 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
591 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
593 TRACE("Printer already exists\n");
594 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
595 RegCloseKey(hkeyPrinter
);
597 static CHAR data_type
[] = "RAW",
598 print_proc
[] = "WinPrint",
599 comment
[] = "WINEPS Printer using LPR",
600 params
[] = "<parameters?>",
601 share_name
[] = "<share name?>",
602 sep_file
[] = "<sep file?>";
604 add_printer_driver(devnameW
);
606 memset(&pinfo2a
,0,sizeof(pinfo2a
));
607 pinfo2a
.pPrinterName
= devname
;
608 pinfo2a
.pDatatype
= data_type
;
609 pinfo2a
.pPrintProcessor
= print_proc
;
610 pinfo2a
.pDriverName
= devname
;
611 pinfo2a
.pComment
= comment
;
612 pinfo2a
.pLocation
= prettyname
;
613 pinfo2a
.pPortName
= port
;
614 pinfo2a
.pParameters
= params
;
615 pinfo2a
.pShareName
= share_name
;
616 pinfo2a
.pSepFile
= sep_file
;
618 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
619 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
620 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
623 RegCloseKey(hkeyPrinters
);
625 if (isfirst
|| set_default
)
626 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
629 HeapFree(GetProcessHeap(), 0, port
);
630 HeapFree(GetProcessHeap(), 0, name
);
635 PRINTCAP_LoadPrinters(void) {
636 BOOL hadprinter
= FALSE
;
640 BOOL had_bash
= FALSE
;
642 f
= fopen("/etc/printcap","r");
646 while(fgets(buf
,sizeof(buf
),f
)) {
649 end
=strchr(buf
,'\n');
653 while(isspace(*start
)) start
++;
654 if(*start
== '#' || *start
== '\0')
657 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
658 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
659 HeapFree(GetProcessHeap(),0,pent
);
663 if (end
&& *--end
== '\\') {
670 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
673 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
679 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
680 HeapFree(GetProcessHeap(),0,pent
);
686 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
689 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
690 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
692 return ERROR_FILE_NOT_FOUND
;
695 /******************************************************************
696 * get_servername_from_name (internal)
698 * for an external server, a copy of the serverpart from the full name is returned
701 static LPWSTR
get_servername_from_name(LPCWSTR name
)
705 WCHAR buffer
[MAX_PATH
];
708 if (name
== NULL
) return NULL
;
709 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
711 server
= strdupW(&name
[2]); /* skip over both backslash */
712 if (server
== NULL
) return NULL
;
714 /* strip '\' and the printername */
715 ptr
= strchrW(server
, '\\');
716 if (ptr
) ptr
[0] = '\0';
718 TRACE("found %s\n", debugstr_w(server
));
720 len
= sizeof(buffer
)/sizeof(buffer
[0]);
721 if (GetComputerNameW(buffer
, &len
)) {
722 if (lstrcmpW(buffer
, server
) == 0) {
723 /* The requested Servername is our computername */
724 HeapFree(GetProcessHeap(), 0, server
);
731 /******************************************************************
732 * get_basename_from_name (internal)
734 * skip over the serverpart from the full name
737 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
739 if (name
== NULL
) return NULL
;
740 if ((name
[0] == '\\') && (name
[1] == '\\')) {
741 /* skip over the servername and search for the following '\' */
742 name
= strchrW(&name
[2], '\\');
743 if ((name
) && (name
[1])) {
744 /* found a separator ('\') followed by a name:
745 skip over the separator and return the rest */
750 /* no basename present (we found only a servername) */
757 /******************************************************************
758 * get_opened_printer_entry
759 * Get the first place empty in the opened printer table
762 * - pDefault is ignored
764 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
766 UINT_PTR handle
= nb_printer_handles
, i
;
767 jobqueue_t
*queue
= NULL
;
768 opened_printer_t
*printer
= NULL
;
772 if ((backend
== NULL
) && !load_backend()) return NULL
;
774 servername
= get_servername_from_name(name
);
776 FIXME("server %s not supported\n", debugstr_w(servername
));
777 HeapFree(GetProcessHeap(), 0, servername
);
778 SetLastError(ERROR_INVALID_PRINTER_NAME
);
782 printername
= get_basename_from_name(name
);
783 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
785 /* an empty printername is invalid */
786 if (printername
&& (!printername
[0])) {
787 SetLastError(ERROR_INVALID_PARAMETER
);
791 EnterCriticalSection(&printer_handles_cs
);
793 for (i
= 0; i
< nb_printer_handles
; i
++)
795 if (!printer_handles
[i
])
797 if(handle
== nb_printer_handles
)
802 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
803 queue
= printer_handles
[i
]->queue
;
807 if (handle
>= nb_printer_handles
)
809 opened_printer_t
**new_array
;
811 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
812 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
814 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
815 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
822 printer_handles
= new_array
;
823 nb_printer_handles
+= 16;
826 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
832 /* get a printer handle from the backend */
833 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
838 /* clone the base name. This is NULL for the printserver */
839 printer
->printername
= strdupW(printername
);
841 /* clone the full name */
842 printer
->name
= strdupW(name
);
843 if (name
&& (!printer
->name
)) {
849 printer
->queue
= queue
;
852 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
853 if (!printer
->queue
) {
857 list_init(&printer
->queue
->jobs
);
858 printer
->queue
->ref
= 0;
860 InterlockedIncrement(&printer
->queue
->ref
);
862 printer_handles
[handle
] = printer
;
865 LeaveCriticalSection(&printer_handles_cs
);
866 if (!handle
&& printer
) {
867 /* Something failed: Free all resources */
868 HeapFree(GetProcessHeap(), 0, printer
->printername
);
869 HeapFree(GetProcessHeap(), 0, printer
->name
);
870 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
871 HeapFree(GetProcessHeap(), 0, printer
);
874 return (HANDLE
)handle
;
877 /******************************************************************
879 * Get the pointer to the opened printer referred by the handle
881 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
883 UINT_PTR idx
= (UINT_PTR
)hprn
;
884 opened_printer_t
*ret
= NULL
;
886 EnterCriticalSection(&printer_handles_cs
);
888 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
889 ret
= printer_handles
[idx
- 1];
891 LeaveCriticalSection(&printer_handles_cs
);
895 /******************************************************************
896 * get_opened_printer_name
897 * Get the pointer to the opened printer name referred by the handle
899 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
901 opened_printer_t
*printer
= get_opened_printer(hprn
);
902 if(!printer
) return NULL
;
903 return printer
->name
;
906 /******************************************************************
907 * WINSPOOL_GetOpenedPrinterRegKey
910 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
912 LPCWSTR name
= get_opened_printer_name(hPrinter
);
916 if(!name
) return ERROR_INVALID_HANDLE
;
918 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
922 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
924 ERR("Can't find opened printer %s in registry\n",
926 RegCloseKey(hkeyPrinters
);
927 return ERROR_INVALID_PRINTER_NAME
; /* ? */
929 RegCloseKey(hkeyPrinters
);
930 return ERROR_SUCCESS
;
933 void WINSPOOL_LoadSystemPrinters(void)
935 HKEY hkey
, hkeyPrinters
;
937 DWORD needed
, num
, i
;
938 WCHAR PrinterName
[256];
941 /* This ensures that all printer entries have a valid Name value. If causes
942 problems later if they don't. If one is found to be missed we create one
943 and set it equal to the name of the key */
944 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
945 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
946 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
947 for(i
= 0; i
< num
; i
++) {
948 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
949 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
950 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
951 set_reg_szW(hkey
, NameW
, PrinterName
);
958 RegCloseKey(hkeyPrinters
);
961 /* We want to avoid calling AddPrinter on printers as much as
962 possible, because on cups printers this will (eventually) lead
963 to a call to cupsGetPPD which takes forever, even with non-cups
964 printers AddPrinter takes a while. So we'll tag all printers that
965 were automatically added last time around, if they still exist
966 we'll leave them be otherwise we'll delete them. */
967 if (EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
) && needed
) {
968 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
969 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
970 for(i
= 0; i
< num
; i
++) {
971 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
972 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
973 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
975 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
983 HeapFree(GetProcessHeap(), 0, pi
);
987 #ifdef SONAME_LIBCUPS
988 done
= CUPS_LoadPrinters();
991 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
992 PRINTCAP_LoadPrinters();
994 /* Now enumerate the list again and delete any printers that are still tagged */
995 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
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 BOOL delete_driver
= FALSE
;
1003 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1004 DWORD dw
, type
, size
= sizeof(dw
);
1005 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1006 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1007 DeletePrinter(hprn
);
1008 delete_driver
= TRUE
;
1014 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1019 HeapFree(GetProcessHeap(), 0, pi
);
1026 /******************************************************************
1029 * Get the pointer to the specified job.
1030 * Should hold the printer_handles_cs before calling.
1032 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1034 opened_printer_t
*printer
= get_opened_printer(hprn
);
1037 if(!printer
) return NULL
;
1038 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1040 if(job
->job_id
== JobId
)
1046 /***********************************************************
1049 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1052 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1055 Formname
= (dmA
->dmSize
> off_formname
);
1056 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1057 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1058 dmW
->dmDeviceName
, CCHDEVICENAME
);
1060 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1061 dmA
->dmSize
- CCHDEVICENAME
);
1063 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1064 off_formname
- CCHDEVICENAME
);
1065 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1066 dmW
->dmFormName
, CCHFORMNAME
);
1067 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1068 (off_formname
+ CCHFORMNAME
));
1071 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1072 dmA
->dmDriverExtra
);
1076 /***********************************************************
1078 * Creates an ansi copy of supplied devmode
1080 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1085 if (!dmW
) return NULL
;
1086 size
= dmW
->dmSize
- CCHDEVICENAME
-
1087 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1089 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1090 if (!dmA
) return NULL
;
1092 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1093 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1095 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1096 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1097 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1101 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1102 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1103 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1104 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1106 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1110 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1114 /******************************************************************
1115 * convert_printerinfo_W_to_A [internal]
1118 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1119 DWORD level
, DWORD outlen
, DWORD numentries
)
1125 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1127 len
= pi_sizeof
[level
] * numentries
;
1128 ptr
= (LPSTR
) out
+ len
;
1131 /* copy the numbers of all PRINTER_INFO_* first */
1132 memcpy(out
, pPrintersW
, len
);
1134 while (id
< numentries
) {
1138 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1139 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1141 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1142 if (piW
->pDescription
) {
1143 piA
->pDescription
= ptr
;
1144 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1145 ptr
, outlen
, NULL
, NULL
);
1151 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1152 ptr
, outlen
, NULL
, NULL
);
1156 if (piW
->pComment
) {
1157 piA
->pComment
= ptr
;
1158 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1159 ptr
, outlen
, NULL
, NULL
);
1168 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1169 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1172 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1173 if (piW
->pServerName
) {
1174 piA
->pServerName
= ptr
;
1175 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1176 ptr
, outlen
, NULL
, NULL
);
1180 if (piW
->pPrinterName
) {
1181 piA
->pPrinterName
= ptr
;
1182 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1183 ptr
, outlen
, NULL
, NULL
);
1187 if (piW
->pShareName
) {
1188 piA
->pShareName
= ptr
;
1189 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1190 ptr
, outlen
, NULL
, NULL
);
1194 if (piW
->pPortName
) {
1195 piA
->pPortName
= ptr
;
1196 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1197 ptr
, outlen
, NULL
, NULL
);
1201 if (piW
->pDriverName
) {
1202 piA
->pDriverName
= ptr
;
1203 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1204 ptr
, outlen
, NULL
, NULL
);
1208 if (piW
->pComment
) {
1209 piA
->pComment
= ptr
;
1210 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1211 ptr
, outlen
, NULL
, NULL
);
1215 if (piW
->pLocation
) {
1216 piA
->pLocation
= ptr
;
1217 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1218 ptr
, outlen
, NULL
, NULL
);
1223 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1225 /* align DEVMODEA to a DWORD boundary */
1226 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1230 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1231 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1232 memcpy(ptr
, dmA
, len
);
1233 HeapFree(GetProcessHeap(), 0, dmA
);
1239 if (piW
->pSepFile
) {
1240 piA
->pSepFile
= ptr
;
1241 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1242 ptr
, outlen
, NULL
, NULL
);
1246 if (piW
->pPrintProcessor
) {
1247 piA
->pPrintProcessor
= ptr
;
1248 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1249 ptr
, outlen
, NULL
, NULL
);
1253 if (piW
->pDatatype
) {
1254 piA
->pDatatype
= ptr
;
1255 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1256 ptr
, outlen
, NULL
, NULL
);
1260 if (piW
->pParameters
) {
1261 piA
->pParameters
= ptr
;
1262 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1263 ptr
, outlen
, NULL
, NULL
);
1267 if (piW
->pSecurityDescriptor
) {
1268 piA
->pSecurityDescriptor
= NULL
;
1269 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1276 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1277 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1279 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1281 if (piW
->pPrinterName
) {
1282 piA
->pPrinterName
= ptr
;
1283 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1284 ptr
, outlen
, NULL
, NULL
);
1288 if (piW
->pServerName
) {
1289 piA
->pServerName
= ptr
;
1290 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1291 ptr
, outlen
, NULL
, NULL
);
1300 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1301 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1303 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1305 if (piW
->pPrinterName
) {
1306 piA
->pPrinterName
= ptr
;
1307 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1308 ptr
, outlen
, NULL
, NULL
);
1312 if (piW
->pPortName
) {
1313 piA
->pPortName
= ptr
;
1314 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1315 ptr
, outlen
, NULL
, NULL
);
1322 case 6: /* 6A and 6W are the same structure */
1327 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1328 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1330 TRACE("(%u) #%u\n", level
, id
);
1331 if (piW
->pszObjectGUID
) {
1332 piA
->pszObjectGUID
= ptr
;
1333 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1334 ptr
, outlen
, NULL
, NULL
);
1343 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1344 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1347 TRACE("(%u) #%u\n", level
, id
);
1348 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1350 /* align DEVMODEA to a DWORD boundary */
1351 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1355 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1356 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1357 memcpy(ptr
, dmA
, len
);
1358 HeapFree(GetProcessHeap(), 0, dmA
);
1368 FIXME("for level %u\n", level
);
1370 pPrintersW
+= pi_sizeof
[level
];
1371 out
+= pi_sizeof
[level
];
1376 /******************************************************************
1377 * convert_driverinfo_W_to_A [internal]
1380 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1381 DWORD level
, DWORD outlen
, DWORD numentries
)
1387 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1389 len
= di_sizeof
[level
] * numentries
;
1390 ptr
= (LPSTR
) out
+ len
;
1393 /* copy the numbers of all PRINTER_INFO_* first */
1394 memcpy(out
, pDriversW
, len
);
1396 #define COPY_STRING(fld) \
1399 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1400 ptr += len; outlen -= len;\
1402 #define COPY_MULTIZ_STRING(fld) \
1403 { LPWSTR p = diW->fld; if (p){ \
1406 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1407 ptr += len; outlen -= len; p += len;\
1409 while(len > 1 && outlen > 0); \
1412 while (id
< numentries
)
1418 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1419 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1421 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1428 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1429 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1431 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1434 COPY_STRING(pEnvironment
);
1435 COPY_STRING(pDriverPath
);
1436 COPY_STRING(pDataFile
);
1437 COPY_STRING(pConfigFile
);
1442 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1443 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1445 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1448 COPY_STRING(pEnvironment
);
1449 COPY_STRING(pDriverPath
);
1450 COPY_STRING(pDataFile
);
1451 COPY_STRING(pConfigFile
);
1452 COPY_STRING(pHelpFile
);
1453 COPY_MULTIZ_STRING(pDependentFiles
);
1454 COPY_STRING(pMonitorName
);
1455 COPY_STRING(pDefaultDataType
);
1460 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1461 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1463 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1466 COPY_STRING(pEnvironment
);
1467 COPY_STRING(pDriverPath
);
1468 COPY_STRING(pDataFile
);
1469 COPY_STRING(pConfigFile
);
1470 COPY_STRING(pHelpFile
);
1471 COPY_MULTIZ_STRING(pDependentFiles
);
1472 COPY_STRING(pMonitorName
);
1473 COPY_STRING(pDefaultDataType
);
1474 COPY_MULTIZ_STRING(pszzPreviousNames
);
1479 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1480 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1482 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1485 COPY_STRING(pEnvironment
);
1486 COPY_STRING(pDriverPath
);
1487 COPY_STRING(pDataFile
);
1488 COPY_STRING(pConfigFile
);
1493 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1494 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1496 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1499 COPY_STRING(pEnvironment
);
1500 COPY_STRING(pDriverPath
);
1501 COPY_STRING(pDataFile
);
1502 COPY_STRING(pConfigFile
);
1503 COPY_STRING(pHelpFile
);
1504 COPY_MULTIZ_STRING(pDependentFiles
);
1505 COPY_STRING(pMonitorName
);
1506 COPY_STRING(pDefaultDataType
);
1507 COPY_MULTIZ_STRING(pszzPreviousNames
);
1508 COPY_STRING(pszMfgName
);
1509 COPY_STRING(pszOEMUrl
);
1510 COPY_STRING(pszHardwareID
);
1511 COPY_STRING(pszProvider
);
1516 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1517 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1519 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1522 COPY_STRING(pEnvironment
);
1523 COPY_STRING(pDriverPath
);
1524 COPY_STRING(pDataFile
);
1525 COPY_STRING(pConfigFile
);
1526 COPY_STRING(pHelpFile
);
1527 COPY_MULTIZ_STRING(pDependentFiles
);
1528 COPY_STRING(pMonitorName
);
1529 COPY_STRING(pDefaultDataType
);
1530 COPY_MULTIZ_STRING(pszzPreviousNames
);
1531 COPY_STRING(pszMfgName
);
1532 COPY_STRING(pszOEMUrl
);
1533 COPY_STRING(pszHardwareID
);
1534 COPY_STRING(pszProvider
);
1535 COPY_STRING(pszPrintProcessor
);
1536 COPY_STRING(pszVendorSetup
);
1537 COPY_MULTIZ_STRING(pszzColorProfiles
);
1538 COPY_STRING(pszInfPath
);
1539 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1545 FIXME("for level %u\n", level
);
1548 pDriversW
+= di_sizeof
[level
];
1549 out
+= di_sizeof
[level
];
1554 #undef COPY_MULTIZ_STRING
1558 /***********************************************************
1559 * PRINTER_INFO_2AtoW
1560 * Creates a unicode copy of PRINTER_INFO_2A on heap
1562 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1564 LPPRINTER_INFO_2W piW
;
1565 UNICODE_STRING usBuffer
;
1567 if(!piA
) return NULL
;
1568 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1569 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1571 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1572 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1573 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1574 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1575 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1576 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1577 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1578 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1579 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1580 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1581 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1582 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1586 /***********************************************************
1587 * FREE_PRINTER_INFO_2W
1588 * Free PRINTER_INFO_2W and all strings
1590 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1594 HeapFree(heap
,0,piW
->pServerName
);
1595 HeapFree(heap
,0,piW
->pPrinterName
);
1596 HeapFree(heap
,0,piW
->pShareName
);
1597 HeapFree(heap
,0,piW
->pPortName
);
1598 HeapFree(heap
,0,piW
->pDriverName
);
1599 HeapFree(heap
,0,piW
->pComment
);
1600 HeapFree(heap
,0,piW
->pLocation
);
1601 HeapFree(heap
,0,piW
->pDevMode
);
1602 HeapFree(heap
,0,piW
->pSepFile
);
1603 HeapFree(heap
,0,piW
->pPrintProcessor
);
1604 HeapFree(heap
,0,piW
->pDatatype
);
1605 HeapFree(heap
,0,piW
->pParameters
);
1606 HeapFree(heap
,0,piW
);
1610 /******************************************************************
1611 * DeviceCapabilities [WINSPOOL.@]
1612 * DeviceCapabilitiesA [WINSPOOL.@]
1615 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1616 LPSTR pOutput
, LPDEVMODEA lpdm
)
1620 if (!GDI_CallDeviceCapabilities16
)
1622 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1624 if (!GDI_CallDeviceCapabilities16
) return -1;
1626 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1628 /* If DC_PAPERSIZE map POINT16s to POINTs */
1629 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1630 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1631 POINT
*pt
= (POINT
*)pOutput
;
1633 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1634 for(i
= 0; i
< ret
; i
++, pt
++)
1639 HeapFree( GetProcessHeap(), 0, tmp
);
1645 /*****************************************************************************
1646 * DeviceCapabilitiesW [WINSPOOL.@]
1648 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1651 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1652 WORD fwCapability
, LPWSTR pOutput
,
1653 const DEVMODEW
*pDevMode
)
1655 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1656 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1657 LPSTR pPortA
= strdupWtoA(pPort
);
1660 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1661 fwCapability
== DC_FILEDEPENDENCIES
||
1662 fwCapability
== DC_PAPERNAMES
)) {
1663 /* These need A -> W translation */
1666 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1670 switch(fwCapability
) {
1675 case DC_FILEDEPENDENCIES
:
1679 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1680 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1682 for(i
= 0; i
< ret
; i
++)
1683 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1684 pOutput
+ (i
* size
), size
);
1685 HeapFree(GetProcessHeap(), 0, pOutputA
);
1687 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1688 (LPSTR
)pOutput
, dmA
);
1690 HeapFree(GetProcessHeap(),0,pPortA
);
1691 HeapFree(GetProcessHeap(),0,pDeviceA
);
1692 HeapFree(GetProcessHeap(),0,dmA
);
1696 /******************************************************************
1697 * DocumentPropertiesA [WINSPOOL.@]
1699 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1701 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1702 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1703 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1705 LPSTR lpName
= pDeviceName
;
1706 static CHAR port
[] = "LPT1:";
1709 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1710 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1714 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1716 ERR("no name from hPrinter?\n");
1717 SetLastError(ERROR_INVALID_HANDLE
);
1720 lpName
= strdupWtoA(lpNameW
);
1723 if (!GDI_CallExtDeviceMode16
)
1725 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1727 if (!GDI_CallExtDeviceMode16
) {
1728 ERR("No CallExtDeviceMode16?\n");
1732 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1733 pDevModeInput
, NULL
, fMode
);
1736 HeapFree(GetProcessHeap(),0,lpName
);
1741 /*****************************************************************************
1742 * DocumentPropertiesW (WINSPOOL.@)
1744 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1746 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1748 LPDEVMODEW pDevModeOutput
,
1749 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1752 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1753 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1754 LPDEVMODEA pDevModeOutputA
= NULL
;
1757 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1758 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1760 if(pDevModeOutput
) {
1761 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1762 if(ret
< 0) return ret
;
1763 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1765 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1766 pDevModeInputA
, fMode
);
1767 if(pDevModeOutput
) {
1768 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1769 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1771 if(fMode
== 0 && ret
> 0)
1772 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1773 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1774 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1778 /*****************************************************************************
1779 * IsValidDevmodeA [WINSPOOL.@]
1781 * Validate a DEVMODE structure and fix errors if possible.
1784 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1786 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1794 /*****************************************************************************
1795 * IsValidDevmodeW [WINSPOOL.@]
1797 * Validate a DEVMODE structure and fix errors if possible.
1800 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1802 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1810 /******************************************************************
1811 * OpenPrinterA [WINSPOOL.@]
1816 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1817 LPPRINTER_DEFAULTSA pDefault
)
1819 UNICODE_STRING lpPrinterNameW
;
1820 UNICODE_STRING usBuffer
;
1821 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1822 PWSTR pwstrPrinterNameW
;
1825 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1828 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1829 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1830 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1831 pDefaultW
= &DefaultW
;
1833 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1835 RtlFreeUnicodeString(&usBuffer
);
1836 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1838 RtlFreeUnicodeString(&lpPrinterNameW
);
1842 /******************************************************************
1843 * OpenPrinterW [WINSPOOL.@]
1845 * Open a Printer / Printserver or a Printer-Object
1848 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1849 * phPrinter [O] The resulting Handle is stored here
1850 * pDefault [I] PTR to Default Printer Settings or NULL
1857 * lpPrinterName is one of:
1858 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1859 *| Printer: "PrinterName"
1860 *| Printer-Object: "PrinterName,Job xxx"
1861 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1862 *| XcvPort: "Servername,XcvPort PortName"
1865 *| Printer-Object not supported
1866 *| pDefaults is ignored
1869 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1872 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1874 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1875 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1879 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1880 SetLastError(ERROR_INVALID_PARAMETER
);
1884 /* Get the unique handle of the printer or Printserver */
1885 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1886 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1887 return (*phPrinter
!= 0);
1890 /******************************************************************
1891 * AddMonitorA [WINSPOOL.@]
1896 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1898 LPWSTR nameW
= NULL
;
1901 LPMONITOR_INFO_2A mi2a
;
1902 MONITOR_INFO_2W mi2w
;
1904 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1905 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1906 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1907 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1908 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1911 SetLastError(ERROR_INVALID_LEVEL
);
1915 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1921 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1922 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1923 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1926 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1928 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1929 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1930 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1932 if (mi2a
->pEnvironment
) {
1933 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1934 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1935 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1937 if (mi2a
->pDLLName
) {
1938 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1939 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1940 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1943 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1945 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1946 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1947 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1949 HeapFree(GetProcessHeap(), 0, nameW
);
1953 /******************************************************************************
1954 * AddMonitorW [WINSPOOL.@]
1956 * Install a Printmonitor
1959 * pName [I] Servername or NULL (local Computer)
1960 * Level [I] Structure-Level (Must be 2)
1961 * pMonitors [I] PTR to MONITOR_INFO_2
1968 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1971 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1973 LPMONITOR_INFO_2W mi2w
;
1975 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1976 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1977 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1978 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1979 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1981 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1984 SetLastError(ERROR_INVALID_LEVEL
);
1988 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1993 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
1996 /******************************************************************
1997 * DeletePrinterDriverA [WINSPOOL.@]
2000 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2002 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2005 /******************************************************************
2006 * DeletePrinterDriverW [WINSPOOL.@]
2009 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2011 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2014 /******************************************************************
2015 * DeleteMonitorA [WINSPOOL.@]
2017 * See DeleteMonitorW.
2020 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2022 LPWSTR nameW
= NULL
;
2023 LPWSTR EnvironmentW
= NULL
;
2024 LPWSTR MonitorNameW
= NULL
;
2029 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2030 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2031 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2035 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2036 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2037 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2040 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2041 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2042 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2045 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2047 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2048 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2049 HeapFree(GetProcessHeap(), 0, nameW
);
2053 /******************************************************************
2054 * DeleteMonitorW [WINSPOOL.@]
2056 * Delete a specific Printmonitor from a Printing-Environment
2059 * pName [I] Servername or NULL (local Computer)
2060 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2061 * pMonitorName [I] Name of the Monitor, that should be deleted
2068 * pEnvironment is ignored in Windows for the local Computer.
2071 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2074 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2075 debugstr_w(pMonitorName
));
2077 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2079 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2083 /******************************************************************
2084 * DeletePortA [WINSPOOL.@]
2089 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2091 LPWSTR nameW
= NULL
;
2092 LPWSTR portW
= NULL
;
2096 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2098 /* convert servername to unicode */
2100 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2101 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2102 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2105 /* convert portname to unicode */
2107 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2108 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2109 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2112 res
= DeletePortW(nameW
, hWnd
, portW
);
2113 HeapFree(GetProcessHeap(), 0, nameW
);
2114 HeapFree(GetProcessHeap(), 0, portW
);
2118 /******************************************************************
2119 * DeletePortW [WINSPOOL.@]
2121 * Delete a specific Port
2124 * pName [I] Servername or NULL (local Computer)
2125 * hWnd [I] Handle to parent Window for the Dialog-Box
2126 * pPortName [I] Name of the Port, that should be deleted
2133 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2135 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2137 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2140 SetLastError(RPC_X_NULL_REF_POINTER
);
2144 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2147 /******************************************************************************
2148 * SetPrinterW [WINSPOOL.@]
2150 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2152 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2157 /******************************************************************************
2158 * WritePrinter [WINSPOOL.@]
2160 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2162 opened_printer_t
*printer
;
2165 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2167 EnterCriticalSection(&printer_handles_cs
);
2168 printer
= get_opened_printer(hPrinter
);
2171 SetLastError(ERROR_INVALID_HANDLE
);
2177 SetLastError(ERROR_SPL_NO_STARTDOC
);
2181 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2183 LeaveCriticalSection(&printer_handles_cs
);
2187 /*****************************************************************************
2188 * AddFormA [WINSPOOL.@]
2190 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2192 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2196 /*****************************************************************************
2197 * AddFormW [WINSPOOL.@]
2199 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2205 /*****************************************************************************
2206 * AddJobA [WINSPOOL.@]
2208 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2211 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2215 SetLastError(ERROR_INVALID_LEVEL
);
2219 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2222 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2223 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2224 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2225 if(*pcbNeeded
> cbBuf
) {
2226 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2229 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2230 addjobA
->JobId
= addjobW
->JobId
;
2231 addjobA
->Path
= (char *)(addjobA
+ 1);
2232 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2238 /*****************************************************************************
2239 * AddJobW [WINSPOOL.@]
2241 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2243 opened_printer_t
*printer
;
2246 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2247 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2248 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2250 ADDJOB_INFO_1W
*addjob
;
2252 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2254 EnterCriticalSection(&printer_handles_cs
);
2256 printer
= get_opened_printer(hPrinter
);
2259 SetLastError(ERROR_INVALID_HANDLE
);
2264 SetLastError(ERROR_INVALID_LEVEL
);
2268 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2272 job
->job_id
= InterlockedIncrement(&next_job_id
);
2274 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2275 if(path
[len
- 1] != '\\')
2277 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2278 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2280 len
= strlenW(filename
);
2281 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2282 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2283 job
->document_title
= strdupW(default_doc_title
);
2284 job
->printer_name
= strdupW(printer
->name
);
2285 job
->devmode
= NULL
;
2286 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2288 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2289 if(*pcbNeeded
<= cbBuf
) {
2290 addjob
= (ADDJOB_INFO_1W
*)pData
;
2291 addjob
->JobId
= job
->job_id
;
2292 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2293 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2296 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2299 LeaveCriticalSection(&printer_handles_cs
);
2303 /*****************************************************************************
2304 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2306 * Return the PATH for the Print-Processors
2308 * See GetPrintProcessorDirectoryW.
2312 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2313 DWORD level
, LPBYTE Info
,
2314 DWORD cbBuf
, LPDWORD pcbNeeded
)
2316 LPWSTR serverW
= NULL
;
2321 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2322 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2326 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2327 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2328 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2332 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2333 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2334 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2337 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2338 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2340 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2343 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2344 cbBuf
, NULL
, NULL
) > 0;
2347 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2348 HeapFree(GetProcessHeap(), 0, envW
);
2349 HeapFree(GetProcessHeap(), 0, serverW
);
2353 /*****************************************************************************
2354 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2356 * Return the PATH for the Print-Processors
2359 * server [I] Servername (NT only) or NULL (local Computer)
2360 * env [I] Printing-Environment (see below) or NULL (Default)
2361 * level [I] Structure-Level (must be 1)
2362 * Info [O] PTR to Buffer that receives the Result
2363 * cbBuf [I] Size of Buffer at "Info"
2364 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2365 * required for the Buffer at "Info"
2368 * Success: TRUE and in pcbNeeded the Bytes used in Info
2369 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2370 * if cbBuf is too small
2372 * Native Values returned in Info on Success:
2373 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2374 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2375 *| win9x(Windows 4.0): "%winsysdir%"
2377 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2380 * Only NULL or "" is supported for server
2383 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2384 DWORD level
, LPBYTE Info
,
2385 DWORD cbBuf
, LPDWORD pcbNeeded
)
2388 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2389 Info
, cbBuf
, pcbNeeded
);
2391 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2394 /* (Level != 1) is ignored in win9x */
2395 SetLastError(ERROR_INVALID_LEVEL
);
2399 if (pcbNeeded
== NULL
) {
2400 /* (pcbNeeded == NULL) is ignored in win9x */
2401 SetLastError(RPC_X_NULL_REF_POINTER
);
2405 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2408 /*****************************************************************************
2409 * WINSPOOL_OpenDriverReg [internal]
2411 * opens the registry for the printer drivers depending on the given input
2412 * variable pEnvironment
2415 * the opened hkey on success
2418 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2422 const printenv_t
* env
;
2424 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2426 env
= validate_envW(pEnvironment
);
2427 if (!env
) return NULL
;
2429 buffer
= HeapAlloc( GetProcessHeap(), 0,
2430 (strlenW(DriversW
) + strlenW(env
->envname
) +
2431 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2433 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2434 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2435 HeapFree(GetProcessHeap(), 0, buffer
);
2440 /*****************************************************************************
2441 * set_devices_and_printerports [internal]
2443 * set the [Devices] and [PrinterPorts] entries for a printer.
2446 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2448 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2452 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2454 /* FIXME: the driver must change to "winspool" */
2455 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2457 lstrcpyW(devline
, driver_nt
);
2458 lstrcatW(devline
, commaW
);
2459 lstrcatW(devline
, pi
->pPortName
);
2461 TRACE("using %s\n", debugstr_w(devline
));
2462 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2463 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2464 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2465 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2469 lstrcatW(devline
, timeout_15_45
);
2470 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2471 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2472 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2473 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2476 HeapFree(GetProcessHeap(), 0, devline
);
2480 /*****************************************************************************
2481 * AddPrinterW [WINSPOOL.@]
2483 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2485 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2489 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2491 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2492 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2493 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2494 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2495 statusW
[] = {'S','t','a','t','u','s',0},
2496 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2498 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2501 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2502 SetLastError(ERROR_INVALID_PARAMETER
);
2506 ERR("Level = %d, unsupported!\n", Level
);
2507 SetLastError(ERROR_INVALID_LEVEL
);
2511 SetLastError(ERROR_INVALID_PARAMETER
);
2514 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2516 ERR("Can't create Printers key\n");
2519 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2520 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2521 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2522 RegCloseKey(hkeyPrinter
);
2523 RegCloseKey(hkeyPrinters
);
2526 RegCloseKey(hkeyPrinter
);
2528 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2530 ERR("Can't create Drivers key\n");
2531 RegCloseKey(hkeyPrinters
);
2534 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2536 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2537 RegCloseKey(hkeyPrinters
);
2538 RegCloseKey(hkeyDrivers
);
2539 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2542 RegCloseKey(hkeyDriver
);
2543 RegCloseKey(hkeyDrivers
);
2545 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2546 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2547 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2548 RegCloseKey(hkeyPrinters
);
2552 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2554 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2555 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2556 RegCloseKey(hkeyPrinters
);
2560 set_devices_and_printerports(pi
);
2561 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2562 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2563 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2565 /* See if we can load the driver. We may need the devmode structure anyway
2568 * Note that DocumentPropertiesW will briefly try to open the printer we
2569 * just create to find a DEVMODEA struct (it will use the WINEPS default
2570 * one in case it is not there, so we are ok).
2572 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2575 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2576 size
= sizeof(DEVMODEW
);
2582 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2584 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2586 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2587 HeapFree(GetProcessHeap(),0,dmW
);
2592 /* set devmode to printer name */
2593 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2597 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2598 and we support these drivers. NT writes DEVMODEW so somehow
2599 we'll need to distinguish between these when we support NT
2603 dmA
= DEVMODEdupWtoA(dmW
);
2604 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2605 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2606 HeapFree(GetProcessHeap(), 0, dmA
);
2608 HeapFree(GetProcessHeap(), 0, dmW
);
2610 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2611 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2612 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2613 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2615 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2616 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2617 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2618 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2619 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2620 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2621 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2622 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2623 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2624 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2625 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2626 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2627 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2629 RegCloseKey(hkeyPrinter
);
2630 RegCloseKey(hkeyPrinters
);
2631 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2632 ERR("OpenPrinter failing\n");
2638 /*****************************************************************************
2639 * AddPrinterA [WINSPOOL.@]
2641 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2643 UNICODE_STRING pNameW
;
2645 PRINTER_INFO_2W
*piW
;
2646 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2649 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2651 ERR("Level = %d, unsupported!\n", Level
);
2652 SetLastError(ERROR_INVALID_LEVEL
);
2655 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2656 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2658 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2660 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2661 RtlFreeUnicodeString(&pNameW
);
2666 /*****************************************************************************
2667 * ClosePrinter [WINSPOOL.@]
2669 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2671 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2672 opened_printer_t
*printer
= NULL
;
2675 TRACE("(%p)\n", hPrinter
);
2677 EnterCriticalSection(&printer_handles_cs
);
2679 if ((i
> 0) && (i
<= nb_printer_handles
))
2680 printer
= printer_handles
[i
- 1];
2685 struct list
*cursor
, *cursor2
;
2687 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2689 if (printer
->backend_printer
) {
2690 backend
->fpClosePrinter(printer
->backend_printer
);
2694 EndDocPrinter(hPrinter
);
2696 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2698 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2700 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2701 ScheduleJob(hPrinter
, job
->job_id
);
2703 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2706 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2707 HeapFree(GetProcessHeap(), 0, printer
->name
);
2708 HeapFree(GetProcessHeap(), 0, printer
);
2709 printer_handles
[i
- 1] = NULL
;
2712 LeaveCriticalSection(&printer_handles_cs
);
2716 /*****************************************************************************
2717 * DeleteFormA [WINSPOOL.@]
2719 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2721 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2725 /*****************************************************************************
2726 * DeleteFormW [WINSPOOL.@]
2728 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2730 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2734 /*****************************************************************************
2735 * DeletePrinter [WINSPOOL.@]
2737 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2739 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2740 HKEY hkeyPrinters
, hkey
;
2743 SetLastError(ERROR_INVALID_HANDLE
);
2746 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2747 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2748 RegCloseKey(hkeyPrinters
);
2750 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2751 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2753 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2754 RegDeleteValueW(hkey
, lpNameW
);
2758 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2759 RegDeleteValueW(hkey
, lpNameW
);
2765 /*****************************************************************************
2766 * SetPrinterA [WINSPOOL.@]
2768 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2771 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2775 /*****************************************************************************
2776 * SetJobA [WINSPOOL.@]
2778 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2779 LPBYTE pJob
, DWORD Command
)
2783 UNICODE_STRING usBuffer
;
2785 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2787 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2788 are all ignored by SetJob, so we don't bother copying them */
2796 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2797 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2799 JobW
= (LPBYTE
)info1W
;
2800 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2801 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2802 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2803 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2804 info1W
->Status
= info1A
->Status
;
2805 info1W
->Priority
= info1A
->Priority
;
2806 info1W
->Position
= info1A
->Position
;
2807 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2812 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2813 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2815 JobW
= (LPBYTE
)info2W
;
2816 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2817 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2818 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2819 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2820 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2821 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2822 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2823 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2824 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2825 info2W
->Status
= info2A
->Status
;
2826 info2W
->Priority
= info2A
->Priority
;
2827 info2W
->Position
= info2A
->Position
;
2828 info2W
->StartTime
= info2A
->StartTime
;
2829 info2W
->UntilTime
= info2A
->UntilTime
;
2830 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2834 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2835 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2838 SetLastError(ERROR_INVALID_LEVEL
);
2842 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2848 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2849 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2850 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2851 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2852 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2857 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2858 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2859 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2860 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2861 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2862 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2863 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2864 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2865 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2869 HeapFree(GetProcessHeap(), 0, JobW
);
2874 /*****************************************************************************
2875 * SetJobW [WINSPOOL.@]
2877 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2878 LPBYTE pJob
, DWORD Command
)
2884 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2885 FIXME("Ignoring everything other than document title\n");
2887 EnterCriticalSection(&printer_handles_cs
);
2888 job
= get_job(hPrinter
, JobId
);
2898 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2899 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2900 job
->document_title
= strdupW(info1
->pDocument
);
2905 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2906 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2907 job
->document_title
= strdupW(info2
->pDocument
);
2908 HeapFree(GetProcessHeap(), 0, job
->devmode
);
2909 if (info2
->pDevMode
)
2911 size
= info2
->pDevMode
->dmSize
+ info2
->pDevMode
->dmDriverExtra
;
2912 job
->devmode
= HeapAlloc(GetProcessHeap(), 0, size
);
2913 memcpy(job
->devmode
, info2
->pDevMode
, size
);
2916 job
->devmode
= NULL
;
2922 SetLastError(ERROR_INVALID_LEVEL
);
2927 LeaveCriticalSection(&printer_handles_cs
);
2931 /*****************************************************************************
2932 * EndDocPrinter [WINSPOOL.@]
2934 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2936 opened_printer_t
*printer
;
2938 TRACE("(%p)\n", hPrinter
);
2940 EnterCriticalSection(&printer_handles_cs
);
2942 printer
= get_opened_printer(hPrinter
);
2945 SetLastError(ERROR_INVALID_HANDLE
);
2951 SetLastError(ERROR_SPL_NO_STARTDOC
);
2955 CloseHandle(printer
->doc
->hf
);
2956 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2957 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2958 printer
->doc
= NULL
;
2961 LeaveCriticalSection(&printer_handles_cs
);
2965 /*****************************************************************************
2966 * EndPagePrinter [WINSPOOL.@]
2968 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2970 FIXME("(%p): stub\n", hPrinter
);
2974 /*****************************************************************************
2975 * StartDocPrinterA [WINSPOOL.@]
2977 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2979 UNICODE_STRING usBuffer
;
2981 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2984 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2985 or one (DOC_INFO_3) extra DWORDs */
2989 doc2W
.JobId
= doc2
->JobId
;
2992 doc2W
.dwMode
= doc2
->dwMode
;
2995 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2996 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2997 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3001 SetLastError(ERROR_INVALID_LEVEL
);
3005 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3007 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3008 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3009 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3014 /*****************************************************************************
3015 * StartDocPrinterW [WINSPOOL.@]
3017 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3019 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3020 opened_printer_t
*printer
;
3021 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3022 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3023 JOB_INFO_1W job_info
;
3024 DWORD needed
, ret
= 0;
3029 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3030 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3031 debugstr_w(doc
->pDatatype
));
3033 if(Level
< 1 || Level
> 3)
3035 SetLastError(ERROR_INVALID_LEVEL
);
3039 EnterCriticalSection(&printer_handles_cs
);
3040 printer
= get_opened_printer(hPrinter
);
3043 SetLastError(ERROR_INVALID_HANDLE
);
3049 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3053 /* Even if we're printing to a file we still add a print job, we'll
3054 just ignore the spool file name */
3056 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3058 ERR("AddJob failed gle %u\n", GetLastError());
3062 /* use pOutputFile only, when it is a real filename */
3063 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3064 filename
= doc
->pOutputFile
;
3066 filename
= addjob
->Path
;
3068 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3069 if(hf
== INVALID_HANDLE_VALUE
)
3072 memset(&job_info
, 0, sizeof(job_info
));
3073 job_info
.pDocument
= doc
->pDocName
;
3074 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3076 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3077 printer
->doc
->hf
= hf
;
3078 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3079 job
= get_job(hPrinter
, ret
);
3080 job
->portname
= strdupW(doc
->pOutputFile
);
3083 LeaveCriticalSection(&printer_handles_cs
);
3088 /*****************************************************************************
3089 * StartPagePrinter [WINSPOOL.@]
3091 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3093 FIXME("(%p): stub\n", hPrinter
);
3097 /*****************************************************************************
3098 * GetFormA [WINSPOOL.@]
3100 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3101 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3103 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3104 Level
,pForm
,cbBuf
,pcbNeeded
);
3108 /*****************************************************************************
3109 * GetFormW [WINSPOOL.@]
3111 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3112 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3114 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3115 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3119 /*****************************************************************************
3120 * SetFormA [WINSPOOL.@]
3122 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3125 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3129 /*****************************************************************************
3130 * SetFormW [WINSPOOL.@]
3132 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3135 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3139 /*****************************************************************************
3140 * ReadPrinter [WINSPOOL.@]
3142 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3143 LPDWORD pNoBytesRead
)
3145 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3149 /*****************************************************************************
3150 * ResetPrinterA [WINSPOOL.@]
3152 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3154 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3158 /*****************************************************************************
3159 * ResetPrinterW [WINSPOOL.@]
3161 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3163 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3167 /*****************************************************************************
3168 * WINSPOOL_GetDWORDFromReg
3170 * Return DWORD associated with ValueName from hkey.
3172 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3174 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3177 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3179 if(ret
!= ERROR_SUCCESS
) {
3180 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3183 if(type
!= REG_DWORD
) {
3184 ERR("Got type %d\n", type
);
3191 /*****************************************************************************
3192 * get_filename_from_reg [internal]
3194 * Get ValueName from hkey storing result in out
3195 * when the Value in the registry has only a filename, use driverdir as prefix
3196 * outlen is space left in out
3197 * String is stored either as unicode or ascii
3201 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3202 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3204 WCHAR filename
[MAX_PATH
];
3208 LPWSTR buffer
= filename
;
3212 size
= sizeof(filename
);
3214 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3215 if (ret
== ERROR_MORE_DATA
) {
3216 TRACE("need dynamic buffer: %u\n", size
);
3217 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3219 /* No Memory is bad */
3223 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3226 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3227 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3233 /* do we have a full path ? */
3234 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3235 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3238 /* we must build the full Path */
3240 if ((out
) && (outlen
> dirlen
)) {
3241 lstrcpyW((LPWSTR
)out
, driverdir
);
3249 /* write the filename */
3250 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3251 if ((out
) && (outlen
>= size
)) {
3252 lstrcpyW((LPWSTR
)out
, ptr
);
3259 ptr
+= lstrlenW(ptr
)+1;
3260 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3263 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3265 /* write the multisz-termination */
3266 if (type
== REG_MULTI_SZ
) {
3267 size
= sizeof(WCHAR
);
3270 if (out
&& (outlen
>= size
)) {
3271 memset (out
, 0, size
);
3277 /*****************************************************************************
3278 * WINSPOOL_GetStringFromReg
3280 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3281 * String is stored as unicode.
3283 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3284 DWORD buflen
, DWORD
*needed
)
3286 DWORD sz
= buflen
, type
;
3289 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3290 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3291 WARN("Got ret = %d\n", ret
);
3295 /* add space for terminating '\0' */
3296 sz
+= sizeof(WCHAR
);
3300 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3305 /*****************************************************************************
3306 * WINSPOOL_GetDefaultDevMode
3308 * Get a default DevMode values for wineps.
3312 static void WINSPOOL_GetDefaultDevMode(
3314 DWORD buflen
, DWORD
*needed
)
3317 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3319 /* fill default DEVMODE - should be read from ppd... */
3320 ZeroMemory( &dm
, sizeof(dm
) );
3321 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3322 dm
.dmSpecVersion
= DM_SPECVERSION
;
3323 dm
.dmDriverVersion
= 1;
3324 dm
.dmSize
= sizeof(DEVMODEW
);
3325 dm
.dmDriverExtra
= 0;
3327 DM_ORIENTATION
| DM_PAPERSIZE
|
3328 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3331 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3332 DM_YRESOLUTION
| DM_TTOPTION
;
3334 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3335 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3336 dm
.u1
.s1
.dmPaperLength
= 2970;
3337 dm
.u1
.s1
.dmPaperWidth
= 2100;
3339 dm
.u1
.s1
.dmScale
= 100;
3340 dm
.u1
.s1
.dmCopies
= 1;
3341 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3342 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3345 dm
.dmYResolution
= 300; /* 300dpi */
3346 dm
.dmTTOption
= DMTT_BITMAP
;
3349 /* dm.dmLogPixels */
3350 /* dm.dmBitsPerPel */
3351 /* dm.dmPelsWidth */
3352 /* dm.dmPelsHeight */
3353 /* dm.u2.dmDisplayFlags */
3354 /* dm.dmDisplayFrequency */
3355 /* dm.dmICMMethod */
3356 /* dm.dmICMIntent */
3357 /* dm.dmMediaType */
3358 /* dm.dmDitherType */
3359 /* dm.dmReserved1 */
3360 /* dm.dmReserved2 */
3361 /* dm.dmPanningWidth */
3362 /* dm.dmPanningHeight */
3364 if(buflen
>= sizeof(DEVMODEW
))
3365 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3366 *needed
= sizeof(DEVMODEW
);
3369 /*****************************************************************************
3370 * WINSPOOL_GetDevModeFromReg
3372 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3373 * DevMode is stored either as unicode or ascii.
3375 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3377 DWORD buflen
, DWORD
*needed
)
3379 DWORD sz
= buflen
, type
;
3382 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3383 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3384 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3385 if (sz
< sizeof(DEVMODEA
))
3387 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3390 /* ensures that dmSize is not erratically bogus if registry is invalid */
3391 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3392 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3393 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3394 if (ptr
&& (buflen
>= sz
)) {
3395 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3396 memcpy(ptr
, dmW
, sz
);
3397 HeapFree(GetProcessHeap(),0,dmW
);
3403 /*********************************************************************
3404 * WINSPOOL_GetPrinter_1
3406 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3408 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3409 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3411 DWORD size
, left
= cbBuf
;
3412 BOOL space
= (cbBuf
> 0);
3417 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3418 if(space
&& size
<= left
) {
3419 pi1
->pName
= (LPWSTR
)ptr
;
3427 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3428 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3429 if(space
&& size
<= left
) {
3430 pi1
->pDescription
= (LPWSTR
)ptr
;
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3439 if(space
&& size
<= left
) {
3440 pi1
->pComment
= (LPWSTR
)ptr
;
3448 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3450 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3451 memset(pi1
, 0, sizeof(*pi1
));
3455 /*********************************************************************
3456 * WINSPOOL_GetPrinter_2
3458 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3460 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3461 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3463 DWORD size
, left
= cbBuf
;
3464 BOOL space
= (cbBuf
> 0);
3469 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3470 if(space
&& size
<= left
) {
3471 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3478 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3479 if(space
&& size
<= left
) {
3480 pi2
->pShareName
= (LPWSTR
)ptr
;
3487 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3488 if(space
&& size
<= left
) {
3489 pi2
->pPortName
= (LPWSTR
)ptr
;
3496 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3497 if(space
&& size
<= left
) {
3498 pi2
->pDriverName
= (LPWSTR
)ptr
;
3505 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3506 if(space
&& size
<= left
) {
3507 pi2
->pComment
= (LPWSTR
)ptr
;
3514 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3515 if(space
&& size
<= left
) {
3516 pi2
->pLocation
= (LPWSTR
)ptr
;
3523 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3524 if(space
&& size
<= left
) {
3525 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3534 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3535 if(space
&& size
<= left
) {
3536 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3543 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3544 if(space
&& size
<= left
) {
3545 pi2
->pSepFile
= (LPWSTR
)ptr
;
3552 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3553 if(space
&& size
<= left
) {
3554 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3561 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3562 if(space
&& size
<= left
) {
3563 pi2
->pDatatype
= (LPWSTR
)ptr
;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3571 if(space
&& size
<= left
) {
3572 pi2
->pParameters
= (LPWSTR
)ptr
;
3580 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3581 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3582 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3583 "Default Priority");
3584 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3585 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3588 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3589 memset(pi2
, 0, sizeof(*pi2
));
3594 /*********************************************************************
3595 * WINSPOOL_GetPrinter_4
3597 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3599 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3600 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3602 DWORD size
, left
= cbBuf
;
3603 BOOL space
= (cbBuf
> 0);
3608 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3609 if(space
&& size
<= left
) {
3610 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3618 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3621 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3622 memset(pi4
, 0, sizeof(*pi4
));
3627 /*********************************************************************
3628 * WINSPOOL_GetPrinter_5
3630 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3632 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3633 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3635 DWORD size
, left
= cbBuf
;
3636 BOOL space
= (cbBuf
> 0);
3641 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3642 if(space
&& size
<= left
) {
3643 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3651 if(space
&& size
<= left
) {
3652 pi5
->pPortName
= (LPWSTR
)ptr
;
3660 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3661 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3663 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3667 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3668 memset(pi5
, 0, sizeof(*pi5
));
3673 /*********************************************************************
3674 * WINSPOOL_GetPrinter_7
3676 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3678 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3679 DWORD cbBuf
, LPDWORD pcbNeeded
)
3681 DWORD size
, left
= cbBuf
;
3682 BOOL space
= (cbBuf
> 0);
3687 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3690 size
= sizeof(pi7
->pszObjectGUID
);
3692 if (space
&& size
<= left
) {
3693 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3700 /* We do not have a Directory Service */
3701 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3704 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3705 memset(pi7
, 0, sizeof(*pi7
));
3710 /*********************************************************************
3711 * WINSPOOL_GetPrinter_9
3713 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3715 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3716 DWORD cbBuf
, LPDWORD pcbNeeded
)
3719 BOOL space
= (cbBuf
> 0);
3723 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3724 if(space
&& size
<= cbBuf
) {
3725 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3732 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3733 if(space
&& size
<= cbBuf
) {
3734 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3740 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3741 memset(pi9
, 0, sizeof(*pi9
));
3746 /*****************************************************************************
3747 * GetPrinterW [WINSPOOL.@]
3749 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3750 DWORD cbBuf
, LPDWORD pcbNeeded
)
3753 DWORD size
, needed
= 0;
3755 HKEY hkeyPrinter
, hkeyPrinters
;
3758 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3760 if (!(name
= get_opened_printer_name(hPrinter
))) {
3761 SetLastError(ERROR_INVALID_HANDLE
);
3765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3767 ERR("Can't create Printers key\n");
3770 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3772 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3773 RegCloseKey(hkeyPrinters
);
3774 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3781 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3783 size
= sizeof(PRINTER_INFO_2W
);
3785 ptr
= pPrinter
+ size
;
3787 memset(pPrinter
, 0, size
);
3792 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3799 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3801 size
= sizeof(PRINTER_INFO_4W
);
3803 ptr
= pPrinter
+ size
;
3805 memset(pPrinter
, 0, size
);
3810 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3818 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3820 size
= sizeof(PRINTER_INFO_5W
);
3822 ptr
= pPrinter
+ size
;
3824 memset(pPrinter
, 0, size
);
3830 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3838 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3840 size
= sizeof(PRINTER_INFO_6
);
3841 if (size
<= cbBuf
) {
3842 /* FIXME: We do not update the status yet */
3843 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3855 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3857 size
= sizeof(PRINTER_INFO_7W
);
3858 if (size
<= cbBuf
) {
3859 ptr
= pPrinter
+ size
;
3861 memset(pPrinter
, 0, size
);
3867 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3875 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3877 size
= sizeof(PRINTER_INFO_9W
);
3879 ptr
= pPrinter
+ size
;
3881 memset(pPrinter
, 0, size
);
3887 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3894 FIXME("Unimplemented level %d\n", Level
);
3895 SetLastError(ERROR_INVALID_LEVEL
);
3896 RegCloseKey(hkeyPrinters
);
3897 RegCloseKey(hkeyPrinter
);
3901 RegCloseKey(hkeyPrinter
);
3902 RegCloseKey(hkeyPrinters
);
3904 TRACE("returning %d needed = %d\n", ret
, needed
);
3905 if(pcbNeeded
) *pcbNeeded
= needed
;
3907 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3911 /*****************************************************************************
3912 * GetPrinterA [WINSPOOL.@]
3914 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3915 DWORD cbBuf
, LPDWORD pcbNeeded
)
3921 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3923 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3925 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3926 HeapFree(GetProcessHeap(), 0, buf
);
3931 /*****************************************************************************
3932 * WINSPOOL_EnumPrintersW
3934 * Implementation of EnumPrintersW
3936 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3937 DWORD dwLevel
, LPBYTE lpbPrinters
,
3938 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3939 LPDWORD lpdwReturned
)
3942 HKEY hkeyPrinters
, hkeyPrinter
;
3943 WCHAR PrinterName
[255];
3944 DWORD needed
= 0, number
= 0;
3945 DWORD used
, i
, left
;
3949 memset(lpbPrinters
, 0, cbBuf
);
3955 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3956 if(dwType
== PRINTER_ENUM_DEFAULT
)
3959 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3960 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3961 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3963 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3969 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3970 FIXME("dwType = %08x\n", dwType
);
3971 SetLastError(ERROR_INVALID_FLAGS
);
3975 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3977 ERR("Can't create Printers key\n");
3981 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3982 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3983 RegCloseKey(hkeyPrinters
);
3984 ERR("Can't query Printers key\n");
3987 TRACE("Found %d printers\n", number
);
3991 used
= number
* sizeof(PRINTER_INFO_1W
);
3994 used
= number
* sizeof(PRINTER_INFO_2W
);
3997 used
= number
* sizeof(PRINTER_INFO_4W
);
4000 used
= number
* sizeof(PRINTER_INFO_5W
);
4004 SetLastError(ERROR_INVALID_LEVEL
);
4005 RegCloseKey(hkeyPrinters
);
4008 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4010 for(i
= 0; i
< number
; i
++) {
4011 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4013 ERR("Can't enum key number %d\n", i
);
4014 RegCloseKey(hkeyPrinters
);
4017 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4018 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4020 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4021 RegCloseKey(hkeyPrinters
);
4026 buf
= lpbPrinters
+ used
;
4027 left
= cbBuf
- used
;
4035 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4038 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4041 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4044 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4047 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4050 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4053 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4056 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4059 ERR("Shouldn't be here!\n");
4060 RegCloseKey(hkeyPrinter
);
4061 RegCloseKey(hkeyPrinters
);
4064 RegCloseKey(hkeyPrinter
);
4066 RegCloseKey(hkeyPrinters
);
4073 memset(lpbPrinters
, 0, cbBuf
);
4074 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4078 *lpdwReturned
= number
;
4079 SetLastError(ERROR_SUCCESS
);
4084 /******************************************************************
4085 * EnumPrintersW [WINSPOOL.@]
4087 * Enumerates the available printers, print servers and print
4088 * providers, depending on the specified flags, name and level.
4092 * If level is set to 1:
4093 * Returns an array of PRINTER_INFO_1 data structures in the
4094 * lpbPrinters buffer.
4096 * If level is set to 2:
4097 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4098 * Returns an array of PRINTER_INFO_2 data structures in the
4099 * lpbPrinters buffer. Note that according to MSDN also an
4100 * OpenPrinter should be performed on every remote printer.
4102 * If level is set to 4 (officially WinNT only):
4103 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4104 * Fast: Only the registry is queried to retrieve printer names,
4105 * no connection to the driver is made.
4106 * Returns an array of PRINTER_INFO_4 data structures in the
4107 * lpbPrinters buffer.
4109 * If level is set to 5 (officially WinNT4/Win9x only):
4110 * Fast: Only the registry is queried to retrieve printer names,
4111 * no connection to the driver is made.
4112 * Returns an array of PRINTER_INFO_5 data structures in the
4113 * lpbPrinters buffer.
4115 * If level set to 3 or 6+:
4116 * returns zero (failure!)
4118 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4122 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4123 * - Only levels 2, 4 and 5 are implemented at the moment.
4124 * - 16-bit printer drivers are not enumerated.
4125 * - Returned amount of bytes used/needed does not match the real Windoze
4126 * implementation (as in this implementation, all strings are part
4127 * of the buffer, whereas Win32 keeps them somewhere else)
4128 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4131 * - In a regular Wine installation, no registry settings for printers
4132 * exist, which makes this function return an empty list.
4134 BOOL WINAPI
EnumPrintersW(
4135 DWORD dwType
, /* [in] Types of print objects to enumerate */
4136 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4137 DWORD dwLevel
, /* [in] type of printer info structure */
4138 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4139 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4140 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4141 LPDWORD lpdwReturned
/* [out] number of entries returned */
4144 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4145 lpdwNeeded
, lpdwReturned
);
4148 /******************************************************************
4149 * EnumPrintersA [WINSPOOL.@]
4154 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4155 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4158 UNICODE_STRING pNameU
;
4162 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4163 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4165 pNameW
= asciitounicode(&pNameU
, pName
);
4167 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4168 MS Office need this */
4169 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4171 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4173 RtlFreeUnicodeString(&pNameU
);
4175 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4177 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4181 /*****************************************************************************
4182 * WINSPOOL_GetDriverInfoFromReg [internal]
4184 * Enters the information from the registry into the DRIVER_INFO struct
4187 * zero if the printer driver does not exist in the registry
4188 * (only if Level > 1) otherwise nonzero
4190 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4193 const printenv_t
* env
,
4195 LPBYTE ptr
, /* DRIVER_INFO */
4196 LPBYTE pDriverStrings
, /* strings buffer */
4197 DWORD cbBuf
, /* size of string buffer */
4198 LPDWORD pcbNeeded
) /* space needed for str. */
4202 WCHAR driverdir
[MAX_PATH
];
4204 LPBYTE strPtr
= pDriverStrings
;
4205 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4207 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4208 debugstr_w(DriverName
), env
,
4209 Level
, di
, pDriverStrings
, cbBuf
);
4211 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4213 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4214 if (*pcbNeeded
<= cbBuf
)
4215 strcpyW((LPWSTR
)strPtr
, DriverName
);
4217 /* pName for level 1 has a different offset! */
4219 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4223 /* .cVersion and .pName for level > 1 */
4225 di
->cVersion
= env
->driverversion
;
4226 di
->pName
= (LPWSTR
) strPtr
;
4227 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4230 /* Reserve Space for the largest subdir and a Backslash*/
4231 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4232 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4233 /* Should never Fail */
4236 lstrcatW(driverdir
, env
->versionsubdir
);
4237 lstrcatW(driverdir
, backslashW
);
4239 /* dirlen must not include the terminating zero */
4240 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4242 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4243 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4244 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4249 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4252 if (*pcbNeeded
<= cbBuf
) {
4253 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4254 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4255 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4258 /* .pDriverPath is the Graphics rendering engine.
4259 The full Path is required to avoid a crash in some apps */
4260 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4262 if (*pcbNeeded
<= cbBuf
)
4263 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4265 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4266 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4269 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4270 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4272 if (*pcbNeeded
<= cbBuf
)
4273 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4275 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4276 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4279 /* .pConfigFile is the Driver user Interface */
4280 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4282 if (*pcbNeeded
<= cbBuf
)
4283 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4285 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4286 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4290 RegCloseKey(hkeyDriver
);
4291 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4296 RegCloseKey(hkeyDriver
);
4297 FIXME("level 5: incomplete\n");
4302 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4304 if (*pcbNeeded
<= cbBuf
)
4305 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4307 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4308 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4311 /* .pDependentFiles */
4312 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4314 if (*pcbNeeded
<= cbBuf
)
4315 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4317 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4318 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4320 else if (GetVersion() & 0x80000000) {
4321 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4322 size
= 2 * sizeof(WCHAR
);
4324 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4326 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4327 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4330 /* .pMonitorName is the optional Language Monitor */
4331 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4333 if (*pcbNeeded
<= cbBuf
)
4334 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4336 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4337 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4340 /* .pDefaultDataType */
4341 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4343 if(*pcbNeeded
<= cbBuf
)
4344 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4346 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4347 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4351 RegCloseKey(hkeyDriver
);
4352 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4356 /* .pszzPreviousNames */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4359 if(*pcbNeeded
<= cbBuf
)
4360 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4362 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4363 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4367 RegCloseKey(hkeyDriver
);
4368 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4372 /* support is missing, but not important enough for a FIXME */
4373 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4376 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4378 if(*pcbNeeded
<= cbBuf
)
4379 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4381 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4382 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4386 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4388 if(*pcbNeeded
<= cbBuf
)
4389 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4391 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4392 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4395 /* .pszHardwareID */
4396 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4398 if(*pcbNeeded
<= cbBuf
)
4399 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4401 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4402 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4406 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4408 if(*pcbNeeded
<= cbBuf
)
4409 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4411 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4412 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4416 RegCloseKey(hkeyDriver
);
4420 /* support is missing, but not important enough for a FIXME */
4421 TRACE("level 8: incomplete\n");
4423 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4424 RegCloseKey(hkeyDriver
);
4428 /*****************************************************************************
4429 * GetPrinterDriverW [WINSPOOL.@]
4431 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4432 DWORD Level
, LPBYTE pDriverInfo
,
4433 DWORD cbBuf
, LPDWORD pcbNeeded
)
4436 WCHAR DriverName
[100];
4437 DWORD ret
, type
, size
, needed
= 0;
4439 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4440 const printenv_t
* env
;
4442 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4443 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4446 ZeroMemory(pDriverInfo
, cbBuf
);
4448 if (!(name
= get_opened_printer_name(hPrinter
))) {
4449 SetLastError(ERROR_INVALID_HANDLE
);
4453 if (Level
< 1 || Level
== 7 || Level
> 8) {
4454 SetLastError(ERROR_INVALID_LEVEL
);
4458 env
= validate_envW(pEnvironment
);
4459 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4461 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4463 ERR("Can't create Printers key\n");
4466 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4468 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4469 RegCloseKey(hkeyPrinters
);
4470 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4473 size
= sizeof(DriverName
);
4475 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4476 (LPBYTE
)DriverName
, &size
);
4477 RegCloseKey(hkeyPrinter
);
4478 RegCloseKey(hkeyPrinters
);
4479 if(ret
!= ERROR_SUCCESS
) {
4480 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4484 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4486 ERR("Can't create Drivers key\n");
4490 size
= di_sizeof
[Level
];
4491 if ((size
<= cbBuf
) && pDriverInfo
)
4492 ptr
= pDriverInfo
+ size
;
4494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4495 env
, Level
, pDriverInfo
, ptr
,
4496 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4498 RegCloseKey(hkeyDrivers
);
4502 RegCloseKey(hkeyDrivers
);
4504 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4505 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4506 if(cbBuf
>= size
+ needed
) return TRUE
;
4507 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4511 /*****************************************************************************
4512 * GetPrinterDriverA [WINSPOOL.@]
4514 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4515 DWORD Level
, LPBYTE pDriverInfo
,
4516 DWORD cbBuf
, LPDWORD pcbNeeded
)
4519 UNICODE_STRING pEnvW
;
4525 ZeroMemory(pDriverInfo
, cbBuf
);
4526 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4529 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4530 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4533 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4535 HeapFree(GetProcessHeap(), 0, buf
);
4537 RtlFreeUnicodeString(&pEnvW
);
4541 /*****************************************************************************
4542 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4544 * Return the PATH for the Printer-Drivers (UNICODE)
4547 * pName [I] Servername (NT only) or NULL (local Computer)
4548 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4549 * Level [I] Structure-Level (must be 1)
4550 * pDriverDirectory [O] PTR to Buffer that receives the Result
4551 * cbBuf [I] Size of Buffer at pDriverDirectory
4552 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4553 * required for pDriverDirectory
4556 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4557 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4558 * if cbBuf is too small
4560 * Native Values returned in pDriverDirectory on Success:
4561 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4562 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4563 *| win9x(Windows 4.0): "%winsysdir%"
4565 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4568 *- Only NULL or "" is supported for pName
4571 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4572 DWORD Level
, LPBYTE pDriverDirectory
,
4573 DWORD cbBuf
, LPDWORD pcbNeeded
)
4575 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4576 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4578 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4581 /* (Level != 1) is ignored in win9x */
4582 SetLastError(ERROR_INVALID_LEVEL
);
4585 if (pcbNeeded
== NULL
) {
4586 /* (pcbNeeded == NULL) is ignored in win9x */
4587 SetLastError(RPC_X_NULL_REF_POINTER
);
4591 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4592 pDriverDirectory
, cbBuf
, pcbNeeded
);
4597 /*****************************************************************************
4598 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4600 * Return the PATH for the Printer-Drivers (ANSI)
4602 * See GetPrinterDriverDirectoryW.
4605 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4608 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4609 DWORD Level
, LPBYTE pDriverDirectory
,
4610 DWORD cbBuf
, LPDWORD pcbNeeded
)
4612 UNICODE_STRING nameW
, environmentW
;
4615 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4616 WCHAR
*driverDirectoryW
= NULL
;
4618 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4619 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4621 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4623 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4624 else nameW
.Buffer
= NULL
;
4625 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4626 else environmentW
.Buffer
= NULL
;
4628 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4629 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4632 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4633 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4635 *pcbNeeded
= needed
;
4636 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4638 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4640 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4642 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4643 RtlFreeUnicodeString(&environmentW
);
4644 RtlFreeUnicodeString(&nameW
);
4649 /*****************************************************************************
4650 * AddPrinterDriverA [WINSPOOL.@]
4652 * See AddPrinterDriverW.
4655 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4657 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4658 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4661 /******************************************************************************
4662 * AddPrinterDriverW (WINSPOOL.@)
4664 * Install a Printer Driver
4667 * pName [I] Servername or NULL (local Computer)
4668 * level [I] Level for the supplied DRIVER_INFO_*W struct
4669 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4676 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4678 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4679 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4682 /*****************************************************************************
4683 * AddPrintProcessorA [WINSPOOL.@]
4685 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4686 LPSTR pPrintProcessorName
)
4688 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4689 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4693 /*****************************************************************************
4694 * AddPrintProcessorW [WINSPOOL.@]
4696 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4697 LPWSTR pPrintProcessorName
)
4699 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4700 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4704 /*****************************************************************************
4705 * AddPrintProvidorA [WINSPOOL.@]
4707 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4709 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4713 /*****************************************************************************
4714 * AddPrintProvidorW [WINSPOOL.@]
4716 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4718 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4722 /*****************************************************************************
4723 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4725 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4726 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4728 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4729 pDevModeOutput
, pDevModeInput
);
4733 /*****************************************************************************
4734 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4736 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4737 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4739 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4740 pDevModeOutput
, pDevModeInput
);
4744 /*****************************************************************************
4745 * PrinterProperties [WINSPOOL.@]
4747 * Displays a dialog to set the properties of the printer.
4750 * nonzero on success or zero on failure
4753 * implemented as stub only
4755 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4756 HANDLE hPrinter
/* [in] handle to printer object */
4758 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4759 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4763 /*****************************************************************************
4764 * EnumJobsA [WINSPOOL.@]
4767 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4768 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4771 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4772 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4774 if(pcbNeeded
) *pcbNeeded
= 0;
4775 if(pcReturned
) *pcReturned
= 0;
4780 /*****************************************************************************
4781 * EnumJobsW [WINSPOOL.@]
4784 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4785 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4788 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4789 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4791 if(pcbNeeded
) *pcbNeeded
= 0;
4792 if(pcReturned
) *pcReturned
= 0;
4796 /*****************************************************************************
4797 * WINSPOOL_EnumPrinterDrivers [internal]
4799 * Delivers information about all printer drivers installed on the
4800 * localhost or a given server
4803 * nonzero on success or zero on failure. If the buffer for the returned
4804 * information is too small the function will return an error
4807 * - only implemented for localhost, foreign hosts will return an error
4809 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4810 DWORD Level
, LPBYTE pDriverInfo
,
4812 DWORD cbBuf
, LPDWORD pcbNeeded
,
4813 LPDWORD pcFound
, DWORD data_offset
)
4817 const printenv_t
* env
;
4819 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4820 debugstr_w(pName
), debugstr_w(pEnvironment
),
4821 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4823 env
= validate_envW(pEnvironment
);
4824 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4828 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4830 ERR("Can't open Drivers key\n");
4834 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4835 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4836 RegCloseKey(hkeyDrivers
);
4837 ERR("Can't query Drivers key\n");
4840 TRACE("Found %d Drivers\n", *pcFound
);
4842 /* get size of single struct
4843 * unicode and ascii structure have the same size
4845 size
= di_sizeof
[Level
];
4847 if (data_offset
== 0)
4848 data_offset
= size
* (*pcFound
);
4849 *pcbNeeded
= data_offset
;
4851 for( i
= 0; i
< *pcFound
; i
++) {
4852 WCHAR DriverNameW
[255];
4853 PBYTE table_ptr
= NULL
;
4854 PBYTE data_ptr
= NULL
;
4857 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4859 ERR("Can't enum key number %d\n", i
);
4860 RegCloseKey(hkeyDrivers
);
4864 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4865 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4866 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4867 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4869 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4870 env
, Level
, table_ptr
, data_ptr
,
4871 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4873 RegCloseKey(hkeyDrivers
);
4877 *pcbNeeded
+= needed
;
4880 RegCloseKey(hkeyDrivers
);
4882 if(cbBuf
< *pcbNeeded
){
4883 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4890 /*****************************************************************************
4891 * EnumPrinterDriversW [WINSPOOL.@]
4893 * see function EnumPrinterDrivers for RETURNS, BUGS
4895 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4896 LPBYTE pDriverInfo
, DWORD cbBuf
,
4897 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4899 static const WCHAR allW
[] = {'a','l','l',0};
4903 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4905 SetLastError(RPC_X_NULL_REF_POINTER
);
4909 /* check for local drivers */
4910 if((pName
) && (pName
[0])) {
4911 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4912 SetLastError(ERROR_ACCESS_DENIED
);
4916 /* check input parameter */
4917 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4918 SetLastError(ERROR_INVALID_LEVEL
);
4922 if(pDriverInfo
&& cbBuf
> 0)
4923 memset( pDriverInfo
, 0, cbBuf
);
4925 /* Exception: pull all printers */
4926 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4928 DWORD i
, needed
, bufsize
= cbBuf
;
4929 DWORD total_needed
= 0;
4930 DWORD total_found
= 0;
4933 /* Precompute the overall total; we need this to know
4934 where pointers end and data begins (i.e. data_offset) */
4935 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4938 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4939 NULL
, 0, 0, &needed
, &found
, 0);
4940 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4941 total_needed
+= needed
;
4942 total_found
+= found
;
4945 data_offset
= di_sizeof
[Level
] * total_found
;
4950 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4953 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4954 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4955 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4957 *pcReturned
+= found
;
4958 *pcbNeeded
= needed
;
4959 data_offset
= needed
;
4960 total_found
+= found
;
4965 /* Normal behavior */
4966 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4967 0, cbBuf
, pcbNeeded
, &found
, 0);
4969 *pcReturned
= found
;
4974 /*****************************************************************************
4975 * EnumPrinterDriversA [WINSPOOL.@]
4977 * see function EnumPrinterDrivers for RETURNS, BUGS
4979 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4980 LPBYTE pDriverInfo
, DWORD cbBuf
,
4981 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4984 UNICODE_STRING pNameW
, pEnvironmentW
;
4985 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4989 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4991 pwstrNameW
= asciitounicode(&pNameW
, pName
);
4992 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
4994 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
4995 buf
, cbBuf
, pcbNeeded
, pcReturned
);
4997 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
4999 HeapFree(GetProcessHeap(), 0, buf
);
5001 RtlFreeUnicodeString(&pNameW
);
5002 RtlFreeUnicodeString(&pEnvironmentW
);
5007 /******************************************************************************
5008 * EnumPortsA (WINSPOOL.@)
5013 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5014 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5017 LPBYTE bufferW
= NULL
;
5018 LPWSTR nameW
= NULL
;
5020 DWORD numentries
= 0;
5023 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5024 cbBuf
, pcbNeeded
, pcReturned
);
5026 /* convert servername to unicode */
5028 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5029 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5030 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5032 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5033 needed
= cbBuf
* sizeof(WCHAR
);
5034 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5035 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5037 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5038 if (pcbNeeded
) needed
= *pcbNeeded
;
5039 /* HeapReAlloc return NULL, when bufferW was NULL */
5040 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5041 HeapAlloc(GetProcessHeap(), 0, needed
);
5043 /* Try again with the large Buffer */
5044 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5046 needed
= pcbNeeded
? *pcbNeeded
: 0;
5047 numentries
= pcReturned
? *pcReturned
: 0;
5050 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5051 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5054 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5055 DWORD entrysize
= 0;
5058 LPPORT_INFO_2W pi2w
;
5059 LPPORT_INFO_2A pi2a
;
5062 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5064 /* First pass: calculate the size for all Entries */
5065 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5066 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5068 while (index
< numentries
) {
5070 needed
+= entrysize
; /* PORT_INFO_?A */
5071 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5073 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5074 NULL
, 0, NULL
, NULL
);
5076 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5077 NULL
, 0, NULL
, NULL
);
5078 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5079 NULL
, 0, NULL
, NULL
);
5081 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5082 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5083 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5086 /* check for errors and quit on failure */
5087 if (cbBuf
< needed
) {
5088 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5092 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5093 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5094 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5095 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5096 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5098 /* Second Pass: Fill the User Buffer (if we have one) */
5099 while ((index
< numentries
) && pPorts
) {
5101 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5102 pi2a
->pPortName
= ptr
;
5103 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5104 ptr
, cbBuf
, NULL
, NULL
);
5108 pi2a
->pMonitorName
= ptr
;
5109 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5110 ptr
, cbBuf
, NULL
, NULL
);
5114 pi2a
->pDescription
= ptr
;
5115 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5116 ptr
, cbBuf
, NULL
, NULL
);
5120 pi2a
->fPortType
= pi2w
->fPortType
;
5121 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5124 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5125 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5126 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5131 if (pcbNeeded
) *pcbNeeded
= needed
;
5132 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5134 HeapFree(GetProcessHeap(), 0, nameW
);
5135 HeapFree(GetProcessHeap(), 0, bufferW
);
5137 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5138 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5144 /******************************************************************************
5145 * EnumPortsW (WINSPOOL.@)
5147 * Enumerate available Ports
5150 * pName [I] Servername or NULL (local Computer)
5151 * Level [I] Structure-Level (1 or 2)
5152 * pPorts [O] PTR to Buffer that receives the Result
5153 * cbBuf [I] Size of Buffer at pPorts
5154 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5155 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5159 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5162 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5165 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5166 cbBuf
, pcbNeeded
, pcReturned
);
5168 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5170 /* Level is not checked in win9x */
5171 if (!Level
|| (Level
> 2)) {
5172 WARN("level (%d) is ignored in win9x\n", Level
);
5173 SetLastError(ERROR_INVALID_LEVEL
);
5176 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5177 SetLastError(RPC_X_NULL_REF_POINTER
);
5181 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5184 /******************************************************************************
5185 * GetDefaultPrinterW (WINSPOOL.@)
5188 * This function must read the value from data 'device' of key
5189 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5191 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5195 WCHAR
*buffer
, *ptr
;
5199 SetLastError(ERROR_INVALID_PARAMETER
);
5203 /* make the buffer big enough for the stuff from the profile/registry,
5204 * the content must fit into the local buffer to compute the correct
5205 * size even if the extern buffer is too small or not given.
5206 * (20 for ,driver,port) */
5208 len
= max(100, (insize
+ 20));
5209 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5211 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5213 SetLastError (ERROR_FILE_NOT_FOUND
);
5217 TRACE("%s\n", debugstr_w(buffer
));
5219 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5221 SetLastError(ERROR_INVALID_NAME
);
5227 *namesize
= strlenW(buffer
) + 1;
5228 if(!name
|| (*namesize
> insize
))
5230 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5234 strcpyW(name
, buffer
);
5237 HeapFree( GetProcessHeap(), 0, buffer
);
5242 /******************************************************************************
5243 * GetDefaultPrinterA (WINSPOOL.@)
5245 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5249 WCHAR
*bufferW
= NULL
;
5253 SetLastError(ERROR_INVALID_PARAMETER
);
5257 if(name
&& *namesize
) {
5259 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5262 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5267 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5271 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5274 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5277 HeapFree( GetProcessHeap(), 0, bufferW
);
5282 /******************************************************************************
5283 * SetDefaultPrinterW (WINSPOOL.204)
5285 * Set the Name of the Default Printer
5288 * pszPrinter [I] Name of the Printer or NULL
5295 * When the Parameter is NULL or points to an Empty String and
5296 * a Default Printer was already present, then this Function changes nothing.
5297 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5298 * the First enumerated local Printer is used.
5301 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5303 WCHAR default_printer
[MAX_PATH
];
5304 LPWSTR buffer
= NULL
;
5310 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5311 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5313 default_printer
[0] = '\0';
5314 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5316 /* if we have a default Printer, do nothing. */
5317 if (GetDefaultPrinterW(default_printer
, &size
))
5321 /* we have no default Printer: search local Printers and use the first */
5322 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5324 default_printer
[0] = '\0';
5325 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5326 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5328 pszPrinter
= default_printer
;
5329 TRACE("using %s\n", debugstr_w(pszPrinter
));
5334 if (pszPrinter
== NULL
) {
5335 TRACE("no local printer found\n");
5336 SetLastError(ERROR_FILE_NOT_FOUND
);
5341 /* "pszPrinter" is never empty or NULL here. */
5342 namelen
= lstrlenW(pszPrinter
);
5343 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5344 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5346 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5347 HeapFree(GetProcessHeap(), 0, buffer
);
5348 SetLastError(ERROR_FILE_NOT_FOUND
);
5352 /* read the devices entry for the printer (driver,port) to build the string for the
5353 default device entry (printer,driver,port) */
5354 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5355 buffer
[namelen
] = ',';
5356 namelen
++; /* move index to the start of the driver */
5358 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5359 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5361 TRACE("set device to %s\n", debugstr_w(buffer
));
5363 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5364 TRACE("failed to set the device entry: %d\n", GetLastError());
5365 lres
= ERROR_INVALID_PRINTER_NAME
;
5368 /* remove the next section, when INIFileMapping is implemented */
5371 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5372 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5379 if (lres
!= ERROR_FILE_NOT_FOUND
)
5380 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5382 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5386 HeapFree(GetProcessHeap(), 0, buffer
);
5387 return (lres
== ERROR_SUCCESS
);
5390 /******************************************************************************
5391 * SetDefaultPrinterA (WINSPOOL.202)
5393 * See SetDefaultPrinterW.
5396 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5398 LPWSTR bufferW
= NULL
;
5401 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5403 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5404 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5405 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5407 res
= SetDefaultPrinterW(bufferW
);
5408 HeapFree(GetProcessHeap(), 0, bufferW
);
5412 /******************************************************************************
5413 * SetPrinterDataExA (WINSPOOL.@)
5415 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5416 LPCSTR pValueName
, DWORD Type
,
5417 LPBYTE pData
, DWORD cbData
)
5419 HKEY hkeyPrinter
, hkeySubkey
;
5422 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5423 debugstr_a(pValueName
), Type
, pData
, cbData
);
5425 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5429 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5431 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5432 RegCloseKey(hkeyPrinter
);
5435 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5436 RegCloseKey(hkeySubkey
);
5437 RegCloseKey(hkeyPrinter
);
5441 /******************************************************************************
5442 * SetPrinterDataExW (WINSPOOL.@)
5444 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5445 LPCWSTR pValueName
, DWORD Type
,
5446 LPBYTE pData
, DWORD cbData
)
5448 HKEY hkeyPrinter
, hkeySubkey
;
5451 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5452 debugstr_w(pValueName
), Type
, pData
, cbData
);
5454 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5458 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5460 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5461 RegCloseKey(hkeyPrinter
);
5464 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5465 RegCloseKey(hkeySubkey
);
5466 RegCloseKey(hkeyPrinter
);
5470 /******************************************************************************
5471 * SetPrinterDataA (WINSPOOL.@)
5473 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5474 LPBYTE pData
, DWORD cbData
)
5476 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5480 /******************************************************************************
5481 * SetPrinterDataW (WINSPOOL.@)
5483 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5484 LPBYTE pData
, DWORD cbData
)
5486 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5490 /******************************************************************************
5491 * GetPrinterDataExA (WINSPOOL.@)
5493 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5494 LPCSTR pValueName
, LPDWORD pType
,
5495 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5497 opened_printer_t
*printer
;
5498 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5501 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5502 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5504 printer
= get_opened_printer(hPrinter
);
5505 if(!printer
) return ERROR_INVALID_HANDLE
;
5507 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5508 if (ret
) return ret
;
5510 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5512 if (printer
->name
) {
5514 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5516 RegCloseKey(hkeyPrinters
);
5519 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5520 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5521 RegCloseKey(hkeyPrinter
);
5522 RegCloseKey(hkeyPrinters
);
5527 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5528 0, pType
, pData
, pcbNeeded
);
5530 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5532 RegCloseKey(hkeySubkey
);
5533 RegCloseKey(hkeyPrinter
);
5534 RegCloseKey(hkeyPrinters
);
5536 TRACE("--> %d\n", ret
);
5540 /******************************************************************************
5541 * GetPrinterDataExW (WINSPOOL.@)
5543 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5544 LPCWSTR pValueName
, LPDWORD pType
,
5545 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5547 opened_printer_t
*printer
;
5548 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5551 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5552 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5554 printer
= get_opened_printer(hPrinter
);
5555 if(!printer
) return ERROR_INVALID_HANDLE
;
5557 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5558 if (ret
) return ret
;
5560 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5562 if (printer
->name
) {
5564 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5566 RegCloseKey(hkeyPrinters
);
5569 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5570 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5571 RegCloseKey(hkeyPrinter
);
5572 RegCloseKey(hkeyPrinters
);
5577 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5578 0, pType
, pData
, pcbNeeded
);
5580 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5582 RegCloseKey(hkeySubkey
);
5583 RegCloseKey(hkeyPrinter
);
5584 RegCloseKey(hkeyPrinters
);
5586 TRACE("--> %d\n", ret
);
5590 /******************************************************************************
5591 * GetPrinterDataA (WINSPOOL.@)
5593 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5594 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5596 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5597 pData
, nSize
, pcbNeeded
);
5600 /******************************************************************************
5601 * GetPrinterDataW (WINSPOOL.@)
5603 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5604 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5606 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5607 pData
, nSize
, pcbNeeded
);
5610 /*******************************************************************************
5611 * EnumPrinterDataExW [WINSPOOL.@]
5613 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5614 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5615 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5617 HKEY hkPrinter
, hkSubKey
;
5618 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5619 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5624 PPRINTER_ENUM_VALUESW ppev
;
5626 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5628 if (pKeyName
== NULL
|| *pKeyName
== 0)
5629 return ERROR_INVALID_PARAMETER
;
5631 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5632 if (ret
!= ERROR_SUCCESS
)
5634 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5639 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5640 if (ret
!= ERROR_SUCCESS
)
5642 r
= RegCloseKey (hkPrinter
);
5643 if (r
!= ERROR_SUCCESS
)
5644 WARN ("RegCloseKey returned %i\n", r
);
5645 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5646 debugstr_w (pKeyName
), ret
);
5650 ret
= RegCloseKey (hkPrinter
);
5651 if (ret
!= ERROR_SUCCESS
)
5653 ERR ("RegCloseKey returned %i\n", ret
);
5654 r
= RegCloseKey (hkSubKey
);
5655 if (r
!= ERROR_SUCCESS
)
5656 WARN ("RegCloseKey returned %i\n", r
);
5660 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5661 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5662 if (ret
!= ERROR_SUCCESS
)
5664 r
= RegCloseKey (hkSubKey
);
5665 if (r
!= ERROR_SUCCESS
)
5666 WARN ("RegCloseKey returned %i\n", r
);
5667 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5671 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5672 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5674 if (cValues
== 0) /* empty key */
5676 r
= RegCloseKey (hkSubKey
);
5677 if (r
!= ERROR_SUCCESS
)
5678 WARN ("RegCloseKey returned %i\n", r
);
5679 *pcbEnumValues
= *pnEnumValues
= 0;
5680 return ERROR_SUCCESS
;
5683 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5685 hHeap
= GetProcessHeap ();
5688 ERR ("GetProcessHeap failed\n");
5689 r
= RegCloseKey (hkSubKey
);
5690 if (r
!= ERROR_SUCCESS
)
5691 WARN ("RegCloseKey returned %i\n", r
);
5692 return ERROR_OUTOFMEMORY
;
5695 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5696 if (lpValueName
== NULL
)
5698 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5699 r
= RegCloseKey (hkSubKey
);
5700 if (r
!= ERROR_SUCCESS
)
5701 WARN ("RegCloseKey returned %i\n", r
);
5702 return ERROR_OUTOFMEMORY
;
5705 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5706 if (lpValue
== NULL
)
5708 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5709 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5710 WARN ("HeapFree failed with code %i\n", GetLastError ());
5711 r
= RegCloseKey (hkSubKey
);
5712 if (r
!= ERROR_SUCCESS
)
5713 WARN ("RegCloseKey returned %i\n", r
);
5714 return ERROR_OUTOFMEMORY
;
5717 TRACE ("pass 1: calculating buffer required for all names and values\n");
5719 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5721 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5723 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5725 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5726 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5727 NULL
, NULL
, lpValue
, &cbValueLen
);
5728 if (ret
!= ERROR_SUCCESS
)
5730 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5731 WARN ("HeapFree failed with code %i\n", GetLastError ());
5732 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5733 WARN ("HeapFree failed with code %i\n", GetLastError ());
5734 r
= RegCloseKey (hkSubKey
);
5735 if (r
!= ERROR_SUCCESS
)
5736 WARN ("RegCloseKey returned %i\n", r
);
5737 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5741 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5742 debugstr_w (lpValueName
), dwIndex
,
5743 cbValueNameLen
+ 1, cbValueLen
);
5745 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5746 cbBufSize
+= cbValueLen
;
5749 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5751 *pcbEnumValues
= cbBufSize
;
5752 *pnEnumValues
= cValues
;
5754 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5756 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5757 WARN ("HeapFree failed with code %i\n", GetLastError ());
5758 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5759 WARN ("HeapFree failed with code %i\n", GetLastError ());
5760 r
= RegCloseKey (hkSubKey
);
5761 if (r
!= ERROR_SUCCESS
)
5762 WARN ("RegCloseKey returned %i\n", r
);
5763 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5764 return ERROR_MORE_DATA
;
5767 TRACE ("pass 2: copying all names and values to buffer\n");
5769 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5770 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5772 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5774 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5775 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5776 NULL
, &dwType
, lpValue
, &cbValueLen
);
5777 if (ret
!= ERROR_SUCCESS
)
5779 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5780 WARN ("HeapFree failed with code %i\n", GetLastError ());
5781 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5782 WARN ("HeapFree failed with code %i\n", GetLastError ());
5783 r
= RegCloseKey (hkSubKey
);
5784 if (r
!= ERROR_SUCCESS
)
5785 WARN ("RegCloseKey returned %i\n", r
);
5786 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5790 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5791 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5792 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5793 pEnumValues
+= cbValueNameLen
;
5795 /* return # of *bytes* (including trailing \0), not # of chars */
5796 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5798 ppev
[dwIndex
].dwType
= dwType
;
5800 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5801 ppev
[dwIndex
].pData
= pEnumValues
;
5802 pEnumValues
+= cbValueLen
;
5804 ppev
[dwIndex
].cbData
= cbValueLen
;
5806 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5807 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5810 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5812 ret
= GetLastError ();
5813 ERR ("HeapFree failed with code %i\n", ret
);
5814 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5815 WARN ("HeapFree failed with code %i\n", GetLastError ());
5816 r
= RegCloseKey (hkSubKey
);
5817 if (r
!= ERROR_SUCCESS
)
5818 WARN ("RegCloseKey returned %i\n", r
);
5822 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5824 ret
= GetLastError ();
5825 ERR ("HeapFree failed with code %i\n", ret
);
5826 r
= RegCloseKey (hkSubKey
);
5827 if (r
!= ERROR_SUCCESS
)
5828 WARN ("RegCloseKey returned %i\n", r
);
5832 ret
= RegCloseKey (hkSubKey
);
5833 if (ret
!= ERROR_SUCCESS
)
5835 ERR ("RegCloseKey returned %i\n", ret
);
5839 return ERROR_SUCCESS
;
5842 /*******************************************************************************
5843 * EnumPrinterDataExA [WINSPOOL.@]
5845 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5846 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5847 * what Windows 2000 SP1 does.
5850 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5851 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5852 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5856 DWORD ret
, dwIndex
, dwBufSize
;
5860 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5862 if (pKeyName
== NULL
|| *pKeyName
== 0)
5863 return ERROR_INVALID_PARAMETER
;
5865 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5868 ret
= GetLastError ();
5869 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5873 hHeap
= GetProcessHeap ();
5876 ERR ("GetProcessHeap failed\n");
5877 return ERROR_OUTOFMEMORY
;
5880 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5881 if (pKeyNameW
== NULL
)
5883 ERR ("Failed to allocate %i bytes from process heap\n",
5884 (LONG
)(len
* sizeof (WCHAR
)));
5885 return ERROR_OUTOFMEMORY
;
5888 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5890 ret
= GetLastError ();
5891 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5892 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5893 WARN ("HeapFree failed with code %i\n", GetLastError ());
5897 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5898 pcbEnumValues
, pnEnumValues
);
5899 if (ret
!= ERROR_SUCCESS
)
5901 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5907 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5909 ret
= GetLastError ();
5910 ERR ("HeapFree failed with code %i\n", ret
);
5914 if (*pnEnumValues
== 0) /* empty key */
5915 return ERROR_SUCCESS
;
5918 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5920 PPRINTER_ENUM_VALUESW ppev
=
5921 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5923 if (dwBufSize
< ppev
->cbValueName
)
5924 dwBufSize
= ppev
->cbValueName
;
5926 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5927 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5928 dwBufSize
= ppev
->cbData
;
5931 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5933 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5934 if (pBuffer
== NULL
)
5936 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5937 return ERROR_OUTOFMEMORY
;
5940 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5942 PPRINTER_ENUM_VALUESW ppev
=
5943 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5945 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5946 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5950 ret
= GetLastError ();
5951 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5952 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5953 WARN ("HeapFree failed with code %i\n", GetLastError ());
5957 memcpy (ppev
->pValueName
, pBuffer
, len
);
5959 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5961 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5962 ppev
->dwType
!= REG_MULTI_SZ
)
5965 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5966 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, 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
->pData
, pBuffer
, len
);
5978 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5979 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5982 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5984 ret
= GetLastError ();
5985 ERR ("HeapFree failed with code %i\n", ret
);
5989 return ERROR_SUCCESS
;
5992 /******************************************************************************
5993 * AbortPrinter (WINSPOOL.@)
5995 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5997 FIXME("(%p), stub!\n", hPrinter
);
6001 /******************************************************************************
6002 * AddPortA (WINSPOOL.@)
6007 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6009 LPWSTR nameW
= NULL
;
6010 LPWSTR monitorW
= NULL
;
6014 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6017 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6018 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6019 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6023 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6024 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6025 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6027 res
= AddPortW(nameW
, hWnd
, monitorW
);
6028 HeapFree(GetProcessHeap(), 0, nameW
);
6029 HeapFree(GetProcessHeap(), 0, monitorW
);
6033 /******************************************************************************
6034 * AddPortW (WINSPOOL.@)
6036 * Add a Port for a specific Monitor
6039 * pName [I] Servername or NULL (local Computer)
6040 * hWnd [I] Handle to parent Window for the Dialog-Box
6041 * pMonitorName [I] Name of the Monitor that manage the Port
6048 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6050 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6052 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6054 if (!pMonitorName
) {
6055 SetLastError(RPC_X_NULL_REF_POINTER
);
6059 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6062 /******************************************************************************
6063 * AddPortExA (WINSPOOL.@)
6068 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6071 PORT_INFO_2A
* pi2A
;
6072 LPWSTR nameW
= NULL
;
6073 LPWSTR monitorW
= NULL
;
6077 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6079 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6080 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6082 if ((level
< 1) || (level
> 2)) {
6083 SetLastError(ERROR_INVALID_LEVEL
);
6088 SetLastError(ERROR_INVALID_PARAMETER
);
6093 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6094 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6095 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6099 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6100 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6101 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6104 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6106 if (pi2A
->pPortName
) {
6107 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6108 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6109 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6113 if (pi2A
->pMonitorName
) {
6114 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6115 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6116 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6119 if (pi2A
->pDescription
) {
6120 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6121 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6122 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6124 pi2W
.fPortType
= pi2A
->fPortType
;
6125 pi2W
.Reserved
= pi2A
->Reserved
;
6128 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6130 HeapFree(GetProcessHeap(), 0, nameW
);
6131 HeapFree(GetProcessHeap(), 0, monitorW
);
6132 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6133 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6134 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6139 /******************************************************************************
6140 * AddPortExW (WINSPOOL.@)
6142 * Add a Port for a specific Monitor, without presenting a user interface
6145 * pName [I] Servername or NULL (local Computer)
6146 * level [I] Structure-Level (1 or 2) for pBuffer
6147 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6148 * pMonitorName [I] Name of the Monitor that manage the Port
6155 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6159 pi2
= (PORT_INFO_2W
*) pBuffer
;
6161 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6162 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6163 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6164 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6166 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6168 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6169 SetLastError(ERROR_INVALID_PARAMETER
);
6173 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6176 /******************************************************************************
6177 * AddPrinterConnectionA (WINSPOOL.@)
6179 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6181 FIXME("%s\n", debugstr_a(pName
));
6185 /******************************************************************************
6186 * AddPrinterConnectionW (WINSPOOL.@)
6188 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6190 FIXME("%s\n", debugstr_w(pName
));
6194 /******************************************************************************
6195 * AddPrinterDriverExW (WINSPOOL.@)
6197 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6200 * pName [I] Servername or NULL (local Computer)
6201 * level [I] Level for the supplied DRIVER_INFO_*W struct
6202 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6203 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6210 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6212 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6214 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6216 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6217 SetLastError(ERROR_INVALID_LEVEL
);
6222 SetLastError(ERROR_INVALID_PARAMETER
);
6226 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6229 /******************************************************************************
6230 * AddPrinterDriverExA (WINSPOOL.@)
6232 * See AddPrinterDriverExW.
6235 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6237 DRIVER_INFO_8A
*diA
;
6239 LPWSTR nameW
= NULL
;
6244 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6246 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6247 ZeroMemory(&diW
, sizeof(diW
));
6249 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6250 SetLastError(ERROR_INVALID_LEVEL
);
6255 SetLastError(ERROR_INVALID_PARAMETER
);
6259 /* convert servername to unicode */
6261 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6262 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6263 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6267 diW
.cVersion
= diA
->cVersion
;
6270 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6271 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6272 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6275 if (diA
->pEnvironment
) {
6276 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6277 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6278 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6281 if (diA
->pDriverPath
) {
6282 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6283 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6284 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6287 if (diA
->pDataFile
) {
6288 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6289 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6290 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6293 if (diA
->pConfigFile
) {
6294 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6295 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6296 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6299 if ((Level
> 2) && diA
->pDependentFiles
) {
6300 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6301 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6302 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6303 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6306 if ((Level
> 2) && diA
->pMonitorName
) {
6307 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6308 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6309 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6312 if ((Level
> 3) && diA
->pDefaultDataType
) {
6313 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6314 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6315 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6318 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6319 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6320 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6321 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6322 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6325 if ((Level
> 5) && diA
->pszMfgName
) {
6326 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6327 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6328 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6331 if ((Level
> 5) && diA
->pszOEMUrl
) {
6332 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6333 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6334 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6337 if ((Level
> 5) && diA
->pszHardwareID
) {
6338 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6339 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6340 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6343 if ((Level
> 5) && diA
->pszProvider
) {
6344 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6345 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6346 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6350 FIXME("level %u is incomplete\n", Level
);
6353 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6354 TRACE("got %u with %u\n", res
, GetLastError());
6355 HeapFree(GetProcessHeap(), 0, nameW
);
6356 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6357 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6358 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6359 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6360 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6361 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6362 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6363 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6364 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6365 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6366 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6367 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6368 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6370 TRACE("=> %u with %u\n", res
, GetLastError());
6374 /******************************************************************************
6375 * ConfigurePortA (WINSPOOL.@)
6377 * See ConfigurePortW.
6380 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6382 LPWSTR nameW
= NULL
;
6383 LPWSTR portW
= NULL
;
6387 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6389 /* convert servername to unicode */
6391 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6392 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6393 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6396 /* convert portname to unicode */
6398 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6399 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6400 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6403 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6404 HeapFree(GetProcessHeap(), 0, nameW
);
6405 HeapFree(GetProcessHeap(), 0, portW
);
6409 /******************************************************************************
6410 * ConfigurePortW (WINSPOOL.@)
6412 * Display the Configuration-Dialog for a specific Port
6415 * pName [I] Servername or NULL (local Computer)
6416 * hWnd [I] Handle to parent Window for the Dialog-Box
6417 * pPortName [I] Name of the Port, that should be configured
6424 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6427 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6429 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6432 SetLastError(RPC_X_NULL_REF_POINTER
);
6436 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6439 /******************************************************************************
6440 * ConnectToPrinterDlg (WINSPOOL.@)
6442 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6444 FIXME("%p %x\n", hWnd
, Flags
);
6448 /******************************************************************************
6449 * DeletePrinterConnectionA (WINSPOOL.@)
6451 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6453 FIXME("%s\n", debugstr_a(pName
));
6457 /******************************************************************************
6458 * DeletePrinterConnectionW (WINSPOOL.@)
6460 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6462 FIXME("%s\n", debugstr_w(pName
));
6466 /******************************************************************************
6467 * DeletePrinterDriverExW (WINSPOOL.@)
6469 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6470 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6475 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6476 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6478 if(pName
&& pName
[0])
6480 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6481 SetLastError(ERROR_INVALID_PARAMETER
);
6487 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6488 SetLastError(ERROR_INVALID_PARAMETER
);
6492 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6496 ERR("Can't open drivers key\n");
6500 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6503 RegCloseKey(hkey_drivers
);
6508 /******************************************************************************
6509 * DeletePrinterDriverExA (WINSPOOL.@)
6511 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6512 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6514 UNICODE_STRING NameW
, EnvW
, DriverW
;
6517 asciitounicode(&NameW
, pName
);
6518 asciitounicode(&EnvW
, pEnvironment
);
6519 asciitounicode(&DriverW
, pDriverName
);
6521 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6523 RtlFreeUnicodeString(&DriverW
);
6524 RtlFreeUnicodeString(&EnvW
);
6525 RtlFreeUnicodeString(&NameW
);
6530 /******************************************************************************
6531 * DeletePrinterDataExW (WINSPOOL.@)
6533 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6536 FIXME("%p %s %s\n", hPrinter
,
6537 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6538 return ERROR_INVALID_PARAMETER
;
6541 /******************************************************************************
6542 * DeletePrinterDataExA (WINSPOOL.@)
6544 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6547 FIXME("%p %s %s\n", hPrinter
,
6548 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6549 return ERROR_INVALID_PARAMETER
;
6552 /******************************************************************************
6553 * DeletePrintProcessorA (WINSPOOL.@)
6555 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6557 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6558 debugstr_a(pPrintProcessorName
));
6562 /******************************************************************************
6563 * DeletePrintProcessorW (WINSPOOL.@)
6565 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6567 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6568 debugstr_w(pPrintProcessorName
));
6572 /******************************************************************************
6573 * DeletePrintProvidorA (WINSPOOL.@)
6575 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6577 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6578 debugstr_a(pPrintProviderName
));
6582 /******************************************************************************
6583 * DeletePrintProvidorW (WINSPOOL.@)
6585 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6587 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6588 debugstr_w(pPrintProviderName
));
6592 /******************************************************************************
6593 * EnumFormsA (WINSPOOL.@)
6595 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6596 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6598 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6599 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6603 /******************************************************************************
6604 * EnumFormsW (WINSPOOL.@)
6606 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6607 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6609 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6614 /*****************************************************************************
6615 * EnumMonitorsA [WINSPOOL.@]
6617 * See EnumMonitorsW.
6620 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6621 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6624 LPBYTE bufferW
= NULL
;
6625 LPWSTR nameW
= NULL
;
6627 DWORD numentries
= 0;
6630 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6631 cbBuf
, pcbNeeded
, pcReturned
);
6633 /* convert servername to unicode */
6635 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6636 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6637 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6639 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6640 needed
= cbBuf
* sizeof(WCHAR
);
6641 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6642 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6644 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6645 if (pcbNeeded
) needed
= *pcbNeeded
;
6646 /* HeapReAlloc return NULL, when bufferW was NULL */
6647 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6648 HeapAlloc(GetProcessHeap(), 0, needed
);
6650 /* Try again with the large Buffer */
6651 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6653 numentries
= pcReturned
? *pcReturned
: 0;
6656 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6657 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6660 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6661 DWORD entrysize
= 0;
6664 LPMONITOR_INFO_2W mi2w
;
6665 LPMONITOR_INFO_2A mi2a
;
6667 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6668 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6670 /* First pass: calculate the size for all Entries */
6671 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6672 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6674 while (index
< numentries
) {
6676 needed
+= entrysize
; /* MONITOR_INFO_?A */
6677 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6679 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6680 NULL
, 0, NULL
, NULL
);
6682 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6683 NULL
, 0, NULL
, NULL
);
6684 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6685 NULL
, 0, NULL
, NULL
);
6687 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6688 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6689 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6692 /* check for errors and quit on failure */
6693 if (cbBuf
< needed
) {
6694 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6698 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6699 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6700 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6701 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6702 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6704 /* Second Pass: Fill the User Buffer (if we have one) */
6705 while ((index
< numentries
) && pMonitors
) {
6707 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6709 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6710 ptr
, cbBuf
, NULL
, NULL
);
6714 mi2a
->pEnvironment
= ptr
;
6715 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6716 ptr
, cbBuf
, NULL
, NULL
);
6720 mi2a
->pDLLName
= ptr
;
6721 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6722 ptr
, cbBuf
, NULL
, NULL
);
6726 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6727 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6728 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6732 if (pcbNeeded
) *pcbNeeded
= needed
;
6733 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6735 HeapFree(GetProcessHeap(), 0, nameW
);
6736 HeapFree(GetProcessHeap(), 0, bufferW
);
6738 TRACE("returning %d with %d (%d byte for %d entries)\n",
6739 (res
), GetLastError(), needed
, numentries
);
6745 /*****************************************************************************
6746 * EnumMonitorsW [WINSPOOL.@]
6748 * Enumerate available Port-Monitors
6751 * pName [I] Servername or NULL (local Computer)
6752 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6753 * pMonitors [O] PTR to Buffer that receives the Result
6754 * cbBuf [I] Size of Buffer at pMonitors
6755 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6756 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6760 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6763 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6764 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6767 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6768 cbBuf
, pcbNeeded
, pcReturned
);
6770 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6772 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6773 SetLastError(RPC_X_NULL_REF_POINTER
);
6777 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6780 /******************************************************************************
6781 * SpoolerInit (WINSPOOL.@)
6783 * Initialize the Spooler
6790 * The function fails on windows, when the spooler service is not running
6793 BOOL WINAPI
SpoolerInit(void)
6796 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6800 /******************************************************************************
6801 * XcvDataW (WINSPOOL.@)
6803 * Execute commands in the Printmonitor DLL
6806 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6807 * pszDataName [i] Name of the command to execute
6808 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6809 * cbInputData [i] Size in Bytes of Buffer at pInputData
6810 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6811 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6812 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6813 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6820 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6821 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6823 * Minimal List of commands, that a Printmonitor DLL should support:
6825 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6826 *| "AddPort" : Add a Port
6827 *| "DeletePort": Delete a Port
6829 * Many Printmonitors support additional commands. Examples for localspl.dll:
6830 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6831 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6834 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6835 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6836 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6838 opened_printer_t
*printer
;
6840 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6841 pInputData
, cbInputData
, pOutputData
,
6842 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6844 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6846 printer
= get_opened_printer(hXcv
);
6847 if (!printer
|| (!printer
->backend_printer
)) {
6848 SetLastError(ERROR_INVALID_HANDLE
);
6852 if (!pcbOutputNeeded
) {
6853 SetLastError(ERROR_INVALID_PARAMETER
);
6857 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6858 SetLastError(RPC_X_NULL_REF_POINTER
);
6862 *pcbOutputNeeded
= 0;
6864 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6865 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6869 /*****************************************************************************
6870 * EnumPrinterDataA [WINSPOOL.@]
6873 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6874 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6875 DWORD cbData
, LPDWORD pcbData
)
6877 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6878 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6879 return ERROR_NO_MORE_ITEMS
;
6882 /*****************************************************************************
6883 * EnumPrinterDataW [WINSPOOL.@]
6886 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6887 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6888 DWORD cbData
, LPDWORD pcbData
)
6890 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6891 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6892 return ERROR_NO_MORE_ITEMS
;
6895 /*****************************************************************************
6896 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6899 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6900 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6901 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6903 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6904 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6905 pcbNeeded
, pcReturned
);
6909 /*****************************************************************************
6910 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6913 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6914 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6915 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6917 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6918 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6919 pcbNeeded
, pcReturned
);
6923 /*****************************************************************************
6924 * EnumPrintProcessorsA [WINSPOOL.@]
6926 * See EnumPrintProcessorsW.
6929 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6930 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6933 LPBYTE bufferW
= NULL
;
6934 LPWSTR nameW
= NULL
;
6937 DWORD numentries
= 0;
6940 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6941 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6943 /* convert names to unicode */
6945 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6946 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6947 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6950 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6951 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6952 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6955 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6956 needed
= cbBuf
* sizeof(WCHAR
);
6957 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6958 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6960 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6961 if (pcbNeeded
) needed
= *pcbNeeded
;
6962 /* HeapReAlloc return NULL, when bufferW was NULL */
6963 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6964 HeapAlloc(GetProcessHeap(), 0, needed
);
6966 /* Try again with the large Buffer */
6967 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6969 numentries
= pcReturned
? *pcReturned
: 0;
6973 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6976 PPRINTPROCESSOR_INFO_1W ppiw
;
6977 PPRINTPROCESSOR_INFO_1A ppia
;
6979 /* First pass: calculate the size for all Entries */
6980 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6981 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6983 while (index
< numentries
) {
6985 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
6986 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
6988 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6989 NULL
, 0, NULL
, NULL
);
6991 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
6992 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
6995 /* check for errors and quit on failure */
6996 if (cbBuf
< needed
) {
6997 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7002 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7003 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7004 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7005 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7006 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7008 /* Second Pass: Fill the User Buffer (if we have one) */
7009 while ((index
< numentries
) && pPPInfo
) {
7011 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7013 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7014 ptr
, cbBuf
, NULL
, NULL
);
7018 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7019 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7024 if (pcbNeeded
) *pcbNeeded
= needed
;
7025 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7027 HeapFree(GetProcessHeap(), 0, nameW
);
7028 HeapFree(GetProcessHeap(), 0, envW
);
7029 HeapFree(GetProcessHeap(), 0, bufferW
);
7031 TRACE("returning %d with %d (%d byte for %d entries)\n",
7032 (res
), GetLastError(), needed
, numentries
);
7037 /*****************************************************************************
7038 * EnumPrintProcessorsW [WINSPOOL.@]
7040 * Enumerate available Print Processors
7043 * pName [I] Servername or NULL (local Computer)
7044 * pEnvironment [I] Printing-Environment or NULL (Default)
7045 * Level [I] Structure-Level (Only 1 is allowed)
7046 * pPPInfo [O] PTR to Buffer that receives the Result
7047 * cbBuf [I] Size of Buffer at pPPInfo
7048 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7049 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7053 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7056 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7057 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7060 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7061 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7063 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7065 if (!pcbNeeded
|| !pcReturned
) {
7066 SetLastError(RPC_X_NULL_REF_POINTER
);
7070 if (!pPPInfo
&& (cbBuf
> 0)) {
7071 SetLastError(ERROR_INVALID_USER_BUFFER
);
7075 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7076 cbBuf
, pcbNeeded
, pcReturned
);
7079 /*****************************************************************************
7080 * ExtDeviceMode [WINSPOOL.@]
7083 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7084 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7087 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7088 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7089 debugstr_a(pProfile
), fMode
);
7093 /*****************************************************************************
7094 * FindClosePrinterChangeNotification [WINSPOOL.@]
7097 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7099 FIXME("Stub: %p\n", hChange
);
7103 /*****************************************************************************
7104 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7107 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7108 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7110 FIXME("Stub: %p %x %x %p\n",
7111 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7112 return INVALID_HANDLE_VALUE
;
7115 /*****************************************************************************
7116 * FindNextPrinterChangeNotification [WINSPOOL.@]
7119 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7120 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7122 FIXME("Stub: %p %p %p %p\n",
7123 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7127 /*****************************************************************************
7128 * FreePrinterNotifyInfo [WINSPOOL.@]
7131 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7133 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7137 /*****************************************************************************
7140 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7141 * ansi depending on the unicode parameter.
7143 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7153 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7156 memcpy(ptr
, str
, *size
);
7163 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7166 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7173 /*****************************************************************************
7176 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7177 LPDWORD pcbNeeded
, BOOL unicode
)
7179 DWORD size
, left
= cbBuf
;
7180 BOOL space
= (cbBuf
> 0);
7187 ji1
->JobId
= job
->job_id
;
7190 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7191 if(space
&& size
<= left
)
7193 ji1
->pDocument
= (LPWSTR
)ptr
;
7201 if (job
->printer_name
)
7203 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7204 if(space
&& size
<= left
)
7206 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7218 /*****************************************************************************
7221 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7222 LPDWORD pcbNeeded
, BOOL unicode
)
7224 DWORD size
, left
= cbBuf
;
7226 BOOL space
= (cbBuf
> 0);
7228 LPDEVMODEA dmA
= NULL
;
7235 ji2
->JobId
= job
->job_id
;
7238 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7239 if(space
&& size
<= left
)
7241 ji2
->pDocument
= (LPWSTR
)ptr
;
7249 if (job
->printer_name
)
7251 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7252 if(space
&& size
<= left
)
7254 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7267 dmA
= DEVMODEdupWtoA(job
->devmode
);
7268 devmode
= (LPDEVMODEW
) dmA
;
7269 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7273 devmode
= job
->devmode
;
7274 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7278 FIXME("Can't convert DEVMODE W to A\n");
7281 /* align DEVMODE to a DWORD boundary */
7282 shift
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
7288 memcpy(ptr
, devmode
, size
-shift
);
7289 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7290 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7303 /*****************************************************************************
7306 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7307 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7310 DWORD needed
= 0, size
;
7314 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7316 EnterCriticalSection(&printer_handles_cs
);
7317 job
= get_job(hPrinter
, JobId
);
7324 size
= sizeof(JOB_INFO_1W
);
7329 memset(pJob
, 0, size
);
7333 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7338 size
= sizeof(JOB_INFO_2W
);
7343 memset(pJob
, 0, size
);
7347 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7352 size
= sizeof(JOB_INFO_3
);
7356 memset(pJob
, 0, size
);
7365 SetLastError(ERROR_INVALID_LEVEL
);
7369 *pcbNeeded
= needed
;
7371 LeaveCriticalSection(&printer_handles_cs
);
7375 /*****************************************************************************
7376 * GetJobA [WINSPOOL.@]
7379 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7380 DWORD cbBuf
, LPDWORD pcbNeeded
)
7382 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7385 /*****************************************************************************
7386 * GetJobW [WINSPOOL.@]
7389 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7390 DWORD cbBuf
, LPDWORD pcbNeeded
)
7392 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7395 /*****************************************************************************
7398 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7401 char *unixname
, *cmdA
;
7403 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7407 if(!(unixname
= wine_get_unix_file_name(filename
)))
7410 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7411 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7412 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7414 TRACE("printing with: %s\n", cmdA
);
7416 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7421 ERR("pipe() failed!\n");
7431 /* reset signals that we previously set to SIG_IGN */
7432 signal(SIGPIPE
, SIG_DFL
);
7433 signal(SIGCHLD
, SIG_DFL
);
7435 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7439 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7440 write(fds
[1], buf
, no_read
);
7445 if(file_fd
!= -1) close(file_fd
);
7446 if(fds
[0] != -1) close(fds
[0]);
7447 if(fds
[1] != -1) close(fds
[1]);
7449 HeapFree(GetProcessHeap(), 0, cmdA
);
7450 HeapFree(GetProcessHeap(), 0, unixname
);
7457 /*****************************************************************************
7460 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7463 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7466 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7467 sprintfW(cmd
, fmtW
, printer_name
);
7469 r
= schedule_pipe(cmd
, filename
);
7471 HeapFree(GetProcessHeap(), 0, cmd
);
7475 /*****************************************************************************
7478 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7480 #ifdef SONAME_LIBCUPS
7483 char *unixname
, *queue
, *unix_doc_title
;
7487 if(!(unixname
= wine_get_unix_file_name(filename
)))
7490 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7491 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7492 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7494 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7495 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7496 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7498 TRACE("printing via cups\n");
7499 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7500 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7501 HeapFree(GetProcessHeap(), 0, queue
);
7502 HeapFree(GetProcessHeap(), 0, unixname
);
7508 return schedule_lpr(printer_name
, filename
);
7512 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7519 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7523 if(HIWORD(wparam
) == BN_CLICKED
)
7525 if(LOWORD(wparam
) == IDOK
)
7528 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7531 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7532 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7534 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7536 WCHAR caption
[200], message
[200];
7539 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7540 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7541 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7542 if(mb_ret
== IDCANCEL
)
7544 HeapFree(GetProcessHeap(), 0, filename
);
7548 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7549 if(hf
== INVALID_HANDLE_VALUE
)
7551 WCHAR caption
[200], message
[200];
7553 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7554 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7555 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7556 HeapFree(GetProcessHeap(), 0, filename
);
7560 DeleteFileW(filename
);
7561 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7563 EndDialog(hwnd
, IDOK
);
7566 if(LOWORD(wparam
) == IDCANCEL
)
7568 EndDialog(hwnd
, IDCANCEL
);
7577 /*****************************************************************************
7580 static BOOL
get_filename(LPWSTR
*filename
)
7582 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7583 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7586 /*****************************************************************************
7589 static BOOL
schedule_file(LPCWSTR filename
)
7591 LPWSTR output
= NULL
;
7593 if(get_filename(&output
))
7596 TRACE("copy to %s\n", debugstr_w(output
));
7597 r
= CopyFileW(filename
, output
, FALSE
);
7598 HeapFree(GetProcessHeap(), 0, output
);
7604 /*****************************************************************************
7607 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7609 int in_fd
, out_fd
, no_read
;
7612 char *unixname
, *outputA
;
7615 if(!(unixname
= wine_get_unix_file_name(filename
)))
7618 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7619 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7620 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7622 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7623 in_fd
= open(unixname
, O_RDONLY
);
7624 if(out_fd
== -1 || in_fd
== -1)
7627 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7628 write(out_fd
, buf
, no_read
);
7632 if(in_fd
!= -1) close(in_fd
);
7633 if(out_fd
!= -1) close(out_fd
);
7634 HeapFree(GetProcessHeap(), 0, outputA
);
7635 HeapFree(GetProcessHeap(), 0, unixname
);
7639 /*****************************************************************************
7640 * ScheduleJob [WINSPOOL.@]
7643 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7645 opened_printer_t
*printer
;
7647 struct list
*cursor
, *cursor2
;
7649 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7650 EnterCriticalSection(&printer_handles_cs
);
7651 printer
= get_opened_printer(hPrinter
);
7655 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7657 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7660 if(job
->job_id
!= dwJobID
) continue;
7662 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7663 if(hf
!= INVALID_HANDLE_VALUE
)
7665 PRINTER_INFO_5W
*pi5
= NULL
;
7666 LPWSTR portname
= job
->portname
;
7670 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7671 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7675 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7676 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7677 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7678 portname
= pi5
->pPortName
;
7680 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7681 debugstr_w(portname
));
7685 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7686 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7688 DWORD type
, count
= sizeof(output
);
7689 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7692 if(output
[0] == '|')
7694 ret
= schedule_pipe(output
+ 1, job
->filename
);
7698 ret
= schedule_unixfile(output
, job
->filename
);
7700 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7702 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7704 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7706 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7708 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7710 ret
= schedule_file(job
->filename
);
7714 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7716 HeapFree(GetProcessHeap(), 0, pi5
);
7718 DeleteFileW(job
->filename
);
7720 list_remove(cursor
);
7721 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7722 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7723 HeapFree(GetProcessHeap(), 0, job
->portname
);
7724 HeapFree(GetProcessHeap(), 0, job
->filename
);
7725 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7726 HeapFree(GetProcessHeap(), 0, job
);
7730 LeaveCriticalSection(&printer_handles_cs
);
7734 /*****************************************************************************
7735 * StartDocDlgA [WINSPOOL.@]
7737 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7739 UNICODE_STRING usBuffer
;
7742 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7745 docW
.cbSize
= sizeof(docW
);
7746 if (doc
->lpszDocName
)
7748 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7749 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7751 if (doc
->lpszOutput
)
7753 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7754 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7756 if (doc
->lpszDatatype
)
7758 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7759 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7761 docW
.fwType
= doc
->fwType
;
7763 retW
= StartDocDlgW(hPrinter
, &docW
);
7767 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7768 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7769 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7770 HeapFree(GetProcessHeap(), 0, retW
);
7773 HeapFree(GetProcessHeap(), 0, datatypeW
);
7774 HeapFree(GetProcessHeap(), 0, outputW
);
7775 HeapFree(GetProcessHeap(), 0, docnameW
);
7780 /*****************************************************************************
7781 * StartDocDlgW [WINSPOOL.@]
7783 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7784 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7785 * port is "FILE:". Also returns the full path if passed a relative path.
7787 * The caller should free the returned string from the process heap.
7789 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7794 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7796 PRINTER_INFO_5W
*pi5
;
7797 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7798 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7800 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7801 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7802 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7804 HeapFree(GetProcessHeap(), 0, pi5
);
7807 HeapFree(GetProcessHeap(), 0, pi5
);
7810 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7814 if (get_filename(&name
))
7816 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7818 HeapFree(GetProcessHeap(), 0, name
);
7821 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7822 GetFullPathNameW(name
, len
, ret
, NULL
);
7823 HeapFree(GetProcessHeap(), 0, name
);
7828 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7831 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7832 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7834 attr
= GetFileAttributesW(ret
);
7835 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7837 HeapFree(GetProcessHeap(), 0, ret
);