Handle the EnumPrinters() flag PRINTER_ENUM_DEFAULT in the same way
[wine/hacks.git] / dlls / winspool / info.c
blob21b093661a2a60713ab2929fd9b8e2ed13667bcc
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 Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
77 'i','l','e',0};
78 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
79 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
81 /******************************************************************
82 * WINSPOOL_GetOpenedPrinterEntry
83 * Get the first place empty in the opened printer table
85 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinterEntry()
87 int i;
88 LPOPENEDPRINTER pOpenedPrinter;
91 * Create the opened printers' handle dynamic array.
93 if (!pOpenedPrinterDPA)
95 pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
96 for (i = 0; i < 10; i++)
98 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
99 HEAP_ZERO_MEMORY,
100 sizeof(OPENEDPRINTER));
101 pOpenedPrinter->hPrinter = -1;
102 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
107 * Search for a handle not yet allocated.
109 for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
111 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
113 if (pOpenedPrinter->hPrinter == -1)
115 pOpenedPrinter->hPrinter = i + 1;
116 return pOpenedPrinter;
121 * Didn't find one, insert new element in the array.
123 if (i == pOpenedPrinterDPA->nItemCount)
125 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
126 HEAP_ZERO_MEMORY,
127 sizeof(OPENEDPRINTER));
128 pOpenedPrinter->hPrinter = i + 1;
129 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
130 return pOpenedPrinter;
133 return NULL;
136 /******************************************************************
137 * WINSPOOL_GetOpenedPrinter
138 * Get the pointer to the opened printer referred by the handle
140 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinter(int printerHandle)
142 LPOPENEDPRINTER pOpenedPrinter;
144 if(!pOpenedPrinterDPA) return NULL;
145 if((printerHandle <=0) ||
146 (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
147 return NULL;
149 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
151 return pOpenedPrinter;
154 /***********************************************************
155 * DEVMODEcpyAtoW
157 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
159 BOOL Formname;
160 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
161 DWORD size;
163 Formname = (dmA->dmSize > off_formname);
164 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
165 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
166 CCHDEVICENAME);
167 if(!Formname) {
168 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
169 dmA->dmSize - CCHDEVICENAME);
170 } else {
171 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
172 off_formname - CCHDEVICENAME);
173 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
174 CCHFORMNAME);
175 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
176 (off_formname + CCHFORMNAME));
178 dmW->dmSize = size;
179 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
180 dmA->dmDriverExtra);
181 return dmW;
184 /***********************************************************
185 * DEVMODEdupAtoW
186 * Creates a unicode copy of supplied devmode on heap
188 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
190 LPDEVMODEW dmW;
191 DWORD size;
192 BOOL Formname;
193 ptrdiff_t off_formname;
195 TRACE("\n");
196 if(!dmA) return NULL;
198 off_formname = (char *)dmA->dmFormName - (char *)dmA;
199 Formname = (dmA->dmSize > off_formname);
200 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
201 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
202 return DEVMODEcpyAtoW(dmW, dmA);
205 /***********************************************************
206 * DEVMODEdupWtoA
207 * Creates an ascii copy of supplied devmode on heap
209 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
211 LPDEVMODEA dmA;
212 DWORD size;
213 BOOL Formname;
214 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
216 if(!dmW) return NULL;
217 Formname = (dmW->dmSize > off_formname);
218 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
219 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
220 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
221 CCHDEVICENAME, NULL, NULL);
222 if(!Formname) {
223 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
224 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
225 } else {
226 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
227 off_formname - CCHDEVICENAME * sizeof(WCHAR));
228 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
229 CCHFORMNAME, NULL, NULL);
230 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
231 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
233 dmA->dmSize = size;
234 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
235 dmW->dmDriverExtra);
236 return dmA;
239 /***********************************************************
240 * PRINTER_INFO_2AtoW
241 * Creates a unicode copy of PRINTER_INFO_2A on heap
243 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
245 LPPRINTER_INFO_2W piW;
246 if(!piA) return NULL;
247 piW = HeapAlloc(heap, 0, sizeof(*piW));
248 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
249 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
250 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
251 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
252 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
253 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
254 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
255 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
256 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
257 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
258 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
259 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
260 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
261 return piW;
264 /***********************************************************
265 * FREE_PRINTER_INFO_2W
266 * Free PRINTER_INFO_2W and all strings
268 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
270 if(!piW) return;
272 HeapFree(heap,0,piW->pServerName);
273 HeapFree(heap,0,piW->pPrinterName);
274 HeapFree(heap,0,piW->pShareName);
275 HeapFree(heap,0,piW->pPortName);
276 HeapFree(heap,0,piW->pDriverName);
277 HeapFree(heap,0,piW->pComment);
278 HeapFree(heap,0,piW->pLocation);
279 HeapFree(heap,0,piW->pDevMode);
280 HeapFree(heap,0,piW->pSepFile);
281 HeapFree(heap,0,piW->pPrintProcessor);
282 HeapFree(heap,0,piW->pDatatype);
283 HeapFree(heap,0,piW->pParameters);
284 HeapFree(heap,0,piW);
285 return;
288 /******************************************************************
289 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
292 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
293 LPSTR pOutput, LPDEVMODEA lpdm)
295 INT ret;
297 if (!GDI_CallDeviceCapabilities16)
299 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
300 (LPCSTR)104 );
301 if (!GDI_CallDeviceCapabilities16) return -1;
303 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
305 /* If DC_PAPERSIZE map POINT16s to POINTs */
306 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
307 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
308 POINT *pt = (POINT *)pOutput;
309 INT i;
310 memcpy(tmp, pOutput, ret * sizeof(POINT16));
311 for(i = 0; i < ret; i++, pt++)
313 pt->x = tmp[i].x;
314 pt->y = tmp[i].y;
316 HeapFree( GetProcessHeap(), 0, tmp );
318 return ret;
322 /*****************************************************************************
323 * DeviceCapabilitiesW [WINSPOOL.152]
325 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
328 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
329 WORD fwCapability, LPWSTR pOutput,
330 const DEVMODEW *pDevMode)
332 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
333 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
334 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
335 INT ret;
337 if(pOutput && (fwCapability == DC_BINNAMES ||
338 fwCapability == DC_FILEDEPENDENCIES ||
339 fwCapability == DC_PAPERNAMES)) {
340 /* These need A -> W translation */
341 INT size = 0, i;
342 LPSTR pOutputA;
343 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
344 dmA);
345 if(ret == -1)
346 return ret;
347 switch(fwCapability) {
348 case DC_BINNAMES:
349 size = 24;
350 break;
351 case DC_PAPERNAMES:
352 case DC_FILEDEPENDENCIES:
353 size = 64;
354 break;
356 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
357 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
358 dmA);
359 for(i = 0; i < ret; i++)
360 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
361 pOutput + (i * size), size);
362 HeapFree(GetProcessHeap(), 0, pOutputA);
363 } else {
364 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
365 (LPSTR)pOutput, dmA);
367 HeapFree(GetProcessHeap(),0,pPortA);
368 HeapFree(GetProcessHeap(),0,pDeviceA);
369 HeapFree(GetProcessHeap(),0,dmA);
370 return ret;
373 /******************************************************************
374 * DocumentPropertiesA [WINSPOOL.155]
377 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
378 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
379 LPDEVMODEA pDevModeInput,DWORD fMode )
381 LPOPENEDPRINTER lpOpenedPrinter;
382 LPSTR lpName = pDeviceName;
383 LONG ret;
385 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
386 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
389 if(!pDeviceName) {
390 LPWSTR lpNameW;
391 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
392 if(!lpOpenedPrinter) {
393 SetLastError(ERROR_INVALID_HANDLE);
394 return -1;
396 lpNameW = lpOpenedPrinter->lpsPrinterName;
397 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
400 if (!GDI_CallExtDeviceMode16)
402 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
403 (LPCSTR)102 );
404 if (!GDI_CallExtDeviceMode16) return -1;
406 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
407 pDevModeInput, NULL, fMode);
409 if(!pDeviceName)
410 HeapFree(GetProcessHeap(),0,lpName);
411 return ret;
415 /*****************************************************************************
416 * DocumentPropertiesW
418 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
419 LPWSTR pDeviceName,
420 LPDEVMODEW pDevModeOutput,
421 LPDEVMODEW pDevModeInput, DWORD fMode)
424 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
425 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
426 LPDEVMODEA pDevModeOutputA = NULL;
427 LONG ret;
429 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
430 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
431 fMode);
432 if(pDevModeOutput) {
433 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
434 if(ret < 0) return ret;
435 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
437 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
438 pDevModeInputA, fMode);
439 if(pDevModeOutput) {
440 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
441 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
443 if(fMode == 0 && ret > 0)
444 ret += (CCHDEVICENAME + CCHFORMNAME);
445 HeapFree(GetProcessHeap(),0,pDevModeInputA);
446 HeapFree(GetProcessHeap(),0,pDeviceNameA);
447 return ret;
450 /******************************************************************
451 * OpenPrinterA [WINSPOOL.196]
454 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
455 LPPRINTER_DEFAULTSA pDefault)
457 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
458 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
459 BOOL ret;
461 if(pDefault) {
462 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
463 pDefault->pDatatype);
464 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
465 pDefault->pDevMode);
466 DefaultW.DesiredAccess = pDefault->DesiredAccess;
467 pDefaultW = &DefaultW;
469 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
470 if(pDefault) {
471 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
472 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
474 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
475 return ret;
478 /******************************************************************
479 * OpenPrinterW [WINSPOOL.197]
482 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
483 LPPRINTER_DEFAULTSW pDefault)
485 LPOPENEDPRINTER lpOpenedPrinter;
486 HKEY hkeyPrinters, hkeyPrinter;
488 if (!lpPrinterName) {
489 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
490 SetLastError(ERROR_INVALID_PARAMETER);
491 return FALSE;
494 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
495 pDefault);
497 /* Check Printer exists */
498 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
499 ERROR_SUCCESS) {
500 ERR("Can't create Printers key\n");
501 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
502 return FALSE;
505 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
506 != ERROR_SUCCESS) {
507 WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
508 RegCloseKey(hkeyPrinters);
509 SetLastError(ERROR_INVALID_PARAMETER);
510 return FALSE;
512 RegCloseKey(hkeyPrinter);
513 RegCloseKey(hkeyPrinters);
515 if(!phPrinter) /* This seems to be what win95 does anyway */
516 return TRUE;
518 /* Get a place in the opened printer buffer*/
519 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntry();
520 if(!lpOpenedPrinter) {
521 ERR("Can't allocate printer slot\n");
522 SetLastError(ERROR_OUTOFMEMORY);
523 return FALSE;
526 /* Get the name of the printer */
527 lpOpenedPrinter->lpsPrinterName = HeapAlloc( GetProcessHeap(), 0,
528 (strlenW(lpPrinterName)+1)*sizeof(WCHAR) );
529 strcpyW( lpOpenedPrinter->lpsPrinterName, lpPrinterName );
531 /* Get the unique handle of the printer*/
532 *phPrinter = lpOpenedPrinter->hPrinter;
534 if (pDefault != NULL)
535 FIXME("Not handling pDefault\n");
537 return TRUE;
540 /******************************************************************
541 * AddMonitorA [WINSPOOL.107]
544 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
546 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
547 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
548 return FALSE;
551 /******************************************************************
552 * DeletePrinterDriverA [WINSPOOL.146]
555 BOOL WINAPI
556 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
558 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
559 debugstr_a(pDriverName));
560 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
561 return FALSE;
565 /******************************************************************
566 * DeleteMonitorA [WINSPOOL.135]
569 BOOL WINAPI
570 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
572 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
573 debugstr_a(pMonitorName));
574 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
575 return FALSE;
579 /******************************************************************
580 * DeletePortA [WINSPOOL.137]
583 BOOL WINAPI
584 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
586 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
587 debugstr_a(pPortName));
588 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
589 return FALSE;
592 /******************************************************************************
593 * SetPrinterW [WINSPOOL.214]
595 BOOL WINAPI
596 SetPrinterW(
597 HANDLE hPrinter,
598 DWORD Level,
599 LPBYTE pPrinter,
600 DWORD Command) {
602 FIXME("():stub\n");
603 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
604 return FALSE;
607 /******************************************************************************
608 * WritePrinter [WINSPOOL.223]
610 BOOL WINAPI
611 WritePrinter(
612 HANDLE hPrinter,
613 LPVOID pBuf,
614 DWORD cbBuf,
615 LPDWORD pcWritten) {
617 FIXME("():stub\n");
618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
619 return FALSE;
622 /*****************************************************************************
623 * AddFormA [WINSPOOL.103]
625 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
627 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
628 return 1;
631 /*****************************************************************************
632 * AddFormW [WINSPOOL.104]
634 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
636 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
637 return 1;
640 /*****************************************************************************
641 * AddJobA [WINSPOOL.105]
643 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
644 DWORD cbBuf, LPDWORD pcbNeeded)
646 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
647 pcbNeeded);
648 return 1;
651 /*****************************************************************************
652 * AddJobW [WINSPOOL.106]
654 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
655 LPDWORD pcbNeeded)
657 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
658 pcbNeeded);
659 return 1;
662 /*****************************************************************************
663 * WINSPOOL_OpenDriverReg [internal]
665 * opens the registry for the printer drivers depending on the given input
666 * variable pEnvironment
668 * RETURNS:
669 * the opened hkey on success
670 * NULL on error
672 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
673 { HKEY retval;
674 LPSTR lpKey, p = NULL;
676 TRACE("%s\n",
677 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
679 if(pEnvironment)
680 p = (unicode) ? HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment) :
681 pEnvironment;
682 else {
683 OSVERSIONINFOA ver;
684 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
686 if(!GetVersionExA( &ver))
687 return 0;
689 switch (ver.dwPlatformId) {
690 case VER_PLATFORM_WIN32s:
691 return 0;
692 case VER_PLATFORM_WIN32_NT:
693 p = "Windows NT x86";
694 break;
695 default:
696 p = "Windows 4.0";
697 break;
699 TRACE("set environment to %s\n", p);
702 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
703 strlen(p) + strlen(Drivers));
704 sprintf( lpKey, Drivers, p);
706 TRACE("%s\n", lpKey);
708 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
709 ERROR_SUCCESS)
710 retval = 0;
712 if(pEnvironment && unicode)
713 HeapFree( GetProcessHeap(), 0, p);
714 HeapFree( GetProcessHeap(), 0, lpKey);
716 return retval;
719 /*****************************************************************************
720 * AddPrinterW [WINSPOOL.122]
722 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
724 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
725 LPDEVMODEA dmA;
726 LPDEVMODEW dmW;
727 HANDLE retval;
728 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
729 LONG size;
731 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
733 if(pName != NULL) {
734 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
735 SetLastError(ERROR_INVALID_PARAMETER);
736 return 0;
738 if(Level != 2) {
739 WARN("Level = %ld\n", Level);
740 SetLastError(ERROR_INVALID_LEVEL);
741 return 0;
743 if(!pPrinter) {
744 SetLastError(ERROR_INVALID_PARAMETER);
745 return 0;
747 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
748 ERROR_SUCCESS) {
749 ERR("Can't create Printers key\n");
750 return 0;
752 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
753 ERROR_SUCCESS) {
754 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
755 RegCloseKey(hkeyPrinter);
756 RegCloseKey(hkeyPrinters);
757 return 0;
759 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
760 if(!hkeyDrivers) {
761 ERR("Can't create Drivers key\n");
762 RegCloseKey(hkeyPrinters);
763 return 0;
765 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
766 ERROR_SUCCESS) {
767 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
768 RegCloseKey(hkeyPrinters);
769 RegCloseKey(hkeyDrivers);
770 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
771 return 0;
773 RegCloseKey(hkeyDriver);
774 RegCloseKey(hkeyDrivers);
776 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
777 WARN("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
778 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
779 RegCloseKey(hkeyPrinters);
780 return 0;
783 /* See if we can load the driver. We may need the devmode structure anyway
785 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
786 if(size < 0) {
787 WARN("DocumentProperties fails\n");
788 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
789 return 0;
791 if(pi->pDevMode) {
792 dmW = pi->pDevMode;
793 } else {
794 dmW = HeapAlloc(GetProcessHeap(), 0, size);
795 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
798 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
799 ERROR_SUCCESS) {
800 WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
801 SetLastError(ERROR_INVALID_PRINTER_NAME);
802 RegCloseKey(hkeyPrinters);
803 if(!pi->pDevMode)
804 HeapFree(GetProcessHeap(), 0, dmW);
805 return 0;
807 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
808 (LPBYTE)&pi->Attributes, sizeof(DWORD));
809 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
812 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
813 and we support these drivers. NT writes DEVMODEW so somehow
814 we'll need to distinguish between these when we support NT
815 drivers */
816 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
817 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
818 dmA->dmSize + dmA->dmDriverExtra);
819 HeapFree(GetProcessHeap(), 0, dmA);
820 if(!pi->pDevMode)
821 HeapFree(GetProcessHeap(), 0, dmW);
822 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
824 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
826 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
827 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
828 (LPBYTE)pi->pParameters, 0);
829 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
830 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
831 (LPBYTE)pi->pPrintProcessor, 0);
832 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
833 (LPBYTE)pi->pDriverName, 0);
834 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
835 (LPBYTE)&pi->Priority, sizeof(DWORD));
836 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
837 (LPBYTE)pi->pSepFile, 0);
838 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
840 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
841 (LPBYTE)&pi->StartTime, sizeof(DWORD));
842 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
843 (LPBYTE)&pi->Status, sizeof(DWORD));
844 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
845 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
847 RegCloseKey(hkeyPrinter);
848 RegCloseKey(hkeyPrinters);
849 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
850 ERR("OpenPrinter failing\n");
851 return 0;
853 return retval;
856 /*****************************************************************************
857 * AddPrinterA [WINSPOOL.117]
859 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
861 WCHAR *pNameW;
862 PRINTER_INFO_2W *piW;
863 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
864 HANDLE ret;
866 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
867 if(Level != 2) {
868 WARN("Level = %ld\n", Level);
869 SetLastError(ERROR_INVALID_LEVEL);
870 return 0;
872 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
873 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
875 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
877 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
878 HeapFree(GetProcessHeap(),0,pNameW);
879 return ret;
883 /*****************************************************************************
884 * ClosePrinter [WINSPOOL.126]
886 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
888 LPOPENEDPRINTER lpOpenedPrinter;
890 TRACE("Handle %d\n", hPrinter);
892 if (!pOpenedPrinterDPA)
893 return FALSE;
895 if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
897 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
898 HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
899 lpOpenedPrinter->lpsPrinterName = NULL;
900 lpOpenedPrinter->hPrinter = -1;
902 return TRUE;
904 return FALSE;
907 /*****************************************************************************
908 * DeleteFormA [WINSPOOL.133]
910 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
912 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
913 return 1;
916 /*****************************************************************************
917 * DeleteFormW [WINSPOOL.134]
919 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
921 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
922 return 1;
925 /*****************************************************************************
926 * DeletePrinter [WINSPOOL.143]
928 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
930 LPWSTR lpNameW;
931 HKEY hkeyPrinters;
933 LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
934 if(!lpOpenedPrinter) {
935 SetLastError(ERROR_INVALID_HANDLE);
936 return FALSE;
938 lpNameW = lpOpenedPrinter->lpsPrinterName;
939 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
940 ERROR_SUCCESS) {
941 ERR("Can't open Printers key\n");
942 return 0;
945 /* This should use a recursive delete see Q142491 or SHDeleteKey */
946 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
947 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
948 RegCloseKey(hkeyPrinters);
949 return 0;
952 ClosePrinter(hPrinter);
953 return TRUE;
956 /*****************************************************************************
957 * SetPrinterA [WINSPOOL.211]
959 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
960 DWORD Command)
962 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
963 return FALSE;
966 /*****************************************************************************
967 * SetJobA [WINSPOOL.209]
969 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
970 LPBYTE pJob, DWORD Command)
972 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
973 Command);
974 return FALSE;
977 /*****************************************************************************
978 * SetJobW [WINSPOOL.210]
980 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
981 LPBYTE pJob, DWORD Command)
983 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
984 Command);
985 return FALSE;
988 /*****************************************************************************
989 * GetFormA [WINSPOOL.181]
991 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
992 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
994 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
995 Level,pForm,cbBuf,pcbNeeded);
996 return FALSE;
999 /*****************************************************************************
1000 * GetFormW [WINSPOOL.182]
1002 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1003 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
1005 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
1006 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
1007 return FALSE;
1010 /*****************************************************************************
1011 * SetFormA [WINSPOOL.207]
1013 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
1014 LPBYTE pForm)
1016 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1017 return FALSE;
1020 /*****************************************************************************
1021 * SetFormW [WINSPOOL.208]
1023 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
1024 LPBYTE pForm)
1026 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
1027 return FALSE;
1030 /*****************************************************************************
1031 * ReadPrinter [WINSPOOL.202]
1033 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
1034 LPDWORD pNoBytesRead)
1036 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
1037 return FALSE;
1040 /*****************************************************************************
1041 * ResetPrinterA [WINSPOOL.203]
1043 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
1045 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1046 return FALSE;
1049 /*****************************************************************************
1050 * ResetPrinterW [WINSPOOL.204]
1052 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
1054 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
1055 return FALSE;
1058 /*****************************************************************************
1059 * WINSPOOL_GetDWORDFromReg
1061 * Return DWORD associated with ValueName from hkey.
1063 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
1065 DWORD sz = sizeof(DWORD), type, value = 0;
1066 LONG ret;
1068 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
1070 if(ret != ERROR_SUCCESS) {
1071 WARN("Got ret = %ld on name %s\n", ret, ValueName);
1072 return 0;
1074 if(type != REG_DWORD) {
1075 ERR("Got type %ld\n", type);
1076 return 0;
1078 return value;
1081 /*****************************************************************************
1082 * WINSPOOL_GetStringFromReg
1084 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1085 * String is stored either as unicode or ascii.
1086 * Bit of a hack here to get the ValueName if we want ascii.
1088 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1089 DWORD buflen, DWORD *needed,
1090 BOOL unicode)
1092 DWORD sz = buflen, type;
1093 LONG ret;
1095 if(unicode)
1096 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1097 else {
1098 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1099 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1100 HeapFree(GetProcessHeap(),0,ValueNameA);
1102 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1103 WARN("Got ret = %ld\n", ret);
1104 *needed = 0;
1105 return FALSE;
1107 *needed = sz;
1108 return TRUE;
1111 /*****************************************************************************
1112 * WINSPOOL_GetDevModeFromReg
1114 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1115 * DevMode is stored either as unicode or ascii.
1117 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1118 LPBYTE ptr,
1119 DWORD buflen, DWORD *needed,
1120 BOOL unicode)
1122 DWORD sz = buflen, type;
1123 LONG ret;
1125 if (ptr) memset(ptr, 0, sizeof(DEVMODEA));
1126 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1127 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
1128 if (sz < sizeof(DEVMODEA))
1130 ERR("corrupted registry for %s\n", debugstr_w(ValueName));
1131 sz = sizeof(DEVMODEA);
1133 /* ensures that dmSize is not erratically bogus if registry is invalid */
1134 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
1135 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
1136 if(unicode) {
1137 sz += (CCHDEVICENAME + CCHFORMNAME);
1138 if(buflen >= sz) {
1139 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1140 memcpy(ptr, dmW, sz);
1141 HeapFree(GetProcessHeap(),0,dmW);
1144 *needed = sz;
1145 return TRUE;
1148 /*********************************************************************
1149 * WINSPOOL_GetPrinter_2
1151 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1152 * The strings are either stored as unicode or ascii.
1154 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1155 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1156 BOOL unicode)
1158 DWORD size, left = cbBuf;
1159 BOOL space = (cbBuf > 0);
1160 LPBYTE ptr = buf;
1162 *pcbNeeded = 0;
1164 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1165 unicode)) {
1166 if(space && size <= left) {
1167 pi2->pPrinterName = (LPWSTR)ptr;
1168 ptr += size;
1169 left -= size;
1170 } else
1171 space = FALSE;
1172 *pcbNeeded += size;
1174 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1175 unicode)) {
1176 if(space && size <= left) {
1177 pi2->pShareName = (LPWSTR)ptr;
1178 ptr += size;
1179 left -= size;
1180 } else
1181 space = FALSE;
1182 *pcbNeeded += size;
1184 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1185 unicode)) {
1186 if(space && size <= left) {
1187 pi2->pPortName = (LPWSTR)ptr;
1188 ptr += size;
1189 left -= size;
1190 } else
1191 space = FALSE;
1192 *pcbNeeded += size;
1194 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1195 &size, unicode)) {
1196 if(space && size <= left) {
1197 pi2->pDriverName = (LPWSTR)ptr;
1198 ptr += size;
1199 left -= size;
1200 } else
1201 space = FALSE;
1202 *pcbNeeded += size;
1204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1205 unicode)) {
1206 if(space && size <= left) {
1207 pi2->pComment = (LPWSTR)ptr;
1208 ptr += size;
1209 left -= size;
1210 } else
1211 space = FALSE;
1212 *pcbNeeded += size;
1214 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1215 unicode)) {
1216 if(space && size <= left) {
1217 pi2->pLocation = (LPWSTR)ptr;
1218 ptr += size;
1219 left -= size;
1220 } else
1221 space = FALSE;
1222 *pcbNeeded += size;
1224 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1225 &size, unicode)) {
1226 if(space && size <= left) {
1227 pi2->pDevMode = (LPDEVMODEW)ptr;
1228 ptr += size;
1229 left -= size;
1230 } else
1231 space = FALSE;
1232 *pcbNeeded += size;
1234 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1235 &size, unicode)) {
1236 if(space && size <= left) {
1237 pi2->pSepFile = (LPWSTR)ptr;
1238 ptr += size;
1239 left -= size;
1240 } else
1241 space = FALSE;
1242 *pcbNeeded += size;
1244 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1245 &size, unicode)) {
1246 if(space && size <= left) {
1247 pi2->pPrintProcessor = (LPWSTR)ptr;
1248 ptr += size;
1249 left -= size;
1250 } else
1251 space = FALSE;
1252 *pcbNeeded += size;
1254 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1255 &size, unicode)) {
1256 if(space && size <= left) {
1257 pi2->pDatatype = (LPWSTR)ptr;
1258 ptr += size;
1259 left -= size;
1260 } else
1261 space = FALSE;
1262 *pcbNeeded += size;
1264 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1265 &size, unicode)) {
1266 if(space && size <= left) {
1267 pi2->pParameters = (LPWSTR)ptr;
1268 ptr += size;
1269 left -= size;
1270 } else
1271 space = FALSE;
1272 *pcbNeeded += size;
1274 if(pi2) {
1275 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1276 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1277 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1278 "Default Priority");
1279 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1280 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1283 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1284 memset(pi2, 0, sizeof(*pi2));
1286 return space;
1289 /*********************************************************************
1290 * WINSPOOL_GetPrinter_4
1292 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1294 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1295 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1296 BOOL unicode)
1298 DWORD size, left = cbBuf;
1299 BOOL space = (cbBuf > 0);
1300 LPBYTE ptr = buf;
1302 *pcbNeeded = 0;
1304 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1305 unicode)) {
1306 if(space && size <= left) {
1307 pi4->pPrinterName = (LPWSTR)ptr;
1308 ptr += size;
1309 left -= size;
1310 } else
1311 space = FALSE;
1312 *pcbNeeded += size;
1314 if(pi4) {
1315 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1318 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1319 memset(pi4, 0, sizeof(*pi4));
1321 return space;
1324 /*********************************************************************
1325 * WINSPOOL_GetPrinter_5
1327 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1329 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1330 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1331 BOOL unicode)
1333 DWORD size, left = cbBuf;
1334 BOOL space = (cbBuf > 0);
1335 LPBYTE ptr = buf;
1337 *pcbNeeded = 0;
1339 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1340 unicode)) {
1341 if(space && size <= left) {
1342 pi5->pPrinterName = (LPWSTR)ptr;
1343 ptr += size;
1344 left -= size;
1345 } else
1346 space = FALSE;
1347 *pcbNeeded += size;
1349 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1350 unicode)) {
1351 if(space && size <= left) {
1352 pi5->pPortName = (LPWSTR)ptr;
1353 ptr += size;
1354 left -= size;
1355 } else
1356 space = FALSE;
1357 *pcbNeeded += size;
1359 if(pi5) {
1360 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1361 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1362 "dnsTimeout");
1363 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1364 "txTimeout");
1367 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1368 memset(pi5, 0, sizeof(*pi5));
1370 return space;
1373 /*****************************************************************************
1374 * WINSPOOL_GetPrinter
1376 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1377 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1378 * just a collection of pointers to strings.
1380 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1381 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1383 OPENEDPRINTER *lpOpenedPrinter;
1384 DWORD size, needed = 0;
1385 LPBYTE ptr = NULL;
1386 HKEY hkeyPrinter, hkeyPrinters;
1387 BOOL ret;
1389 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1391 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1392 if(!lpOpenedPrinter) {
1393 SetLastError(ERROR_INVALID_HANDLE);
1394 return FALSE;
1396 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1397 ERROR_SUCCESS) {
1398 ERR("Can't create Printers key\n");
1399 return FALSE;
1401 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1402 != ERROR_SUCCESS) {
1403 ERR("Can't find opened printer %s in registry\n",
1404 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1405 RegCloseKey(hkeyPrinters);
1406 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1407 return FALSE;
1410 switch(Level) {
1411 case 2:
1413 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1415 size = sizeof(PRINTER_INFO_2W);
1416 if(size <= cbBuf) {
1417 ptr = pPrinter + size;
1418 cbBuf -= size;
1419 memset(pPrinter, 0, size);
1420 } else {
1421 pi2 = NULL;
1422 cbBuf = 0;
1424 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1425 unicode);
1426 needed += size;
1427 break;
1430 case 4:
1432 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1434 size = sizeof(PRINTER_INFO_4W);
1435 if(size <= cbBuf) {
1436 ptr = pPrinter + size;
1437 cbBuf -= size;
1438 memset(pPrinter, 0, size);
1439 } else {
1440 pi4 = NULL;
1441 cbBuf = 0;
1443 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1444 unicode);
1445 needed += size;
1446 break;
1450 case 5:
1452 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1454 size = sizeof(PRINTER_INFO_5W);
1455 if(size <= cbBuf) {
1456 ptr = pPrinter + size;
1457 cbBuf -= size;
1458 memset(pPrinter, 0, size);
1459 } else {
1460 pi5 = NULL;
1461 cbBuf = 0;
1464 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1465 unicode);
1466 needed += size;
1467 break;
1470 default:
1471 FIXME("Unimplemented level %ld\n", Level);
1472 SetLastError(ERROR_INVALID_LEVEL);
1473 RegCloseKey(hkeyPrinters);
1474 RegCloseKey(hkeyPrinter);
1475 return FALSE;
1478 RegCloseKey(hkeyPrinter);
1479 RegCloseKey(hkeyPrinters);
1481 TRACE("returing %d needed = %ld\n", ret, needed);
1482 if(pcbNeeded) *pcbNeeded = needed;
1483 if(!ret)
1484 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1485 return ret;
1488 /*****************************************************************************
1489 * GetPrinterW [WINSPOOL.194]
1491 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1492 DWORD cbBuf, LPDWORD pcbNeeded)
1494 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1495 TRUE);
1498 /*****************************************************************************
1499 * GetPrinterA [WINSPOOL.187]
1501 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1502 DWORD cbBuf, LPDWORD pcbNeeded)
1504 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1505 FALSE);
1508 /*****************************************************************************
1509 * WINSPOOL_EnumPrinters
1511 * Implementation of EnumPrintersA|W
1513 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1514 DWORD dwLevel, LPBYTE lpbPrinters,
1515 DWORD cbBuf, LPDWORD lpdwNeeded,
1516 LPDWORD lpdwReturned, BOOL unicode)
1519 HKEY hkeyPrinters, hkeyPrinter;
1520 WCHAR PrinterName[255];
1521 DWORD needed = 0, number = 0;
1522 DWORD used, i, left;
1523 PBYTE pi, buf;
1525 if(lpbPrinters)
1526 memset(lpbPrinters, 0, cbBuf);
1527 if(lpdwReturned)
1528 *lpdwReturned = 0;
1529 if(lpdwNeeded)
1530 *lpdwNeeded = 0;
1532 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1533 if(dwType == PRINTER_ENUM_DEFAULT)
1534 return TRUE;
1536 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1537 FIXME("dwType = %08lx\n", dwType);
1538 SetLastError(ERROR_INVALID_FLAGS);
1539 return FALSE;
1542 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1543 ERROR_SUCCESS) {
1544 ERR("Can't create Printers key\n");
1545 return FALSE;
1548 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1549 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1550 RegCloseKey(hkeyPrinters);
1551 ERR("Can't query Printers key\n");
1552 return FALSE;
1554 TRACE("Found %ld printers\n", number);
1556 switch(dwLevel) {
1557 case 1:
1558 RegCloseKey(hkeyPrinters);
1559 if (lpdwReturned)
1560 *lpdwReturned = number;
1561 return TRUE;
1563 case 2:
1564 used = number * sizeof(PRINTER_INFO_2W);
1565 break;
1566 case 4:
1567 used = number * sizeof(PRINTER_INFO_4W);
1568 break;
1569 case 5:
1570 used = number * sizeof(PRINTER_INFO_5W);
1571 break;
1573 default:
1574 SetLastError(ERROR_INVALID_LEVEL);
1575 RegCloseKey(hkeyPrinters);
1576 return FALSE;
1578 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1580 for(i = 0; i < number; i++) {
1581 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1582 ERROR_SUCCESS) {
1583 ERR("Can't enum key number %ld\n", i);
1584 RegCloseKey(hkeyPrinters);
1585 return FALSE;
1587 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1588 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1589 ERROR_SUCCESS) {
1590 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1591 RegCloseKey(hkeyPrinters);
1592 return FALSE;
1595 if(cbBuf > used) {
1596 buf = lpbPrinters + used;
1597 left = cbBuf - used;
1598 } else {
1599 buf = NULL;
1600 left = 0;
1603 switch(dwLevel) {
1604 case 2:
1605 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1606 left, &needed, unicode);
1607 used += needed;
1608 if(pi) pi += sizeof(PRINTER_INFO_2W);
1609 break;
1610 case 4:
1611 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1612 left, &needed, unicode);
1613 used += needed;
1614 if(pi) pi += sizeof(PRINTER_INFO_4W);
1615 break;
1616 case 5:
1617 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1618 left, &needed, unicode);
1619 used += needed;
1620 if(pi) pi += sizeof(PRINTER_INFO_5W);
1621 break;
1622 default:
1623 ERR("Shouldn't be here!\n");
1624 RegCloseKey(hkeyPrinter);
1625 RegCloseKey(hkeyPrinters);
1626 return FALSE;
1628 RegCloseKey(hkeyPrinter);
1630 RegCloseKey(hkeyPrinters);
1632 if(lpdwNeeded)
1633 *lpdwNeeded = used;
1635 if(used > cbBuf) {
1636 if(lpbPrinters)
1637 memset(lpbPrinters, 0, cbBuf);
1638 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1639 return FALSE;
1641 if(lpdwReturned)
1642 *lpdwReturned = number;
1643 SetLastError(ERROR_SUCCESS);
1644 return TRUE;
1648 /******************************************************************
1649 * EnumPrintersW [WINSPOOL.175]
1651 * Enumerates the available printers, print servers and print
1652 * providers, depending on the specified flags, name and level.
1654 * RETURNS:
1656 * If level is set to 1:
1657 * Not implemented yet!
1658 * Returns TRUE with an empty list.
1660 * If level is set to 2:
1661 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1662 * Returns an array of PRINTER_INFO_2 data structures in the
1663 * lpbPrinters buffer. Note that according to MSDN also an
1664 * OpenPrinter should be performed on every remote printer.
1666 * If level is set to 4 (officially WinNT only):
1667 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1668 * Fast: Only the registry is queried to retrieve printer names,
1669 * no connection to the driver is made.
1670 * Returns an array of PRINTER_INFO_4 data structures in the
1671 * lpbPrinters buffer.
1673 * If level is set to 5 (officially WinNT4/Win9x only):
1674 * Fast: Only the registry is queried to retrieve printer names,
1675 * no connection to the driver is made.
1676 * Returns an array of PRINTER_INFO_5 data structures in the
1677 * lpbPrinters buffer.
1679 * If level set to 3 or 6+:
1680 * returns zero (faillure!)
1682 * Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
1683 * for information.
1685 * BUGS:
1686 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1687 * - Only levels 2, 4 and 5 are implemented at the moment.
1688 * - 16-bit printer drivers are not enumerated.
1689 * - Returned amount of bytes used/needed does not match the real Windoze
1690 * implementation (as in this implementation, all strings are part
1691 * of the buffer, whereas Win32 keeps them somewhere else)
1692 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1694 * NOTE:
1695 * - In a regular Wine installation, no registry settings for printers
1696 * exist, which makes this function return an empty list.
1698 BOOL WINAPI EnumPrintersW(
1699 DWORD dwType, /* [in] Types of print objects to enumerate */
1700 LPWSTR lpszName, /* [in] name of objects to enumerate */
1701 DWORD dwLevel, /* [in] type of printer info structure */
1702 LPBYTE lpbPrinters, /* [out] buffer which receives info */
1703 DWORD cbBuf, /* [in] max size of buffer in bytes */
1704 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
1705 LPDWORD lpdwReturned /* [out] number of entries returned */
1708 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1709 lpdwNeeded, lpdwReturned, TRUE);
1712 /******************************************************************
1713 * EnumPrintersA [WINSPOOL.174]
1716 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1717 DWORD dwLevel, LPBYTE lpbPrinters,
1718 DWORD cbBuf, LPDWORD lpdwNeeded,
1719 LPDWORD lpdwReturned)
1721 BOOL ret;
1722 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1724 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1725 lpdwNeeded, lpdwReturned, FALSE);
1726 HeapFree(GetProcessHeap(),0,lpszNameW);
1727 return ret;
1730 /*****************************************************************************
1731 * WINSPOOL_GetDriverInfoFromReg [internal]
1733 * Enters the information from the registry into the DRIVER_INFO struct
1735 * RETURNS
1736 * zero if the printer driver does not exist in the registry
1737 * (only if Level > 1) otherwise nonzero
1739 static BOOL WINSPOOL_GetDriverInfoFromReg(
1740 HKEY hkeyDrivers,
1741 LPWSTR DriverName,
1742 LPWSTR pEnvironment,
1743 DWORD Level,
1744 LPBYTE ptr, /* DRIVER_INFO */
1745 LPBYTE pDriverStrings, /* strings buffer */
1746 DWORD cbBuf, /* size of string buffer */
1747 LPDWORD pcbNeeded, /* space needed for str. */
1748 BOOL unicode) /* type of strings */
1749 { DWORD dw, size, tmp, type;
1750 HKEY hkeyDriver;
1751 LPBYTE strPtr = pDriverStrings;
1753 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1754 debugstr_w(DriverName), debugstr_w(pEnvironment),
1755 Level, ptr, pDriverStrings, cbBuf, unicode);
1757 if(unicode) {
1758 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1759 if (*pcbNeeded <= cbBuf)
1760 strcpyW((LPWSTR)strPtr, DriverName);
1761 } else {
1762 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1763 NULL, NULL);
1764 if(*pcbNeeded <= cbBuf)
1765 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, strPtr, *pcbNeeded,
1766 NULL, NULL);
1768 if(Level == 1) {
1769 if(ptr)
1770 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1771 return TRUE;
1772 } else {
1773 if(ptr)
1774 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1775 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1778 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1779 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1780 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1781 return FALSE;
1784 size = sizeof(dw);
1785 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1786 ERROR_SUCCESS)
1787 WARN("Can't get Version\n");
1788 else if(ptr)
1789 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1791 if(!pEnvironment)
1792 pEnvironment = DefaultEnvironmentW;
1793 if(unicode)
1794 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1795 else
1796 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1797 NULL, NULL);
1798 *pcbNeeded += size;
1799 if(*pcbNeeded <= cbBuf) {
1800 if(unicode)
1801 strcpyW((LPWSTR)strPtr, pEnvironment);
1802 else
1803 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, strPtr, size,
1804 NULL, NULL);
1805 if(ptr)
1806 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1807 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1810 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1811 unicode)) {
1812 *pcbNeeded += size;
1813 if(*pcbNeeded <= cbBuf)
1814 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1815 unicode);
1816 if(ptr)
1817 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1818 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1821 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1822 unicode)) {
1823 *pcbNeeded += size;
1824 if(*pcbNeeded <= cbBuf)
1825 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1826 &tmp, unicode);
1827 if(ptr)
1828 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1829 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1832 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1833 0, &size, unicode)) {
1834 *pcbNeeded += size;
1835 if(*pcbNeeded <= cbBuf)
1836 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1837 size, &tmp, unicode);
1838 if(ptr)
1839 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1840 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1843 if(Level == 2 ) {
1844 RegCloseKey(hkeyDriver);
1845 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1846 return TRUE;
1849 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1850 unicode)) {
1851 *pcbNeeded += size;
1852 if(*pcbNeeded <= cbBuf)
1853 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1854 size, &tmp, unicode);
1855 if(ptr)
1856 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1857 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1860 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1861 &size, unicode)) {
1862 *pcbNeeded += size;
1863 if(*pcbNeeded <= cbBuf)
1864 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1865 size, &tmp, unicode);
1866 if(ptr)
1867 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1868 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1871 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1872 unicode)) {
1873 *pcbNeeded += size;
1874 if(*pcbNeeded <= cbBuf)
1875 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1876 size, &tmp, unicode);
1877 if(ptr)
1878 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1879 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1882 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1883 unicode)) {
1884 *pcbNeeded += size;
1885 if(*pcbNeeded <= cbBuf)
1886 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1887 size, &tmp, unicode);
1888 if(ptr)
1889 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1890 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1893 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1894 RegCloseKey(hkeyDriver);
1895 return TRUE;
1898 /*****************************************************************************
1899 * WINSPOOL_GetPrinterDriver
1901 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1902 DWORD Level, LPBYTE pDriverInfo,
1903 DWORD cbBuf, LPDWORD pcbNeeded,
1904 BOOL unicode)
1906 OPENEDPRINTER *lpOpenedPrinter;
1907 WCHAR DriverName[100];
1908 DWORD ret, type, size, needed = 0;
1909 LPBYTE ptr = NULL;
1910 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1912 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1913 Level,pDriverInfo,cbBuf, pcbNeeded);
1915 ZeroMemory(pDriverInfo, cbBuf);
1917 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1918 if(!lpOpenedPrinter) {
1919 SetLastError(ERROR_INVALID_HANDLE);
1920 return FALSE;
1922 if(Level < 1 || Level > 3) {
1923 SetLastError(ERROR_INVALID_LEVEL);
1924 return FALSE;
1926 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1927 ERROR_SUCCESS) {
1928 ERR("Can't create Printers key\n");
1929 return FALSE;
1931 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1932 != ERROR_SUCCESS) {
1933 ERR("Can't find opened printer %s in registry\n",
1934 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1935 RegCloseKey(hkeyPrinters);
1936 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1937 return FALSE;
1939 size = sizeof(DriverName);
1940 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1941 (LPBYTE)DriverName, &size);
1942 RegCloseKey(hkeyPrinter);
1943 RegCloseKey(hkeyPrinters);
1944 if(ret != ERROR_SUCCESS) {
1945 ERR("Can't get DriverName for printer %s\n",
1946 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1947 return FALSE;
1950 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1951 if(!hkeyDrivers) {
1952 ERR("Can't create Drivers key\n");
1953 return FALSE;
1956 switch(Level) {
1957 case 1:
1958 size = sizeof(DRIVER_INFO_1W);
1959 break;
1960 case 2:
1961 size = sizeof(DRIVER_INFO_2W);
1962 break;
1963 case 3:
1964 size = sizeof(DRIVER_INFO_3W);
1965 break;
1966 default:
1967 ERR("Invalid level\n");
1968 return FALSE;
1971 if(size <= cbBuf)
1972 ptr = pDriverInfo + size;
1974 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
1975 pEnvironment, Level, pDriverInfo,
1976 (cbBuf < size) ? NULL : ptr,
1977 (cbBuf < size) ? 0 : cbBuf - size,
1978 &needed, unicode)) {
1979 RegCloseKey(hkeyDrivers);
1980 return FALSE;
1983 RegCloseKey(hkeyDrivers);
1985 if(pcbNeeded) *pcbNeeded = size + needed;
1986 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1987 if(cbBuf >= needed) return TRUE;
1988 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1989 return FALSE;
1992 /*****************************************************************************
1993 * GetPrinterDriverA [WINSPOOL.190]
1995 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1996 DWORD Level, LPBYTE pDriverInfo,
1997 DWORD cbBuf, LPDWORD pcbNeeded)
1999 BOOL ret;
2000 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2001 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2002 cbBuf, pcbNeeded, FALSE);
2003 HeapFree(GetProcessHeap(),0,pEnvW);
2004 return ret;
2006 /*****************************************************************************
2007 * GetPrinterDriverW [WINSPOOL.193]
2009 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
2010 DWORD Level, LPBYTE pDriverInfo,
2011 DWORD cbBuf, LPDWORD pcbNeeded)
2013 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
2014 pDriverInfo, cbBuf, pcbNeeded, TRUE);
2017 /*****************************************************************************
2018 * GetPrinterDriverDirectoryA [WINSPOOL.191]
2020 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
2021 DWORD Level, LPBYTE pDriverDirectory,
2022 DWORD cbBuf, LPDWORD pcbNeeded)
2024 DWORD needed;
2026 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2027 pDriverDirectory, cbBuf, pcbNeeded);
2028 if(pName != NULL) {
2029 FIXME("pName = `%s' - unsupported\n", pName);
2030 SetLastError(ERROR_INVALID_PARAMETER);
2031 return FALSE;
2033 if(pEnvironment != NULL) {
2034 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2035 SetLastError(ERROR_INVALID_ENVIRONMENT);
2036 return FALSE;
2038 if(Level != 1) /* win95 ignores this so we just carry on */
2039 WARN("Level = %ld - assuming 1\n", Level);
2041 /* FIXME should read from registry */
2042 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
2043 needed++;
2044 if(pcbNeeded)
2045 *pcbNeeded = needed;
2046 if(needed > cbBuf) {
2047 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2048 return FALSE;
2050 return TRUE;
2054 /*****************************************************************************
2055 * GetPrinterDriverDirectoryW [WINSPOOL.192]
2057 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
2058 DWORD Level, LPBYTE pDriverDirectory,
2059 DWORD cbBuf, LPDWORD pcbNeeded)
2061 LPSTR pNameA = NULL, pEnvironmentA = NULL;
2062 BOOL ret;
2064 if(pName)
2065 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
2066 if(pEnvironment)
2067 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
2068 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
2069 pDriverDirectory, cbBuf, pcbNeeded );
2070 if(pNameA)
2071 HeapFree( GetProcessHeap(), 0, pNameA );
2072 if(pEnvironmentA)
2073 HeapFree( GetProcessHeap(), 0, pEnvironmentA );
2075 return ret;
2078 /*****************************************************************************
2079 * AddPrinterDriverA [WINSPOOL.120]
2081 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2083 DRIVER_INFO_3A di3;
2084 HKEY hkeyDrivers, hkeyName;
2086 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
2088 if(level != 2 && level != 3) {
2089 SetLastError(ERROR_INVALID_LEVEL);
2090 return FALSE;
2092 if(pName != NULL) {
2093 FIXME("pName= `%s' - unsupported\n", pName);
2094 SetLastError(ERROR_INVALID_PARAMETER);
2095 return FALSE;
2097 if(!pDriverInfo) {
2098 WARN("pDriverInfo == NULL");
2099 SetLastError(ERROR_INVALID_PARAMETER);
2100 return FALSE;
2103 if(level == 3)
2104 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2105 else {
2106 memset(&di3, 0, sizeof(di3));
2107 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2110 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2111 !di3.pDataFile) {
2112 SetLastError(ERROR_INVALID_PARAMETER);
2113 return FALSE;
2115 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2116 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2117 if(!di3.pHelpFile) di3.pHelpFile = "";
2118 if(!di3.pMonitorName) di3.pMonitorName = "";
2120 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2122 if(!hkeyDrivers) {
2123 ERR("Can't create Drivers key\n");
2124 return FALSE;
2127 if(level == 2) { /* apparently can't overwrite with level2 */
2128 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2129 RegCloseKey(hkeyName);
2130 RegCloseKey(hkeyDrivers);
2131 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2132 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2133 return FALSE;
2136 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2137 RegCloseKey(hkeyDrivers);
2138 ERR("Can't create Name key\n");
2139 return FALSE;
2141 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2143 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2144 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2145 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2146 sizeof(DWORD));
2147 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2148 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2149 di3.pDependentFiles, 0);
2150 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2151 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2152 RegCloseKey(hkeyName);
2153 RegCloseKey(hkeyDrivers);
2155 return TRUE;
2157 /*****************************************************************************
2158 * AddPrinterDriverW [WINSPOOL.121]
2160 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2161 LPBYTE pDriverInfo)
2163 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2164 level,pDriverInfo);
2165 return FALSE;
2169 /*****************************************************************************
2170 * PrinterProperties [WINSPOOL.201]
2172 * Displays a dialog to set the properties of the printer.
2174 * RETURNS
2175 * nonzero on succes or zero on faillure
2177 * BUGS
2178 * implemented as stub only
2180 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
2181 HANDLE hPrinter /* [in] handle to printer object */
2183 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2185 return FALSE;
2188 /*****************************************************************************
2189 * EnumJobsA [WINSPOOL.162]
2192 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2193 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2194 LPDWORD pcReturned)
2196 FIXME("stub\n");
2197 if(pcbNeeded) *pcbNeeded = 0;
2198 if(pcReturned) *pcReturned = 0;
2199 return TRUE;
2203 /*****************************************************************************
2204 * EnumJobsW [WINSPOOL.163]
2207 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2208 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2209 LPDWORD pcReturned)
2211 FIXME("stub\n");
2212 if(pcbNeeded) *pcbNeeded = 0;
2213 if(pcReturned) *pcReturned = 0;
2214 return TRUE;
2217 /*****************************************************************************
2218 * WINSPOOL_EnumPrinterDrivers [internal]
2220 * Delivers information about all installed printer drivers installed on
2221 * localhost or a given server
2223 * RETURNS
2224 * nonzero on succes or zero on failure, if the buffer for the returned
2225 * information is too small the function will return an error
2227 * BUGS
2228 * - only implemented for localhost, foreign hosts will return an error
2230 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
2231 DWORD Level, LPBYTE pDriverInfo,
2232 DWORD cbBuf, LPDWORD pcbNeeded,
2233 LPDWORD pcReturned, BOOL unicode)
2235 { HKEY hkeyDrivers;
2236 DWORD i, needed, number = 0, size = 0;
2237 WCHAR DriverNameW[255];
2238 PBYTE ptr;
2240 TRACE("%s,%s,%ld,%p,%ld,%d\n",
2241 debugstr_w(pName), debugstr_w(pEnvironment),
2242 Level, pDriverInfo, cbBuf, unicode);
2244 /* check for local drivers */
2245 if(pName) {
2246 ERR("remote drivers unsupported! Current remote host is %s\n",
2247 debugstr_w(pName));
2248 return FALSE;
2251 /* check input parameter */
2252 if((Level < 1) || (Level > 3)) {
2253 ERR("unsupported level %ld \n", Level);
2254 return FALSE;
2257 /* initialize return values */
2258 if(pDriverInfo)
2259 memset( pDriverInfo, 0, cbBuf);
2260 *pcbNeeded = 0;
2261 *pcReturned = 0;
2263 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
2264 if(!hkeyDrivers) {
2265 ERR("Can't open Drivers key\n");
2266 return FALSE;
2269 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
2270 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2271 RegCloseKey(hkeyDrivers);
2272 ERR("Can't query Drivers key\n");
2273 return FALSE;
2275 TRACE("Found %ld Drivers\n", number);
2277 /* get size of single struct
2278 * unicode and ascii structure have the same size
2280 switch (Level) {
2281 case 1:
2282 size = sizeof(DRIVER_INFO_1A);
2283 break;
2284 case 2:
2285 size = sizeof(DRIVER_INFO_2A);
2286 break;
2287 case 3:
2288 size = sizeof(DRIVER_INFO_3A);
2289 break;
2292 /* calculate required buffer size */
2293 *pcbNeeded = size * number;
2295 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
2296 i < number;
2297 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
2298 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
2299 != ERROR_SUCCESS) {
2300 ERR("Can't enum key number %ld\n", i);
2301 RegCloseKey(hkeyDrivers);
2302 return FALSE;
2304 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
2305 pEnvironment, Level, ptr,
2306 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
2307 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
2308 &needed, unicode)) {
2309 RegCloseKey(hkeyDrivers);
2310 return FALSE;
2312 (*pcbNeeded) += needed;
2315 RegCloseKey(hkeyDrivers);
2317 if(cbBuf < *pcbNeeded){
2318 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2319 return FALSE;
2322 return TRUE;
2325 /*****************************************************************************
2326 * EnumPrinterDriversW [WINSPOOL.173]
2328 * see function EnumPrinterDrivers for RETURNS, BUGS
2330 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2331 LPBYTE pDriverInfo, DWORD cbBuf,
2332 LPDWORD pcbNeeded, LPDWORD pcReturned)
2334 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
2335 cbBuf, pcbNeeded, pcReturned, TRUE);
2338 /*****************************************************************************
2339 * EnumPrinterDriversA [WINSPOOL.172]
2341 * see function EnumPrinterDrivers for RETURNS, BUGS
2343 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
2344 LPBYTE pDriverInfo, DWORD cbBuf,
2345 LPDWORD pcbNeeded, LPDWORD pcReturned)
2346 { BOOL ret;
2347 WCHAR *pNameW = NULL, *pEnvironmentW = NULL;
2349 if(pName)
2350 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
2351 if(pEnvironment)
2352 pEnvironmentW = HEAP_strdupAtoW(GetProcessHeap(), 0, pEnvironment);
2354 ret = WINSPOOL_EnumPrinterDrivers(pNameW, pEnvironmentW, Level, pDriverInfo,
2355 cbBuf, pcbNeeded, pcReturned, FALSE);
2356 if(pNameW)
2357 HeapFree(GetProcessHeap(), 0, pNameW);
2358 if(pEnvironmentW)
2359 HeapFree(GetProcessHeap(), 0, pEnvironmentW);
2361 return ret;
2365 /******************************************************************************
2366 * EnumPortsA (WINSPOOL.166)
2368 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE ports,DWORD bufsize,
2369 LPDWORD bufneeded,LPDWORD bufreturned)
2371 FIXME("(%s,%ld,%p,%ld,%p,%p), stub!\n",name,level,ports,bufsize,bufneeded,bufreturned);
2372 return FALSE;