/* * WINSPOOL functions * * Copyright 1996 John Harvey * Copyright 1998 Andreas Mohr * Copyright 1999 Klaas van Gend, Huw D M Davies */ #include #include #include #include "winspool.h" #include "winbase.h" #include "winerror.h" #include "winreg.h" #include "debugtools.h" #include "heap.h" #include "commctrl.h" DEFAULT_DEBUG_CHANNEL(winspool) CRITICAL_SECTION PRINT32_RegistryBlocker; typedef struct _OPENEDPRINTERA { LPSTR lpsPrinterName; HANDLE hPrinter; LPPRINTER_DEFAULTSA lpDefault; } OPENEDPRINTERA, *LPOPENEDPRINTERA; /* The OpenedPrinter Table dynamic array */ static HDPA pOpenedPrinterDPA = NULL; extern HDPA (WINAPI* WINSPOOL_DPA_CreateEx) (INT, HANDLE); extern LPVOID (WINAPI* WINSPOOL_DPA_GetPtr) (const HDPA, INT); extern INT (WINAPI* WINSPOOL_DPA_InsertPtr) (const HDPA, INT, LPVOID); static char Printers[] = "System\\CurrentControlSet\\control\\Print\\Printers\\"; static char Drivers[] = "System\\CurrentControlSet\\control\\Print\\Environments\\Windows 4.0\\Drivers\\"; /* Hmm, well */ /****************************************************************** * WINSPOOL_GetOpenedPrinterEntryA * Get the first place empty in the opened printer table */ static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterEntryA() { int i; LPOPENEDPRINTERA pOpenedPrinter; /* * Create the opened printers' handle dynamic array. */ if (!pOpenedPrinterDPA) { pOpenedPrinterDPA = WINSPOOL_DPA_CreateEx(10, GetProcessHeap()); for (i = 0; i < 10; i++) { pOpenedPrinter = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OPENEDPRINTERA)); pOpenedPrinter->hPrinter = -1; WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter); } } /* * Search for a handle not yet allocated. */ for (i = 0; i < pOpenedPrinterDPA->nItemCount; i++) { pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, i); if (pOpenedPrinter->hPrinter == -1) { pOpenedPrinter->hPrinter = i + 1; return pOpenedPrinter; } } /* * Didn't find one, insert new element in the array. */ if (i == pOpenedPrinterDPA->nItemCount) { pOpenedPrinter = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OPENEDPRINTERA)); pOpenedPrinter->hPrinter = i + 1; WINSPOOL_DPA_InsertPtr(pOpenedPrinterDPA, i, pOpenedPrinter); return pOpenedPrinter; } return NULL; } /****************************************************************** * WINSPOOL_GetOpenedPrinterA * Get the pointer to the opened printer referred by the handle */ static LPOPENEDPRINTERA WINSPOOL_GetOpenedPrinterA(int printerHandle) { LPOPENEDPRINTERA pOpenedPrinter; if(!pOpenedPrinterDPA) return NULL; if((printerHandle <=0) || (printerHandle > (pOpenedPrinterDPA->nItemCount - 1))) return NULL; pOpenedPrinter = WINSPOOL_DPA_GetPtr(pOpenedPrinterDPA, printerHandle-1); return pOpenedPrinter; } /****************************************************************** * DeviceCapabilitiesA [WINSPOOL.151] * */ INT WINAPI DeviceCapabilitiesA(LPCSTR pDeivce,LPCSTR pPort, WORD cap, LPSTR pOutput, LPDEVMODEA lpdm) { INT ret; ret = GDI_CallDeviceCapabilities16(pDeivce, pPort, cap, pOutput, lpdm); /* If DC_PAPERSIZE map POINT16s to POINTs */ if(ret != -1 && cap == DC_PAPERSIZE && pOutput) { POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) ); INT i; memcpy(tmp, pOutput, ret * sizeof(POINT16)); for(i = 0; i < ret; i++) CONV_POINT16TO32(tmp + i, (POINT*)pOutput + i); HeapFree( GetProcessHeap(), 0, tmp ); } return ret; } /***************************************************************************** * DeviceCapabilitiesW */ INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW *pDevMode) { FIXME("(%p,%p,%d,%p,%p): stub\n", pDevice, pPort, fwCapability, pOutput, pDevMode); return -1; } /****************************************************************** * DocumentPropertiesA [WINSPOOL.155] * */ LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter, LPSTR pDeviceName, LPDEVMODEA pDevModeOutput, LPDEVMODEA pDevModeInput,DWORD fMode ) { LPOPENEDPRINTERA lpOpenedPrinter; LPSTR lpName = pDeviceName; TRACE("(%d,%d,%s,%p,%p,%ld)\n", hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode ); if(!pDeviceName) { lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter); if(!lpOpenedPrinter) { SetLastError(ERROR_INVALID_HANDLE); return -1; } lpName = lpOpenedPrinter->lpsPrinterName; } return GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:", pDevModeInput, NULL, fMode); } /***************************************************************************** * DocumentPropertiesW */ LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, LPDEVMODEW pDevModeOutput, LPDEVMODEW pDevModeInput, DWORD fMode) { FIXME("(%d,%d,%s,%p,%p,%ld): stub\n", hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput, fMode); return -1; } /****************************************************************** * OpenPrinterA [WINSPOOL.196] * */ BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSA pDefault) { /* Not implemented: use the DesiredAccess of pDefault to set the access rights to the printer */ LPOPENEDPRINTERA lpOpenedPrinter; HKEY hkeyPrinters, hkeyPrinter; if (!lpPrinterName) { WARN("(printerName: NULL, pDefault %p Ret: False\n", pDefault); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } TRACE("(printerName: %s, pDefault %p\n", lpPrinterName, pDefault); /* Check Printer exists */ if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS) { ERR("Can't create Printers key\n"); SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */ return FALSE; } if(RegOpenKeyA(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS) { WARN("Can't find printer `%s' in registry\n", lpPrinterName); RegCloseKey(hkeyPrinters); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); if(!phPrinter) /* This seems to be what win95 does anyway */ return TRUE; /* Get a place in the opened printer buffer*/ lpOpenedPrinter = WINSPOOL_GetOpenedPrinterEntryA(); if(!lpOpenedPrinter) { ERR("Can't allocate printer slot\n"); SetLastError(ERROR_OUTOFMEMORY); return FALSE; } /* Get the name of the printer */ lpOpenedPrinter->lpsPrinterName = HEAP_strdupA( GetProcessHeap(), 0, lpPrinterName ); /* Get the unique handle of the printer*/ *phPrinter = lpOpenedPrinter->hPrinter; if (pDefault != NULL) { lpOpenedPrinter->lpDefault = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTER_DEFAULTSA)); lpOpenedPrinter->lpDefault->pDevMode = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVMODEA)); memcpy(lpOpenedPrinter->lpDefault->pDevMode, pDefault->pDevMode, sizeof(DEVMODEA)); lpOpenedPrinter->lpDefault->pDatatype = HEAP_strdupA( GetProcessHeap(), 0, pDefault->pDatatype ); lpOpenedPrinter->lpDefault->DesiredAccess = pDefault->DesiredAccess; } return TRUE; } /****************************************************************** * OpenPrinterW [WINSPOOL.197] * */ BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault) { FIXME("(%s,%p,%p):stub\n",debugstr_w(lpPrinterName), phPrinter, pDefault); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************** * AddMonitorA [WINSPOOL.107] * */ BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors) { FIXME("(%s,%lx,%p):stub!\n", pName, Level, pMonitors); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************** * DeletePrinterDriverA [WINSPOOL.146] * */ BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName) { FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment), debugstr_a(pDriverName)); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************** * DeleteMonitorA [WINSPOOL.135] * */ BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName) { FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment), debugstr_a(pMonitorName)); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************** * DeletePortA [WINSPOOL.137] * */ BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName) { FIXME("(%s,0x%08x,%s):stub\n",debugstr_a(pName),hWnd, debugstr_a(pPortName)); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************************** * SetPrinterW [WINSPOOL.214] */ BOOL WINAPI SetPrinterW( HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command) { FIXME("():stub\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************************** * WritePrinter [WINSPOOL.223] */ BOOL WINAPI WritePrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten) { FIXME("():stub\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /***************************************************************************** * AddFormA [WINSPOOL.103] */ BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm) { FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm); return 1; } /***************************************************************************** * AddFormW [WINSPOOL.104] */ BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm) { FIXME("(%d,%ld,%p): stub\n", hPrinter, Level, pForm); return 1; } /***************************************************************************** * AddJobA [WINSPOOL.105] */ BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf, pcbNeeded); return 1; } /***************************************************************************** * AddJobW [WINSPOOL.106] */ BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pData, cbBuf, pcbNeeded); return 1; } /***************************************************************************** * AddPrinterA [WINSPOOL.117] */ HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter) { PRINTER_INFO_2A *pi = (PRINTER_INFO_2A *) pPrinter; HANDLE retval; HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers; TRACE("(%s,%ld,%p)\n", pName, Level, pPrinter); if(pName != NULL) { FIXME("pName = `%s' - unsupported\n", pName); SetLastError(ERROR_INVALID_PARAMETER); return 0; } if(Level != 2) { WARN("Level = %ld\n", Level); SetLastError(ERROR_INVALID_LEVEL); return 0; } if(!pPrinter) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS) { ERR("Can't create Printers key\n"); return 0; } if(RegOpenKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) == ERROR_SUCCESS) { SetLastError(ERROR_PRINTER_ALREADY_EXISTS); RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); return 0; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) != ERROR_SUCCESS) { ERR("Can't create Drivers key\n"); RegCloseKey(hkeyPrinters); return 0; } if(RegOpenKeyA(hkeyDrivers, pi->pDriverName, &hkeyDriver) != ERROR_SUCCESS) { WARN("Can't find driver `%s'\n", pi->pDriverName); RegCloseKey(hkeyPrinters); RegCloseKey(hkeyDrivers); SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); return 0; } RegCloseKey(hkeyDriver); RegCloseKey(hkeyDrivers); if(strcasecmp(pi->pPrintProcessor, "WinPrint")) { /* FIXME */ WARN("Can't find processor `%s'\n", pi->pPrintProcessor); SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR); RegCloseKey(hkeyPrinters); return 0; } if(RegCreateKeyA(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) != ERROR_SUCCESS) { WARN("Can't create printer `%s'\n", pi->pPrinterName); SetLastError(ERROR_INVALID_PRINTER_NAME); RegCloseKey(hkeyPrinters); return 0; } RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD, (LPSTR)&pi->Attributes, sizeof(DWORD)); RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPSTR)&pi->pDevMode, pi->pDevMode ? pi->pDevMode->dmSize : 0); RegSetValueExA(hkeyPrinter, "Description", 0, REG_SZ, pi->pComment, 0); RegSetValueExA(hkeyPrinter, "Location", 0, REG_SZ, pi->pLocation, 0); RegSetValueExA(hkeyPrinter, "Name", 0, REG_SZ, pi->pPrinterName, 0); RegSetValueExA(hkeyPrinter, "Parameters", 0, REG_SZ, pi->pParameters, 0); RegSetValueExA(hkeyPrinter, "Port", 0, REG_SZ, pi->pPortName, 0); RegSetValueExA(hkeyPrinter, "Print Processor", 0, REG_SZ, pi->pPrintProcessor, 0); RegSetValueExA(hkeyPrinter, "Printer Driver", 0, REG_SZ, pi->pDriverName, 0); RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD, (LPSTR)&pi->Priority, sizeof(DWORD)); RegSetValueExA(hkeyPrinter, "Separator File", 0, REG_SZ, pi->pSepFile, 0); RegSetValueExA(hkeyPrinter, "Share Name", 0, REG_SZ, pi->pShareName, 0); RegSetValueExA(hkeyPrinter, "Start Time", 0, REG_DWORD, (LPSTR)&pi->StartTime, sizeof(DWORD)); RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD, (LPSTR)&pi->Status, sizeof(DWORD)); RegSetValueExA(hkeyPrinter, "Until Time", 0, REG_DWORD, (LPSTR)&pi->UntilTime, sizeof(DWORD)); RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); if(!OpenPrinterA(pi->pPrinterName, &retval, NULL)) { ERR("OpenPrinter failing\n"); return 0; } return retval; } /***************************************************************************** * AddPrinterW [WINSPOOL.122] */ HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter) { FIXME("(%p,%ld,%p): stub\n", pName, Level, pPrinter); return 0; } /***************************************************************************** * ClosePrinter [WINSPOOL.126] */ BOOL WINAPI ClosePrinter(HANDLE hPrinter) { LPOPENEDPRINTERA lpOpenedPrinter; TRACE("Handle %d\n", hPrinter); if (!pOpenedPrinterDPA) return FALSE; if ((hPrinter != -1) && (hPrinter < (pOpenedPrinterDPA->nItemCount - 1))) { lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter); HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpsPrinterName); lpOpenedPrinter->lpsPrinterName = NULL; /* Free the memory of lpDefault if it has been initialized*/ if(lpOpenedPrinter->lpDefault != NULL) { HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpDefault->pDevMode); HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpDefault->pDatatype); HeapFree(GetProcessHeap(), 0, lpOpenedPrinter->lpDefault); lpOpenedPrinter->lpDefault = NULL; } lpOpenedPrinter->hPrinter = -1; return TRUE; } return FALSE; } /***************************************************************************** * DeleteFormA [WINSPOOL.133] */ BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName) { FIXME("(%d,%s): stub\n", hPrinter, pFormName); return 1; } /***************************************************************************** * DeleteFormW [WINSPOOL.134] */ BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName) { FIXME("(%d,%s): stub\n", hPrinter, debugstr_w(pFormName)); return 1; } /***************************************************************************** * DeletePrinter [WINSPOOL.143] */ BOOL WINAPI DeletePrinter(HANDLE hPrinter) { FIXME("(%d): stub\n", hPrinter); return 1; } /***************************************************************************** * SetPrinterA [WINSPOOL.211] */ BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command) { FIXME("(%d,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command); return FALSE; } /***************************************************************************** * SetJobA [WINSPOOL.209] */ BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command) { FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob, Command); return FALSE; } /***************************************************************************** * SetJobW [WINSPOOL.210] */ BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command) { FIXME("(%d,%ld,%ld,%p,%ld): stub\n",hPrinter,JobId,Level,pJob, Command); return FALSE; } /***************************************************************************** * GetFormA [WINSPOOL.181] */ BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level, LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName, Level,pForm,cbBuf,pcbNeeded); return FALSE; } /***************************************************************************** * GetFormW [WINSPOOL.182] */ BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level, LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter, debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded); return FALSE; } /***************************************************************************** * SetFormA [WINSPOOL.207] */ BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level, LPBYTE pForm) { FIXME("(%d,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm); return FALSE; } /***************************************************************************** * SetFormW [WINSPOOL.208] */ BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level, LPBYTE pForm) { FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm); return FALSE; } /***************************************************************************** * ReadPrinter [WINSPOOL.202] */ BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pNoBytesRead) { FIXME("(%d,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead); return FALSE; } /***************************************************************************** * ResetPrinterA [WINSPOOL.203] */ BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault) { FIXME("(%d, %p): stub\n", hPrinter, pDefault); return FALSE; } /***************************************************************************** * ResetPrinterW [WINSPOOL.204] */ BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault) { FIXME("(%d, %p): stub\n", hPrinter, pDefault); return FALSE; } /***************************************************************************** * WINSPOOL_GetStringFromRegA * * Get ValueName from hkey storing result in str. buflen is space left in str */ static BOOL WINSPOOL_GetStringFromRegA(HKEY hkey, LPCSTR ValueName, LPSTR ptr, DWORD buflen, DWORD *needed) { DWORD sz = buflen, type; LONG ret; ret = RegQueryValueExA(hkey, ValueName, 0, &type, ptr, &sz); if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) { ERR("Got ret = %ld\n", ret); return FALSE; } *needed = sz; return TRUE; } /********************************************************************* * WINSPOOL_GetPrinter_2A * * Fills out a PRINTER_INFO_2A struct storing the strings in buf. */ static BOOL WINSPOOL_GetPrinter_2A(HKEY hkeyPrinter, PRINTER_INFO_2A *pi2, LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD size, left = cbBuf; BOOL space = (cbBuf > 0); LPBYTE ptr = buf; *pcbNeeded = 0; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size); if(space && size <= left) { pi2->pPrinterName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, left, &size); if(space && size <= left) { pi2->pPortName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, left, &size); if(space && size <= left) { pi2->pDriverName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, left, &size); if(space && size <= left) { pi2->pDevMode = (LPDEVMODEA)ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, left, &size); if(space && size <= left) { pi2->pPrintProcessor = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; if(!space && pi2) /* zero out pi2 if we can't completely fill buf */ memset(pi2, 0, sizeof(*pi2)); return space; } /********************************************************************* * WINSPOOL_GetPrinter_4A * * Fills out a PRINTER_INFO_4A struct storing the strings in buf. */ static BOOL WINSPOOL_GetPrinter_4A(HKEY hkeyPrinter, PRINTER_INFO_4A *pi4, LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD size, left = cbBuf; BOOL space = (cbBuf > 0); LPBYTE ptr = buf; *pcbNeeded = 0; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size); if(space && size <= left) { pi4->pPrinterName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; if(!space && pi4) /* zero out pi4 if we can't completely fill buf */ memset(pi4, 0, sizeof(*pi4)); return space; } /********************************************************************* * WINSPOOL_GetPrinter_5A * * Fills out a PRINTER_INFO_5A struct storing the strings in buf. */ static BOOL WINSPOOL_GetPrinter_5A(HKEY hkeyPrinter, PRINTER_INFO_5A *pi5, LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD size, left = cbBuf; BOOL space = (cbBuf > 0); LPBYTE ptr = buf; *pcbNeeded = 0; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, left, &size); if(space && size <= left) { pi5->pPrinterName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, left, &size); if(space && size <= left) { pi5->pPortName = ptr; ptr += size; left -= size; } else space = FALSE; *pcbNeeded += size; if(!space && pi5) /* zero out pi5 if we can't completely fill buf */ memset(pi5, 0, sizeof(*pi5)); return space; } /***************************************************************************** * GetPrinterA [WINSPOOL.187] */ BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) { OPENEDPRINTERA *lpOpenedPrinter; DWORD size, needed = 0; LPBYTE ptr = NULL; HKEY hkeyPrinter, hkeyPrinters; BOOL ret; TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded); lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter); if(!lpOpenedPrinter) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS) { ERR("Can't create Printers key\n"); return FALSE; } if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter) != ERROR_SUCCESS) { ERR("Can't find opened printer `%s' in registry\n", lpOpenedPrinter->lpsPrinterName); RegCloseKey(hkeyPrinters); SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */ return FALSE; } switch(Level) { case 2: { PRINTER_INFO_2A *pi2 = (PRINTER_INFO_2A *)pPrinter; size = sizeof(PRINTER_INFO_2A); if(size <= cbBuf) { ptr = pPrinter + size; cbBuf -= size; memset(pPrinter, 0, size); } else { pi2 = NULL; cbBuf = 0; } ret = WINSPOOL_GetPrinter_2A(hkeyPrinter, pi2, ptr, cbBuf, &needed); needed += size; break; } case 4: { PRINTER_INFO_4A *pi4 = (PRINTER_INFO_4A *)pPrinter; size = sizeof(PRINTER_INFO_4A); if(size <= cbBuf) { ptr = pPrinter + size; cbBuf -= size; memset(pPrinter, 0, size); } else { pi4 = NULL; cbBuf = 0; } ret = WINSPOOL_GetPrinter_4A(hkeyPrinter, pi4, ptr, cbBuf, &needed); needed += size; break; } case 5: { PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A *)pPrinter; size = sizeof(PRINTER_INFO_5A); if(size <= cbBuf) { ptr = pPrinter + size; cbBuf -= size; memset(pPrinter, 0, size); } else { pi5 = NULL; cbBuf = 0; } ret = WINSPOOL_GetPrinter_5A(hkeyPrinter, pi5, ptr, cbBuf, &needed); needed += size; break; } default: FIXME("Unimplemented level %ld\n", Level); SetLastError(ERROR_INVALID_LEVEL); RegCloseKey(hkeyPrinters); RegCloseKey(hkeyPrinter); return FALSE; } RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); if(pcbNeeded) *pcbNeeded = needed; if(!ret) SetLastError(ERROR_INSUFFICIENT_BUFFER); return ret; } /***************************************************************************** * GetPrinterW [WINSPOOL.194] */ BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); return FALSE; } /****************************************************************** * EnumPrintersA [WINSPOOL.174] * * Enumerates the available printers, print servers and print * providers, depending on the specified flags, name and level. * * RETURNS: * * If level is set to 1: * Not implemented yet! * Returns TRUE with an empty list. * * If level is set to 2: * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL. * Returns an array of PRINTER_INFO_2 data structures in the * lpbPrinters buffer. Note that according to MSDN also an * OpenPrinter should be performed on every remote printer. * * If level is set to 4 (officially WinNT only): * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL. * Fast: Only the registry is queried to retrieve printer names, * no connection to the driver is made. * Returns an array of PRINTER_INFO_4 data structures in the * lpbPrinters buffer. * * If level is set to 5 (officially WinNT4/Win9x only): * Fast: Only the registry is queried to retrieve printer names, * no connection to the driver is made. * Returns an array of PRINTER_INFO_5 data structures in the * lpbPrinters buffer. * * If level set to 3 or 6+: * returns zero (faillure!) * * Returns nonzero (TRUE) on succes, or zero on faillure, use GetLastError * for information. * * BUGS: * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented. * - Only levels 2, 4 and 5 are implemented at the moment. * - 16-bit printer drivers are not enumerated. * - Returned amount of bytes used/needed does not match the real Windoze * implementation (as in this implementation, all strings are part * of the buffer, whereas Win32 keeps them somewhere else) * - At level 2, EnumPrinters should also call OpenPrinter for remote printers. * * NOTE: * - In a regular Wine installation, no registry settings for printers * exist, which makes this function return an empty list. */ BOOL WINAPI EnumPrintersA( DWORD dwType, /* Types of print objects to enumerate */ LPSTR lpszName, /* name of objects to enumerate */ DWORD dwLevel, /* type of printer info structure */ LPBYTE lpbPrinters, /* buffer which receives info */ DWORD cbBuf, /* max size of buffer in bytes */ LPDWORD lpdwNeeded, /* pointer to var: # bytes used/needed */ LPDWORD lpdwReturned /* number of entries returned */ ) { HKEY hkeyPrinters, hkeyPrinter; char PrinterName[255]; DWORD needed = 0, number = 0; DWORD used, i, left; PBYTE pi, buf; if(lpbPrinters) memset(lpbPrinters, 0, cbBuf); if(lpdwReturned) *lpdwReturned = 0; if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) { FIXME("dwType = %08lx\n", dwType); SetLastError(ERROR_INVALID_FLAGS); return FALSE; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS) { ERR("Can't create Printers key\n"); return FALSE; } if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) { RegCloseKey(hkeyPrinters); ERR("Can't query Printers key\n"); return FALSE; } TRACE("Found %ld printers\n", number); switch(dwLevel) { case 1: RegCloseKey(hkeyPrinters); if (lpdwReturned) *lpdwReturned = number; return TRUE; case 2: used = number * sizeof(PRINTER_INFO_2A); break; case 4: used = number * sizeof(PRINTER_INFO_4A); break; case 5: used = number * sizeof(PRINTER_INFO_5A); break; default: SetLastError(ERROR_INVALID_LEVEL); RegCloseKey(hkeyPrinters); return FALSE; } pi = (used <= cbBuf) ? lpbPrinters : NULL; for(i = 0; i < number; i++) { if(RegEnumKeyA(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) != ERROR_SUCCESS) { ERR("Can't enum key number %ld\n", i); RegCloseKey(hkeyPrinters); return FALSE; } if(RegOpenKeyA(hkeyPrinters, PrinterName, &hkeyPrinter) != ERROR_SUCCESS) { ERR("Can't open key '%s'\n", PrinterName); RegCloseKey(hkeyPrinters); return FALSE; } if(cbBuf > used) { buf = lpbPrinters + used; left = cbBuf - used; } else { buf = NULL; left = 0; } switch(dwLevel) { case 2: WINSPOOL_GetPrinter_2A(hkeyPrinter, (PRINTER_INFO_2A *)pi, buf, left, &needed); used += needed; if(pi) pi += sizeof(PRINTER_INFO_2A); break; case 4: WINSPOOL_GetPrinter_4A(hkeyPrinter, (PRINTER_INFO_4A *)pi, buf, left, &needed); used += needed; if(pi) pi += sizeof(PRINTER_INFO_4A); break; case 5: WINSPOOL_GetPrinter_5A(hkeyPrinter, (PRINTER_INFO_5A *)pi, buf, left, &needed); used += needed; if(pi) pi += sizeof(PRINTER_INFO_5A); break; default: ERR("Shouldn't be here!\n"); RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); return FALSE; } RegCloseKey(hkeyPrinter); } RegCloseKey(hkeyPrinters); if(lpdwNeeded) *lpdwNeeded = used; if(used > cbBuf) { if(lpbPrinters) memset(lpbPrinters, 0, cbBuf); SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } if(lpdwReturned) *lpdwReturned = number; SetLastError(ERROR_SUCCESS); return TRUE; } /****************************************************************** * EnumPrintersW [WINSPOOL.175] * */ BOOL WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName, DWORD dwLevel, LPBYTE lpbPrinters, DWORD cbBuf, LPDWORD lpdwNeeded, LPDWORD lpdwReturned) { FIXME("Nearly empty stub\n"); *lpdwReturned=0; *lpdwNeeded = 0; return TRUE; } /***************************************************************************** * GetPrinterDriverA [WINSPOOL.190] */ BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) { OPENEDPRINTERA *lpOpenedPrinter; char DriverName[100]; DWORD ret, type, size, dw, needed = 0; LPBYTE ptr = NULL; HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers; TRACE("(%d,%s,%ld,%p,%ld,%p)\n",hPrinter,pEnvironment, Level,pDriverInfo,cbBuf, pcbNeeded); ZeroMemory(pDriverInfo, cbBuf); lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter); if(!lpOpenedPrinter) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } if(pEnvironment) { FIXME("pEnvironment = `%s'\n", pEnvironment); SetLastError(ERROR_INVALID_ENVIRONMENT); return FALSE; } if(Level < 1 || Level > 3) { SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS) { ERR("Can't create Printers key\n"); return FALSE; } if(RegOpenKeyA(hkeyPrinters, lpOpenedPrinter->lpsPrinterName, &hkeyPrinter) != ERROR_SUCCESS) { ERR("Can't find opened printer `%s' in registry\n", lpOpenedPrinter->lpsPrinterName); RegCloseKey(hkeyPrinters); SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */ return FALSE; } size = sizeof(DriverName); ret = RegQueryValueExA(hkeyPrinter, "Printer Driver", 0, &type, DriverName, &size); RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinters); if(ret != ERROR_SUCCESS) { ERR("Can't get DriverName for printer `%s'\n", lpOpenedPrinter->lpsPrinterName); return FALSE; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) != ERROR_SUCCESS) { ERR("Can't create Drivers key\n"); return FALSE; } if(RegOpenKeyA(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) { ERR("Can't find driver `%s' in registry\n", DriverName); RegCloseKey(hkeyDrivers); SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */ return FALSE; } switch(Level) { case 1: size = sizeof(DRIVER_INFO_1A); break; case 2: size = sizeof(DRIVER_INFO_2A); break; case 3: size = sizeof(DRIVER_INFO_3A); break; default: ERR("Invalid level\n"); return FALSE; } if(size <= cbBuf) { ptr = pDriverInfo + size; cbBuf -= size; } else cbBuf = 0; needed = size; size = strlen(DriverName) + 1; if(size <= cbBuf) { cbBuf -= size; strcpy(ptr, DriverName); if(Level == 1) ((DRIVER_INFO_1A *)pDriverInfo)->pName = ptr; else ((DRIVER_INFO_2A *)pDriverInfo)->pName = ptr; ptr += size; } needed += size; if(Level > 1) { DRIVER_INFO_2A *di2 = (DRIVER_INFO_2A *)pDriverInfo; size = sizeof(dw); if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) != ERROR_SUCCESS) WARN("Can't get Version\n"); else if(cbBuf) di2->cVersion = dw; size = strlen("Wine") + 1; /* FIXME */ if(size <= cbBuf) { cbBuf -= size; strcpy(ptr, "Wine"); di2->pEnvironment = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "Driver", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di2->pDriverPath = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di2->pDataFile = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di2->pConfigFile = ptr; ptr += size; } else cbBuf = 0; needed += size; } if(Level > 2) { DRIVER_INFO_3A *di3 = (DRIVER_INFO_3A *)pDriverInfo; WINSPOOL_GetStringFromRegA(hkeyDriver, "Help File", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di3->pHelpFile = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di3->pDependentFiles = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di3->pMonitorName = ptr; ptr += size; } else cbBuf = 0; needed += size; WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size); if(cbBuf && size <= cbBuf) { di3->pDefaultDataType = ptr; ptr += size; } else cbBuf = 0; needed += size; } RegCloseKey(hkeyDriver); RegCloseKey(hkeyDrivers); if(pcbNeeded) *pcbNeeded = needed; if(cbBuf) return TRUE; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } /***************************************************************************** * GetPrinterDriverW [WINSPOOL.193] */ BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) { FIXME("(%d,%p,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment, Level,pDriverInfo,cbBuf, pcbNeeded); return FALSE; } /***************************************************************************** * GetPrinterDriverDirectoryA [WINSPOOL.191] */ BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD needed; TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded); if(pName != NULL) { FIXME("pName = `%s' - unsupported\n", pName); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(pEnvironment != NULL) { FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment); SetLastError(ERROR_INVALID_ENVIRONMENT); return FALSE; } if(Level != 1) /* win95 ignores this so we just carry on */ WARN("Level = %ld - assuming 1\n", Level); /* FIXME should read from registry */ needed = GetSystemDirectoryA(pDriverDirectory, cbBuf); needed++; if(pcbNeeded) *pcbNeeded = needed; if(needed > cbBuf) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } return TRUE; } /***************************************************************************** * GetPrinterDriverDirectoryW [WINSPOOL.192] */ BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded) { LPSTR pNameA = NULL, pEnvironmentA = NULL; BOOL ret; if(pName) pNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, pName ); if(pEnvironment) pEnvironmentA = HEAP_strdupWtoA( GetProcessHeap(), 0, pEnvironment ); ret = GetPrinterDriverDirectoryA( pNameA, pEnvironmentA, Level, pDriverDirectory, cbBuf, pcbNeeded ); if(pNameA) HeapFree( GetProcessHeap(), 0, pNameA ); if(pEnvironmentA) HeapFree( GetProcessHeap(), 0, pEnvironment ); return ret; } /***************************************************************************** * AddPrinterDriverA [WINSPOOL.120] */ BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo) { DRIVER_INFO_3A di3; HKEY hkeyDrivers, hkeyName; TRACE("(%s,%ld,%p)\n",pName,level,pDriverInfo); if(level != 2 && level != 3) { SetLastError(ERROR_INVALID_LEVEL); return FALSE; } if(pName != NULL) { FIXME("pName= `%s' - unsupported\n", pName); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(!pDriverInfo) { WARN("pDriverInfo == NULL"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(level == 3) di3 = *(DRIVER_INFO_3A *)pDriverInfo; else { memset(&di3, 0, sizeof(di3)); *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo; } if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile || !di3.pDataFile) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if(!di3.pDefaultDataType) di3.pDefaultDataType = ""; if(!di3.pDependentFiles) di3.pDependentFiles = "\0"; if(!di3.pHelpFile) di3.pHelpFile = ""; if(!di3.pMonitorName) di3.pMonitorName = ""; if(di3.pEnvironment) { FIXME("pEnvironment = `%s'\n", di3.pEnvironment); SetLastError(ERROR_INVALID_ENVIRONMENT); return FALSE; } if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Drivers, &hkeyDrivers) != ERROR_SUCCESS) { ERR("Can't create Drivers key\n"); return FALSE; } if(level == 2) { /* apparently can't overwrite with level2 */ if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) { RegCloseKey(hkeyName); RegCloseKey(hkeyDrivers); WARN("Trying to create existing printer driver `%s'\n", di3.pName); SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED); return FALSE; } } if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) { RegCloseKey(hkeyDrivers); ERR("Can't create Name key\n"); return FALSE; } RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, di3.pConfigFile, 0); RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, di3.pDataFile, 0); RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, di3.pDriverPath, 0); RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPSTR)&di3.cVersion, sizeof(DWORD)); RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, di3.pDefaultDataType, 0); RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ, di3.pDependentFiles, 0); RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, di3.pHelpFile, 0); RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, di3.pMonitorName, 0); RegCloseKey(hkeyName); RegCloseKey(hkeyDrivers); return TRUE; } /***************************************************************************** * AddPrinterDriverW [WINSPOOL.121] */ BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level, LPBYTE pDriverInfo) { FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName), level,pDriverInfo); return FALSE; } /***************************************************************************** * PrinterProperties [WINSPOOL.201] * * Displays a dialog to set the properties of the printer. * * RETURNS * nonzero on succes or zero on faillure * * BUGS * implemented as stub only */ BOOL WINAPI PrinterProperties(HWND hWnd, /* handle to parent window */ HANDLE hPrinter /* handle to printer object */ ){ FIXME("(%d,%d): stub\n", hWnd, hPrinter); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /***************************************************************************** * EnumJobsA [WINSPOOL.162] * */ BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) { FIXME("stub\n"); if(pcbNeeded) *pcbNeeded = 0; if(pcReturned) *pcReturned = 0; return TRUE; } /***************************************************************************** * EnumJobsW [WINSPOOL.163] * */ BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) { FIXME("stub\n"); if(pcbNeeded) *pcbNeeded = 0; if(pcReturned) *pcReturned = 0; return TRUE; }