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                                       [EMAIL PROTECTED]
========================================================================
--- ../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

Reply via email to