Implementation of EnumPrintersA, info level 4 and 5.
diff --git a/include/winspool.h b/include/winspool.h
index e370a23..b4aa0c4 100644
--- a/include/winspool.h
+++ b/include/winspool.h
@@ -182,6 +182,42 @@
DECL_WINELIB_TYPE_AW(PPRINTER_INFO_2)
DECL_WINELIB_TYPE_AW(LPPRINTER_INFO_2)
+typedef struct _PRINTER_INFO_4A {
+ LPSTR pPrinterName;
+ LPSTR pServerName;
+ DWORD Attributes;
+} PRINTER_INFO_4A, *PPRINTER_INFO_4A, *LPPRINTER_INFO_4A;
+
+typedef struct _PRINTER_INFO_4W {
+ LPWSTR pPrinterName;
+ LPWSTR pServerName;
+ DWORD Attributes;
+} PRINTER_INFO_4W, *PPRINTER_INFO_4W, *LPPRINTER_INFO_4W;
+
+DECL_WINELIB_TYPE_AW(PRINTER_INFO_4)
+DECL_WINELIB_TYPE_AW(PPRINTER_INFO_4)
+DECL_WINELIB_TYPE_AW(LPPRINTER_INFO_4)
+
+typedef struct _PRINTER_INFO_5A {
+ LPSTR pPrinterName;
+ LPSTR pPortName;
+ DWORD Attributes;
+ DWORD DeviceNotSelectedTimeOut;
+ DWORD TransmissionRetryTimeout;
+} PRINTER_INFO_5A, *PPRINTER_INFO_5A, *LPPRINTER_INFO_5A;
+
+typedef struct _PRINTER_INFO_5W {
+ LPWSTR pPrinterName;
+ LPWSTR pPortName;
+ DWORD Attributes;
+ DWORD DeviceNotSelectedTimeOut;
+ DWORD TransmissionRetryTimeout;
+} PRINTER_INFO_5W, *PPRINTER_INFO_5W, *LPPRINTER_INFO_5W;
+
+DECL_WINELIB_TYPE_AW(PRINTER_INFO_5)
+DECL_WINELIB_TYPE_AW(PPRINTER_INFO_5)
+DECL_WINELIB_TYPE_AW(LPPRINTER_INFO_5)
+
#endif /* Status */
/* DECLARATIONS */
@@ -225,6 +261,17 @@
BOOL WINAPI ClosePrinter (HANDLE phPrinter);
+BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
+ DWORD dwLevel, LPBYTE lpbPrinters,
+ DWORD cbBuf, LPDWORD lpdwNeeded,
+ LPDWORD lpdwReturned);
+BOOL WINAPI EnumPrintersW(DWORD dwType, LPWSTR lpszName,
+ DWORD dwLevel, LPBYTE lpbPrinters,
+ DWORD cbBuf, LPDWORD lpdwNeeded,
+ LPDWORD lpdwReturned);
+#define EnumPrinters WINELIB_NAME_AW(EnumPrinters)
+
+
#ifdef __cplusplus
} // extern "C"
diff --git a/misc/printdrv.c b/misc/printdrv.c
index 55e4286..0d3f7a0 100644
--- a/misc/printdrv.c
+++ b/misc/printdrv.c
@@ -401,19 +401,342 @@
return FALSE;
}
+
/******************************************************************
- * EnumPrinters32A [WINSPOOL.174]
+ * ENUMPRINTERS_AddInfo4A internal
*
+ * Creates a PRINTER_INFO_4A structure at: lpbPrinters[dwNextStructPos]
+ * for printer PrinterNameKey.
+ * Note that there is no check whether the information really fits!
+ *
+ * RETURNS
+ * FALSE if there is still space left in the buffer.
+ *
+ * BUGS:
+ * This function should not exist in Win95 mode, but does anyway.
*/
-BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
- DWORD dwLevel, LPBYTE lpbPrinters,
- DWORD cbBuf, LPDWORD lpdwNeeded,
- LPDWORD lpdwReturned)
+BOOL ENUMPRINTERS_AddInfo4A(
+ LPSTR lpszPrinterName,/* name of printer to fill struct for*/
+ LPBYTE lpbPrinters, /* buffer which receives info*/
+ DWORD dwNextStructPos, /* pos in buffer for struct */
+ LPDWORD dwNextStringPos, /* pos in buffer for next string */
+ DWORD dwBufSize, /* max size of buffer in bytes */
+ BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
+){
+ HKEY hPrinterSettings;
+ DWORD DataType;
+ DWORD DataSize=8;
+ char Data[8];
+ DWORD* DataPointer= (DWORD*) Data;
+ LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
+ strlen(lpszPrinterName)+2);
+ LPPRINTER_INFO_4A lpPInfo4 = (LPPRINTER_INFO_4A) &lpbPrinters[dwNextStructPos];
+
+ lpPInfo4->pPrinterName = &lpbPrinters[*dwNextStringPos];
+ *dwNextStringPos += strlen(lpszPrinterName)+1;
+ if (*dwNextStringPos > dwBufSize)
+ bCalcSpaceOnly=TRUE;
+ if (bCalcSpaceOnly==FALSE)
+ strcpy(lpPInfo4->pPrinterName, lpszPrinterName);
+ lpPInfo4->pServerName = NULL;
+
+ /* open the registry to find the attributes of the printer */
+ if (lpszPrinterSettings!=NULL)
+ {
+ strcpy(lpszPrinterSettings,Printers);
+ strcat(lpszPrinterSettings,lpszPrinterName);
+ }
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0,
+ KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
+ {
+ FIXME(print, "The registry did not contain my printer anymore?\n");
+ lpPInfo4->Attributes = 0;
+ }
+ else
+ {
+ RegQueryValueExA(hPrinterSettings, "Attributes", NULL, &DataType,
+ Data, &DataSize);
+ if (DataType==REG_DWORD)
+ lpPInfo4->Attributes = PRINTER_ATTRIBUTE_LOCAL + *DataPointer;
+ }
+ if (lpszPrinterSettings)
+ free(lpszPrinterSettings);
+
+ return(bCalcSpaceOnly);
+}
+
+/******************************************************************
+ * ENUMPRINTERS_AddInfo5A internal
+ *
+ * Creates a PRINTER_INFO_5A structure at: lpbPrinters[dwNextStructPos]
+ * for printer PrinterNameKey.
+ * Settings are read from the registry.
+ * Note that there is no check whether the information really fits!
+ * RETURNS
+ * FALSE if there is still space left in the buffer.
+ */
+BOOL ENUMPRINTERS_AddInfo5A(
+ LPSTR lpszPrinterName,/* name of printer to fill struct for*/
+ LPBYTE lpbPrinters, /* buffer which receives info*/
+ DWORD dwNextStructPos, /* pos in buffer for struct */
+ LPDWORD dwNextStringPos, /* pos in buffer for next string */
+ DWORD dwBufSize, /* max size of buffer in bytes */
+ BOOL bCalcSpaceOnly /* TRUE if out-of-space in buffer */
+){
+ HKEY hPrinterSettings;
+ DWORD DataType;
+ DWORD DataSize=255;
+ char Data[255];
+ DWORD* DataPointer= (DWORD*) Data;
+ LPSTR lpszPrinterSettings = (LPSTR) malloc(strlen(Printers)+
+ strlen(lpszPrinterName)+2);
+ LPPRINTER_INFO_5A lpPInfo5 = (LPPRINTER_INFO_5A) &lpbPrinters[dwNextStructPos];
+
+ /* copy the PrinterName into the structure */
+ lpPInfo5->pPrinterName = &lpbPrinters[*dwNextStringPos];
+ *dwNextStringPos += strlen(lpszPrinterName)+1;
+ if (*dwNextStringPos > dwBufSize)
+ bCalcSpaceOnly=TRUE;
+ if (bCalcSpaceOnly==FALSE)
+ strcpy(lpPInfo5->pPrinterName, lpszPrinterName);
+
+ /* open the registry to find the attributes, etc of the printer */
+ if (lpszPrinterSettings!=NULL)
+ {
+ strcpy(lpszPrinterSettings,Printers);
+ strcat(lpszPrinterSettings,lpszPrinterName);
+ }
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpszPrinterSettings, 0,
+ KEY_READ, &hPrinterSettings) != ERROR_SUCCESS)
+ {
+ FIXME(print, "The registry did not contain my printer anymore?\n");
+ lpPInfo5->Attributes = 0;
+ lpPInfo5->pPortName = NULL;
+ lpPInfo5->Attributes = 0;
+ lpPInfo5->DeviceNotSelectedTimeOut =0;
+ lpPInfo5->TransmissionRetryTimeout = 0;
+ }
+ else
+ {
+ RegQueryValueExA(hPrinterSettings, "Attributes", NULL, &DataType,
+ Data, &DataSize);
+ if (DataType==REG_DWORD)
+ lpPInfo5->Attributes = PRINTER_ATTRIBUTE_LOCAL + *DataPointer;
+
+ DataSize=255;
+ RegQueryValueExA(hPrinterSettings, "txTimeout", NULL, &DataType,
+ Data, &DataSize);
+ if (DataType==REG_DWORD)
+ lpPInfo5->DeviceNotSelectedTimeOut = *DataPointer;
+
+ DataSize=255;
+ RegQueryValueExA(hPrinterSettings, "dnsTimeout", NULL, &DataType,
+ Data, &DataSize);
+ if (DataType==REG_DWORD)
+ lpPInfo5->TransmissionRetryTimeout = *DataPointer;
+
+ DataSize=255;
+ RegQueryValueExA(hPrinterSettings, "Port", NULL, &DataType,
+ Data, &DataSize);
+ lpPInfo5->pPortName = &lpbPrinters[*dwNextStringPos];
+ *dwNextStringPos += DataSize+1;
+ if (*dwNextStringPos > dwBufSize)
+ bCalcSpaceOnly=TRUE;
+ if (bCalcSpaceOnly==FALSE)
+ strcpy(lpPInfo5->pPortName, Data);
+ }
+
+ if (lpszPrinterSettings)
+ free(lpszPrinterSettings);
+
+ return(bCalcSpaceOnly);
+}
+
+
+/******************************************************************
+ * 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:
+ * If level is set to 2:
+ * Not implemented yet!
+ * Returns TRUE with an empty list.
+ *
+ * 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 level 4 and 5 are implemented at the moment.
+ * - 16-bit printer drivers are not enumerated.
+ * - returned bytes used/needed do not match the real Windoze implementation
+ *
+ * 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 */
+ )
{
- FIXME(print,"Nearly empty stub\n");
+ HKEY hPrinterListKey;
+ DWORD dwIndex=0;
+ char PrinterName[255];
+ DWORD PrinterNameLength=255;
+ FILETIME FileTime;
+ DWORD dwNextStringPos; /* position of next space for a string in the buffer*/
+ DWORD dwStructPrinterInfoSize; /* size of a Printer_Info_X structure */
+ BOOL bCalcSpaceOnly=FALSE;/* if TRUE: don't store data, just calculate space*/
+
+ TRACE(print, "EnumPrintersA\n");
+
+ /* check for valid Flags */
+ if (dwType != PRINTER_ENUM_LOCAL && dwType != PRINTER_ENUM_NAME)
+ {
+ SetLastError(ERROR_INVALID_FLAGS);
+ return(0);
+ }
+ if (dwLevel == 1 || dwLevel == 2)
+ return(TRUE);
+ if (dwLevel != 4 && dwLevel != 5)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return(0);
+ }
+
+ /* zero out the data area, and initialise some returns to zero,
+ * to prevent problems
+ */
+{
+ int i;
+ for (i=0; i<cbBuf; i++)
+ lpbPrinters[i]=0;
+ }
*lpdwReturned=0;
*lpdwNeeded = 0;
- return TRUE;
+
+ /* get a pointer to a list of all printer names in the registry */
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Printers, 0, KEY_READ,
+ &hPrinterListKey) !=ERROR_SUCCESS)
+ {
+ /* Oh no! An empty list of printers!
+ * (which is a valid configuration anyway)
+ */
+ TRACE(print, "No entries in the Printers part of the registry\n");
+ return(TRUE);
+ }
+
+ /* count the number of entries and check if it fits in the buffer
+ */
+ while(RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
+ NULL, NULL, NULL, &FileTime)==ERROR_SUCCESS)
+ {
+ PrinterNameLength=255;
+ dwIndex++;
+ }
+ *lpdwReturned = dwIndex;
+ switch(dwLevel)
+ {
+ case 1:
+ dwStructPrinterInfoSize = sizeof(PRINTER_INFO_1A);
+ break;
+ case 2:
+ dwStructPrinterInfoSize = sizeof(PRINTER_INFO_2A);
+ break;
+ case 4:
+ dwStructPrinterInfoSize = sizeof(PRINTER_INFO_4A);
+ break;
+ case 5:
+ dwStructPrinterInfoSize = sizeof(PRINTER_INFO_5A);
+ break;
+ default:
+ dwStructPrinterInfoSize = 0;
+ break;
+ }
+ if (dwIndex*dwStructPrinterInfoSize+1 > cbBuf)
+ bCalcSpaceOnly = TRUE;
+
+ /* the strings which contain e.g. PrinterName, PortName, etc,
+ * are also stored in lpbPrinters, but after the regular structs.
+ * dwNextStringPos will always point to the next free place for a
+ * string.
+ */
+ dwNextStringPos=(dwIndex+1)*dwStructPrinterInfoSize;
+
+ /* check each entry: if OK, add to list in corresponding INFO .
+ */
+ for(dwIndex=0; dwIndex < *lpdwReturned; dwIndex++)
+ {
+ PrinterNameLength=255;
+ if (RegEnumKeyExA(hPrinterListKey, dwIndex, PrinterName, &PrinterNameLength,
+ NULL, NULL, NULL, &FileTime)!=ERROR_SUCCESS)
+ break; /* exit for loop*/
+
+ /* check whether this printer is allowed in the list
+ * by comparing name to lpszName
+ */
+ if (dwType == PRINTER_ENUM_NAME)
+ if (strcmp(PrinterName,lpszName)!=0)
+ continue;
+
+ switch(dwLevel)
+ {
+ case 1:
+ /* FIXME: unimplemented */
+ break;
+ case 2:
+ /* FIXME: unimplemented */
+ break;
+ case 4:
+ bCalcSpaceOnly = ENUMPRINTERS_AddInfo4A(PrinterName, lpbPrinters,
+ dwIndex*dwStructPrinterInfoSize,
+ &dwNextStringPos, cbBuf, bCalcSpaceOnly);
+ break;
+ case 5:
+ bCalcSpaceOnly = ENUMPRINTERS_AddInfo5A(PrinterName, lpbPrinters,
+ dwIndex*dwStructPrinterInfoSize,
+ &dwNextStringPos, cbBuf, bCalcSpaceOnly);
+ break;
+ }
+ }
+ RegCloseKey(hPrinterListKey);
+ *lpdwNeeded = dwNextStringPos;
+
+ if (bCalcSpaceOnly==TRUE)
+ {
+ int i;
+ for (i=0; i<cbBuf; i++)
+ lpbPrinters[i]=0;
+ *lpdwReturned=0;
+ }
+
+ return(TRUE);
}
/******************************************************************