4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs
;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
75 0, 0, &printer_handles_cs
,
76 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
77 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer
;
107 WCHAR
*document_title
;
117 LPCWSTR versionregpath
;
118 LPCWSTR versionsubdir
;
121 /* ############################### */
123 static opened_printer_t
**printer_handles
;
124 static UINT nb_printer_handles
;
125 static LONG next_job_id
= 1;
127 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
128 WORD fwCapability
, LPSTR lpszOutput
,
130 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
131 LPSTR lpszDevice
, LPSTR lpszPort
,
132 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
135 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
186 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW
[] = {'\\',0};
188 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW
[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW
[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW
[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW
[] = {'R','A','W',0};
222 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW
[] = {',',0};
226 static WCHAR emptyStringW
[] = {0};
228 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
238 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
239 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
240 0, sizeof(DRIVER_INFO_8W
)};
243 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
244 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
245 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
246 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
247 sizeof(PRINTER_INFO_9W
)};
249 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
250 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
251 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
253 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
259 * env [I] PTR to Environment-String or NULL
263 * Success: PTR to printenv_t
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t
* validate_envW(LPCWSTR env
)
273 const printenv_t
*result
= NULL
;
276 TRACE("testing %s\n", debugstr_w(env
));
279 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
281 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
283 result
= all_printenv
[i
];
288 if (result
== NULL
) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
290 SetLastError(ERROR_INVALID_ENVIRONMENT
);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
298 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
312 return usBufferPtr
->Buffer
;
314 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR
strdupW(LPCWSTR p
)
324 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
325 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
330 static LPSTR
strdupWtoA( LPCWSTR str
)
335 if (!str
) return NULL
;
336 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
337 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
338 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
342 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
346 if (!dm
) return NULL
;
347 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
348 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
352 /***********************************************************
354 * Creates an ansi copy of supplied devmode
356 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
361 if (!dmW
) return NULL
;
362 size
= dmW
->dmSize
- CCHDEVICENAME
-
363 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
365 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
366 if (!dmA
) return NULL
;
368 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
369 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
371 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
373 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
374 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
378 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
379 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
380 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
381 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
383 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
387 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
392 /******************************************************************
393 * verify, that the filename is a local file
396 static inline BOOL
is_local_file(LPWSTR name
)
398 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
401 /* ################################ */
403 static int multi_sz_lenA(const char *str
)
405 const char *ptr
= str
;
409 ptr
+= lstrlenA(ptr
) + 1;
412 return ptr
- str
+ 1;
416 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
419 /* If forcing, or no profile string entry for device yet, set the entry
421 * The always change entry if not WINEPS yet is discussable.
424 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
426 !strstr(qbuf
,"WINEPS.DRV")
428 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
431 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
432 WriteProfileStringA("windows","device",buf
);
433 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
434 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
437 HeapFree(GetProcessHeap(),0,buf
);
441 static BOOL
add_printer_driver(WCHAR
*name
)
445 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
448 di3
.pEnvironment
= envname_x86W
;
449 di3
.pDriverPath
= driver_nt
;
450 di3
.pDataFile
= generic_ppdW
;
451 di3
.pConfigFile
= driver_nt
;
452 di3
.pDefaultDataType
= rawW
;
454 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
458 di3
.pEnvironment
= envname_win40W
;
459 di3
.pDriverPath
= driver_9x
;
460 di3
.pConfigFile
= driver_9x
;
461 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
471 #ifdef SONAME_LIBCUPS
473 static void *cupshandle
;
476 DO_FUNC(cupsFreeDests); \
477 DO_FUNC(cupsFreeOptions); \
478 DO_FUNC(cupsGetDests); \
479 DO_FUNC(cupsGetPPD); \
480 DO_FUNC(cupsParseOptions); \
481 DO_FUNC(cupsPrintFile);
483 #define DO_FUNC(f) static typeof(f) *p##f
487 static BOOL
CUPS_LoadPrinters(void)
490 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
494 HKEY hkeyPrinter
, hkeyPrinters
;
496 WCHAR nameW
[MAX_PATH
];
497 HANDLE added_printer
;
499 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
501 TRACE("%s\n", loaderror
);
504 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
506 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
512 ERR("Can't create Printers key\n");
516 nrofdests
= pcupsGetDests(&dests
);
517 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
518 for (i
=0;i
<nrofdests
;i
++) {
519 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
521 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
522 lstrcpyW(port
, CUPS_Port
);
523 lstrcatW(port
, nameW
);
525 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
526 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
527 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
529 TRACE("Printer already exists\n");
530 /* overwrite old LPR:* port */
531 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
532 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
533 RegCloseKey(hkeyPrinter
);
535 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
536 ' ','u','s','i','n','g',' ','C','U','P','S',0};
538 add_printer_driver(nameW
);
540 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
541 pi2
.pPrinterName
= nameW
;
542 pi2
.pDatatype
= rawW
;
543 pi2
.pPrintProcessor
= WinPrintW
;
544 pi2
.pDriverName
= nameW
;
545 pi2
.pComment
= comment_cups
;
546 pi2
.pLocation
= emptyStringW
;
547 pi2
.pPortName
= port
;
548 pi2
.pParameters
= emptyStringW
;
549 pi2
.pShareName
= emptyStringW
;
550 pi2
.pSepFile
= emptyStringW
;
552 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
553 if (added_printer
) ClosePrinter( added_printer
);
554 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
555 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
557 HeapFree(GetProcessHeap(),0,port
);
560 if (dests
[i
].is_default
) {
561 SetDefaultPrinterW(nameW
);
565 if (hadprinter
&& !haddefault
) {
566 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
567 SetDefaultPrinterW(nameW
);
569 pcupsFreeDests(nrofdests
, dests
);
570 RegCloseKey(hkeyPrinters
);
575 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
577 PRINTER_INFO_2A pinfo2a
;
580 char *e
,*s
,*name
,*prettyname
,*devname
;
581 BOOL ret
= FALSE
, set_default
= FALSE
;
582 char *port
= NULL
, *env_default
;
583 HKEY hkeyPrinter
, hkeyPrinters
;
584 WCHAR devnameW
[MAX_PATH
];
585 HANDLE added_printer
;
587 while (isspace(*pent
)) pent
++;
588 r
= strchr(pent
,':');
592 name_len
= strlen(pent
);
593 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
594 memcpy(name
, pent
, name_len
);
595 name
[name_len
] = '\0';
601 TRACE("name=%s entry=%s\n",name
, pent
);
603 if(ispunct(*name
)) { /* a tc entry, not a real printer */
604 TRACE("skipping tc entry\n");
608 if(strstr(pent
,":server")) { /* server only version so skip */
609 TRACE("skipping server entry\n");
613 /* Determine whether this is a postscript printer. */
616 env_default
= getenv("PRINTER");
618 /* Get longest name, usually the one at the right for later display. */
619 while((s
=strchr(prettyname
,'|'))) {
622 while(isspace(*--e
)) *e
= '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname
));
624 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
625 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
628 e
= prettyname
+ strlen(prettyname
);
629 while(isspace(*--e
)) *e
= '\0';
630 TRACE("\t%s\n", debugstr_a(prettyname
));
631 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
633 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
634 * if it is too long, we use it as comment below. */
635 devname
= prettyname
;
636 if (strlen(devname
)>=CCHDEVICENAME
-1)
638 if (strlen(devname
)>=CCHDEVICENAME
-1) {
643 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
644 sprintf(port
,"LPR:%s",name
);
646 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
648 ERR("Can't create Printers key\n");
653 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
655 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
656 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
658 TRACE("Printer already exists\n");
659 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
660 RegCloseKey(hkeyPrinter
);
662 static CHAR data_type
[] = "RAW",
663 print_proc
[] = "WinPrint",
664 comment
[] = "WINEPS Printer using LPR",
665 params
[] = "<parameters?>",
666 share_name
[] = "<share name?>",
667 sep_file
[] = "<sep file?>";
669 add_printer_driver(devnameW
);
671 memset(&pinfo2a
,0,sizeof(pinfo2a
));
672 pinfo2a
.pPrinterName
= devname
;
673 pinfo2a
.pDatatype
= data_type
;
674 pinfo2a
.pPrintProcessor
= print_proc
;
675 pinfo2a
.pDriverName
= devname
;
676 pinfo2a
.pComment
= comment
;
677 pinfo2a
.pLocation
= prettyname
;
678 pinfo2a
.pPortName
= port
;
679 pinfo2a
.pParameters
= params
;
680 pinfo2a
.pShareName
= share_name
;
681 pinfo2a
.pSepFile
= sep_file
;
683 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
684 if (added_printer
) ClosePrinter( added_printer
);
685 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
686 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
688 RegCloseKey(hkeyPrinters
);
690 if (isfirst
|| set_default
)
691 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
694 HeapFree(GetProcessHeap(), 0, port
);
695 HeapFree(GetProcessHeap(), 0, name
);
700 PRINTCAP_LoadPrinters(void) {
701 BOOL hadprinter
= FALSE
;
705 BOOL had_bash
= FALSE
;
707 f
= fopen("/etc/printcap","r");
711 while(fgets(buf
,sizeof(buf
),f
)) {
714 end
=strchr(buf
,'\n');
718 while(isspace(*start
)) start
++;
719 if(*start
== '#' || *start
== '\0')
722 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
723 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
724 HeapFree(GetProcessHeap(),0,pent
);
728 if (end
&& *--end
== '\\') {
735 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
738 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
744 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
745 HeapFree(GetProcessHeap(),0,pent
);
751 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
754 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
755 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
757 return ERROR_FILE_NOT_FOUND
;
760 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
762 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
763 DWORD ret
= ERROR_FILE_NOT_FOUND
;
765 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
766 and we support these drivers. NT writes DEVMODEW so somehow
767 we'll need to distinguish between these when we support NT
772 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
773 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
774 HeapFree( GetProcessHeap(), 0, dmA
);
780 /******************************************************************
781 * get_servername_from_name (internal)
783 * for an external server, a copy of the serverpart from the full name is returned
786 static LPWSTR
get_servername_from_name(LPCWSTR name
)
790 WCHAR buffer
[MAX_PATH
];
793 if (name
== NULL
) return NULL
;
794 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
796 server
= strdupW(&name
[2]); /* skip over both backslash */
797 if (server
== NULL
) return NULL
;
799 /* strip '\' and the printername */
800 ptr
= strchrW(server
, '\\');
801 if (ptr
) ptr
[0] = '\0';
803 TRACE("found %s\n", debugstr_w(server
));
805 len
= sizeof(buffer
)/sizeof(buffer
[0]);
806 if (GetComputerNameW(buffer
, &len
)) {
807 if (lstrcmpW(buffer
, server
) == 0) {
808 /* The requested Servername is our computername */
809 HeapFree(GetProcessHeap(), 0, server
);
816 /******************************************************************
817 * get_basename_from_name (internal)
819 * skip over the serverpart from the full name
822 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
824 if (name
== NULL
) return NULL
;
825 if ((name
[0] == '\\') && (name
[1] == '\\')) {
826 /* skip over the servername and search for the following '\' */
827 name
= strchrW(&name
[2], '\\');
828 if ((name
) && (name
[1])) {
829 /* found a separator ('\') followed by a name:
830 skip over the separator and return the rest */
835 /* no basename present (we found only a servername) */
842 static void free_printer_entry( opened_printer_t
*printer
)
844 /* the queue is shared, so don't free that here */
845 HeapFree( GetProcessHeap(), 0, printer
->printername
);
846 HeapFree( GetProcessHeap(), 0, printer
->name
);
847 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
848 HeapFree( GetProcessHeap(), 0, printer
);
851 /******************************************************************
852 * get_opened_printer_entry
853 * Get the first place empty in the opened printer table
856 * - pDefault is ignored
858 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
860 UINT_PTR handle
= nb_printer_handles
, i
;
861 jobqueue_t
*queue
= NULL
;
862 opened_printer_t
*printer
= NULL
;
866 if ((backend
== NULL
) && !load_backend()) return NULL
;
868 servername
= get_servername_from_name(name
);
870 FIXME("server %s not supported\n", debugstr_w(servername
));
871 HeapFree(GetProcessHeap(), 0, servername
);
872 SetLastError(ERROR_INVALID_PRINTER_NAME
);
876 printername
= get_basename_from_name(name
);
877 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
879 /* an empty printername is invalid */
880 if (printername
&& (!printername
[0])) {
881 SetLastError(ERROR_INVALID_PARAMETER
);
885 EnterCriticalSection(&printer_handles_cs
);
887 for (i
= 0; i
< nb_printer_handles
; i
++)
889 if (!printer_handles
[i
])
891 if(handle
== nb_printer_handles
)
896 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
897 queue
= printer_handles
[i
]->queue
;
901 if (handle
>= nb_printer_handles
)
903 opened_printer_t
**new_array
;
905 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
906 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
908 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
909 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
916 printer_handles
= new_array
;
917 nb_printer_handles
+= 16;
920 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
926 /* get a printer handle from the backend */
927 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
932 /* clone the base name. This is NULL for the printserver */
933 printer
->printername
= strdupW(printername
);
935 /* clone the full name */
936 printer
->name
= strdupW(name
);
937 if (name
&& (!printer
->name
)) {
942 if (pDefault
&& pDefault
->pDevMode
)
943 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
946 printer
->queue
= queue
;
949 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
950 if (!printer
->queue
) {
954 list_init(&printer
->queue
->jobs
);
955 printer
->queue
->ref
= 0;
957 InterlockedIncrement(&printer
->queue
->ref
);
959 printer_handles
[handle
] = printer
;
962 LeaveCriticalSection(&printer_handles_cs
);
963 if (!handle
&& printer
) {
964 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
965 free_printer_entry( printer
);
968 return (HANDLE
)handle
;
971 /******************************************************************
973 * Get the pointer to the opened printer referred by the handle
975 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
977 UINT_PTR idx
= (UINT_PTR
)hprn
;
978 opened_printer_t
*ret
= NULL
;
980 EnterCriticalSection(&printer_handles_cs
);
982 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
983 ret
= printer_handles
[idx
- 1];
985 LeaveCriticalSection(&printer_handles_cs
);
989 /******************************************************************
990 * get_opened_printer_name
991 * Get the pointer to the opened printer name referred by the handle
993 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
995 opened_printer_t
*printer
= get_opened_printer(hprn
);
996 if(!printer
) return NULL
;
997 return printer
->name
;
1000 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
1006 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
1007 if (err
) return err
;
1009 err
= RegOpenKeyW( printers
, name
, key
);
1010 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
1011 RegCloseKey( printers
);
1015 /******************************************************************
1016 * WINSPOOL_GetOpenedPrinterRegKey
1019 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1021 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1023 if(!name
) return ERROR_INVALID_HANDLE
;
1024 return open_printer_reg_key( name
, phkey
);
1027 static void old_printer_check( BOOL delete_phase
)
1029 PRINTER_INFO_5W
* pi
;
1030 DWORD needed
, type
, num
, delete, i
, size
;
1031 const DWORD one
= 1;
1035 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1036 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1038 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1039 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1040 for (i
= 0; i
< num
; i
++)
1042 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1043 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1046 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1050 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1056 size
= sizeof( delete );
1057 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1061 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1062 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1064 DeletePrinter( hprn
);
1065 ClosePrinter( hprn
);
1067 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1071 HeapFree(GetProcessHeap(), 0, pi
);
1074 void WINSPOOL_LoadSystemPrinters(void)
1076 HKEY hkey
, hkeyPrinters
;
1077 DWORD needed
, num
, i
;
1078 WCHAR PrinterName
[256];
1081 /* This ensures that all printer entries have a valid Name value. If causes
1082 problems later if they don't. If one is found to be missed we create one
1083 and set it equal to the name of the key */
1084 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1085 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1086 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1087 for(i
= 0; i
< num
; i
++) {
1088 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1089 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1090 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1091 set_reg_szW(hkey
, NameW
, PrinterName
);
1098 RegCloseKey(hkeyPrinters
);
1101 old_printer_check( FALSE
);
1103 #ifdef SONAME_LIBCUPS
1104 done
= CUPS_LoadPrinters();
1107 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1108 PRINTCAP_LoadPrinters();
1110 old_printer_check( TRUE
);
1115 /******************************************************************
1118 * Get the pointer to the specified job.
1119 * Should hold the printer_handles_cs before calling.
1121 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1123 opened_printer_t
*printer
= get_opened_printer(hprn
);
1126 if(!printer
) return NULL
;
1127 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1129 if(job
->job_id
== JobId
)
1135 /***********************************************************
1138 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1141 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1144 Formname
= (dmA
->dmSize
> off_formname
);
1145 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1146 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1147 dmW
->dmDeviceName
, CCHDEVICENAME
);
1149 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1150 dmA
->dmSize
- CCHDEVICENAME
);
1152 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1153 off_formname
- CCHDEVICENAME
);
1154 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1155 dmW
->dmFormName
, CCHFORMNAME
);
1156 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1157 (off_formname
+ CCHFORMNAME
));
1160 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1161 dmA
->dmDriverExtra
);
1165 /******************************************************************
1166 * convert_printerinfo_W_to_A [internal]
1169 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1170 DWORD level
, DWORD outlen
, DWORD numentries
)
1176 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1178 len
= pi_sizeof
[level
] * numentries
;
1179 ptr
= (LPSTR
) out
+ len
;
1182 /* copy the numbers of all PRINTER_INFO_* first */
1183 memcpy(out
, pPrintersW
, len
);
1185 while (id
< numentries
) {
1189 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1190 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1192 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1193 if (piW
->pDescription
) {
1194 piA
->pDescription
= ptr
;
1195 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1196 ptr
, outlen
, NULL
, NULL
);
1202 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1203 ptr
, outlen
, NULL
, NULL
);
1207 if (piW
->pComment
) {
1208 piA
->pComment
= ptr
;
1209 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1210 ptr
, outlen
, NULL
, NULL
);
1219 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1220 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1223 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1224 if (piW
->pServerName
) {
1225 piA
->pServerName
= ptr
;
1226 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1227 ptr
, outlen
, NULL
, NULL
);
1231 if (piW
->pPrinterName
) {
1232 piA
->pPrinterName
= ptr
;
1233 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1234 ptr
, outlen
, NULL
, NULL
);
1238 if (piW
->pShareName
) {
1239 piA
->pShareName
= ptr
;
1240 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1241 ptr
, outlen
, NULL
, NULL
);
1245 if (piW
->pPortName
) {
1246 piA
->pPortName
= ptr
;
1247 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1248 ptr
, outlen
, NULL
, NULL
);
1252 if (piW
->pDriverName
) {
1253 piA
->pDriverName
= ptr
;
1254 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1255 ptr
, outlen
, NULL
, NULL
);
1259 if (piW
->pComment
) {
1260 piA
->pComment
= ptr
;
1261 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1262 ptr
, outlen
, NULL
, NULL
);
1266 if (piW
->pLocation
) {
1267 piA
->pLocation
= ptr
;
1268 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1269 ptr
, outlen
, NULL
, NULL
);
1274 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1276 /* align DEVMODEA to a DWORD boundary */
1277 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1281 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1282 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1283 memcpy(ptr
, dmA
, len
);
1284 HeapFree(GetProcessHeap(), 0, dmA
);
1290 if (piW
->pSepFile
) {
1291 piA
->pSepFile
= ptr
;
1292 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1293 ptr
, outlen
, NULL
, NULL
);
1297 if (piW
->pPrintProcessor
) {
1298 piA
->pPrintProcessor
= ptr
;
1299 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1300 ptr
, outlen
, NULL
, NULL
);
1304 if (piW
->pDatatype
) {
1305 piA
->pDatatype
= ptr
;
1306 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1307 ptr
, outlen
, NULL
, NULL
);
1311 if (piW
->pParameters
) {
1312 piA
->pParameters
= ptr
;
1313 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1314 ptr
, outlen
, NULL
, NULL
);
1318 if (piW
->pSecurityDescriptor
) {
1319 piA
->pSecurityDescriptor
= NULL
;
1320 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1327 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1328 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1330 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1332 if (piW
->pPrinterName
) {
1333 piA
->pPrinterName
= ptr
;
1334 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1335 ptr
, outlen
, NULL
, NULL
);
1339 if (piW
->pServerName
) {
1340 piA
->pServerName
= ptr
;
1341 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1342 ptr
, outlen
, NULL
, NULL
);
1351 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1352 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1354 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1356 if (piW
->pPrinterName
) {
1357 piA
->pPrinterName
= ptr
;
1358 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1359 ptr
, outlen
, NULL
, NULL
);
1363 if (piW
->pPortName
) {
1364 piA
->pPortName
= ptr
;
1365 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1366 ptr
, outlen
, NULL
, NULL
);
1373 case 6: /* 6A and 6W are the same structure */
1378 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1379 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1381 TRACE("(%u) #%u\n", level
, id
);
1382 if (piW
->pszObjectGUID
) {
1383 piA
->pszObjectGUID
= ptr
;
1384 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1385 ptr
, outlen
, NULL
, NULL
);
1394 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1395 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1398 TRACE("(%u) #%u\n", level
, id
);
1399 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1401 /* align DEVMODEA to a DWORD boundary */
1402 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1406 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1407 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1408 memcpy(ptr
, dmA
, len
);
1409 HeapFree(GetProcessHeap(), 0, dmA
);
1419 FIXME("for level %u\n", level
);
1421 pPrintersW
+= pi_sizeof
[level
];
1422 out
+= pi_sizeof
[level
];
1427 /******************************************************************
1428 * convert_driverinfo_W_to_A [internal]
1431 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1432 DWORD level
, DWORD outlen
, DWORD numentries
)
1438 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1440 len
= di_sizeof
[level
] * numentries
;
1441 ptr
= (LPSTR
) out
+ len
;
1444 /* copy the numbers of all PRINTER_INFO_* first */
1445 memcpy(out
, pDriversW
, len
);
1447 #define COPY_STRING(fld) \
1450 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1451 ptr += len; outlen -= len;\
1453 #define COPY_MULTIZ_STRING(fld) \
1454 { LPWSTR p = diW->fld; if (p){ \
1457 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1458 ptr += len; outlen -= len; p += len;\
1460 while(len > 1 && outlen > 0); \
1463 while (id
< numentries
)
1469 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1470 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1472 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1479 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1480 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) 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_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1494 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) 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
);
1511 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1512 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1514 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1517 COPY_STRING(pEnvironment
);
1518 COPY_STRING(pDriverPath
);
1519 COPY_STRING(pDataFile
);
1520 COPY_STRING(pConfigFile
);
1521 COPY_STRING(pHelpFile
);
1522 COPY_MULTIZ_STRING(pDependentFiles
);
1523 COPY_STRING(pMonitorName
);
1524 COPY_STRING(pDefaultDataType
);
1525 COPY_MULTIZ_STRING(pszzPreviousNames
);
1530 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1531 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1533 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1536 COPY_STRING(pEnvironment
);
1537 COPY_STRING(pDriverPath
);
1538 COPY_STRING(pDataFile
);
1539 COPY_STRING(pConfigFile
);
1544 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1545 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1547 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1550 COPY_STRING(pEnvironment
);
1551 COPY_STRING(pDriverPath
);
1552 COPY_STRING(pDataFile
);
1553 COPY_STRING(pConfigFile
);
1554 COPY_STRING(pHelpFile
);
1555 COPY_MULTIZ_STRING(pDependentFiles
);
1556 COPY_STRING(pMonitorName
);
1557 COPY_STRING(pDefaultDataType
);
1558 COPY_MULTIZ_STRING(pszzPreviousNames
);
1559 COPY_STRING(pszMfgName
);
1560 COPY_STRING(pszOEMUrl
);
1561 COPY_STRING(pszHardwareID
);
1562 COPY_STRING(pszProvider
);
1567 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1568 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1570 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1573 COPY_STRING(pEnvironment
);
1574 COPY_STRING(pDriverPath
);
1575 COPY_STRING(pDataFile
);
1576 COPY_STRING(pConfigFile
);
1577 COPY_STRING(pHelpFile
);
1578 COPY_MULTIZ_STRING(pDependentFiles
);
1579 COPY_STRING(pMonitorName
);
1580 COPY_STRING(pDefaultDataType
);
1581 COPY_MULTIZ_STRING(pszzPreviousNames
);
1582 COPY_STRING(pszMfgName
);
1583 COPY_STRING(pszOEMUrl
);
1584 COPY_STRING(pszHardwareID
);
1585 COPY_STRING(pszProvider
);
1586 COPY_STRING(pszPrintProcessor
);
1587 COPY_STRING(pszVendorSetup
);
1588 COPY_MULTIZ_STRING(pszzColorProfiles
);
1589 COPY_STRING(pszInfPath
);
1590 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1596 FIXME("for level %u\n", level
);
1599 pDriversW
+= di_sizeof
[level
];
1600 out
+= di_sizeof
[level
];
1605 #undef COPY_MULTIZ_STRING
1609 /***********************************************************
1612 static void *printer_info_AtoW( const void *data
, DWORD level
)
1615 UNICODE_STRING usBuffer
;
1617 if (!data
) return NULL
;
1619 if (level
< 1 || level
> 9) return NULL
;
1621 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
1622 if (!ret
) return NULL
;
1624 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
1630 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
1631 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
1633 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
1634 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
1635 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
1636 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
1637 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
1638 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
1639 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
1640 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1641 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
1642 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
1643 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
1644 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
1651 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
1652 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
1654 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1659 FIXME( "Unhandled level %d\n", level
);
1660 HeapFree( GetProcessHeap(), 0, ret
);
1667 /***********************************************************
1670 static void free_printer_info( void *data
, DWORD level
)
1678 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
1680 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
1681 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
1682 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
1683 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
1684 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
1685 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
1686 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
1687 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
1688 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
1689 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
1690 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
1691 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
1698 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
1700 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
1705 FIXME( "Unhandled level %d\n", level
);
1708 HeapFree( GetProcessHeap(), 0, data
);
1712 /******************************************************************
1713 * DeviceCapabilities [WINSPOOL.@]
1714 * DeviceCapabilitiesA [WINSPOOL.@]
1717 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1718 LPSTR pOutput
, LPDEVMODEA lpdm
)
1722 if (!GDI_CallDeviceCapabilities16
)
1724 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1726 if (!GDI_CallDeviceCapabilities16
) return -1;
1728 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1730 /* If DC_PAPERSIZE map POINT16s to POINTs */
1731 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1732 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1733 POINT
*pt
= (POINT
*)pOutput
;
1735 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1736 for(i
= 0; i
< ret
; i
++, pt
++)
1741 HeapFree( GetProcessHeap(), 0, tmp
);
1747 /*****************************************************************************
1748 * DeviceCapabilitiesW [WINSPOOL.@]
1750 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1753 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1754 WORD fwCapability
, LPWSTR pOutput
,
1755 const DEVMODEW
*pDevMode
)
1757 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1758 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1759 LPSTR pPortA
= strdupWtoA(pPort
);
1762 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1763 fwCapability
== DC_FILEDEPENDENCIES
||
1764 fwCapability
== DC_PAPERNAMES
)) {
1765 /* These need A -> W translation */
1768 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1772 switch(fwCapability
) {
1777 case DC_FILEDEPENDENCIES
:
1781 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1782 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1784 for(i
= 0; i
< ret
; i
++)
1785 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1786 pOutput
+ (i
* size
), size
);
1787 HeapFree(GetProcessHeap(), 0, pOutputA
);
1789 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1790 (LPSTR
)pOutput
, dmA
);
1792 HeapFree(GetProcessHeap(),0,pPortA
);
1793 HeapFree(GetProcessHeap(),0,pDeviceA
);
1794 HeapFree(GetProcessHeap(),0,dmA
);
1798 /******************************************************************
1799 * DocumentPropertiesA [WINSPOOL.@]
1801 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1803 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1804 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1805 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1807 LPSTR lpName
= pDeviceName
;
1808 static CHAR port
[] = "LPT1:";
1811 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1812 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1816 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1818 ERR("no name from hPrinter?\n");
1819 SetLastError(ERROR_INVALID_HANDLE
);
1822 lpName
= strdupWtoA(lpNameW
);
1825 if (!GDI_CallExtDeviceMode16
)
1827 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1829 if (!GDI_CallExtDeviceMode16
) {
1830 ERR("No CallExtDeviceMode16?\n");
1834 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1835 pDevModeInput
, NULL
, fMode
);
1838 HeapFree(GetProcessHeap(),0,lpName
);
1843 /*****************************************************************************
1844 * DocumentPropertiesW (WINSPOOL.@)
1846 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1848 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1850 LPDEVMODEW pDevModeOutput
,
1851 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1854 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1855 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1856 LPDEVMODEA pDevModeOutputA
= NULL
;
1859 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1860 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1862 if(pDevModeOutput
) {
1863 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1864 if(ret
< 0) return ret
;
1865 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1867 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1868 pDevModeInputA
, fMode
);
1869 if(pDevModeOutput
) {
1870 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1871 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1873 if(fMode
== 0 && ret
> 0)
1874 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1875 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1876 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1880 /*****************************************************************************
1881 * IsValidDevmodeA [WINSPOOL.@]
1883 * Validate a DEVMODE structure and fix errors if possible.
1886 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1888 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1896 /*****************************************************************************
1897 * IsValidDevmodeW [WINSPOOL.@]
1899 * Validate a DEVMODE structure and fix errors if possible.
1902 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1904 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1912 /******************************************************************
1913 * OpenPrinterA [WINSPOOL.@]
1918 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1919 LPPRINTER_DEFAULTSA pDefault
)
1921 UNICODE_STRING lpPrinterNameW
;
1922 UNICODE_STRING usBuffer
;
1923 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1924 PWSTR pwstrPrinterNameW
;
1927 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1930 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1931 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1932 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1933 pDefaultW
= &DefaultW
;
1935 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1937 RtlFreeUnicodeString(&usBuffer
);
1938 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1940 RtlFreeUnicodeString(&lpPrinterNameW
);
1944 /******************************************************************
1945 * OpenPrinterW [WINSPOOL.@]
1947 * Open a Printer / Printserver or a Printer-Object
1950 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1951 * phPrinter [O] The resulting Handle is stored here
1952 * pDefault [I] PTR to Default Printer Settings or NULL
1959 * lpPrinterName is one of:
1960 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1961 *| Printer: "PrinterName"
1962 *| Printer-Object: "PrinterName,Job xxx"
1963 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1964 *| XcvPort: "Servername,XcvPort PortName"
1967 *| Printer-Object not supported
1968 *| pDefaults is ignored
1971 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1974 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1977 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1978 SetLastError(ERROR_INVALID_PARAMETER
);
1982 /* Get the unique handle of the printer or Printserver */
1983 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1984 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1985 return (*phPrinter
!= 0);
1988 /******************************************************************
1989 * AddMonitorA [WINSPOOL.@]
1994 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1996 LPWSTR nameW
= NULL
;
1999 LPMONITOR_INFO_2A mi2a
;
2000 MONITOR_INFO_2W mi2w
;
2002 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2003 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2004 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2005 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2006 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2009 SetLastError(ERROR_INVALID_LEVEL
);
2013 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2019 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2020 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2021 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2024 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2026 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2027 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2028 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2030 if (mi2a
->pEnvironment
) {
2031 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2032 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2033 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2035 if (mi2a
->pDLLName
) {
2036 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2037 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2038 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2041 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2043 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2044 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2045 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2047 HeapFree(GetProcessHeap(), 0, nameW
);
2051 /******************************************************************************
2052 * AddMonitorW [WINSPOOL.@]
2054 * Install a Printmonitor
2057 * pName [I] Servername or NULL (local Computer)
2058 * Level [I] Structure-Level (Must be 2)
2059 * pMonitors [I] PTR to MONITOR_INFO_2
2066 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2069 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2071 LPMONITOR_INFO_2W mi2w
;
2073 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2074 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2075 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2076 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2077 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2079 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2082 SetLastError(ERROR_INVALID_LEVEL
);
2086 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2091 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2094 /******************************************************************
2095 * DeletePrinterDriverA [WINSPOOL.@]
2098 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2100 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2103 /******************************************************************
2104 * DeletePrinterDriverW [WINSPOOL.@]
2107 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2109 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2112 /******************************************************************
2113 * DeleteMonitorA [WINSPOOL.@]
2115 * See DeleteMonitorW.
2118 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2120 LPWSTR nameW
= NULL
;
2121 LPWSTR EnvironmentW
= NULL
;
2122 LPWSTR MonitorNameW
= NULL
;
2127 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2128 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2129 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2133 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2134 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2135 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2138 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2139 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2140 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2143 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2145 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2146 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2147 HeapFree(GetProcessHeap(), 0, nameW
);
2151 /******************************************************************
2152 * DeleteMonitorW [WINSPOOL.@]
2154 * Delete a specific Printmonitor from a Printing-Environment
2157 * pName [I] Servername or NULL (local Computer)
2158 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2159 * pMonitorName [I] Name of the Monitor, that should be deleted
2166 * pEnvironment is ignored in Windows for the local Computer.
2169 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2172 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2173 debugstr_w(pMonitorName
));
2175 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2177 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2181 /******************************************************************
2182 * DeletePortA [WINSPOOL.@]
2187 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2189 LPWSTR nameW
= NULL
;
2190 LPWSTR portW
= NULL
;
2194 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2196 /* convert servername to unicode */
2198 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2199 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2200 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2203 /* convert portname to unicode */
2205 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2206 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2207 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2210 res
= DeletePortW(nameW
, hWnd
, portW
);
2211 HeapFree(GetProcessHeap(), 0, nameW
);
2212 HeapFree(GetProcessHeap(), 0, portW
);
2216 /******************************************************************
2217 * DeletePortW [WINSPOOL.@]
2219 * Delete a specific Port
2222 * pName [I] Servername or NULL (local Computer)
2223 * hWnd [I] Handle to parent Window for the Dialog-Box
2224 * pPortName [I] Name of the Port, that should be deleted
2231 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2233 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2235 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2238 SetLastError(RPC_X_NULL_REF_POINTER
);
2242 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2245 /******************************************************************************
2246 * WritePrinter [WINSPOOL.@]
2248 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2250 opened_printer_t
*printer
;
2253 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2255 EnterCriticalSection(&printer_handles_cs
);
2256 printer
= get_opened_printer(hPrinter
);
2259 SetLastError(ERROR_INVALID_HANDLE
);
2265 SetLastError(ERROR_SPL_NO_STARTDOC
);
2269 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2271 LeaveCriticalSection(&printer_handles_cs
);
2275 /*****************************************************************************
2276 * AddFormA [WINSPOOL.@]
2278 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2280 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2284 /*****************************************************************************
2285 * AddFormW [WINSPOOL.@]
2287 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2289 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2293 /*****************************************************************************
2294 * AddJobA [WINSPOOL.@]
2296 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2299 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2303 SetLastError(ERROR_INVALID_LEVEL
);
2307 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2310 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2311 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2312 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2313 if(*pcbNeeded
> cbBuf
) {
2314 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2317 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2318 addjobA
->JobId
= addjobW
->JobId
;
2319 addjobA
->Path
= (char *)(addjobA
+ 1);
2320 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2326 /*****************************************************************************
2327 * AddJobW [WINSPOOL.@]
2329 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2331 opened_printer_t
*printer
;
2334 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2335 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2336 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2338 ADDJOB_INFO_1W
*addjob
;
2340 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2342 EnterCriticalSection(&printer_handles_cs
);
2344 printer
= get_opened_printer(hPrinter
);
2347 SetLastError(ERROR_INVALID_HANDLE
);
2352 SetLastError(ERROR_INVALID_LEVEL
);
2356 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2360 job
->job_id
= InterlockedIncrement(&next_job_id
);
2362 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2363 if(path
[len
- 1] != '\\')
2365 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2366 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2368 len
= strlenW(filename
);
2369 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2370 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2371 job
->portname
= NULL
;
2372 job
->document_title
= strdupW(default_doc_title
);
2373 job
->printer_name
= strdupW(printer
->name
);
2374 job
->devmode
= dup_devmode( printer
->devmode
);
2375 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2377 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2378 if(*pcbNeeded
<= cbBuf
) {
2379 addjob
= (ADDJOB_INFO_1W
*)pData
;
2380 addjob
->JobId
= job
->job_id
;
2381 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2382 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2385 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2388 LeaveCriticalSection(&printer_handles_cs
);
2392 /*****************************************************************************
2393 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2395 * Return the PATH for the Print-Processors
2397 * See GetPrintProcessorDirectoryW.
2401 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2402 DWORD level
, LPBYTE Info
,
2403 DWORD cbBuf
, LPDWORD pcbNeeded
)
2405 LPWSTR serverW
= NULL
;
2410 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2411 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2415 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2416 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2417 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2421 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2422 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2423 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2426 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2427 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2429 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2432 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2433 cbBuf
, NULL
, NULL
) > 0;
2436 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2437 HeapFree(GetProcessHeap(), 0, envW
);
2438 HeapFree(GetProcessHeap(), 0, serverW
);
2442 /*****************************************************************************
2443 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2445 * Return the PATH for the Print-Processors
2448 * server [I] Servername (NT only) or NULL (local Computer)
2449 * env [I] Printing-Environment (see below) or NULL (Default)
2450 * level [I] Structure-Level (must be 1)
2451 * Info [O] PTR to Buffer that receives the Result
2452 * cbBuf [I] Size of Buffer at "Info"
2453 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2454 * required for the Buffer at "Info"
2457 * Success: TRUE and in pcbNeeded the Bytes used in Info
2458 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2459 * if cbBuf is too small
2461 * Native Values returned in Info on Success:
2462 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2463 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2464 *| win9x(Windows 4.0): "%winsysdir%"
2466 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2469 * Only NULL or "" is supported for server
2472 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2473 DWORD level
, LPBYTE Info
,
2474 DWORD cbBuf
, LPDWORD pcbNeeded
)
2477 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2478 Info
, cbBuf
, pcbNeeded
);
2480 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2483 /* (Level != 1) is ignored in win9x */
2484 SetLastError(ERROR_INVALID_LEVEL
);
2488 if (pcbNeeded
== NULL
) {
2489 /* (pcbNeeded == NULL) is ignored in win9x */
2490 SetLastError(RPC_X_NULL_REF_POINTER
);
2494 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2497 /*****************************************************************************
2498 * WINSPOOL_OpenDriverReg [internal]
2500 * opens the registry for the printer drivers depending on the given input
2501 * variable pEnvironment
2504 * the opened hkey on success
2507 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2511 const printenv_t
* env
;
2513 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2515 env
= validate_envW(pEnvironment
);
2516 if (!env
) return NULL
;
2518 buffer
= HeapAlloc( GetProcessHeap(), 0,
2519 (strlenW(DriversW
) + strlenW(env
->envname
) +
2520 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2522 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2523 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2524 HeapFree(GetProcessHeap(), 0, buffer
);
2529 /*****************************************************************************
2530 * set_devices_and_printerports [internal]
2532 * set the [Devices] and [PrinterPorts] entries for a printer.
2535 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2537 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2541 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2543 /* FIXME: the driver must change to "winspool" */
2544 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2546 lstrcpyW(devline
, driver_nt
);
2547 lstrcatW(devline
, commaW
);
2548 lstrcatW(devline
, pi
->pPortName
);
2550 TRACE("using %s\n", debugstr_w(devline
));
2551 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2552 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2553 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2554 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2558 lstrcatW(devline
, timeout_15_45
);
2559 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2560 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2561 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2562 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2565 HeapFree(GetProcessHeap(), 0, devline
);
2569 /*****************************************************************************
2570 * AddPrinterW [WINSPOOL.@]
2572 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2574 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2577 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2579 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2580 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2581 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2582 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2583 statusW
[] = {'S','t','a','t','u','s',0},
2584 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2586 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2589 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2590 SetLastError(ERROR_INVALID_PARAMETER
);
2594 ERR("Level = %d, unsupported!\n", Level
);
2595 SetLastError(ERROR_INVALID_LEVEL
);
2599 SetLastError(ERROR_INVALID_PARAMETER
);
2602 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2604 ERR("Can't create Printers key\n");
2607 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2608 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2609 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2610 RegCloseKey(hkeyPrinter
);
2611 RegCloseKey(hkeyPrinters
);
2614 RegCloseKey(hkeyPrinter
);
2616 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2618 ERR("Can't create Drivers key\n");
2619 RegCloseKey(hkeyPrinters
);
2622 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2624 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2625 RegCloseKey(hkeyPrinters
);
2626 RegCloseKey(hkeyDrivers
);
2627 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2630 RegCloseKey(hkeyDriver
);
2631 RegCloseKey(hkeyDrivers
);
2633 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2634 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2635 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2636 RegCloseKey(hkeyPrinters
);
2640 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2642 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2643 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2644 RegCloseKey(hkeyPrinters
);
2648 set_devices_and_printerports(pi
);
2649 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2650 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2651 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2653 /* See if we can load the driver. We may need the devmode structure anyway
2656 * Note that DocumentPropertiesW will briefly try to open the printer we
2657 * just create to find a DEVMODE struct (it will use the WINEPS default
2658 * one in case it is not there, so we are ok).
2660 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2663 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2664 size
= sizeof(DEVMODEW
);
2670 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2672 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
2674 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2675 HeapFree( GetProcessHeap(), 0, dm
);
2680 /* set devmode to printer name */
2681 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2685 set_reg_devmode( hkeyPrinter
, default_devmodeW
, dm
);
2686 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
2688 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2689 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2690 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2691 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2693 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2694 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2695 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2696 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2697 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2698 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2699 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2700 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2701 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2702 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2703 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2704 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2705 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2707 RegCloseKey(hkeyPrinter
);
2708 RegCloseKey(hkeyPrinters
);
2709 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2710 ERR("OpenPrinter failing\n");
2716 /*****************************************************************************
2717 * AddPrinterA [WINSPOOL.@]
2719 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2721 UNICODE_STRING pNameW
;
2723 PRINTER_INFO_2W
*piW
;
2724 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2727 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2729 ERR("Level = %d, unsupported!\n", Level
);
2730 SetLastError(ERROR_INVALID_LEVEL
);
2733 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2734 piW
= printer_info_AtoW( piA
, Level
);
2736 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2738 free_printer_info( piW
, Level
);
2739 RtlFreeUnicodeString(&pNameW
);
2744 /*****************************************************************************
2745 * ClosePrinter [WINSPOOL.@]
2747 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2749 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2750 opened_printer_t
*printer
= NULL
;
2753 TRACE("(%p)\n", hPrinter
);
2755 EnterCriticalSection(&printer_handles_cs
);
2757 if ((i
> 0) && (i
<= nb_printer_handles
))
2758 printer
= printer_handles
[i
- 1];
2763 struct list
*cursor
, *cursor2
;
2765 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2767 if (printer
->backend_printer
) {
2768 backend
->fpClosePrinter(printer
->backend_printer
);
2772 EndDocPrinter(hPrinter
);
2774 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2776 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2778 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2779 ScheduleJob(hPrinter
, job
->job_id
);
2781 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2784 free_printer_entry( printer
);
2785 printer_handles
[i
- 1] = NULL
;
2788 LeaveCriticalSection(&printer_handles_cs
);
2792 /*****************************************************************************
2793 * DeleteFormA [WINSPOOL.@]
2795 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2797 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2801 /*****************************************************************************
2802 * DeleteFormW [WINSPOOL.@]
2804 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2806 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2810 /*****************************************************************************
2811 * DeletePrinter [WINSPOOL.@]
2813 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2815 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2816 HKEY hkeyPrinters
, hkey
;
2817 WCHAR def
[MAX_PATH
];
2818 DWORD size
= sizeof( def
) / sizeof( def
[0] );
2821 SetLastError(ERROR_INVALID_HANDLE
);
2824 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2825 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2826 RegCloseKey(hkeyPrinters
);
2828 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2829 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2831 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2832 RegDeleteValueW(hkey
, lpNameW
);
2836 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2837 RegDeleteValueW(hkey
, lpNameW
);
2841 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
2843 WriteProfileStringW( windowsW
, deviceW
, NULL
);
2844 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
2846 RegDeleteValueW( hkey
, deviceW
);
2847 RegCloseKey( hkey
);
2849 SetDefaultPrinterW( NULL
);
2855 /*****************************************************************************
2856 * SetPrinterA [WINSPOOL.@]
2858 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2865 dataW
= printer_info_AtoW( data
, level
);
2866 if (!dataW
) return FALSE
;
2869 ret
= SetPrinterW( printer
, level
, dataW
, command
);
2871 if (dataW
!= data
) free_printer_info( dataW
, level
);
2876 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
2878 if (!pi
->pDevMode
) return FALSE
;
2880 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
2884 /******************************************************************************
2885 * SetPrinterW [WINSPOOL.@]
2887 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2892 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
2894 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
2896 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
2903 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
2904 ret
= set_printer_9( key
, pi
);
2909 FIXME( "Unimplemented level %d\n", level
);
2910 SetLastError( ERROR_INVALID_LEVEL
);
2917 /*****************************************************************************
2918 * SetJobA [WINSPOOL.@]
2920 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2921 LPBYTE pJob
, DWORD Command
)
2925 UNICODE_STRING usBuffer
;
2927 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2929 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2930 are all ignored by SetJob, so we don't bother copying them */
2938 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2939 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2941 JobW
= (LPBYTE
)info1W
;
2942 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2943 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2944 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2945 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2946 info1W
->Status
= info1A
->Status
;
2947 info1W
->Priority
= info1A
->Priority
;
2948 info1W
->Position
= info1A
->Position
;
2949 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2954 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2955 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2957 JobW
= (LPBYTE
)info2W
;
2958 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2959 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2960 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2961 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2962 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2963 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2964 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2965 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2966 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2967 info2W
->Status
= info2A
->Status
;
2968 info2W
->Priority
= info2A
->Priority
;
2969 info2W
->Position
= info2A
->Position
;
2970 info2W
->StartTime
= info2A
->StartTime
;
2971 info2W
->UntilTime
= info2A
->UntilTime
;
2972 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2976 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2977 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2980 SetLastError(ERROR_INVALID_LEVEL
);
2984 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2990 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2991 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2992 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2993 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2994 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2999 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3000 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3001 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3002 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3003 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3004 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3005 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3006 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3007 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3011 HeapFree(GetProcessHeap(), 0, JobW
);
3016 /*****************************************************************************
3017 * SetJobW [WINSPOOL.@]
3019 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3020 LPBYTE pJob
, DWORD Command
)
3025 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3026 FIXME("Ignoring everything other than document title\n");
3028 EnterCriticalSection(&printer_handles_cs
);
3029 job
= get_job(hPrinter
, JobId
);
3039 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3040 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3041 job
->document_title
= strdupW(info1
->pDocument
);
3046 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3047 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3048 job
->document_title
= strdupW(info2
->pDocument
);
3049 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3050 job
->devmode
= dup_devmode( info2
->pDevMode
);
3056 SetLastError(ERROR_INVALID_LEVEL
);
3061 LeaveCriticalSection(&printer_handles_cs
);
3065 /*****************************************************************************
3066 * EndDocPrinter [WINSPOOL.@]
3068 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3070 opened_printer_t
*printer
;
3072 TRACE("(%p)\n", hPrinter
);
3074 EnterCriticalSection(&printer_handles_cs
);
3076 printer
= get_opened_printer(hPrinter
);
3079 SetLastError(ERROR_INVALID_HANDLE
);
3085 SetLastError(ERROR_SPL_NO_STARTDOC
);
3089 CloseHandle(printer
->doc
->hf
);
3090 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3091 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3092 printer
->doc
= NULL
;
3095 LeaveCriticalSection(&printer_handles_cs
);
3099 /*****************************************************************************
3100 * EndPagePrinter [WINSPOOL.@]
3102 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3104 FIXME("(%p): stub\n", hPrinter
);
3108 /*****************************************************************************
3109 * StartDocPrinterA [WINSPOOL.@]
3111 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3113 UNICODE_STRING usBuffer
;
3115 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3118 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3119 or one (DOC_INFO_3) extra DWORDs */
3123 doc2W
.JobId
= doc2
->JobId
;
3126 doc2W
.dwMode
= doc2
->dwMode
;
3129 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3130 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3131 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3135 SetLastError(ERROR_INVALID_LEVEL
);
3139 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3141 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3142 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3143 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3148 /*****************************************************************************
3149 * StartDocPrinterW [WINSPOOL.@]
3151 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3153 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3154 opened_printer_t
*printer
;
3155 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3156 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3157 JOB_INFO_1W job_info
;
3158 DWORD needed
, ret
= 0;
3163 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3164 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3165 debugstr_w(doc
->pDatatype
));
3167 if(Level
< 1 || Level
> 3)
3169 SetLastError(ERROR_INVALID_LEVEL
);
3173 EnterCriticalSection(&printer_handles_cs
);
3174 printer
= get_opened_printer(hPrinter
);
3177 SetLastError(ERROR_INVALID_HANDLE
);
3183 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3187 /* Even if we're printing to a file we still add a print job, we'll
3188 just ignore the spool file name */
3190 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3192 ERR("AddJob failed gle %u\n", GetLastError());
3196 /* use pOutputFile only, when it is a real filename */
3197 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3198 filename
= doc
->pOutputFile
;
3200 filename
= addjob
->Path
;
3202 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3203 if(hf
== INVALID_HANDLE_VALUE
)
3206 memset(&job_info
, 0, sizeof(job_info
));
3207 job_info
.pDocument
= doc
->pDocName
;
3208 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3210 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3211 printer
->doc
->hf
= hf
;
3212 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3213 job
= get_job(hPrinter
, ret
);
3214 job
->portname
= strdupW(doc
->pOutputFile
);
3217 LeaveCriticalSection(&printer_handles_cs
);
3222 /*****************************************************************************
3223 * StartPagePrinter [WINSPOOL.@]
3225 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3227 FIXME("(%p): stub\n", hPrinter
);
3231 /*****************************************************************************
3232 * GetFormA [WINSPOOL.@]
3234 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3235 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3237 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3238 Level
,pForm
,cbBuf
,pcbNeeded
);
3242 /*****************************************************************************
3243 * GetFormW [WINSPOOL.@]
3245 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3246 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3248 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3249 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3253 /*****************************************************************************
3254 * SetFormA [WINSPOOL.@]
3256 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3259 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3263 /*****************************************************************************
3264 * SetFormW [WINSPOOL.@]
3266 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3269 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3273 /*****************************************************************************
3274 * ReadPrinter [WINSPOOL.@]
3276 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3277 LPDWORD pNoBytesRead
)
3279 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3283 /*****************************************************************************
3284 * ResetPrinterA [WINSPOOL.@]
3286 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3288 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3292 /*****************************************************************************
3293 * ResetPrinterW [WINSPOOL.@]
3295 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3297 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3301 /*****************************************************************************
3302 * WINSPOOL_GetDWORDFromReg
3304 * Return DWORD associated with ValueName from hkey.
3306 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3308 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3311 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3313 if(ret
!= ERROR_SUCCESS
) {
3314 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3317 if(type
!= REG_DWORD
) {
3318 ERR("Got type %d\n", type
);
3325 /*****************************************************************************
3326 * get_filename_from_reg [internal]
3328 * Get ValueName from hkey storing result in out
3329 * when the Value in the registry has only a filename, use driverdir as prefix
3330 * outlen is space left in out
3331 * String is stored either as unicode or ascii
3335 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3336 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3338 WCHAR filename
[MAX_PATH
];
3342 LPWSTR buffer
= filename
;
3346 size
= sizeof(filename
);
3348 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3349 if (ret
== ERROR_MORE_DATA
) {
3350 TRACE("need dynamic buffer: %u\n", size
);
3351 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3353 /* No Memory is bad */
3357 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3360 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3361 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3367 /* do we have a full path ? */
3368 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3369 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3372 /* we must build the full Path */
3374 if ((out
) && (outlen
> dirlen
)) {
3375 lstrcpyW((LPWSTR
)out
, driverdir
);
3383 /* write the filename */
3384 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3385 if ((out
) && (outlen
>= size
)) {
3386 lstrcpyW((LPWSTR
)out
, ptr
);
3393 ptr
+= lstrlenW(ptr
)+1;
3394 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3397 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3399 /* write the multisz-termination */
3400 if (type
== REG_MULTI_SZ
) {
3401 size
= sizeof(WCHAR
);
3404 if (out
&& (outlen
>= size
)) {
3405 memset (out
, 0, size
);
3411 /*****************************************************************************
3412 * WINSPOOL_GetStringFromReg
3414 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3415 * String is stored as unicode.
3417 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3418 DWORD buflen
, DWORD
*needed
)
3420 DWORD sz
= buflen
, type
;
3423 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3424 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3425 WARN("Got ret = %d\n", ret
);
3429 /* add space for terminating '\0' */
3430 sz
+= sizeof(WCHAR
);
3434 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3439 /*****************************************************************************
3440 * WINSPOOL_GetDefaultDevMode
3442 * Get a default DevMode values for wineps.
3446 static void WINSPOOL_GetDefaultDevMode(
3448 DWORD buflen
, DWORD
*needed
)
3451 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3453 /* fill default DEVMODE - should be read from ppd... */
3454 ZeroMemory( &dm
, sizeof(dm
) );
3455 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3456 dm
.dmSpecVersion
= DM_SPECVERSION
;
3457 dm
.dmDriverVersion
= 1;
3458 dm
.dmSize
= sizeof(DEVMODEW
);
3459 dm
.dmDriverExtra
= 0;
3461 DM_ORIENTATION
| DM_PAPERSIZE
|
3462 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3465 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3466 DM_YRESOLUTION
| DM_TTOPTION
;
3468 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3469 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3470 dm
.u1
.s1
.dmPaperLength
= 2970;
3471 dm
.u1
.s1
.dmPaperWidth
= 2100;
3473 dm
.u1
.s1
.dmScale
= 100;
3474 dm
.u1
.s1
.dmCopies
= 1;
3475 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3476 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3479 dm
.dmYResolution
= 300; /* 300dpi */
3480 dm
.dmTTOption
= DMTT_BITMAP
;
3483 /* dm.dmLogPixels */
3484 /* dm.dmBitsPerPel */
3485 /* dm.dmPelsWidth */
3486 /* dm.dmPelsHeight */
3487 /* dm.u2.dmDisplayFlags */
3488 /* dm.dmDisplayFrequency */
3489 /* dm.dmICMMethod */
3490 /* dm.dmICMIntent */
3491 /* dm.dmMediaType */
3492 /* dm.dmDitherType */
3493 /* dm.dmReserved1 */
3494 /* dm.dmReserved2 */
3495 /* dm.dmPanningWidth */
3496 /* dm.dmPanningHeight */
3498 if(buflen
>= sizeof(DEVMODEW
))
3499 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3500 *needed
= sizeof(DEVMODEW
);
3503 /*****************************************************************************
3504 * WINSPOOL_GetDevModeFromReg
3506 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3507 * DevMode is stored either as unicode or ascii.
3509 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3511 DWORD buflen
, DWORD
*needed
)
3513 DWORD sz
= buflen
, type
;
3516 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3517 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3518 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3519 if (sz
< sizeof(DEVMODEA
))
3521 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3524 /* ensures that dmSize is not erratically bogus if registry is invalid */
3525 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3526 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3527 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3528 if (ptr
&& (buflen
>= sz
)) {
3529 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3530 memcpy(ptr
, dmW
, sz
);
3531 HeapFree(GetProcessHeap(),0,dmW
);
3537 /*********************************************************************
3538 * WINSPOOL_GetPrinter_1
3540 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3542 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3543 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3545 DWORD size
, left
= cbBuf
;
3546 BOOL space
= (cbBuf
> 0);
3551 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3552 if(space
&& size
<= left
) {
3553 pi1
->pName
= (LPWSTR
)ptr
;
3561 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3562 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3563 if(space
&& size
<= left
) {
3564 pi1
->pDescription
= (LPWSTR
)ptr
;
3572 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3573 if(space
&& size
<= left
) {
3574 pi1
->pComment
= (LPWSTR
)ptr
;
3582 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3584 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3585 memset(pi1
, 0, sizeof(*pi1
));
3589 /*********************************************************************
3590 * WINSPOOL_GetPrinter_2
3592 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3594 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3595 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3597 DWORD size
, left
= cbBuf
;
3598 BOOL space
= (cbBuf
> 0);
3603 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3604 if(space
&& size
<= left
) {
3605 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3612 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3613 if(space
&& size
<= left
) {
3614 pi2
->pShareName
= (LPWSTR
)ptr
;
3621 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3622 if(space
&& size
<= left
) {
3623 pi2
->pPortName
= (LPWSTR
)ptr
;
3630 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3631 if(space
&& size
<= left
) {
3632 pi2
->pDriverName
= (LPWSTR
)ptr
;
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3640 if(space
&& size
<= left
) {
3641 pi2
->pComment
= (LPWSTR
)ptr
;
3648 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3649 if(space
&& size
<= left
) {
3650 pi2
->pLocation
= (LPWSTR
)ptr
;
3657 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3658 if(space
&& size
<= left
) {
3659 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3668 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3669 if(space
&& size
<= left
) {
3670 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3677 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3678 if(space
&& size
<= left
) {
3679 pi2
->pSepFile
= (LPWSTR
)ptr
;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3687 if(space
&& size
<= left
) {
3688 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3696 if(space
&& size
<= left
) {
3697 pi2
->pDatatype
= (LPWSTR
)ptr
;
3704 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3705 if(space
&& size
<= left
) {
3706 pi2
->pParameters
= (LPWSTR
)ptr
;
3714 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3715 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3716 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3717 "Default Priority");
3718 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3719 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3722 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3723 memset(pi2
, 0, sizeof(*pi2
));
3728 /*********************************************************************
3729 * WINSPOOL_GetPrinter_4
3731 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3733 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3734 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3736 DWORD size
, left
= cbBuf
;
3737 BOOL space
= (cbBuf
> 0);
3742 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3743 if(space
&& size
<= left
) {
3744 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3752 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3755 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3756 memset(pi4
, 0, sizeof(*pi4
));
3761 /*********************************************************************
3762 * WINSPOOL_GetPrinter_5
3764 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3766 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3767 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3769 DWORD size
, left
= cbBuf
;
3770 BOOL space
= (cbBuf
> 0);
3775 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3776 if(space
&& size
<= left
) {
3777 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3785 if(space
&& size
<= left
) {
3786 pi5
->pPortName
= (LPWSTR
)ptr
;
3794 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3795 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3797 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3801 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3802 memset(pi5
, 0, sizeof(*pi5
));
3807 /*********************************************************************
3808 * WINSPOOL_GetPrinter_7
3810 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3812 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3813 DWORD cbBuf
, LPDWORD pcbNeeded
)
3815 DWORD size
, left
= cbBuf
;
3816 BOOL space
= (cbBuf
> 0);
3821 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3824 size
= sizeof(pi7
->pszObjectGUID
);
3826 if (space
&& size
<= left
) {
3827 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3834 /* We do not have a Directory Service */
3835 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3838 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3839 memset(pi7
, 0, sizeof(*pi7
));
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_9
3847 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3849 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3850 DWORD cbBuf
, LPDWORD pcbNeeded
)
3853 BOOL space
= (cbBuf
> 0);
3857 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3858 if(space
&& size
<= cbBuf
) {
3859 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3866 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3867 if(space
&& size
<= cbBuf
) {
3868 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3874 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3875 memset(pi9
, 0, sizeof(*pi9
));
3880 /*****************************************************************************
3881 * GetPrinterW [WINSPOOL.@]
3883 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3884 DWORD cbBuf
, LPDWORD pcbNeeded
)
3886 DWORD size
, needed
= 0, err
;
3891 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3893 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
3896 SetLastError( err
);
3903 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3905 size
= sizeof(PRINTER_INFO_2W
);
3907 ptr
= pPrinter
+ size
;
3909 memset(pPrinter
, 0, size
);
3914 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3921 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3923 size
= sizeof(PRINTER_INFO_4W
);
3925 ptr
= pPrinter
+ size
;
3927 memset(pPrinter
, 0, size
);
3932 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3940 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3942 size
= sizeof(PRINTER_INFO_5W
);
3944 ptr
= pPrinter
+ size
;
3946 memset(pPrinter
, 0, size
);
3952 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3960 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3962 size
= sizeof(PRINTER_INFO_6
);
3963 if (size
<= cbBuf
) {
3964 /* FIXME: We do not update the status yet */
3965 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3977 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3979 size
= sizeof(PRINTER_INFO_7W
);
3980 if (size
<= cbBuf
) {
3981 ptr
= pPrinter
+ size
;
3983 memset(pPrinter
, 0, size
);
3989 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3997 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3999 size
= sizeof(PRINTER_INFO_9W
);
4001 ptr
= pPrinter
+ size
;
4003 memset(pPrinter
, 0, size
);
4009 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4016 FIXME("Unimplemented level %d\n", Level
);
4017 SetLastError(ERROR_INVALID_LEVEL
);
4018 RegCloseKey(hkeyPrinter
);
4022 RegCloseKey(hkeyPrinter
);
4024 TRACE("returning %d needed = %d\n", ret
, needed
);
4025 if(pcbNeeded
) *pcbNeeded
= needed
;
4027 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4031 /*****************************************************************************
4032 * GetPrinterA [WINSPOOL.@]
4034 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4035 DWORD cbBuf
, LPDWORD pcbNeeded
)
4041 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4043 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4045 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4046 HeapFree(GetProcessHeap(), 0, buf
);
4051 /*****************************************************************************
4052 * WINSPOOL_EnumPrintersW
4054 * Implementation of EnumPrintersW
4056 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4057 DWORD dwLevel
, LPBYTE lpbPrinters
,
4058 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4059 LPDWORD lpdwReturned
)
4062 HKEY hkeyPrinters
, hkeyPrinter
;
4063 WCHAR PrinterName
[255];
4064 DWORD needed
= 0, number
= 0;
4065 DWORD used
, i
, left
;
4069 memset(lpbPrinters
, 0, cbBuf
);
4075 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4076 if(dwType
== PRINTER_ENUM_DEFAULT
)
4079 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4080 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4081 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4083 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4089 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4090 FIXME("dwType = %08x\n", dwType
);
4091 SetLastError(ERROR_INVALID_FLAGS
);
4095 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4097 ERR("Can't create Printers key\n");
4101 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4102 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4103 RegCloseKey(hkeyPrinters
);
4104 ERR("Can't query Printers key\n");
4107 TRACE("Found %d printers\n", number
);
4111 used
= number
* sizeof(PRINTER_INFO_1W
);
4114 used
= number
* sizeof(PRINTER_INFO_2W
);
4117 used
= number
* sizeof(PRINTER_INFO_4W
);
4120 used
= number
* sizeof(PRINTER_INFO_5W
);
4124 SetLastError(ERROR_INVALID_LEVEL
);
4125 RegCloseKey(hkeyPrinters
);
4128 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4130 for(i
= 0; i
< number
; i
++) {
4131 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4133 ERR("Can't enum key number %d\n", i
);
4134 RegCloseKey(hkeyPrinters
);
4137 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4138 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4140 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4141 RegCloseKey(hkeyPrinters
);
4146 buf
= lpbPrinters
+ used
;
4147 left
= cbBuf
- used
;
4155 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4158 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4161 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4164 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4167 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4170 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4173 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4176 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4179 ERR("Shouldn't be here!\n");
4180 RegCloseKey(hkeyPrinter
);
4181 RegCloseKey(hkeyPrinters
);
4184 RegCloseKey(hkeyPrinter
);
4186 RegCloseKey(hkeyPrinters
);
4193 memset(lpbPrinters
, 0, cbBuf
);
4194 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4198 *lpdwReturned
= number
;
4199 SetLastError(ERROR_SUCCESS
);
4204 /******************************************************************
4205 * EnumPrintersW [WINSPOOL.@]
4207 * Enumerates the available printers, print servers and print
4208 * providers, depending on the specified flags, name and level.
4212 * If level is set to 1:
4213 * Returns an array of PRINTER_INFO_1 data structures in the
4214 * lpbPrinters buffer.
4216 * If level is set to 2:
4217 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4218 * Returns an array of PRINTER_INFO_2 data structures in the
4219 * lpbPrinters buffer. Note that according to MSDN also an
4220 * OpenPrinter should be performed on every remote printer.
4222 * If level is set to 4 (officially WinNT only):
4223 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4224 * Fast: Only the registry is queried to retrieve printer names,
4225 * no connection to the driver is made.
4226 * Returns an array of PRINTER_INFO_4 data structures in the
4227 * lpbPrinters buffer.
4229 * If level is set to 5 (officially WinNT4/Win9x only):
4230 * Fast: Only the registry is queried to retrieve printer names,
4231 * no connection to the driver is made.
4232 * Returns an array of PRINTER_INFO_5 data structures in the
4233 * lpbPrinters buffer.
4235 * If level set to 3 or 6+:
4236 * returns zero (failure!)
4238 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4242 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4243 * - Only levels 2, 4 and 5 are implemented at the moment.
4244 * - 16-bit printer drivers are not enumerated.
4245 * - Returned amount of bytes used/needed does not match the real Windoze
4246 * implementation (as in this implementation, all strings are part
4247 * of the buffer, whereas Win32 keeps them somewhere else)
4248 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4251 * - In a regular Wine installation, no registry settings for printers
4252 * exist, which makes this function return an empty list.
4254 BOOL WINAPI
EnumPrintersW(
4255 DWORD dwType
, /* [in] Types of print objects to enumerate */
4256 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4257 DWORD dwLevel
, /* [in] type of printer info structure */
4258 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4259 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4260 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4261 LPDWORD lpdwReturned
/* [out] number of entries returned */
4264 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4265 lpdwNeeded
, lpdwReturned
);
4268 /******************************************************************
4269 * EnumPrintersA [WINSPOOL.@]
4274 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4275 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4278 UNICODE_STRING pNameU
;
4282 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4283 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4285 pNameW
= asciitounicode(&pNameU
, pName
);
4287 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4288 MS Office need this */
4289 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4291 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4293 RtlFreeUnicodeString(&pNameU
);
4295 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4297 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4301 /*****************************************************************************
4302 * WINSPOOL_GetDriverInfoFromReg [internal]
4304 * Enters the information from the registry into the DRIVER_INFO struct
4307 * zero if the printer driver does not exist in the registry
4308 * (only if Level > 1) otherwise nonzero
4310 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4313 const printenv_t
* env
,
4315 LPBYTE ptr
, /* DRIVER_INFO */
4316 LPBYTE pDriverStrings
, /* strings buffer */
4317 DWORD cbBuf
, /* size of string buffer */
4318 LPDWORD pcbNeeded
) /* space needed for str. */
4322 WCHAR driverdir
[MAX_PATH
];
4324 LPBYTE strPtr
= pDriverStrings
;
4325 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4327 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4328 debugstr_w(DriverName
), env
,
4329 Level
, di
, pDriverStrings
, cbBuf
);
4331 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4333 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4334 if (*pcbNeeded
<= cbBuf
)
4335 strcpyW((LPWSTR
)strPtr
, DriverName
);
4337 /* pName for level 1 has a different offset! */
4339 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4343 /* .cVersion and .pName for level > 1 */
4345 di
->cVersion
= env
->driverversion
;
4346 di
->pName
= (LPWSTR
) strPtr
;
4347 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4350 /* Reserve Space for the largest subdir and a Backslash*/
4351 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4352 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4353 /* Should never Fail */
4356 lstrcatW(driverdir
, env
->versionsubdir
);
4357 lstrcatW(driverdir
, backslashW
);
4359 /* dirlen must not include the terminating zero */
4360 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4362 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4363 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4364 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4369 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4372 if (*pcbNeeded
<= cbBuf
) {
4373 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4374 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4375 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4378 /* .pDriverPath is the Graphics rendering engine.
4379 The full Path is required to avoid a crash in some apps */
4380 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4382 if (*pcbNeeded
<= cbBuf
)
4383 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4385 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4386 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4389 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4390 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4392 if (*pcbNeeded
<= cbBuf
)
4393 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4395 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4396 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4399 /* .pConfigFile is the Driver user Interface */
4400 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4402 if (*pcbNeeded
<= cbBuf
)
4403 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4405 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4406 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4410 RegCloseKey(hkeyDriver
);
4411 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4416 RegCloseKey(hkeyDriver
);
4417 FIXME("level 5: incomplete\n");
4422 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4424 if (*pcbNeeded
<= cbBuf
)
4425 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4427 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4428 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4431 /* .pDependentFiles */
4432 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4434 if (*pcbNeeded
<= cbBuf
)
4435 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4437 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4438 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4440 else if (GetVersion() & 0x80000000) {
4441 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4442 size
= 2 * sizeof(WCHAR
);
4444 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4446 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4447 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4450 /* .pMonitorName is the optional Language Monitor */
4451 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4453 if (*pcbNeeded
<= cbBuf
)
4454 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4456 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4457 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4460 /* .pDefaultDataType */
4461 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4463 if(*pcbNeeded
<= cbBuf
)
4464 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4466 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4467 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4471 RegCloseKey(hkeyDriver
);
4472 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4476 /* .pszzPreviousNames */
4477 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4479 if(*pcbNeeded
<= cbBuf
)
4480 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4482 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4483 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4487 RegCloseKey(hkeyDriver
);
4488 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4492 /* support is missing, but not important enough for a FIXME */
4493 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4496 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4498 if(*pcbNeeded
<= cbBuf
)
4499 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4501 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4502 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4506 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4508 if(*pcbNeeded
<= cbBuf
)
4509 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4511 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4512 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4515 /* .pszHardwareID */
4516 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4518 if(*pcbNeeded
<= cbBuf
)
4519 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4521 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4522 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4526 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4528 if(*pcbNeeded
<= cbBuf
)
4529 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4531 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4532 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4536 RegCloseKey(hkeyDriver
);
4540 /* support is missing, but not important enough for a FIXME */
4541 TRACE("level 8: incomplete\n");
4543 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4544 RegCloseKey(hkeyDriver
);
4548 /*****************************************************************************
4549 * GetPrinterDriverW [WINSPOOL.@]
4551 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4552 DWORD Level
, LPBYTE pDriverInfo
,
4553 DWORD cbBuf
, LPDWORD pcbNeeded
)
4556 WCHAR DriverName
[100];
4557 DWORD ret
, type
, size
, needed
= 0;
4559 HKEY hkeyPrinter
, hkeyDrivers
;
4560 const printenv_t
* env
;
4562 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4563 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4566 ZeroMemory(pDriverInfo
, cbBuf
);
4568 if (!(name
= get_opened_printer_name(hPrinter
))) {
4569 SetLastError(ERROR_INVALID_HANDLE
);
4573 if (Level
< 1 || Level
== 7 || Level
> 8) {
4574 SetLastError(ERROR_INVALID_LEVEL
);
4578 env
= validate_envW(pEnvironment
);
4579 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4581 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4584 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4585 SetLastError( ret
);
4589 size
= sizeof(DriverName
);
4591 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4592 (LPBYTE
)DriverName
, &size
);
4593 RegCloseKey(hkeyPrinter
);
4594 if(ret
!= ERROR_SUCCESS
) {
4595 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4599 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4601 ERR("Can't create Drivers key\n");
4605 size
= di_sizeof
[Level
];
4606 if ((size
<= cbBuf
) && pDriverInfo
)
4607 ptr
= pDriverInfo
+ size
;
4609 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4610 env
, Level
, pDriverInfo
, ptr
,
4611 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4613 RegCloseKey(hkeyDrivers
);
4617 RegCloseKey(hkeyDrivers
);
4619 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4620 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4621 if(cbBuf
>= size
+ needed
) return TRUE
;
4622 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4626 /*****************************************************************************
4627 * GetPrinterDriverA [WINSPOOL.@]
4629 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4630 DWORD Level
, LPBYTE pDriverInfo
,
4631 DWORD cbBuf
, LPDWORD pcbNeeded
)
4634 UNICODE_STRING pEnvW
;
4640 ZeroMemory(pDriverInfo
, cbBuf
);
4641 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4644 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4645 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4648 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4650 HeapFree(GetProcessHeap(), 0, buf
);
4652 RtlFreeUnicodeString(&pEnvW
);
4656 /*****************************************************************************
4657 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4659 * Return the PATH for the Printer-Drivers (UNICODE)
4662 * pName [I] Servername (NT only) or NULL (local Computer)
4663 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4664 * Level [I] Structure-Level (must be 1)
4665 * pDriverDirectory [O] PTR to Buffer that receives the Result
4666 * cbBuf [I] Size of Buffer at pDriverDirectory
4667 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4668 * required for pDriverDirectory
4671 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4672 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4673 * if cbBuf is too small
4675 * Native Values returned in pDriverDirectory on Success:
4676 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4677 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4678 *| win9x(Windows 4.0): "%winsysdir%"
4680 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4683 *- Only NULL or "" is supported for pName
4686 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4687 DWORD Level
, LPBYTE pDriverDirectory
,
4688 DWORD cbBuf
, LPDWORD pcbNeeded
)
4690 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4691 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4693 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4696 /* (Level != 1) is ignored in win9x */
4697 SetLastError(ERROR_INVALID_LEVEL
);
4700 if (pcbNeeded
== NULL
) {
4701 /* (pcbNeeded == NULL) is ignored in win9x */
4702 SetLastError(RPC_X_NULL_REF_POINTER
);
4706 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4707 pDriverDirectory
, cbBuf
, pcbNeeded
);
4712 /*****************************************************************************
4713 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4715 * Return the PATH for the Printer-Drivers (ANSI)
4717 * See GetPrinterDriverDirectoryW.
4720 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4723 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4724 DWORD Level
, LPBYTE pDriverDirectory
,
4725 DWORD cbBuf
, LPDWORD pcbNeeded
)
4727 UNICODE_STRING nameW
, environmentW
;
4730 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4731 WCHAR
*driverDirectoryW
= NULL
;
4733 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4734 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4736 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4738 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4739 else nameW
.Buffer
= NULL
;
4740 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4741 else environmentW
.Buffer
= NULL
;
4743 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4744 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4747 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4748 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4750 *pcbNeeded
= needed
;
4751 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4753 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4755 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4757 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4758 RtlFreeUnicodeString(&environmentW
);
4759 RtlFreeUnicodeString(&nameW
);
4764 /*****************************************************************************
4765 * AddPrinterDriverA [WINSPOOL.@]
4767 * See AddPrinterDriverW.
4770 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4772 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4773 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4776 /******************************************************************************
4777 * AddPrinterDriverW (WINSPOOL.@)
4779 * Install a Printer Driver
4782 * pName [I] Servername or NULL (local Computer)
4783 * level [I] Level for the supplied DRIVER_INFO_*W struct
4784 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4791 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4793 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4794 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4797 /*****************************************************************************
4798 * AddPrintProcessorA [WINSPOOL.@]
4800 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4801 LPSTR pPrintProcessorName
)
4803 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4804 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4808 /*****************************************************************************
4809 * AddPrintProcessorW [WINSPOOL.@]
4811 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4812 LPWSTR pPrintProcessorName
)
4814 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4815 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4819 /*****************************************************************************
4820 * AddPrintProvidorA [WINSPOOL.@]
4822 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4824 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4828 /*****************************************************************************
4829 * AddPrintProvidorW [WINSPOOL.@]
4831 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4833 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4840 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4841 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4844 pDevModeOutput
, pDevModeInput
);
4848 /*****************************************************************************
4849 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4851 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4852 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4854 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4855 pDevModeOutput
, pDevModeInput
);
4859 /*****************************************************************************
4860 * PrinterProperties [WINSPOOL.@]
4862 * Displays a dialog to set the properties of the printer.
4865 * nonzero on success or zero on failure
4868 * implemented as stub only
4870 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4871 HANDLE hPrinter
/* [in] handle to printer object */
4873 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4874 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4878 /*****************************************************************************
4879 * EnumJobsA [WINSPOOL.@]
4882 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4883 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4886 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4887 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4889 if(pcbNeeded
) *pcbNeeded
= 0;
4890 if(pcReturned
) *pcReturned
= 0;
4895 /*****************************************************************************
4896 * EnumJobsW [WINSPOOL.@]
4899 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4900 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4903 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4904 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4906 if(pcbNeeded
) *pcbNeeded
= 0;
4907 if(pcReturned
) *pcReturned
= 0;
4911 /*****************************************************************************
4912 * WINSPOOL_EnumPrinterDrivers [internal]
4914 * Delivers information about all printer drivers installed on the
4915 * localhost or a given server
4918 * nonzero on success or zero on failure. If the buffer for the returned
4919 * information is too small the function will return an error
4922 * - only implemented for localhost, foreign hosts will return an error
4924 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4925 DWORD Level
, LPBYTE pDriverInfo
,
4927 DWORD cbBuf
, LPDWORD pcbNeeded
,
4928 LPDWORD pcFound
, DWORD data_offset
)
4932 const printenv_t
* env
;
4934 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4935 debugstr_w(pName
), debugstr_w(pEnvironment
),
4936 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4938 env
= validate_envW(pEnvironment
);
4939 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4943 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4945 ERR("Can't open Drivers key\n");
4949 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4950 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4951 RegCloseKey(hkeyDrivers
);
4952 ERR("Can't query Drivers key\n");
4955 TRACE("Found %d Drivers\n", *pcFound
);
4957 /* get size of single struct
4958 * unicode and ascii structure have the same size
4960 size
= di_sizeof
[Level
];
4962 if (data_offset
== 0)
4963 data_offset
= size
* (*pcFound
);
4964 *pcbNeeded
= data_offset
;
4966 for( i
= 0; i
< *pcFound
; i
++) {
4967 WCHAR DriverNameW
[255];
4968 PBYTE table_ptr
= NULL
;
4969 PBYTE data_ptr
= NULL
;
4972 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4974 ERR("Can't enum key number %d\n", i
);
4975 RegCloseKey(hkeyDrivers
);
4979 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4980 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4981 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4982 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4984 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4985 env
, Level
, table_ptr
, data_ptr
,
4986 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4988 RegCloseKey(hkeyDrivers
);
4992 *pcbNeeded
+= needed
;
4995 RegCloseKey(hkeyDrivers
);
4997 if(cbBuf
< *pcbNeeded
){
4998 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5005 /*****************************************************************************
5006 * EnumPrinterDriversW [WINSPOOL.@]
5008 * see function EnumPrinterDrivers for RETURNS, BUGS
5010 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5011 LPBYTE pDriverInfo
, DWORD cbBuf
,
5012 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5014 static const WCHAR allW
[] = {'a','l','l',0};
5018 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5020 SetLastError(RPC_X_NULL_REF_POINTER
);
5024 /* check for local drivers */
5025 if((pName
) && (pName
[0])) {
5026 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5027 SetLastError(ERROR_ACCESS_DENIED
);
5031 /* check input parameter */
5032 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5033 SetLastError(ERROR_INVALID_LEVEL
);
5037 if(pDriverInfo
&& cbBuf
> 0)
5038 memset( pDriverInfo
, 0, cbBuf
);
5040 /* Exception: pull all printers */
5041 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5043 DWORD i
, needed
, bufsize
= cbBuf
;
5044 DWORD total_needed
= 0;
5045 DWORD total_found
= 0;
5048 /* Precompute the overall total; we need this to know
5049 where pointers end and data begins (i.e. data_offset) */
5050 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5053 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5054 NULL
, 0, 0, &needed
, &found
, 0);
5055 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5056 total_needed
+= needed
;
5057 total_found
+= found
;
5060 data_offset
= di_sizeof
[Level
] * total_found
;
5065 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5068 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5069 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5070 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5072 *pcReturned
+= found
;
5073 *pcbNeeded
= needed
;
5074 data_offset
= needed
;
5075 total_found
+= found
;
5080 /* Normal behavior */
5081 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5082 0, cbBuf
, pcbNeeded
, &found
, 0);
5084 *pcReturned
= found
;
5089 /*****************************************************************************
5090 * EnumPrinterDriversA [WINSPOOL.@]
5092 * see function EnumPrinterDrivers for RETURNS, BUGS
5094 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5095 LPBYTE pDriverInfo
, DWORD cbBuf
,
5096 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5099 UNICODE_STRING pNameW
, pEnvironmentW
;
5100 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5104 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5106 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5107 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5109 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5110 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5112 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5114 HeapFree(GetProcessHeap(), 0, buf
);
5116 RtlFreeUnicodeString(&pNameW
);
5117 RtlFreeUnicodeString(&pEnvironmentW
);
5122 /******************************************************************************
5123 * EnumPortsA (WINSPOOL.@)
5128 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5129 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5132 LPBYTE bufferW
= NULL
;
5133 LPWSTR nameW
= NULL
;
5135 DWORD numentries
= 0;
5138 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5139 cbBuf
, pcbNeeded
, pcReturned
);
5141 /* convert servername to unicode */
5143 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5144 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5145 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5147 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5148 needed
= cbBuf
* sizeof(WCHAR
);
5149 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5150 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5152 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5153 if (pcbNeeded
) needed
= *pcbNeeded
;
5154 /* HeapReAlloc return NULL, when bufferW was NULL */
5155 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5156 HeapAlloc(GetProcessHeap(), 0, needed
);
5158 /* Try again with the large Buffer */
5159 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5161 needed
= pcbNeeded
? *pcbNeeded
: 0;
5162 numentries
= pcReturned
? *pcReturned
: 0;
5165 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5166 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5169 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5170 DWORD entrysize
= 0;
5173 LPPORT_INFO_2W pi2w
;
5174 LPPORT_INFO_2A pi2a
;
5177 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5179 /* First pass: calculate the size for all Entries */
5180 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5181 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5183 while (index
< numentries
) {
5185 needed
+= entrysize
; /* PORT_INFO_?A */
5186 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5188 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5189 NULL
, 0, NULL
, NULL
);
5191 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5192 NULL
, 0, NULL
, NULL
);
5193 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5194 NULL
, 0, NULL
, NULL
);
5196 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5197 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5198 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5201 /* check for errors and quit on failure */
5202 if (cbBuf
< needed
) {
5203 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5207 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5208 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5209 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5210 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5211 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5213 /* Second Pass: Fill the User Buffer (if we have one) */
5214 while ((index
< numentries
) && pPorts
) {
5216 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5217 pi2a
->pPortName
= ptr
;
5218 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5219 ptr
, cbBuf
, NULL
, NULL
);
5223 pi2a
->pMonitorName
= ptr
;
5224 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5225 ptr
, cbBuf
, NULL
, NULL
);
5229 pi2a
->pDescription
= ptr
;
5230 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5231 ptr
, cbBuf
, NULL
, NULL
);
5235 pi2a
->fPortType
= pi2w
->fPortType
;
5236 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5239 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5240 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5241 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5246 if (pcbNeeded
) *pcbNeeded
= needed
;
5247 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5249 HeapFree(GetProcessHeap(), 0, nameW
);
5250 HeapFree(GetProcessHeap(), 0, bufferW
);
5252 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5253 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5259 /******************************************************************************
5260 * EnumPortsW (WINSPOOL.@)
5262 * Enumerate available Ports
5265 * pName [I] Servername or NULL (local Computer)
5266 * Level [I] Structure-Level (1 or 2)
5267 * pPorts [O] PTR to Buffer that receives the Result
5268 * cbBuf [I] Size of Buffer at pPorts
5269 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5270 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5274 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5277 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5280 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5281 cbBuf
, pcbNeeded
, pcReturned
);
5283 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5285 /* Level is not checked in win9x */
5286 if (!Level
|| (Level
> 2)) {
5287 WARN("level (%d) is ignored in win9x\n", Level
);
5288 SetLastError(ERROR_INVALID_LEVEL
);
5291 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5292 SetLastError(RPC_X_NULL_REF_POINTER
);
5296 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5299 /******************************************************************************
5300 * GetDefaultPrinterW (WINSPOOL.@)
5303 * This function must read the value from data 'device' of key
5304 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5306 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5310 WCHAR
*buffer
, *ptr
;
5314 SetLastError(ERROR_INVALID_PARAMETER
);
5318 /* make the buffer big enough for the stuff from the profile/registry,
5319 * the content must fit into the local buffer to compute the correct
5320 * size even if the extern buffer is too small or not given.
5321 * (20 for ,driver,port) */
5323 len
= max(100, (insize
+ 20));
5324 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5326 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5328 SetLastError (ERROR_FILE_NOT_FOUND
);
5332 TRACE("%s\n", debugstr_w(buffer
));
5334 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5336 SetLastError(ERROR_INVALID_NAME
);
5342 *namesize
= strlenW(buffer
) + 1;
5343 if(!name
|| (*namesize
> insize
))
5345 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5349 strcpyW(name
, buffer
);
5352 HeapFree( GetProcessHeap(), 0, buffer
);
5357 /******************************************************************************
5358 * GetDefaultPrinterA (WINSPOOL.@)
5360 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5364 WCHAR
*bufferW
= NULL
;
5368 SetLastError(ERROR_INVALID_PARAMETER
);
5372 if(name
&& *namesize
) {
5374 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5377 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5382 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5386 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5389 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5392 HeapFree( GetProcessHeap(), 0, bufferW
);
5397 /******************************************************************************
5398 * SetDefaultPrinterW (WINSPOOL.204)
5400 * Set the Name of the Default Printer
5403 * pszPrinter [I] Name of the Printer or NULL
5410 * When the Parameter is NULL or points to an Empty String and
5411 * a Default Printer was already present, then this Function changes nothing.
5412 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5413 * the First enumerated local Printer is used.
5416 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5418 WCHAR default_printer
[MAX_PATH
];
5419 LPWSTR buffer
= NULL
;
5425 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5426 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5428 default_printer
[0] = '\0';
5429 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5431 /* if we have a default Printer, do nothing. */
5432 if (GetDefaultPrinterW(default_printer
, &size
))
5436 /* we have no default Printer: search local Printers and use the first */
5437 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5439 default_printer
[0] = '\0';
5440 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5441 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5443 pszPrinter
= default_printer
;
5444 TRACE("using %s\n", debugstr_w(pszPrinter
));
5449 if (pszPrinter
== NULL
) {
5450 TRACE("no local printer found\n");
5451 SetLastError(ERROR_FILE_NOT_FOUND
);
5456 /* "pszPrinter" is never empty or NULL here. */
5457 namelen
= lstrlenW(pszPrinter
);
5458 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5459 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5461 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5462 HeapFree(GetProcessHeap(), 0, buffer
);
5463 SetLastError(ERROR_FILE_NOT_FOUND
);
5467 /* read the devices entry for the printer (driver,port) to build the string for the
5468 default device entry (printer,driver,port) */
5469 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5470 buffer
[namelen
] = ',';
5471 namelen
++; /* move index to the start of the driver */
5473 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5474 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5476 TRACE("set device to %s\n", debugstr_w(buffer
));
5478 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5479 TRACE("failed to set the device entry: %d\n", GetLastError());
5480 lres
= ERROR_INVALID_PRINTER_NAME
;
5483 /* remove the next section, when INIFileMapping is implemented */
5486 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5487 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5494 if (lres
!= ERROR_FILE_NOT_FOUND
)
5495 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5497 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5501 HeapFree(GetProcessHeap(), 0, buffer
);
5502 return (lres
== ERROR_SUCCESS
);
5505 /******************************************************************************
5506 * SetDefaultPrinterA (WINSPOOL.202)
5508 * See SetDefaultPrinterW.
5511 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5513 LPWSTR bufferW
= NULL
;
5516 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5518 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5519 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5520 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5522 res
= SetDefaultPrinterW(bufferW
);
5523 HeapFree(GetProcessHeap(), 0, bufferW
);
5527 /******************************************************************************
5528 * SetPrinterDataExA (WINSPOOL.@)
5530 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5531 LPCSTR pValueName
, DWORD Type
,
5532 LPBYTE pData
, DWORD cbData
)
5534 HKEY hkeyPrinter
, hkeySubkey
;
5537 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5538 debugstr_a(pValueName
), Type
, pData
, cbData
);
5540 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5544 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5546 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5547 RegCloseKey(hkeyPrinter
);
5550 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5551 RegCloseKey(hkeySubkey
);
5552 RegCloseKey(hkeyPrinter
);
5556 /******************************************************************************
5557 * SetPrinterDataExW (WINSPOOL.@)
5559 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5560 LPCWSTR pValueName
, DWORD Type
,
5561 LPBYTE pData
, DWORD cbData
)
5563 HKEY hkeyPrinter
, hkeySubkey
;
5566 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5567 debugstr_w(pValueName
), Type
, pData
, cbData
);
5569 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5573 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5575 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5576 RegCloseKey(hkeyPrinter
);
5579 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5580 RegCloseKey(hkeySubkey
);
5581 RegCloseKey(hkeyPrinter
);
5585 /******************************************************************************
5586 * SetPrinterDataA (WINSPOOL.@)
5588 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5589 LPBYTE pData
, DWORD cbData
)
5591 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5595 /******************************************************************************
5596 * SetPrinterDataW (WINSPOOL.@)
5598 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5599 LPBYTE pData
, DWORD cbData
)
5601 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5605 /******************************************************************************
5606 * GetPrinterDataExA (WINSPOOL.@)
5608 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5609 LPCSTR pValueName
, LPDWORD pType
,
5610 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5612 opened_printer_t
*printer
;
5613 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5616 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5617 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5619 printer
= get_opened_printer(hPrinter
);
5620 if(!printer
) return ERROR_INVALID_HANDLE
;
5622 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5623 if (ret
) return ret
;
5625 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5627 if (printer
->name
) {
5629 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5631 RegCloseKey(hkeyPrinters
);
5634 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5635 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5636 RegCloseKey(hkeyPrinter
);
5637 RegCloseKey(hkeyPrinters
);
5642 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5643 0, pType
, pData
, pcbNeeded
);
5645 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5647 RegCloseKey(hkeySubkey
);
5648 RegCloseKey(hkeyPrinter
);
5649 RegCloseKey(hkeyPrinters
);
5651 TRACE("--> %d\n", ret
);
5655 /******************************************************************************
5656 * GetPrinterDataExW (WINSPOOL.@)
5658 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5659 LPCWSTR pValueName
, LPDWORD pType
,
5660 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5662 opened_printer_t
*printer
;
5663 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5666 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5667 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5669 printer
= get_opened_printer(hPrinter
);
5670 if(!printer
) return ERROR_INVALID_HANDLE
;
5672 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5673 if (ret
) return ret
;
5675 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5677 if (printer
->name
) {
5679 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5681 RegCloseKey(hkeyPrinters
);
5684 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5685 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5686 RegCloseKey(hkeyPrinter
);
5687 RegCloseKey(hkeyPrinters
);
5692 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5693 0, pType
, pData
, pcbNeeded
);
5695 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5697 RegCloseKey(hkeySubkey
);
5698 RegCloseKey(hkeyPrinter
);
5699 RegCloseKey(hkeyPrinters
);
5701 TRACE("--> %d\n", ret
);
5705 /******************************************************************************
5706 * GetPrinterDataA (WINSPOOL.@)
5708 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5709 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5711 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5712 pData
, nSize
, pcbNeeded
);
5715 /******************************************************************************
5716 * GetPrinterDataW (WINSPOOL.@)
5718 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5719 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5721 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5722 pData
, nSize
, pcbNeeded
);
5725 /*******************************************************************************
5726 * EnumPrinterDataExW [WINSPOOL.@]
5728 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5729 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5730 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5732 HKEY hkPrinter
, hkSubKey
;
5733 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5734 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5739 PPRINTER_ENUM_VALUESW ppev
;
5741 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5743 if (pKeyName
== NULL
|| *pKeyName
== 0)
5744 return ERROR_INVALID_PARAMETER
;
5746 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5747 if (ret
!= ERROR_SUCCESS
)
5749 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5754 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5755 if (ret
!= ERROR_SUCCESS
)
5757 r
= RegCloseKey (hkPrinter
);
5758 if (r
!= ERROR_SUCCESS
)
5759 WARN ("RegCloseKey returned %i\n", r
);
5760 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5761 debugstr_w (pKeyName
), ret
);
5765 ret
= RegCloseKey (hkPrinter
);
5766 if (ret
!= ERROR_SUCCESS
)
5768 ERR ("RegCloseKey returned %i\n", ret
);
5769 r
= RegCloseKey (hkSubKey
);
5770 if (r
!= ERROR_SUCCESS
)
5771 WARN ("RegCloseKey returned %i\n", r
);
5775 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5776 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5777 if (ret
!= ERROR_SUCCESS
)
5779 r
= RegCloseKey (hkSubKey
);
5780 if (r
!= ERROR_SUCCESS
)
5781 WARN ("RegCloseKey returned %i\n", r
);
5782 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5786 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5787 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5789 if (cValues
== 0) /* empty key */
5791 r
= RegCloseKey (hkSubKey
);
5792 if (r
!= ERROR_SUCCESS
)
5793 WARN ("RegCloseKey returned %i\n", r
);
5794 *pcbEnumValues
= *pnEnumValues
= 0;
5795 return ERROR_SUCCESS
;
5798 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5800 hHeap
= GetProcessHeap ();
5803 ERR ("GetProcessHeap failed\n");
5804 r
= RegCloseKey (hkSubKey
);
5805 if (r
!= ERROR_SUCCESS
)
5806 WARN ("RegCloseKey returned %i\n", r
);
5807 return ERROR_OUTOFMEMORY
;
5810 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5811 if (lpValueName
== NULL
)
5813 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5814 r
= RegCloseKey (hkSubKey
);
5815 if (r
!= ERROR_SUCCESS
)
5816 WARN ("RegCloseKey returned %i\n", r
);
5817 return ERROR_OUTOFMEMORY
;
5820 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5821 if (lpValue
== NULL
)
5823 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5824 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 r
= RegCloseKey (hkSubKey
);
5827 if (r
!= ERROR_SUCCESS
)
5828 WARN ("RegCloseKey returned %i\n", r
);
5829 return ERROR_OUTOFMEMORY
;
5832 TRACE ("pass 1: calculating buffer required for all names and values\n");
5834 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5836 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5838 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5840 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5841 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5842 NULL
, NULL
, lpValue
, &cbValueLen
);
5843 if (ret
!= ERROR_SUCCESS
)
5845 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5846 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 r
= RegCloseKey (hkSubKey
);
5850 if (r
!= ERROR_SUCCESS
)
5851 WARN ("RegCloseKey returned %i\n", r
);
5852 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5856 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5857 debugstr_w (lpValueName
), dwIndex
,
5858 cbValueNameLen
+ 1, cbValueLen
);
5860 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5861 cbBufSize
+= cbValueLen
;
5864 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5866 *pcbEnumValues
= cbBufSize
;
5867 *pnEnumValues
= cValues
;
5869 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5871 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5874 WARN ("HeapFree failed with code %i\n", GetLastError ());
5875 r
= RegCloseKey (hkSubKey
);
5876 if (r
!= ERROR_SUCCESS
)
5877 WARN ("RegCloseKey returned %i\n", r
);
5878 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5879 return ERROR_MORE_DATA
;
5882 TRACE ("pass 2: copying all names and values to buffer\n");
5884 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5885 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5887 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5889 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5890 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5891 NULL
, &dwType
, lpValue
, &cbValueLen
);
5892 if (ret
!= ERROR_SUCCESS
)
5894 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5895 WARN ("HeapFree failed with code %i\n", GetLastError ());
5896 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5897 WARN ("HeapFree failed with code %i\n", GetLastError ());
5898 r
= RegCloseKey (hkSubKey
);
5899 if (r
!= ERROR_SUCCESS
)
5900 WARN ("RegCloseKey returned %i\n", r
);
5901 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5905 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5906 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5907 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5908 pEnumValues
+= cbValueNameLen
;
5910 /* return # of *bytes* (including trailing \0), not # of chars */
5911 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5913 ppev
[dwIndex
].dwType
= dwType
;
5915 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5916 ppev
[dwIndex
].pData
= pEnumValues
;
5917 pEnumValues
+= cbValueLen
;
5919 ppev
[dwIndex
].cbData
= cbValueLen
;
5921 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5922 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5925 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5927 ret
= GetLastError ();
5928 ERR ("HeapFree failed with code %i\n", ret
);
5929 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5931 r
= RegCloseKey (hkSubKey
);
5932 if (r
!= ERROR_SUCCESS
)
5933 WARN ("RegCloseKey returned %i\n", r
);
5937 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5939 ret
= GetLastError ();
5940 ERR ("HeapFree failed with code %i\n", ret
);
5941 r
= RegCloseKey (hkSubKey
);
5942 if (r
!= ERROR_SUCCESS
)
5943 WARN ("RegCloseKey returned %i\n", r
);
5947 ret
= RegCloseKey (hkSubKey
);
5948 if (ret
!= ERROR_SUCCESS
)
5950 ERR ("RegCloseKey returned %i\n", ret
);
5954 return ERROR_SUCCESS
;
5957 /*******************************************************************************
5958 * EnumPrinterDataExA [WINSPOOL.@]
5960 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5961 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5962 * what Windows 2000 SP1 does.
5965 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5966 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5967 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5971 DWORD ret
, dwIndex
, dwBufSize
;
5975 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5977 if (pKeyName
== NULL
|| *pKeyName
== 0)
5978 return ERROR_INVALID_PARAMETER
;
5980 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5983 ret
= GetLastError ();
5984 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5988 hHeap
= GetProcessHeap ();
5991 ERR ("GetProcessHeap failed\n");
5992 return ERROR_OUTOFMEMORY
;
5995 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5996 if (pKeyNameW
== NULL
)
5998 ERR ("Failed to allocate %i bytes from process heap\n",
5999 (LONG
)(len
* sizeof (WCHAR
)));
6000 return ERROR_OUTOFMEMORY
;
6003 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6005 ret
= GetLastError ();
6006 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6007 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6008 WARN ("HeapFree failed with code %i\n", GetLastError ());
6012 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6013 pcbEnumValues
, pnEnumValues
);
6014 if (ret
!= ERROR_SUCCESS
)
6016 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6017 WARN ("HeapFree failed with code %i\n", GetLastError ());
6018 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6022 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6024 ret
= GetLastError ();
6025 ERR ("HeapFree failed with code %i\n", ret
);
6029 if (*pnEnumValues
== 0) /* empty key */
6030 return ERROR_SUCCESS
;
6033 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6035 PPRINTER_ENUM_VALUESW ppev
=
6036 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6038 if (dwBufSize
< ppev
->cbValueName
)
6039 dwBufSize
= ppev
->cbValueName
;
6041 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6042 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6043 dwBufSize
= ppev
->cbData
;
6046 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6048 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6049 if (pBuffer
== NULL
)
6051 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6052 return ERROR_OUTOFMEMORY
;
6055 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6057 PPRINTER_ENUM_VALUESW ppev
=
6058 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6060 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6061 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6065 ret
= GetLastError ();
6066 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6067 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6068 WARN ("HeapFree failed with code %i\n", GetLastError ());
6072 memcpy (ppev
->pValueName
, pBuffer
, len
);
6074 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6076 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6077 ppev
->dwType
!= REG_MULTI_SZ
)
6080 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6081 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6084 ret
= GetLastError ();
6085 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6086 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6087 WARN ("HeapFree failed with code %i\n", GetLastError ());
6091 memcpy (ppev
->pData
, pBuffer
, len
);
6093 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6094 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6097 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6099 ret
= GetLastError ();
6100 ERR ("HeapFree failed with code %i\n", ret
);
6104 return ERROR_SUCCESS
;
6107 /******************************************************************************
6108 * AbortPrinter (WINSPOOL.@)
6110 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6112 FIXME("(%p), stub!\n", hPrinter
);
6116 /******************************************************************************
6117 * AddPortA (WINSPOOL.@)
6122 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6124 LPWSTR nameW
= NULL
;
6125 LPWSTR monitorW
= NULL
;
6129 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6132 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6133 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6134 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6138 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6139 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6140 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6142 res
= AddPortW(nameW
, hWnd
, monitorW
);
6143 HeapFree(GetProcessHeap(), 0, nameW
);
6144 HeapFree(GetProcessHeap(), 0, monitorW
);
6148 /******************************************************************************
6149 * AddPortW (WINSPOOL.@)
6151 * Add a Port for a specific Monitor
6154 * pName [I] Servername or NULL (local Computer)
6155 * hWnd [I] Handle to parent Window for the Dialog-Box
6156 * pMonitorName [I] Name of the Monitor that manage the Port
6163 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6165 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6167 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6169 if (!pMonitorName
) {
6170 SetLastError(RPC_X_NULL_REF_POINTER
);
6174 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6177 /******************************************************************************
6178 * AddPortExA (WINSPOOL.@)
6183 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6186 PORT_INFO_2A
* pi2A
;
6187 LPWSTR nameW
= NULL
;
6188 LPWSTR monitorW
= NULL
;
6192 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6194 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6195 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6197 if ((level
< 1) || (level
> 2)) {
6198 SetLastError(ERROR_INVALID_LEVEL
);
6203 SetLastError(ERROR_INVALID_PARAMETER
);
6208 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6209 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6210 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6214 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6215 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6216 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6219 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6221 if (pi2A
->pPortName
) {
6222 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6223 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6224 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6228 if (pi2A
->pMonitorName
) {
6229 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6230 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6231 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6234 if (pi2A
->pDescription
) {
6235 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6236 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6237 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6239 pi2W
.fPortType
= pi2A
->fPortType
;
6240 pi2W
.Reserved
= pi2A
->Reserved
;
6243 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6245 HeapFree(GetProcessHeap(), 0, nameW
);
6246 HeapFree(GetProcessHeap(), 0, monitorW
);
6247 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6248 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6249 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6254 /******************************************************************************
6255 * AddPortExW (WINSPOOL.@)
6257 * Add a Port for a specific Monitor, without presenting a user interface
6260 * pName [I] Servername or NULL (local Computer)
6261 * level [I] Structure-Level (1 or 2) for pBuffer
6262 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6263 * pMonitorName [I] Name of the Monitor that manage the Port
6270 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6274 pi2
= (PORT_INFO_2W
*) pBuffer
;
6276 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6277 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6278 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6279 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6281 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6283 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6284 SetLastError(ERROR_INVALID_PARAMETER
);
6288 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6291 /******************************************************************************
6292 * AddPrinterConnectionA (WINSPOOL.@)
6294 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6296 FIXME("%s\n", debugstr_a(pName
));
6300 /******************************************************************************
6301 * AddPrinterConnectionW (WINSPOOL.@)
6303 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6305 FIXME("%s\n", debugstr_w(pName
));
6309 /******************************************************************************
6310 * AddPrinterDriverExW (WINSPOOL.@)
6312 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6315 * pName [I] Servername or NULL (local Computer)
6316 * level [I] Level for the supplied DRIVER_INFO_*W struct
6317 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6318 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6325 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6327 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6329 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6331 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6332 SetLastError(ERROR_INVALID_LEVEL
);
6337 SetLastError(ERROR_INVALID_PARAMETER
);
6341 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6344 /******************************************************************************
6345 * AddPrinterDriverExA (WINSPOOL.@)
6347 * See AddPrinterDriverExW.
6350 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6352 DRIVER_INFO_8A
*diA
;
6354 LPWSTR nameW
= NULL
;
6359 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6361 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6362 ZeroMemory(&diW
, sizeof(diW
));
6364 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6365 SetLastError(ERROR_INVALID_LEVEL
);
6370 SetLastError(ERROR_INVALID_PARAMETER
);
6374 /* convert servername to unicode */
6376 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6377 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6378 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6382 diW
.cVersion
= diA
->cVersion
;
6385 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6386 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6387 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6390 if (diA
->pEnvironment
) {
6391 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6392 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6393 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6396 if (diA
->pDriverPath
) {
6397 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6398 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6399 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6402 if (diA
->pDataFile
) {
6403 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6404 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6405 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6408 if (diA
->pConfigFile
) {
6409 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6410 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6411 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6414 if ((Level
> 2) && diA
->pDependentFiles
) {
6415 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6416 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6417 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6418 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6421 if ((Level
> 2) && diA
->pMonitorName
) {
6422 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6423 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6424 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6427 if ((Level
> 3) && diA
->pDefaultDataType
) {
6428 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6429 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6430 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6433 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6434 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6435 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6436 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6437 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6440 if ((Level
> 5) && diA
->pszMfgName
) {
6441 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6442 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6443 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6446 if ((Level
> 5) && diA
->pszOEMUrl
) {
6447 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6448 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6449 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6452 if ((Level
> 5) && diA
->pszHardwareID
) {
6453 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6454 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6455 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6458 if ((Level
> 5) && diA
->pszProvider
) {
6459 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6460 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6461 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6465 FIXME("level %u is incomplete\n", Level
);
6468 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6469 TRACE("got %u with %u\n", res
, GetLastError());
6470 HeapFree(GetProcessHeap(), 0, nameW
);
6471 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6472 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6473 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6474 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6475 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6476 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6477 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6478 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6479 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6480 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6481 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6482 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6483 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6485 TRACE("=> %u with %u\n", res
, GetLastError());
6489 /******************************************************************************
6490 * ConfigurePortA (WINSPOOL.@)
6492 * See ConfigurePortW.
6495 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6497 LPWSTR nameW
= NULL
;
6498 LPWSTR portW
= NULL
;
6502 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6504 /* convert servername to unicode */
6506 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6507 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6508 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6511 /* convert portname to unicode */
6513 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6514 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6515 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6518 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6519 HeapFree(GetProcessHeap(), 0, nameW
);
6520 HeapFree(GetProcessHeap(), 0, portW
);
6524 /******************************************************************************
6525 * ConfigurePortW (WINSPOOL.@)
6527 * Display the Configuration-Dialog for a specific Port
6530 * pName [I] Servername or NULL (local Computer)
6531 * hWnd [I] Handle to parent Window for the Dialog-Box
6532 * pPortName [I] Name of the Port, that should be configured
6539 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6542 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6544 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6547 SetLastError(RPC_X_NULL_REF_POINTER
);
6551 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6554 /******************************************************************************
6555 * ConnectToPrinterDlg (WINSPOOL.@)
6557 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6559 FIXME("%p %x\n", hWnd
, Flags
);
6563 /******************************************************************************
6564 * DeletePrinterConnectionA (WINSPOOL.@)
6566 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6568 FIXME("%s\n", debugstr_a(pName
));
6572 /******************************************************************************
6573 * DeletePrinterConnectionW (WINSPOOL.@)
6575 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6577 FIXME("%s\n", debugstr_w(pName
));
6581 /******************************************************************************
6582 * DeletePrinterDriverExW (WINSPOOL.@)
6584 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6585 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6590 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6591 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6593 if(pName
&& pName
[0])
6595 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6596 SetLastError(ERROR_INVALID_PARAMETER
);
6602 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6603 SetLastError(ERROR_INVALID_PARAMETER
);
6607 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6611 ERR("Can't open drivers key\n");
6615 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6618 RegCloseKey(hkey_drivers
);
6623 /******************************************************************************
6624 * DeletePrinterDriverExA (WINSPOOL.@)
6626 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6627 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6629 UNICODE_STRING NameW
, EnvW
, DriverW
;
6632 asciitounicode(&NameW
, pName
);
6633 asciitounicode(&EnvW
, pEnvironment
);
6634 asciitounicode(&DriverW
, pDriverName
);
6636 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6638 RtlFreeUnicodeString(&DriverW
);
6639 RtlFreeUnicodeString(&EnvW
);
6640 RtlFreeUnicodeString(&NameW
);
6645 /******************************************************************************
6646 * DeletePrinterDataExW (WINSPOOL.@)
6648 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6651 FIXME("%p %s %s\n", hPrinter
,
6652 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6653 return ERROR_INVALID_PARAMETER
;
6656 /******************************************************************************
6657 * DeletePrinterDataExA (WINSPOOL.@)
6659 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6662 FIXME("%p %s %s\n", hPrinter
,
6663 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6664 return ERROR_INVALID_PARAMETER
;
6667 /******************************************************************************
6668 * DeletePrintProcessorA (WINSPOOL.@)
6670 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6672 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6673 debugstr_a(pPrintProcessorName
));
6677 /******************************************************************************
6678 * DeletePrintProcessorW (WINSPOOL.@)
6680 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6682 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6683 debugstr_w(pPrintProcessorName
));
6687 /******************************************************************************
6688 * DeletePrintProvidorA (WINSPOOL.@)
6690 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6692 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6693 debugstr_a(pPrintProviderName
));
6697 /******************************************************************************
6698 * DeletePrintProvidorW (WINSPOOL.@)
6700 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6702 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6703 debugstr_w(pPrintProviderName
));
6707 /******************************************************************************
6708 * EnumFormsA (WINSPOOL.@)
6710 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6711 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6713 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6714 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6718 /******************************************************************************
6719 * EnumFormsW (WINSPOOL.@)
6721 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6722 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6724 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6725 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6729 /*****************************************************************************
6730 * EnumMonitorsA [WINSPOOL.@]
6732 * See EnumMonitorsW.
6735 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6736 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6739 LPBYTE bufferW
= NULL
;
6740 LPWSTR nameW
= NULL
;
6742 DWORD numentries
= 0;
6745 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6746 cbBuf
, pcbNeeded
, pcReturned
);
6748 /* convert servername to unicode */
6750 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6751 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6752 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6754 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6755 needed
= cbBuf
* sizeof(WCHAR
);
6756 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6757 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6759 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6760 if (pcbNeeded
) needed
= *pcbNeeded
;
6761 /* HeapReAlloc return NULL, when bufferW was NULL */
6762 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6763 HeapAlloc(GetProcessHeap(), 0, needed
);
6765 /* Try again with the large Buffer */
6766 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6768 numentries
= pcReturned
? *pcReturned
: 0;
6771 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6772 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6775 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6776 DWORD entrysize
= 0;
6779 LPMONITOR_INFO_2W mi2w
;
6780 LPMONITOR_INFO_2A mi2a
;
6782 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6783 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6785 /* First pass: calculate the size for all Entries */
6786 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6787 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6789 while (index
< numentries
) {
6791 needed
+= entrysize
; /* MONITOR_INFO_?A */
6792 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6794 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6795 NULL
, 0, NULL
, NULL
);
6797 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6798 NULL
, 0, NULL
, NULL
);
6799 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6800 NULL
, 0, NULL
, NULL
);
6802 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6803 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6804 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6807 /* check for errors and quit on failure */
6808 if (cbBuf
< needed
) {
6809 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6813 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6814 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6815 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6816 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6817 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6819 /* Second Pass: Fill the User Buffer (if we have one) */
6820 while ((index
< numentries
) && pMonitors
) {
6822 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6824 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6825 ptr
, cbBuf
, NULL
, NULL
);
6829 mi2a
->pEnvironment
= ptr
;
6830 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6831 ptr
, cbBuf
, NULL
, NULL
);
6835 mi2a
->pDLLName
= ptr
;
6836 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6837 ptr
, cbBuf
, NULL
, NULL
);
6841 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6842 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6843 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6847 if (pcbNeeded
) *pcbNeeded
= needed
;
6848 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6850 HeapFree(GetProcessHeap(), 0, nameW
);
6851 HeapFree(GetProcessHeap(), 0, bufferW
);
6853 TRACE("returning %d with %d (%d byte for %d entries)\n",
6854 (res
), GetLastError(), needed
, numentries
);
6860 /*****************************************************************************
6861 * EnumMonitorsW [WINSPOOL.@]
6863 * Enumerate available Port-Monitors
6866 * pName [I] Servername or NULL (local Computer)
6867 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6868 * pMonitors [O] PTR to Buffer that receives the Result
6869 * cbBuf [I] Size of Buffer at pMonitors
6870 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6871 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6875 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6878 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6879 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6882 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6883 cbBuf
, pcbNeeded
, pcReturned
);
6885 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6887 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6888 SetLastError(RPC_X_NULL_REF_POINTER
);
6892 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6895 /******************************************************************************
6896 * SpoolerInit (WINSPOOL.@)
6898 * Initialize the Spooler
6905 * The function fails on windows, when the spooler service is not running
6908 BOOL WINAPI
SpoolerInit(void)
6911 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6915 /******************************************************************************
6916 * XcvDataW (WINSPOOL.@)
6918 * Execute commands in the Printmonitor DLL
6921 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6922 * pszDataName [i] Name of the command to execute
6923 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6924 * cbInputData [i] Size in Bytes of Buffer at pInputData
6925 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6926 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6927 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6928 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6935 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6936 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6938 * Minimal List of commands, that a Printmonitor DLL should support:
6940 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6941 *| "AddPort" : Add a Port
6942 *| "DeletePort": Delete a Port
6944 * Many Printmonitors support additional commands. Examples for localspl.dll:
6945 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6946 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6949 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6950 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6951 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6953 opened_printer_t
*printer
;
6955 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6956 pInputData
, cbInputData
, pOutputData
,
6957 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6959 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6961 printer
= get_opened_printer(hXcv
);
6962 if (!printer
|| (!printer
->backend_printer
)) {
6963 SetLastError(ERROR_INVALID_HANDLE
);
6967 if (!pcbOutputNeeded
) {
6968 SetLastError(ERROR_INVALID_PARAMETER
);
6972 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6973 SetLastError(RPC_X_NULL_REF_POINTER
);
6977 *pcbOutputNeeded
= 0;
6979 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6980 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6984 /*****************************************************************************
6985 * EnumPrinterDataA [WINSPOOL.@]
6988 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6989 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6990 DWORD cbData
, LPDWORD pcbData
)
6992 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6993 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6994 return ERROR_NO_MORE_ITEMS
;
6997 /*****************************************************************************
6998 * EnumPrinterDataW [WINSPOOL.@]
7001 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7002 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7003 DWORD cbData
, LPDWORD pcbData
)
7005 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7006 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7007 return ERROR_NO_MORE_ITEMS
;
7010 /*****************************************************************************
7011 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7014 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7015 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7016 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7018 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7019 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7020 pcbNeeded
, pcReturned
);
7024 /*****************************************************************************
7025 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7028 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7029 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7030 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7032 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7033 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7034 pcbNeeded
, pcReturned
);
7038 /*****************************************************************************
7039 * EnumPrintProcessorsA [WINSPOOL.@]
7041 * See EnumPrintProcessorsW.
7044 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7045 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7048 LPBYTE bufferW
= NULL
;
7049 LPWSTR nameW
= NULL
;
7052 DWORD numentries
= 0;
7055 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7056 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7058 /* convert names to unicode */
7060 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7061 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7062 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7065 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7066 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7067 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7070 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7071 needed
= cbBuf
* sizeof(WCHAR
);
7072 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7073 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7075 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7076 if (pcbNeeded
) needed
= *pcbNeeded
;
7077 /* HeapReAlloc return NULL, when bufferW was NULL */
7078 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7079 HeapAlloc(GetProcessHeap(), 0, needed
);
7081 /* Try again with the large Buffer */
7082 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7084 numentries
= pcReturned
? *pcReturned
: 0;
7088 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7091 PPRINTPROCESSOR_INFO_1W ppiw
;
7092 PPRINTPROCESSOR_INFO_1A ppia
;
7094 /* First pass: calculate the size for all Entries */
7095 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7096 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7098 while (index
< numentries
) {
7100 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7101 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7103 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7104 NULL
, 0, NULL
, NULL
);
7106 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7107 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7110 /* check for errors and quit on failure */
7111 if (cbBuf
< needed
) {
7112 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7117 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7118 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7119 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7120 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7121 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7123 /* Second Pass: Fill the User Buffer (if we have one) */
7124 while ((index
< numentries
) && pPPInfo
) {
7126 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7128 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7129 ptr
, cbBuf
, NULL
, NULL
);
7133 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7134 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7139 if (pcbNeeded
) *pcbNeeded
= needed
;
7140 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7142 HeapFree(GetProcessHeap(), 0, nameW
);
7143 HeapFree(GetProcessHeap(), 0, envW
);
7144 HeapFree(GetProcessHeap(), 0, bufferW
);
7146 TRACE("returning %d with %d (%d byte for %d entries)\n",
7147 (res
), GetLastError(), needed
, numentries
);
7152 /*****************************************************************************
7153 * EnumPrintProcessorsW [WINSPOOL.@]
7155 * Enumerate available Print Processors
7158 * pName [I] Servername or NULL (local Computer)
7159 * pEnvironment [I] Printing-Environment or NULL (Default)
7160 * Level [I] Structure-Level (Only 1 is allowed)
7161 * pPPInfo [O] PTR to Buffer that receives the Result
7162 * cbBuf [I] Size of Buffer at pPPInfo
7163 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7164 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7168 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7171 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7172 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7175 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7176 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7178 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7180 if (!pcbNeeded
|| !pcReturned
) {
7181 SetLastError(RPC_X_NULL_REF_POINTER
);
7185 if (!pPPInfo
&& (cbBuf
> 0)) {
7186 SetLastError(ERROR_INVALID_USER_BUFFER
);
7190 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7191 cbBuf
, pcbNeeded
, pcReturned
);
7194 /*****************************************************************************
7195 * ExtDeviceMode [WINSPOOL.@]
7198 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7199 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7202 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7203 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7204 debugstr_a(pProfile
), fMode
);
7208 /*****************************************************************************
7209 * FindClosePrinterChangeNotification [WINSPOOL.@]
7212 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7214 FIXME("Stub: %p\n", hChange
);
7218 /*****************************************************************************
7219 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7222 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7223 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7225 FIXME("Stub: %p %x %x %p\n",
7226 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7227 return INVALID_HANDLE_VALUE
;
7230 /*****************************************************************************
7231 * FindNextPrinterChangeNotification [WINSPOOL.@]
7234 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7235 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7237 FIXME("Stub: %p %p %p %p\n",
7238 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7242 /*****************************************************************************
7243 * FreePrinterNotifyInfo [WINSPOOL.@]
7246 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7248 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7252 /*****************************************************************************
7255 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7256 * ansi depending on the unicode parameter.
7258 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7268 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7271 memcpy(ptr
, str
, *size
);
7278 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7281 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7288 /*****************************************************************************
7291 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7292 LPDWORD pcbNeeded
, BOOL unicode
)
7294 DWORD size
, left
= cbBuf
;
7295 BOOL space
= (cbBuf
> 0);
7302 ji1
->JobId
= job
->job_id
;
7305 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7306 if(space
&& size
<= left
)
7308 ji1
->pDocument
= (LPWSTR
)ptr
;
7316 if (job
->printer_name
)
7318 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7319 if(space
&& size
<= left
)
7321 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7333 /*****************************************************************************
7336 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7337 LPDWORD pcbNeeded
, BOOL unicode
)
7339 DWORD size
, left
= cbBuf
;
7341 BOOL space
= (cbBuf
> 0);
7343 LPDEVMODEA dmA
= NULL
;
7350 ji2
->JobId
= job
->job_id
;
7353 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7354 if(space
&& size
<= left
)
7356 ji2
->pDocument
= (LPWSTR
)ptr
;
7364 if (job
->printer_name
)
7366 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7367 if(space
&& size
<= left
)
7369 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7382 dmA
= DEVMODEdupWtoA(job
->devmode
);
7383 devmode
= (LPDEVMODEW
) dmA
;
7384 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7388 devmode
= job
->devmode
;
7389 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7393 FIXME("Can't convert DEVMODE W to A\n");
7396 /* align DEVMODE to a DWORD boundary */
7397 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7403 memcpy(ptr
, devmode
, size
-shift
);
7404 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7405 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7418 /*****************************************************************************
7421 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7422 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7425 DWORD needed
= 0, size
;
7429 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7431 EnterCriticalSection(&printer_handles_cs
);
7432 job
= get_job(hPrinter
, JobId
);
7439 size
= sizeof(JOB_INFO_1W
);
7444 memset(pJob
, 0, size
);
7448 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7453 size
= sizeof(JOB_INFO_2W
);
7458 memset(pJob
, 0, size
);
7462 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7467 size
= sizeof(JOB_INFO_3
);
7471 memset(pJob
, 0, size
);
7480 SetLastError(ERROR_INVALID_LEVEL
);
7484 *pcbNeeded
= needed
;
7486 LeaveCriticalSection(&printer_handles_cs
);
7490 /*****************************************************************************
7491 * GetJobA [WINSPOOL.@]
7494 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7495 DWORD cbBuf
, LPDWORD pcbNeeded
)
7497 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7500 /*****************************************************************************
7501 * GetJobW [WINSPOOL.@]
7504 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7505 DWORD cbBuf
, LPDWORD pcbNeeded
)
7507 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7510 /*****************************************************************************
7513 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7516 char *unixname
, *cmdA
;
7518 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7524 if(!(unixname
= wine_get_unix_file_name(filename
)))
7527 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7528 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7529 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7531 TRACE("printing with: %s\n", cmdA
);
7533 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7538 ERR("pipe() failed!\n");
7542 if ((pid
= fork()) == 0)
7548 /* reset signals that we previously set to SIG_IGN */
7549 signal(SIGPIPE
, SIG_DFL
);
7551 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7556 ERR("fork() failed!\n");
7560 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7561 write(fds
[1], buf
, no_read
);
7568 wret
= waitpid(pid
, &status
, 0);
7569 } while (wret
< 0 && errno
== EINTR
);
7572 ERR("waitpid() failed!\n");
7575 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7577 ERR("child process failed! %d\n", status
);
7584 if(file_fd
!= -1) close(file_fd
);
7585 if(fds
[0] != -1) close(fds
[0]);
7586 if(fds
[1] != -1) close(fds
[1]);
7588 HeapFree(GetProcessHeap(), 0, cmdA
);
7589 HeapFree(GetProcessHeap(), 0, unixname
);
7596 /*****************************************************************************
7599 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7602 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7605 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7606 sprintfW(cmd
, fmtW
, printer_name
);
7608 r
= schedule_pipe(cmd
, filename
);
7610 HeapFree(GetProcessHeap(), 0, cmd
);
7614 #ifdef SONAME_LIBCUPS
7615 /*****************************************************************************
7616 * get_cups_jobs_ticket_options
7618 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7619 * The CUPS scheduler only looks for these in Print-File requests, and since
7620 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7623 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
7625 FILE *fp
= fopen( file
, "r" );
7626 char buf
[257]; /* DSC max of 256 + '\0' */
7627 const char *ps_adobe
= "%!PS-Adobe-";
7628 const char *cups_job
= "%cupsJobTicket:";
7630 if (!fp
) return num_options
;
7631 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
7632 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
7633 while (fgets( buf
, sizeof(buf
), fp
))
7635 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
7636 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
7645 /*****************************************************************************
7648 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7650 #ifdef SONAME_LIBCUPS
7653 char *unixname
, *queue
, *unix_doc_title
;
7656 int num_options
= 0, i
;
7657 cups_option_t
*options
= NULL
;
7659 if(!(unixname
= wine_get_unix_file_name(filename
)))
7662 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7663 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7664 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7666 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7667 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7668 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7670 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
7672 TRACE( "printing via cups with options:\n" );
7673 for (i
= 0; i
< num_options
; i
++)
7674 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
7676 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
7678 pcupsFreeOptions( num_options
, options
);
7680 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7681 HeapFree(GetProcessHeap(), 0, queue
);
7682 HeapFree(GetProcessHeap(), 0, unixname
);
7688 return schedule_lpr(printer_name
, filename
);
7692 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7699 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7703 if(HIWORD(wparam
) == BN_CLICKED
)
7705 if(LOWORD(wparam
) == IDOK
)
7708 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7711 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7712 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7714 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7716 WCHAR caption
[200], message
[200];
7719 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7720 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7721 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7722 if(mb_ret
== IDCANCEL
)
7724 HeapFree(GetProcessHeap(), 0, filename
);
7728 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7729 if(hf
== INVALID_HANDLE_VALUE
)
7731 WCHAR caption
[200], message
[200];
7733 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7734 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7735 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7736 HeapFree(GetProcessHeap(), 0, filename
);
7740 DeleteFileW(filename
);
7741 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7743 EndDialog(hwnd
, IDOK
);
7746 if(LOWORD(wparam
) == IDCANCEL
)
7748 EndDialog(hwnd
, IDCANCEL
);
7757 /*****************************************************************************
7760 static BOOL
get_filename(LPWSTR
*filename
)
7762 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7763 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7766 /*****************************************************************************
7769 static BOOL
schedule_file(LPCWSTR filename
)
7771 LPWSTR output
= NULL
;
7773 if(get_filename(&output
))
7776 TRACE("copy to %s\n", debugstr_w(output
));
7777 r
= CopyFileW(filename
, output
, FALSE
);
7778 HeapFree(GetProcessHeap(), 0, output
);
7784 /*****************************************************************************
7787 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7789 int in_fd
, out_fd
, no_read
;
7792 char *unixname
, *outputA
;
7795 if(!(unixname
= wine_get_unix_file_name(filename
)))
7798 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7799 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7800 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7802 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7803 in_fd
= open(unixname
, O_RDONLY
);
7804 if(out_fd
== -1 || in_fd
== -1)
7807 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7808 write(out_fd
, buf
, no_read
);
7812 if(in_fd
!= -1) close(in_fd
);
7813 if(out_fd
!= -1) close(out_fd
);
7814 HeapFree(GetProcessHeap(), 0, outputA
);
7815 HeapFree(GetProcessHeap(), 0, unixname
);
7819 /*****************************************************************************
7820 * ScheduleJob [WINSPOOL.@]
7823 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7825 opened_printer_t
*printer
;
7827 struct list
*cursor
, *cursor2
;
7829 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7830 EnterCriticalSection(&printer_handles_cs
);
7831 printer
= get_opened_printer(hPrinter
);
7835 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7837 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7840 if(job
->job_id
!= dwJobID
) continue;
7842 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7843 if(hf
!= INVALID_HANDLE_VALUE
)
7845 PRINTER_INFO_5W
*pi5
= NULL
;
7846 LPWSTR portname
= job
->portname
;
7850 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7851 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7855 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7856 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7857 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7858 portname
= pi5
->pPortName
;
7860 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7861 debugstr_w(portname
));
7865 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7866 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7868 DWORD type
, count
= sizeof(output
);
7869 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7872 if(output
[0] == '|')
7874 ret
= schedule_pipe(output
+ 1, job
->filename
);
7878 ret
= schedule_unixfile(output
, job
->filename
);
7880 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7882 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7884 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7886 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7888 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7890 ret
= schedule_file(job
->filename
);
7894 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7896 HeapFree(GetProcessHeap(), 0, pi5
);
7898 DeleteFileW(job
->filename
);
7900 list_remove(cursor
);
7901 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7902 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7903 HeapFree(GetProcessHeap(), 0, job
->portname
);
7904 HeapFree(GetProcessHeap(), 0, job
->filename
);
7905 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7906 HeapFree(GetProcessHeap(), 0, job
);
7910 LeaveCriticalSection(&printer_handles_cs
);
7914 /*****************************************************************************
7915 * StartDocDlgA [WINSPOOL.@]
7917 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7919 UNICODE_STRING usBuffer
;
7922 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7925 docW
.cbSize
= sizeof(docW
);
7926 if (doc
->lpszDocName
)
7928 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7929 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7931 if (doc
->lpszOutput
)
7933 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7934 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7936 if (doc
->lpszDatatype
)
7938 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7939 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7941 docW
.fwType
= doc
->fwType
;
7943 retW
= StartDocDlgW(hPrinter
, &docW
);
7947 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7948 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7949 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7950 HeapFree(GetProcessHeap(), 0, retW
);
7953 HeapFree(GetProcessHeap(), 0, datatypeW
);
7954 HeapFree(GetProcessHeap(), 0, outputW
);
7955 HeapFree(GetProcessHeap(), 0, docnameW
);
7960 /*****************************************************************************
7961 * StartDocDlgW [WINSPOOL.@]
7963 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7964 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7965 * port is "FILE:". Also returns the full path if passed a relative path.
7967 * The caller should free the returned string from the process heap.
7969 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7974 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7976 PRINTER_INFO_5W
*pi5
;
7977 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7978 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7980 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7981 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7982 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7984 HeapFree(GetProcessHeap(), 0, pi5
);
7987 HeapFree(GetProcessHeap(), 0, pi5
);
7990 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7994 if (get_filename(&name
))
7996 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7998 HeapFree(GetProcessHeap(), 0, name
);
8001 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8002 GetFullPathNameW(name
, len
, ret
, NULL
);
8003 HeapFree(GetProcessHeap(), 0, name
);
8008 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8011 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8012 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8014 attr
= GetFileAttributesW(ret
);
8015 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8017 HeapFree(GetProcessHeap(), 0, ret
);