From 450270bb03a3f2f063014e5b8f91b45e4f6febbc Mon Sep 17 00:00:00 2001
From: Huw D M Davies <h.davies1@physics.ox.ac.uk>
Date: Sat, 10 Jul 1999 11:58:50 +0000
Subject: [PATCH] Implemented GetPrinterA and GetPrinterDriverA.

---
 dlls/winspool/info.c  | 351 +++++++++++++++++++++++++++++++++++++++---
 graphics/psdrv/init.c |   2 +-
 include/winspool.h    |   8 +
 3 files changed, 339 insertions(+), 22 deletions(-)

diff --git a/dlls/winspool/info.c b/dlls/winspool/info.c
index 183d877a103..c0ce6b728a8 100644
--- a/dlls/winspool/info.c
+++ b/dlls/winspool/info.c
@@ -256,13 +256,13 @@ DWORD ENUMPRINTERS_GetDWORDFromRegistryA(
  *    FALSE if there is still space left in the buffer.
  */
 BOOL ENUMPRINTERS_AddStringFromRegistryA(
-				HKEY  hPrinterSettings,  /* handle to registry key */
-				LPSTR KeyName,			 /* name key to retrieve string from*/
-                LPSTR* Dest,		     /* pointer to write string addres to */
-                LPBYTE lpbPrinters,      /* buffer which receives info*/
-                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, /* handle to registry key */
+		LPSTR KeyName,	        /* name key to retrieve string from*/
+                LPSTR* Dest,	        /* pointer to write string addres to */
+                LPBYTE lpbPrinters,     /* buffer which receives info*/
+                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 */
 ){                   
  DWORD DataSize=34;
  DWORD DataType;
@@ -597,8 +597,7 @@ 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 */
+                    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 */
                    )
@@ -1165,26 +1164,171 @@ BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW 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;
+}
+
+
 /*****************************************************************************
  *          GetPrinter32A  [WINSPOOL.187]
  */
 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
 			DWORD cbBuf, LPDWORD pcbNeeded)
 {
-    FIXME("(%d,%ld,%p,%ld,%p): stub\n", hPrinter, Level, pPrinter,
-		  cbBuf, pcbNeeded);
+    OPENEDPRINTERA *lpOpenedPrinter;
+    DWORD size, needed = 0;
+    LPBYTE ptr = NULL;
+    HKEY hkeyPrinter, hkeyPrinters;
+    
+    TRACE("(%d,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
 
-    *pcbNeeded = sizeof(PRINTER_INFO_2A);
+    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;
+    }
 
-    if(cbBuf < *pcbNeeded) {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    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
+	    cbBuf = 0;
+	needed = size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    pi2->pPrinterName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    pi2->pPortName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Printer Driver", ptr, cbBuf,
+				   &size);
+	if(size <= cbBuf) {
+	    pi2->pDriverName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Default DevMode", ptr, cbBuf,
+				   &size);
+	if(size <= cbBuf) {
+	    pi2->pDevMode = (LPDEVMODEA)ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Print Processor", ptr, cbBuf,
+				   &size);
+	if(size <= cbBuf) {
+	    pi2->pPrintProcessor = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	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
+	    cbBuf = 0;
+	needed = size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Name", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    pi5->pPrinterName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyPrinter, "Port", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    pi5->pPortName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	break;
+      }
+
+    default:
+        FIXME("Unimplemented level %ld\n", Level);
+        SetLastError(ERROR_INVALID_LEVEL);
+	RegCloseKey(hkeyPrinters);
+	RegCloseKey(hkeyPrinter);
 	return FALSE;
     }
-    memset(pPrinter, 0, cbBuf);
 
-    return TRUE;
+    RegCloseKey(hkeyPrinter);
+    RegCloseKey(hkeyPrinters);
+
+    if(pcbNeeded) *pcbNeeded = needed;
+    if(cbBuf) return TRUE;
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return FALSE;
 }
 
+
 /*****************************************************************************
  *          GetPrinter32W  [WINSPOOL.194]
  */
@@ -1196,6 +1340,7 @@ BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
     return FALSE;
 }
 
+
 /*****************************************************************************
  *          GetPrinterDriver32A  [WINSPOOL.190]
  */
@@ -1204,9 +1349,12 @@ BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
 			      DWORD cbBuf, LPDWORD pcbNeeded)
 {
     OPENEDPRINTERA *lpOpenedPrinter;
-    LPSTR lpName;
-
-    FIXME("(%d,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pEnvironment,
+    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);
 
     lpOpenedPrinter = WINSPOOL_GetOpenedPrinterA(hPrinter);
@@ -1214,13 +1362,174 @@ BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
         SetLastError(ERROR_INVALID_HANDLE);
 	return FALSE;
     }
-    lpName = lpOpenedPrinter->lpsPrinterName;
     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(size <= cbBuf) {
+	    di2->pDriverPath = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyDriver, "Data File", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    di2->pDataFile = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyDriver, "Configuration File", ptr,
+				   cbBuf, &size);
+	if(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(size <= cbBuf) {
+	    di3->pHelpFile = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyDriver, "Dependent Files", ptr, cbBuf,
+				   &size);
+	if(size <= cbBuf) {
+	    di3->pDependentFiles = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyDriver, "Monitor", ptr, cbBuf, &size);
+	if(size <= cbBuf) {
+	    di3->pMonitorName = ptr;
+	    ptr += size;
+	} else
+	    cbBuf = 0;
+	needed += size;
+
+	WINSPOOL_GetStringFromRegA(hkeyDriver, "DataType", ptr, cbBuf, &size);
+	if(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;
 }
 
diff --git a/graphics/psdrv/init.c b/graphics/psdrv/init.c
index 3295f62d88a..c849343eb15 100644
--- a/graphics/psdrv/init.c
+++ b/graphics/psdrv/init.c
@@ -349,7 +349,7 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name)
     res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
 			    NULL, 0, &needed );
 
-    if(res == ERROR_INVALID_PRINTER_NAME) {
+    if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) {
         pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
 	memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) );
 	DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE,
diff --git a/include/winspool.h b/include/winspool.h
index f3087523c26..c2d8e28ab75 100644
--- a/include/winspool.h
+++ b/include/winspool.h
@@ -292,6 +292,14 @@ BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR,LPSTR,DWORD,LPBYTE,DWORD,LPDWORD);
 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR,LPWSTR,DWORD,LPBYTE,DWORD,LPDWORD);
 #define GetPrinterDriverDirectory WINELIB_NAME_AW(GetPrinterDriverDirectory)
 
+BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
+			      DWORD Level, LPBYTE pDriverInfo,
+			      DWORD cbBuf, LPDWORD pcbNeeded);
+BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
+			      DWORD Level, LPBYTE pDriverInfo,
+			      DWORD cbBuf, LPDWORD pcbNeeded);
+#define GetPrinterDriver WINELIB_NAME_AW(GetPrinterDriver)
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
GitLab