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
34 #include "wine/test.h"
36 /*******************************************************************************
37 * Pointers used instead of direct calls. These procedures are not available on
38 * older system, which causes problem while loading test binary.
40 static BOOL WINAPI (*_ConvertSidToStringSidW)(PSID,LPWSTR*);
41 static LONG WINAPI (*_RegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
43 /*******************************************************************************
46 * Helper function, prepares pointers to system procedures which may be not
47 * available on older operating systems.
50 * TRUE procedures were loaded successfunnly
51 * FALSE procedures were not loaded successfunnly
53 static BOOL _loadDynamicRoutines(void)
55 HMODULE hAdvapiModule = GetModuleHandleA( "advapi32.dll" );
57 _ConvertSidToStringSidW = (LPVOID)GetProcAddress(hAdvapiModule, "ConvertSidToStringSidW");
58 if (!_ConvertSidToStringSidW) return FALSE;
59 _RegGetValueW = (LPVOID)GetProcAddress(hAdvapiModule, "RegGetValueW");
60 if (!_RegGetValueW) return FALSE;
64 /*******************************************************************************
65 * _buildGameRegistryPath
67 * Helper function, builds registry path to key, where game's data are stored
70 * installScope [I] the scope which was used in AddGame/InstallGame call
71 * gameInstanceId [I] game instance GUID
72 * lpRegistryPath [O] pointer which will receive address to string
73 * containing expected registry path. Path
74 * is relative to HKLM registry key. It
75 * must be freed by calling CoTaskMemFree
77 static HRESULT _buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
78 LPCGUID gameInstanceId,
79 LPWSTR* lpRegistryPath)
81 static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\',
82 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
83 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
84 static const WCHAR sGames[] = {'G','a','m','e','s',0};
85 static const WCHAR sBackslash[] = {'\\',0};
89 PTOKEN_USER pTokenUser = NULL;
92 WCHAR sInstanceId[40];
93 WCHAR sRegistryPath[8192];
95 lstrcpyW(sRegistryPath, sGameUxRegistryPath);
96 lstrcatW(sRegistryPath, sBackslash);
98 if(installScope == GIS_CURRENT_USER)
100 /* build registry path containing user's SID */
101 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
102 hr = HRESULT_FROM_WIN32(GetLastError());
106 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
107 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
108 hr = HRESULT_FROM_WIN32(GetLastError());
112 pTokenUser = CoTaskMemAlloc(dwLength);
118 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
119 hr = HRESULT_FROM_WIN32(GetLastError());
122 if(!_ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
123 hr = HRESULT_FROM_WIN32(GetLastError());
127 lstrcatW(sRegistryPath, lpSID);
131 CoTaskMemFree(pTokenUser);
135 else if(installScope == GIS_ALL_USERS)
136 /* build registry path without SID */
137 lstrcatW(sRegistryPath, sGames);
141 /* put game's instance id on the end of path */
143 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
147 lstrcatW(sRegistryPath, sBackslash);
148 lstrcatW(sRegistryPath, sInstanceId);
153 *lpRegistryPath = CoTaskMemAlloc((lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
159 lstrcpyW(*lpRegistryPath, sRegistryPath);
163 /*******************************************************************************
164 * _validateRegistryValue
166 * Helper function, verifies single registry value with expected
169 * hKey [I] handle to game's key. Key must be opened
170 * keyPath [I] string with path to game's key. Used only
171 * to display more useful message on test fail
172 * valueName [I] name of value to check
173 * dwExpectedType [I] expected type of value. It should be
174 * one of RRF_RT_* flags
175 * lpExpectedContent [I] expected content of value. It should be
176 * pointer to variable with same type as
177 * passed in dwExpectedType
180 * S_OK value exists and contains expected data
181 * S_FALSE value exists, but contains other data
183 * E_OUTOFMEMORY allocation problem
184 * HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
185 * value does not exist
187 * Note: this function returns error codes instead of failing test case, because
188 * it is sometimes expected that given value may not exist on some systems, or
189 * contain other data.
191 static HRESULT _validateRegistryValue(
195 DWORD dwExpectedType,
196 LPCVOID lpExpectedContent)
199 DWORD dwType, dwSize;
200 LPVOID lpData = NULL;
202 hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, NULL, &dwSize));
203 if(FAILED(hr)) trace("registry value cannot be opened\n"
206 " expected type: 0x%x\n"
207 " found type: 0x%x\n"
208 " result code: 0x%0x\n",
209 wine_dbgstr_w(keyPath),
210 wine_dbgstr_w(valueName),
217 lpData = CoTaskMemAlloc(dwSize);
223 hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, lpData, &dwSize));
227 if(memcmp(lpData, lpExpectedContent, dwSize)==0)
231 if(dwExpectedType == RRF_RT_REG_SZ)
232 /* if value type is REG_SZ, display expected and found values */
233 trace("not expected content of registry value\n"
236 " expected REG_SZ content: %s\n"
237 " found REG_SZ content: %s\n",
238 wine_dbgstr_w(keyPath),
239 wine_dbgstr_w(valueName),
240 wine_dbgstr_w(lpExpectedContent),
241 wine_dbgstr_w(lpData));
243 /* in the other case, do not display content */
244 trace("not expected content of registry value\n"
247 " value type: 0x%x\n",
248 wine_dbgstr_w(keyPath),
249 wine_dbgstr_w(valueName),
256 CoTaskMemFree(lpData);
259 /*******************************************************************************
260 * _validateGameRegistryValues
262 * Helper function, verifies values in game's registry key
265 * line [I] place of original call. Used only to display
266 * more useful message on test fail
267 * hKey [I] handle to game's key. Key must be opened
268 * with KEY_READ access permission
269 * keyPath [I] string with path to game's key. Used only
270 * to display more useful message on test fail
271 * gameApplicationId [I] game application identifier
272 * gameExePath [I] directory where game executable is stored
273 * gameExeName [I] full path to executable, including directory and file name
275 static void _validateGameRegistryValues(int line,
278 LPCGUID gameApplicationId,
282 static const WCHAR sApplicationId[] = {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
283 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};
284 static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
285 static const WCHAR sDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
286 static const WCHAR sExampleGame[] = {'E','x','a','m','p','l','e',' ','G','a','m','e',0};
287 static const WCHAR sGameDescription[] = {'G','a','m','e',' ','D','e','s','c','r','i','p','t','i','o','n',0};
288 static const WCHAR sTitle[] = {'T','i','t','l','e',0};
291 WCHAR sGameApplicationId[40];
293 hr = (StringFromGUID2(gameApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
294 ok_(__FILE__, line)(hr == S_OK, "cannot convert game application id to string\n");
296 /* these values exist up from Vista */
297 hr = _validateRegistryValue(hKey, keyPath, sApplicationId, RRF_RT_REG_SZ, sGameApplicationId);
298 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
299 hr = _validateRegistryValue(hKey, keyPath, sConfigApplicationPath, RRF_RT_REG_SZ, gameExePath);
300 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
301 hr = _validateRegistryValue(hKey, keyPath, sConfigGDFBinaryPath, RRF_RT_REG_SZ, gameExeName);
302 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
303 hr = _validateRegistryValue(hKey, keyPath, sTitle, RRF_RT_REG_SZ, sExampleGame);
304 ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
306 /* this value exists up from Win7 */
307 hr = _validateRegistryValue(hKey, keyPath, sDescription, RRF_RT_REG_SZ, sGameDescription);
308 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);
310 /*******************************************************************************
313 * Helper function, verifies current state of game's registry key with expected.
316 * line [I] place of original call. Used only to display
317 * more useful message on test fail
318 * installScope [I] the scope which was used in AddGame/InstallGame call
319 * gameInstanceId [I] game instance identifier
320 * gameApplicationId [I] game application identifier
321 * gameExePath [I] directory where game executable is stored
322 * gameExeName [I] full path to executable, including directory and file name
323 * presenceExpected [I] is it expected that game should be currently
324 * registered or not. Should be TRUE if checking
325 * after using AddGame/InstallGame, and FALSE
326 * if checking after RemoveGame/UninstallGame
328 static void _validateGameRegistryKey(int line,
329 GAME_INSTALL_SCOPE installScope,
330 LPCGUID gameInstanceId,
331 LPCGUID gameApplicationId,
334 BOOL presenceExpected)
337 LPWSTR lpRegistryPath = NULL;
340 /* check key presence */
341 hr = _buildGameRegistryPath(installScope, gameInstanceId, &lpRegistryPath);
345 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0,
346 KEY_READ | KEY_WOW64_64KEY, &hKey));
349 ok_(__FILE__, line)(hr == S_OK,
350 "problem while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr);
352 ok_(__FILE__, line)(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
353 "other than expected (FILE_NOT_FOUND) error while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr);
359 /* if the key exists and we expected it, let's verify it's content */
360 _validateGameRegistryValues(line, hKey, lpRegistryPath, gameApplicationId, gameExePath, gameExeName);
365 CoTaskMemFree(lpRegistryPath);
368 /*******************************************************************************
371 static void test_create(BOOL* gameExplorerAvailable, BOOL* gameExplorer2Available)
375 IGameExplorer* ge = NULL;
376 IGameExplorer2* ge2 = NULL;
378 /* interface available up from Vista */
379 hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*)&ge);
382 ok(hr == S_OK, "IGameExplorer creating failed (result false)\n");
383 *gameExplorerAvailable = TRUE;
384 IGameExplorer_Release(ge);
387 win_skip("IGameExplorer cannot be created\n");
389 /* interface available up from Win7 */
390 hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2);
393 ok( hr == S_OK, "IGameExplorer2 creating failed (result false)\n");
394 *gameExplorer2Available = TRUE;
395 IGameExplorer2_Release(ge2);
398 win_skip("IGameExplorer2 cannot be created\n");
401 static void test_add_remove_game(void)
403 static const GUID defaultGUID = {0x01234567, 0x89AB, 0xCDEF,
404 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}};
405 static const GUID applicationId = { 0x17A6558E, 0x60BE, 0x4078,
406 { 0xB6, 0x6F, 0x9C, 0x3A, 0xDA, 0x2A, 0x32, 0xE6 }};
410 IGameExplorer* ge = NULL;
411 WCHAR sExeName[MAX_PATH];
412 WCHAR sExePath[MAX_PATH];
413 BSTR bstrExeName = NULL, bstrExePath = NULL;
417 hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*) & ge);
418 ok(ge != NULL, "cannot create coclass IGameExplorer\n");
419 ok(hr == S_OK, "cannot create coclass IGameExplorer\n");
423 /* prepare path to binary */
424 dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0]));
425 ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n");
426 lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1);
427 bstrExeName = SysAllocString(sExeName);
428 ok(bstrExeName != NULL, "cannot allocate string for exe name\n");
429 bstrExePath = SysAllocString(sExePath);
430 ok(bstrExePath != NULL, "cannot allocate string for exe path\n");
432 if(bstrExeName && bstrExePath)
434 trace("prepared EXE name: %s\n", wine_dbgstr_w(bstrExeName));
435 trace("prepared EXE path: %s\n", wine_dbgstr_w(bstrExePath));
438 /* try to register game with provided guid */
439 memcpy(&guid, &defaultGUID, sizeof (guid));
441 hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid);
442 ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
443 ok(memcmp(&guid, &defaultGUID, sizeof (guid)) == 0, "AddGame unexpectedly modified GUID\n");
447 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
449 hr = IGameExplorer_RemoveGame(ge, guid);
450 ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
453 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
456 /* try to register game with empty guid */
457 memcpy(&guid, &GUID_NULL, sizeof (guid));
459 hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid);
460 ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
461 ok(memcmp(&guid, &GUID_NULL, sizeof (guid)) != 0, "AddGame did not modify GUID\n");
465 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
467 hr = IGameExplorer_RemoveGame(ge, guid);
468 ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
471 _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
474 /* free allocated resources */
475 SysFreeString(bstrExePath);
476 SysFreeString(bstrExeName);
478 IGameExplorer_Release(ge);
481 void test_install_uninstall_game(void)
485 IGameExplorer2* ge2 = NULL;
486 WCHAR sExeName[MAX_PATH];
487 WCHAR sExePath[MAX_PATH];
490 hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2);
491 ok(ge2 != NULL, "cannot create coclass IGameExplorer2\n");
492 ok(hr == S_OK, "cannot create coclass IGameExplorer2\n");
496 /* prepare path to binary */
497 dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0]));
498 ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n");
499 lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1);
501 trace("prepared EXE name: %s\n", wine_dbgstr_w(sExeName));
502 trace("prepared EXE path: %s\n", wine_dbgstr_w(sExePath));
505 hr = IGameExplorer2_InstallGame(ge2, sExeName, sExePath, GIS_CURRENT_USER);
506 todo_wine ok(SUCCEEDED(hr), "IGameExplorer2::InstallGame failed (error 0x%08x)\n", hr);
510 hr = IGameExplorer2_UninstallGame(ge2, sExeName);
511 todo_wine ok(SUCCEEDED(hr), "IGameExplorer2::UninstallGame failed (error 0x%08x)\n", hr);
514 IGameExplorer2_Release(ge2);
518 START_TEST(gameexplorer)
521 BOOL gameExplorerAvailable = FALSE;
522 BOOL gameExplorer2Available = FALSE;
524 if(_loadDynamicRoutines())
526 r = CoInitialize( NULL );
527 ok( r == S_OK, "failed to init COM\n");
529 test_create(&gameExplorerAvailable, &gameExplorer2Available);
531 if(gameExplorerAvailable)
532 test_add_remove_game();
534 if(gameExplorer2Available)
535 test_install_uninstall_game();
538 /* this is not a failure, because both procedures loaded by address
539 * are always available on systems which has gameux.dll */
540 win_skip("too old system, cannot load required dynamic procedures\n");