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