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@concentric.net
========================================================================
--- ../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