shell32: Use shared IUnknown implementation for both vtables.
[wine/multimedia.git] / dlls / gameux / tests / gameexplorer.c
blob462fb8f8443f526b6b629423e84a0fb7cffaf879
1 /*
2 * IGameExplorer and IGameExplorer2 tests
4 * Copyright (C) 2010 Mariusz PluciƄski
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include "windows.h"
24 #include "ole2.h"
25 #include "objsafe.h"
26 #include "objbase.h"
27 #include "shlwapi.h"
28 #include "sddl.h"
29 #include "shobjidl.h"
31 #include "initguid.h"
32 #include "gameux.h"
34 #include "wine/test.h"
36 /* function from Shell32, not defined in header */
37 extern BOOL WINAPI GUIDFromStringW(LPCWSTR psz, LPGUID pguid);
39 /*******************************************************************************
40 * Pointers used instead of direct calls. These procedures are not available on
41 * older system, which causes problem while loading test binary.
43 static BOOL WINAPI (*_ConvertSidToStringSidW)(PSID,LPWSTR*);
44 static LONG WINAPI (*_RegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
46 /*******************************************************************************
47 *_loadDynamicRoutines
49 * Helper function, prepares pointers to system procedures which may be not
50 * available on older operating systems.
52 * Returns:
53 * TRUE procedures were loaded successfully
54 * FALSE procedures were not loaded successfully
56 static BOOL _loadDynamicRoutines(void)
58 HMODULE hAdvapiModule = GetModuleHandleA( "advapi32.dll" );
60 _ConvertSidToStringSidW = (LPVOID)GetProcAddress(hAdvapiModule, "ConvertSidToStringSidW");
61 if (!_ConvertSidToStringSidW) return FALSE;
62 _RegGetValueW = (LPVOID)GetProcAddress(hAdvapiModule, "RegGetValueW");
63 if (!_RegGetValueW) return FALSE;
64 return TRUE;
67 /*******************************************************************************
68 * _buildGameRegistryPath
70 * Helper function, builds registry path to key, where game's data are stored
72 * Parameters:
73 * installScope [I] the scope which was used in AddGame/InstallGame call
74 * gameInstanceId [I] game instance GUID. If NULL, then only
75 * path to scope is returned
76 * lpRegistryPath [O] pointer which will receive address to string
77 * containing expected registry path. Path
78 * is relative to HKLM registry key. It
79 * must be freed by calling CoTaskMemFree
81 static HRESULT _buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
82 LPCGUID gameInstanceId,
83 LPWSTR* lpRegistryPath)
85 static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\',
86 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
87 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
88 static const WCHAR sGames[] = {'G','a','m','e','s',0};
89 static const WCHAR sBackslash[] = {'\\',0};
91 HRESULT hr = S_OK;
92 HANDLE hToken = NULL;
93 PTOKEN_USER pTokenUser = NULL;
94 DWORD dwLength;
95 LPWSTR lpSID = NULL;
96 WCHAR sInstanceId[40];
97 WCHAR sRegistryPath[8192];
99 lstrcpyW(sRegistryPath, sGameUxRegistryPath);
100 lstrcatW(sRegistryPath, sBackslash);
102 if(installScope == GIS_CURRENT_USER)
104 /* build registry path containing user's SID */
105 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
106 hr = HRESULT_FROM_WIN32(GetLastError());
108 if(SUCCEEDED(hr))
110 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
111 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
112 hr = HRESULT_FROM_WIN32(GetLastError());
114 if(SUCCEEDED(hr))
116 pTokenUser = CoTaskMemAlloc(dwLength);
117 if(!pTokenUser)
118 hr = E_OUTOFMEMORY;
121 if(SUCCEEDED(hr))
122 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
123 hr = HRESULT_FROM_WIN32(GetLastError());
125 if(SUCCEEDED(hr))
126 if(!_ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
127 hr = HRESULT_FROM_WIN32(GetLastError());
129 if(SUCCEEDED(hr))
131 lstrcatW(sRegistryPath, lpSID);
132 LocalFree(lpSID);
135 CoTaskMemFree(pTokenUser);
136 CloseHandle(hToken);
139 else if(installScope == GIS_ALL_USERS)
140 /* build registry path without SID */
141 lstrcatW(sRegistryPath, sGames);
142 else
143 hr = E_INVALIDARG;
145 /* put game's instance id on the end of path, but only if id was passes */
146 if(gameInstanceId)
148 if(SUCCEEDED(hr))
149 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
151 if(SUCCEEDED(hr))
153 lstrcatW(sRegistryPath, sBackslash);
154 lstrcatW(sRegistryPath, sInstanceId);
158 if(SUCCEEDED(hr))
160 *lpRegistryPath = CoTaskMemAlloc((lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
161 if(!*lpRegistryPath)
162 hr = E_OUTOFMEMORY;
165 if(SUCCEEDED(hr))
166 lstrcpyW(*lpRegistryPath, sRegistryPath);
168 return hr;
170 /*******************************************************************************
171 * _validateRegistryValue
173 * Helper function, verifies single registry value with expected
175 * Parameters:
176 * hKey [I] handle to game's key. Key must be opened
177 * keyPath [I] string with path to game's key. Used only
178 * to display more useful message on test fail
179 * valueName [I] name of value to check
180 * dwExpectedType [I] expected type of value. It should be
181 * one of RRF_RT_* flags
182 * lpExpectedContent [I] expected content of value. It should be
183 * pointer to variable with same type as
184 * passed in dwExpectedType
186 * Returns:
187 * S_OK value exists and contains expected data
188 * S_FALSE value exists, but contains other data
189 * than expected
190 * E_OUTOFMEMORY allocation problem
191 * HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
192 * value does not exist
194 * Note: this function returns error codes instead of failing test case, because
195 * it is sometimes expected that given value may not exist on some systems, or
196 * contain other data.
198 static HRESULT _validateRegistryValue(
199 HKEY hKey,
200 LPCWSTR keyPath,
201 LPCWSTR valueName,
202 DWORD dwExpectedType,
203 LPCVOID lpExpectedContent)
205 HRESULT hr;
206 DWORD dwType, dwSize;
207 LPVOID lpData = NULL;
209 hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, NULL, &dwSize));
210 if(FAILED(hr)) trace("registry value cannot be opened\n"
211 " key: %s\n"
212 " value: %s\n"
213 " expected type: 0x%x\n"
214 " found type: 0x%x\n"
215 " result code: 0x%0x\n",
216 wine_dbgstr_w(keyPath),
217 wine_dbgstr_w(valueName),
218 dwExpectedType,
219 dwType,
220 hr);
222 if(SUCCEEDED(hr))
224 lpData = CoTaskMemAlloc(dwSize);
225 if(!lpData)
226 hr = E_OUTOFMEMORY;
229 if(SUCCEEDED(hr))
230 hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, lpData, &dwSize));
232 if(SUCCEEDED(hr))
234 if(memcmp(lpData, lpExpectedContent, dwSize)==0)
235 hr = S_OK;
236 else
238 if(dwExpectedType == RRF_RT_REG_SZ)
239 /* if value type is REG_SZ, display expected and found values */
240 trace("not expected content of registry value\n"
241 " key: %s\n"
242 " value: %s\n"
243 " expected REG_SZ content: %s\n"
244 " found REG_SZ content: %s\n",
245 wine_dbgstr_w(keyPath),
246 wine_dbgstr_w(valueName),
247 wine_dbgstr_w(lpExpectedContent),
248 wine_dbgstr_w(lpData));
249 else
250 /* in the other case, do not display content */
251 trace("not expected content of registry value\n"
252 " key: %s\n"
253 " value: %s\n"
254 " value type: 0x%x\n",
255 wine_dbgstr_w(keyPath),
256 wine_dbgstr_w(valueName),
257 dwType);
259 hr = S_FALSE;
263 CoTaskMemFree(lpData);
264 return hr;
266 /*******************************************************************************
267 * _validateGameRegistryValues
269 * Helper function, verifies values in game's registry key
271 * Parameters:
272 * line [I] place of original call. Used only to display
273 * more useful message on test fail
274 * hKey [I] handle to game's key. Key must be opened
275 * with KEY_READ access permission
276 * keyPath [I] string with path to game's key. Used only
277 * to display more useful message on test fail
278 * gameApplicationId [I] game application identifier
279 * gameExePath [I] directory where game executable is stored
280 * gameExeName [I] full path to executable, including directory and file name
282 static void _validateGameRegistryValues(int line,
283 HKEY hKey,
284 LPCWSTR keyPath,
285 LPCGUID gameApplicationId,
286 LPCWSTR gameExePath,
287 LPCWSTR gameExeName)
289 static const WCHAR sApplicationId[] = {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
290 static const WCHAR sConfigApplicationPath[] = {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
291 static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
292 static const WCHAR sDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
293 static const WCHAR sExampleGame[] = {'E','x','a','m','p','l','e',' ','G','a','m','e',0};
294 static const WCHAR sGameDescription[] = {'G','a','m','e',' ','D','e','s','c','r','i','p','t','i','o','n',0};
295 static const WCHAR sTitle[] = {'T','i','t','l','e',0};
297 HRESULT hr;
298 WCHAR sGameApplicationId[40];
300 hr = (StringFromGUID2(gameApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
301 ok_(__FILE__, line)(hr == S_OK, "cannot convert game application id to string\n");
303 /* these values exist up from Vista */
304 hr = _validateRegistryValue(hKey, keyPath, sApplicationId, RRF_RT_REG_SZ, sGameApplicationId);
305 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
306 hr = _validateRegistryValue(hKey, keyPath, sConfigApplicationPath, RRF_RT_REG_SZ, gameExePath);
307 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
308 hr = _validateRegistryValue(hKey, keyPath, sConfigGDFBinaryPath, RRF_RT_REG_SZ, gameExeName);
309 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
310 hr = _validateRegistryValue(hKey, keyPath, sTitle, RRF_RT_REG_SZ, sExampleGame);
311 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
313 /* this value exists up from Win7 */
314 hr = _validateRegistryValue(hKey, keyPath, sDescription, RRF_RT_REG_SZ, sGameDescription);
315 ok_(__FILE__, line)(hr==S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)), "failed while checking registry value (error 0x%x)\n", hr);
317 /*******************************************************************************
318 * _validateGameKey
320 * Helper function, verifies current state of game's registry key with expected.
322 * Parameters:
323 * line [I] place of original call. Used only to display
324 * more useful message on test fail
325 * installScope [I] the scope which was used in AddGame/InstallGame call
326 * gameInstanceId [I] game instance identifier
327 * gameApplicationId [I] game application identifier
328 * gameExePath [I] directory where game executable is stored
329 * gameExeName [I] full path to executable, including directory and file name
330 * presenceExpected [I] is it expected that game should be currently
331 * registered or not. Should be TRUE if checking
332 * after using AddGame/InstallGame, and FALSE
333 * if checking after RemoveGame/UninstallGame
335 static void _validateGameRegistryKey(int line,
336 GAME_INSTALL_SCOPE installScope,
337 LPCGUID gameInstanceId,
338 LPCGUID gameApplicationId,
339 LPCWSTR gameExePath,
340 LPCWSTR gameExeName,
341 BOOL presenceExpected)
343 HRESULT hr;
344 LPWSTR lpRegistryPath = NULL;
345 HKEY hKey;
347 /* check key presence */
348 hr = _buildGameRegistryPath(installScope, gameInstanceId, &lpRegistryPath);
350 if(SUCCEEDED(hr))
352 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0,
353 KEY_READ | KEY_WOW64_64KEY, &hKey));
355 if(presenceExpected)
356 ok_(__FILE__, line)(hr == S_OK,
357 "problem while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr);
358 else
359 ok_(__FILE__, line)(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
360 "other than expected (FILE_NOT_FOUND) error while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr);
363 if(SUCCEEDED(hr))
365 if(presenceExpected)
366 /* if the key exists and we expected it, let's verify it's content */
367 _validateGameRegistryValues(line, hKey, lpRegistryPath, gameApplicationId, gameExePath, gameExeName);
369 RegCloseKey(hKey);
372 CoTaskMemFree(lpRegistryPath);
375 /*******************************************************************************
376 * _LoadRegistryString
378 * Helper function, loads string from registry value and allocates buffer for it
380 * Parameters:
381 * hRootKey [I] base key for reading. Should be opened
382 * with KEY_READ permission
383 * lpRegistryKey [I] name of registry key, subkey of root key
384 * lpRegistryValue [I] name of registry value
385 * lpValue [O] pointer where address of received
386 * value will be stored. Value should be
387 * freed by CoTaskMemFree call
389 static HRESULT _LoadRegistryString(HKEY hRootKey,
390 LPCWSTR lpRegistryKey,
391 LPCWSTR lpRegistryValue,
392 LPWSTR* lpValue)
394 HRESULT hr;
395 DWORD dwSize;
397 *lpValue = NULL;
399 hr = HRESULT_FROM_WIN32(_RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
400 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
402 if(SUCCEEDED(hr))
404 *lpValue = CoTaskMemAlloc(dwSize);
405 if(!*lpValue)
406 hr = E_OUTOFMEMORY;
408 if(SUCCEEDED(hr))
409 hr = HRESULT_FROM_WIN32(_RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
410 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
412 return hr;
414 /*******************************************************************************
415 * _findGameInstanceId
417 * Helper function. Searches for instance identifier of given game in given
418 * installation scope.
420 * Parameters:
421 * line [I] line to display messages
422 * sGDFBinaryPath [I] path to binary containing GDF
423 * installScope [I] game install scope to search in
424 * pInstanceId [O] instance identifier of given game
426 static void _findGameInstanceId(int line,
427 LPWSTR sGDFBinaryPath,
428 GAME_INSTALL_SCOPE installScope,
429 GUID* pInstanceId)
431 static const WCHAR sConfigGDFBinaryPath[] =
432 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
434 HRESULT hr;
435 BOOL found = FALSE;
436 LPWSTR lpRegistryPath = NULL;
437 HKEY hRootKey;
438 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
439 LPWSTR lpName = NULL, lpValue = NULL;
441 hr = _buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
442 ok_(__FILE__, line)(SUCCEEDED(hr), "cannot get registry path to given scope: %d\n", installScope);
444 if(SUCCEEDED(hr))
445 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
446 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
447 lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey));
448 ok_(__FILE__, line)(SUCCEEDED(hr), "cannot open key registry key: %s\n", wine_dbgstr_w(lpRegistryPath));
450 if(SUCCEEDED(hr))
452 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
453 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
455 if(SUCCEEDED(hr))
457 ++dwMaxSubKeyLen; /* for string terminator */
458 lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR));
459 if(!lpName) hr = E_OUTOFMEMORY;
460 ok_(__FILE__, line)(SUCCEEDED(hr), "cannot allocate memory for key name");
463 if(SUCCEEDED(hr))
465 for(i=0; i<dwSubKeys && !found; ++i)
467 dwSubKeyLen = dwMaxSubKeyLen;
468 hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen,
469 NULL, NULL, NULL, NULL));
471 if(SUCCEEDED(hr))
472 hr = _LoadRegistryString(hRootKey, lpName,
473 sConfigGDFBinaryPath, &lpValue);
475 if(SUCCEEDED(hr))
476 if(lstrcmpW(lpValue, sGDFBinaryPath)==0)
478 /* key found, let's copy instance id and exit */
479 hr = (GUIDFromStringW(lpName, pInstanceId) ? S_OK : E_FAIL);
480 ok(SUCCEEDED(hr), "cannot convert subkey to guid: %s\n",
481 wine_dbgstr_w(lpName));
483 found = TRUE;
485 CoTaskMemFree(lpValue);
489 CoTaskMemFree(lpName);
490 RegCloseKey(hRootKey);
493 CoTaskMemFree(lpRegistryPath);
494 ok_(__FILE__, line)(found==TRUE, "cannot find game with GDF path %s in scope %d\n",
495 wine_dbgstr_w(sGDFBinaryPath), installScope);
497 /*******************************************************************************
498 * Test routines
500 static void test_create(BOOL* gameExplorerAvailable, BOOL* gameExplorer2Available)
502 HRESULT hr;
504 IGameExplorer* ge = NULL;
505 IGameExplorer2* ge2 = NULL;
507 /* interface available up from Vista */
508 hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*)&ge);
509 if(ge)
511 ok(hr == S_OK, "IGameExplorer creating failed (result false)\n");
512 *gameExplorerAvailable = TRUE;
513 IGameExplorer_Release(ge);
515 else
516 win_skip("IGameExplorer cannot be created\n");
518 /* interface available up from Win7 */
519 hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2);
520 if(ge2)
522 ok( hr == S_OK, "IGameExplorer2 creating failed (result false)\n");
523 *gameExplorer2Available = TRUE;
524 IGameExplorer2_Release(ge2);
526 else
527 win_skip("IGameExplorer2 cannot be created\n");
530 static void test_add_remove_game(void)
532 static const GUID defaultGUID = {0x01234567, 0x89AB, 0xCDEF,
533 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}};
534 static const GUID applicationId = { 0x17A6558E, 0x60BE, 0x4078,
535 { 0xB6, 0x6F, 0x9C, 0x3A, 0xDA, 0x2A, 0x32, 0xE6 }};
537 HRESULT hr;
539 IGameExplorer* ge = NULL;
540 WCHAR sExeName[MAX_PATH];
541 WCHAR sExePath[MAX_PATH];
542 BSTR bstrExeName = NULL, bstrExePath = NULL;
543 DWORD dwExeNameLen;
544 GUID guid;
546 hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*) & ge);
547 ok(ge != NULL, "cannot create coclass IGameExplorer\n");
548 ok(hr == S_OK, "cannot create coclass IGameExplorer\n");
550 if(ge)
552 /* prepare path to binary */
553 dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0]));
554 ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n");
555 lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1);
556 bstrExeName = SysAllocString(sExeName);
557 ok(bstrExeName != NULL, "cannot allocate string for exe name\n");
558 bstrExePath = SysAllocString(sExePath);
559 ok(bstrExePath != NULL, "cannot allocate string for exe path\n");
561 if(bstrExeName && bstrExePath)
563 trace("prepared EXE name: %s\n", wine_dbgstr_w(bstrExeName));
564 trace("prepared EXE path: %s\n", wine_dbgstr_w(bstrExePath));
567 /* try to register game with provided guid */
568 memcpy(&guid, &defaultGUID, sizeof (guid));
570 hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid);
571 ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
572 ok(memcmp(&guid, &defaultGUID, sizeof (guid)) == 0, "AddGame unexpectedly modified GUID\n");
574 if(SUCCEEDED(hr))
576 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
578 hr = IGameExplorer_RemoveGame(ge, guid);
579 ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
582 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
585 /* try to register game with empty guid */
586 memcpy(&guid, &GUID_NULL, sizeof (guid));
588 hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid);
589 ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
590 ok(memcmp(&guid, &GUID_NULL, sizeof (guid)) != 0, "AddGame did not modify GUID\n");
592 if(SUCCEEDED(hr))
594 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
596 hr = IGameExplorer_RemoveGame(ge, guid);
597 ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
600 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
603 /* free allocated resources */
604 SysFreeString(bstrExePath);
605 SysFreeString(bstrExeName);
607 IGameExplorer_Release(ge);
611 static void test_install_uninstall_game(void)
613 static const GUID applicationId = { 0x17A6558E, 0x60BE, 0x4078,
614 { 0xB6, 0x6F, 0x9C, 0x3A, 0xDA, 0x2A, 0x32, 0xE6 }};
616 HRESULT hr;
618 IGameExplorer2* ge2 = NULL;
619 WCHAR sExeName[MAX_PATH];
620 WCHAR sExePath[MAX_PATH];
621 DWORD dwExeNameLen;
622 GUID guid;
624 hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2);
625 ok(ge2 != NULL, "cannot create coclass IGameExplorer2\n");
626 ok(hr == S_OK, "cannot create coclass IGameExplorer2\n");
628 if(ge2)
630 /* prepare path to binary */
631 dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0]));
632 ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n");
633 lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1);
635 trace("prepared EXE name: %s\n", wine_dbgstr_w(sExeName));
636 trace("prepared EXE path: %s\n", wine_dbgstr_w(sExePath));
639 hr = IGameExplorer2_InstallGame(ge2, sExeName, sExePath, GIS_CURRENT_USER);
640 ok(SUCCEEDED(hr), "IGameExplorer2::InstallGame failed (error 0x%08x)\n", hr);
641 /* in comparison to AddGame, InstallGame does not return instance ID,
642 * so we need to find it manually */
643 _findGameInstanceId(__LINE__, sExeName, GIS_CURRENT_USER, &guid);
645 if(SUCCEEDED(hr))
647 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
649 hr = IGameExplorer2_UninstallGame(ge2, sExeName);
650 ok(SUCCEEDED(hr), "IGameExplorer2::UninstallGame failed (error 0x%08x)\n", hr);
653 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
655 IGameExplorer2_Release(ge2);
659 static void run_tests(void)
661 BOOL gameExplorerAvailable = FALSE;
662 BOOL gameExplorer2Available = FALSE;
664 test_create(&gameExplorerAvailable, &gameExplorer2Available);
666 if(gameExplorerAvailable)
667 test_add_remove_game();
669 if(gameExplorer2Available)
670 test_install_uninstall_game();
673 START_TEST(gameexplorer)
675 if(_loadDynamicRoutines())
677 HRESULT hr;
679 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
680 ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr);
681 trace("Running apartment threaded tests.\n");
682 run_tests();
683 if(SUCCEEDED(hr))
684 CoUninitialize();
686 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
687 ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr);
688 trace("Running multithreaded tests.\n");
689 run_tests();
690 if(SUCCEEDED(hr))
691 CoUninitialize();
693 else
694 /* this is not a failure, because both procedures loaded by address
695 * are always available on systems which has gameux.dll */
696 win_skip("too old system, cannot load required dynamic procedures\n");