Moved idle event handling to the server.
[wine.git] / dlls / winspool / info.c
blob4a71e6c6234e216e952b92b8ffc93b78896b36bd
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 <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <stddef.h>
14 #include "winspool.h"
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "winreg.h"
18 #include "debugtools.h"
19 #include "heap.h"
20 #include "commctrl.h"
21 #include "winnls.h"
23 DEFAULT_DEBUG_CHANNEL(winspool)
25 CRITICAL_SECTION PRINT32_RegistryBlocker;
27 typedef struct _OPENEDPRINTER
29 LPWSTR lpsPrinterName;
30 HANDLE hPrinter;
31 } OPENEDPRINTER, *LPOPENEDPRINTER;
33 /* The OpenedPrinter Table dynamic array */
34 static HDPA pOpenedPrinterDPA = NULL;
36 extern HDPA (WINAPI* WINSPOOL_DPA_CreateEx) (INT, HANDLE);
37 extern LPVOID (WINAPI* WINSPOOL_DPA_GetPtr) (const HDPA, INT);
38 extern INT (WINAPI* WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID);
40 static char Printers[] =
41 "System\\CurrentControlSet\\control\\Print\\Printers\\";
42 static char Drivers[] =
43 "System\\CurrentControlSet\\control\\Print\\Environments\\Windows 4.0\\Drivers\\"; /* Hmm, well */
45 static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
47 static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
48 'i','o','n',' ','F','i','l','e',0};
49 static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
50 static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
51 static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
52 'M','o','d','e',0};
53 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
54 'i','l','e','s',0};
55 static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
56 static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
57 static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
58 static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
59 static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
60 static WCHAR NameW[] = {'N','a','m','e',0};
61 static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
62 static WCHAR PortW[] = {'P','o','r','t',0};
63 static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
64 's','s','o','r',0};
65 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
66 'v','e','r',0};
67 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
68 'i','l','e',0};
69 static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
70 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
72 /******************************************************************
73 * WINSPOOL_GetOpenedPrinterEntry
74 * Get the first place empty in the opened printer table
76 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinterEntry()
78 int i;
79 LPOPENEDPRINTER pOpenedPrinter;
82 * Create the opened printers' handle dynamic array.
84 if (!pOpenedPrinterDPA)
86 pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap());
87 for (i = 0; i < 10; i++)
89 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
90 HEAP_ZERO_MEMORY,
91 sizeof(OPENEDPRINTER));
92 pOpenedPrinter->hPrinter = -1;
93 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
98 * Search for a handle not yet allocated.
100 for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++)
102 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i);
104 if (pOpenedPrinter->hPrinter == -1)
106 pOpenedPrinter->hPrinter = i + 1;
107 return pOpenedPrinter;
112 * Didn't find one, insert new element in the array.
114 if (i == pOpenedPrinterDPA->nItemCount)
116 pOpenedPrinter = HeapAlloc(GetProcessHeap(),
117 HEAP_ZERO_MEMORY,
118 sizeof(OPENEDPRINTER));
119 pOpenedPrinter->hPrinter = i + 1;
120 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
121 return pOpenedPrinter;
124 return NULL;
127 /******************************************************************
128 * WINSPOOL_GetOpenedPrinter
129 * Get the pointer to the opened printer referred by the handle
131 static LPOPENEDPRINTER WINSPOOL_GetOpenedPrinter(int printerHandle)
133 LPOPENEDPRINTER pOpenedPrinter;
135 if(!pOpenedPrinterDPA) return NULL;
136 if((printerHandle <=0) ||
137 (printerHandle > (pOpenedPrinterDPA->nItemCount - 1)))
138 return NULL;
140 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
142 return pOpenedPrinter;
145 /***********************************************************
146 * DEVMODEcpyAtoW
148 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
150 BOOL Formname;
151 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
152 DWORD size;
154 Formname = (dmA->dmSize > off_formname);
155 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
156 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
157 CCHDEVICENAME);
158 if(!Formname) {
159 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
160 dmA->dmSize - CCHDEVICENAME);
161 } else {
162 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
163 off_formname - CCHDEVICENAME);
164 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
165 CCHFORMNAME);
166 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
167 (off_formname + CCHFORMNAME));
169 dmW->dmSize = size;
170 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
171 dmA->dmDriverExtra);
172 return dmW;
175 /***********************************************************
176 * DEVMODEdupAtoW
177 * Creates a unicode copy of supplied devmode on heap
179 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
181 LPDEVMODEW dmW;
182 DWORD size;
183 BOOL Formname;
184 ptrdiff_t off_formname;
186 TRACE("\n");
187 if(!dmA) return NULL;
189 off_formname = (char *)dmA->dmFormName - (char *)dmA;
190 Formname = (dmA->dmSize > off_formname);
191 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
192 dmW = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
193 return DEVMODEcpyAtoW(dmW, dmA);
196 /***********************************************************
197 * DEVMODEdupWtoA
198 * Creates an ascii copy of supplied devmode on heap
200 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
202 LPDEVMODEA dmA;
203 DWORD size;
204 BOOL Formname;
205 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
207 if(!dmW) return NULL;
208 Formname = (dmW->dmSize > off_formname);
209 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
210 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
211 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, dmA->dmDeviceName,
212 CCHDEVICENAME, NULL, NULL);
213 if(!Formname) {
214 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
215 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
216 } else {
217 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
218 off_formname - CCHDEVICENAME * sizeof(WCHAR));
219 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, dmA->dmFormName,
220 CCHFORMNAME, NULL, NULL);
221 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
222 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
224 dmA->dmSize = size;
225 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
226 dmW->dmDriverExtra);
227 return dmA;
230 /***********************************************************
231 * PRINTER_INFO_2AtoW
232 * Creates a unicode copy of PRINTER_INFO_2A on heap
234 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
236 LPPRINTER_INFO_2W piW;
237 if(!piA) return NULL;
238 piW = HeapAlloc(heap, 0, sizeof(*piW));
239 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
240 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
241 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
242 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
243 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
244 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
245 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
246 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
247 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
248 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
249 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
250 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
251 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
252 return piW;
255 /***********************************************************
256 * FREE_PRINTER_INFO_2W
257 * Free PRINTER_INFO_2W and all strings
259 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
261 if(!piW) return;
263 HeapFree(heap,0,piW->pServerName);
264 HeapFree(heap,0,piW->pPrinterName);
265 HeapFree(heap,0,piW->pShareName);
266 HeapFree(heap,0,piW->pPortName);
267 HeapFree(heap,0,piW->pDriverName);
268 HeapFree(heap,0,piW->pComment);
269 HeapFree(heap,0,piW->pLocation);
270 HeapFree(heap,0,piW->pDevMode);
271 HeapFree(heap,0,piW->pSepFile);
272 HeapFree(heap,0,piW->pPrintProcessor);
273 HeapFree(heap,0,piW->pDatatype);
274 HeapFree(heap,0,piW->pParameters);
275 HeapFree(heap,0,piW);
276 return;
279 /******************************************************************
280 * DeviceCapabilitiesA [WINSPOOL.151]
283 INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap,
284 LPSTR pOutput, LPDEVMODEA lpdm)
286 INT ret;
287 ret = GDI_CallDeviceCapabilities16(pDeivce, pPort, cap, pOutput, lpdm);
289 /* If DC_PAPERSIZE map POINT16s to POINTs */
290 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
291 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
292 INT i;
293 memcpy(tmp, pOutput, ret * sizeof(POINT16));
294 for(i = 0; i < ret; i++)
295 CONV_POINT16TO32(tmp + i, (POINT*)pOutput + i);
296 HeapFree( GetProcessHeap(), 0, tmp );
298 return ret;
302 /*****************************************************************************
303 * DeviceCapabilitiesW
305 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
308 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
309 WORD fwCapability, LPWSTR pOutput,
310 const DEVMODEW *pDevMode)
312 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
313 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
314 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
315 INT ret;
317 if(pOutput && (fwCapability == DC_BINNAMES ||
318 fwCapability == DC_FILEDEPENDENCIES ||
319 fwCapability == DC_PAPERNAMES)) {
320 /* These need A -> W translation */
321 INT size = 0, i;
322 LPSTR pOutputA;
323 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
324 dmA);
325 if(ret == -1)
326 return ret;
327 switch(fwCapability) {
328 case DC_BINNAMES:
329 size = 24;
330 break;
331 case DC_PAPERNAMES:
332 case DC_FILEDEPENDENCIES:
333 size = 64;
334 break;
336 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
337 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
338 dmA);
339 for(i = 0; i < ret; i++)
340 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
341 pOutput + (i * size), size);
342 HeapFree(GetProcessHeap(), 0, pOutputA);
343 } else {
344 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
345 (LPSTR)pOutput, dmA);
347 HeapFree(GetProcessHeap(),0,pPortA);
348 HeapFree(GetProcessHeap(),0,pDeviceA);
349 HeapFree(GetProcessHeap(),0,dmA);
350 return ret;
353 /******************************************************************
354 * DocumentPropertiesA [WINSPOOL.155]
357 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
358 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
359 LPDEVMODEA pDevModeInput,DWORD fMode )
361 LPOPENEDPRINTER lpOpenedPrinter;
362 LPSTR lpName = pDeviceName;
363 LONG ret;
365 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
366 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
369 if(!pDeviceName) {
370 LPWSTR lpNameW;
371 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
372 if(!lpOpenedPrinter) {
373 SetLastError(ERROR_INVALID_HANDLE);
374 return -1;
376 lpNameW = lpOpenedPrinter->lpsPrinterName;
377 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
380 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
381 pDevModeInput, NULL, fMode);
383 if(!pDeviceName)
384 HeapFree(GetProcessHeap(),0,lpName);
385 return ret;
389 /*****************************************************************************
390 * DocumentPropertiesW
392 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
393 LPWSTR pDeviceName,
394 LPDEVMODEW pDevModeOutput,
395 LPDEVMODEW pDevModeInput, DWORD fMode)
398 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
399 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
400 LPDEVMODEA pDevModeOutputA = NULL;
401 LONG ret;
403 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
404 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
405 fMode);
406 if(pDevModeOutput) {
407 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
408 if(ret < 0) return ret;
409 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
411 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
412 pDevModeInputA, fMode);
413 if(pDevModeOutput) {
414 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
415 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
417 if(fMode == 0 && ret > 0)
418 ret += (CCHDEVICENAME + CCHFORMNAME);
419 HeapFree(GetProcessHeap(),0,pDevModeInputA);
420 HeapFree(GetProcessHeap(),0,pDeviceNameA);
421 return ret;
424 /******************************************************************
425 * OpenPrinterA [WINSPOOL.196]
428 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
429 LPPRINTER_DEFAULTSA pDefault)
431 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
432 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
433 BOOL ret;
435 if(pDefault) {
436 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
437 pDefault->pDatatype);
438 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
439 pDefault->pDevMode);
440 DefaultW.DesiredAccess = pDefault->DesiredAccess;
441 pDefaultW = &DefaultW;
443 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
444 if(pDefault) {
445 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
446 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
448 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
449 return ret;
452 /******************************************************************
453 * OpenPrinterW [WINSPOOL.197]
456 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
457 LPPRINTER_DEFAULTSW pDefault)
459 LPOPENEDPRINTER lpOpenedPrinter;
460 HKEY hkeyPrinters, hkeyPrinter;
462 if (!lpPrinterName) {
463 WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
464 SetLastError(ERROR_INVALID_PARAMETER);
465 return FALSE;
468 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
469 pDefault);
471 /* Check Printer exists */
472 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
473 ERROR_SUCCESS) {
474 ERR("Can't create Printers key\n");
475 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
476 return FALSE;
479 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
480 != ERROR_SUCCESS) {
481 WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
482 RegCloseKey(hkeyPrinters);
483 SetLastError(ERROR_INVALID_PARAMETER);
484 return FALSE;
486 RegCloseKey(hkeyPrinter);
487 RegCloseKey(hkeyPrinters);
489 if(!phPrinter) /* This seems to be what win95 does anyway */
490 return TRUE;
492 /* Get a place in the opened printer buffer*/
493 lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntry();
494 if(!lpOpenedPrinter) {
495 ERR("Can't allocate printer slot\n");
496 SetLastError(ERROR_OUTOFMEMORY);
497 return FALSE;
500 /* Get the name of the printer */
501 lpOpenedPrinter->lpsPrinterName =
502 HEAP_strdupW( GetProcessHeap(), 0, lpPrinterName );
504 /* Get the unique handle of the printer*/
505 *phPrinter = lpOpenedPrinter->hPrinter;
507 if (pDefault != NULL)
508 FIXME("Not handling pDefault\n");
510 return TRUE;
513 /******************************************************************
514 * AddMonitorA [WINSPOOL.107]
517 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
519 FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors);
520 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
521 return FALSE;
524 /******************************************************************
525 * DeletePrinterDriverA [WINSPOOL.146]
528 BOOL WINAPI
529 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
531 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
532 debugstr_a(pDriverName));
533 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
534 return FALSE;
538 /******************************************************************
539 * DeleteMonitorA [WINSPOOL.135]
542 BOOL WINAPI
543 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
545 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
546 debugstr_a(pMonitorName));
547 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
548 return FALSE;
552 /******************************************************************
553 * DeletePortA [WINSPOOL.137]
556 BOOL WINAPI
557 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
559 FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd,
560 debugstr_a(pPortName));
561 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
562 return FALSE;
565 /******************************************************************************
566 * SetPrinterW [WINSPOOL.214]
568 BOOL WINAPI
569 SetPrinterW(
570 HANDLE hPrinter,
571 DWORD Level,
572 LPBYTE pPrinter,
573 DWORD Command) {
575 FIXME("():stub\n");
576 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
577 return FALSE;
580 /******************************************************************************
581 * WritePrinter [WINSPOOL.223]
583 BOOL WINAPI
584 WritePrinter(
585 HANDLE hPrinter,
586 LPVOID pBuf,
587 DWORD cbBuf,
588 LPDWORD pcWritten) {
590 FIXME("():stub\n");
591 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
592 return FALSE;
595 /*****************************************************************************
596 * AddFormA [WINSPOOL.103]
598 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
600 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
601 return 1;
604 /*****************************************************************************
605 * AddFormW [WINSPOOL.104]
607 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
609 FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm);
610 return 1;
613 /*****************************************************************************
614 * AddJobA [WINSPOOL.105]
616 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData,
617 DWORD cbBuf, LPDWORD pcbNeeded)
619 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
620 pcbNeeded);
621 return 1;
624 /*****************************************************************************
625 * AddJobW [WINSPOOL.106]
627 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
628 LPDWORD pcbNeeded)
630 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
631 pcbNeeded);
632 return 1;
635 /*****************************************************************************
636 * AddPrinterW [WINSPOOL.122]
638 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
640 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
641 LPDEVMODEA dmA;
642 LPDEVMODEW dmW;
643 HANDLE retval;
644 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
645 LONG size;
647 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
649 if(pName != NULL) {
650 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
651 SetLastError(ERROR_INVALID_PARAMETER);
652 return 0;
654 if(Level != 2) {
655 WARN("Level = %ld\n", Level);
656 SetLastError(ERROR_INVALID_LEVEL);
657 return 0;
659 if(!pPrinter) {
660 SetLastError(ERROR_INVALID_PARAMETER);
661 return 0;
663 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
664 ERROR_SUCCESS) {
665 ERR("Can't create Printers key\n");
666 return 0;
668 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
669 ERROR_SUCCESS) {
670 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
671 RegCloseKey(hkeyPrinter);
672 RegCloseKey(hkeyPrinters);
673 return 0;
675 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
676 ERROR_SUCCESS) {
677 ERR("Can't create Drivers key\n");
678 RegCloseKey(hkeyPrinters);
679 return 0;
681 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
682 ERROR_SUCCESS) {
683 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
684 RegCloseKey(hkeyPrinters);
685 RegCloseKey(hkeyDrivers);
686 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
687 return 0;
689 RegCloseKey(hkeyDriver);
690 RegCloseKey(hkeyDrivers);
692 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
693 WARN("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
694 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
695 RegCloseKey(hkeyPrinters);
696 return 0;
699 /* See if we can load the driver. We may need the devmode structure anyway
701 size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
702 if(size < 0) {
703 WARN("DocumentProperties fails\n");
704 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
705 return 0;
707 if(pi->pDevMode) {
708 dmW = pi->pDevMode;
709 } else {
710 dmW = HeapAlloc(GetProcessHeap(), 0, size);
711 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
714 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
715 ERROR_SUCCESS) {
716 WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
717 SetLastError(ERROR_INVALID_PRINTER_NAME);
718 RegCloseKey(hkeyPrinters);
719 if(!pi->pDevMode)
720 HeapFree(GetProcessHeap(), 0, dmW);
721 return 0;
723 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
724 (LPBYTE)&pi->Attributes, sizeof(DWORD));
725 RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
728 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
729 and we support these drivers. NT writes DEVMODEW so somehow
730 we'll need to distinguish between these when we support NT
731 drivers */
732 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
733 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
734 dmA->dmSize + dmA->dmDriverExtra);
735 HeapFree(GetProcessHeap(), 0, dmA);
736 if(!pi->pDevMode)
737 HeapFree(GetProcessHeap(), 0, dmW);
738 RegSetValueExW(hkeyPrinter, DescriptionW, 0, REG_SZ, (LPBYTE)pi->pComment,
740 RegSetValueExW(hkeyPrinter, LocationW, 0, REG_SZ, (LPBYTE)pi->pLocation,
742 RegSetValueExW(hkeyPrinter, NameW, 0, REG_SZ, (LPBYTE)pi->pPrinterName, 0);
743 RegSetValueExW(hkeyPrinter, ParametersW, 0, REG_SZ,
744 (LPBYTE)pi->pParameters, 0);
745 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)pi->pPortName, 0);
746 RegSetValueExW(hkeyPrinter, Print_ProcessorW, 0, REG_SZ,
747 (LPBYTE)pi->pPrintProcessor, 0);
748 RegSetValueExW(hkeyPrinter, Printer_DriverW, 0, REG_SZ,
749 (LPBYTE)pi->pDriverName, 0);
750 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
751 (LPBYTE)&pi->Priority, sizeof(DWORD));
752 RegSetValueExW(hkeyPrinter, Separator_FileW, 0, REG_SZ,
753 (LPBYTE)pi->pSepFile, 0);
754 RegSetValueExW(hkeyPrinter, Share_NameW, 0, REG_SZ, (LPBYTE)pi->pShareName,
756 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
757 (LPBYTE)&pi->StartTime, sizeof(DWORD));
758 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
759 (LPBYTE)&pi->Status, sizeof(DWORD));
760 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
761 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
763 RegCloseKey(hkeyPrinter);
764 RegCloseKey(hkeyPrinters);
765 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
766 ERR("OpenPrinter failing\n");
767 return 0;
769 return retval;
772 /*****************************************************************************
773 * AddPrinterA [WINSPOOL.117]
775 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
777 WCHAR *pNameW;
778 PRINTER_INFO_2W *piW;
779 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
780 HANDLE ret;
782 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
783 if(Level != 2) {
784 WARN("Level = %ld\n", Level);
785 SetLastError(ERROR_INVALID_LEVEL);
786 return 0;
788 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
789 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
791 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
793 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
794 HeapFree(GetProcessHeap(),0,pNameW);
795 return ret;
799 /*****************************************************************************
800 * ClosePrinter [WINSPOOL.126]
802 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
804 LPOPENEDPRINTER lpOpenedPrinter;
806 TRACE("Handle %d\n", hPrinter);
808 if (!pOpenedPrinterDPA)
809 return FALSE;
811 if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1)))
813 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
814 HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName);
815 lpOpenedPrinter->lpsPrinterName = NULL;
816 lpOpenedPrinter->hPrinter = -1;
818 return TRUE;
820 return FALSE;
823 /*****************************************************************************
824 * DeleteFormA [WINSPOOL.133]
826 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
828 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
829 return 1;
832 /*****************************************************************************
833 * DeleteFormW [WINSPOOL.134]
835 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
837 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
838 return 1;
841 /*****************************************************************************
842 * DeletePrinter [WINSPOOL.143]
844 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
846 LPWSTR lpNameW;
847 HKEY hkeyPrinters;
849 LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
850 if(!lpOpenedPrinter) {
851 SetLastError(ERROR_INVALID_HANDLE);
852 return FALSE;
854 lpNameW = lpOpenedPrinter->lpsPrinterName;
855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
856 ERROR_SUCCESS) {
857 ERR("Can't open Printers key\n");
858 return 0;
861 /* This should use a recursive delete see Q142491 or SHDeleteKey */
862 if(RegDeleteKeyW(hkeyPrinters, lpNameW) == ERROR_SUCCESS) {
863 SetLastError(ERROR_PRINTER_NOT_FOUND); /* ?? */
864 RegCloseKey(hkeyPrinters);
865 return 0;
868 ClosePrinter(hPrinter);
869 return TRUE;
872 /*****************************************************************************
873 * SetPrinterA [WINSPOOL.211]
875 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
876 DWORD Command)
878 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
879 return FALSE;
882 /*****************************************************************************
883 * SetJobA [WINSPOOL.209]
885 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
886 LPBYTE pJob, DWORD Command)
888 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
889 Command);
890 return FALSE;
893 /*****************************************************************************
894 * SetJobW [WINSPOOL.210]
896 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
897 LPBYTE pJob, DWORD Command)
899 FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob,
900 Command);
901 return FALSE;
904 /*****************************************************************************
905 * GetFormA [WINSPOOL.181]
907 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
908 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
910 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
911 Level,pForm,cbBuf,pcbNeeded);
912 return FALSE;
915 /*****************************************************************************
916 * GetFormW [WINSPOOL.182]
918 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
919 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
921 FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
922 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
923 return FALSE;
926 /*****************************************************************************
927 * SetFormA [WINSPOOL.207]
929 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
930 LPBYTE pForm)
932 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
933 return FALSE;
936 /*****************************************************************************
937 * SetFormW [WINSPOOL.208]
939 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
940 LPBYTE pForm)
942 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
943 return FALSE;
946 /*****************************************************************************
947 * ReadPrinter [WINSPOOL.202]
949 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
950 LPDWORD pNoBytesRead)
952 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
953 return FALSE;
956 /*****************************************************************************
957 * ResetPrinterA [WINSPOOL.203]
959 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
961 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
962 return FALSE;
965 /*****************************************************************************
966 * ResetPrinterW [WINSPOOL.204]
968 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
970 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
971 return FALSE;
974 /*****************************************************************************
975 * WINSPOOL_GetDWORDFromReg
977 * Return DWORD associated with ValueName from hkey.
979 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
981 DWORD sz = sizeof(DWORD), type, value = 0;
982 LONG ret;
984 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
986 if(ret != ERROR_SUCCESS) {
987 WARN("Got ret = %ld on name %s\n", ret, ValueName);
988 return 0;
990 if(type != REG_DWORD) {
991 ERR("Got type %ld\n", type);
992 return 0;
994 return value;
997 /*****************************************************************************
998 * WINSPOOL_GetStringFromReg
1000 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1001 * String is stored either as unicode or ascii.
1002 * Bit of a hack here to get the ValueName if we want ascii.
1004 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
1005 DWORD buflen, DWORD *needed,
1006 BOOL unicode)
1008 DWORD sz = buflen, type;
1009 LONG ret;
1011 if(unicode)
1012 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1013 else {
1014 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
1015 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
1016 HeapFree(GetProcessHeap(),0,ValueNameA);
1018 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1019 WARN("Got ret = %ld\n", ret);
1020 *needed = 0;
1021 return FALSE;
1023 *needed = sz;
1024 return TRUE;
1027 /*****************************************************************************
1028 * WINSPOOL_GetDevModeFromReg
1030 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1031 * DevMode is stored either as unicode or ascii.
1033 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
1034 LPBYTE ptr,
1035 DWORD buflen, DWORD *needed,
1036 BOOL unicode)
1038 DWORD sz = buflen, type;
1039 LONG ret;
1041 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
1042 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1043 WARN("Got ret = %ld\n", ret);
1044 *needed = 0;
1045 return FALSE;
1047 if(unicode) {
1048 sz += (CCHDEVICENAME + CCHFORMNAME);
1049 if(buflen >= sz) {
1050 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1051 memcpy(ptr, dmW, sz);
1052 HeapFree(GetProcessHeap(),0,dmW);
1055 *needed = sz;
1056 return TRUE;
1059 /*********************************************************************
1060 * WINSPOOL_GetPrinter_2
1062 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
1063 * The strings are either stored as unicode or ascii.
1065 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
1066 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1067 BOOL unicode)
1069 DWORD size, left = cbBuf;
1070 BOOL space = (cbBuf > 0);
1071 LPBYTE ptr = buf;
1073 *pcbNeeded = 0;
1075 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1076 unicode)) {
1077 if(space && size <= left) {
1078 pi2->pPrinterName = (LPWSTR)ptr;
1079 ptr += size;
1080 left -= size;
1081 } else
1082 space = FALSE;
1083 *pcbNeeded += size;
1085 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1086 unicode)) {
1087 if(space && size <= left) {
1088 pi2->pShareName = (LPWSTR)ptr;
1089 ptr += size;
1090 left -= size;
1091 } else
1092 space = FALSE;
1093 *pcbNeeded += size;
1095 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1096 unicode)) {
1097 if(space && size <= left) {
1098 pi2->pPortName = (LPWSTR)ptr;
1099 ptr += size;
1100 left -= size;
1101 } else
1102 space = FALSE;
1103 *pcbNeeded += size;
1105 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1106 &size, unicode)) {
1107 if(space && size <= left) {
1108 pi2->pDriverName = (LPWSTR)ptr;
1109 ptr += size;
1110 left -= size;
1111 } else
1112 space = FALSE;
1113 *pcbNeeded += size;
1115 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1116 unicode)) {
1117 if(space && size <= left) {
1118 pi2->pComment = (LPWSTR)ptr;
1119 ptr += size;
1120 left -= size;
1121 } else
1122 space = FALSE;
1123 *pcbNeeded += size;
1125 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1126 unicode)) {
1127 if(space && size <= left) {
1128 pi2->pLocation = (LPWSTR)ptr;
1129 ptr += size;
1130 left -= size;
1131 } else
1132 space = FALSE;
1133 *pcbNeeded += size;
1135 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1136 &size, unicode)) {
1137 if(space && size <= left) {
1138 pi2->pDevMode = (LPDEVMODEW)ptr;
1139 ptr += size;
1140 left -= size;
1141 } else
1142 space = FALSE;
1143 *pcbNeeded += size;
1145 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1146 &size, unicode)) {
1147 if(space && size <= left) {
1148 pi2->pSepFile = (LPWSTR)ptr;
1149 ptr += size;
1150 left -= size;
1151 } else
1152 space = FALSE;
1153 *pcbNeeded += size;
1155 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1156 &size, unicode)) {
1157 if(space && size <= left) {
1158 pi2->pPrintProcessor = (LPWSTR)ptr;
1159 ptr += size;
1160 left -= size;
1161 } else
1162 space = FALSE;
1163 *pcbNeeded += size;
1165 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1166 &size, unicode)) {
1167 if(space && size <= left) {
1168 pi2->pDatatype = (LPWSTR)ptr;
1169 ptr += size;
1170 left -= size;
1171 } else
1172 space = FALSE;
1173 *pcbNeeded += size;
1175 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1176 &size, unicode)) {
1177 if(space && size <= left) {
1178 pi2->pParameters = (LPWSTR)ptr;
1179 ptr += size;
1180 left -= size;
1181 } else
1182 space = FALSE;
1183 *pcbNeeded += size;
1185 if(pi2) {
1186 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1187 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1188 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1189 "Default Priority");
1190 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1191 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1194 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1195 memset(pi2, 0, sizeof(*pi2));
1197 return space;
1200 /*********************************************************************
1201 * WINSPOOL_GetPrinter_4
1203 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1205 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1206 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1207 BOOL unicode)
1209 DWORD size, left = cbBuf;
1210 BOOL space = (cbBuf > 0);
1211 LPBYTE ptr = buf;
1213 *pcbNeeded = 0;
1215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1216 unicode)) {
1217 if(space && size <= left) {
1218 pi4->pPrinterName = (LPWSTR)ptr;
1219 ptr += size;
1220 left -= size;
1221 } else
1222 space = FALSE;
1223 *pcbNeeded += size;
1225 if(pi4) {
1226 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1229 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1230 memset(pi4, 0, sizeof(*pi4));
1232 return space;
1235 /*********************************************************************
1236 * WINSPOOL_GetPrinter_5
1238 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1240 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1241 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1242 BOOL unicode)
1244 DWORD size, left = cbBuf;
1245 BOOL space = (cbBuf > 0);
1246 LPBYTE ptr = buf;
1248 *pcbNeeded = 0;
1250 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1251 unicode)) {
1252 if(space && size <= left) {
1253 pi5->pPrinterName = (LPWSTR)ptr;
1254 ptr += size;
1255 left -= size;
1256 } else
1257 space = FALSE;
1258 *pcbNeeded += size;
1260 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1261 unicode)) {
1262 if(space && size <= left) {
1263 pi5->pPortName = (LPWSTR)ptr;
1264 ptr += size;
1265 left -= size;
1266 } else
1267 space = FALSE;
1268 *pcbNeeded += size;
1270 if(pi5) {
1271 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1272 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1273 "dnsTimeout");
1274 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1275 "txTimeout");
1278 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1279 memset(pi5, 0, sizeof(*pi5));
1281 return space;
1284 /*****************************************************************************
1285 * WINSPOOL_GetPrinter
1287 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1288 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1289 * just a collection of pointers to strings.
1291 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1292 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1294 OPENEDPRINTER *lpOpenedPrinter;
1295 DWORD size, needed = 0;
1296 LPBYTE ptr = NULL;
1297 HKEY hkeyPrinter, hkeyPrinters;
1298 BOOL ret;
1300 TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1302 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1303 if(!lpOpenedPrinter) {
1304 SetLastError(ERROR_INVALID_HANDLE);
1305 return FALSE;
1307 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1308 ERROR_SUCCESS) {
1309 ERR("Can't create Printers key\n");
1310 return FALSE;
1312 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1313 != ERROR_SUCCESS) {
1314 ERR("Can't find opened printer %s in registry\n",
1315 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1316 RegCloseKey(hkeyPrinters);
1317 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1318 return FALSE;
1321 switch(Level) {
1322 case 2:
1324 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1326 size = sizeof(PRINTER_INFO_2W);
1327 if(size <= cbBuf) {
1328 ptr = pPrinter + size;
1329 cbBuf -= size;
1330 memset(pPrinter, 0, size);
1331 } else {
1332 pi2 = NULL;
1333 cbBuf = 0;
1335 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1336 unicode);
1337 needed += size;
1338 break;
1341 case 4:
1343 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1345 size = sizeof(PRINTER_INFO_4W);
1346 if(size <= cbBuf) {
1347 ptr = pPrinter + size;
1348 cbBuf -= size;
1349 memset(pPrinter, 0, size);
1350 } else {
1351 pi4 = NULL;
1352 cbBuf = 0;
1354 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1355 unicode);
1356 needed += size;
1357 break;
1361 case 5:
1363 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1365 size = sizeof(PRINTER_INFO_5W);
1366 if(size <= cbBuf) {
1367 ptr = pPrinter + size;
1368 cbBuf -= size;
1369 memset(pPrinter, 0, size);
1370 } else {
1371 pi5 = NULL;
1372 cbBuf = 0;
1375 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1376 unicode);
1377 needed += size;
1378 break;
1381 default:
1382 FIXME("Unimplemented level %ld\n", Level);
1383 SetLastError(ERROR_INVALID_LEVEL);
1384 RegCloseKey(hkeyPrinters);
1385 RegCloseKey(hkeyPrinter);
1386 return FALSE;
1389 RegCloseKey(hkeyPrinter);
1390 RegCloseKey(hkeyPrinters);
1392 TRACE("returing %d needed = %ld\n", ret, needed);
1393 if(pcbNeeded) *pcbNeeded = needed;
1394 if(!ret)
1395 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1396 return ret;
1399 /*****************************************************************************
1400 * GetPrinterW [WINSPOOL.194]
1402 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1403 DWORD cbBuf, LPDWORD pcbNeeded)
1405 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1406 TRUE);
1409 /*****************************************************************************
1410 * GetPrinterA [WINSPOOL.187]
1412 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1413 DWORD cbBuf, LPDWORD pcbNeeded)
1415 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
1416 FALSE);
1419 /*****************************************************************************
1420 * WINSPOOL_EnumPrinters
1422 * Implementation of EnumPrintersA|W
1424 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1425 DWORD dwLevel, LPBYTE lpbPrinters,
1426 DWORD cbBuf, LPDWORD lpdwNeeded,
1427 LPDWORD lpdwReturned, BOOL unicode)
1430 HKEY hkeyPrinters, hkeyPrinter;
1431 WCHAR PrinterName[255];
1432 DWORD needed = 0, number = 0;
1433 DWORD used, i, left;
1434 PBYTE pi, buf;
1436 if(lpbPrinters)
1437 memset(lpbPrinters, 0, cbBuf);
1438 if(lpdwReturned)
1439 *lpdwReturned = 0;
1441 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1442 FIXME("dwType = %08lx\n", dwType);
1443 SetLastError(ERROR_INVALID_FLAGS);
1444 return FALSE;
1447 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1448 ERROR_SUCCESS) {
1449 ERR("Can't create Printers key\n");
1450 return FALSE;
1453 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1454 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1455 RegCloseKey(hkeyPrinters);
1456 ERR("Can't query Printers key\n");
1457 return FALSE;
1459 TRACE("Found %ld printers\n", number);
1461 switch(dwLevel) {
1462 case 1:
1463 RegCloseKey(hkeyPrinters);
1464 if (lpdwReturned)
1465 *lpdwReturned = number;
1466 return TRUE;
1468 case 2:
1469 used = number * sizeof(PRINTER_INFO_2W);
1470 break;
1471 case 4:
1472 used = number * sizeof(PRINTER_INFO_4W);
1473 break;
1474 case 5:
1475 used = number * sizeof(PRINTER_INFO_5W);
1476 break;
1478 default:
1479 SetLastError(ERROR_INVALID_LEVEL);
1480 RegCloseKey(hkeyPrinters);
1481 return FALSE;
1483 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1485 for(i = 0; i < number; i++) {
1486 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1487 ERROR_SUCCESS) {
1488 ERR("Can't enum key number %ld\n", i);
1489 RegCloseKey(hkeyPrinters);
1490 return FALSE;
1492 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1493 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1494 ERROR_SUCCESS) {
1495 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1496 RegCloseKey(hkeyPrinters);
1497 return FALSE;
1500 if(cbBuf > used) {
1501 buf = lpbPrinters + used;
1502 left = cbBuf - used;
1503 } else {
1504 buf = NULL;
1505 left = 0;
1508 switch(dwLevel) {
1509 case 2:
1510 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1511 left, &needed, unicode);
1512 used += needed;
1513 if(pi) pi += sizeof(PRINTER_INFO_2W);
1514 break;
1515 case 4:
1516 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1517 left, &needed, unicode);
1518 used += needed;
1519 if(pi) pi += sizeof(PRINTER_INFO_4W);
1520 break;
1521 case 5:
1522 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1523 left, &needed, unicode);
1524 used += needed;
1525 if(pi) pi += sizeof(PRINTER_INFO_5W);
1526 break;
1527 default:
1528 ERR("Shouldn't be here!\n");
1529 RegCloseKey(hkeyPrinter);
1530 RegCloseKey(hkeyPrinters);
1531 return FALSE;
1533 RegCloseKey(hkeyPrinter);
1535 RegCloseKey(hkeyPrinters);
1537 if(lpdwNeeded)
1538 *lpdwNeeded = used;
1540 if(used > cbBuf) {
1541 if(lpbPrinters)
1542 memset(lpbPrinters, 0, cbBuf);
1543 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1544 return FALSE;
1546 if(lpdwReturned)
1547 *lpdwReturned = number;
1548 SetLastError(ERROR_SUCCESS);
1549 return TRUE;
1553 /******************************************************************
1554 * EnumPrintersW [WINSPOOL.175]
1556 * Enumerates the available printers, print servers and print
1557 * providers, depending on the specified flags, name and level.
1559 * RETURNS:
1561 * If level is set to 1:
1562 * Not implemented yet!
1563 * Returns TRUE with an empty list.
1565 * If level is set to 2:
1566 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1567 * Returns an array of PRINTER_INFO_2 data structures in the
1568 * lpbPrinters buffer. Note that according to MSDN also an
1569 * OpenPrinter should be performed on every remote printer.
1571 * If level is set to 4 (officially WinNT only):
1572 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
1573 * Fast: Only the registry is queried to retrieve printer names,
1574 * no connection to the driver is made.
1575 * Returns an array of PRINTER_INFO_4 data structures in the
1576 * lpbPrinters buffer.
1578 * If level is set to 5 (officially WinNT4/Win9x only):
1579 * Fast: Only the registry is queried to retrieve printer names,
1580 * no connection to the driver is made.
1581 * Returns an array of PRINTER_INFO_5 data structures in the
1582 * lpbPrinters buffer.
1584 * If level set to 3 or 6+:
1585 * returns zero (faillure!)
1587 * Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError
1588 * for information.
1590 * BUGS:
1591 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
1592 * - Only levels 2, 4 and 5 are implemented at the moment.
1593 * - 16-bit printer drivers are not enumerated.
1594 * - Returned amount of bytes used/needed does not match the real Windoze
1595 * implementation (as in this implementation, all strings are part
1596 * of the buffer, whereas Win32 keeps them somewhere else)
1597 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
1599 * NOTE:
1600 * - In a regular Wine installation, no registry settings for printers
1601 * exist, which makes this function return an empty list.
1603 BOOL WINAPI EnumPrintersW(
1604 DWORD dwType, /* Types of print objects to enumerate */
1605 LPWSTR lpszName, /* name of objects to enumerate */
1606 DWORD dwLevel, /* type of printer info structure */
1607 LPBYTE lpbPrinters, /* buffer which receives info */
1608 DWORD cbBuf, /* max size of buffer in bytes */
1609 LPDWORD lpdwNeeded, /* pointer to var: # bytes used/needed */
1610 LPDWORD lpdwReturned /* number of entries returned */
1613 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
1614 lpdwNeeded, lpdwReturned, TRUE);
1617 /******************************************************************
1618 * EnumPrintersA [WINSPOOL.174]
1621 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1622 DWORD dwLevel, LPBYTE lpbPrinters,
1623 DWORD cbBuf, LPDWORD lpdwNeeded,
1624 LPDWORD lpdwReturned)
1626 BOOL ret;
1627 LPWSTR lpszNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1629 ret = WINSPOOL_EnumPrinters(dwType, lpszNameW, dwLevel, lpbPrinters, cbBuf,
1630 lpdwNeeded, lpdwReturned, FALSE);
1631 HeapFree(GetProcessHeap(),0,lpszNameW);
1632 return ret;
1636 /*****************************************************************************
1637 * WINSPOOL_GetPrinterDriver
1639 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1640 DWORD Level, LPBYTE pDriverInfo,
1641 DWORD cbBuf, LPDWORD pcbNeeded,
1642 BOOL unicode)
1644 OPENEDPRINTER *lpOpenedPrinter;
1645 WCHAR DriverName[100];
1646 DWORD ret, type, size, dw, needed = 0;
1647 LPBYTE ptr = NULL;
1648 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1650 TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1651 Level,pDriverInfo,cbBuf, pcbNeeded);
1653 ZeroMemory(pDriverInfo, cbBuf);
1655 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
1656 if(!lpOpenedPrinter) {
1657 SetLastError(ERROR_INVALID_HANDLE);
1658 return FALSE;
1660 if(pEnvironment) {
1661 FIXME("pEnvironment = %s\n", debugstr_w(pEnvironment));
1662 SetLastError(ERROR_INVALID_ENVIRONMENT);
1663 return FALSE;
1665 if(Level < 1 || Level > 3) {
1666 SetLastError(ERROR_INVALID_LEVEL);
1667 return FALSE;
1669 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1670 ERROR_SUCCESS) {
1671 ERR("Can't create Printers key\n");
1672 return FALSE;
1674 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
1675 != ERROR_SUCCESS) {
1676 ERR("Can't find opened printer %s in registry\n",
1677 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1678 RegCloseKey(hkeyPrinters);
1679 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1680 return FALSE;
1682 size = sizeof(DriverName);
1683 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1684 (LPBYTE)DriverName, &size);
1685 RegCloseKey(hkeyPrinter);
1686 RegCloseKey(hkeyPrinters);
1687 if(ret != ERROR_SUCCESS) {
1688 ERR("Can't get DriverName for printer %s\n",
1689 debugstr_w(lpOpenedPrinter->lpsPrinterName));
1690 return FALSE;
1692 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1693 ERROR_SUCCESS) {
1694 ERR("Can't create Drivers key\n");
1695 return FALSE;
1697 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver)
1698 != ERROR_SUCCESS) {
1699 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1700 RegCloseKey(hkeyDrivers);
1701 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1702 return FALSE;
1705 switch(Level) {
1706 case 1:
1707 size = sizeof(DRIVER_INFO_1W);
1708 break;
1709 case 2:
1710 size = sizeof(DRIVER_INFO_2W);
1711 break;
1712 case 3:
1713 size = sizeof(DRIVER_INFO_3W);
1714 break;
1715 default:
1716 ERR("Invalid level\n");
1717 return FALSE;
1720 if(size <= cbBuf) {
1721 ptr = pDriverInfo + size;
1722 cbBuf -= size;
1723 } else
1724 cbBuf = 0;
1725 needed = size;
1727 if(unicode)
1728 size = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1729 else
1730 size = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL,
1731 NULL);
1733 if(size <= cbBuf) {
1734 cbBuf -= size;
1735 if(unicode)
1736 lstrcpyW((LPWSTR)ptr, DriverName);
1737 else
1738 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, ptr, size, NULL,
1739 NULL);
1740 if(Level == 1)
1741 ((DRIVER_INFO_1W *)pDriverInfo)->pName = (LPWSTR)ptr;
1742 else
1743 ((DRIVER_INFO_2W *)pDriverInfo)->pName = (LPWSTR)ptr;
1744 ptr += size;
1746 needed += size;
1748 if(Level > 1) {
1749 DRIVER_INFO_2W *di2 = (DRIVER_INFO_2W *)pDriverInfo;
1751 size = sizeof(dw);
1752 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1753 &size) !=
1754 ERROR_SUCCESS)
1755 WARN("Can't get Version\n");
1756 else if(cbBuf)
1757 di2->cVersion = dw;
1759 if(!pEnvironment)
1760 pEnvironment = DefaultEnvironmentW;
1761 if(unicode)
1762 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1763 else
1764 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1765 NULL, NULL);
1766 if(size <= cbBuf) {
1767 cbBuf -= size;
1768 if(unicode)
1769 lstrcpyW((LPWSTR)ptr, pEnvironment);
1770 else
1771 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, ptr, size,
1772 NULL, NULL);
1773 di2->pEnvironment = (LPWSTR)ptr;
1774 ptr += size;
1775 } else
1776 cbBuf = 0;
1777 needed += size;
1779 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, ptr, cbBuf, &size,
1780 unicode)) {
1781 if(cbBuf && size <= cbBuf) {
1782 di2->pDriverPath = (LPWSTR)ptr;
1783 ptr += size;
1784 } else
1785 cbBuf = 0;
1786 needed += size;
1788 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, ptr, cbBuf, &size,
1789 unicode)) {
1790 if(cbBuf && size <= cbBuf) {
1791 di2->pDataFile = (LPWSTR)ptr;
1792 ptr += size;
1793 } else
1794 cbBuf = 0;
1795 needed += size;
1797 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, ptr,
1798 cbBuf, &size, unicode)) {
1799 if(cbBuf && size <= cbBuf) {
1800 di2->pConfigFile = (LPWSTR)ptr;
1801 ptr += size;
1802 } else
1803 cbBuf = 0;
1804 needed += size;
1807 if(Level > 2) {
1808 DRIVER_INFO_3W *di3 = (DRIVER_INFO_3W *)pDriverInfo;
1810 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, ptr, cbBuf, &size,
1811 unicode)) {
1812 if(cbBuf && size <= cbBuf) {
1813 di3->pHelpFile = (LPWSTR)ptr;
1814 ptr += size;
1815 } else
1816 cbBuf = 0;
1817 needed += size;
1819 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, ptr, cbBuf,
1820 &size, unicode)) {
1821 if(cbBuf && size <= cbBuf) {
1822 di3->pDependentFiles = (LPWSTR)ptr;
1823 ptr += size;
1824 } else
1825 cbBuf = 0;
1826 needed += size;
1828 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, ptr, cbBuf, &size,
1829 unicode)) {
1830 if(cbBuf && size <= cbBuf) {
1831 di3->pMonitorName = (LPWSTR)ptr;
1832 ptr += size;
1833 } else
1834 cbBuf = 0;
1835 needed += size;
1837 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, ptr, cbBuf, &size,
1838 unicode)) {
1839 if(cbBuf && size <= cbBuf) {
1840 di3->pDefaultDataType = (LPWSTR)ptr;
1841 ptr += size;
1842 } else
1843 cbBuf = 0;
1844 needed += size;
1847 RegCloseKey(hkeyDriver);
1848 RegCloseKey(hkeyDrivers);
1850 if(pcbNeeded) *pcbNeeded = needed;
1851 if(cbBuf) return TRUE;
1852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1853 return FALSE;
1856 /*****************************************************************************
1857 * GetPrinterDriverA [WINSPOOL.190]
1859 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1860 DWORD Level, LPBYTE pDriverInfo,
1861 DWORD cbBuf, LPDWORD pcbNeeded)
1863 BOOL ret;
1864 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
1865 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
1866 cbBuf, pcbNeeded, FALSE);
1867 HeapFree(GetProcessHeap(),0,pEnvW);
1868 return ret;
1870 /*****************************************************************************
1871 * GetPrinterDriverW [WINSPOOL.193]
1873 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
1874 DWORD Level, LPBYTE pDriverInfo,
1875 DWORD cbBuf, LPDWORD pcbNeeded)
1877 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
1878 pDriverInfo, cbBuf, pcbNeeded, TRUE);
1881 /*****************************************************************************
1882 * GetPrinterDriverDirectoryA [WINSPOOL.191]
1884 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
1885 DWORD Level, LPBYTE pDriverDirectory,
1886 DWORD cbBuf, LPDWORD pcbNeeded)
1888 DWORD needed;
1890 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1891 pDriverDirectory, cbBuf, pcbNeeded);
1892 if(pName != NULL) {
1893 FIXME("pName = `%s' - unsupported\n", pName);
1894 SetLastError(ERROR_INVALID_PARAMETER);
1895 return FALSE;
1897 if(pEnvironment != NULL) {
1898 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1899 SetLastError(ERROR_INVALID_ENVIRONMENT);
1900 return FALSE;
1902 if(Level != 1) /* win95 ignores this so we just carry on */
1903 WARN("Level = %ld - assuming 1\n", Level);
1905 /* FIXME should read from registry */
1906 needed = GetSystemDirectoryA(pDriverDirectory, cbBuf);
1907 needed++;
1908 if(pcbNeeded)
1909 *pcbNeeded = needed;
1910 if(needed > cbBuf) {
1911 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1912 return FALSE;
1914 return TRUE;
1918 /*****************************************************************************
1919 * GetPrinterDriverDirectoryW [WINSPOOL.192]
1921 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
1922 DWORD Level, LPBYTE pDriverDirectory,
1923 DWORD cbBuf, LPDWORD pcbNeeded)
1925 LPSTR pNameA = NULL, pEnvironmentA = NULL;
1926 BOOL ret;
1928 if(pName)
1929 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1930 if(pEnvironment)
1931 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1932 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1933 pDriverDirectory, cbBuf, pcbNeeded );
1934 if(pNameA)
1935 HeapFree( GetProcessHeap(), 0, pNameA );
1936 if(pEnvironmentA)
1937 HeapFree( GetProcessHeap(), 0, pEnvironment );
1939 return ret;
1942 /*****************************************************************************
1943 * AddPrinterDriverA [WINSPOOL.120]
1945 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1947 DRIVER_INFO_3A di3;
1948 HKEY hkeyDrivers, hkeyName;
1950 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1952 if(level != 2 && level != 3) {
1953 SetLastError(ERROR_INVALID_LEVEL);
1954 return FALSE;
1956 if(pName != NULL) {
1957 FIXME("pName= `%s' - unsupported\n", pName);
1958 SetLastError(ERROR_INVALID_PARAMETER);
1959 return FALSE;
1961 if(!pDriverInfo) {
1962 WARN("pDriverInfo == NULL");
1963 SetLastError(ERROR_INVALID_PARAMETER);
1964 return FALSE;
1967 if(level == 3)
1968 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1969 else {
1970 memset(&di3, 0, sizeof(di3));
1971 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1974 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1975 !di3.pDataFile) {
1976 SetLastError(ERROR_INVALID_PARAMETER);
1977 return FALSE;
1979 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
1980 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
1981 if(!di3.pHelpFile) di3.pHelpFile = "";
1982 if(!di3.pMonitorName) di3.pMonitorName = "";
1984 if(di3.pEnvironment) {
1985 FIXME("pEnvironment = `%s'\n", di3.pEnvironment);
1986 SetLastError(ERROR_INVALID_ENVIRONMENT);
1987 return FALSE;
1989 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1990 ERROR_SUCCESS) {
1991 ERR("Can't create Drivers key\n");
1992 return FALSE;
1995 if(level == 2) { /* apparently can't overwrite with level2 */
1996 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
1997 RegCloseKey(hkeyName);
1998 RegCloseKey(hkeyDrivers);
1999 WARN("Trying to create existing printer driver `%s'\n", di3.pName);
2000 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2001 return FALSE;
2004 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2005 RegCloseKey(hkeyDrivers);
2006 ERR("Can't create Name key\n");
2007 return FALSE;
2009 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile,
2011 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0);
2012 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0);
2013 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion,
2014 sizeof(DWORD));
2015 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0);
2016 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2017 di3.pDependentFiles, 0);
2018 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0);
2019 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0);
2020 RegCloseKey(hkeyName);
2021 RegCloseKey(hkeyDrivers);
2023 return TRUE;
2025 /*****************************************************************************
2026 * AddPrinterDriverW [WINSPOOL.121]
2028 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2029 LPBYTE pDriverInfo)
2031 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2032 level,pDriverInfo);
2033 return FALSE;
2037 /*****************************************************************************
2038 * PrinterProperties [WINSPOOL.201]
2040 * Displays a dialog to set the properties of the printer.
2042 * RETURNS
2043 * nonzero on succes or zero on faillure
2045 * BUGS
2046 * implemented as stub only
2048 BOOL WINAPI PrinterProperties(HWND hWnd, /* handle to parent window */
2049 HANDLE hPrinter /* handle to printer object */
2051 FIXME("(%d,%d): stub\n", hWnd, hPrinter);
2052 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2053 return FALSE;
2056 /*****************************************************************************
2057 * EnumJobsA [WINSPOOL.162]
2060 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2061 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2062 LPDWORD pcReturned)
2064 FIXME("stub\n");
2065 if(pcbNeeded) *pcbNeeded = 0;
2066 if(pcReturned) *pcReturned = 0;
2067 return TRUE;
2071 /*****************************************************************************
2072 * EnumJobsW [WINSPOOL.163]
2075 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2076 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2077 LPDWORD pcReturned)
2079 FIXME("stub\n");
2080 if(pcbNeeded) *pcbNeeded = 0;
2081 if(pcReturned) *pcReturned = 0;
2082 return TRUE;