While the great alloca debate rages on, here is a version of the patch
that uses HeapAlloc for all dynamic allocation.
(FWIW, my personal take is that if alloca causes the program to crash
when it fails, then it's not really useful. I only used it, because the
GNU libc documentation indicates that it returns NULL when it fails.)
If no one has any other feedback on the patch, I'll submit it to wine-
patches tomorrow. (So speak now or forever hold your peace.)
--
========================================================================
Ian Pilcher pilcher(a)concentric.net
========================================================================
--- ../wine-20010211cvs/include/winspool.h Sun Feb 11 19:26:47 2001
+++ include/winspool.h Mon Feb 12 09:32:58 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-20010211cvs/dlls/winspool/winspool.drv.spec Sun Feb 11 19:26:47 2001
+++ dlls/winspool/winspool.drv.spec Mon Feb 12 09:32:58 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-20010211cvs/dlls/winspool/info.c Sun Feb 11 19:26:47 2001
+++ dlls/winspool/info.c Mon Feb 12 10:51:00 2001
@@ -2561,3 +2561,328 @@
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' */
+
+ hHeap = GetProcessHeap ();
+ if (hHeap == (HANDLE) NULL)
+ {
+ ERR ("GetProcessHeap failed\n");
+ REGCLOSEKEY (hkSubKey);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
+ if (lpValueName == NULL)
+ {
+ ERR ("Failed to allocate %li bytes from process heap\n",
+ cbMaxValueNameLen * sizeof (WCHAR));
+ REGCLOSEKEY (hkSubKey);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
+ if (lpValue == NULL)
+ {
+ ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
+ HEAPFREE (hHeap, 0, lpValueName);
+ 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); HEAPFREE (hHeap, 0, lpValueName);
+ 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); HEAPFREE (hHeap, 0, lpValueName);
+ 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); HEAPFREE (hHeap, 0, lpValueName);
+ 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); HEAPFREE (hHeap, 0, lpValueName);
+ 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);
+
+ hHeap = GetProcessHeap ();
+ if (hHeap == (HANDLE) NULL)
+ {
+ ERR ("GetProcessHeap failed\n");
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
+ if (pKeyNameW == NULL)
+ {
+ ERR ("Failed to allocate %li bytes from process heap\n",
+ (LONG) len * sizeof (WCHAR));
+ return ERROR_OUTOFMEMORY;
+ }
+
+ if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
+ {
+ HEAPFREE (hHeap, 0, pKeyNameW);
+ 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)
+ {
+ HEAPFREE (hHeap, 0, pKeyNameW);
+ TRACE ("EnumPrinterDataExW returned %li\n", ret);
+ return ret;
+ }
+
+ HEAPFREE (hHeap, 0, pKeyNameW);
+
+ 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);
+
+ 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