Eyes requested

Ian Pilcher pilcher at concentric.net
Sun Feb 11 10:47:32 CST 2001


Attached is a patch to implement EnumPrinterDataEx (which should let
everyone be happy about where the PostScript driver's font substitution
table goes).

Since this is the first time I've implemented a "real" Win32 API, rather
than just doing internal tweaking, I may have missed something that's
glaringly obvious to the more experienced.  Before I send this to wine-
patches, I'd appreciate it if some folks would take a quick look and let
me know what they think.

Thanks!
-- 
========================================================================
Ian Pilcher                                       pilcher at concentric.net
========================================================================
-------------- next part --------------
--- ../wine-20010203cvs/include/winspool.h	Sun Feb 11 21:46:34 2001
+++ include/winspool.h	Sun Feb 11 14:59:53 2001
@@ -763,6 +763,25 @@
 DECL_WINELIB_TYPE_AW(PPROVIDOR_INFO_1)
 DECL_WINELIB_TYPE_AW(LPPROVIDOR_INFO_1)
 
+typedef struct _PRINTER_ENUM_VALUESA {
+  LPSTR	 pValueName;
+  DWORD  cbValueName;
+  DWORD  dwType;
+  LPBYTE pData;
+  DWORD  cbData;
+} PRINTER_ENUM_VALUESA, *PPRINTER_ENUM_VALUESA;
+
+typedef struct _PRINTER_ENUM_VALUESW {
+  LPWSTR pValueName;
+  DWORD  cbValueName;
+  DWORD  dwType;
+  LPBYTE pData;
+  DWORD  cbData;
+} PRINTER_ENUM_VALUESW, *PPRINTER_ENUM_VALUESW;
+
+DECL_WINELIB_TYPE_AW(PRINTER_ENUM_VALUES)
+DECL_WINELIB_TYPE_AW(PPRINTER_ENUM_VALUES)
+
 /* DECLARATIONS */
 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,
 			       LPSTR pOutput, LPDEVMODEA pDevMode);
@@ -1082,6 +1101,14 @@
 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment,
 				 LPWSTR pPrintProvidorName);
 #define DeletePrintProvidor WINELIB_NAME_AW(DeletePrintProvidor)
+
+DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
+				LPBYTE pEnumValues, DWORD cbEnumValues,
+				LPDWORD pcbEnumValues, LPDWORD pnEnumValues);
+DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
+				LPBYTE pEnumValues, DWORD cbEnumValues,
+				LPDWORD pcbEnumValues, LPDWORD pnEnumValues);
+#define EnumPrinterDataEx WINELIB_NAME_AW(EnumPrinterDataEx)
 
 
 
--- ../wine-20010203cvs/dlls/winspool/winspool.drv.spec	Sun Feb 11 21:46:34 2001
+++ dlls/winspool/winspool.drv.spec	Sun Feb 11 14:59:53 2001
@@ -80,6 +80,10 @@
 @ stub EnumPrintProcessorDatatypesW
 @ stub EnumPrintProcessorsA
 @ stub EnumPrintProcessorsW
+@ stub EnumPrinterDataA
+@ stdcall EnumPrinterDataExA(long str ptr long ptr ptr) EnumPrinterDataExA
+@ stdcall EnumPrinterDataExW(long wstr ptr long ptr ptr) EnumPrinterDataExW
+@ stub EnumPrinterDataW
 @ stdcall EnumPrinterDriversA(str str long ptr long ptr ptr) EnumPrinterDriversA
 @ stdcall EnumPrinterDriversW(wstr wstr long ptr long ptr ptr) EnumPrinterDriversW
 @ stdcall EnumPrintersA(long ptr long ptr long ptr ptr) EnumPrintersA
--- ../wine-20010203cvs/dlls/winspool/info.c	Sun Feb 11 21:46:34 2001
+++ dlls/winspool/info.c	Sun Feb 11 21:36:19 2001
@@ -2561,3 +2561,322 @@
     return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
 			     pData, nSize, pcbNeeded);
 }
