Added CUPS printing support.
[wine.git] / dlls / winspool / info.c
bloba0978dbe451cbca48d007d64fe3ae04429ee0eb3
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 * Copyright 2001 Marcus Meissner
9 */
11 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <stddef.h>
18 #ifdef HAVE_CUPS
19 # include <cups/cups.h>
20 #endif
21 #include "winspool.h"
22 #include "winbase.h"
23 #include "winerror.h"
24 #include "winreg.h"
25 #include "wine/windef16.h"
26 #include "wine/unicode.h"
27 #include "debugtools.h"
28 #include "heap.h"
29 #include "winnls.h"
31 DEFAULT_DEBUG_CHANNEL(winspool);
33 static LPWSTR *printer_array;
34 static int nb_printers;
36 static DWORD WINAPI (*GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
37 WORD fwCapability, LPSTR lpszOutput,
38 LPDEVMODEA lpdm );
39 static INT WINAPI (*GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
40 LPSTR lpszDevice, LPSTR lpszPort,
41 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
42 DWORD fwMode );
44 static char Printers[] =
45 "System\\CurrentControlSet\\control\\Print\\Printers\\";
46 static char Drivers[] =
47 "System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
49 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
51 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
52 'i','o','n',' ','F','i','l','e',0};
53 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
54 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
55 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
56 'M','o','d','e',0};
57 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
58 'i','l','e','s',0};
59 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
60 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
61 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
62 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
63 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
64 static WCHAR NameW[] = {'N','a','m','e',0};
65 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
66 static WCHAR PortW[] = {'P','o','r','t',0};
67 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
68 's','s','o','r',0};
69 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
70 'v','e','r',0};
71 static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
72 'v','e','r','D','a','t','a',0};
73 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
74 'i','l','e',0};
75 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
76 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
78 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
80 #ifdef HAVE_CUPS
81 void
82 CUPS_LoadPrinters(void) {
83 cups_dest_t *dests;
84 int i,nrofdests;
85 PRINTER_INFO_2A pinfo2a;
86 DRIVER_INFO_3A di3a;
87 const char* def = cupsGetDefault();
89 nrofdests = cupsGetDests(&dests);
91 di3a.cVersion = 0x400;
92 di3a.pName = "PS Driver";
93 di3a.pEnvironment = NULL; /* NULL means auto */
94 di3a.pDriverPath = "wineps.drv";
95 di3a.pDataFile = "<datafile?>";
96 di3a.pConfigFile = "wineps.drv";
97 di3a.pHelpFile = "<helpfile?>";
98 di3a.pDependentFiles = "<dependend files?>";
99 di3a.pMonitorName = "<monitor name?>";
100 di3a.pDefaultDataType = "RAW";
103 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
104 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
105 return;
107 for (i=0;i<nrofdests;i++) {
108 const char *ppd = cupsGetPPD(dests[i].name);
109 char *port,*devline;
111 if (!ppd)
112 continue;
113 unlink(ppd);
115 if (!strcmp(def,dests[i].name)) {
116 char *buf = HeapAlloc(GetProcessHeap(),0,2*strlen(dests[i].name)+strlen(",WINEPS,CUPS:")+1);
118 sprintf(buf,"%s,WINEPS,CUPS:%s",dests[i].name,dests[i].name);
119 WriteProfileStringA("windows","device",buf);
120 HeapFree(GetProcessHeap(),0,buf);
122 memset(&pinfo2a,0,sizeof(pinfo2a));
123 pinfo2a.pPrinterName = dests[i].name;
124 pinfo2a.pDatatype = "RAW";
125 pinfo2a.pPrintProcessor = "WinPrint";
126 pinfo2a.pDriverName = "PS Driver";
127 pinfo2a.pComment = "WINEPS Printer using CUPS";
128 pinfo2a.pLocation = "<physical location of printer>";
129 port = HeapAlloc(GetProcessHeap(),0,strlen("CUPS:")+strlen(dests[i].name)+1);
130 sprintf(port,"CUPS:%s",dests[i].name);
131 pinfo2a.pPortName = port;
132 pinfo2a.pParameters = "<parameters?>";
133 pinfo2a.pShareName = "<share name?>";
134 pinfo2a.pSepFile = "<sep file?>";
136 devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
137 sprintf(devline,"WINEPS,%s",port);
138 WriteProfileStringA("devices",dests[i].name,devline);
139 HeapFree(GetProcessHeap(),0,devline);
141 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
142 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
143 ERR("%s not added by AddPrinterA (%ld)\n",dests[i].name,GetLastError());
145 HeapFree(GetProcessHeap(),0,port);
148 #endif
151 /******************************************************************
152 * WINSPOOL_GetOpenedPrinterEntry
153 * Get the first place empty in the opened printer table
155 static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
157 int i;
159 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
161 if (i >= nb_printers)
163 LPWSTR *new_array = HeapReAlloc( GetProcessHeap(), 0, printer_array,
164 (nb_printers + 16) * sizeof(*new_array) );
165 if (!new_array) return 0;
166 printer_array = new_array;
167 nb_printers += 16;
170 if ((printer_array[i] = HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )))
172 strcpyW( printer_array[i], name );
173 return (HANDLE)(i + 1);
175 return 0;
178 /******************************************************************
179 * WINSPOOL_GetOpenedPrinter
180 * Get the pointer to the opened printer referred by the handle
182 static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
184 int idx = (int)printerHandle;
185 if ((idx <= 0) || (idx > nb_printers))
187 SetLastError(ERROR_INVALID_HANDLE);
188 return NULL;
190 return printer_array[idx - 1];
193 /******************************************************************
194 * WINSPOOL_GetOpenedPrinterRegKey
197 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
199 LPCWSTR name = WINSPOOL_GetOpenedPrinter(hPrinter);
200 DWORD ret;
201 HKEY hkeyPrinters;
203 if(!name) return ERROR_INVALID_HANDLE;
205 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
206 ERROR_SUCCESS)
207 return ret;
209 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
211 ERR("Can't find opened printer %s in registry\n",
212 debugstr_w(name));
213 RegCloseKey(hkeyPrinters);
214 return ERROR_INVALID_PRINTER_NAME; /* ? */
216 RegCloseKey(hkeyPrinters);
217 return ERROR_SUCCESS;
220 /***********************************************************
221 * DEVMODEcpyAtoW
223 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
225 BOOL Formname;
226 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
227 DWORD size;
229 Formname = (dmA->dmSize > off_formname);
230 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
231 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
232 CCHDEVICENAME);
233 if(!Formname) {
234 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
235 dmA->dmSize - CCHDEVICENAME);
236 } else {
237 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
238 off_formname - CCHDEVICENAME);
239 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
240 CCHFORMNAME);
241 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
242 (off_formname + CCHFORMNAME));
244 dmW->dmSize = size;
245 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
246 dmA->dmDriverExtra);
247 return dmW;
250 /***********************************************************
251 * DEVMODEdupAtoW
252 * Creates a unicode copy of supplied devmode on heap
254 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
256 LPDEVMODEW dmW;
257 DWORD size;
258 BOOL Formname;
259 ptrdiff_t off_formname;
261 TRACE("\n");
262 if(!dmA) return NULL;
264 off_formname = (char *)dmA->dmFormName - (char *)dmA;
265 Formname = (dmA->dmSize > off_formname);
266 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
267 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
268 return DEVMODEcpyAtoW(dmW, dmA);
271 /***********************************************************
272 * DEVMODEdupWtoA
273 * Creates an ascii copy of supplied devmode on heap
275 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
277 LPDEVMODEA dmA;
278 DWORD size;
279 BOOL Formname;
280 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
282 if(!dmW) return NULL;
283 Formname = (dmW->dmSize > off_formname);
284 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
285 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
286 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
287 CCHDEVICENAME, NULL, NULL);
288 if(!Formname) {
289 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
290 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
291 } else {
292 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
293 off_formname - CCHDEVICENAME * sizeof(WCHAR));
294 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
295 CCHFORMNAME, NULL, NULL);
296 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
297 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
299 dmA->dmSize = size;
300 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
301 dmW->dmDriverExtra);
302 return dmA;
305 /***********************************************************
306 * PRINTER_INFO_2AtoW
307 * Creates a unicode copy of PRINTER_INFO_2A on heap
309 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
311 LPPRINTER_INFO_2W piW;
312 if(!piA) return NULL;
313 piW = HeapAlloc(heap, 0, sizeof(*piW));
314 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
315 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
316 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
317 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
318 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
319 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
320 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
321 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
322 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
323 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
324 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
325 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
326 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
327 return piW;
330 /***********************************************************
331 * FREE_PRINTER_INFO_2W
332 * Free PRINTER_INFO_2W and all strings
334 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
336 if(!piW) return;
338 HeapFree(heap,0,piW->pServerName);
339 HeapFree(heap,0,piW->pPrinterName);
340 HeapFree(heap,0,piW->pShareName);
341 HeapFree(heap,0,piW->pPortName);
342 HeapFree(heap,0,piW->pDriverName);
343 HeapFree(heap,0,piW->pComment);
344 HeapFree(heap,0,piW->pLocation);
345 HeapFree(heap,0,piW->pDevMode);
346 HeapFree(heap,0,piW->pSepFile);
347 HeapFree(heap,0,piW->pPrintProcessor);
348 HeapFree(heap,0,piW->pDatatype);
349 HeapFree(heap,0,piW->pParameters);
350 HeapFree(heap,0,piW);
351 return;
354 /******************************************************************
355 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
358 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
359 LPSTR pOutput, LPDEVMODEA lpdm)
361 INT ret;
363 if (!GDI_CallDeviceCapabilities16)
365 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
366 (LPCSTR)104 );
367 if (!GDI_CallDeviceCapabilities16) return -1;
369 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
371 /* If DC_PAPERSIZE map POINT16s to POINTs */
372 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
373 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
374 POINT *pt = (POINT *)pOutput;
375 INT i;
376 memcpy(tmp, pOutput, ret * sizeof(POINT16));
377 for(i = 0; i < ret; i++, pt++)
379 pt->x = tmp[i].x;
380 pt->y = tmp[i].y;
382 HeapFree( GetProcessHeap(), 0, tmp );
384 return ret;
388 /*****************************************************************************
389 * DeviceCapabilitiesW [WINSPOOL.152]
391 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
394 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
395 WORD fwCapability, LPWSTR pOutput,
396 const DEVMODEW *pDevMode)
398 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
399 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
400 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
401 INT ret;
403 if(pOutput && (fwCapability == DC_BINNAMES ||
404 fwCapability == DC_FILEDEPENDENCIES ||
405 fwCapability == DC_PAPERNAMES)) {
406 /* These need A -> W translation */
407 INT size = 0, i;
408 LPSTR pOutputA;
409 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
410 dmA);
411 if(ret == -1)
412 return ret;
413 switch(fwCapability) {
414 case DC_BINNAMES:
415 size = 24;
416 break;
417 case DC_PAPERNAMES:
418 case DC_FILEDEPENDENCIES:
419 size = 64;
420 break;
422 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
423 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
424 dmA);
425 for(i = 0; i < ret; i++)
426 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
427 pOutput + (i * size), size);
428 HeapFree(GetProcessHeap(), 0, pOutputA);
429 } else {
430 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
431 (LPSTR)pOutput, dmA);
433 HeapFree(GetProcessHeap(),0,pPortA);
434 HeapFree(GetProcessHeap(),0,pDeviceA);
435 HeapFree(GetProcessHeap(),0,dmA);
436 return ret;
439 /******************************************************************
440 * DocumentPropertiesA [WINSPOOL.155]
443 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
444 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
445 LPDEVMODEA pDevModeInput,DWORD fMode )
447 LPSTR lpName = pDeviceName;
448 LONG ret;
450 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
451 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
454 if(!pDeviceName) {
455 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
456 if(!lpNameW) {
457 ERR("no name from hPrinter?\n");
458 return -1;
460 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
463 if (!GDI_CallExtDeviceMode16)
465 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
466 (LPCSTR)102 );
467 if (!GDI_CallExtDeviceMode16) {
468 ERR("No CallExtDeviceMode16?\n");
469 return -1;
472 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
473 pDevModeInput, NULL, fMode);
475 if(!pDeviceName)
476 HeapFree(GetProcessHeap(),0,lpName);
477 return ret;
481 /*****************************************************************************
482 * DocumentPropertiesW
484 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
485 LPWSTR pDeviceName,
486 LPDEVMODEW pDevModeOutput,
487 LPDEVMODEW pDevModeInput, DWORD fMode)
490 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
491 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
492 LPDEVMODEA pDevModeOutputA = NULL;
493 LONG ret;
495 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
496 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
497 fMode);
498 if(pDevModeOutput) {
499 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
500 if(ret < 0) return ret;
501 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
503 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
504 pDevModeInputA, fMode);
505 if(pDevModeOutput) {
506 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
507 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
509 if(fMode == 0 && ret > 0)
510 ret += (CCHDEVICENAME + CCHFORMNAME);
511 HeapFree(GetProcessHeap(),0,pDevModeInputA);
512 HeapFree(GetProcessHeap(),0,pDeviceNameA);
513 return ret;
516 /******************************************************************
517 * OpenPrinterA [WINSPOOL.196]
520 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
521 LPPRINTER_DEFAULTSA pDefault)
523 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
524 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
525 BOOL ret;
527 if(pDefault) {
528 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
529 pDefault->pDatatype);
530 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
531 pDefault->pDevMode);
532 DefaultW.DesiredAccess = pDefault->DesiredAccess;
533 pDefaultW = &DefaultW;
535 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
536 if(pDefault) {
537 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
538 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
540 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
541 return ret;
544 /******************************************************************
545 * OpenPrinterW [WINSPOOL.197]
548 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
549 LPPRINTER_DEFAULTSW pDefault)
551 HKEY hkeyPrinters, hkeyPrinter;
553 if (!lpPrinterName) {
554 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
555 SetLastError(ERROR_INVALID_PARAMETER);
556 return FALSE;
559 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
560 pDefault);
562 /* Check Printer exists */
563 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
564 ERROR_SUCCESS) {
565 ERR("Can't create Printers key\n");
566 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
567 return FALSE;
570 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
571 != ERROR_SUCCESS) {
572 ERR("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
573 RegCloseKey(hkeyPrinters);
574 SetLastError(ERROR_INVALID_PARAMETER);
575 return FALSE;
577 RegCloseKey(hkeyPrinter);
578 RegCloseKey(hkeyPrinters);
580 if(!phPrinter) /* This seems to be what win95 does anyway */
581 return TRUE;
583 /* Get the unique handle of the printer*/
584 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
586 if (pDefault != NULL)
587 FIXME("Not handling pDefault\n");
589 return TRUE;
592 /******************************************************************
593 * AddMonitorA [WINSPOOL.107]
596 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
598 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
599 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
600 return FALSE;
603 /******************************************************************
604 * DeletePrinterDriverA [WINSPOOL.146]
607 BOOL WINAPI
608 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
610 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
611 debugstr_a(pDriverName));
612 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
613 return FALSE;
617 /******************************************************************
618 * DeleteMonitorA [WINSPOOL.135]
621 BOOL WINAPI
622 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
624 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
625 debugstr_a(pMonitorName));
626 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
627 return FALSE;
631 /******************************************************************
632 * DeletePortA [WINSPOOL.137]
635 BOOL WINAPI
636 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
638 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
639 debugstr_a(pPortName));
640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
641 return FALSE;
644 /******************************************************************************
645 * SetPrinterW [WINSPOOL.214]
647 BOOL WINAPI
648 SetPrinterW(
649 HANDLE hPrinter,
650 DWORD Level,
651 LPBYTE pPrinter,
652 DWORD Command) {
654 FIXME("():stub\n");
655 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
656 return FALSE;
659 /******************************************************************************
660 * WritePrinter [WINSPOOL.223]
662 BOOL WINAPI
663 WritePrinter(
664 HANDLE hPrinter,
665 LPVOID pBuf,
666 DWORD cbBuf,
667 LPDWORD pcWritten) {
669 FIXME("():stub\n");
670 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
671 return FALSE;
674 /*****************************************************************************
675 * AddFormA [WINSPOOL.103]
677 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
679 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
680 return 1;
683 /*****************************************************************************
684 * AddFormW [WINSPOOL.104]
686 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
688 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
689 return 1;
692 /*****************************************************************************
693 * AddJobA [WINSPOOL.105]
695 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
696 DWORD cbBuf, LPDWORD pcbNeeded)
698 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
699 pcbNeeded);
700 return 1;
703 /*****************************************************************************
704 * AddJobW [WINSPOOL.106]
706 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
707 LPDWORD pcbNeeded)
709 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
710 pcbNeeded);
711 return 1;
714 /*****************************************************************************
715 * WINSPOOL_OpenDriverReg [internal]
717 * opens the registry for the printer drivers depending on the given input
718 * variable pEnvironment
720 * RETURNS:
721 * the opened hkey on success
722 * NULL on error
724 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
725 { HKEY retval;
726 LPSTR lpKey, p = NULL;
728 TRACE("%s\n",
729 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
731 if(pEnvironment)
732 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
733 pEnvironment;
734 else {
735 OSVERSIONINFOA ver;
736 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
738 if(!GetVersionExA( &ver))
739 return 0;
741 switch (ver.dwPlatformId) {
742 case VER_PLATFORM_WIN32s:
743 return 0;
744 case VER_PLATFORM_WIN32_NT:
745 p = "Windows NT x86";
746 break;
747 default:
748 p = "Windows 4.0";
749 break;
751 TRACE("set environment to %s\n", p);
754 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
755 strlen(p) + strlen(Drivers));
756 sprintf( lpKey, Drivers, p);
758 TRACE("%s\n", lpKey);
760 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
761 ERROR_SUCCESS)
762 retval = 0;
764 if(pEnvironment && unicode)
765 HeapFree( GetProcessHeap(), 0, p);
766 HeapFree( GetProcessHeap(), 0, lpKey);
768 return retval;
771 /*****************************************************************************
772 * AddPrinterW [WINSPOOL.122]
774 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
776 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
777 LPDEVMODEA dmA;
778 LPDEVMODEW dmW;
779 HANDLE retval;
780 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
781 LONG size;
783 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
785 if(pName != NULL) {
786 ERR("pName = %s - unsupported\n", debugstr_w(pName));
787 SetLastError(ERROR_INVALID_PARAMETER);
788 return 0;
790 if(Level != 2) {
791 ERR("Level = %ld, unsupported!\n", Level);
792 SetLastError(ERROR_INVALID_LEVEL);
793 return 0;
795 if(!pPrinter) {
796 SetLastError(ERROR_INVALID_PARAMETER);
797 return 0;
799 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
800 ERROR_SUCCESS) {
801 ERR("Can't create Printers key\n");
802 return 0;
804 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
805 ERROR_SUCCESS) {
806 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
807 RegCloseKey(hkeyPrinter);
808 RegCloseKey(hkeyPrinters);
809 return 0;
811 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
812 if(!hkeyDrivers) {
813 ERR("Can't create Drivers key\n");
814 RegCloseKey(hkeyPrinters);
815 return 0;
817 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
818 ERROR_SUCCESS) {
819 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
820 RegCloseKey(hkeyPrinters);
821 RegCloseKey(hkeyDrivers);
822 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
823 return 0;
825 RegCloseKey(hkeyDriver);
826 RegCloseKey(hkeyDrivers);
828 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
829 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
830 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
831 RegCloseKey(hkeyPrinters);
832 return 0;
835 /* See if we can load the driver. We may need the devmode structure anyway
837 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
838 if(size < 0) {
839 FIXME("DocumentProperties fails\n");
840 size = sizeof(DEVMODEW);
842 if(pi->pDevMode) {
843 dmW = pi->pDevMode;
844 } else {
845 dmW = HeapAlloc(GetProcessHeap(), 0, size);
846 dmW->dmSize = size;
847 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
850 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
851 ERROR_SUCCESS) {
852 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
853 SetLastError(ERROR_INVALID_PRINTER_NAME);
854 RegCloseKey(hkeyPrinters);
855 if(!pi->pDevMode)
856 HeapFree(GetProcessHeap(), 0, dmW);
857 return 0;
859 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
860 (LPBYTE)&pi->Attributes, sizeof(DWORD));
861 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
863 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
864 and we support these drivers. NT writes DEVMODEW so somehow
865 we'll need to distinguish between these when we support NT
866 drivers */
867 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
868 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
869 dmA->dmSize + dmA->dmDriverExtra);
870 HeapFree(GetProcessHeap(), 0, dmA);
871 if(!pi->pDevMode)
872 HeapFree(GetProcessHeap(), 0, dmW);
873 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
875 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
877 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
878 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
879 (LPBYTE)pi->pParameters, 0);
880 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
881 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
882 (LPBYTE)pi->pPrintProcessor, 0);
883 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
884 (LPBYTE)pi->pDriverName, 0);
885 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
886 (LPBYTE)&pi->Priority, sizeof(DWORD));
887 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
888 (LPBYTE)pi->pSepFile, 0);
889 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
891 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
892 (LPBYTE)&pi->StartTime, sizeof(DWORD));
893 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
894 (LPBYTE)&pi->Status, sizeof(DWORD));
895 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
896 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
898 RegCloseKey(hkeyPrinter);
899 RegCloseKey(hkeyPrinters);
900 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
901 ERR("OpenPrinter failing\n");
902 return 0;
904 return retval;
907 /*****************************************************************************
908 * AddPrinterA [WINSPOOL.117]
910 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
912 WCHAR *pNameW;
913 PRINTER_INFO_2W *piW;
914 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
915 HANDLE ret;
917 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
918 if(Level != 2) {
919 ERR("Level = %ld, unsupported!\n", Level);
920 SetLastError(ERROR_INVALID_LEVEL);
921 return 0;
923 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
924 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
926 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
928 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
929 HeapFree(GetProcessHeap(),0,pNameW);
930 return ret;
934 /*****************************************************************************
935 * ClosePrinter [WINSPOOL.126]
937 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
939 int i = (int)hPrinter;
941 TRACE("Handle %d\n", hPrinter);
943 if ((i <= 0) || (i > nb_printers)) return FALSE;
944 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
945 printer_array[i - 1] = NULL;
946 return TRUE;
949 /*****************************************************************************
950 * DeleteFormA [WINSPOOL.133]
952 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
954 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
955 return 1;
958 /*****************************************************************************
959 * DeleteFormW [WINSPOOL.134]
961 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
963 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
964 return 1;
967 /*****************************************************************************
968 * DeletePrinter [WINSPOOL.143]
970 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
972 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
973 HKEY hkeyPrinters;
975 if(!lpNameW) return FALSE;
976 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
977 ERROR_SUCCESS) {
978 ERR("Can't open Printers key\n");
979 return 0;
982 /* This should use a recursive delete see Q142491 or SHDeleteKey */
983 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
984 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
985 RegCloseKey(hkeyPrinters);
986 return 0;
989 ClosePrinter(hPrinter);
990 return TRUE;
993 /*****************************************************************************
994 * SetPrinterA [WINSPOOL.211]
996 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
997 DWORD Command)
999 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1000 return FALSE;
1003 /*****************************************************************************
1004 * SetJobA [WINSPOOL.209]
1006 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1007 LPBYTE pJob, DWORD Command)
1009 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1010 Command);
1011 return FALSE;
1014 /*****************************************************************************
1015 * SetJobW [WINSPOOL.210]
1017 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1018 LPBYTE pJob, DWORD Command)
1020 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
1021 Command);
1022 return FALSE;
1025 /*****************************************************************************
1026 * GetFormA [WINSPOOL.181]
1028 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1029 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1031 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
1032 Level,pForm,cbBuf,pcbNeeded);
1033 return FALSE;
1036 /*****************************************************************************
1037 * GetFormW [WINSPOOL.182]
1039 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1040 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1042 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1043 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1044 return FALSE;
1047 /*****************************************************************************
1048 * SetFormA [WINSPOOL.207]
1050 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1051 LPBYTE pForm)
1053 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1054 return FALSE;
1057 /*****************************************************************************
1058 * SetFormW [WINSPOOL.208]
1060 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1061 LPBYTE pForm)
1063 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1064 return FALSE;
1067 /*****************************************************************************
1068 * ReadPrinter [WINSPOOL.202]
1070 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1071 LPDWORD pNoBytesRead)
1073 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1074 return FALSE;
1077 /*****************************************************************************
1078 * ResetPrinterA [WINSPOOL.203]
1080 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1082 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1083 return FALSE;
1086 /*****************************************************************************
1087 * ResetPrinterW [WINSPOOL.204]
1089 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1091 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1092 return FALSE;
1095 /*****************************************************************************
1096 * WINSPOOL_GetDWORDFromReg
1098 * Return DWORD associated with ValueName from hkey.
1100 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1102 DWORD sz = sizeof(DWORD), type, value = 0;
1103 LONG ret;
1105 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1107 if(ret != ERROR_SUCCESS) {
1108 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1109 return 0;
1111 if(type != REG_DWORD) {
1112 ERR("Got type %ld\n", type);
1113 return 0;
1115 return value;
1118 /*****************************************************************************
1119 * WINSPOOL_GetStringFromReg
1121 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1122 * String is stored either as unicode or ascii.
1123 * Bit of a hack here to get the ValueName if we want ascii.
1125 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1126 DWORD buflen, DWORD *needed,
1127 BOOL unicode)
1129 DWORD sz = buflen, type;
1130 LONG ret;
1132 if(unicode)
1133 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1134 else {
1135 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1136 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1137 HeapFree(GetProcessHeap(),0,ValueNameA);
1139 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1140 WARN("Got ret = %ld\n", ret);
1141 *needed = 0;
1142 return FALSE;
1144 *needed = sz;
1145 return TRUE;
1148 /*****************************************************************************
1149 * WINSPOOL_GetDevModeFromReg
1151 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1152 * DevMode is stored either as unicode or ascii.
1154 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1155 LPBYTE ptr,
1156 DWORD buflen, DWORD *needed,
1157 BOOL unicode)
1159 DWORD sz = buflen, type;
1160 LONG ret;
1162 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1163 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1164 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1165 if (sz < sizeof(DEVMODEA))
1167 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
1168 sz = sizeof(DEVMODEA);
1170 /* ensures that dmSize is not erratically bogus if registry is invalid */
1171 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1172 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1173 if(unicode) {
1174 sz += (CCHDEVICENAME + CCHFORMNAME);
1175 if(buflen >= sz) {
1176 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1177 memcpy(ptr, dmW, sz);
1178 HeapFree(GetProcessHeap(),0,dmW);
1181 *needed = sz;
1182 return TRUE;
1185 /*********************************************************************
1186 * WINSPOOL_GetPrinter_2
1188 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1189 * The strings are either stored as unicode or ascii.
1191 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1192 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1193 BOOL unicode)
1195 DWORD size, left = cbBuf;
1196 BOOL space = (cbBuf > 0);
1197 LPBYTE ptr = buf;
1199 *pcbNeeded = 0;
1201 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1202 unicode)) {
1203 if(space && size <= left) {
1204 pi2->pPrinterName = (LPWSTR)ptr;
1205 ptr += size;
1206 left -= size;
1207 } else
1208 space = FALSE;
1209 *pcbNeeded += size;
1211 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1212 unicode)) {
1213 if(space && size <= left) {
1214 pi2->pShareName = (LPWSTR)ptr;
1215 ptr += size;
1216 left -= size;
1217 } else
1218 space = FALSE;
1219 *pcbNeeded += size;
1221 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1222 unicode)) {
1223 if(space && size <= left) {
1224 pi2->pPortName = (LPWSTR)ptr;
1225 ptr += size;
1226 left -= size;
1227 } else
1228 space = FALSE;
1229 *pcbNeeded += size;
1231 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1232 &size, unicode)) {
1233 if(space && size <= left) {
1234 pi2->pDriverName = (LPWSTR)ptr;
1235 ptr += size;
1236 left -= size;
1237 } else
1238 space = FALSE;
1239 *pcbNeeded += size;
1241 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1242 unicode)) {
1243 if(space && size <= left) {
1244 pi2->pComment = (LPWSTR)ptr;
1245 ptr += size;
1246 left -= size;
1247 } else
1248 space = FALSE;
1249 *pcbNeeded += size;
1251 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1252 unicode)) {
1253 if(space && size <= left) {
1254 pi2->pLocation = (LPWSTR)ptr;
1255 ptr += size;
1256 left -= size;
1257 } else
1258 space = FALSE;
1259 *pcbNeeded += size;
1261 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1262 &size, unicode)) {
1263 if(space && size <= left) {
1264 pi2->pDevMode = (LPDEVMODEW)ptr;
1265 ptr += size;
1266 left -= size;
1267 } else
1268 space = FALSE;
1269 *pcbNeeded += size;
1271 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1272 &size, unicode)) {
1273 if(space && size <= left) {
1274 pi2->pSepFile = (LPWSTR)ptr;
1275 ptr += size;
1276 left -= size;
1277 } else
1278 space = FALSE;
1279 *pcbNeeded += size;
1281 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1282 &size, unicode)) {
1283 if(space && size <= left) {
1284 pi2->pPrintProcessor = (LPWSTR)ptr;
1285 ptr += size;
1286 left -= size;
1287 } else
1288 space = FALSE;
1289 *pcbNeeded += size;
1291 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1292 &size, unicode)) {
1293 if(space && size <= left) {
1294 pi2->pDatatype = (LPWSTR)ptr;
1295 ptr += size;
1296 left -= size;
1297 } else
1298 space = FALSE;
1299 *pcbNeeded += size;
1301 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1302 &size, unicode)) {
1303 if(space && size <= left) {
1304 pi2->pParameters = (LPWSTR)ptr;
1305 ptr += size;
1306 left -= size;
1307 } else
1308 space = FALSE;
1309 *pcbNeeded += size;
1311 if(pi2) {
1312 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1313 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1314 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1315 "Default Priority");
1316 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1317 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1320 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1321 memset(pi2, 0, sizeof(*pi2));
1323 return space;
1326 /*********************************************************************
1327 * WINSPOOL_GetPrinter_4
1329 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1331 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1332 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1333 BOOL unicode)
1335 DWORD size, left = cbBuf;
1336 BOOL space = (cbBuf > 0);
1337 LPBYTE ptr = buf;
1339 *pcbNeeded = 0;
1341 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1342 unicode)) {
1343 if(space && size <= left) {
1344 pi4->pPrinterName = (LPWSTR)ptr;
1345 ptr += size;
1346 left -= size;
1347 } else
1348 space = FALSE;
1349 *pcbNeeded += size;
1351 if(pi4) {
1352 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1355 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1356 memset(pi4, 0, sizeof(*pi4));
1358 return space;
1361 /*********************************************************************
1362 * WINSPOOL_GetPrinter_5
1364 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1366 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1367 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1368 BOOL unicode)
1370 DWORD size, left = cbBuf;
1371 BOOL space = (cbBuf > 0);
1372 LPBYTE ptr = buf;
1374 *pcbNeeded = 0;
1376 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1377 unicode)) {
1378 if(space && size <= left) {
1379 pi5->pPrinterName = (LPWSTR)ptr;
1380 ptr += size;
1381 left -= size;
1382 } else
1383 space = FALSE;
1384 *pcbNeeded += size;
1386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1387 unicode)) {
1388 if(space && size <= left) {
1389 pi5->pPortName = (LPWSTR)ptr;
1390 ptr += size;
1391 left -= size;
1392 } else
1393 space = FALSE;
1394 *pcbNeeded += size;
1396 if(pi5) {
1397 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1398 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1399 "dnsTimeout");
1400 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1401 "txTimeout");
1404 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1405 memset(pi5, 0, sizeof(*pi5));
1407 return space;
1410 /*****************************************************************************
1411 * WINSPOOL_GetPrinter
1413 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1414 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1415 * just a collection of pointers to strings.
1417 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1418 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1420 LPCWSTR name;
1421 DWORD size, needed = 0;
1422 LPBYTE ptr = NULL;
1423 HKEY hkeyPrinter, hkeyPrinters;
1424 BOOL ret;
1426 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1428 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1430 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1431 ERROR_SUCCESS) {
1432 ERR("Can't create Printers key\n");
1433 return FALSE;
1435 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1437 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1438 RegCloseKey(hkeyPrinters);
1439 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1440 return FALSE;
1443 switch(Level) {
1444 case 2:
1446 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1448 size = sizeof(PRINTER_INFO_2W);
1449 if(size <= cbBuf) {
1450 ptr = pPrinter + size;
1451 cbBuf -= size;
1452 memset(pPrinter, 0, size);
1453 } else {
1454 pi2 = NULL;
1455 cbBuf = 0;
1457 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1458 unicode);
1459 needed += size;
1460 break;
1463 case 4:
1465 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1467 size = sizeof(PRINTER_INFO_4W);
1468 if(size <= cbBuf) {
1469 ptr = pPrinter + size;
1470 cbBuf -= size;
1471 memset(pPrinter, 0, size);
1472 } else {
1473 pi4 = NULL;
1474 cbBuf = 0;
1476 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1477 unicode);
1478 needed += size;
1479 break;
1483 case 5:
1485 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1487 size = sizeof(PRINTER_INFO_5W);
1488 if(size <= cbBuf) {
1489 ptr = pPrinter + size;
1490 cbBuf -= size;
1491 memset(pPrinter, 0, size);
1492 } else {
1493 pi5 = NULL;
1494 cbBuf = 0;
1497 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1498 unicode);
1499 needed += size;
1500 break;
1503 default:
1504 FIXME("Unimplemented level %ld\n", Level);
1505 SetLastError(ERROR_INVALID_LEVEL);
1506 RegCloseKey(hkeyPrinters);
1507 RegCloseKey(hkeyPrinter);
1508 return FALSE;
1511 RegCloseKey(hkeyPrinter);
1512 RegCloseKey(hkeyPrinters);
1514 TRACE("returing %d needed = %ld\n", ret, needed);
1515 if(pcbNeeded) *pcbNeeded = needed;
1516 if(!ret)
1517 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1518 return ret;
1521 /*****************************************************************************
1522 * GetPrinterW [WINSPOOL.194]
1524 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1525 DWORD cbBuf, LPDWORD pcbNeeded)
1527 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1528 TRUE);
1531 /*****************************************************************************
1532 * GetPrinterA [WINSPOOL.187]
1534 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1535 DWORD cbBuf, LPDWORD pcbNeeded)
1537 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1538 FALSE);
1541 /*****************************************************************************
1542 * WINSPOOL_EnumPrinters
1544 * Implementation of EnumPrintersA|W
1546 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1547 DWORD dwLevel, LPBYTE lpbPrinters,
1548 DWORD cbBuf, LPDWORD lpdwNeeded,
1549 LPDWORD lpdwReturned, BOOL unicode)
1552 HKEY hkeyPrinters, hkeyPrinter;
1553 WCHAR PrinterName[255];
1554 DWORD needed = 0, number = 0;
1555 DWORD used, i, left;
1556 PBYTE pi, buf;
1558 if(lpbPrinters)
1559 memset(lpbPrinters, 0, cbBuf);
1560 if(lpdwReturned)
1561 *lpdwReturned = 0;
1562 if(lpdwNeeded)
1563 *lpdwNeeded = 0;
1565 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1566 if(dwType == PRINTER_ENUM_DEFAULT)
1567 return TRUE;
1569 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1570 FIXME("dwType = %08lx\n", dwType);
1571 SetLastError(ERROR_INVALID_FLAGS);
1572 return FALSE;
1575 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1576 ERROR_SUCCESS) {
1577 ERR("Can't create Printers key\n");
1578 return FALSE;
1581 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1582 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1583 RegCloseKey(hkeyPrinters);
1584 ERR("Can't query Printers key\n");
1585 return FALSE;
1587 TRACE("Found %ld printers\n", number);
1589 switch(dwLevel) {
1590 case 1:
1591 RegCloseKey(hkeyPrinters);
1592 if (lpdwReturned)
1593 *lpdwReturned = number;
1594 return TRUE;
1596 case 2:
1597 used = number * sizeof(PRINTER_INFO_2W);
1598 break;
1599 case 4:
1600 used = number * sizeof(PRINTER_INFO_4W);
1601 break;
1602 case 5:
1603 used = number * sizeof(PRINTER_INFO_5W);
1604 break;
1606 default:
1607 SetLastError(ERROR_INVALID_LEVEL);
1608 RegCloseKey(hkeyPrinters);
1609 return FALSE;
1611 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1613 for(i = 0; i < number; i++) {
1614 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1615 ERROR_SUCCESS) {
1616 ERR("Can't enum key number %ld\n", i);
1617 RegCloseKey(hkeyPrinters);
1618 return FALSE;
1620 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1621 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1622 ERROR_SUCCESS) {
1623 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1624 RegCloseKey(hkeyPrinters);
1625 return FALSE;
1628 if(cbBuf > used) {
1629 buf = lpbPrinters + used;
1630 left = cbBuf - used;
1631 } else {
1632 buf = NULL;
1633 left = 0;
1636 switch(dwLevel) {
1637 case 2:
1638 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1639 left, &needed, unicode);
1640 used += needed;
1641 if(pi) pi += sizeof(PRINTER_INFO_2W);
1642 break;
1643 case 4:
1644 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1645 left, &needed, unicode);
1646 used += needed;
1647 if(pi) pi += sizeof(PRINTER_INFO_4W);
1648 break;
1649 case 5:
1650 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1651 left, &needed, unicode);
1652 used += needed;
1653 if(pi) pi += sizeof(PRINTER_INFO_5W);
1654 break;
1655 default:
1656 ERR("Shouldn't be here!\n");
1657 RegCloseKey(hkeyPrinter);
1658 RegCloseKey(hkeyPrinters);
1659 return FALSE;
1661 RegCloseKey(hkeyPrinter);
1663 RegCloseKey(hkeyPrinters);
1665 if(lpdwNeeded)
1666 *lpdwNeeded = used;
1668 if(used > cbBuf) {
1669 if(lpbPrinters)
1670 memset(lpbPrinters, 0, cbBuf);
1671 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1672 return FALSE;
1674 if(lpdwReturned)
1675 *lpdwReturned = number;
1676 SetLastError(ERROR_SUCCESS);
1677 return TRUE;
1681 /******************************************************************
1682 * EnumPrintersW [WINSPOOL.175]
1684 * Enumerates the available printers, print servers and print
1685 * providers, depending on the specified flags, name and level.
1687 * RETURNS:
1689 * If level is set to 1:
1690 * Not implemented yet!
1691 * Returns TRUE with an empty list.
1693 * If level is set to 2:
1694 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1695 * Returns an array of PRINTER_INFO_2 data structures in the
1696 * lpbPrinters buffer. Note that according to MSDN also an
1697 * OpenPrinter should be performed on every remote printer.
1699 * If level is set to 4 (officially WinNT only):
1700 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1701 * Fast: Only the registry is queried to retrieve printer names,
1702 * no connection to the driver is made.
1703 * Returns an array of PRINTER_INFO_4 data structures in the
1704 * lpbPrinters buffer.
1706 * If level is set to 5 (officially WinNT4/Win9x only):
1707 * Fast: Only the registry is queried to retrieve printer names,
1708 * no connection to the driver is made.
1709 * Returns an array of PRINTER_INFO_5 data structures in the
1710 * lpbPrinters buffer.
1712 * If level set to 3 or 6+:
1713 * returns zero (failure!)
1715 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
1716 * for information.
1718 * BUGS:
1719 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1720 * - Only levels 2, 4 and 5 are implemented at the moment.
1721 * - 16-bit printer drivers are not enumerated.
1722 * - Returned amount of bytes used/needed does not match the real Windoze
1723 * implementation (as in this implementation, all strings are part
1724 * of the buffer, whereas Win32 keeps them somewhere else)
1725 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1727 * NOTE:
1728 * - In a regular Wine installation, no registry settings for printers
1729 * exist, which makes this function return an empty list.
1731 BOOL WINAPI EnumPrintersW(
1732 DWORD dwType, /* [in] Types of print objects to enumerate */
1733 LPWSTR lpszName, /* [in] name of objects to enumerate */
1734 DWORD dwLevel, /* [in] type of printer info structure */
1735 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1736 DWORD cbBuf, /* [in] max size of buffer in bytes */
1737 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1738 LPDWORD lpdwReturned /* [out] number of entries returned */
1741 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1742 lpdwNeeded, lpdwReturned, TRUE);
1745 /******************************************************************
1746 * EnumPrintersA [WINSPOOL.174]
1749 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1750 DWORD dwLevel, LPBYTE lpbPrinters,
1751 DWORD cbBuf, LPDWORD lpdwNeeded,
1752 LPDWORD lpdwReturned)
1754 BOOL ret;
1755 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1757 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1758 lpdwNeeded, lpdwReturned, FALSE);
1759 HeapFree(GetProcessHeap(),0,lpszNameW);
1760 return ret;
1763 /*****************************************************************************
1764 * WINSPOOL_GetDriverInfoFromReg [internal]
1766 * Enters the information from the registry into the DRIVER_INFO struct
1768 * RETURNS
1769 * zero if the printer driver does not exist in the registry
1770 * (only if Level > 1) otherwise nonzero
1772 static BOOL WINSPOOL_GetDriverInfoFromReg(
1773 HKEY hkeyDrivers,
1774 LPWSTR DriverName,
1775 LPWSTR pEnvironment,
1776 DWORD Level,
1777 LPBYTE ptr, /* DRIVER_INFO */
1778 LPBYTE pDriverStrings, /* strings buffer */
1779 DWORD cbBuf, /* size of string buffer */
1780 LPDWORD pcbNeeded, /* space needed for str. */
1781 BOOL unicode) /* type of strings */
1782 { DWORD dw, size, tmp, type;
1783 HKEY hkeyDriver;
1784 LPBYTE strPtr = pDriverStrings;
1786 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1787 debugstr_w(DriverName), debugstr_w(pEnvironment),
1788 Level, ptr, pDriverStrings, cbBuf, unicode);
1790 if(unicode) {
1791 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1792 if (*pcbNeeded <= cbBuf)
1793 strcpyW((LPWSTR)strPtr, DriverName);
1794 } else {
1795 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1796 NULL, NULL);
1797 if(*pcbNeeded <= cbBuf)
1798 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1799 NULL, NULL);
1801 if(Level == 1) {
1802 if(ptr)
1803 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1804 return TRUE;
1805 } else {
1806 if(ptr)
1807 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1808 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1811 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1812 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1813 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1814 return FALSE;
1817 size = sizeof(dw);
1818 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1819 ERROR_SUCCESS)
1820 WARN("Can't get Version\n");
1821 else if(ptr)
1822 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1824 if(!pEnvironment)
1825 pEnvironment = DefaultEnvironmentW;
1826 if(unicode)
1827 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1828 else
1829 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1830 NULL, NULL);
1831 *pcbNeeded += size;
1832 if(*pcbNeeded <= cbBuf) {
1833 if(unicode)
1834 strcpyW((LPWSTR)strPtr, pEnvironment);
1835 else
1836 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
1837 NULL, NULL);
1838 if(ptr)
1839 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1840 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1843 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1844 unicode)) {
1845 *pcbNeeded += size;
1846 if(*pcbNeeded <= cbBuf)
1847 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1848 unicode);
1849 if(ptr)
1850 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1851 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1854 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1855 unicode)) {
1856 *pcbNeeded += size;
1857 if(*pcbNeeded <= cbBuf)
1858 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1859 &tmp, unicode);
1860 if(ptr)
1861 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1862 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1865 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1866 0, &size, unicode)) {
1867 *pcbNeeded += size;
1868 if(*pcbNeeded <= cbBuf)
1869 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1870 size, &tmp, unicode);
1871 if(ptr)
1872 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1873 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1876 if(Level == 2 ) {
1877 RegCloseKey(hkeyDriver);
1878 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1879 return TRUE;
1882 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1883 unicode)) {
1884 *pcbNeeded += size;
1885 if(*pcbNeeded <= cbBuf)
1886 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1887 size, &tmp, unicode);
1888 if(ptr)
1889 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1890 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1893 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1894 &size, unicode)) {
1895 *pcbNeeded += size;
1896 if(*pcbNeeded <= cbBuf)
1897 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1898 size, &tmp, unicode);
1899 if(ptr)
1900 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1901 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1904 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1905 unicode)) {
1906 *pcbNeeded += size;
1907 if(*pcbNeeded <= cbBuf)
1908 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1909 size, &tmp, unicode);
1910 if(ptr)
1911 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1912 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1915 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1916 unicode)) {
1917 *pcbNeeded += size;
1918 if(*pcbNeeded <= cbBuf)
1919 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1920 size, &tmp, unicode);
1921 if(ptr)
1922 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1923 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1926 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1927 RegCloseKey(hkeyDriver);
1928 return TRUE;
1931 /*****************************************************************************
1932 * WINSPOOL_GetPrinterDriver
1934 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1935 DWORD Level, LPBYTE pDriverInfo,
1936 DWORD cbBuf, LPDWORD pcbNeeded,
1937 BOOL unicode)
1939 LPCWSTR name;
1940 WCHAR DriverName[100];
1941 DWORD ret, type, size, needed = 0;
1942 LPBYTE ptr = NULL;
1943 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1945 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1946 Level,pDriverInfo,cbBuf, pcbNeeded);
1948 ZeroMemory(pDriverInfo, cbBuf);
1950 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) 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, name, &hkeyPrinter)
1962 != ERROR_SUCCESS) {
1963 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1964 RegCloseKey(hkeyPrinters);
1965 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1966 return FALSE;
1968 size = sizeof(DriverName);
1969 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1970 (LPBYTE)DriverName, &size);
1971 RegCloseKey(hkeyPrinter);
1972 RegCloseKey(hkeyPrinters);
1973 if(ret != ERROR_SUCCESS) {
1974 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
1975 return FALSE;
1978 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1979 if(!hkeyDrivers) {
1980 ERR("Can't create Drivers key\n");
1981 return FALSE;
1984 switch(Level) {
1985 case 1:
1986 size = sizeof(DRIVER_INFO_1W);
1987 break;
1988 case 2:
1989 size = sizeof(DRIVER_INFO_2W);
1990 break;
1991 case 3:
1992 size = sizeof(DRIVER_INFO_3W);
1993 break;
1994 default:
1995 ERR("Invalid level\n");
1996 return FALSE;
1999 if(size <= cbBuf)
2000 ptr = pDriverInfo + size;
2002 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
2003 pEnvironment, Level, pDriverInfo,
2004 (cbBuf < size) ? NULL : ptr,
2005 (cbBuf < size) ? 0 : cbBuf - size,
2006 &needed, unicode)) {
2007 RegCloseKey(hkeyDrivers);
2008 return FALSE;
2011 RegCloseKey(hkeyDrivers);
2013 if(pcbNeeded) *pcbNeeded = size + needed;
2014 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
2015 if(cbBuf >= needed) return TRUE;
2016 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2017 return FALSE;
2020 /*****************************************************************************
2021 * GetPrinterDriverA [WINSPOOL.190]
2023 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
2024 DWORD Level, LPBYTE pDriverInfo,
2025 DWORD cbBuf, LPDWORD pcbNeeded)
2027 BOOL ret;
2028 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2029 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2030 cbBuf, pcbNeeded, FALSE);
2031 HeapFree(GetProcessHeap(),0,pEnvW);
2032 return ret;
2034 /*****************************************************************************
2035 * GetPrinterDriverW [WINSPOOL.193]
2037 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2038 DWORD Level, LPBYTE pDriverInfo,
2039 DWORD cbBuf, LPDWORD pcbNeeded)
2041 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2042 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2045 /*****************************************************************************
2046 * GetPrinterDriverDirectoryA [WINSPOOL.191]
2048 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2049 DWORD Level, LPBYTE pDriverDirectory,
2050 DWORD cbBuf, LPDWORD pcbNeeded)
2052 DWORD needed;
2054 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2055 pDriverDirectory, cbBuf, pcbNeeded);
2056 if(pName != NULL) {
2057 FIXME("pName = `%s' - unsupported\n", pName);
2058 SetLastError(ERROR_INVALID_PARAMETER);
2059 return FALSE;
2061 if(pEnvironment != NULL) {
2062 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2063 SetLastError(ERROR_INVALID_ENVIRONMENT);
2064 return FALSE;
2066 if(Level != 1) /* win95 ignores this so we just carry on */
2067 WARN("Level = %ld - assuming 1\n", Level);
2069 /* FIXME should read from registry */
2070 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2071 needed++;
2072 if(pcbNeeded)
2073 *pcbNeeded = needed;
2074 if(needed > cbBuf) {
2075 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2076 return FALSE;
2078 return TRUE;
2082 /*****************************************************************************
2083 * GetPrinterDriverDirectoryW [WINSPOOL.192]
2085 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2086 DWORD Level, LPBYTE pDriverDirectory,
2087 DWORD cbBuf, LPDWORD pcbNeeded)
2089 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2090 BOOL ret;
2092 if(pName)
2093 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2094 if(pEnvironment)
2095 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2096 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2097 pDriverDirectory, cbBuf, pcbNeeded );
2098 if(pNameA)
2099 HeapFree( GetProcessHeap(), 0, pNameA );
2100 if(pEnvironmentA)
2101 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2103 return ret;
2106 /*****************************************************************************
2107 * AddPrinterDriverA [WINSPOOL.120]
2109 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2111 DRIVER_INFO_3A di3;
2112 HKEY hkeyDrivers, hkeyName;
2114 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2116 if(level != 2 && level != 3) {
2117 SetLastError(ERROR_INVALID_LEVEL);
2118 return FALSE;
2120 if(pName != NULL) {
2121 FIXME("pName= `%s' - unsupported\n", pName);
2122 SetLastError(ERROR_INVALID_PARAMETER);
2123 return FALSE;
2125 if(!pDriverInfo) {
2126 WARN("pDriverInfo == NULL");
2127 SetLastError(ERROR_INVALID_PARAMETER);
2128 return FALSE;
2131 if(level == 3)
2132 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2133 else {
2134 memset(&di3, 0, sizeof(di3));
2135 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2138 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2139 !di3.pDataFile) {
2140 SetLastError(ERROR_INVALID_PARAMETER);
2141 return FALSE;
2143 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2144 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2145 if(!di3.pHelpFile) di3.pHelpFile = "";
2146 if(!di3.pMonitorName) di3.pMonitorName = "";
2148 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2150 if(!hkeyDrivers) {
2151 ERR("Can't create Drivers key\n");
2152 return FALSE;
2155 if(level == 2) { /* apparently can't overwrite with level2 */
2156 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2157 RegCloseKey(hkeyName);
2158 RegCloseKey(hkeyDrivers);
2159 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2160 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2161 return FALSE;
2164 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2165 RegCloseKey(hkeyDrivers);
2166 ERR("Can't create Name key\n");
2167 return FALSE;
2169 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2171 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2172 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2173 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2174 sizeof(DWORD));
2175 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2176 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2177 di3.pDependentFiles, 0);
2178 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2179 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2180 RegCloseKey(hkeyName);
2181 RegCloseKey(hkeyDrivers);
2183 return TRUE;
2185 /*****************************************************************************
2186 * AddPrinterDriverW [WINSPOOL.121]
2188 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2189 LPBYTE pDriverInfo)
2191 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2192 level,pDriverInfo);
2193 return FALSE;
2197 /*****************************************************************************
2198 * PrinterProperties [WINSPOOL.201]
2200 * Displays a dialog to set the properties of the printer.
2202 * RETURNS
2203 * nonzero on success or zero on failure
2205 * BUGS
2206 * implemented as stub only
2208 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2209 HANDLE hPrinter /* [in] handle to printer object */
2211 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2212 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2213 return FALSE;
2216 /*****************************************************************************
2217 * EnumJobsA [WINSPOOL.162]
2220 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2221 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2222 LPDWORD pcReturned)
2224 FIXME("stub\n");
2225 if(pcbNeeded) *pcbNeeded = 0;
2226 if(pcReturned) *pcReturned = 0;
2227 return TRUE;
2231 /*****************************************************************************
2232 * EnumJobsW [WINSPOOL.163]
2235 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2236 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2237 LPDWORD pcReturned)
2239 FIXME("stub\n");
2240 if(pcbNeeded) *pcbNeeded = 0;
2241 if(pcReturned) *pcReturned = 0;
2242 return TRUE;
2245 /*****************************************************************************
2246 * WINSPOOL_EnumPrinterDrivers [internal]
2248 * Delivers information about all printer drivers installed on the
2249 * localhost or a given server
2251 * RETURNS
2252 * nonzero on success or zero on failure. If the buffer for the returned
2253 * information is too small the function will return an error
2255 * BUGS
2256 * - only implemented for localhost, foreign hosts will return an error
2258 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2259 DWORD Level, LPBYTE pDriverInfo,
2260 DWORD cbBuf, LPDWORD pcbNeeded,
2261 LPDWORD pcReturned, BOOL unicode)
2263 { HKEY hkeyDrivers;
2264 DWORD i, needed, number = 0, size = 0;
2265 WCHAR DriverNameW[255];
2266 PBYTE ptr;
2268 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2269 debugstr_w(pName), debugstr_w(pEnvironment),
2270 Level, pDriverInfo, cbBuf, unicode);
2272 /* check for local drivers */
2273 if(pName) {
2274 ERR("remote drivers unsupported! Current remote host is %s\n",
2275 debugstr_w(pName));
2276 return FALSE;
2279 /* check input parameter */
2280 if((Level < 1) || (Level > 3)) {
2281 ERR("unsupported level %ld \n", Level);
2282 return FALSE;
2285 /* initialize return values */
2286 if(pDriverInfo)
2287 memset( pDriverInfo, 0, cbBuf);
2288 *pcbNeeded = 0;
2289 *pcReturned = 0;
2291 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2292 if(!hkeyDrivers) {
2293 ERR("Can't open Drivers key\n");
2294 return FALSE;
2297 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2298 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2299 RegCloseKey(hkeyDrivers);
2300 ERR("Can't query Drivers key\n");
2301 return FALSE;
2303 TRACE("Found %ld Drivers\n", number);
2305 /* get size of single struct
2306 * unicode and ascii structure have the same size
2308 switch (Level) {
2309 case 1:
2310 size = sizeof(DRIVER_INFO_1A);
2311 break;
2312 case 2:
2313 size = sizeof(DRIVER_INFO_2A);
2314 break;
2315 case 3:
2316 size = sizeof(DRIVER_INFO_3A);
2317 break;
2320 /* calculate required buffer size */
2321 *pcbNeeded = size * number;
2323 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2324 i < number;
2325 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2326 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2327 != ERROR_SUCCESS) {
2328 ERR("Can't enum key number %ld\n", i);
2329 RegCloseKey(hkeyDrivers);
2330 return FALSE;
2332 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2333 pEnvironment, Level, ptr,
2334 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2335 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2336 &needed, unicode)) {
2337 RegCloseKey(hkeyDrivers);
2338 return FALSE;
2340 (*pcbNeeded) += needed;
2343 RegCloseKey(hkeyDrivers);
2345 if(cbBuf < *pcbNeeded){
2346 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2347 return FALSE;
2350 return TRUE;
2353 /*****************************************************************************
2354 * EnumPrinterDriversW [WINSPOOL.173]
2356 * see function EnumPrinterDrivers for RETURNS, BUGS
2358 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2359 LPBYTE pDriverInfo, DWORD cbBuf,
2360 LPDWORD pcbNeeded, LPDWORD pcReturned)
2362 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2363 cbBuf, pcbNeeded, pcReturned, TRUE);
2366 /*****************************************************************************
2367 * EnumPrinterDriversA [WINSPOOL.172]
2369 * see function EnumPrinterDrivers for RETURNS, BUGS
2371 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2372 LPBYTE pDriverInfo, DWORD cbBuf,
2373 LPDWORD pcbNeeded, LPDWORD pcReturned)
2374 { BOOL ret;
2375 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2377 if(pName)
2378 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2379 if(pEnvironment)
2380 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2382 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2383 cbBuf, pcbNeeded, pcReturned, FALSE);
2384 if(pNameW)
2385 HeapFree(GetProcessHeap(), 0, pNameW);
2386 if(pEnvironmentW)
2387 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2389 return ret;
2393 /******************************************************************************
2394 * EnumPortsA (WINSPOOL.166)
2396 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2397 LPDWORD bufneeded,LPDWORD bufreturned)
2399 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2400 return FALSE;
2403 /******************************************************************************
2404 * SetPrinterDataExA (WINSPOOL)
2406 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2407 LPSTR pValueName, DWORD Type,
2408 LPBYTE pData, DWORD cbData)
2410 HKEY hkeyPrinter, hkeySubkey;
2411 DWORD ret;
2413 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
2414 debugstr_a(pValueName), Type, pData, cbData);
2416 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2417 != ERROR_SUCCESS)
2418 return ret;
2420 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2421 != ERROR_SUCCESS) {
2422 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
2423 RegCloseKey(hkeyPrinter);
2424 return ret;
2426 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
2427 RegCloseKey(hkeySubkey);
2428 RegCloseKey(hkeyPrinter);
2429 return ret;
2432 /******************************************************************************
2433 * SetPrinterDataExW (WINSPOOL)
2435 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2436 LPWSTR pValueName, DWORD Type,
2437 LPBYTE pData, DWORD cbData)
2439 HKEY hkeyPrinter, hkeySubkey;
2440 DWORD ret;
2442 TRACE("(%08x, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
2443 debugstr_w(pValueName), Type, pData, cbData);
2445 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2446 != ERROR_SUCCESS)
2447 return ret;
2449 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2450 != ERROR_SUCCESS) {
2451 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
2452 RegCloseKey(hkeyPrinter);
2453 return ret;
2455 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
2456 RegCloseKey(hkeySubkey);
2457 RegCloseKey(hkeyPrinter);
2458 return ret;
2461 /******************************************************************************
2462 * SetPrinterDataA (WINSPOOL)
2464 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
2465 LPBYTE pData, DWORD cbData)
2467 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
2468 pData, cbData);
2471 /******************************************************************************
2472 * SetPrinterDataW (WINSPOOL)
2474 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
2475 LPBYTE pData, DWORD cbData)
2477 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
2478 pData, cbData);
2481 /******************************************************************************
2482 * GetPrinterDataExA (WINSPOOL)
2484 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPSTR pKeyName,
2485 LPSTR pValueName, LPDWORD pType,
2486 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2488 HKEY hkeyPrinter, hkeySubkey;
2489 DWORD ret;
2491 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2492 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
2493 pcbNeeded);
2495 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2496 != ERROR_SUCCESS)
2497 return ret;
2499 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
2500 != ERROR_SUCCESS) {
2501 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
2502 RegCloseKey(hkeyPrinter);
2503 return ret;
2505 *pcbNeeded = nSize;
2506 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2507 RegCloseKey(hkeySubkey);
2508 RegCloseKey(hkeyPrinter);
2509 return ret;
2512 /******************************************************************************
2513 * GetPrinterDataExW (WINSPOOL)
2515 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPWSTR pKeyName,
2516 LPWSTR pValueName, LPDWORD pType,
2517 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2519 HKEY hkeyPrinter, hkeySubkey;
2520 DWORD ret;
2522 TRACE("(%08x, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
2523 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
2524 pcbNeeded);
2526 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
2527 != ERROR_SUCCESS)
2528 return ret;
2530 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
2531 != ERROR_SUCCESS) {
2532 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
2533 RegCloseKey(hkeyPrinter);
2534 return ret;
2536 *pcbNeeded = nSize;
2537 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
2538 RegCloseKey(hkeySubkey);
2539 RegCloseKey(hkeyPrinter);
2540 return ret;
2543 /******************************************************************************
2544 * GetPrinterDataA (WINSPOOL)
2546 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
2547 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2549 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
2550 pData, nSize, pcbNeeded);
2553 /******************************************************************************
2554 * GetPrinterDataW (WINSPOOL)
2556 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
2557 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
2559 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
2560 pData, nSize, pcbNeeded);
2563 /*******************************************************************************
2564 * EnumPrinterDataExW [WINSPOOL.197]
2566 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
2567 LPBYTE pEnumValues, DWORD cbEnumValues,
2568 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2570 HKEY hkPrinter, hkSubKey;
2571 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
2572 cbValueNameLen, cbMaxValueLen, cbValueLen,
2573 cbBufSize, dwType;
2574 LPWSTR lpValueName;
2575 HANDLE hHeap;
2576 PBYTE lpValue;
2577 PPRINTER_ENUM_VALUESW ppev;
2579 TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
2581 if (pKeyName == NULL || *pKeyName == 0)
2582 return ERROR_INVALID_PARAMETER;
2584 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
2585 if (ret != ERROR_SUCCESS)
2587 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
2588 hPrinter, ret);
2589 return ret;
2592 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
2593 if (ret != ERROR_SUCCESS)
2595 r = RegCloseKey (hkPrinter);
2596 if (r != ERROR_SUCCESS)
2597 WARN ("RegCloseKey returned %li\n", r);
2598 TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
2599 debugstr_w (pKeyName), ret);
2600 return ret;
2603 ret = RegCloseKey (hkPrinter);
2604 if (ret != ERROR_SUCCESS)
2606 ERR ("RegCloseKey returned %li\n", ret);
2607 r = RegCloseKey (hkSubKey);
2608 if (r != ERROR_SUCCESS)
2609 WARN ("RegCloseKey returned %li\n", r);
2610 return ret;
2613 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
2614 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
2615 if (ret != ERROR_SUCCESS)
2617 r = RegCloseKey (hkSubKey);
2618 if (r != ERROR_SUCCESS)
2619 WARN ("RegCloseKey returned %li\n", r);
2620 TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
2621 return ret;
2624 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
2625 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
2627 if (cValues == 0) /* empty key */
2629 r = RegCloseKey (hkSubKey);
2630 if (r != ERROR_SUCCESS)
2631 WARN ("RegCloseKey returned %li\n", r);
2632 *pcbEnumValues = *pnEnumValues = 0;
2633 return ERROR_SUCCESS;
2636 ++cbMaxValueNameLen; /* allow for trailing '\0' */
2638 hHeap = GetProcessHeap ();
2639 if (hHeap == (HANDLE) NULL)
2641 ERR ("GetProcessHeap failed\n");
2642 r = RegCloseKey (hkSubKey);
2643 if (r != ERROR_SUCCESS)
2644 WARN ("RegCloseKey returned %li\n", r);
2645 return ERROR_OUTOFMEMORY;
2648 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
2649 if (lpValueName == NULL)
2651 ERR ("Failed to allocate %li bytes from process heap\n",
2652 cbMaxValueNameLen * sizeof (WCHAR));
2653 r = RegCloseKey (hkSubKey);
2654 if (r != ERROR_SUCCESS)
2655 WARN ("RegCloseKey returned %li\n", r);
2656 return ERROR_OUTOFMEMORY;
2659 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
2660 if (lpValue == NULL)
2662 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
2663 if (HeapFree (hHeap, 0, lpValueName) == 0)
2664 WARN ("HeapFree failed with code %li\n", GetLastError ());
2665 r = RegCloseKey (hkSubKey);
2666 if (r != ERROR_SUCCESS)
2667 WARN ("RegCloseKey returned %li\n", r);
2668 return ERROR_OUTOFMEMORY;
2671 TRACE ("pass 1: calculating buffer required for all names and values\n");
2673 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
2675 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
2677 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2679 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2680 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2681 NULL, NULL, lpValue, &cbValueLen);
2682 if (ret != ERROR_SUCCESS)
2684 if (HeapFree (hHeap, 0, lpValue) == 0)
2685 WARN ("HeapFree failed with code %li\n", GetLastError ());
2686 if (HeapFree (hHeap, 0, lpValueName) == 0)
2687 WARN ("HeapFree failed with code %li\n", GetLastError ());
2688 r = RegCloseKey (hkSubKey);
2689 if (r != ERROR_SUCCESS)
2690 WARN ("RegCloseKey returned %li\n", r);
2691 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2692 return ret;
2695 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
2696 debugstr_w (lpValueName), dwIndex,
2697 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
2699 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
2700 cbBufSize += cbValueLen;
2703 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
2705 *pcbEnumValues = cbBufSize;
2706 *pnEnumValues = cValues;
2708 if (cbEnumValues < cbBufSize) /* buffer too small */
2710 if (HeapFree (hHeap, 0, lpValue) == 0)
2711 WARN ("HeapFree failed with code %li\n", GetLastError ());
2712 if (HeapFree (hHeap, 0, lpValueName) == 0)
2713 WARN ("HeapFree failed with code %li\n", GetLastError ());
2714 r = RegCloseKey (hkSubKey);
2715 if (r != ERROR_SUCCESS)
2716 WARN ("RegCloseKey returned %li\n", r);
2717 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
2718 return ERROR_MORE_DATA;
2721 TRACE ("pass 2: copying all names and values to buffer\n");
2723 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
2724 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
2726 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
2728 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
2729 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
2730 NULL, &dwType, lpValue, &cbValueLen);
2731 if (ret != ERROR_SUCCESS)
2733 if (HeapFree (hHeap, 0, lpValue) == 0)
2734 WARN ("HeapFree failed with code %li\n", GetLastError ());
2735 if (HeapFree (hHeap, 0, lpValueName) == 0)
2736 WARN ("HeapFree failed with code %li\n", GetLastError ());
2737 r = RegCloseKey (hkSubKey);
2738 if (r != ERROR_SUCCESS)
2739 WARN ("RegCloseKey returned %li\n", r);
2740 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
2741 return ret;
2744 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
2745 memcpy (pEnumValues, lpValueName, cbValueNameLen);
2746 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
2747 pEnumValues += cbValueNameLen;
2749 /* return # of *bytes* (including trailing \0), not # of chars */
2750 ppev[dwIndex].cbValueName = cbValueNameLen;
2752 ppev[dwIndex].dwType = dwType;
2754 memcpy (pEnumValues, lpValue, cbValueLen);
2755 ppev[dwIndex].pData = pEnumValues;
2756 pEnumValues += cbValueLen;
2758 ppev[dwIndex].cbData = cbValueLen;
2760 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
2761 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
2764 if (HeapFree (hHeap, 0, lpValue) == 0)
2766 ret = GetLastError ();
2767 ERR ("HeapFree failed with code %li\n", ret);
2768 if (HeapFree (hHeap, 0, lpValueName) == 0)
2769 WARN ("HeapFree failed with code %li\n", GetLastError ());
2770 r = RegCloseKey (hkSubKey);
2771 if (r != ERROR_SUCCESS)
2772 WARN ("RegCloseKey returned %li\n", r);
2773 return ret;
2776 if (HeapFree (hHeap, 0, lpValueName) == 0)
2778 ret = GetLastError ();
2779 ERR ("HeapFree failed with code %li\n", ret);
2780 r = RegCloseKey (hkSubKey);
2781 if (r != ERROR_SUCCESS)
2782 WARN ("RegCloseKey returned %li\n", r);
2783 return ret;
2786 ret = RegCloseKey (hkSubKey);
2787 if (ret != ERROR_SUCCESS)
2789 ERR ("RegCloseKey returned %li\n", ret);
2790 return ret;
2793 return ERROR_SUCCESS;
2796 /*******************************************************************************
2797 * EnumPrinterDataExA [WINSPOOL.196]
2799 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
2800 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
2801 * what Windows 2000 SP1 does.
2804 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
2805 LPBYTE pEnumValues, DWORD cbEnumValues,
2806 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
2808 INT len;
2809 LPWSTR pKeyNameW;
2810 DWORD ret, dwIndex, dwBufSize;
2811 HANDLE hHeap;
2812 LPSTR pBuffer;
2814 TRACE ("%08x %s\n", hPrinter, pKeyName);
2816 if (pKeyName == NULL || *pKeyName == 0)
2817 return ERROR_INVALID_PARAMETER;
2819 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
2820 if (len == 0)
2822 ret = GetLastError ();
2823 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2824 return ret;
2827 hHeap = GetProcessHeap ();
2828 if (hHeap == (HANDLE) NULL)
2830 ERR ("GetProcessHeap failed\n");
2831 return ERROR_OUTOFMEMORY;
2834 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
2835 if (pKeyNameW == NULL)
2837 ERR ("Failed to allocate %li bytes from process heap\n",
2838 (LONG) len * sizeof (WCHAR));
2839 return ERROR_OUTOFMEMORY;
2842 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
2844 ret = GetLastError ();
2845 ERR ("MultiByteToWideChar failed with code %li\n", ret);
2846 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2847 WARN ("HeapFree failed with code %li\n", GetLastError ());
2848 return ret;
2851 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
2852 pcbEnumValues, pnEnumValues);
2853 if (ret != ERROR_SUCCESS)
2855 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2856 WARN ("HeapFree failed with code %li\n", GetLastError ());
2857 TRACE ("EnumPrinterDataExW returned %li\n", ret);
2858 return ret;
2861 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
2863 ret = GetLastError ();
2864 ERR ("HeapFree failed with code %li\n", ret);
2865 return ret;
2868 if (*pnEnumValues == 0) /* empty key */
2869 return ERROR_SUCCESS;
2871 dwBufSize = 0;
2872 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2874 PPRINTER_ENUM_VALUESW ppev =
2875 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2877 if (dwBufSize < ppev->cbValueName)
2878 dwBufSize = ppev->cbValueName;
2880 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
2881 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
2882 dwBufSize = ppev->cbData;
2885 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
2887 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
2888 if (pBuffer == NULL)
2890 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
2891 return ERROR_OUTOFMEMORY;
2894 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
2896 PPRINTER_ENUM_VALUESW ppev =
2897 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
2899 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
2900 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
2901 NULL);
2902 if (len == 0)
2904 ret = GetLastError ();
2905 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2906 if (HeapFree (hHeap, 0, pBuffer) == 0)
2907 WARN ("HeapFree failed with code %li\n", GetLastError ());
2908 return ret;
2911 memcpy (ppev->pValueName, pBuffer, len);
2913 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2915 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
2916 ppev->dwType != REG_MULTI_SZ)
2917 continue;
2919 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
2920 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
2921 if (len == 0)
2923 ret = GetLastError ();
2924 ERR ("WideCharToMultiByte failed with code %li\n", ret);
2925 if (HeapFree (hHeap, 0, pBuffer) == 0)
2926 WARN ("HeapFree failed with code %li\n", GetLastError ());
2927 return ret;
2930 memcpy (ppev->pData, pBuffer, len);
2932 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
2933 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
2936 if (HeapFree (hHeap, 0, pBuffer) == 0)
2938 ret = GetLastError ();
2939 ERR ("HeapFree failed with code %li\n", ret);
2940 return ret;
2943 return ERROR_SUCCESS;