dplayx: Cache the results of DirectPlayEnumerateAW()
Bruno Jesus
00cpxxx at gmail.com
Sun Jan 4 16:05:22 CST 2015
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
-------------- next part --------------
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;
More information about the wine-patches
mailing list