Implement EnumPrinterDataEx{A|W}.
[wine.git] / dlls / winspool / info.c
blobf5d96109f3ca7ea765852dcd23befb27367c949e
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 "commctrl.h"
24 #include "winnls.h"
26 DEFAULT_DEBUG_CHANNEL(winspool);
28 typedef struct _OPENEDPRINTER
30 LPWSTR lpsPrinterName;
31 HANDLE hPrinter;
32 } OPENEDPRINTER, *LPOPENEDPRINTER;
34 /* The OpenedPrinter Table dynamic array */
35 static HDPA pOpenedPrinterDPA = NULL;
37 extern HDPA WINAPI (*WINSPOOL_DPA_CreateEx) (INT, HANDLE);
38 extern LPVOID WINAPI (*WINSPOOL_DPA_GetPtr) (const HDPA, INT);
39 extern INT WINAPI (*WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID);
41 static DWORD WINAPI (*GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
42 WORD fwCapability, LPSTR lpszOutput,
43 LPDEVMODEA lpdm );
44 static INT WINAPI (*GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
45 LPSTR lpszDevice, LPSTR lpszPort,
46 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
47 DWORD fwMode );
49 static char Printers[] =
50 "System\\CurrentControlSet\\control\\Print\\Printers\\";
51 static char Drivers[] =
52 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
54 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
56 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
57 'i','o','n',' ','F','i','l','e',0};
58 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
59 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
60 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
61 'M','o','d','e',0};
62 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
63 'i','l','e','s',0};
64 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
65 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
66 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
67 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
68 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
69 static WCHAR NameW[] = {'N','a','m','e',0};
70 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
71 static WCHAR PortW[] = {'P','o','r','t',0};
72 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
73 's','s','o','r',0};
74 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
75 'v','e','r',0};
76 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
77 'v','e','r','D','a','t','a',0};
78 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
79 'i','l','e',0};
80 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
81 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
83 /******************************************************************
84 * WINSPOOL_GetOpenedPrinterEntry
85 * Get the first place empty in the opened printer table
87 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinterEntry()
89 int i;
90 LPOPENEDPRINTER pOpenedPrinter;
93 * Create the opened printers' handle dynamic array.
95 if (!pOpenedPrinterDPA)
97 pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
98 for (i = 0; i < 10; i++)
100 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
101 HEAP_ZERO_MEMORY,
102 sizeof(OPENEDPRINTER));
103 pOpenedPrinter->hPrinter = -1;
104 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
109 * Search for a handle not yet allocated.
111 for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
113 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
115 if (pOpenedPrinter->hPrinter == -1)
117 pOpenedPrinter->hPrinter = i + 1;
118 return pOpenedPrinter;
123 * Didn't find one, insert new element in the array.
125 if (i == pOpenedPrinterDPA->nItemCount)
127 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
128 HEAP_ZERO_MEMORY,
129 sizeof(OPENEDPRINTER));
130 pOpenedPrinter->hPrinter = i + 1;
131 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
132 return pOpenedPrinter;
135 return NULL;
138 /******************************************************************
139 * WINSPOOL_GetOpenedPrinter
140 * Get the pointer to the opened printer referred by the handle
142 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinter(int printerHandle)
144 LPOPENEDPRINTER pOpenedPrinter;
146 if(!pOpenedPrinterDPA) return NULL;
147 if((printerHandle <=0) ||
148 (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
149 return NULL;
151 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
153 return pOpenedPrinter;
156 /******************************************************************
157 * WINSPOOL_GetOpenedPrinterRegKey
160 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
162 LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
163 DWORD ret;
164 HKEY hkeyPrinters;
166 if(!lpOpenedPrinter)
167 return ERROR_INVALID_HANDLE;
169 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
170 ERROR_SUCCESS)
171 return ret;
173 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, phkey)
174 != ERROR_SUCCESS) {
175 ERR("Can't find opened printer %s in registry\n",
176 debugstr_w(lpOpenedPrinter->lpsPrinterName));
177 RegCloseKey(hkeyPrinters);
178 return ERROR_INVALID_PRINTER_NAME; /* ? */
180 RegCloseKey(hkeyPrinters);
181 return ERROR_SUCCESS;
184 /***********************************************************
185 * DEVMODEcpyAtoW
187 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
189 BOOL Formname;
190 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
191 DWORD size;
193 Formname = (dmA->dmSize > off_formname);
194 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
195 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
196 CCHDEVICENAME);
197 if(!Formname) {
198 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
199 dmA->dmSize - CCHDEVICENAME);
200 } else {
201 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
202 off_formname - CCHDEVICENAME);
203 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
204 CCHFORMNAME);
205 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
206 (off_formname + CCHFORMNAME));
208 dmW->dmSize = size;
209 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
210 dmA->dmDriverExtra);
211 return dmW;
214 /***********************************************************
215 * DEVMODEdupAtoW
216 * Creates a unicode copy of supplied devmode on heap
218 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
220 LPDEVMODEW dmW;
221 DWORD size;
222 BOOL Formname;
223 ptrdiff_t off_formname;
225 TRACE("\n");
226 if(!dmA) return NULL;
228 off_formname = (char *)dmA->dmFormName - (char *)dmA;
229 Formname = (dmA->dmSize > off_formname);
230 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
231 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
232 return DEVMODEcpyAtoW(dmW, dmA);
235 /***********************************************************
236 * DEVMODEdupWtoA
237 * Creates an ascii copy of supplied devmode on heap
239 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
241 LPDEVMODEA dmA;
242 DWORD size;
243 BOOL Formname;
244 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
246 if(!dmW) return NULL;
247 Formname = (dmW->dmSize > off_formname);
248 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
249 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
250 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
251 CCHDEVICENAME, NULL, NULL);
252 if(!Formname) {
253 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
254 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
255 } else {
256 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
257 off_formname - CCHDEVICENAME * sizeof(WCHAR));
258 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
259 CCHFORMNAME, NULL, NULL);
260 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
261 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
263 dmA->dmSize = size;
264 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
265 dmW->dmDriverExtra);
266 return dmA;
269 /***********************************************************
270 * PRINTER_INFO_2AtoW
271 * Creates a unicode copy of PRINTER_INFO_2A on heap
273 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
275 LPPRINTER_INFO_2W piW;
276 if(!piA) return NULL;
277 piW = HeapAlloc(heap, 0, sizeof(*piW));
278 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
279 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
280 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
281 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
282 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
283 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
284 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
285 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
286 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
287 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
288 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
289 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
290 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
291 return piW;
294 /***********************************************************
295 * FREE_PRINTER_INFO_2W
296 * Free PRINTER_INFO_2W and all strings
298 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
300 if(!piW) return;
302 HeapFree(heap,0,piW->pServerName);
303 HeapFree(heap,0,piW->pPrinterName);
304 HeapFree(heap,0,piW->pShareName);
305 HeapFree(heap,0,piW->pPortName);
306 HeapFree(heap,0,piW->pDriverName);
307 HeapFree(heap,0,piW->pComment);
308 HeapFree(heap,0,piW->pLocation);
309 HeapFree(heap,0,piW->pDevMode);
310 HeapFree(heap,0,piW->pSepFile);
311 HeapFree(heap,0,piW->pPrintProcessor);
312 HeapFree(heap,0,piW->pDatatype);
313 HeapFree(heap,0,piW->pParameters);
314 HeapFree(heap,0,piW);
315 return;
318 /******************************************************************
319 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
322 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
323 LPSTR pOutput, LPDEVMODEA lpdm)
325 INT ret;
327 if (!GDI_CallDeviceCapabilities16)
329 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
330 (LPCSTR)104 );
331 if (!GDI_CallDeviceCapabilities16) return -1;
333 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
335 /* If DC_PAPERSIZE map POINT16s to POINTs */
336 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
337 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
338 POINT *pt = (POINT *)pOutput;
339 INT i;
340 memcpy(tmp, pOutput, ret * sizeof(POINT16));
341 for(i = 0; i < ret; i++, pt++)
343 pt->x = tmp[i].x;
344 pt->y = tmp[i].y;
346 HeapFree( GetProcessHeap(), 0, tmp );
348 return ret;
352 /*****************************************************************************
353 * DeviceCapabilitiesW [WINSPOOL.152]
355 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
358 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
359 WORD fwCapability, LPWSTR pOutput,
360 const DEVMODEW *pDevMode)
362 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
363 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
364 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
365 INT ret;
367 if(pOutput && (fwCapability == DC_BINNAMES ||
368 fwCapability == DC_FILEDEPENDENCIES ||
369 fwCapability == DC_PAPERNAMES)) {
370 /* These need A -> W translation */
371 INT size = 0, i;
372 LPSTR pOutputA;
373 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
374 dmA);
375 if(ret == -1)
376 return ret;
377 switch(fwCapability) {
378 case DC_BINNAMES:
379 size = 24;
380 break;
381 case DC_PAPERNAMES:
382 case DC_FILEDEPENDENCIES:
383 size = 64;
384 break;
386 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
387 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
388 dmA);
389 for(i = 0; i < ret; i++)
390 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
391 pOutput + (i * size), size);
392 HeapFree(GetProcessHeap(), 0, pOutputA);
393 } else {
394 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
395 (LPSTR)pOutput, dmA);
397 HeapFree(GetProcessHeap(),0,pPortA);
398 HeapFree(GetProcessHeap(),0,pDeviceA);
399 HeapFree(GetProcessHeap(),0,dmA);
400 return ret;
403 /******************************************************************
404 * DocumentPropertiesA [WINSPOOL.155]
407 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
408 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
409 LPDEVMODEA pDevModeInput,DWORD fMode )
411 LPOPENEDPRINTER lpOpenedPrinter;
412 LPSTR lpName = pDeviceName;
413 LONG ret;
415 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
416 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
419 if(!pDeviceName) {
420 LPWSTR lpNameW;
421 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
422 if(!lpOpenedPrinter) {
423 SetLastError(ERROR_INVALID_HANDLE);
424 return -1;
426 lpNameW = lpOpenedPrinter->lpsPrinterName;
427 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
430 if (!GDI_CallExtDeviceMode16)
432 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
433 (LPCSTR)102 );
434 if (!GDI_CallExtDeviceMode16) return -1;
436 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
437 pDevModeInput, NULL, fMode);
439 if(!pDeviceName)
440 HeapFree(GetProcessHeap(),0,lpName);
441 return ret;
445 /*****************************************************************************
446 * DocumentPropertiesW
448 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
449 LPWSTR pDeviceName,
450 LPDEVMODEW pDevModeOutput,
451 LPDEVMODEW pDevModeInput, DWORD fMode)
454 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
455 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
456 LPDEVMODEA pDevModeOutputA = NULL;
457 LONG ret;
459 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
460 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
461 fMode);
462 if(pDevModeOutput) {
463 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
464 if(ret < 0) return ret;
465 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
467 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
468 pDevModeInputA, fMode);
469 if(pDevModeOutput) {
470 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
471 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
473 if(fMode == 0 && ret > 0)
474 ret += (CCHDEVICENAME + CCHFORMNAME);
475 HeapFree(GetProcessHeap(),0,pDevModeInputA);
476 HeapFree(GetProcessHeap(),0,pDeviceNameA);
477 return ret;
480 /******************************************************************
481 * OpenPrinterA [WINSPOOL.196]
484 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
485 LPPRINTER_DEFAULTSA pDefault)
487 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
488 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
489 BOOL ret;
491 if(pDefault) {
492 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
493 pDefault->pDatatype);
494 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
495 pDefault->pDevMode);
496 DefaultW.DesiredAccess = pDefault->DesiredAccess;
497 pDefaultW = &DefaultW;
499 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
500 if(pDefault) {
501 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
502 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
504 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
505 return ret;
508 /******************************************************************
509 * OpenPrinterW [WINSPOOL.197]
512 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
513 LPPRINTER_DEFAULTSW pDefault)
515 LPOPENEDPRINTER lpOpenedPrinter;
516 HKEY hkeyPrinters, hkeyPrinter;
518 if (!lpPrinterName) {
519 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
520 SetLastError(ERROR_INVALID_PARAMETER);
521 return FALSE;
524 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
525 pDefault);
527 /* Check Printer exists */
528 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
529 ERROR_SUCCESS) {
530 ERR("Can't create Printers key\n");
531 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
532 return FALSE;
535 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
536 != ERROR_SUCCESS) {
537 WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
538 RegCloseKey(hkeyPrinters);
539 SetLastError(ERROR_INVALID_PARAMETER);
540 return FALSE;
542 RegCloseKey(hkeyPrinter);
543 RegCloseKey(hkeyPrinters);
545 if(!phPrinter) /* This seems to be what win95 does anyway */
546 return TRUE;
548 /* Get a place in the opened printer buffer*/
549 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntry();
550 if(!lpOpenedPrinter) {
551 ERR("Can't allocate printer slot\n");
552 SetLastError(ERROR_OUTOFMEMORY);
553 return FALSE;
556 /* Get the name of the printer */
557 lpOpenedPrinter->lpsPrinterName = HeapAlloc( GetProcessHeap(), 0,
558 (strlenW(lpPrinterName)+1)*sizeof(WCHAR) );
559 strcpyW( lpOpenedPrinter->lpsPrinterName, lpPrinterName );
561 /* Get the unique handle of the printer*/
562 *phPrinter = lpOpenedPrinter->hPrinter;
564 if (pDefault != NULL)
565 FIXME("Not handling pDefault\n");
567 return TRUE;
570 /******************************************************************
571 * AddMonitorA [WINSPOOL.107]
574 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
576 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
577 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
578 return FALSE;
581 /******************************************************************
582 * DeletePrinterDriverA [WINSPOOL.146]
585 BOOL WINAPI
586 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
588 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
589 debugstr_a(pDriverName));
590 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
591 return FALSE;
595 /******************************************************************
596 * DeleteMonitorA [WINSPOOL.135]
599 BOOL WINAPI
600 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
602 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
603 debugstr_a(pMonitorName));
604 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
605 return FALSE;
609 /******************************************************************
610 * DeletePortA [WINSPOOL.137]
613 BOOL WINAPI
614 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
616 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
617 debugstr_a(pPortName));
618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
619 return FALSE;
622 /******************************************************************************
623 * SetPrinterW [WINSPOOL.214]
625 BOOL WINAPI
626 SetPrinterW(
627 HANDLE hPrinter,
628 DWORD Level,
629 LPBYTE pPrinter,
630 DWORD Command) {
632 FIXME("():stub\n");
633 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
634 return FALSE;
637 /******************************************************************************
638 * WritePrinter [WINSPOOL.223]
640 BOOL WINAPI
641 WritePrinter(
642 HANDLE hPrinter,
643 LPVOID pBuf,
644 DWORD cbBuf,
645 LPDWORD pcWritten) {
647 FIXME("():stub\n");
648 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
649 return FALSE;
652 /*****************************************************************************
653 * AddFormA [WINSPOOL.103]
655 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
657 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
658 return 1;
661 /*****************************************************************************
662 * AddFormW [WINSPOOL.104]
664 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
666 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
667 return 1;
670 /*****************************************************************************
671 * AddJobA [WINSPOOL.105]
673 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
674 DWORD cbBuf, LPDWORD pcbNeeded)
676 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
677 pcbNeeded);
678 return 1;
681 /*****************************************************************************
682 * AddJobW [WINSPOOL.106]
684 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
685 LPDWORD pcbNeeded)
687 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
688 pcbNeeded);
689 return 1;
692 /*****************************************************************************
693 * WINSPOOL_OpenDriverReg [internal]
695 * opens the registry for the printer drivers depending on the given input
696 * variable pEnvironment
698 * RETURNS:
699 * the opened hkey on success
700 * NULL on error
702 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
703 { HKEY retval;
704 LPSTR lpKey, p = NULL;
706 TRACE("%s\n",
707 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
709 if(pEnvironment)
710 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
711 pEnvironment;
712 else {
713 OSVERSIONINFOA ver;
714 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
716 if(!GetVersionExA( &ver))
717 return 0;
719 switch (ver.dwPlatformId) {
720 case VER_PLATFORM_WIN32s:
721 return 0;
722 case VER_PLATFORM_WIN32_NT:
723 p = "Windows NT x86";
724 break;
725 default:
726 p = "Windows 4.0";
727 break;
729 TRACE("set environment to %s\n", p);
732 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
733 strlen(p) + strlen(Drivers));
734 sprintf( lpKey, Drivers, p);
736 TRACE("%s\n", lpKey);
738 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
739 ERROR_SUCCESS)
740 retval = 0;
742 if(pEnvironment && unicode)
743 HeapFree( GetProcessHeap(), 0, p);
744 HeapFree( GetProcessHeap(), 0, lpKey);
746 return retval;
749 /*****************************************************************************
750 * AddPrinterW [WINSPOOL.122]
752 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
754 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
755 LPDEVMODEA dmA;
756 LPDEVMODEW dmW;
757 HANDLE retval;
758 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
759 LONG size;
761 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
763 if(pName != NULL) {
764 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
765 SetLastError(ERROR_INVALID_PARAMETER);
766 return 0;
768 if(Level != 2) {
769 WARN("Level = %ld\n", Level);
770 SetLastError(ERROR_INVALID_LEVEL);
771 return 0;
773 if(!pPrinter) {
774 SetLastError(ERROR_INVALID_PARAMETER);
775 return 0;
777 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
778 ERROR_SUCCESS) {
779 ERR("Can't create Printers key\n");
780 return 0;
782 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
783 ERROR_SUCCESS) {
784 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
785 RegCloseKey(hkeyPrinter);
786 RegCloseKey(hkeyPrinters);
787 return 0;
789 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
790 if(!hkeyDrivers) {
791 ERR("Can't create Drivers key\n");
792 RegCloseKey(hkeyPrinters);
793 return 0;
795 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
796 ERROR_SUCCESS) {
797 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
798 RegCloseKey(hkeyPrinters);
799 RegCloseKey(hkeyDrivers);
800 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
801 return 0;
803 RegCloseKey(hkeyDriver);
804 RegCloseKey(hkeyDrivers);
806 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
807 WARN("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
808 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
809 RegCloseKey(hkeyPrinters);
810 return 0;
813 /* See if we can load the driver. We may need the devmode structure anyway
815 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
816 if(size < 0) {
817 WARN("DocumentProperties fails\n");
818 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
819 return 0;
821 if(pi->pDevMode) {
822 dmW = pi->pDevMode;
823 } else {
824 dmW = HeapAlloc(GetProcessHeap(), 0, size);
825 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
828 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
829 ERROR_SUCCESS) {
830 WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
831 SetLastError(ERROR_INVALID_PRINTER_NAME);
832 RegCloseKey(hkeyPrinters);
833 if(!pi->pDevMode)
834 HeapFree(GetProcessHeap(), 0, dmW);
835 return 0;
837 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
838 (LPBYTE)&pi->Attributes, sizeof(DWORD));
839 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
842 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
843 and we support these drivers. NT writes DEVMODEW so somehow
844 we'll need to distinguish between these when we support NT
845 drivers */
846 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
847 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
848 dmA->dmSize + dmA->dmDriverExtra);
849 HeapFree(GetProcessHeap(), 0, dmA);
850 if(!pi->pDevMode)
851 HeapFree(GetProcessHeap(), 0, dmW);
852 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
854 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
856 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
857 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
858 (LPBYTE)pi->pParameters, 0);
859 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
860 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
861 (LPBYTE)pi->pPrintProcessor, 0);
862 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
863 (LPBYTE)pi->pDriverName, 0);
864 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
865 (LPBYTE)&pi->Priority, sizeof(DWORD));
866 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
867 (LPBYTE)pi->pSepFile, 0);
868 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
870 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
871 (LPBYTE)&pi->StartTime, sizeof(DWORD));
872 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
873 (LPBYTE)&pi->Status, sizeof(DWORD));
874 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
875 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
877 RegCloseKey(hkeyPrinter);
878 RegCloseKey(hkeyPrinters);
879 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
880 ERR("OpenPrinter failing\n");
881 return 0;
883 return retval;
886 /*****************************************************************************
887 * AddPrinterA [WINSPOOL.117]
889 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
891 WCHAR *pNameW;
892 PRINTER_INFO_2W *piW;
893 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
894 HANDLE ret;
896 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
897 if(Level != 2) {
898 WARN("Level = %ld\n", Level);
899 SetLastError(ERROR_INVALID_LEVEL);
900 return 0;
902 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
903 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
905 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
907 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
908 HeapFree(GetProcessHeap(),0,pNameW);
909 return ret;
913 /*****************************************************************************
914 * ClosePrinter [WINSPOOL.126]
916 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
918 LPOPENEDPRINTER lpOpenedPrinter;
920 TRACE("Handle %d\n", hPrinter);
922 if (!pOpenedPrinterDPA)
923 return FALSE;
925 if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
927 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
928 HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
929 lpOpenedPrinter->lpsPrinterName = NULL;
930 lpOpenedPrinter->hPrinter = -1;
932 return TRUE;
934 return FALSE;
937 /*****************************************************************************
938 * DeleteFormA [WINSPOOL.133]
940 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
942 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
943 return 1;
946 /*****************************************************************************
947 * DeleteFormW [WINSPOOL.134]
949 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
951 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
952 return 1;
955 /*****************************************************************************
956 * DeletePrinter [WINSPOOL.143]
958 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
960 LPWSTR lpNameW;
961 HKEY hkeyPrinters;
963 LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
964 if(!lpOpenedPrinter) {
965 SetLastError(ERROR_INVALID_HANDLE);
966 return FALSE;
968 lpNameW = lpOpenedPrinter->lpsPrinterName;
969 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
970 ERROR_SUCCESS) {
971 ERR("Can't open Printers key\n");
972 return 0;
975 /* This should use a recursive delete see Q142491 or SHDeleteKey */
976 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
977 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
978 RegCloseKey(hkeyPrinters);
979 return 0;
982 ClosePrinter(hPrinter);
983 return TRUE;
986 /*****************************************************************************
987 * SetPrinterA [WINSPOOL.211]
989 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
990 DWORD Command)
992 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
993 return FALSE;
996 /*****************************************************************************
997 * SetJobA [WINSPOOL.209]
999 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1000 LPBYTE pJob, DWORD Command)
1002 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1003 Command);
1004 return FALSE;
1007 /*****************************************************************************
1008 * SetJobW [WINSPOOL.210]
1010 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1011 LPBYTE pJob, DWORD Command)
1013 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1014 Command);
1015 return FALSE;
1018 /*****************************************************************************
1019 * GetFormA [WINSPOOL.181]
1021 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1022 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1024 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1025 Level,pForm,cbBuf,pcbNeeded);
1026 return FALSE;
1029 /*****************************************************************************
1030 * GetFormW [WINSPOOL.182]
1032 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1033 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1035 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1036 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1037 return FALSE;
1040 /*****************************************************************************
1041 * SetFormA [WINSPOOL.207]
1043 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1044 LPBYTE pForm)
1046 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1047 return FALSE;
1050 /*****************************************************************************
1051 * SetFormW [WINSPOOL.208]
1053 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1054 LPBYTE pForm)
1056 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1057 return FALSE;
1060 /*****************************************************************************
1061 * ReadPrinter [WINSPOOL.202]
1063 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1064 LPDWORD pNoBytesRead)
1066 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1067 return FALSE;
1070 /*****************************************************************************
1071 * ResetPrinterA [WINSPOOL.203]
1073 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1075 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1076 return FALSE;
1079 /*****************************************************************************
1080 * ResetPrinterW [WINSPOOL.204]
1082 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1084 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1085 return FALSE;
1088 /*****************************************************************************
1089 * WINSPOOL_GetDWORDFromReg
1091 * Return DWORD associated with ValueName from hkey.
1093 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1095 DWORD sz = sizeof(DWORD), type, value = 0;
1096 LONG ret;
1098 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1100 if(ret != ERROR_SUCCESS) {
1101 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1102 return 0;
1104 if(type != REG_DWORD) {
1105 ERR("Got type %ld\n", type);
1106 return 0;
1108 return value;
1111 /*****************************************************************************
1112 * WINSPOOL_GetStringFromReg
1114 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1115 * String is stored either as unicode or ascii.
1116 * Bit of a hack here to get the ValueName if we want ascii.
1118 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1119 DWORD buflen, DWORD *needed,
1120 BOOL unicode)
1122 DWORD sz = buflen, type;
1123 LONG ret;
1125 if(unicode)
1126 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1127 else {
1128 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1129 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1130 HeapFree(GetProcessHeap(),0,ValueNameA);
1132 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1133 WARN("Got ret = %ld\n", ret);
1134 *needed = 0;
1135 return FALSE;
1137 *needed = sz;
1138 return TRUE;
1141 /*****************************************************************************
1142 * WINSPOOL_GetDevModeFromReg
1144 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1145 * DevMode is stored either as unicode or ascii.
1147 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1148 LPBYTE ptr,
1149 DWORD buflen, DWORD *needed,
1150 BOOL unicode)
1152 DWORD sz = buflen, type;
1153 LONG ret;
1155 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1156 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1157 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1158 if (sz < sizeof(DEVMODEA))
1160 ERR("corrupted registry for %s\n", debugstr_w(ValueName));
1161 sz = sizeof(DEVMODEA);
1163 /* ensures that dmSize is not erratically bogus if registry is invalid */
1164 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1165 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1166 if(unicode) {
1167 sz += (CCHDEVICENAME + CCHFORMNAME);
1168 if(buflen >= sz) {
1169 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1170 memcpy(ptr, dmW, sz);
1171 HeapFree(GetProcessHeap(),0,dmW);
1174 *needed = sz;
1175 return TRUE;
1178 /*********************************************************************
1179 * WINSPOOL_GetPrinter_2
1181 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1182 * The strings are either stored as unicode or ascii.
1184 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1185 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1186 BOOL unicode)
1188 DWORD size, left = cbBuf;
1189 BOOL space = (cbBuf > 0);
1190 LPBYTE ptr = buf;
1192 *pcbNeeded = 0;
1194 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1195 unicode)) {
1196 if(space && size <= left) {
1197 pi2->pPrinterName = (LPWSTR)ptr;
1198 ptr += size;
1199 left -= size;
1200 } else
1201 space = FALSE;
1202 *pcbNeeded += size;
1204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1205 unicode)) {
1206 if(space && size <= left) {
1207 pi2->pShareName = (LPWSTR)ptr;
1208 ptr += size;
1209 left -= size;
1210 } else
1211 space = FALSE;
1212 *pcbNeeded += size;
1214 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1215 unicode)) {
1216 if(space && size <= left) {
1217 pi2->pPortName = (LPWSTR)ptr;
1218 ptr += size;
1219 left -= size;
1220 } else
1221 space = FALSE;
1222 *pcbNeeded += size;
1224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1225 &size, unicode)) {
1226 if(space && size <= left) {
1227 pi2->pDriverName = (LPWSTR)ptr;
1228 ptr += size;
1229 left -= size;
1230 } else
1231 space = FALSE;
1232 *pcbNeeded += size;
1234 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1235 unicode)) {
1236 if(space && size <= left) {
1237 pi2->pComment = (LPWSTR)ptr;
1238 ptr += size;
1239 left -= size;
1240 } else
1241 space = FALSE;
1242 *pcbNeeded += size;
1244 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1245 unicode)) {
1246 if(space && size <= left) {
1247 pi2->pLocation = (LPWSTR)ptr;
1248 ptr += size;
1249 left -= size;
1250 } else
1251 space = FALSE;
1252 *pcbNeeded += size;
1254 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1255 &size, unicode)) {
1256 if(space && size <= left) {
1257 pi2->pDevMode = (LPDEVMODEW)ptr;
1258 ptr += size;
1259 left -= size;
1260 } else
1261 space = FALSE;
1262 *pcbNeeded += size;
1264 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1265 &size, unicode)) {
1266 if(space && size <= left) {
1267 pi2->pSepFile = (LPWSTR)ptr;
1268 ptr += size;
1269 left -= size;
1270 } else
1271 space = FALSE;
1272 *pcbNeeded += size;
1274 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1275 &size, unicode)) {
1276 if(space && size <= left) {
1277 pi2->pPrintProcessor = (LPWSTR)ptr;
1278 ptr += size;
1279 left -= size;
1280 } else
1281 space = FALSE;
1282 *pcbNeeded += size;
1284 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1285 &size, unicode)) {
1286 if(space && size <= left) {
1287 pi2->pDatatype = (LPWSTR)ptr;
1288 ptr += size;
1289 left -= size;
1290 } else
1291 space = FALSE;
1292 *pcbNeeded += size;
1294 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1295 &size, unicode)) {
1296 if(space && size <= left) {
1297 pi2->pParameters = (LPWSTR)ptr;
1298 ptr += size;
1299 left -= size;
1300 } else
1301 space = FALSE;
1302 *pcbNeeded += size;
1304 if(pi2) {
1305 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1306 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1307 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1308 "Default Priority");
1309 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1310 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1313 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1314 memset(pi2, 0, sizeof(*pi2));
1316 return space;
1319 /*********************************************************************
1320 * WINSPOOL_GetPrinter_4
1322 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1324 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1325 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1326 BOOL unicode)
1328 DWORD size, left = cbBuf;
1329 BOOL space = (cbBuf > 0);
1330 LPBYTE ptr = buf;
1332 *pcbNeeded = 0;
1334 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1335 unicode)) {
1336 if(space && size <= left) {
1337 pi4->pPrinterName = (LPWSTR)ptr;
1338 ptr += size;
1339 left -= size;
1340 } else
1341 space = FALSE;
1342 *pcbNeeded += size;
1344 if(pi4) {
1345 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1348 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1349 memset(pi4, 0, sizeof(*pi4));
1351 return space;
1354 /*********************************************************************
1355 * WINSPOOL_GetPrinter_5
1357 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1359 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1360 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1361 BOOL unicode)
1363 DWORD size, left = cbBuf;
1364 BOOL space = (cbBuf > 0);
1365 LPBYTE ptr = buf;
1367 *pcbNeeded = 0;
1369 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1370 unicode)) {
1371 if(space && size <= left) {
1372 pi5->pPrinterName = (LPWSTR)ptr;
1373 ptr += size;
1374 left -= size;
1375 } else
1376 space = FALSE;
1377 *pcbNeeded += size;
1379 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1380 unicode)) {
1381 if(space && size <= left) {
1382 pi5->pPortName = (LPWSTR)ptr;
1383 ptr += size;
1384 left -= size;
1385 } else
1386 space = FALSE;
1387 *pcbNeeded += size;
1389 if(pi5) {
1390 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1391 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1392 "dnsTimeout");
1393 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1394 "txTimeout");
1397 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1398 memset(pi5, 0, sizeof(*pi5));
1400 return space;
1403 /*****************************************************************************
1404 * WINSPOOL_GetPrinter
1406 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1407 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1408 * just a collection of pointers to strings.
1410 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1411 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1413 OPENEDPRINTER *lpOpenedPrinter;
1414 DWORD size, needed = 0;
1415 LPBYTE ptr = NULL;
1416 HKEY hkeyPrinter, hkeyPrinters;
1417 BOOL ret;
1419 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1421 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1422 if(!lpOpenedPrinter) {
1423 SetLastError(ERROR_INVALID_HANDLE);
1424 return FALSE;
1426 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1427 ERROR_SUCCESS) {
1428 ERR("Can't create Printers key\n");
1429 return FALSE;
1431 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1432 != ERROR_SUCCESS) {
1433 ERR("Can't find opened printer %s in registry\n",
1434 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1435 RegCloseKey(hkeyPrinters);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1437 return FALSE;
1440 switch(Level) {
1441 case 2:
1443 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1445 size = sizeof(PRINTER_INFO_2W);
1446 if(size <= cbBuf) {
1447 ptr = pPrinter + size;
1448 cbBuf -= size;
1449 memset(pPrinter, 0, size);
1450 } else {
1451 pi2 = NULL;
1452 cbBuf = 0;
1454 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1455 unicode);
1456 needed += size;
1457 break;
1460 case 4:
1462 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1464 size = sizeof(PRINTER_INFO_4W);
1465 if(size <= cbBuf) {
1466 ptr = pPrinter + size;
1467 cbBuf -= size;
1468 memset(pPrinter, 0, size);
1469 } else {
1470 pi4 = NULL;
1471 cbBuf = 0;
1473 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1474 unicode);
1475 needed += size;
1476 break;
1480 case 5:
1482 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1484 size = sizeof(PRINTER_INFO_5W);
1485 if(size <= cbBuf) {
1486 ptr = pPrinter + size;
1487 cbBuf -= size;
1488 memset(pPrinter, 0, size);
1489 } else {
1490 pi5 = NULL;
1491 cbBuf = 0;
1494 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1495 unicode);
1496 needed += size;
1497 break;
1500 default:
1501 FIXME("Unimplemented level %ld\n", Level);
1502 SetLastError(ERROR_INVALID_LEVEL);
1503 RegCloseKey(hkeyPrinters);
1504 RegCloseKey(hkeyPrinter);
1505 return FALSE;
1508 RegCloseKey(hkeyPrinter);
1509 RegCloseKey(hkeyPrinters);
1511 TRACE("returing %d needed = %ld\n", ret, needed);
1512 if(pcbNeeded) *pcbNeeded = needed;
1513 if(!ret)
1514 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1515 return ret;
1518 /*****************************************************************************
1519 * GetPrinterW [WINSPOOL.194]
1521 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1522 DWORD cbBuf, LPDWORD pcbNeeded)
1524 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1525 TRUE);
1528 /*****************************************************************************
1529 * GetPrinterA [WINSPOOL.187]
1531 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1532 DWORD cbBuf, LPDWORD pcbNeeded)
1534 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1535 FALSE);
1538 /*****************************************************************************
1539 * WINSPOOL_EnumPrinters
1541 * Implementation of EnumPrintersA|W
1543 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1544 DWORD dwLevel, LPBYTE lpbPrinters,
1545 DWORD cbBuf, LPDWORD lpdwNeeded,
1546 LPDWORD lpdwReturned, BOOL unicode)
1549 HKEY hkeyPrinters, hkeyPrinter;
1550 WCHAR PrinterName[255];
1551 DWORD needed = 0, number = 0;
1552 DWORD used, i, left;
1553 PBYTE pi, buf;
1555 if(lpbPrinters)
1556 memset(lpbPrinters, 0, cbBuf);
1557 if(lpdwReturned)
1558 *lpdwReturned = 0;
1559 if(lpdwNeeded)
1560 *lpdwNeeded = 0;
1562 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1563 if(dwType == PRINTER_ENUM_DEFAULT)
1564 return TRUE;
1566 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1567 FIXME("dwType = %08lx\n", dwType);
1568 SetLastError(ERROR_INVALID_FLAGS);
1569 return FALSE;
1572 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1573 ERROR_SUCCESS) {
1574 ERR("Can't create Printers key\n");
1575 return FALSE;
1578 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1579 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1580 RegCloseKey(hkeyPrinters);
1581 ERR("Can't query Printers key\n");
1582 return FALSE;
1584 TRACE("Found %ld printers\n", number);
1586 switch(dwLevel) {
1587 case 1:
1588 RegCloseKey(hkeyPrinters);
1589 if (lpdwReturned)
1590 *lpdwReturned = number;
1591 return TRUE;
1593 case 2:
1594 used = number * sizeof(PRINTER_INFO_2W);
1595 break;
1596 case 4:
1597 used = number * sizeof(PRINTER_INFO_4W);
1598 break;
1599 case 5:
1600 used = number * sizeof(PRINTER_INFO_5W);
1601 break;
1603 default:
1604 SetLastError(ERROR_INVALID_LEVEL);
1605 RegCloseKey(hkeyPrinters);
1606 return FALSE;
1608 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1610 for(i = 0; i < number; i++) {
1611 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1612 ERROR_SUCCESS) {
1613 ERR("Can't enum key number %ld\n", i);
1614 RegCloseKey(hkeyPrinters);
1615 return FALSE;
1617 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1618 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1619 ERROR_SUCCESS) {
1620 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1621 RegCloseKey(hkeyPrinters);
1622 return FALSE;
1625 if(cbBuf > used) {
1626 buf = lpbPrinters + used;
1627 left = cbBuf - used;
1628 } else {
1629 buf = NULL;
1630 left = 0;
1633 switch(dwLevel) {
1634 case 2:
1635 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1636 left, &needed, unicode);
1637 used += needed;
1638 if(pi) pi += sizeof(PRINTER_INFO_2W);
1639 break;
1640 case 4:
1641 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1642 left, &needed, unicode);
1643 used += needed;
1644 if(pi) pi += sizeof(PRINTER_INFO_4W);
1645 break;
1646 case 5:
1647 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1648 left, &needed, unicode);
1649 used += needed;
1650 if(pi) pi += sizeof(PRINTER_INFO_5W);
1651 break;
1652 default:
1653 ERR("Shouldn't be here!\n");
1654 RegCloseKey(hkeyPrinter);
1655 RegCloseKey(hkeyPrinters);
1656 return FALSE;
1658 RegCloseKey(hkeyPrinter);
1660 RegCloseKey(hkeyPrinters);
1662 if(lpdwNeeded)
1663 *lpdwNeeded = used;
1665 if(used > cbBuf) {
1666 if(lpbPrinters)
1667 memset(lpbPrinters, 0, cbBuf);
1668 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1669 return FALSE;
1671 if(lpdwReturned)
1672 *lpdwReturned = number;
1673 SetLastError(ERROR_SUCCESS);
1674 return TRUE;
1678 /******************************************************************
1679 * EnumPrintersW [WINSPOOL.175]
1681 * Enumerates the available printers, print servers and print
1682 * providers, depending on the specified flags, name and level.
1684 * RETURNS:
1686 * If level is set to 1:
1687 * Not implemented yet!
1688 * Returns TRUE with an empty list.
1690 * If level is set to 2:
1691 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1692 * Returns an array of PRINTER_INFO_2 data structures in the
1693 * lpbPrinters buffer. Note that according to MSDN also an
1694 * OpenPrinter should be performed on every remote printer.
1696 * If level is set to 4 (officially WinNT only):
1697 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1698 * Fast: Only the registry is queried to retrieve printer names,
1699 * no connection to the driver is made.
1700 * Returns an array of PRINTER_INFO_4 data structures in the
1701 * lpbPrinters buffer.
1703 * If level is set to 5 (officially WinNT4/Win9x only):
1704 * Fast: Only the registry is queried to retrieve printer names,
1705 * no connection to the driver is made.
1706 * Returns an array of PRINTER_INFO_5 data structures in the
1707 * lpbPrinters buffer.
1709 * If level set to 3 or 6+:
1710 * returns zero (faillure!)
1712 * Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
1713 * for information.
1715 * BUGS:
1716 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1717 * - Only levels 2, 4 and 5 are implemented at the moment.
1718 * - 16-bit printer drivers are not enumerated.
1719 * - Returned amount of bytes used/needed does not match the real Windoze
1720 * implementation (as in this implementation, all strings are part
1721 * of the buffer, whereas Win32 keeps them somewhere else)
1722 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1724 * NOTE:
1725 * - In a regular Wine installation, no registry settings for printers
1726 * exist, which makes this function return an empty list.
1728 BOOL WINAPI EnumPrintersW(
1729 DWORD dwType, /* [in] Types of print objects to enumerate */
1730 LPWSTR lpszName, /* [in] name of objects to enumerate */
1731 DWORD dwLevel, /* [in] type of printer info structure */
1732 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1733 DWORD cbBuf, /* [in] max size of buffer in bytes */
1734 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1735 LPDWORD lpdwReturned /* [out] number of entries returned */
1738 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1739 lpdwNeeded, lpdwReturned, TRUE);
1742 /******************************************************************
1743 * EnumPrintersA [WINSPOOL.174]
1746 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1747 DWORD dwLevel, LPBYTE lpbPrinters,
1748 DWORD cbBuf, LPDWORD lpdwNeeded,
1749 LPDWORD lpdwReturned)
1751 BOOL ret;
1752 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1754 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1755 lpdwNeeded, lpdwReturned, FALSE);
1756 HeapFree(GetProcessHeap(),0,lpszNameW);
1757 return ret;
1760 /*****************************************************************************
1761 * WINSPOOL_GetDriverInfoFromReg [internal]
1763 * Enters the information from the registry into the DRIVER_INFO struct
1765 * RETURNS
1766 * zero if the printer driver does not exist in the registry
1767 * (only if Level > 1) otherwise nonzero
1769 static BOOL WINSPOOL_GetDriverInfoFromReg(
1770 HKEY hkeyDrivers,
1771 LPWSTR DriverName,
1772 LPWSTR pEnvironment,
1773 DWORD Level,
1774 LPBYTE ptr, /* DRIVER_INFO */
1775 LPBYTE pDriverStrings, /* strings buffer */
1776 DWORD cbBuf, /* size of string buffer */
1777 LPDWORD pcbNeeded, /* space needed for str. */
1778 BOOL unicode) /* type of strings */
1779 { DWORD dw, size, tmp, type;
1780 HKEY hkeyDriver;
1781 LPBYTE strPtr = pDriverStrings;
1783 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1784 debugstr_w(DriverName), debugstr_w(pEnvironment),
1785 Level, ptr, pDriverStrings, cbBuf, unicode);
1787 if(unicode) {
1788 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1789 if (*pcbNeeded <= cbBuf)
1790 strcpyW((LPWSTR)strPtr, DriverName);
1791 } else {
1792 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1793 NULL, NULL);
1794 if(*pcbNeeded <= cbBuf)
1795 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1796 NULL, NULL);
1798 if(Level == 1) {
1799 if(ptr)
1800 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1801 return TRUE;
1802 } else {
1803 if(ptr)
1804 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1805 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1808 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1809 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1810 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1811 return FALSE;
1814 size = sizeof(dw);
1815 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1816 ERROR_SUCCESS)
1817 WARN("Can't get Version\n");
1818 else if(ptr)
1819 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1821 if(!pEnvironment)
1822 pEnvironment = DefaultEnvironmentW;
1823 if(unicode)
1824 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1825 else
1826 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1827 NULL, NULL);
1828 *pcbNeeded += size;
1829 if(*pcbNeeded <= cbBuf) {
1830 if(unicode)
1831 strcpyW((LPWSTR)strPtr, pEnvironment);
1832 else
1833 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
1834 NULL, NULL);
1835 if(ptr)
1836 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1837 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1840 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1841 unicode)) {
1842 *pcbNeeded += size;
1843 if(*pcbNeeded <= cbBuf)
1844 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1845 unicode);
1846 if(ptr)
1847 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1848 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1851 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1852 unicode)) {
1853 *pcbNeeded += size;
1854 if(*pcbNeeded <= cbBuf)
1855 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1856 &tmp, unicode);
1857 if(ptr)
1858 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1859 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1862 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1863 0, &size, unicode)) {
1864 *pcbNeeded += size;
1865 if(*pcbNeeded <= cbBuf)
1866 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1867 size, &tmp, unicode);
1868 if(ptr)
1869 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1870 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1873 if(Level == 2 ) {
1874 RegCloseKey(hkeyDriver);
1875 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1876 return TRUE;
1879 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1880 unicode)) {
1881 *pcbNeeded += size;
1882 if(*pcbNeeded <= cbBuf)
1883 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1884 size, &tmp, unicode);
1885 if(ptr)
1886 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1887 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1890 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1891 &size, unicode)) {
1892 *pcbNeeded += size;
1893 if(*pcbNeeded <= cbBuf)
1894 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1895 size, &tmp, unicode);
1896 if(ptr)
1897 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1898 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1901 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1902 unicode)) {
1903 *pcbNeeded += size;
1904 if(*pcbNeeded <= cbBuf)
1905 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1906 size, &tmp, unicode);
1907 if(ptr)
1908 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1909 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1912 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1913 unicode)) {
1914 *pcbNeeded += size;
1915 if(*pcbNeeded <= cbBuf)
1916 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1917 size, &tmp, unicode);
1918 if(ptr)
1919 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1920 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1923 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1924 RegCloseKey(hkeyDriver);
1925 return TRUE;
1928 /*****************************************************************************
1929 * WINSPOOL_GetPrinterDriver
1931 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1932 DWORD Level, LPBYTE pDriverInfo,
1933 DWORD cbBuf, LPDWORD pcbNeeded,
1934 BOOL unicode)
1936 OPENEDPRINTER *lpOpenedPrinter;
1937 WCHAR DriverName[100];
1938 DWORD ret, type, size, needed = 0;
1939 LPBYTE ptr = NULL;
1940 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1942 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1943 Level,pDriverInfo,cbBuf, pcbNeeded);
1945 ZeroMemory(pDriverInfo, cbBuf);
1947 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1948 if(!lpOpenedPrinter) {
1949 SetLastError(ERROR_INVALID_HANDLE);
1950 return FALSE;
1952 if(Level < 1 || Level > 3) {
1953 SetLastError(ERROR_INVALID_LEVEL);
1954 return FALSE;
1956 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1957 ERROR_SUCCESS) {
1958 ERR("Can't create Printers key\n");
1959 return FALSE;
1961 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1962 != ERROR_SUCCESS) {
1963 ERR("Can't find opened printer %s in registry\n",
1964 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1965 RegCloseKey(hkeyPrinters);
1966 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1967 return FALSE;
1969 size = sizeof(DriverName);
1970 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1971 (LPBYTE)DriverName, &size);
1972 RegCloseKey(hkeyPrinter);
1973 RegCloseKey(hkeyPrinters);
1974 if(ret != ERROR_SUCCESS) {
1975 ERR("Can't get DriverName for printer %s\n",
1976 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1977 return FALSE;
1980 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1981 if(!hkeyDrivers) {
1982 ERR("Can't create Drivers key\n");
1983 return FALSE;
1986 switch(Level) {
1987 case 1:
1988 size = sizeof(DRIVER_INFO_1W);
1989 break;
1990 case 2:
1991 size = sizeof(DRIVER_INFO_2W);
1992 break;
1993 case 3:
1994 size = sizeof(DRIVER_INFO_3W);
1995 break;
1996 default:
1997 ERR("Invalid level\n");
1998 return FALSE;
2001 if(size <= cbBuf)
2002 ptr = pDriverInfo + size;
2004 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2005 pEnvironment, Level, pDriverInfo,
2006 (cbBuf < size) ? NULL : ptr,
2007 (cbBuf < size) ? 0 : cbBuf - size,
2008 &needed, unicode)) {
2009 RegCloseKey(hkeyDrivers);
2010 return FALSE;
2013 RegCloseKey(hkeyDrivers);
2015 if(pcbNeeded) *pcbNeeded = size + needed;
2016 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2017 if(cbBuf >= needed) return TRUE;
2018 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2019 return FALSE;
2022 /*****************************************************************************
2023 * GetPrinterDriverA [WINSPOOL.190]
2025 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2026 DWORD Level, LPBYTE pDriverInfo,
2027 DWORD cbBuf, LPDWORD pcbNeeded)
2029 BOOL ret;
2030 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2031 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2032 cbBuf, pcbNeeded, FALSE);
2033 HeapFree(GetProcessHeap(),0,pEnvW);
2034 return ret;
2036 /*****************************************************************************
2037 * GetPrinterDriverW [WINSPOOL.193]
2039 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2040 DWORD Level, LPBYTE pDriverInfo,
2041 DWORD cbBuf, LPDWORD pcbNeeded)
2043 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2044 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2047 /*****************************************************************************
2048 * GetPrinterDriverDirectoryA [WINSPOOL.191]
2050 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2051 DWORD Level, LPBYTE pDriverDirectory,
2052 DWORD cbBuf, LPDWORD pcbNeeded)
2054 DWORD needed;
2056 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2057 pDriverDirectory, cbBuf, pcbNeeded);
2058 if(pName != NULL) {
2059 FIXME("pName = `%s' - unsupported\n", pName);
2060 SetLastError(ERROR_INVALID_PARAMETER);
2061 return FALSE;
2063 if(pEnvironment != NULL) {
2064 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2065 SetLastError(ERROR_INVALID_ENVIRONMENT);
2066 return FALSE;
2068 if(Level != 1) /* win95 ignores this so we just carry on */
2069 WARN("Level = %ld - assuming 1\n", Level);
2071 /* FIXME should read from registry */
2072 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2073 needed++;
2074 if(pcbNeeded)
2075 *pcbNeeded = needed;
2076 if(needed > cbBuf) {
2077 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2078 return FALSE;
2080 return TRUE;
2084 /*****************************************************************************
2085 * GetPrinterDriverDirectoryW [WINSPOOL.192]
2087 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2088 DWORD Level, LPBYTE pDriverDirectory,
2089 DWORD cbBuf, LPDWORD pcbNeeded)
2091 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2092 BOOL ret;
2094 if(pName)
2095 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2096 if(pEnvironment)
2097 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2098 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2099 pDriverDirectory, cbBuf, pcbNeeded );
2100 if(pNameA)
2101 HeapFree( GetProcessHeap(), 0, pNameA );
2102 if(pEnvironmentA)
2103 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2105 return ret;
2108 /*****************************************************************************
2109 * AddPrinterDriverA [WINSPOOL.120]
2111 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2113 DRIVER_INFO_3A di3;
2114 HKEY hkeyDrivers, hkeyName;
2116 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2118 if(level != 2 && level != 3) {
2119 SetLastError(ERROR_INVALID_LEVEL);
2120 return FALSE;
2122 if(pName != NULL) {
2123 FIXME("pName= `%s' - unsupported\n", pName);
2124 SetLastError(ERROR_INVALID_PARAMETER);
2125 return FALSE;
2127 if(!pDriverInfo) {
2128 WARN("pDriverInfo == NULL");
2129 SetLastError(ERROR_INVALID_PARAMETER);
2130 return FALSE;
2133 if(level == 3)
2134 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2135 else {
2136 memset(&di3, 0, sizeof(di3));
2137 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2140 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2141 !di3.pDataFile) {
2142 SetLastError(ERROR_INVALID_PARAMETER);
2143 return FALSE;
2145 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2146 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2147 if(!di3.pHelpFile) di3.pHelpFile = "";
2148 if(!di3.pMonitorName) di3.pMonitorName = "";
2150 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2152 if(!hkeyDrivers) {
2153 ERR("Can't create Drivers key\n");
2154 return FALSE;
2157 if(level == 2) { /* apparently can't overwrite with level2 */
2158 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2159 RegCloseKey(hkeyName);
2160 RegCloseKey(hkeyDrivers);
2161 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2162 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2163 return FALSE;
2166 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2167 RegCloseKey(hkeyDrivers);
2168 ERR("Can't create Name key\n");
2169 return FALSE;
2171 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2173 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2174 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2175 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2176 sizeof(DWORD));
2177 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2178 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2179 di3.pDependentFiles, 0);
2180 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2181 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2182 RegCloseKey(hkeyName);
2183 RegCloseKey(hkeyDrivers);
2185 return TRUE;
2187 /*****************************************************************************
2188 * AddPrinterDriverW [WINSPOOL.121]
2190 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2191 LPBYTE pDriverInfo)
2193 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2194 level,pDriverInfo);
2195 return FALSE;
2199 /*****************************************************************************
2200 * PrinterProperties [WINSPOOL.201]
2202 * Displays a dialog to set the properties of the printer.
2204 * RETURNS
2205 * nonzero on succes or zero on faillure
2207 * BUGS
2208 * implemented as stub only
2210 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2211 HANDLE hPrinter /* [in] handle to printer object */
2213 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2214 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2215 return FALSE;
2218 /*****************************************************************************
2219 * EnumJobsA [WINSPOOL.162]
2222 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2223 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2224 LPDWORD pcReturned)
2226 FIXME("stub\n");
2227 if(pcbNeeded) *pcbNeeded = 0;
2228 if(pcReturned) *pcReturned = 0;
2229 return TRUE;
2233 /*****************************************************************************
2234 * EnumJobsW [WINSPOOL.163]
2237 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2238 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2239 LPDWORD pcReturned)
2241 FIXME("stub\n");
2242 if(pcbNeeded) *pcbNeeded = 0;
2243 if(pcReturned) *pcReturned = 0;
2244 return TRUE;
2247 /*****************************************************************************
2248 * WINSPOOL_EnumPrinterDrivers [internal]
2250 * Delivers information about all installed printer drivers installed on
2251 * localhost or a given server
2253 * RETURNS
2254 * nonzero on succes or zero on failure, if the buffer for the returned
2255 * information is too small the function will return an error
2257 * BUGS
2258 * - only implemented for localhost, foreign hosts will return an error
2260 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2261 DWORD Level, LPBYTE pDriverInfo,
2262 DWORD cbBuf, LPDWORD pcbNeeded,
2263 LPDWORD pcReturned, BOOL unicode)
2265 { HKEY hkeyDrivers;
2266 DWORD i, needed, number = 0, size = 0;
2267 WCHAR DriverNameW[255];
2268 PBYTE ptr;
2270 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2271 debugstr_w(pName), debugstr_w(pEnvironment),
2272 Level, pDriverInfo, cbBuf, unicode);
2274 /* check for local drivers */
2275 if(pName) {
2276 ERR("remote drivers unsupported! Current remote host is %s\n",
2277 debugstr_w(pName));
2278 return FALSE;
2281 /* check input parameter */
2282 if((Level < 1) || (Level > 3)) {
2283 ERR("unsupported level %ld \n", Level);
2284 return FALSE;
2287 /* initialize return values */
2288 if(pDriverInfo)
2289 memset( pDriverInfo, 0, cbBuf);
2290 *pcbNeeded = 0;
2291 *pcReturned = 0;
2293 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2294 if(!hkeyDrivers) {
2295 ERR("Can't open Drivers key\n");
2296 return FALSE;
2299 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2300 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2301 RegCloseKey(hkeyDrivers);
2302 ERR("Can't query Drivers key\n");
2303 return FALSE;
2305 TRACE("Found %ld Drivers\n", number);
2307 /* get size of single struct
2308 * unicode and ascii structure have the same size
2310 switch (Level) {
2311 case 1:
2312 size = sizeof(DRIVER_INFO_1A);
2313 break;
2314 case 2:
2315 size = sizeof(DRIVER_INFO_2A);
2316 break;
2317 case 3:
2318 size = sizeof(DRIVER_INFO_3A);
2319 break;
2322 /* calculate required buffer size */
2323 *pcbNeeded = size * number;
2325 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2326 i < number;
2327 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2328 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2329 != ERROR_SUCCESS) {
2330 ERR("Can't enum key number %ld\n", i);
2331 RegCloseKey(hkeyDrivers);
2332 return FALSE;
2334 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2335 pEnvironment, Level, ptr,
2336 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2337 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2338 &needed, unicode)) {
2339 RegCloseKey(hkeyDrivers);
2340 return FALSE;
2342 (*pcbNeeded) += needed;
2345 RegCloseKey(hkeyDrivers);
2347 if(cbBuf < *pcbNeeded){
2348 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2349 return FALSE;
2352 return TRUE;
2355 /*****************************************************************************
2356 * EnumPrinterDriversW [WINSPOOL.173]
2358 * see function EnumPrinterDrivers for RETURNS, BUGS
2360 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2361 LPBYTE pDriverInfo, DWORD cbBuf,
2362 LPDWORD pcbNeeded, LPDWORD pcReturned)
2364 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2365 cbBuf, pcbNeeded, pcReturned, TRUE);
2368 /*****************************************************************************
2369 * EnumPrinterDriversA [WINSPOOL.172]
2371 * see function EnumPrinterDrivers for RETURNS, BUGS
2373 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2374 LPBYTE pDriverInfo, DWORD cbBuf,
2375 LPDWORD pcbNeeded, LPDWORD pcReturned)
2376 { BOOL ret;
2377 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2379 if(pName)
2380 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2381 if(pEnvironment)
2382 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2384 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2385 cbBuf, pcbNeeded, pcReturned, FALSE);
2386 if(pNameW)
2387 HeapFree(GetProcessHeap(), 0, pNameW);
2388 if(pEnvironmentW)
2389 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2391 return ret;
2395 /******************************************************************************
2396 * EnumPortsA (WINSPOOL.166)
2398 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2399 LPDWORD bufneeded,LPDWORD bufreturned)
2401 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2402 return FALSE;
2405 /******************************************************************************
2406 * SetPrinterDataExA (WINSPOOL)
2408 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2409 LPSTR pValueName, DWORD Type,
2410 LPBYTE pData, DWORD cbData)
2412 HKEY hkeyPrinter, hkeySubkey;
2413 DWORD ret;
2415 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2416 debugstr_a(pValueName), Type, pData, cbData);
2418 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2419 != ERROR_SUCCESS)
2420 return ret;
2422 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2423 != ERROR_SUCCESS) {
2424 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2425 RegCloseKey(hkeyPrinter);
2426 return ret;
2428 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2429 RegCloseKey(hkeySubkey);
2430 RegCloseKey(hkeyPrinter);
2431 return ret;
2434 /******************************************************************************
2435 * SetPrinterDataExW (WINSPOOL)
2437 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2438 LPWSTR pValueName, DWORD Type,
2439 LPBYTE pData, DWORD cbData)
2441 HKEY hkeyPrinter, hkeySubkey;
2442 DWORD ret;
2444 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2445 debugstr_w(pValueName), Type, pData, cbData);
2447 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2448 != ERROR_SUCCESS)
2449 return ret;
2451 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2452 != ERROR_SUCCESS) {
2453 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2454 RegCloseKey(hkeyPrinter);
2455 return ret;
2457 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2458 RegCloseKey(hkeySubkey);
2459 RegCloseKey(hkeyPrinter);
2460 return ret;
2463 /******************************************************************************
2464 * SetPrinterDataA (WINSPOOL)
2466 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2467 LPBYTE pData, DWORD cbData)
2469 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2470 pData, cbData);
2473 /******************************************************************************
2474 * SetPrinterDataW (WINSPOOL)
2476 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2477 LPBYTE pData, DWORD cbData)
2479 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2480 pData, cbData);
2483 /******************************************************************************
2484 * GetPrinterDataExA (WINSPOOL)
2486 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2487 LPSTR pValueName, LPDWORD pType,
2488 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2490 HKEY hkeyPrinter, hkeySubkey;
2491 DWORD ret;
2493 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2494 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2495 pcbNeeded);
2497 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2498 != ERROR_SUCCESS)
2499 return ret;
2501 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2502 != ERROR_SUCCESS) {
2503 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2504 RegCloseKey(hkeyPrinter);
2505 return ret;
2507 *pcbNeeded = nSize;
2508 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2509 RegCloseKey(hkeySubkey);
2510 RegCloseKey(hkeyPrinter);
2511 return ret;
2514 /******************************************************************************
2515 * GetPrinterDataExW (WINSPOOL)
2517 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2518 LPWSTR pValueName, LPDWORD pType,
2519 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2521 HKEY hkeyPrinter, hkeySubkey;
2522 DWORD ret;
2524 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2525 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2526 pcbNeeded);
2528 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2529 != ERROR_SUCCESS)
2530 return ret;
2532 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2533 != ERROR_SUCCESS) {
2534 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2535 RegCloseKey(hkeyPrinter);
2536 return ret;
2538 *pcbNeeded = nSize;
2539 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2540 RegCloseKey(hkeySubkey);
2541 RegCloseKey(hkeyPrinter);
2542 return ret;
2545 /******************************************************************************
2546 * GetPrinterDataA (WINSPOOL)
2548 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2549 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2551 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2552 pData, nSize, pcbNeeded);
2555 /******************************************************************************
2556 * GetPrinterDataW (WINSPOOL)
2558 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2559 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2561 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2562 pData, nSize, pcbNeeded);
2565 /*******************************************************************************
2566 * EnumPrinterDataExW [WINSPOOL.197]
2568 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2569 LPBYTE pEnumValues, DWORD cbEnumValues,
2570 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2572 HKEY hkPrinter, hkSubKey;
2573 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2574 cbValueNameLen, cbMaxValueLen, cbValueLen,
2575 cbBufSize, dwType;
2576 LPWSTR lpValueName;
2577 HANDLE hHeap;
2578 PBYTE lpValue;
2579 PPRINTER_ENUM_VALUESW ppev;
2581 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2583 if (pKeyName == NULL || *pKeyName == 0)
2584 return ERROR_INVALID_PARAMETER;
2586 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2587 if (ret != ERROR_SUCCESS)
2589 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2590 hPrinter, ret);
2591 return ret;
2594 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2595 if (ret != ERROR_SUCCESS)
2597 r = RegCloseKey (hkPrinter);
2598 if (r != ERROR_SUCCESS)
2599 WARN ("RegCloseKey returned %li\n", r);
2600 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2601 debugstr_w (pKeyName), ret);
2602 return ret;
2605 ret = RegCloseKey (hkPrinter);
2606 if (ret != ERROR_SUCCESS)
2608 ERR ("RegCloseKey returned %li\n", ret);
2609 r = RegCloseKey (hkSubKey);
2610 if (r != ERROR_SUCCESS)
2611 WARN ("RegCloseKey returned %li\n", r);
2612 return ret;
2615 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2616 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2617 if (ret != ERROR_SUCCESS)
2619 r = RegCloseKey (hkSubKey);
2620 if (r != ERROR_SUCCESS)
2621 WARN ("RegCloseKey returned %li\n", r);
2622 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2623 return ret;
2626 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2627 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2629 if (cValues == 0) /* empty key */
2631 r = RegCloseKey (hkSubKey);
2632 if (r != ERROR_SUCCESS)
2633 WARN ("RegCloseKey returned %li\n", r);
2634 *pcbEnumValues = *pnEnumValues = 0;
2635 return ERROR_SUCCESS;
2638 ++cbMaxValueNameLen; /* allow for trailing '\0' */
2640 hHeap = GetProcessHeap ();
2641 if (hHeap == (HANDLE) NULL)
2643 ERR ("GetProcessHeap failed\n");
2644 r = RegCloseKey (hkSubKey);
2645 if (r != ERROR_SUCCESS)
2646 WARN ("RegCloseKey returned %li\n", r);
2647 return ERROR_OUTOFMEMORY;
2650 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
2651 if (lpValueName == NULL)
2653 ERR ("Failed to allocate %li bytes from process heap\n",
2654 cbMaxValueNameLen * sizeof (WCHAR));
2655 r = RegCloseKey (hkSubKey);
2656 if (r != ERROR_SUCCESS)
2657 WARN ("RegCloseKey returned %li\n", r);
2658 return ERROR_OUTOFMEMORY;
2661 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
2662 if (lpValue == NULL)
2664 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
2665 if (HeapFree (hHeap, 0, lpValueName) == 0)
2666 WARN ("HeapFree failed with code %li\n", GetLastError ());
2667 r = RegCloseKey (hkSubKey);
2668 if (r != ERROR_SUCCESS)
2669 WARN ("RegCloseKey returned %li\n", r);
2670 return ERROR_OUTOFMEMORY;
2673 TRACE ("pass 1: calculating buffer required for all names and values\n");
2675 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
2677 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
2679 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2681 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2682 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2683 NULL, NULL, lpValue, &cbValueLen);
2684 if (ret != ERROR_SUCCESS)
2686 if (HeapFree (hHeap, 0, lpValue) == 0)
2687 WARN ("HeapFree failed with code %li\n", GetLastError ());
2688 if (HeapFree (hHeap, 0, lpValueName) == 0)
2689 WARN ("HeapFree failed with code %li\n", GetLastError ());
2690 r = RegCloseKey (hkSubKey);
2691 if (r != ERROR_SUCCESS)
2692 WARN ("RegCloseKey returned %li\n", r);
2693 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2694 return ret;
2697 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
2698 debugstr_w (lpValueName), dwIndex,
2699 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
2701 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
2702 cbBufSize += cbValueLen;
2705 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
2707 *pcbEnumValues = cbBufSize;
2708 *pnEnumValues = cValues;
2710 if (cbEnumValues < cbBufSize) /* buffer too small */
2712 if (HeapFree (hHeap, 0, lpValue) == 0)
2713 WARN ("HeapFree failed with code %li\n", GetLastError ());
2714 if (HeapFree (hHeap, 0, lpValueName) == 0)
2715 WARN ("HeapFree failed with code %li\n", GetLastError ());
2716 r = RegCloseKey (hkSubKey);
2717 if (r != ERROR_SUCCESS)
2718 WARN ("RegCloseKey returned %li\n", r);
2719 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
2720 return ERROR_MORE_DATA;
2723 TRACE ("pass 2: copying all names and values to buffer\n");
2725 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
2726 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
2728 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2730 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2731 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2732 NULL, &dwType, lpValue, &cbValueLen);
2733 if (ret != ERROR_SUCCESS)
2735 if (HeapFree (hHeap, 0, lpValue) == 0)
2736 WARN ("HeapFree failed with code %li\n", GetLastError ());
2737 if (HeapFree (hHeap, 0, lpValueName) == 0)
2738 WARN ("HeapFree failed with code %li\n", GetLastError ());
2739 r = RegCloseKey (hkSubKey);
2740 if (r != ERROR_SUCCESS)
2741 WARN ("RegCloseKey returned %li\n", r);
2742 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2743 return ret;
2746 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
2747 memcpy (pEnumValues, lpValueName, cbValueNameLen);
2748 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
2749 pEnumValues += cbValueNameLen;
2751 /* return # of *bytes* (including trailing \0), not # of chars */
2752 ppev[dwIndex].cbValueName = cbValueNameLen;
2754 ppev[dwIndex].dwType = dwType;
2756 memcpy (pEnumValues, lpValue, cbValueLen);
2757 ppev[dwIndex].pData = pEnumValues;
2758 pEnumValues += cbValueLen;
2760 ppev[dwIndex].cbData = cbValueLen;
2762 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
2763 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
2766 if (HeapFree (hHeap, 0, lpValue) == 0)
2768 ret = GetLastError ();
2769 ERR ("HeapFree failed with code %li\n", ret);
2770 if (HeapFree (hHeap, 0, lpValueName) == 0)
2771 WARN ("HeapFree failed with code %li\n", GetLastError ());
2772 r = RegCloseKey (hkSubKey);
2773 if (r != ERROR_SUCCESS)
2774 WARN ("RegCloseKey returned %li\n", r);
2775 return ret;
2778 if (HeapFree (hHeap, 0, lpValueName) == 0)
2780 ret = GetLastError ();
2781 ERR ("HeapFree failed with code %li\n", ret);
2782 r = RegCloseKey (hkSubKey);
2783 if (r != ERROR_SUCCESS)
2784 WARN ("RegCloseKey returned %li\n", r);
2785 return ret;
2788 ret = RegCloseKey (hkSubKey);
2789 if (ret != ERROR_SUCCESS)
2791 ERR ("RegCloseKey returned %li\n", ret);
2792 return ret;
2795 return ERROR_SUCCESS;
2798 /*******************************************************************************
2799 * EnumPrinterDataExA [WINSPOOL.196]
2801 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
2802 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
2803 * what Windows 2000 SP1 does.
2806 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
2807 LPBYTE pEnumValues, DWORD cbEnumValues,
2808 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2810 INT len;
2811 LPWSTR pKeyNameW;
2812 DWORD ret, dwIndex, dwBufSize;
2813 HANDLE hHeap;
2814 LPSTR pBuffer;
2816 TRACE ("%08x %s\n", hPrinter, pKeyName);
2818 if (pKeyName == NULL || *pKeyName == 0)
2819 return ERROR_INVALID_PARAMETER;
2821 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
2822 if (len == 0)
2824 ret = GetLastError ();
2825 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2826 return ret;
2829 hHeap = GetProcessHeap ();
2830 if (hHeap == (HANDLE) NULL)
2832 ERR ("GetProcessHeap failed\n");
2833 return ERROR_OUTOFMEMORY;
2836 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
2837 if (pKeyNameW == NULL)
2839 ERR ("Failed to allocate %li bytes from process heap\n",
2840 (LONG) len * sizeof (WCHAR));
2841 return ERROR_OUTOFMEMORY;
2844 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
2846 ret = GetLastError ();
2847 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2848 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2849 WARN ("HeapFree failed with code %li\n", GetLastError ());
2850 return ret;
2853 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
2854 pcbEnumValues, pnEnumValues);
2855 if (ret != ERROR_SUCCESS)
2857 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2858 WARN ("HeapFree failed with code %li\n", GetLastError ());
2859 TRACE ("EnumPrinterDataExW returned %li\n", ret);
2860 return ret;
2863 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2865 ret = GetLastError ();
2866 ERR ("HeapFree failed with code %li\n", ret);
2867 return ret;
2870 if (*pnEnumValues == 0) /* empty key */
2871 return ERROR_SUCCESS;
2873 dwBufSize = 0;
2874 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2876 PPRINTER_ENUM_VALUESW ppev =
2877 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2879 if (dwBufSize < ppev->cbValueName)
2880 dwBufSize = ppev->cbValueName;
2882 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
2883 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
2884 dwBufSize = ppev->cbData;
2887 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
2889 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
2890 if (pBuffer == NULL)
2892 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
2893 return ERROR_OUTOFMEMORY;
2896 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2898 PPRINTER_ENUM_VALUESW ppev =
2899 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2901 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
2902 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
2903 NULL);
2904 if (len == 0)
2906 ret = GetLastError ();
2907 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2908 if (HeapFree (hHeap, 0, pBuffer) == 0)
2909 WARN ("HeapFree failed with code %li\n", GetLastError ());
2910 return ret;
2913 memcpy (ppev->pValueName, pBuffer, len);
2915 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2917 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
2918 ppev->dwType != REG_MULTI_SZ)
2919 continue;
2921 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
2922 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
2923 if (len == 0)
2925 ret = GetLastError ();
2926 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2927 if (HeapFree (hHeap, 0, pBuffer) == 0)
2928 WARN ("HeapFree failed with code %li\n", GetLastError ());
2929 return ret;
2932 memcpy (ppev->pData, pBuffer, len);
2934 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2935 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
2938 if (HeapFree (hHeap, 0, pBuffer) == 0)
2940 ret = GetLastError ();
2941 ERR ("HeapFree failed with code %li\n", ret);
2942 return ret;
2945 return ERROR_SUCCESS;