Fixed callback parameters (bogus hWave); added acm conversion for
[wine.git] / dlls / winspool / info.c
blob73c2aa9a0f0dc009df4439bd0e749fe2bdeef7e9
1 /*
2 * WINSPOOL functions
3 *
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 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <stddef.h>
15 #include "winspool.h"
16 #include "winbase.h"
17 #include "winerror.h"
18 #include "winreg.h"
19 #include "wine/windef16.h"
20 #include "wine/unicode.h"
21 #include "debugtools.h"
22 #include "heap.h"
23 #include "winnls.h"
25 DEFAULT_DEBUG_CHANNEL(winspool);
27 static LPWSTR *printer_array;
28 static int nb_printers;
30 static DWORD WINAPI (*GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
31 WORD fwCapability, LPSTR lpszOutput,
32 LPDEVMODEA lpdm );
33 static INT WINAPI (*GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
34 LPSTR lpszDevice, LPSTR lpszPort,
35 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
36 DWORD fwMode );
38 static char Printers[] =
39 "System\\CurrentControlSet\\control\\Print\\Printers\\";
40 static char Drivers[] =
41 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
43 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
45 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
46 'i','o','n',' ','F','i','l','e',0};
47 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
48 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
49 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
50 'M','o','d','e',0};
51 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
52 'i','l','e','s',0};
53 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
54 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
55 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
56 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
57 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
58 static WCHAR NameW[] = {'N','a','m','e',0};
59 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
60 static WCHAR PortW[] = {'P','o','r','t',0};
61 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
62 's','s','o','r',0};
63 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
64 'v','e','r',0};
65 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
66 'v','e','r','D','a','t','a',0};
67 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
68 'i','l','e',0};
69 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
70 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
72 /******************************************************************
73 * WINSPOOL_GetOpenedPrinterEntry
74 * Get the first place empty in the opened printer table
76 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
78 int i;
80 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
82 if (i >= nb_printers)
84 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
85 (nb_printers + 16) * sizeof(*new_array) );
86 if (!new_array) return 0;
87 printer_array = new_array;
88 nb_printers += 16;
91 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
93 strcpyW( printer_array[i], name );
94 return (HANDLE)(i + 1);
96 return 0;
99 /******************************************************************
100 * WINSPOOL_GetOpenedPrinter
101 * Get the pointer to the opened printer referred by the handle
103 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
105 int idx = (int)printerHandle;
106 if ((idx <= 0) || (idx > nb_printers))
108 SetLastError(ERROR_INVALID_HANDLE);
109 return NULL;
111 return printer_array[idx - 1];
114 /******************************************************************
115 * WINSPOOL_GetOpenedPrinterRegKey
118 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
120 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
121 DWORD ret;
122 HKEY hkeyPrinters;
124 if(!name) return ERROR_INVALID_HANDLE;
126 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
127 ERROR_SUCCESS)
128 return ret;
130 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
132 ERR("Can't find opened printer %s in registry\n",
133 debugstr_w(name));
134 RegCloseKey(hkeyPrinters);
135 return ERROR_INVALID_PRINTER_NAME; /* ? */
137 RegCloseKey(hkeyPrinters);
138 return ERROR_SUCCESS;
141 /***********************************************************
142 * DEVMODEcpyAtoW
144 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
146 BOOL Formname;
147 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
148 DWORD size;
150 Formname = (dmA->dmSize > off_formname);
151 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
152 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
153 CCHDEVICENAME);
154 if(!Formname) {
155 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
156 dmA->dmSize - CCHDEVICENAME);
157 } else {
158 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
159 off_formname - CCHDEVICENAME);
160 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
161 CCHFORMNAME);
162 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
163 (off_formname + CCHFORMNAME));
165 dmW->dmSize = size;
166 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
167 dmA->dmDriverExtra);
168 return dmW;
171 /***********************************************************
172 * DEVMODEdupAtoW
173 * Creates a unicode copy of supplied devmode on heap
175 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
177 LPDEVMODEW dmW;
178 DWORD size;
179 BOOL Formname;
180 ptrdiff_t off_formname;
182 TRACE("\n");
183 if(!dmA) return NULL;
185 off_formname = (char *)dmA->dmFormName - (char *)dmA;
186 Formname = (dmA->dmSize > off_formname);
187 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
188 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
189 return DEVMODEcpyAtoW(dmW, dmA);
192 /***********************************************************
193 * DEVMODEdupWtoA
194 * Creates an ascii copy of supplied devmode on heap
196 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
198 LPDEVMODEA dmA;
199 DWORD size;
200 BOOL Formname;
201 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
203 if(!dmW) return NULL;
204 Formname = (dmW->dmSize > off_formname);
205 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
206 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
207 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
208 CCHDEVICENAME, NULL, NULL);
209 if(!Formname) {
210 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
211 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
212 } else {
213 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
214 off_formname - CCHDEVICENAME * sizeof(WCHAR));
215 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
216 CCHFORMNAME, NULL, NULL);
217 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
218 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
220 dmA->dmSize = size;
221 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
222 dmW->dmDriverExtra);
223 return dmA;
226 /***********************************************************
227 * PRINTER_INFO_2AtoW
228 * Creates a unicode copy of PRINTER_INFO_2A on heap
230 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
232 LPPRINTER_INFO_2W piW;
233 if(!piA) return NULL;
234 piW = HeapAlloc(heap, 0, sizeof(*piW));
235 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
236 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
237 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
238 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
239 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
240 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
241 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
242 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
243 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
244 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
245 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
246 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
247 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
248 return piW;
251 /***********************************************************
252 * FREE_PRINTER_INFO_2W
253 * Free PRINTER_INFO_2W and all strings
255 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
257 if(!piW) return;
259 HeapFree(heap,0,piW->pServerName);
260 HeapFree(heap,0,piW->pPrinterName);
261 HeapFree(heap,0,piW->pShareName);
262 HeapFree(heap,0,piW->pPortName);
263 HeapFree(heap,0,piW->pDriverName);
264 HeapFree(heap,0,piW->pComment);
265 HeapFree(heap,0,piW->pLocation);
266 HeapFree(heap,0,piW->pDevMode);
267 HeapFree(heap,0,piW->pSepFile);
268 HeapFree(heap,0,piW->pPrintProcessor);
269 HeapFree(heap,0,piW->pDatatype);
270 HeapFree(heap,0,piW->pParameters);
271 HeapFree(heap,0,piW);
272 return;
275 /******************************************************************
276 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
279 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
280 LPSTR pOutput, LPDEVMODEA lpdm)
282 INT ret;
284 if (!GDI_CallDeviceCapabilities16)
286 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
287 (LPCSTR)104 );
288 if (!GDI_CallDeviceCapabilities16) return -1;
290 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
292 /* If DC_PAPERSIZE map POINT16s to POINTs */
293 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
294 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
295 POINT *pt = (POINT *)pOutput;
296 INT i;
297 memcpy(tmp, pOutput, ret * sizeof(POINT16));
298 for(i = 0; i < ret; i++, pt++)
300 pt->x = tmp[i].x;
301 pt->y = tmp[i].y;
303 HeapFree( GetProcessHeap(), 0, tmp );
305 return ret;
309 /*****************************************************************************
310 * DeviceCapabilitiesW [WINSPOOL.152]
312 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
315 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
316 WORD fwCapability, LPWSTR pOutput,
317 const DEVMODEW *pDevMode)
319 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
320 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
321 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
322 INT ret;
324 if(pOutput && (fwCapability == DC_BINNAMES ||
325 fwCapability == DC_FILEDEPENDENCIES ||
326 fwCapability == DC_PAPERNAMES)) {
327 /* These need A -> W translation */
328 INT size = 0, i;
329 LPSTR pOutputA;
330 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
331 dmA);
332 if(ret == -1)
333 return ret;
334 switch(fwCapability) {
335 case DC_BINNAMES:
336 size = 24;
337 break;
338 case DC_PAPERNAMES:
339 case DC_FILEDEPENDENCIES:
340 size = 64;
341 break;
343 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
344 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
345 dmA);
346 for(i = 0; i < ret; i++)
347 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
348 pOutput + (i * size), size);
349 HeapFree(GetProcessHeap(), 0, pOutputA);
350 } else {
351 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
352 (LPSTR)pOutput, dmA);
354 HeapFree(GetProcessHeap(),0,pPortA);
355 HeapFree(GetProcessHeap(),0,pDeviceA);
356 HeapFree(GetProcessHeap(),0,dmA);
357 return ret;
360 /******************************************************************
361 * DocumentPropertiesA [WINSPOOL.155]
364 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
365 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
366 LPDEVMODEA pDevModeInput,DWORD fMode )
368 LPSTR lpName = pDeviceName;
369 LONG ret;
371 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
372 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
375 if(!pDeviceName) {
376 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
377 if(!lpNameW) return -1;
378 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
381 if (!GDI_CallExtDeviceMode16)
383 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
384 (LPCSTR)102 );
385 if (!GDI_CallExtDeviceMode16) return -1;
387 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
388 pDevModeInput, NULL, fMode);
390 if(!pDeviceName)
391 HeapFree(GetProcessHeap(),0,lpName);
392 return ret;
396 /*****************************************************************************
397 * DocumentPropertiesW
399 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
400 LPWSTR pDeviceName,
401 LPDEVMODEW pDevModeOutput,
402 LPDEVMODEW pDevModeInput, DWORD fMode)
405 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
406 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
407 LPDEVMODEA pDevModeOutputA = NULL;
408 LONG ret;
410 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
411 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
412 fMode);
413 if(pDevModeOutput) {
414 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
415 if(ret < 0) return ret;
416 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
418 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
419 pDevModeInputA, fMode);
420 if(pDevModeOutput) {
421 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
422 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
424 if(fMode == 0 && ret > 0)
425 ret += (CCHDEVICENAME + CCHFORMNAME);
426 HeapFree(GetProcessHeap(),0,pDevModeInputA);
427 HeapFree(GetProcessHeap(),0,pDeviceNameA);
428 return ret;
431 /******************************************************************
432 * OpenPrinterA [WINSPOOL.196]
435 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
436 LPPRINTER_DEFAULTSA pDefault)
438 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
439 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
440 BOOL ret;
442 if(pDefault) {
443 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
444 pDefault->pDatatype);
445 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
446 pDefault->pDevMode);
447 DefaultW.DesiredAccess = pDefault->DesiredAccess;
448 pDefaultW = &DefaultW;
450 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
451 if(pDefault) {
452 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
453 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
455 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
456 return ret;
459 /******************************************************************
460 * OpenPrinterW [WINSPOOL.197]
463 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
464 LPPRINTER_DEFAULTSW pDefault)
466 HKEY hkeyPrinters, hkeyPrinter;
468 if (!lpPrinterName) {
469 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
470 SetLastError(ERROR_INVALID_PARAMETER);
471 return FALSE;
474 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
475 pDefault);
477 /* Check Printer exists */
478 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
479 ERROR_SUCCESS) {
480 ERR("Can't create Printers key\n");
481 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
482 return FALSE;
485 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
486 != ERROR_SUCCESS) {
487 WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
488 RegCloseKey(hkeyPrinters);
489 SetLastError(ERROR_INVALID_PARAMETER);
490 return FALSE;
492 RegCloseKey(hkeyPrinter);
493 RegCloseKey(hkeyPrinters);
495 if(!phPrinter) /* This seems to be what win95 does anyway */
496 return TRUE;
498 /* Get the unique handle of the printer*/
499 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
501 if (pDefault != NULL)
502 FIXME("Not handling pDefault\n");
504 return TRUE;
507 /******************************************************************
508 * AddMonitorA [WINSPOOL.107]
511 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
513 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
515 return FALSE;
518 /******************************************************************
519 * DeletePrinterDriverA [WINSPOOL.146]
522 BOOL WINAPI
523 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
525 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
526 debugstr_a(pDriverName));
527 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
528 return FALSE;
532 /******************************************************************
533 * DeleteMonitorA [WINSPOOL.135]
536 BOOL WINAPI
537 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
539 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
540 debugstr_a(pMonitorName));
541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
542 return FALSE;
546 /******************************************************************
547 * DeletePortA [WINSPOOL.137]
550 BOOL WINAPI
551 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
553 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
554 debugstr_a(pPortName));
555 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
556 return FALSE;
559 /******************************************************************************
560 * SetPrinterW [WINSPOOL.214]
562 BOOL WINAPI
563 SetPrinterW(
564 HANDLE hPrinter,
565 DWORD Level,
566 LPBYTE pPrinter,
567 DWORD Command) {
569 FIXME("():stub\n");
570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
571 return FALSE;
574 /******************************************************************************
575 * WritePrinter [WINSPOOL.223]
577 BOOL WINAPI
578 WritePrinter(
579 HANDLE hPrinter,
580 LPVOID pBuf,
581 DWORD cbBuf,
582 LPDWORD pcWritten) {
584 FIXME("():stub\n");
585 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
586 return FALSE;
589 /*****************************************************************************
590 * AddFormA [WINSPOOL.103]
592 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
594 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
595 return 1;
598 /*****************************************************************************
599 * AddFormW [WINSPOOL.104]
601 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
603 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
604 return 1;
607 /*****************************************************************************
608 * AddJobA [WINSPOOL.105]
610 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
611 DWORD cbBuf, LPDWORD pcbNeeded)
613 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
614 pcbNeeded);
615 return 1;
618 /*****************************************************************************
619 * AddJobW [WINSPOOL.106]
621 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
622 LPDWORD pcbNeeded)
624 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
625 pcbNeeded);
626 return 1;
629 /*****************************************************************************
630 * WINSPOOL_OpenDriverReg [internal]
632 * opens the registry for the printer drivers depending on the given input
633 * variable pEnvironment
635 * RETURNS:
636 * the opened hkey on success
637 * NULL on error
639 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
640 { HKEY retval;
641 LPSTR lpKey, p = NULL;
643 TRACE("%s\n",
644 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
646 if(pEnvironment)
647 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
648 pEnvironment;
649 else {
650 OSVERSIONINFOA ver;
651 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
653 if(!GetVersionExA( &ver))
654 return 0;
656 switch (ver.dwPlatformId) {
657 case VER_PLATFORM_WIN32s:
658 return 0;
659 case VER_PLATFORM_WIN32_NT:
660 p = "Windows NT x86";
661 break;
662 default:
663 p = "Windows 4.0";
664 break;
666 TRACE("set environment to %s\n", p);
669 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
670 strlen(p) + strlen(Drivers));
671 sprintf( lpKey, Drivers, p);
673 TRACE("%s\n", lpKey);
675 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
676 ERROR_SUCCESS)
677 retval = 0;
679 if(pEnvironment && unicode)
680 HeapFree( GetProcessHeap(), 0, p);
681 HeapFree( GetProcessHeap(), 0, lpKey);
683 return retval;
686 /*****************************************************************************
687 * AddPrinterW [WINSPOOL.122]
689 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
691 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
692 LPDEVMODEA dmA;
693 LPDEVMODEW dmW;
694 HANDLE retval;
695 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
696 LONG size;
698 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
700 if(pName != NULL) {
701 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
702 SetLastError(ERROR_INVALID_PARAMETER);
703 return 0;
705 if(Level != 2) {
706 WARN("Level = %ld\n", Level);
707 SetLastError(ERROR_INVALID_LEVEL);
708 return 0;
710 if(!pPrinter) {
711 SetLastError(ERROR_INVALID_PARAMETER);
712 return 0;
714 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
715 ERROR_SUCCESS) {
716 ERR("Can't create Printers key\n");
717 return 0;
719 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
720 ERROR_SUCCESS) {
721 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
722 RegCloseKey(hkeyPrinter);
723 RegCloseKey(hkeyPrinters);
724 return 0;
726 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
727 if(!hkeyDrivers) {
728 ERR("Can't create Drivers key\n");
729 RegCloseKey(hkeyPrinters);
730 return 0;
732 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
733 ERROR_SUCCESS) {
734 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
735 RegCloseKey(hkeyPrinters);
736 RegCloseKey(hkeyDrivers);
737 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
738 return 0;
740 RegCloseKey(hkeyDriver);
741 RegCloseKey(hkeyDrivers);
743 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
744 WARN("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
745 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
746 RegCloseKey(hkeyPrinters);
747 return 0;
750 /* See if we can load the driver. We may need the devmode structure anyway
752 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
753 if(size < 0) {
754 WARN("DocumentProperties fails\n");
755 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
756 return 0;
758 if(pi->pDevMode) {
759 dmW = pi->pDevMode;
760 } else {
761 dmW = HeapAlloc(GetProcessHeap(), 0, size);
762 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
765 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
766 ERROR_SUCCESS) {
767 WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
768 SetLastError(ERROR_INVALID_PRINTER_NAME);
769 RegCloseKey(hkeyPrinters);
770 if(!pi->pDevMode)
771 HeapFree(GetProcessHeap(), 0, dmW);
772 return 0;
774 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
775 (LPBYTE)&pi->Attributes, sizeof(DWORD));
776 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
779 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
780 and we support these drivers. NT writes DEVMODEW so somehow
781 we'll need to distinguish between these when we support NT
782 drivers */
783 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
784 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
785 dmA->dmSize + dmA->dmDriverExtra);
786 HeapFree(GetProcessHeap(), 0, dmA);
787 if(!pi->pDevMode)
788 HeapFree(GetProcessHeap(), 0, dmW);
789 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
791 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
793 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
794 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
795 (LPBYTE)pi->pParameters, 0);
796 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
797 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
798 (LPBYTE)pi->pPrintProcessor, 0);
799 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
800 (LPBYTE)pi->pDriverName, 0);
801 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
802 (LPBYTE)&pi->Priority, sizeof(DWORD));
803 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
804 (LPBYTE)pi->pSepFile, 0);
805 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
807 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
808 (LPBYTE)&pi->StartTime, sizeof(DWORD));
809 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
810 (LPBYTE)&pi->Status, sizeof(DWORD));
811 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
812 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
814 RegCloseKey(hkeyPrinter);
815 RegCloseKey(hkeyPrinters);
816 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
817 ERR("OpenPrinter failing\n");
818 return 0;
820 return retval;
823 /*****************************************************************************
824 * AddPrinterA [WINSPOOL.117]
826 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
828 WCHAR *pNameW;
829 PRINTER_INFO_2W *piW;
830 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
831 HANDLE ret;
833 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
834 if(Level != 2) {
835 WARN("Level = %ld\n", Level);
836 SetLastError(ERROR_INVALID_LEVEL);
837 return 0;
839 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
840 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
842 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
844 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
845 HeapFree(GetProcessHeap(),0,pNameW);
846 return ret;
850 /*****************************************************************************
851 * ClosePrinter [WINSPOOL.126]
853 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
855 int i = (int)hPrinter;
857 TRACE("Handle %d\n", hPrinter);
859 if ((i <= 0) || (i > nb_printers)) return FALSE;
860 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
861 printer_array[i - 1] = NULL;
862 return TRUE;
865 /*****************************************************************************
866 * DeleteFormA [WINSPOOL.133]
868 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
870 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
871 return 1;
874 /*****************************************************************************
875 * DeleteFormW [WINSPOOL.134]
877 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
879 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
880 return 1;
883 /*****************************************************************************
884 * DeletePrinter [WINSPOOL.143]
886 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
888 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
889 HKEY hkeyPrinters;
891 if(!lpNameW) return FALSE;
892 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
893 ERROR_SUCCESS) {
894 ERR("Can't open Printers key\n");
895 return 0;
898 /* This should use a recursive delete see Q142491 or SHDeleteKey */
899 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
900 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
901 RegCloseKey(hkeyPrinters);
902 return 0;
905 ClosePrinter(hPrinter);
906 return TRUE;
909 /*****************************************************************************
910 * SetPrinterA [WINSPOOL.211]
912 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
913 DWORD Command)
915 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
916 return FALSE;
919 /*****************************************************************************
920 * SetJobA [WINSPOOL.209]
922 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
923 LPBYTE pJob, DWORD Command)
925 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
926 Command);
927 return FALSE;
930 /*****************************************************************************
931 * SetJobW [WINSPOOL.210]
933 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
934 LPBYTE pJob, DWORD Command)
936 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
937 Command);
938 return FALSE;
941 /*****************************************************************************
942 * GetFormA [WINSPOOL.181]
944 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
945 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
947 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
948 Level,pForm,cbBuf,pcbNeeded);
949 return FALSE;
952 /*****************************************************************************
953 * GetFormW [WINSPOOL.182]
955 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
956 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
958 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
959 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
960 return FALSE;
963 /*****************************************************************************
964 * SetFormA [WINSPOOL.207]
966 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
967 LPBYTE pForm)
969 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
970 return FALSE;
973 /*****************************************************************************
974 * SetFormW [WINSPOOL.208]
976 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
977 LPBYTE pForm)
979 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
980 return FALSE;
983 /*****************************************************************************
984 * ReadPrinter [WINSPOOL.202]
986 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
987 LPDWORD pNoBytesRead)
989 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
990 return FALSE;
993 /*****************************************************************************
994 * ResetPrinterA [WINSPOOL.203]
996 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
998 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
999 return FALSE;
1002 /*****************************************************************************
1003 * ResetPrinterW [WINSPOOL.204]
1005 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1007 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1008 return FALSE;
1011 /*****************************************************************************
1012 * WINSPOOL_GetDWORDFromReg
1014 * Return DWORD associated with ValueName from hkey.
1016 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1018 DWORD sz = sizeof(DWORD), type, value = 0;
1019 LONG ret;
1021 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1023 if(ret != ERROR_SUCCESS) {
1024 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1025 return 0;
1027 if(type != REG_DWORD) {
1028 ERR("Got type %ld\n", type);
1029 return 0;
1031 return value;
1034 /*****************************************************************************
1035 * WINSPOOL_GetStringFromReg
1037 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1038 * String is stored either as unicode or ascii.
1039 * Bit of a hack here to get the ValueName if we want ascii.
1041 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1042 DWORD buflen, DWORD *needed,
1043 BOOL unicode)
1045 DWORD sz = buflen, type;
1046 LONG ret;
1048 if(unicode)
1049 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1050 else {
1051 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1052 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1053 HeapFree(GetProcessHeap(),0,ValueNameA);
1055 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1056 WARN("Got ret = %ld\n", ret);
1057 *needed = 0;
1058 return FALSE;
1060 *needed = sz;
1061 return TRUE;
1064 /*****************************************************************************
1065 * WINSPOOL_GetDevModeFromReg
1067 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1068 * DevMode is stored either as unicode or ascii.
1070 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1071 LPBYTE ptr,
1072 DWORD buflen, DWORD *needed,
1073 BOOL unicode)
1075 DWORD sz = buflen, type;
1076 LONG ret;
1078 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1079 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1080 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1081 if (sz < sizeof(DEVMODEA))
1083 ERR("corrupted registry for %s\n", debugstr_w(ValueName));
1084 sz = sizeof(DEVMODEA);
1086 /* ensures that dmSize is not erratically bogus if registry is invalid */
1087 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1088 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1089 if(unicode) {
1090 sz += (CCHDEVICENAME + CCHFORMNAME);
1091 if(buflen >= sz) {
1092 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1093 memcpy(ptr, dmW, sz);
1094 HeapFree(GetProcessHeap(),0,dmW);
1097 *needed = sz;
1098 return TRUE;
1101 /*********************************************************************
1102 * WINSPOOL_GetPrinter_2
1104 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1105 * The strings are either stored as unicode or ascii.
1107 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1108 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1109 BOOL unicode)
1111 DWORD size, left = cbBuf;
1112 BOOL space = (cbBuf > 0);
1113 LPBYTE ptr = buf;
1115 *pcbNeeded = 0;
1117 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1118 unicode)) {
1119 if(space && size <= left) {
1120 pi2->pPrinterName = (LPWSTR)ptr;
1121 ptr += size;
1122 left -= size;
1123 } else
1124 space = FALSE;
1125 *pcbNeeded += size;
1127 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1128 unicode)) {
1129 if(space && size <= left) {
1130 pi2->pShareName = (LPWSTR)ptr;
1131 ptr += size;
1132 left -= size;
1133 } else
1134 space = FALSE;
1135 *pcbNeeded += size;
1137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1138 unicode)) {
1139 if(space && size <= left) {
1140 pi2->pPortName = (LPWSTR)ptr;
1141 ptr += size;
1142 left -= size;
1143 } else
1144 space = FALSE;
1145 *pcbNeeded += size;
1147 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1148 &size, unicode)) {
1149 if(space && size <= left) {
1150 pi2->pDriverName = (LPWSTR)ptr;
1151 ptr += size;
1152 left -= size;
1153 } else
1154 space = FALSE;
1155 *pcbNeeded += size;
1157 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1158 unicode)) {
1159 if(space && size <= left) {
1160 pi2->pComment = (LPWSTR)ptr;
1161 ptr += size;
1162 left -= size;
1163 } else
1164 space = FALSE;
1165 *pcbNeeded += size;
1167 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1168 unicode)) {
1169 if(space && size <= left) {
1170 pi2->pLocation = (LPWSTR)ptr;
1171 ptr += size;
1172 left -= size;
1173 } else
1174 space = FALSE;
1175 *pcbNeeded += size;
1177 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1178 &size, unicode)) {
1179 if(space && size <= left) {
1180 pi2->pDevMode = (LPDEVMODEW)ptr;
1181 ptr += size;
1182 left -= size;
1183 } else
1184 space = FALSE;
1185 *pcbNeeded += size;
1187 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1188 &size, unicode)) {
1189 if(space && size <= left) {
1190 pi2->pSepFile = (LPWSTR)ptr;
1191 ptr += size;
1192 left -= size;
1193 } else
1194 space = FALSE;
1195 *pcbNeeded += size;
1197 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1198 &size, unicode)) {
1199 if(space && size <= left) {
1200 pi2->pPrintProcessor = (LPWSTR)ptr;
1201 ptr += size;
1202 left -= size;
1203 } else
1204 space = FALSE;
1205 *pcbNeeded += size;
1207 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1208 &size, unicode)) {
1209 if(space && size <= left) {
1210 pi2->pDatatype = (LPWSTR)ptr;
1211 ptr += size;
1212 left -= size;
1213 } else
1214 space = FALSE;
1215 *pcbNeeded += size;
1217 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1218 &size, unicode)) {
1219 if(space && size <= left) {
1220 pi2->pParameters = (LPWSTR)ptr;
1221 ptr += size;
1222 left -= size;
1223 } else
1224 space = FALSE;
1225 *pcbNeeded += size;
1227 if(pi2) {
1228 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1229 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1230 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1231 "Default Priority");
1232 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1233 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1236 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1237 memset(pi2, 0, sizeof(*pi2));
1239 return space;
1242 /*********************************************************************
1243 * WINSPOOL_GetPrinter_4
1245 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1247 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1248 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1249 BOOL unicode)
1251 DWORD size, left = cbBuf;
1252 BOOL space = (cbBuf > 0);
1253 LPBYTE ptr = buf;
1255 *pcbNeeded = 0;
1257 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1258 unicode)) {
1259 if(space && size <= left) {
1260 pi4->pPrinterName = (LPWSTR)ptr;
1261 ptr += size;
1262 left -= size;
1263 } else
1264 space = FALSE;
1265 *pcbNeeded += size;
1267 if(pi4) {
1268 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1271 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1272 memset(pi4, 0, sizeof(*pi4));
1274 return space;
1277 /*********************************************************************
1278 * WINSPOOL_GetPrinter_5
1280 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1282 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1283 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1284 BOOL unicode)
1286 DWORD size, left = cbBuf;
1287 BOOL space = (cbBuf > 0);
1288 LPBYTE ptr = buf;
1290 *pcbNeeded = 0;
1292 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1293 unicode)) {
1294 if(space && size <= left) {
1295 pi5->pPrinterName = (LPWSTR)ptr;
1296 ptr += size;
1297 left -= size;
1298 } else
1299 space = FALSE;
1300 *pcbNeeded += size;
1302 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1303 unicode)) {
1304 if(space && size <= left) {
1305 pi5->pPortName = (LPWSTR)ptr;
1306 ptr += size;
1307 left -= size;
1308 } else
1309 space = FALSE;
1310 *pcbNeeded += size;
1312 if(pi5) {
1313 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1314 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1315 "dnsTimeout");
1316 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1317 "txTimeout");
1320 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1321 memset(pi5, 0, sizeof(*pi5));
1323 return space;
1326 /*****************************************************************************
1327 * WINSPOOL_GetPrinter
1329 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1330 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1331 * just a collection of pointers to strings.
1333 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1334 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1336 LPCWSTR name;
1337 DWORD size, needed = 0;
1338 LPBYTE ptr = NULL;
1339 HKEY hkeyPrinter, hkeyPrinters;
1340 BOOL ret;
1342 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1344 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1346 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1347 ERROR_SUCCESS) {
1348 ERR("Can't create Printers key\n");
1349 return FALSE;
1351 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1353 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1354 RegCloseKey(hkeyPrinters);
1355 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1356 return FALSE;
1359 switch(Level) {
1360 case 2:
1362 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1364 size = sizeof(PRINTER_INFO_2W);
1365 if(size <= cbBuf) {
1366 ptr = pPrinter + size;
1367 cbBuf -= size;
1368 memset(pPrinter, 0, size);
1369 } else {
1370 pi2 = NULL;
1371 cbBuf = 0;
1373 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1374 unicode);
1375 needed += size;
1376 break;
1379 case 4:
1381 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1383 size = sizeof(PRINTER_INFO_4W);
1384 if(size <= cbBuf) {
1385 ptr = pPrinter + size;
1386 cbBuf -= size;
1387 memset(pPrinter, 0, size);
1388 } else {
1389 pi4 = NULL;
1390 cbBuf = 0;
1392 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1393 unicode);
1394 needed += size;
1395 break;
1399 case 5:
1401 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1403 size = sizeof(PRINTER_INFO_5W);
1404 if(size <= cbBuf) {
1405 ptr = pPrinter + size;
1406 cbBuf -= size;
1407 memset(pPrinter, 0, size);
1408 } else {
1409 pi5 = NULL;
1410 cbBuf = 0;
1413 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1414 unicode);
1415 needed += size;
1416 break;
1419 default:
1420 FIXME("Unimplemented level %ld\n", Level);
1421 SetLastError(ERROR_INVALID_LEVEL);
1422 RegCloseKey(hkeyPrinters);
1423 RegCloseKey(hkeyPrinter);
1424 return FALSE;
1427 RegCloseKey(hkeyPrinter);
1428 RegCloseKey(hkeyPrinters);
1430 TRACE("returing %d needed = %ld\n", ret, needed);
1431 if(pcbNeeded) *pcbNeeded = needed;
1432 if(!ret)
1433 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1434 return ret;
1437 /*****************************************************************************
1438 * GetPrinterW [WINSPOOL.194]
1440 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1441 DWORD cbBuf, LPDWORD pcbNeeded)
1443 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1444 TRUE);
1447 /*****************************************************************************
1448 * GetPrinterA [WINSPOOL.187]
1450 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1451 DWORD cbBuf, LPDWORD pcbNeeded)
1453 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1454 FALSE);
1457 /*****************************************************************************
1458 * WINSPOOL_EnumPrinters
1460 * Implementation of EnumPrintersA|W
1462 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1463 DWORD dwLevel, LPBYTE lpbPrinters,
1464 DWORD cbBuf, LPDWORD lpdwNeeded,
1465 LPDWORD lpdwReturned, BOOL unicode)
1468 HKEY hkeyPrinters, hkeyPrinter;
1469 WCHAR PrinterName[255];
1470 DWORD needed = 0, number = 0;
1471 DWORD used, i, left;
1472 PBYTE pi, buf;
1474 if(lpbPrinters)
1475 memset(lpbPrinters, 0, cbBuf);
1476 if(lpdwReturned)
1477 *lpdwReturned = 0;
1478 if(lpdwNeeded)
1479 *lpdwNeeded = 0;
1481 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1482 if(dwType == PRINTER_ENUM_DEFAULT)
1483 return TRUE;
1485 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1486 FIXME("dwType = %08lx\n", dwType);
1487 SetLastError(ERROR_INVALID_FLAGS);
1488 return FALSE;
1491 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1492 ERROR_SUCCESS) {
1493 ERR("Can't create Printers key\n");
1494 return FALSE;
1497 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1498 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1499 RegCloseKey(hkeyPrinters);
1500 ERR("Can't query Printers key\n");
1501 return FALSE;
1503 TRACE("Found %ld printers\n", number);
1505 switch(dwLevel) {
1506 case 1:
1507 RegCloseKey(hkeyPrinters);
1508 if (lpdwReturned)
1509 *lpdwReturned = number;
1510 return TRUE;
1512 case 2:
1513 used = number * sizeof(PRINTER_INFO_2W);
1514 break;
1515 case 4:
1516 used = number * sizeof(PRINTER_INFO_4W);
1517 break;
1518 case 5:
1519 used = number * sizeof(PRINTER_INFO_5W);
1520 break;
1522 default:
1523 SetLastError(ERROR_INVALID_LEVEL);
1524 RegCloseKey(hkeyPrinters);
1525 return FALSE;
1527 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1529 for(i = 0; i < number; i++) {
1530 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1531 ERROR_SUCCESS) {
1532 ERR("Can't enum key number %ld\n", i);
1533 RegCloseKey(hkeyPrinters);
1534 return FALSE;
1536 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1537 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1538 ERROR_SUCCESS) {
1539 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1540 RegCloseKey(hkeyPrinters);
1541 return FALSE;
1544 if(cbBuf > used) {
1545 buf = lpbPrinters + used;
1546 left = cbBuf - used;
1547 } else {
1548 buf = NULL;
1549 left = 0;
1552 switch(dwLevel) {
1553 case 2:
1554 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1555 left, &needed, unicode);
1556 used += needed;
1557 if(pi) pi += sizeof(PRINTER_INFO_2W);
1558 break;
1559 case 4:
1560 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1561 left, &needed, unicode);
1562 used += needed;
1563 if(pi) pi += sizeof(PRINTER_INFO_4W);
1564 break;
1565 case 5:
1566 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1567 left, &needed, unicode);
1568 used += needed;
1569 if(pi) pi += sizeof(PRINTER_INFO_5W);
1570 break;
1571 default:
1572 ERR("Shouldn't be here!\n");
1573 RegCloseKey(hkeyPrinter);
1574 RegCloseKey(hkeyPrinters);
1575 return FALSE;
1577 RegCloseKey(hkeyPrinter);
1579 RegCloseKey(hkeyPrinters);
1581 if(lpdwNeeded)
1582 *lpdwNeeded = used;
1584 if(used > cbBuf) {
1585 if(lpbPrinters)
1586 memset(lpbPrinters, 0, cbBuf);
1587 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1588 return FALSE;
1590 if(lpdwReturned)
1591 *lpdwReturned = number;
1592 SetLastError(ERROR_SUCCESS);
1593 return TRUE;
1597 /******************************************************************
1598 * EnumPrintersW [WINSPOOL.175]
1600 * Enumerates the available printers, print servers and print
1601 * providers, depending on the specified flags, name and level.
1603 * RETURNS:
1605 * If level is set to 1:
1606 * Not implemented yet!
1607 * Returns TRUE with an empty list.
1609 * If level is set to 2:
1610 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1611 * Returns an array of PRINTER_INFO_2 data structures in the
1612 * lpbPrinters buffer. Note that according to MSDN also an
1613 * OpenPrinter should be performed on every remote printer.
1615 * If level is set to 4 (officially WinNT only):
1616 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1617 * Fast: Only the registry is queried to retrieve printer names,
1618 * no connection to the driver is made.
1619 * Returns an array of PRINTER_INFO_4 data structures in the
1620 * lpbPrinters buffer.
1622 * If level is set to 5 (officially WinNT4/Win9x only):
1623 * Fast: Only the registry is queried to retrieve printer names,
1624 * no connection to the driver is made.
1625 * Returns an array of PRINTER_INFO_5 data structures in the
1626 * lpbPrinters buffer.
1628 * If level set to 3 or 6+:
1629 * returns zero (failure!)
1631 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
1632 * for information.
1634 * BUGS:
1635 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1636 * - Only levels 2, 4 and 5 are implemented at the moment.
1637 * - 16-bit printer drivers are not enumerated.
1638 * - Returned amount of bytes used/needed does not match the real Windoze
1639 * implementation (as in this implementation, all strings are part
1640 * of the buffer, whereas Win32 keeps them somewhere else)
1641 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1643 * NOTE:
1644 * - In a regular Wine installation, no registry settings for printers
1645 * exist, which makes this function return an empty list.
1647 BOOL WINAPI EnumPrintersW(
1648 DWORD dwType, /* [in] Types of print objects to enumerate */
1649 LPWSTR lpszName, /* [in] name of objects to enumerate */
1650 DWORD dwLevel, /* [in] type of printer info structure */
1651 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1652 DWORD cbBuf, /* [in] max size of buffer in bytes */
1653 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1654 LPDWORD lpdwReturned /* [out] number of entries returned */
1657 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1658 lpdwNeeded, lpdwReturned, TRUE);
1661 /******************************************************************
1662 * EnumPrintersA [WINSPOOL.174]
1665 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1666 DWORD dwLevel, LPBYTE lpbPrinters,
1667 DWORD cbBuf, LPDWORD lpdwNeeded,
1668 LPDWORD lpdwReturned)
1670 BOOL ret;
1671 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1673 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1674 lpdwNeeded, lpdwReturned, FALSE);
1675 HeapFree(GetProcessHeap(),0,lpszNameW);
1676 return ret;
1679 /*****************************************************************************
1680 * WINSPOOL_GetDriverInfoFromReg [internal]
1682 * Enters the information from the registry into the DRIVER_INFO struct
1684 * RETURNS
1685 * zero if the printer driver does not exist in the registry
1686 * (only if Level > 1) otherwise nonzero
1688 static BOOL WINSPOOL_GetDriverInfoFromReg(
1689 HKEY hkeyDrivers,
1690 LPWSTR DriverName,
1691 LPWSTR pEnvironment,
1692 DWORD Level,
1693 LPBYTE ptr, /* DRIVER_INFO */
1694 LPBYTE pDriverStrings, /* strings buffer */
1695 DWORD cbBuf, /* size of string buffer */
1696 LPDWORD pcbNeeded, /* space needed for str. */
1697 BOOL unicode) /* type of strings */
1698 { DWORD dw, size, tmp, type;
1699 HKEY hkeyDriver;
1700 LPBYTE strPtr = pDriverStrings;
1702 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1703 debugstr_w(DriverName), debugstr_w(pEnvironment),
1704 Level, ptr, pDriverStrings, cbBuf, unicode);
1706 if(unicode) {
1707 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1708 if (*pcbNeeded <= cbBuf)
1709 strcpyW((LPWSTR)strPtr, DriverName);
1710 } else {
1711 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1712 NULL, NULL);
1713 if(*pcbNeeded <= cbBuf)
1714 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1715 NULL, NULL);
1717 if(Level == 1) {
1718 if(ptr)
1719 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1720 return TRUE;
1721 } else {
1722 if(ptr)
1723 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1724 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1727 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1728 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1729 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1730 return FALSE;
1733 size = sizeof(dw);
1734 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1735 ERROR_SUCCESS)
1736 WARN("Can't get Version\n");
1737 else if(ptr)
1738 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1740 if(!pEnvironment)
1741 pEnvironment = DefaultEnvironmentW;
1742 if(unicode)
1743 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1744 else
1745 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1746 NULL, NULL);
1747 *pcbNeeded += size;
1748 if(*pcbNeeded <= cbBuf) {
1749 if(unicode)
1750 strcpyW((LPWSTR)strPtr, pEnvironment);
1751 else
1752 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
1753 NULL, NULL);
1754 if(ptr)
1755 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1756 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1759 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1760 unicode)) {
1761 *pcbNeeded += size;
1762 if(*pcbNeeded <= cbBuf)
1763 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1764 unicode);
1765 if(ptr)
1766 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1767 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1770 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1771 unicode)) {
1772 *pcbNeeded += size;
1773 if(*pcbNeeded <= cbBuf)
1774 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1775 &tmp, unicode);
1776 if(ptr)
1777 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1778 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1781 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1782 0, &size, unicode)) {
1783 *pcbNeeded += size;
1784 if(*pcbNeeded <= cbBuf)
1785 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1786 size, &tmp, unicode);
1787 if(ptr)
1788 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1789 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1792 if(Level == 2 ) {
1793 RegCloseKey(hkeyDriver);
1794 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1795 return TRUE;
1798 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1799 unicode)) {
1800 *pcbNeeded += size;
1801 if(*pcbNeeded <= cbBuf)
1802 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1803 size, &tmp, unicode);
1804 if(ptr)
1805 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1806 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1809 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1810 &size, unicode)) {
1811 *pcbNeeded += size;
1812 if(*pcbNeeded <= cbBuf)
1813 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1814 size, &tmp, unicode);
1815 if(ptr)
1816 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1817 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1820 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1821 unicode)) {
1822 *pcbNeeded += size;
1823 if(*pcbNeeded <= cbBuf)
1824 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1825 size, &tmp, unicode);
1826 if(ptr)
1827 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1828 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1831 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1832 unicode)) {
1833 *pcbNeeded += size;
1834 if(*pcbNeeded <= cbBuf)
1835 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1836 size, &tmp, unicode);
1837 if(ptr)
1838 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1839 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1842 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1843 RegCloseKey(hkeyDriver);
1844 return TRUE;
1847 /*****************************************************************************
1848 * WINSPOOL_GetPrinterDriver
1850 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1851 DWORD Level, LPBYTE pDriverInfo,
1852 DWORD cbBuf, LPDWORD pcbNeeded,
1853 BOOL unicode)
1855 LPCWSTR name;
1856 WCHAR DriverName[100];
1857 DWORD ret, type, size, needed = 0;
1858 LPBYTE ptr = NULL;
1859 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1861 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1862 Level,pDriverInfo,cbBuf, pcbNeeded);
1864 ZeroMemory(pDriverInfo, cbBuf);
1866 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1868 if(Level < 1 || Level > 3) {
1869 SetLastError(ERROR_INVALID_LEVEL);
1870 return FALSE;
1872 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1873 ERROR_SUCCESS) {
1874 ERR("Can't create Printers key\n");
1875 return FALSE;
1877 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
1878 != ERROR_SUCCESS) {
1879 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1880 RegCloseKey(hkeyPrinters);
1881 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1882 return FALSE;
1884 size = sizeof(DriverName);
1885 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1886 (LPBYTE)DriverName, &size);
1887 RegCloseKey(hkeyPrinter);
1888 RegCloseKey(hkeyPrinters);
1889 if(ret != ERROR_SUCCESS) {
1890 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
1891 return FALSE;
1894 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1895 if(!hkeyDrivers) {
1896 ERR("Can't create Drivers key\n");
1897 return FALSE;
1900 switch(Level) {
1901 case 1:
1902 size = sizeof(DRIVER_INFO_1W);
1903 break;
1904 case 2:
1905 size = sizeof(DRIVER_INFO_2W);
1906 break;
1907 case 3:
1908 size = sizeof(DRIVER_INFO_3W);
1909 break;
1910 default:
1911 ERR("Invalid level\n");
1912 return FALSE;
1915 if(size <= cbBuf)
1916 ptr = pDriverInfo + size;
1918 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
1919 pEnvironment, Level, pDriverInfo,
1920 (cbBuf < size) ? NULL : ptr,
1921 (cbBuf < size) ? 0 : cbBuf - size,
1922 &needed, unicode)) {
1923 RegCloseKey(hkeyDrivers);
1924 return FALSE;
1927 RegCloseKey(hkeyDrivers);
1929 if(pcbNeeded) *pcbNeeded = size + needed;
1930 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1931 if(cbBuf >= needed) return TRUE;
1932 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1933 return FALSE;
1936 /*****************************************************************************
1937 * GetPrinterDriverA [WINSPOOL.190]
1939 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1940 DWORD Level, LPBYTE pDriverInfo,
1941 DWORD cbBuf, LPDWORD pcbNeeded)
1943 BOOL ret;
1944 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
1945 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
1946 cbBuf, pcbNeeded, FALSE);
1947 HeapFree(GetProcessHeap(),0,pEnvW);
1948 return ret;
1950 /*****************************************************************************
1951 * GetPrinterDriverW [WINSPOOL.193]
1953 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1954 DWORD Level, LPBYTE pDriverInfo,
1955 DWORD cbBuf, LPDWORD pcbNeeded)
1957 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
1958 pDriverInfo, cbBuf, pcbNeeded, TRUE);
1961 /*****************************************************************************
1962 * GetPrinterDriverDirectoryA [WINSPOOL.191]
1964 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1965 DWORD Level, LPBYTE pDriverDirectory,
1966 DWORD cbBuf, LPDWORD pcbNeeded)
1968 DWORD needed;
1970 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1971 pDriverDirectory, cbBuf, pcbNeeded);
1972 if(pName != NULL) {
1973 FIXME("pName = `%s' - unsupported\n", pName);
1974 SetLastError(ERROR_INVALID_PARAMETER);
1975 return FALSE;
1977 if(pEnvironment != NULL) {
1978 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1979 SetLastError(ERROR_INVALID_ENVIRONMENT);
1980 return FALSE;
1982 if(Level != 1) /* win95 ignores this so we just carry on */
1983 WARN("Level = %ld - assuming 1\n", Level);
1985 /* FIXME should read from registry */
1986 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1987 needed++;
1988 if(pcbNeeded)
1989 *pcbNeeded = needed;
1990 if(needed > cbBuf) {
1991 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1992 return FALSE;
1994 return TRUE;
1998 /*****************************************************************************
1999 * GetPrinterDriverDirectoryW [WINSPOOL.192]
2001 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2002 DWORD Level, LPBYTE pDriverDirectory,
2003 DWORD cbBuf, LPDWORD pcbNeeded)
2005 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2006 BOOL ret;
2008 if(pName)
2009 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2010 if(pEnvironment)
2011 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2012 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2013 pDriverDirectory, cbBuf, pcbNeeded );
2014 if(pNameA)
2015 HeapFree( GetProcessHeap(), 0, pNameA );
2016 if(pEnvironmentA)
2017 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2019 return ret;
2022 /*****************************************************************************
2023 * AddPrinterDriverA [WINSPOOL.120]
2025 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2027 DRIVER_INFO_3A di3;
2028 HKEY hkeyDrivers, hkeyName;
2030 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2032 if(level != 2 && level != 3) {
2033 SetLastError(ERROR_INVALID_LEVEL);
2034 return FALSE;
2036 if(pName != NULL) {
2037 FIXME("pName= `%s' - unsupported\n", pName);
2038 SetLastError(ERROR_INVALID_PARAMETER);
2039 return FALSE;
2041 if(!pDriverInfo) {
2042 WARN("pDriverInfo == NULL");
2043 SetLastError(ERROR_INVALID_PARAMETER);
2044 return FALSE;
2047 if(level == 3)
2048 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2049 else {
2050 memset(&di3, 0, sizeof(di3));
2051 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2054 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2055 !di3.pDataFile) {
2056 SetLastError(ERROR_INVALID_PARAMETER);
2057 return FALSE;
2059 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2060 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2061 if(!di3.pHelpFile) di3.pHelpFile = "";
2062 if(!di3.pMonitorName) di3.pMonitorName = "";
2064 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2066 if(!hkeyDrivers) {
2067 ERR("Can't create Drivers key\n");
2068 return FALSE;
2071 if(level == 2) { /* apparently can't overwrite with level2 */
2072 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2073 RegCloseKey(hkeyName);
2074 RegCloseKey(hkeyDrivers);
2075 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2076 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2077 return FALSE;
2080 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2081 RegCloseKey(hkeyDrivers);
2082 ERR("Can't create Name key\n");
2083 return FALSE;
2085 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2087 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2088 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2089 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2090 sizeof(DWORD));
2091 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2092 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2093 di3.pDependentFiles, 0);
2094 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2095 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2096 RegCloseKey(hkeyName);
2097 RegCloseKey(hkeyDrivers);
2099 return TRUE;
2101 /*****************************************************************************
2102 * AddPrinterDriverW [WINSPOOL.121]
2104 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2105 LPBYTE pDriverInfo)
2107 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2108 level,pDriverInfo);
2109 return FALSE;
2113 /*****************************************************************************
2114 * PrinterProperties [WINSPOOL.201]
2116 * Displays a dialog to set the properties of the printer.
2118 * RETURNS
2119 * nonzero on success or zero on failure
2121 * BUGS
2122 * implemented as stub only
2124 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2125 HANDLE hPrinter /* [in] handle to printer object */
2127 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2128 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2129 return FALSE;
2132 /*****************************************************************************
2133 * EnumJobsA [WINSPOOL.162]
2136 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2137 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2138 LPDWORD pcReturned)
2140 FIXME("stub\n");
2141 if(pcbNeeded) *pcbNeeded = 0;
2142 if(pcReturned) *pcReturned = 0;
2143 return TRUE;
2147 /*****************************************************************************
2148 * EnumJobsW [WINSPOOL.163]
2151 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2152 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2153 LPDWORD pcReturned)
2155 FIXME("stub\n");
2156 if(pcbNeeded) *pcbNeeded = 0;
2157 if(pcReturned) *pcReturned = 0;
2158 return TRUE;
2161 /*****************************************************************************
2162 * WINSPOOL_EnumPrinterDrivers [internal]
2164 * Delivers information about all printer drivers installed on the
2165 * localhost or a given server
2167 * RETURNS
2168 * nonzero on success or zero on failure. If the buffer for the returned
2169 * information is too small the function will return an error
2171 * BUGS
2172 * - only implemented for localhost, foreign hosts will return an error
2174 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2175 DWORD Level, LPBYTE pDriverInfo,
2176 DWORD cbBuf, LPDWORD pcbNeeded,
2177 LPDWORD pcReturned, BOOL unicode)
2179 { HKEY hkeyDrivers;
2180 DWORD i, needed, number = 0, size = 0;
2181 WCHAR DriverNameW[255];
2182 PBYTE ptr;
2184 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2185 debugstr_w(pName), debugstr_w(pEnvironment),
2186 Level, pDriverInfo, cbBuf, unicode);
2188 /* check for local drivers */
2189 if(pName) {
2190 ERR("remote drivers unsupported! Current remote host is %s\n",
2191 debugstr_w(pName));
2192 return FALSE;
2195 /* check input parameter */
2196 if((Level < 1) || (Level > 3)) {
2197 ERR("unsupported level %ld \n", Level);
2198 return FALSE;
2201 /* initialize return values */
2202 if(pDriverInfo)
2203 memset( pDriverInfo, 0, cbBuf);
2204 *pcbNeeded = 0;
2205 *pcReturned = 0;
2207 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2208 if(!hkeyDrivers) {
2209 ERR("Can't open Drivers key\n");
2210 return FALSE;
2213 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2214 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2215 RegCloseKey(hkeyDrivers);
2216 ERR("Can't query Drivers key\n");
2217 return FALSE;
2219 TRACE("Found %ld Drivers\n", number);
2221 /* get size of single struct
2222 * unicode and ascii structure have the same size
2224 switch (Level) {
2225 case 1:
2226 size = sizeof(DRIVER_INFO_1A);
2227 break;
2228 case 2:
2229 size = sizeof(DRIVER_INFO_2A);
2230 break;
2231 case 3:
2232 size = sizeof(DRIVER_INFO_3A);
2233 break;
2236 /* calculate required buffer size */
2237 *pcbNeeded = size * number;
2239 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2240 i < number;
2241 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2242 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2243 != ERROR_SUCCESS) {
2244 ERR("Can't enum key number %ld\n", i);
2245 RegCloseKey(hkeyDrivers);
2246 return FALSE;
2248 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2249 pEnvironment, Level, ptr,
2250 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2251 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2252 &needed, unicode)) {
2253 RegCloseKey(hkeyDrivers);
2254 return FALSE;
2256 (*pcbNeeded) += needed;
2259 RegCloseKey(hkeyDrivers);
2261 if(cbBuf < *pcbNeeded){
2262 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2263 return FALSE;
2266 return TRUE;
2269 /*****************************************************************************
2270 * EnumPrinterDriversW [WINSPOOL.173]
2272 * see function EnumPrinterDrivers for RETURNS, BUGS
2274 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2275 LPBYTE pDriverInfo, DWORD cbBuf,
2276 LPDWORD pcbNeeded, LPDWORD pcReturned)
2278 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2279 cbBuf, pcbNeeded, pcReturned, TRUE);
2282 /*****************************************************************************
2283 * EnumPrinterDriversA [WINSPOOL.172]
2285 * see function EnumPrinterDrivers for RETURNS, BUGS
2287 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2288 LPBYTE pDriverInfo, DWORD cbBuf,
2289 LPDWORD pcbNeeded, LPDWORD pcReturned)
2290 { BOOL ret;
2291 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2293 if(pName)
2294 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2295 if(pEnvironment)
2296 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2298 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2299 cbBuf, pcbNeeded, pcReturned, FALSE);
2300 if(pNameW)
2301 HeapFree(GetProcessHeap(), 0, pNameW);
2302 if(pEnvironmentW)
2303 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2305 return ret;
2309 /******************************************************************************
2310 * EnumPortsA (WINSPOOL.166)
2312 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2313 LPDWORD bufneeded,LPDWORD bufreturned)
2315 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2316 return FALSE;
2319 /******************************************************************************
2320 * SetPrinterDataExA (WINSPOOL)
2322 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2323 LPSTR pValueName, DWORD Type,
2324 LPBYTE pData, DWORD cbData)
2326 HKEY hkeyPrinter, hkeySubkey;
2327 DWORD ret;
2329 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2330 debugstr_a(pValueName), Type, pData, cbData);
2332 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2333 != ERROR_SUCCESS)
2334 return ret;
2336 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2337 != ERROR_SUCCESS) {
2338 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2339 RegCloseKey(hkeyPrinter);
2340 return ret;
2342 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2343 RegCloseKey(hkeySubkey);
2344 RegCloseKey(hkeyPrinter);
2345 return ret;
2348 /******************************************************************************
2349 * SetPrinterDataExW (WINSPOOL)
2351 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2352 LPWSTR pValueName, DWORD Type,
2353 LPBYTE pData, DWORD cbData)
2355 HKEY hkeyPrinter, hkeySubkey;
2356 DWORD ret;
2358 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2359 debugstr_w(pValueName), Type, pData, cbData);
2361 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2362 != ERROR_SUCCESS)
2363 return ret;
2365 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2366 != ERROR_SUCCESS) {
2367 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2368 RegCloseKey(hkeyPrinter);
2369 return ret;
2371 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2372 RegCloseKey(hkeySubkey);
2373 RegCloseKey(hkeyPrinter);
2374 return ret;
2377 /******************************************************************************
2378 * SetPrinterDataA (WINSPOOL)
2380 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2381 LPBYTE pData, DWORD cbData)
2383 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2384 pData, cbData);
2387 /******************************************************************************
2388 * SetPrinterDataW (WINSPOOL)
2390 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2391 LPBYTE pData, DWORD cbData)
2393 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2394 pData, cbData);
2397 /******************************************************************************
2398 * GetPrinterDataExA (WINSPOOL)
2400 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2401 LPSTR pValueName, LPDWORD pType,
2402 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2404 HKEY hkeyPrinter, hkeySubkey;
2405 DWORD ret;
2407 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2408 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2409 pcbNeeded);
2411 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2412 != ERROR_SUCCESS)
2413 return ret;
2415 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2416 != ERROR_SUCCESS) {
2417 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2418 RegCloseKey(hkeyPrinter);
2419 return ret;
2421 *pcbNeeded = nSize;
2422 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2423 RegCloseKey(hkeySubkey);
2424 RegCloseKey(hkeyPrinter);
2425 return ret;
2428 /******************************************************************************
2429 * GetPrinterDataExW (WINSPOOL)
2431 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2432 LPWSTR pValueName, LPDWORD pType,
2433 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2435 HKEY hkeyPrinter, hkeySubkey;
2436 DWORD ret;
2438 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2439 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2440 pcbNeeded);
2442 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2443 != ERROR_SUCCESS)
2444 return ret;
2446 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2447 != ERROR_SUCCESS) {
2448 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2449 RegCloseKey(hkeyPrinter);
2450 return ret;
2452 *pcbNeeded = nSize;
2453 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2454 RegCloseKey(hkeySubkey);
2455 RegCloseKey(hkeyPrinter);
2456 return ret;
2459 /******************************************************************************
2460 * GetPrinterDataA (WINSPOOL)
2462 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2463 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2465 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2466 pData, nSize, pcbNeeded);
2469 /******************************************************************************
2470 * GetPrinterDataW (WINSPOOL)
2472 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2473 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2475 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2476 pData, nSize, pcbNeeded);
2479 /*******************************************************************************
2480 * EnumPrinterDataExW [WINSPOOL.197]
2482 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2483 LPBYTE pEnumValues, DWORD cbEnumValues,
2484 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2486 HKEY hkPrinter, hkSubKey;
2487 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2488 cbValueNameLen, cbMaxValueLen, cbValueLen,
2489 cbBufSize, dwType;
2490 LPWSTR lpValueName;
2491 HANDLE hHeap;
2492 PBYTE lpValue;
2493 PPRINTER_ENUM_VALUESW ppev;
2495 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2497 if (pKeyName == NULL || *pKeyName == 0)
2498 return ERROR_INVALID_PARAMETER;
2500 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2501 if (ret != ERROR_SUCCESS)
2503 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2504 hPrinter, ret);
2505 return ret;
2508 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2509 if (ret != ERROR_SUCCESS)
2511 r = RegCloseKey (hkPrinter);
2512 if (r != ERROR_SUCCESS)
2513 WARN ("RegCloseKey returned %li\n", r);
2514 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2515 debugstr_w (pKeyName), ret);
2516 return ret;
2519 ret = RegCloseKey (hkPrinter);
2520 if (ret != ERROR_SUCCESS)
2522 ERR ("RegCloseKey returned %li\n", ret);
2523 r = RegCloseKey (hkSubKey);
2524 if (r != ERROR_SUCCESS)
2525 WARN ("RegCloseKey returned %li\n", r);
2526 return ret;
2529 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2530 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2531 if (ret != ERROR_SUCCESS)
2533 r = RegCloseKey (hkSubKey);
2534 if (r != ERROR_SUCCESS)
2535 WARN ("RegCloseKey returned %li\n", r);
2536 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2537 return ret;
2540 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2541 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2543 if (cValues == 0) /* empty key */
2545 r = RegCloseKey (hkSubKey);
2546 if (r != ERROR_SUCCESS)
2547 WARN ("RegCloseKey returned %li\n", r);
2548 *pcbEnumValues = *pnEnumValues = 0;
2549 return ERROR_SUCCESS;
2552 ++cbMaxValueNameLen; /* allow for trailing '\0' */
2554 hHeap = GetProcessHeap ();
2555 if (hHeap == (HANDLE) NULL)
2557 ERR ("GetProcessHeap failed\n");
2558 r = RegCloseKey (hkSubKey);
2559 if (r != ERROR_SUCCESS)
2560 WARN ("RegCloseKey returned %li\n", r);
2561 return ERROR_OUTOFMEMORY;
2564 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
2565 if (lpValueName == NULL)
2567 ERR ("Failed to allocate %li bytes from process heap\n",
2568 cbMaxValueNameLen * sizeof (WCHAR));
2569 r = RegCloseKey (hkSubKey);
2570 if (r != ERROR_SUCCESS)
2571 WARN ("RegCloseKey returned %li\n", r);
2572 return ERROR_OUTOFMEMORY;
2575 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
2576 if (lpValue == NULL)
2578 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
2579 if (HeapFree (hHeap, 0, lpValueName) == 0)
2580 WARN ("HeapFree failed with code %li\n", GetLastError ());
2581 r = RegCloseKey (hkSubKey);
2582 if (r != ERROR_SUCCESS)
2583 WARN ("RegCloseKey returned %li\n", r);
2584 return ERROR_OUTOFMEMORY;
2587 TRACE ("pass 1: calculating buffer required for all names and values\n");
2589 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
2591 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
2593 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2595 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2596 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2597 NULL, NULL, lpValue, &cbValueLen);
2598 if (ret != ERROR_SUCCESS)
2600 if (HeapFree (hHeap, 0, lpValue) == 0)
2601 WARN ("HeapFree failed with code %li\n", GetLastError ());
2602 if (HeapFree (hHeap, 0, lpValueName) == 0)
2603 WARN ("HeapFree failed with code %li\n", GetLastError ());
2604 r = RegCloseKey (hkSubKey);
2605 if (r != ERROR_SUCCESS)
2606 WARN ("RegCloseKey returned %li\n", r);
2607 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2608 return ret;
2611 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
2612 debugstr_w (lpValueName), dwIndex,
2613 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
2615 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
2616 cbBufSize += cbValueLen;
2619 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
2621 *pcbEnumValues = cbBufSize;
2622 *pnEnumValues = cValues;
2624 if (cbEnumValues < cbBufSize) /* buffer too small */
2626 if (HeapFree (hHeap, 0, lpValue) == 0)
2627 WARN ("HeapFree failed with code %li\n", GetLastError ());
2628 if (HeapFree (hHeap, 0, lpValueName) == 0)
2629 WARN ("HeapFree failed with code %li\n", GetLastError ());
2630 r = RegCloseKey (hkSubKey);
2631 if (r != ERROR_SUCCESS)
2632 WARN ("RegCloseKey returned %li\n", r);
2633 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
2634 return ERROR_MORE_DATA;
2637 TRACE ("pass 2: copying all names and values to buffer\n");
2639 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
2640 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
2642 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2644 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2645 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2646 NULL, &dwType, lpValue, &cbValueLen);
2647 if (ret != ERROR_SUCCESS)
2649 if (HeapFree (hHeap, 0, lpValue) == 0)
2650 WARN ("HeapFree failed with code %li\n", GetLastError ());
2651 if (HeapFree (hHeap, 0, lpValueName) == 0)
2652 WARN ("HeapFree failed with code %li\n", GetLastError ());
2653 r = RegCloseKey (hkSubKey);
2654 if (r != ERROR_SUCCESS)
2655 WARN ("RegCloseKey returned %li\n", r);
2656 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2657 return ret;
2660 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
2661 memcpy (pEnumValues, lpValueName, cbValueNameLen);
2662 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
2663 pEnumValues += cbValueNameLen;
2665 /* return # of *bytes* (including trailing \0), not # of chars */
2666 ppev[dwIndex].cbValueName = cbValueNameLen;
2668 ppev[dwIndex].dwType = dwType;
2670 memcpy (pEnumValues, lpValue, cbValueLen);
2671 ppev[dwIndex].pData = pEnumValues;
2672 pEnumValues += cbValueLen;
2674 ppev[dwIndex].cbData = cbValueLen;
2676 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
2677 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
2680 if (HeapFree (hHeap, 0, lpValue) == 0)
2682 ret = GetLastError ();
2683 ERR ("HeapFree failed with code %li\n", ret);
2684 if (HeapFree (hHeap, 0, lpValueName) == 0)
2685 WARN ("HeapFree failed with code %li\n", GetLastError ());
2686 r = RegCloseKey (hkSubKey);
2687 if (r != ERROR_SUCCESS)
2688 WARN ("RegCloseKey returned %li\n", r);
2689 return ret;
2692 if (HeapFree (hHeap, 0, lpValueName) == 0)
2694 ret = GetLastError ();
2695 ERR ("HeapFree failed with code %li\n", ret);
2696 r = RegCloseKey (hkSubKey);
2697 if (r != ERROR_SUCCESS)
2698 WARN ("RegCloseKey returned %li\n", r);
2699 return ret;
2702 ret = RegCloseKey (hkSubKey);
2703 if (ret != ERROR_SUCCESS)
2705 ERR ("RegCloseKey returned %li\n", ret);
2706 return ret;
2709 return ERROR_SUCCESS;
2712 /*******************************************************************************
2713 * EnumPrinterDataExA [WINSPOOL.196]
2715 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
2716 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
2717 * what Windows 2000 SP1 does.
2720 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
2721 LPBYTE pEnumValues, DWORD cbEnumValues,
2722 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2724 INT len;
2725 LPWSTR pKeyNameW;
2726 DWORD ret, dwIndex, dwBufSize;
2727 HANDLE hHeap;
2728 LPSTR pBuffer;
2730 TRACE ("%08x %s\n", hPrinter, pKeyName);
2732 if (pKeyName == NULL || *pKeyName == 0)
2733 return ERROR_INVALID_PARAMETER;
2735 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
2736 if (len == 0)
2738 ret = GetLastError ();
2739 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2740 return ret;
2743 hHeap = GetProcessHeap ();
2744 if (hHeap == (HANDLE) NULL)
2746 ERR ("GetProcessHeap failed\n");
2747 return ERROR_OUTOFMEMORY;
2750 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
2751 if (pKeyNameW == NULL)
2753 ERR ("Failed to allocate %li bytes from process heap\n",
2754 (LONG) len * sizeof (WCHAR));
2755 return ERROR_OUTOFMEMORY;
2758 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
2760 ret = GetLastError ();
2761 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2762 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2763 WARN ("HeapFree failed with code %li\n", GetLastError ());
2764 return ret;
2767 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
2768 pcbEnumValues, pnEnumValues);
2769 if (ret != ERROR_SUCCESS)
2771 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2772 WARN ("HeapFree failed with code %li\n", GetLastError ());
2773 TRACE ("EnumPrinterDataExW returned %li\n", ret);
2774 return ret;
2777 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2779 ret = GetLastError ();
2780 ERR ("HeapFree failed with code %li\n", ret);
2781 return ret;
2784 if (*pnEnumValues == 0) /* empty key */
2785 return ERROR_SUCCESS;
2787 dwBufSize = 0;
2788 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2790 PPRINTER_ENUM_VALUESW ppev =
2791 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2793 if (dwBufSize < ppev->cbValueName)
2794 dwBufSize = ppev->cbValueName;
2796 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
2797 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
2798 dwBufSize = ppev->cbData;
2801 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
2803 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
2804 if (pBuffer == NULL)
2806 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
2807 return ERROR_OUTOFMEMORY;
2810 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2812 PPRINTER_ENUM_VALUESW ppev =
2813 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2815 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
2816 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
2817 NULL);
2818 if (len == 0)
2820 ret = GetLastError ();
2821 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2822 if (HeapFree (hHeap, 0, pBuffer) == 0)
2823 WARN ("HeapFree failed with code %li\n", GetLastError ());
2824 return ret;
2827 memcpy (ppev->pValueName, pBuffer, len);
2829 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2831 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
2832 ppev->dwType != REG_MULTI_SZ)
2833 continue;
2835 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
2836 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
2837 if (len == 0)
2839 ret = GetLastError ();
2840 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2841 if (HeapFree (hHeap, 0, pBuffer) == 0)
2842 WARN ("HeapFree failed with code %li\n", GetLastError ());
2843 return ret;
2846 memcpy (ppev->pData, pBuffer, len);
2848 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2849 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
2852 if (HeapFree (hHeap, 0, pBuffer) == 0)
2854 ret = GetLastError ();
2855 ERR ("HeapFree failed with code %li\n", ret);
2856 return ret;
2859 return ERROR_SUCCESS;