dplayx: Cache GUID values so they persist after enumeration

Bruno Jesus 00cpxxx at gmail.com
Wed Jan 14 17:09:49 CST 2015


The game Swing from bug 37185 expects that the GUID values returned
during callback persist after the end of enumeration. This patch
ensures that by caching the GUID values.

Superseeds 108582 and 108441 (off list already).

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..bae6a15 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -5785,6 +5785,11 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
     DWORD max_sizeOfDescriptionA = 0;
     WCHAR *descriptionW = NULL;
     DWORD max_sizeOfDescriptionW = 0;
+    DWORD sizeOfSubKeyName;
+    WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
+    LONG  ret_value;
+    static GUID *guid_cache;
+    static int cache_count;
     
     if (!lpEnumCallbackA && !lpEnumCallbackW)
     {
@@ -5799,19 +5804,37 @@ 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);
+    /* The game Swing from bug 37185 expects GUID values to persist after
+     * the end of the enumeration. */
+    if (cache_count < dwIndex)
+    {
+	HeapFree(GetProcessHeap(), 0, guid_cache);
+	guid_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID) * dwIndex);
+	if (!guid_cache)
+	{
+	    ERR(": failed to alloc required memory.\n");
+	    return DPERR_EXCEPTION;
+	}
+	cache_count = dwIndex;
+    }
     /* 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;
 	
+	sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
 	ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
 				  NULL, NULL, NULL, &filetime);
 	if (ret_value == ERROR_NO_MORE_ITEMS)
@@ -5842,7 +5865,7 @@ 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, &guid_cache[dwIndex]);
 	
 	/* The enumeration will return FALSE if we are not to continue.
 	 *
@@ -5870,7 +5893,7 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
 	    RegQueryValueExA(hkServiceProvider, "DescriptionA",
 			     NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
 	    
-	    if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
+	    if (!lpEnumCallbackA(&guid_cache[dwIndex], descriptionA, 6, 0, lpContext))
 		goto end;
 	}
 	else
@@ -5892,7 +5915,7 @@ static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
 	    RegQueryValueExW(hkServiceProvider, descW,
 			     NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
 
-	    if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
+	    if (!lpEnumCallbackW(&guid_cache[dwIndex], descriptionW, 6, 0, lpContext))
 		goto end;
 	}
       
diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c
index fb6646d..236e1a8 100644
--- a/dlls/dplayx/tests/dplayx.c
+++ b/dlls/dplayx/tests/dplayx.c
@@ -72,6 +72,13 @@ typedef struct tagCallbackData
     UINT dpidSize;
 } CallbackData, *lpCallbackData;
 
+struct provider_data
+{
+    int call_count;
+    GUID *guid_ptr[10];
+    GUID guid_data[10];
+    BOOL ret_value;
+};
 
 static LPSTR get_temp_buffer(void)
 {
@@ -749,6 +756,113 @@ static void test_DirectPlayCreate(void)
 
 }
 
+static BOOL CALLBACK callback_providersA(GUID* guid, char *name, DWORD major, DWORD minor, void *arg)
+{
+    struct provider_data *prov = arg;
+
+    if (!prov) return TRUE;
+
+    if (prov->call_count < sizeof(prov->guid_data) / sizeof(prov->guid_data[0]))
+    {
+        prov->guid_ptr[prov->call_count] = guid;
+        prov->guid_data[prov->call_count] = *guid;
+
+        prov->call_count++;
+    }
+
+    if (prov->ret_value) /* Only trace when looping all providers */
+        trace("Provider #%d '%s' (%d.%d)\n", prov->call_count, name, major, minor);
+    return prov->ret_value;
+}
+
+static BOOL CALLBACK callback_providersW(GUID* guid, WCHAR *name, DWORD major, DWORD minor, void *arg)
+{
+    struct provider_data *prov = arg;
+
+    if (!prov) return TRUE;
+
+    if (prov->call_count < sizeof(prov->guid_data) / sizeof(prov->guid_data[0]))
+    {
+        prov->guid_ptr[prov->call_count] = guid;
+        prov->guid_data[prov->call_count] = *guid;
+
+        prov->call_count++;
+    }
+
+    return prov->ret_value;
+}
+
+static void test_EnumerateProviders(void)
+{
+    HRESULT hr;
+    int i;
+    struct provider_data arg;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.ret_value = TRUE;
+
+    hr = DirectPlayEnumerateA(callback_providersA, NULL);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateA failed\n");
+
+    SetLastError(0xdeadbeef);
+    hr = DirectPlayEnumerateA(NULL, &arg);
+    ok(FAILED(hr), "DirectPlayEnumerateA expected to fail\n");
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%x\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    hr = DirectPlayEnumerateA(NULL, NULL);
+    ok(FAILED(hr), "DirectPlayEnumerateA expected to fail\n");
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%x\n", GetLastError());
+
+    hr = DirectPlayEnumerateA(callback_providersA, &arg);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateA failed\n");
+    ok(arg.call_count > 0, "Expected at least one valid provider\n");
+    trace("Found %d providers\n", arg.call_count);
+
+    /* The returned GUID values must have persisted after enumeration (bug 37185) */
+    for(i = 0; i < arg.call_count; i++)
+    {
+        ok(IsEqualGUID(arg.guid_ptr[i], &arg.guid_data[i]), "#%d Expected equal GUID values\n", i);
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    arg.ret_value = FALSE;
+    hr = DirectPlayEnumerateA(callback_providersA, &arg);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateA failed\n");
+    ok(arg.call_count == 1, "Expected 1, got %d\n", arg.call_count);
+
+    hr = DirectPlayEnumerateW(callback_providersW, NULL);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateW failed\n");
+
+    SetLastError(0xdeadbeef);
+    hr = DirectPlayEnumerateW(NULL, &arg);
+    ok(FAILED(hr), "DirectPlayEnumerateW expected to fail\n");
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%x\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    hr = DirectPlayEnumerateW(NULL, NULL);
+    ok(FAILED(hr), "DirectPlayEnumerateW expected to fail\n");
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%x\n", GetLastError());
+
+    memset(&arg, 0, sizeof(arg));
+    arg.ret_value = TRUE;
+    hr = DirectPlayEnumerateW(callback_providersW, &arg);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateW failed\n");
+    ok(arg.call_count > 0, "Expected at least one valid provider\n");
+
+    /* The returned GUID values must have persisted after enumeration (bug 37185) */
+    for(i = 0; i < arg.call_count; i++)
+    {
+        ok(IsEqualGUID(arg.guid_ptr[i], &arg.guid_data[i]), "#%d Expected equal GUID values\n", i);
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    arg.ret_value = FALSE;
+    hr = DirectPlayEnumerateW(callback_providersW, &arg);
+    ok(SUCCEEDED(hr), "DirectPlayEnumerateW failed\n");
+    ok(arg.call_count == 1, "Expected 1, got %d\n", arg.call_count);
+}
+
 /* EnumConnections */
 
 static BOOL CALLBACK EnumAddress_cb2( REFGUID guidDataType,
@@ -6544,6 +6658,7 @@ START_TEST(dplayx)
 
     test_COM();
     test_COM_dplobby();
+    test_EnumerateProviders();
 
     if (!winetest_interactive)
     {


More information about the wine-patches mailing list