4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
18 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(winspool)
25 CRITICAL_SECTION PRINT32_RegistryBlocker;
27 typedef struct _OPENEDPRINTER
29 LPWSTR lpsPrinterName;
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',
53 static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
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',
65 static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
67 static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
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()
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(),
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(),
118 sizeof(OPENEDPRINTER));
119 pOpenedPrinter->hPrinter = i + 1;
120 WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter);
121 return pOpenedPrinter;
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)))
140 pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1);
142 return pOpenedPrinter;
145 /***********************************************************
148 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
151 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
154 Formname = (dmA->dmSize > off_formname);
155 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
156 MultiByteToWideChar(CP_ACP, 0, dmA->dmDeviceName, -1, dmW->dmDeviceName,
159 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
160 dmA->dmSize - CCHDEVICENAME);
162 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
163 off_formname - CCHDEVICENAME);
164 MultiByteToWideChar(CP_ACP, 0, dmA->dmFormName, -1, dmW->dmFormName,
166 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
167 (off_formname + CCHFORMNAME));
170 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
175 /***********************************************************
177 * Creates a unicode copy of supplied devmode on heap
179 static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
184 ptrdiff_t off_formname;
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 /***********************************************************
198 * Creates an ascii copy of supplied devmode on heap
200 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
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);
214 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
215 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
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)));
225 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
230 /***********************************************************
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);
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)
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);
279 /******************************************************************
280 * DeviceCapabilitiesA [WINSPOOL.150 & WINSPOOL.151]
283 INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap,
284 LPSTR pOutput, LPDEVMODEA lpdm)
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) );
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 );
302 /*****************************************************************************
303 * DeviceCapabilitiesW [WINSPOOL.152]
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);
317 if(pOutput && (fwCapability == DC_BINNAMES ||
318 fwCapability == DC_FILEDEPENDENCIES ||
319 fwCapability == DC_PAPERNAMES)) {
320 /* These need A -> W translation */
323 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
327 switch(fwCapability) {
332 case DC_FILEDEPENDENCIES:
336 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
337 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
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);
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);
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;
365 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
366 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
371 lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
372 if(!lpOpenedPrinter) {
373 SetLastError(ERROR_INVALID_HANDLE);
376 lpNameW = lpOpenedPrinter->lpsPrinterName;
377 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
380 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
381 pDevModeInput, NULL, fMode);
384 HeapFree(GetProcessHeap(),0,lpName);
389 /*****************************************************************************
390 * DocumentPropertiesW
392 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
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;
403 TRACE("(%d,%d,%s,%p,%p,%ld)\n",
404 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
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);
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);
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;
436 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
437 pDefault->pDatatype);
438 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
440 DefaultW.DesiredAccess = pDefault->DesiredAccess;
441 pDefaultW = &DefaultW;
443 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
445 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
446 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
448 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
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);
468 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
471 /* Check Printer exists */
472 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
474 ERR("Can't create Printers key\n");
475 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
479 if(RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
481 WARN("Can't find printer %s in registry\n", debugstr_w(lpPrinterName));
482 RegCloseKey(hkeyPrinters);
483 SetLastError(ERROR_INVALID_PARAMETER);
486 RegCloseKey(hkeyPrinter);
487 RegCloseKey(hkeyPrinters);
489 if(!phPrinter) /* This seems to be what win95 does anyway */
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);
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");
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);
524 /******************************************************************
525 * DeletePrinterDriverA [WINSPOOL.146]
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);
538 /******************************************************************
539 * DeleteMonitorA [WINSPOOL.135]
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);
552 /******************************************************************
553 * DeletePortA [WINSPOOL.137]
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);
565 /******************************************************************************
566 * SetPrinterW [WINSPOOL.214]
576 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
580 /******************************************************************************
581 * WritePrinter [WINSPOOL.223]
591 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
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);
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);
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,
624 /*****************************************************************************
625 * AddJobW [WINSPOOL.106]
627 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf,
630 FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf,
635 /*****************************************************************************
636 * AddPrinterW [WINSPOOL.122]
638 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
640 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
644 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
647 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
650 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
651 SetLastError(ERROR_INVALID_PARAMETER);
655 WARN("Level = %ld\n", Level);
656 SetLastError(ERROR_INVALID_LEVEL);
660 SetLastError(ERROR_INVALID_PARAMETER);
663 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
665 ERR("Can't create Printers key\n");
668 if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
670 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
671 RegCloseKey(hkeyPrinter);
672 RegCloseKey(hkeyPrinters);
675 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
677 ERR("Can't create Drivers key\n");
678 RegCloseKey(hkeyPrinters);
681 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
683 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
684 RegCloseKey(hkeyPrinters);
685 RegCloseKey(hkeyDrivers);
686 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
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);
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);
703 WARN("DocumentProperties fails\n");
704 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
710 dmW = HeapAlloc(GetProcessHeap(), 0, size);
711 DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
714 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
716 WARN("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
717 SetLastError(ERROR_INVALID_PRINTER_NAME);
718 RegCloseKey(hkeyPrinters);
720 HeapFree(GetProcessHeap(), 0, dmW);
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
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);
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");
772 /*****************************************************************************
773 * AddPrinterA [WINSPOOL.117]
775 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
778 PRINTER_INFO_2W *piW;
779 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
782 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
784 WARN("Level = %ld\n", Level);
785 SetLastError(ERROR_INVALID_LEVEL);
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);
799 /*****************************************************************************
800 * ClosePrinter [WINSPOOL.126]
802 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
804 LPOPENEDPRINTER lpOpenedPrinter;
806 TRACE("Handle %d\n", hPrinter);
808 if (!pOpenedPrinterDPA)
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;
823 /*****************************************************************************
824 * DeleteFormA [WINSPOOL.133]
826 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
828 FIXME("(%d,%s): stub\n", hPrinter, pFormName);
832 /*****************************************************************************
833 * DeleteFormW [WINSPOOL.134]
835 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
837 FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName));
841 /*****************************************************************************
842 * DeletePrinter [WINSPOOL.143]
844 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
849 LPOPENEDPRINTER lpOpenedPrinter = WINSPOOL_GetOpenedPrinter(hPrinter);
850 if(!lpOpenedPrinter) {
851 SetLastError(ERROR_INVALID_HANDLE);
854 lpNameW = lpOpenedPrinter->lpsPrinterName;
855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
857 ERR("Can't open Printers key\n");
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);
868 ClosePrinter(hPrinter);
872 /*****************************************************************************
873 * SetPrinterA [WINSPOOL.211]
875 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
878 FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
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,
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,
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);
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);
926 /*****************************************************************************
927 * SetFormA [WINSPOOL.207]
929 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
932 FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
936 /*****************************************************************************
937 * SetFormW [WINSPOOL.208]
939 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
942 FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
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);
956 /*****************************************************************************
957 * ResetPrinterA [WINSPOOL.203]
959 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
961 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
965 /*****************************************************************************
966 * ResetPrinterW [WINSPOOL.204]
968 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
970 FIXME("(%d, %p): stub\n", hPrinter, pDefault);
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;
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);
990 if(type != REG_DWORD) {
991 ERR("Got type %ld\n", type);
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,
1008 DWORD sz = buflen, type;
1012 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
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);
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,
1035 DWORD buflen, DWORD *needed,
1038 DWORD sz = buflen, type;
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);
1048 sz += (CCHDEVICENAME + CCHFORMNAME);
1050 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
1051 memcpy(ptr, dmW, sz);
1052 HeapFree(GetProcessHeap(),0,dmW);
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,
1069 DWORD size, left = cbBuf;
1070 BOOL space = (cbBuf > 0);
1075 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1077 if(space && size <= left) {
1078 pi2->pPrinterName = (LPWSTR)ptr;
1085 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
1087 if(space && size <= left) {
1088 pi2->pShareName = (LPWSTR)ptr;
1095 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1097 if(space && size <= left) {
1098 pi2->pPortName = (LPWSTR)ptr;
1105 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
1107 if(space && size <= left) {
1108 pi2->pDriverName = (LPWSTR)ptr;
1115 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
1117 if(space && size <= left) {
1118 pi2->pComment = (LPWSTR)ptr;
1125 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
1127 if(space && size <= left) {
1128 pi2->pLocation = (LPWSTR)ptr;
1135 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
1137 if(space && size <= left) {
1138 pi2->pDevMode = (LPDEVMODEW)ptr;
1145 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
1147 if(space && size <= left) {
1148 pi2->pSepFile = (LPWSTR)ptr;
1155 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
1157 if(space && size <= left) {
1158 pi2->pPrintProcessor = (LPWSTR)ptr;
1165 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1167 if(space && size <= left) {
1168 pi2->pDatatype = (LPWSTR)ptr;
1175 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1177 if(space && size <= left) {
1178 pi2->pParameters = (LPWSTR)ptr;
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));
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,
1209 DWORD size, left = cbBuf;
1210 BOOL space = (cbBuf > 0);
1215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1217 if(space && size <= left) {
1218 pi4->pPrinterName = (LPWSTR)ptr;
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));
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,
1244 DWORD size, left = cbBuf;
1245 BOOL space = (cbBuf > 0);
1250 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1252 if(space && size <= left) {
1253 pi5->pPrinterName = (LPWSTR)ptr;
1260 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1262 if(space && size <= left) {
1263 pi5->pPortName = (LPWSTR)ptr;
1271 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1272 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1274 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1278 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1279 memset(pi5, 0, sizeof(*pi5));
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;
1297 HKEY hkeyPrinter, hkeyPrinters;
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);
1307 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1309 ERR("Can't create Printers key\n");
1312 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
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); /* ? */
1324 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1326 size = sizeof(PRINTER_INFO_2W);
1328 ptr = pPrinter + size;
1330 memset(pPrinter, 0, size);
1335 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1343 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1345 size = sizeof(PRINTER_INFO_4W);
1347 ptr = pPrinter + size;
1349 memset(pPrinter, 0, size);
1354 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1363 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1365 size = sizeof(PRINTER_INFO_5W);
1367 ptr = pPrinter + size;
1369 memset(pPrinter, 0, size);
1375 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1382 FIXME("Unimplemented level %ld\n", Level);
1383 SetLastError(ERROR_INVALID_LEVEL);
1384 RegCloseKey(hkeyPrinters);
1385 RegCloseKey(hkeyPrinter);
1389 RegCloseKey(hkeyPrinter);
1390 RegCloseKey(hkeyPrinters);
1392 TRACE("returing %d needed = %ld\n", ret, needed);
1393 if(pcbNeeded) *pcbNeeded = needed;
1395 SetLastError(ERROR_INSUFFICIENT_BUFFER);
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,
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,
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;
1437 memset(lpbPrinters, 0, cbBuf);
1441 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1442 FIXME("dwType = %08lx\n", dwType);
1443 SetLastError(ERROR_INVALID_FLAGS);
1447 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1449 ERR("Can't create Printers key\n");
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");
1459 TRACE("Found %ld printers\n", number);
1463 RegCloseKey(hkeyPrinters);
1465 *lpdwReturned = number;
1469 used = number * sizeof(PRINTER_INFO_2W);
1472 used = number * sizeof(PRINTER_INFO_4W);
1475 used = number * sizeof(PRINTER_INFO_5W);
1479 SetLastError(ERROR_INVALID_LEVEL);
1480 RegCloseKey(hkeyPrinters);
1483 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1485 for(i = 0; i < number; i++) {
1486 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1488 ERR("Can't enum key number %ld\n", i);
1489 RegCloseKey(hkeyPrinters);
1492 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1493 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1495 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1496 RegCloseKey(hkeyPrinters);
1501 buf = lpbPrinters + used;
1502 left = cbBuf - used;
1510 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1511 left, &needed, unicode);
1513 if(pi) pi += sizeof(PRINTER_INFO_2W);
1516 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1517 left, &needed, unicode);
1519 if(pi) pi += sizeof(PRINTER_INFO_4W);
1522 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1523 left, &needed, unicode);
1525 if(pi) pi += sizeof(PRINTER_INFO_5W);
1528 ERR("Shouldn't be here!\n");
1529 RegCloseKey(hkeyPrinter);
1530 RegCloseKey(hkeyPrinters);
1533 RegCloseKey(hkeyPrinter);
1535 RegCloseKey(hkeyPrinters);
1542 memset(lpbPrinters, 0, cbBuf);
1543 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1547 *lpdwReturned = number;
1548 SetLastError(ERROR_SUCCESS);
1553 /******************************************************************
1554 * EnumPrintersW [WINSPOOL.175]
1556 * Enumerates the available printers, print servers and print
1557 * providers, depending on the specified flags, name and level.
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
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.
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)
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);
1636 /*****************************************************************************
1637 * WINSPOOL_GetPrinterDriver
1639 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1640 DWORD Level, LPBYTE pDriverInfo,
1641 DWORD cbBuf, LPDWORD pcbNeeded,
1644 OPENEDPRINTER *lpOpenedPrinter;
1645 WCHAR DriverName[100];
1646 DWORD ret, type, size, dw, needed = 0;
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);
1661 FIXME("pEnvironment = %s\n", debugstr_w(pEnvironment));
1662 SetLastError(ERROR_INVALID_ENVIRONMENT);
1665 if(Level < 1 || Level > 3) {
1666 SetLastError(ERROR_INVALID_LEVEL);
1669 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1671 ERR("Can't create Printers key\n");
1674 if(RegOpenKeyW(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter)
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); /* ? */
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));
1692 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1694 ERR("Can't create Drivers key\n");
1697 if(RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver)
1699 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
1700 RegCloseKey(hkeyDrivers);
1701 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1707 size = sizeof(DRIVER_INFO_1W);
1710 size = sizeof(DRIVER_INFO_2W);
1713 size = sizeof(DRIVER_INFO_3W);
1716 ERR("Invalid level\n");
1721 ptr = pDriverInfo + size;
1728 size = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1730 size = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL,
1736 lstrcpyW((LPWSTR)ptr, DriverName);
1738 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, ptr, size, NULL,
1741 ((DRIVER_INFO_1W *)pDriverInfo)->pName = (LPWSTR)ptr;
1743 ((DRIVER_INFO_2W *)pDriverInfo)->pName = (LPWSTR)ptr;
1749 DRIVER_INFO_2W *di2 = (DRIVER_INFO_2W *)pDriverInfo;
1752 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw,
1755 WARN("Can't get Version\n");
1760 pEnvironment = DefaultEnvironmentW;
1762 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1764 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1769 lstrcpyW((LPWSTR)ptr, pEnvironment);
1771 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, ptr, size,
1773 di2->pEnvironment = (LPWSTR)ptr;
1779 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, ptr, cbBuf, &size,
1781 if(cbBuf && size <= cbBuf) {
1782 di2->pDriverPath = (LPWSTR)ptr;
1788 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, ptr, cbBuf, &size,
1790 if(cbBuf && size <= cbBuf) {
1791 di2->pDataFile = (LPWSTR)ptr;
1797 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, ptr,
1798 cbBuf, &size, unicode)) {
1799 if(cbBuf && size <= cbBuf) {
1800 di2->pConfigFile = (LPWSTR)ptr;
1808 DRIVER_INFO_3W *di3 = (DRIVER_INFO_3W *)pDriverInfo;
1810 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, ptr, cbBuf, &size,
1812 if(cbBuf && size <= cbBuf) {
1813 di3->pHelpFile = (LPWSTR)ptr;
1819 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, ptr, cbBuf,
1821 if(cbBuf && size <= cbBuf) {
1822 di3->pDependentFiles = (LPWSTR)ptr;
1828 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, ptr, cbBuf, &size,
1830 if(cbBuf && size <= cbBuf) {
1831 di3->pMonitorName = (LPWSTR)ptr;
1837 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, ptr, cbBuf, &size,
1839 if(cbBuf && size <= cbBuf) {
1840 di3->pDefaultDataType = (LPWSTR)ptr;
1847 RegCloseKey(hkeyDriver);
1848 RegCloseKey(hkeyDrivers);
1850 if(pcbNeeded) *pcbNeeded = needed;
1851 if(cbBuf) return TRUE;
1852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1856 /*****************************************************************************
1857 * GetPrinterDriverA [WINSPOOL.190]
1859 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
1860 DWORD Level, LPBYTE pDriverInfo,
1861 DWORD cbBuf, LPDWORD pcbNeeded)
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);
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)
1890 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
1891 pDriverDirectory, cbBuf, pcbNeeded);
1893 FIXME("pName = `%s' - unsupported\n", pName);
1894 SetLastError(ERROR_INVALID_PARAMETER);
1897 if(pEnvironment != NULL) {
1898 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
1899 SetLastError(ERROR_INVALID_ENVIRONMENT);
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);
1909 *pcbNeeded = needed;
1910 if(needed > cbBuf) {
1911 SetLastError(ERROR_INSUFFICIENT_BUFFER);
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;
1929 pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName );
1931 pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment );
1932 ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level,
1933 pDriverDirectory, cbBuf, pcbNeeded );
1935 HeapFree( GetProcessHeap(), 0, pNameA );
1937 HeapFree( GetProcessHeap(), 0, pEnvironment );
1942 /*****************************************************************************
1943 * AddPrinterDriverA [WINSPOOL.120]
1945 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
1948 HKEY hkeyDrivers, hkeyName;
1950 TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo);
1952 if(level != 2 && level != 3) {
1953 SetLastError(ERROR_INVALID_LEVEL);
1957 FIXME("pName= `%s' - unsupported\n", pName);
1958 SetLastError(ERROR_INVALID_PARAMETER);
1962 WARN("pDriverInfo == NULL");
1963 SetLastError(ERROR_INVALID_PARAMETER);
1968 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
1970 memset(&di3, 0, sizeof(di3));
1971 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
1974 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
1976 SetLastError(ERROR_INVALID_PARAMETER);
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);
1989 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) !=
1991 ERR("Can't create Drivers key\n");
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);
2004 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2005 RegCloseKey(hkeyDrivers);
2006 ERR("Can't create Name key\n");
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,
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);
2025 /*****************************************************************************
2026 * AddPrinterDriverW [WINSPOOL.121]
2028 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
2031 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
2037 /*****************************************************************************
2038 * PrinterProperties [WINSPOOL.201]
2040 * Displays a dialog to set the properties of the printer.
2043 * nonzero on succes or zero on faillure
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);
2056 /*****************************************************************************
2057 * EnumJobsA [WINSPOOL.162]
2060 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2061 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2065 if(pcbNeeded) *pcbNeeded = 0;
2066 if(pcReturned) *pcReturned = 0;
2071 /*****************************************************************************
2072 * EnumJobsW [WINSPOOL.163]
2075 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
2076 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
2080 if(pcbNeeded) *pcbNeeded = 0;
2081 if(pcReturned) *pcReturned = 0;