+
+/*
+ * The Win32 doc says that RegCloseKey and HeapFree can fail, but it's hard to
+ * imagine why either of them would.  And what is the calling function supposed
+ * to do about it anyway?
+ */
+
+#define REGCLOSEKEY(X)							\
+{									\
+    DWORD ret;								\
+									\
+    ret = RegCloseKey (X);						\
+    if (ret != ERROR_SUCCESS)						\
+	WARN ("RegCloseKey returned %li\n", ret);			\
+}
+
+#define HEAPFREE(X,Y,Z)							\
+{									\
+    if (HeapFree ((X), (Y), (Z)) == 0)					\
+	WARN ("HeapFree failed with code %li\n", GetLastError ());	\
+}
+
+/*******************************************************************************
+ *		EnumPrinterDataExW	[WINSPOOL.197]
+ */
+DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
+				LPBYTE pEnumValues, DWORD cbEnumValues,
+				LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
+{
+    HKEY		    hkPrinter, hkSubKey;
+    DWORD		    ret, dwIndex, cValues, cbMaxValueNameLen,
+			    cbValueNameLen, cbMaxValueLen, cbValueLen,
+			    cbBufSize, dwType;
+    LPWSTR		    lpValueName;
+    HANDLE		    hHeap;
+    PBYTE		    lpValue;
+    PPRINTER_ENUM_VALUESW   ppev;
+
+    TRACE ("%08x %s\n", hPrinter, debugstr_w (pKeyName));
+
+    if (pKeyName == NULL || *pKeyName == 0)
+	return ERROR_INVALID_PARAMETER;
+
+    ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
+    if (ret != ERROR_SUCCESS)
+    {
+	TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%08x) returned %li\n",
+		hPrinter, ret);
+	return ret;
+    }
+
+    ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
+    if (ret != ERROR_SUCCESS)
+    {
+	REGCLOSEKEY (hkPrinter);
+	TRACE ("RegOpenKeyExW (%08x, %s) returned %li\n", hPrinter,
+		debugstr_w (pKeyName), ret);
+	return ret;
+    }
+
+    REGCLOSEKEY (hkPrinter);
+
+    ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
+	    &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
+    if (ret != ERROR_SUCCESS)
+    {
+	REGCLOSEKEY (hkSubKey);
+	TRACE ("RegQueryInfoKeyW (%08x) returned %li\n", hkSubKey, ret);
+	return ret;
+    }
+
+    TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
+	    "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
+
+    if (cValues == 0)			/* empty key */
+    {
+	REGCLOSEKEY (hkSubKey);
+	*pcbEnumValues = *pnEnumValues = 0;
+	return ERROR_SUCCESS;
+    }
+
+    ++cbMaxValueNameLen;			/* allow for trailing '\0' */
+    lpValueName = alloca (cbMaxValueNameLen * sizeof (WCHAR));
+    if (lpValueName == NULL)
+    {
+	ERR ("Failed to allocate %li bytes on stack\n",
+		cbMaxValueNameLen * sizeof (WCHAR));
+	REGCLOSEKEY (hkSubKey);
+	return ERROR_OUTOFMEMORY;
+    }
+
+    hHeap = GetProcessHeap ();
+    if (hHeap == (HANDLE) NULL)
+    {
+	ERR ("GetProcessHeap failed\n");
+	REGCLOSEKEY (hkSubKey);
+	return ERROR_OUTOFMEMORY;
+    }
+
+    lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
+    if (lpValue == NULL)
+    {
+	ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
+	REGCLOSEKEY (hkSubKey);
+	return ERROR_OUTOFMEMORY;
+    }
+
+    TRACE ("pass 1: calculating buffer required for all names and values\n");
+
+    cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
+
+    TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
+
+    for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
+    {
+	cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
+	ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
+		NULL, NULL, lpValue, &cbValueLen);
+	if (ret != ERROR_SUCCESS)
+	{
+	    HEAPFREE (hHeap, 0, lpValue);
+	    REGCLOSEKEY (hkSubKey);
+	    TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
+	    return ret;
+	}
+
+	TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
+		debugstr_w (lpValueName), dwIndex,
+		(cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
+
+	cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
+	cbBufSize += cbValueLen;
+    }
+
+    TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
+
+    *pcbEnumValues = cbBufSize;
+    *pnEnumValues = cValues;
+
+    if (cbEnumValues < cbBufSize)	/* buffer too small */
+    {
+	HEAPFREE (hHeap, 0, lpValue);
+	REGCLOSEKEY (hkSubKey);
+	TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
+	return ERROR_MORE_DATA;
+    }
+
+    TRACE ("pass 2: copying all names and values to buffer\n");
+
+    ppev = (PPRINTER_ENUM_VALUESW) pEnumValues;		/* array of structs */
+    pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
+
+    for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
+    {
+	cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
+	ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
+		NULL, &dwType, lpValue, &cbValueLen);
+	if (ret != ERROR_SUCCESS)
+	{
+	    HEAPFREE (hHeap, 0, lpValue);
+	    REGCLOSEKEY (hkSubKey);
+	    TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
+	    return ret;
+	}
+
+	cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
+	memcpy (pEnumValues, lpValueName, cbValueNameLen);
+	ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
+	pEnumValues += cbValueNameLen;
+
+	/* return # of *bytes* (including trailing \0), not # of chars */
+	ppev[dwIndex].cbValueName = cbValueNameLen;
+
+	ppev[dwIndex].dwType = dwType;
+
+	memcpy (pEnumValues, lpValue, cbValueLen);
+	ppev[dwIndex].pData = pEnumValues;
+	pEnumValues += cbValueLen;
+
+	ppev[dwIndex].cbData = cbValueLen;
+
+	TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
+		debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
+    }
+
+    HEAPFREE (hHeap, 0, lpValue);
+    REGCLOSEKEY (hkSubKey);
+    return ERROR_SUCCESS;
+}
+
+/*******************************************************************************
+ *		EnumPrinterDataExA	[WINSPOOL.196]
+ *
+ * The observant will note that this function returns ASCII strings in Unicode-
+ * sized buffers (for value names and values of type REG_SZ, REG_EXPAND_SZ, and
+ * REG_MULTI_SZ).  This is what Windows 2000 does.
+ *
+ */
+DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
+				LPBYTE pEnumValues, DWORD cbEnumValues,
+				LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
+{
+    INT	    len;
+    LPWSTR  pKeyNameW;
+    DWORD   ret, dwIndex, dwBufSize;
+    HANDLE  hHeap;
+    LPSTR   pBuffer;
+
+    TRACE ("%08x %s\n", hPrinter, pKeyName);
+
+    if (pKeyName == NULL || *pKeyName == 0)
+	return ERROR_INVALID_PARAMETER;
+
+    len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
+
+    pKeyNameW = alloca (len * sizeof (WCHAR));
+    if (pKeyNameW == NULL)
+    {
+	ERR ("Failed to allocate %li bytes on stack\n",
+		(LONG) len * sizeof (WCHAR));
+	return ERROR_OUTOFMEMORY;
+    }
+
+    if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
+    {
+	TRACE ("MultiByteToWide Char (%s, %i) failed with code %li\n", pKeyName,
+		len, GetLastError ());
+	return GetLastError ();
+    }
+
+    ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
+	    pcbEnumValues, pnEnumValues);
+    if (ret != ERROR_SUCCESS)
+    {
+	TRACE ("EnumPrinterDataExW returned %li\n", ret);
+	return ret;
+    }
+
+    if (*pnEnumValues == 0)	/* empty key */
+	return ERROR_SUCCESS;
+
+    dwBufSize = 0;
+    for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
+    {
+	PPRINTER_ENUM_VALUESW ppev =
+		&((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
+
+	if (dwBufSize < ppev->cbValueName)
+	    dwBufSize = ppev->cbValueName;
+
+	if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
+		ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
+	    dwBufSize = ppev->cbData;
+    }
+
+    TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
+
+    hHeap = GetProcessHeap ();
+    if (hHeap == (HANDLE) NULL)
+    {
+	ERR ("GetProcessHeap failed\n");
+	return ERROR_OUTOFMEMORY;
+    }
+
+    pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
+    if (pBuffer == NULL)
+    {
+	ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
+	return ERROR_OUTOFMEMORY;
+    }
+
+    for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
+    {
+	PPRINTER_ENUM_VALUESW ppev =
+		&((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
+
+	len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
+		ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
+		NULL);
+	if (len == 0)
+	{
+	    HEAPFREE (hHeap, 0, pBuffer);
+	    TRACE ("WideCharToMultiByte (%s, %li) failed with code %li\n",
+		    debugstr_w (ppev->pValueName), dwBufSize, GetLastError ());
+	    return GetLastError ();
+	}
+
+	memcpy (ppev->pValueName, pBuffer, len);
+
+	TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
+
+	if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
+		ppev->dwType != REG_MULTI_SZ)
+	    continue;
+
+	len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
+		ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
+	if (len == 0)
+	{
+	    HEAPFREE (hHeap, 0, pBuffer);
+	    TRACE ("WideCharToMultiByte (%s, %li) failed with code %li\n",
+		    debugstr_w ((LPWSTR) ppev->pData), dwBufSize,
+		    GetLastError ());
+	    TRACE (" (only first string of REG_MULTI_SZ printed)\n");
+	    return GetLastError ();
+	}
+
+	memcpy (ppev->pData, pBuffer, len);
+
+	TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
+	TRACE ("  (only first string of REG_MULTI_SZ printed)\n");
+    }
+
+    HEAPFREE (hHeap, 0, pBuffer);
+    return ERROR_SUCCESS;
+}
+
+#undef REGCLOSEKEY
+#undef HEAPFREE


More information about the wine-devel mailing list