| /* |
| * IGameExplorer and IGameExplorer2 tests |
| * |
| * Copyright (C) 2010 Mariusz PluciĆski |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define COBJMACROS |
| |
| #include "windows.h" |
| #include "ole2.h" |
| #include "objsafe.h" |
| #include "objbase.h" |
| #include "shlwapi.h" |
| #include "sddl.h" |
| #include "shobjidl.h" |
| |
| #include "initguid.h" |
| #include "gameux.h" |
| |
| #include "wine/test.h" |
| |
| /******************************************************************************* |
| * Pointers used instead of direct calls. These procedures are not available on |
| * older system, which causes problem while loading test binary. |
| */ |
| static BOOL WINAPI (*_ConvertSidToStringSidW)(PSID,LPWSTR*); |
| static LONG WINAPI (*_RegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD); |
| |
| /******************************************************************************* |
| *_loadDynamicRoutines |
| * |
| * Helper function, prepares pointers to system procedures which may be not |
| * available on older operating systems. |
| * |
| * Returns: |
| * TRUE procedures were loaded successfully |
| * FALSE procedures were not loaded successfully |
| */ |
| static BOOL _loadDynamicRoutines(void) |
| { |
| HMODULE hAdvapiModule = GetModuleHandleA( "advapi32.dll" ); |
| |
| _ConvertSidToStringSidW = (LPVOID)GetProcAddress(hAdvapiModule, "ConvertSidToStringSidW"); |
| if (!_ConvertSidToStringSidW) return FALSE; |
| _RegGetValueW = (LPVOID)GetProcAddress(hAdvapiModule, "RegGetValueW"); |
| if (!_RegGetValueW) return FALSE; |
| return TRUE; |
| } |
| |
| /******************************************************************************* |
| * _buildGameRegistryPath |
| * |
| * Helper function, builds registry path to key, where game's data are stored |
| * |
| * Parameters: |
| * installScope [I] the scope which was used in AddGame/InstallGame call |
| * gameInstanceId [I] game instance GUID. If NULL, then only |
| * path to scope is returned |
| * lpRegistryPath [O] pointer which will receive address to string |
| * containing expected registry path. Path |
| * is relative to HKLM registry key. It |
| * must be freed by calling CoTaskMemFree |
| */ |
| static HRESULT _buildGameRegistryPath(GAME_INSTALL_SCOPE installScope, |
| LPCGUID gameInstanceId, |
| LPWSTR* lpRegistryPath) |
| { |
| static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\', |
| 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', |
| 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0}; |
| static const WCHAR sGames[] = {'G','a','m','e','s',0}; |
| static const WCHAR sBackslash[] = {'\\',0}; |
| |
| HRESULT hr = S_OK; |
| HANDLE hToken = NULL; |
| PTOKEN_USER pTokenUser = NULL; |
| DWORD dwLength; |
| LPWSTR lpSID = NULL; |
| WCHAR sInstanceId[40]; |
| WCHAR sRegistryPath[8192]; |
| |
| lstrcpyW(sRegistryPath, sGameUxRegistryPath); |
| lstrcatW(sRegistryPath, sBackslash); |
| |
| if(installScope == GIS_CURRENT_USER) |
| { |
| /* build registry path containing user's SID */ |
| if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) |
| hr = HRESULT_FROM_WIN32(GetLastError()); |
| |
| if(SUCCEEDED(hr)) |
| { |
| if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) && |
| GetLastError()!=ERROR_INSUFFICIENT_BUFFER) |
| hr = HRESULT_FROM_WIN32(GetLastError()); |
| |
| if(SUCCEEDED(hr)) |
| { |
| pTokenUser = CoTaskMemAlloc(dwLength); |
| if(!pTokenUser) |
| hr = E_OUTOFMEMORY; |
| } |
| |
| if(SUCCEEDED(hr)) |
| if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength)) |
| hr = HRESULT_FROM_WIN32(GetLastError()); |
| |
| if(SUCCEEDED(hr)) |
| if(!_ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID)) |
| hr = HRESULT_FROM_WIN32(GetLastError()); |
| |
| if(SUCCEEDED(hr)) |
| { |
| lstrcatW(sRegistryPath, lpSID); |
| LocalFree(lpSID); |
| } |
| |
| CoTaskMemFree(pTokenUser); |
| CloseHandle(hToken); |
| } |
| } |
| else if(installScope == GIS_ALL_USERS) |
| /* build registry path without SID */ |
| lstrcatW(sRegistryPath, sGames); |
| else |
| hr = E_INVALIDARG; |
| |
| /* put game's instance id on the end of path, but only if id was passes */ |
| if(gameInstanceId) |
| { |
| if(SUCCEEDED(hr)) |
| hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL); |
| |
| if(SUCCEEDED(hr)) |
| { |
| lstrcatW(sRegistryPath, sBackslash); |
| lstrcatW(sRegistryPath, sInstanceId); |
| } |
| } |
| |
| if(SUCCEEDED(hr)) |
| { |
| *lpRegistryPath = CoTaskMemAlloc((lstrlenW(sRegistryPath)+1)*sizeof(WCHAR)); |
| if(!*lpRegistryPath) |
| hr = E_OUTOFMEMORY; |
| } |
| |
| if(SUCCEEDED(hr)) |
| lstrcpyW(*lpRegistryPath, sRegistryPath); |
| |
| return hr; |
| } |
| /******************************************************************************* |
| * _validateRegistryValue |
| * |
| * Helper function, verifies single registry value with expected |
| * |
| * Parameters: |
| * hKey [I] handle to game's key. Key must be opened |
| * keyPath [I] string with path to game's key. Used only |
| * to display more useful message on test fail |
| * valueName [I] name of value to check |
| * dwExpectedType [I] expected type of value. It should be |
| * one of RRF_RT_* flags |
| * lpExpectedContent [I] expected content of value. It should be |
| * pointer to variable with same type as |
| * passed in dwExpectedType |
| * |
| * Returns: |
| * S_OK value exists and contains expected data |
| * S_FALSE value exists, but contains other data |
| * than expected |
| * E_OUTOFMEMORY allocation problem |
| * HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) |
| * value does not exist |
| * |
| * Note: this function returns error codes instead of failing test case, because |
| * it is sometimes expected that given value may not exist on some systems, or |
| * contain other data. |
| */ |
| static HRESULT _validateRegistryValue( |
| HKEY hKey, |
| LPCWSTR keyPath, |
| LPCWSTR valueName, |
| DWORD dwExpectedType, |
| LPCVOID lpExpectedContent) |
| { |
| HRESULT hr; |
| DWORD dwType, dwSize; |
| LPVOID lpData = NULL; |
| |
| hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, NULL, &dwSize)); |
| if(FAILED(hr)) trace("registry value cannot be opened\n" |
| " key: %s\n" |
| " value: %s\n" |
| " expected type: 0x%x\n" |
| " found type: 0x%x\n" |
| " result code: 0x%0x\n", |
| wine_dbgstr_w(keyPath), |
| wine_dbgstr_w(valueName), |
| dwExpectedType, |
| dwType, |
| hr); |
| |
| if(SUCCEEDED(hr)) |
| { |
| lpData = CoTaskMemAlloc(dwSize); |
| if(!lpData) |
| hr = E_OUTOFMEMORY; |
| } |
| |
| if(SUCCEEDED(hr)) |
| hr = HRESULT_FROM_WIN32(_RegGetValueW(hKey, NULL, valueName, dwExpectedType, &dwType, lpData, &dwSize)); |
| |
| if(SUCCEEDED(hr)) |
| { |
| if(memcmp(lpData, lpExpectedContent, dwSize)==0) |
| hr = S_OK; |
| else |
| { |
| if(dwExpectedType == RRF_RT_REG_SZ) |
| /* if value type is REG_SZ, display expected and found values */ |
| trace("not expected content of registry value\n" |
| " key: %s\n" |
| " value: %s\n" |
| " expected REG_SZ content: %s\n" |
| " found REG_SZ content: %s\n", |
| wine_dbgstr_w(keyPath), |
| wine_dbgstr_w(valueName), |
| wine_dbgstr_w(lpExpectedContent), |
| wine_dbgstr_w(lpData)); |
| else |
| /* in the other case, do not display content */ |
| trace("not expected content of registry value\n" |
| " key: %s\n" |
| " value: %s\n" |
| " value type: 0x%x\n", |
| wine_dbgstr_w(keyPath), |
| wine_dbgstr_w(valueName), |
| dwType); |
| |
| hr = S_FALSE; |
| } |
| } |
| |
| CoTaskMemFree(lpData); |
| return hr; |
| } |
| /******************************************************************************* |
| * _validateGameRegistryValues |
| * |
| * Helper function, verifies values in game's registry key |
| * |
| * Parameters: |
| * line [I] place of original call. Used only to display |
| * more useful message on test fail |
| * hKey [I] handle to game's key. Key must be opened |
| * with KEY_READ access permission |
| * keyPath [I] string with path to game's key. Used only |
| * to display more useful message on test fail |
| * gameApplicationId [I] game application identifier |
| * gameExePath [I] directory where game executable is stored |
| * gameExeName [I] full path to executable, including directory and file name |
| */ |
| static void _validateGameRegistryValues(int line, |
| HKEY hKey, |
| LPCWSTR keyPath, |
| LPCGUID gameApplicationId, |
| LPCWSTR gameExePath, |
| LPCWSTR gameExeName) |
| { |
| static const WCHAR sApplicationId[] = {'A','p','p','l','i','c','a','t','i','o','n','I','d',0}; |
| 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}; |
| static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0}; |
| static const WCHAR sDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0}; |
| static const WCHAR sExampleGame[] = {'E','x','a','m','p','l','e',' ','G','a','m','e',0}; |
| static const WCHAR sGameDescription[] = {'G','a','m','e',' ','D','e','s','c','r','i','p','t','i','o','n',0}; |
| static const WCHAR sTitle[] = {'T','i','t','l','e',0}; |
| |
| HRESULT hr; |
| WCHAR sGameApplicationId[40]; |
| |
| hr = (StringFromGUID2(gameApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL); |
| ok_(__FILE__, line)(hr == S_OK, "cannot convert game application id to string\n"); |
| |
| /* these values exist up from Vista */ |
| hr = _validateRegistryValue(hKey, keyPath, sApplicationId, RRF_RT_REG_SZ, sGameApplicationId); |
| ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr); |
| hr = _validateRegistryValue(hKey, keyPath, sConfigApplicationPath, RRF_RT_REG_SZ, gameExePath); |
| ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr); |
| hr = _validateRegistryValue(hKey, keyPath, sConfigGDFBinaryPath, RRF_RT_REG_SZ, gameExeName); |
| ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr); |
| hr = _validateRegistryValue(hKey, keyPath, sTitle, RRF_RT_REG_SZ, sExampleGame); |
| ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr); |
| |
| /* this value exists up from Win7 */ |
| hr = _validateRegistryValue(hKey, keyPath, sDescription, RRF_RT_REG_SZ, sGameDescription); |
| 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); |
| } |
| /******************************************************************************* |
| * _validateGameKey |
| * |
| * Helper function, verifies current state of game's registry key with expected. |
| * |
| * Parameters: |
| * line [I] place of original call. Used only to display |
| * more useful message on test fail |
| * installScope [I] the scope which was used in AddGame/InstallGame call |
| * gameInstanceId [I] game instance identifier |
| * gameApplicationId [I] game application identifier |
| * gameExePath [I] directory where game executable is stored |
| * gameExeName [I] full path to executable, including directory and file name |
| * presenceExpected [I] is it expected that game should be currently |
| * registered or not. Should be TRUE if checking |
| * after using AddGame/InstallGame, and FALSE |
| * if checking after RemoveGame/UninstallGame |
| */ |
| static void _validateGameRegistryKey(int line, |
| GAME_INSTALL_SCOPE installScope, |
| LPCGUID gameInstanceId, |
| LPCGUID gameApplicationId, |
| LPCWSTR gameExePath, |
| LPCWSTR gameExeName, |
| BOOL presenceExpected) |
| { |
| HRESULT hr; |
| LPWSTR lpRegistryPath = NULL; |
| HKEY hKey; |
| |
| /* check key presence */ |
| hr = _buildGameRegistryPath(installScope, gameInstanceId, &lpRegistryPath); |
| |
| if(SUCCEEDED(hr)) |
| { |
| hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, |
| KEY_READ | KEY_WOW64_64KEY, &hKey)); |
| |
| if(presenceExpected) |
| ok_(__FILE__, line)(hr == S_OK, |
| "problem while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr); |
| else |
| ok_(__FILE__, line)(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| "other than expected (FILE_NOT_FOUND) error while trying to open registry key (HKLM): %s, error: 0x%x\n", wine_dbgstr_w(lpRegistryPath), hr); |
| } |
| |
| if(SUCCEEDED(hr)) |
| { |
| if(presenceExpected) |
| /* if the key exists and we expected it, let's verify its content */ |
| _validateGameRegistryValues(line, hKey, lpRegistryPath, gameApplicationId, gameExePath, gameExeName); |
| |
| RegCloseKey(hKey); |
| } |
| |
| CoTaskMemFree(lpRegistryPath); |
| } |
| |
| /******************************************************************************* |
| * _LoadRegistryString |
| * |
| * Helper function, loads string from registry value and allocates buffer for it |
| * |
| * Parameters: |
| * hRootKey [I] base key for reading. Should be opened |
| * with KEY_READ permission |
| * lpRegistryKey [I] name of registry key, subkey of root key |
| * lpRegistryValue [I] name of registry value |
| * lpValue [O] pointer where address of received |
| * value will be stored. Value should be |
| * freed by CoTaskMemFree call |
| */ |
| static HRESULT _LoadRegistryString(HKEY hRootKey, |
| LPCWSTR lpRegistryKey, |
| LPCWSTR lpRegistryValue, |
| LPWSTR* lpValue) |
| { |
| HRESULT hr; |
| DWORD dwSize; |
| |
| *lpValue = NULL; |
| |
| hr = HRESULT_FROM_WIN32(_RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue, |
| RRF_RT_REG_SZ, NULL, NULL, &dwSize)); |
| |
| if(SUCCEEDED(hr)) |
| { |
| *lpValue = CoTaskMemAlloc(dwSize); |
| if(!*lpValue) |
| hr = E_OUTOFMEMORY; |
| } |
| if(SUCCEEDED(hr)) |
| hr = HRESULT_FROM_WIN32(_RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue, |
| RRF_RT_REG_SZ, NULL, *lpValue, &dwSize)); |
| |
| return hr; |
| } |
| /******************************************************************************* |
| * _findGameInstanceId |
| * |
| * Helper function. Searches for instance identifier of given game in given |
| * installation scope. |
| * |
| * Parameters: |
| * line [I] line to display messages |
| * sGDFBinaryPath [I] path to binary containing GDF |
| * installScope [I] game install scope to search in |
| * pInstanceId [O] instance identifier of given game |
| */ |
| static void _findGameInstanceId(int line, |
| LPWSTR sGDFBinaryPath, |
| GAME_INSTALL_SCOPE installScope, |
| GUID* pInstanceId) |
| { |
| static const WCHAR sConfigGDFBinaryPath[] = |
| {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0}; |
| |
| HRESULT hr; |
| BOOL found = FALSE; |
| LPWSTR lpRegistryPath = NULL; |
| HKEY hRootKey; |
| DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i; |
| LPWSTR lpName = NULL, lpValue = NULL; |
| |
| hr = _buildGameRegistryPath(installScope, NULL, &lpRegistryPath); |
| ok_(__FILE__, line)(SUCCEEDED(hr), "cannot get registry path to given scope: %d\n", installScope); |
| |
| if(SUCCEEDED(hr)) |
| /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */ |
| hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
| lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey)); |
| ok_(__FILE__, line)(SUCCEEDED(hr), "cannot open key registry key: %s\n", wine_dbgstr_w(lpRegistryPath)); |
| |
| if(SUCCEEDED(hr)) |
| { |
| hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL, |
| &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL)); |
| |
| if(SUCCEEDED(hr)) |
| { |
| ++dwMaxSubKeyLen; /* for string terminator */ |
| lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR)); |
| if(!lpName) hr = E_OUTOFMEMORY; |
| ok_(__FILE__, line)(SUCCEEDED(hr), "cannot allocate memory for key name"); |
| } |
| |
| if(SUCCEEDED(hr)) |
| { |
| for(i=0; i<dwSubKeys && !found; ++i) |
| { |
| dwSubKeyLen = dwMaxSubKeyLen; |
| hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen, |
| NULL, NULL, NULL, NULL)); |
| |
| if(SUCCEEDED(hr)) |
| hr = _LoadRegistryString(hRootKey, lpName, |
| sConfigGDFBinaryPath, &lpValue); |
| |
| if(SUCCEEDED(hr)) |
| if(lstrcmpW(lpValue, sGDFBinaryPath)==0) |
| { |
| /* key found, let's copy instance id and exit */ |
| hr = CLSIDFromString(lpName, pInstanceId); |
| ok(SUCCEEDED(hr), "cannot convert subkey to guid: %s\n", |
| wine_dbgstr_w(lpName)); |
| |
| found = TRUE; |
| } |
| CoTaskMemFree(lpValue); |
| } |
| } |
| |
| CoTaskMemFree(lpName); |
| RegCloseKey(hRootKey); |
| } |
| |
| CoTaskMemFree(lpRegistryPath); |
| ok_(__FILE__, line)(found==TRUE, "cannot find game with GDF path %s in scope %d\n", |
| wine_dbgstr_w(sGDFBinaryPath), installScope); |
| } |
| /******************************************************************************* |
| * Test routines |
| */ |
| static void test_create(BOOL* gameExplorerAvailable, BOOL* gameExplorer2Available) |
| { |
| HRESULT hr; |
| |
| IGameExplorer* ge = NULL; |
| IGameExplorer2* ge2 = NULL; |
| |
| /* interface available up from Vista */ |
| hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*)&ge); |
| if(ge) |
| { |
| ok(hr == S_OK, "IGameExplorer creating failed (result false)\n"); |
| *gameExplorerAvailable = TRUE; |
| IGameExplorer_Release(ge); |
| } |
| else |
| win_skip("IGameExplorer cannot be created\n"); |
| |
| /* interface available up from Win7 */ |
| hr = CoCreateInstance( &CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2); |
| if(ge2) |
| { |
| ok( hr == S_OK, "IGameExplorer2 creating failed (result false)\n"); |
| *gameExplorer2Available = TRUE; |
| IGameExplorer2_Release(ge2); |
| } |
| else |
| win_skip("IGameExplorer2 cannot be created\n"); |
| } |
| |
| static void test_add_remove_game(void) |
| { |
| static const GUID defaultGUID = {0x01234567, 0x89AB, 0xCDEF, |
| { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}}; |
| static const GUID applicationId = { 0x17A6558E, 0x60BE, 0x4078, |
| { 0xB6, 0x6F, 0x9C, 0x3A, 0xDA, 0x2A, 0x32, 0xE6 }}; |
| |
| HRESULT hr; |
| |
| IGameExplorer* ge = NULL; |
| WCHAR sExeName[MAX_PATH]; |
| WCHAR sExePath[MAX_PATH]; |
| BSTR bstrExeName = NULL, bstrExePath = NULL; |
| DWORD dwExeNameLen; |
| GUID guid; |
| |
| hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer, (LPVOID*) & ge); |
| ok(ge != NULL, "cannot create coclass IGameExplorer\n"); |
| ok(hr == S_OK, "cannot create coclass IGameExplorer\n"); |
| |
| if(ge) |
| { |
| /* prepare path to binary */ |
| dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0])); |
| ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n"); |
| lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1); |
| bstrExeName = SysAllocString(sExeName); |
| ok(bstrExeName != NULL, "cannot allocate string for exe name\n"); |
| bstrExePath = SysAllocString(sExePath); |
| ok(bstrExePath != NULL, "cannot allocate string for exe path\n"); |
| |
| if(bstrExeName && bstrExePath) |
| { |
| trace("prepared EXE name: %s\n", wine_dbgstr_w(bstrExeName)); |
| trace("prepared EXE path: %s\n", wine_dbgstr_w(bstrExePath)); |
| |
| |
| /* try to register game with provided guid */ |
| memcpy(&guid, &defaultGUID, sizeof (guid)); |
| |
| hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid); |
| ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr); |
| ok(memcmp(&guid, &defaultGUID, sizeof (guid)) == 0, "AddGame unexpectedly modified GUID\n"); |
| |
| if(SUCCEEDED(hr)) |
| { |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE); |
| |
| hr = IGameExplorer_RemoveGame(ge, guid); |
| ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr); |
| } |
| |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE); |
| |
| |
| /* try to register game with empty guid */ |
| memcpy(&guid, &GUID_NULL, sizeof (guid)); |
| |
| hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid); |
| ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr); |
| ok(memcmp(&guid, &GUID_NULL, sizeof (guid)) != 0, "AddGame did not modify GUID\n"); |
| |
| if(SUCCEEDED(hr)) |
| { |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE); |
| |
| hr = IGameExplorer_RemoveGame(ge, guid); |
| ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr); |
| } |
| |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE); |
| } |
| |
| /* free allocated resources */ |
| SysFreeString(bstrExePath); |
| SysFreeString(bstrExeName); |
| |
| IGameExplorer_Release(ge); |
| } |
| } |
| |
| static void test_install_uninstall_game(void) |
| { |
| static const GUID applicationId = { 0x17A6558E, 0x60BE, 0x4078, |
| { 0xB6, 0x6F, 0x9C, 0x3A, 0xDA, 0x2A, 0x32, 0xE6 }}; |
| |
| HRESULT hr; |
| |
| IGameExplorer2* ge2 = NULL; |
| WCHAR sExeName[MAX_PATH]; |
| WCHAR sExePath[MAX_PATH]; |
| DWORD dwExeNameLen; |
| GUID guid; |
| |
| hr = CoCreateInstance(&CLSID_GameExplorer, NULL, CLSCTX_INPROC_SERVER, &IID_IGameExplorer2, (LPVOID*)&ge2); |
| ok(ge2 != NULL, "cannot create coclass IGameExplorer2\n"); |
| ok(hr == S_OK, "cannot create coclass IGameExplorer2\n"); |
| |
| if(ge2) |
| { |
| /* prepare path to binary */ |
| dwExeNameLen = GetModuleFileNameW(NULL, sExeName, sizeof (sExeName) / sizeof (sExeName[0])); |
| ok(dwExeNameLen != 0, "GetModuleFileNameW returned invalid value\n"); |
| lstrcpynW(sExePath, sExeName, StrRChrW(sExeName, NULL, '\\') - sExeName + 1); |
| |
| trace("prepared EXE name: %s\n", wine_dbgstr_w(sExeName)); |
| trace("prepared EXE path: %s\n", wine_dbgstr_w(sExePath)); |
| |
| |
| hr = IGameExplorer2_InstallGame(ge2, sExeName, sExePath, GIS_CURRENT_USER); |
| ok(SUCCEEDED(hr), "IGameExplorer2::InstallGame failed (error 0x%08x)\n", hr); |
| /* in comparison to AddGame, InstallGame does not return instance ID, |
| * so we need to find it manually */ |
| _findGameInstanceId(__LINE__, sExeName, GIS_CURRENT_USER, &guid); |
| |
| if(SUCCEEDED(hr)) |
| { |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE); |
| |
| hr = IGameExplorer2_UninstallGame(ge2, sExeName); |
| ok(SUCCEEDED(hr), "IGameExplorer2::UninstallGame failed (error 0x%08x)\n", hr); |
| } |
| |
| _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE); |
| |
| IGameExplorer2_Release(ge2); |
| } |
| } |
| |
| static void run_tests(void) |
| { |
| BOOL gameExplorerAvailable = FALSE; |
| BOOL gameExplorer2Available = FALSE; |
| |
| test_create(&gameExplorerAvailable, &gameExplorer2Available); |
| |
| if(gameExplorerAvailable) |
| test_add_remove_game(); |
| |
| if(gameExplorer2Available) |
| test_install_uninstall_game(); |
| } |
| |
| START_TEST(gameexplorer) |
| { |
| if(_loadDynamicRoutines()) |
| { |
| HRESULT hr; |
| |
| hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); |
| ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr); |
| trace("Running multithreaded tests.\n"); |
| run_tests(); |
| if(SUCCEEDED(hr)) |
| CoUninitialize(); |
| |
| hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); |
| ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr); |
| trace("Running apartment threaded tests.\n"); |
| run_tests(); |
| if(SUCCEEDED(hr)) |
| CoUninitialize(); |
| } |
| else |
| /* this is not a failure, because both procedures loaded by address |
| * are always available on systems which has gameux.dll */ |
| win_skip("too old system, cannot load required dynamic procedures\n"); |
| } |