From: Bruno Jesus <00cpxxx@gmail.com> Subject: dplayx: Cache the results of DirectPlayEnumerateAW() Message-Id: Date: Sun, 4 Jan 2015 20:05:22 -0200 The game Swing expects the callback variables to persist after the end of the providers enumeration, the patch creates a data cache and allows the game to run properly. Also removes the duplicated code to deal with A/W use. Analysis: https://bugs.winehq.org/show_bug.cgi?id=37185#c10 Fixes bug https://bugs.winehq.org/show_bug.cgi?id=37185 diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 36e97a6..479e7b9 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -5778,13 +5778,20 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA, static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 }; static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 }; - DWORD dwIndex; + DWORD dwIndex, i; + LONG ret_value; FILETIME filetime; + WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */ + DWORD sizeOfSubKeyName; - char *descriptionA = NULL; - DWORD max_sizeOfDescriptionA = 0; WCHAR *descriptionW = NULL; DWORD max_sizeOfDescriptionW = 0; + static struct _data + { + GUID guid; + WCHAR descriptionW[256]; + char descriptionA[256]; + } *providers_cache; if (!lpEnumCallbackA && !lpEnumCallbackW) { @@ -5799,19 +5806,38 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA, ERR(": no service provider key in the registry - check your Wine installation !!!\n"); return DPERR_GENERIC; } - + + dwIndex = 0; + do + { + sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR); + ret_value = RegEnumKeyW(hkResult, dwIndex, subKeyName, sizeOfSubKeyName); + dwIndex++; + } + while (ret_value == ERROR_SUCCESS); + + /* Some applications require that the data returned through the callback persist after the callbacks + * are called, so we buffer the information first and do the callbacks later. We will always rewrite + * the buffer as some applications may change it (on purpose or due to bugs). + */ + HeapFree(GetProcessHeap(), 0, providers_cache); + providers_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(*providers_cache) * dwIndex); + if (!providers_cache) + { + ERR(": failed to alloc required memory.\n"); + return DPERR_EXCEPTION; + } + /* Traverse all the service providers we have available */ dwIndex = 0; while (1) { - WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */ - DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR); HKEY hkServiceProvider; - GUID serviceProviderGUID; WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ]; DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent); - LONG ret_value; + DWORD sizeOfDescription = 0; + sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR); ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, &filetime); if (ret_value == ERROR_NO_MORE_ITEMS) @@ -5842,65 +5868,43 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA, ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent)); continue; } - CLSIDFromString(guidKeyContent, &serviceProviderGUID ); - + CLSIDFromString(guidKeyContent, &providers_cache[dwIndex].guid); + + if (RegQueryValueExW(hkServiceProvider, descW, + NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS) + { + ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName)); + continue; + } + if (sizeOfDescription > max_sizeOfDescriptionW) + { + HeapFree(GetProcessHeap(), 0, descriptionW); + max_sizeOfDescriptionW = sizeOfDescription; + } + descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription); + RegQueryValueExW(hkServiceProvider, descW, + NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription); + + lstrcpynW(providers_cache[dwIndex].descriptionW, descriptionW, sizeof(providers_cache[0].descriptionW)); + WideCharToMultiByte(CP_ACP, 0, providers_cache[dwIndex].descriptionW, -1, providers_cache[dwIndex].descriptionA, + sizeof(providers_cache[0].descriptionA), NULL, NULL); + + dwIndex++; + } + for (i = 0; i < dwIndex; i++) + { /* The enumeration will return FALSE if we are not to continue. * * Note: on my windows box, major / minor version is 6 / 0 for all service providers * and have no relation to any of the two dwReserved1 and dwReserved2 keys. * I think that it simply means that they are in-line with DirectX 6.0 */ - if (lpEnumCallbackA) - { - DWORD sizeOfDescription = 0; - - /* Note that this is the A case of this function, so use the A variant to get the description string */ - if (RegQueryValueExA(hkServiceProvider, "DescriptionA", - NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS) - { - ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName)); - continue; - } - if (sizeOfDescription > max_sizeOfDescriptionA) - { - HeapFree(GetProcessHeap(), 0, descriptionA); - max_sizeOfDescriptionA = sizeOfDescription; - } - descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription); - RegQueryValueExA(hkServiceProvider, "DescriptionA", - NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription); - - if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext)) - goto end; - } - else - { - DWORD sizeOfDescription = 0; - - if (RegQueryValueExW(hkServiceProvider, descW, - NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS) - { - ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName)); - continue; - } - if (sizeOfDescription > max_sizeOfDescriptionW) - { - HeapFree(GetProcessHeap(), 0, descriptionW); - max_sizeOfDescriptionW = sizeOfDescription; - } - descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription); - RegQueryValueExW(hkServiceProvider, descW, - NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription); - - if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext)) - goto end; - } - - dwIndex++; - } + if (lpEnumCallbackA && !lpEnumCallbackA(&providers_cache[i].guid, providers_cache[i].descriptionA, 6, 0, lpContext)) + break; + if (lpEnumCallbackW && !lpEnumCallbackW(&providers_cache[i].guid, providers_cache[i].descriptionW, 6, 0, lpContext)) + break; + } - end: - HeapFree(GetProcessHeap(), 0, descriptionA); HeapFree(GetProcessHeap(), 0, descriptionW); return DP_OK;