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