gameux: Initial implementation of IGameExplorer::AddGame.

This commit is contained in:
Mariusz Pluciński 2010-09-07 15:34:41 +02:00 committed by Alexandre Julliard
parent b46183a2b4
commit 0949e083ec
4 changed files with 322 additions and 15 deletions

View File

@ -4,7 +4,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = gameux.dll
IMPORTS = uuid ole32 user32 advapi32
IMPORTS = uuid ole32 user32 advapi32 oleaut32
C_SRCS = \
factory.c \

View File

@ -22,15 +22,261 @@
#include "config.h"
#include "ole2.h"
#include "sddl.h"
#include "gameux.h"
#include "gameux_private.h"
#include "wine/debug.h"
#include "winreg.h"
WINE_DEFAULT_DEBUG_CHANNEL(gameux);
/*
/*******************************************************************************
* GameUX helper functions
*/
/*******************************************************************************
* GAMEUX_initGameData
*
* Internal helper function. Description available in gameux_private.h file
*/
void GAMEUX_initGameData(struct GAMEUX_GAME_DATA *GameData)
{
GameData->sGDFBinaryPath = NULL;
GameData->sGameInstallDirectory = NULL;
}
/*******************************************************************************
* GAMEUX_uninitGameData
*
* Internal helper function. Description available in gameux_private.h file
*/
void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA *GameData)
{
HeapFree(GetProcessHeap(), 0, GameData->sGDFBinaryPath);
HeapFree(GetProcessHeap(), 0, GameData->sGameInstallDirectory);
}
/*******************************************************************************
* GAMEUX_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
* 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 HeapFree(GetProcessHeap(), 0, ...)
*
* Name of game's registry key always follows patterns below:
* When game is installed for current user only (installScope is GIS_CURRENT_USER):
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
* GameUX\[user's security ID]\[game instance ID]
*
* When game is installed for all users (installScope is GIS_ALL_USERS):
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
* GameUX\Games\[game instance ID]
*
*
*/
static HRESULT GAMEUX_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];
TRACE("(0x%x, %s, %p)\n", installScope, debugstr_guid(gameInstanceId), lpRegistryPath);
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 = HeapAlloc(GetProcessHeap(), 0, 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);
}
HeapFree(GetProcessHeap(), 0, 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 */
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 = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
if(!*lpRegistryPath)
hr = E_OUTOFMEMORY;
}
if(SUCCEEDED(hr))
lstrcpyW(*lpRegistryPath, sRegistryPath);
TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
return hr;
}
/*******************************************************************************
* GAMEUX_WriteRegistryRecord
*
* Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
* structure) into expected place in registry.
*
* Parameters:
* GameData [I] structure with data which will
* be written into registry.
* Proper values of fields installScope
* and guidInstanceId are required
* to create registry key.
*
* Schema of naming registry keys associated with games is available in
* description of _buildGameRegistryPath internal function.
*
* List of registry keys associated with structure fields:
* Key Field in GAMEUX_GAME_DATA structure
* ConfigApplicationPath sGameInstallDirectory
* ConfigGDFBinaryPath sGDFBinaryPath
*
*/
static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
{
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};
HRESULT hr, hr2;
LPWSTR lpRegistryKey;
HKEY hKey;
TRACE("(%p)\n", GameData);
hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
if(SUCCEEDED(hr))
hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
0, NULL, 0, KEY_ALL_ACCESS, NULL,
&hKey, NULL));
if(SUCCEEDED(hr))
{
/* write game data to registry key */
hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigApplicationPath, 0,
REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
(lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
if(SUCCEEDED(hr))
hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
(lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
RegCloseKey(hKey);
if(FAILED(hr))
{
/* if something failed, remove whole key */
hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, 0, 0);
/* do not overwrite old failure code with new success code */
if(FAILED(hr2))
hr = hr2;
}
}
HeapFree(GetProcessHeap(), 0, lpRegistryKey);
TRACE("returning 0x%x\n", hr);
return hr;
}
/*******************************************************************************
* GAMEUX_RegisterGame
*
* Internal helper function. Description available in gameux_private.h file
*/
HRESULT WINAPI GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
LPCWSTR sGameInstallDirectory,
GAME_INSTALL_SCOPE installScope,
GUID *pInstanceID)
{
HRESULT hr = S_OK;
struct GAMEUX_GAME_DATA GameData;
TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
GAMEUX_initGameData(&GameData);
GameData.sGDFBinaryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath)+1)*sizeof(WCHAR));
lstrcpyW(GameData.sGDFBinaryPath, sGDFBinaryPath);
GameData.sGameInstallDirectory = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory)+1)*sizeof(WCHAR));
lstrcpyW(GameData.sGameInstallDirectory, sGameInstallDirectory);
GameData.installScope = installScope;
/* generate GUID if it was not provided by user */
if(IsEqualGUID(pInstanceID, &GUID_NULL))
hr = CoCreateGuid(pInstanceID);
GameData.guidInstanceId = *pInstanceID;
FIXME("loading game data from GDF file not yet implemented\n");
/* save data to registry */
if(SUCCEEDED(hr))
hr = GAMEUX_WriteRegistryRecord(&GameData);
GAMEUX_uninitGameData(&GameData);
TRACE("returing 0x%08x\n", hr);
return hr;
}
/*******************************************************************************
* GameExplorer implementation
*/
@ -127,10 +373,8 @@ static HRESULT WINAPI GameExplorerImpl_AddGame(
GUID *pInstanceID)
{
GameExplorerImpl *This = impl_from_IGameExplorer(iface);
TRACE("(%p, %s, %s, %d, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
FIXME("stub\n");
return E_NOTIMPL;
TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
}
static HRESULT WINAPI GameExplorerImpl_RemoveGame(

View File

@ -20,3 +20,66 @@
extern HRESULT GameExplorer_create(IUnknown* pUnkOuter, IUnknown **ppObj);
extern HRESULT GameStatistics_create(IUnknown* pUnkOuter, IUnknown **ppObj);
/*******************************************************************************
* Helper functions and structures
*
* These are helper function and structures, which are used widely in gameux
* implementation. Details about usage and place of implementation is
* in description of each function/strucutre.
*/
/*******************************************************************************
* struct GAMEUX_GAME_DATA
*
* Structure which contains data about single game. It is used to transfer
* data inside of gameux module in various places.
*/
struct GAMEUX_GAME_DATA
{
LPWSTR sGDFBinaryPath; /* path to binary containing GDF */
LPWSTR sGameInstallDirectory; /* directory passed to AddGame/InstallGame methods */
GAME_INSTALL_SCOPE installScope;/* game's installation scope */
GUID guidInstanceId; /* game installation instance identifier */
};
/*******************************************************************************
* GAMEUX_initGameData
*
* Initializes GAME_DATA structure fields with proper values. Should be
* called always before first usage of this structure. Implemented in gameexplorer.c
*
* Parameters:
* GameData [I/O] pointer to structure to initialize
*/
void GAMEUX_initGameData(struct GAMEUX_GAME_DATA *GameData);
/*******************************************************************************
* GAMEUX_uninitGameData
*
* Properly frees all data stored or pointed by fields of GAME_DATA structure.
* Should be called before freeing this structure. Implemented in gameexplorer.c
*
* Parameters:
* GameData [I/O] pointer to structure to uninitialize
*/
void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA *GameData);
/*******************************************************************************
* GAMEUX_RegisterGame
*
* Helper function. Registers game associated with given GDF binary in
* Game Explorer. Implemented in gameexplorer.c
*
* Parameters:
* sGDFBinaryPath [I] path to binary containing GDF file in
* resources
* sGameInstallDirectory [I] path to directory, where game installed
* it's files.
* installScope [I] scope of game installation
* pInstanceID [I/O] pointer to game instance identifier.
* If pointing to GUID_NULL, then new
* identifier will be generated automatically
* and returned via this parameter
*/
HRESULT WINAPI GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
LPCWSTR sGameInstallDirectory,
GAME_INSTALL_SCOPE installScope,
GUID *pInstanceID);

View File

@ -297,9 +297,9 @@ static void _validateGameRegistryValues(int line,
hr = _validateRegistryValue(hKey, keyPath, sApplicationId, RRF_RT_REG_SZ, sGameApplicationId);
todo_wine 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);
todo_wine ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
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);
todo_wine ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
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);
todo_wine ok_(__FILE__, line)(hr==S_OK, "failed while checking registry value (error 0x%x)\n", hr);
@ -438,36 +438,36 @@ static void test_add_remove_game(void)
memcpy(&guid, &defaultGUID, sizeof (guid));
hr = IGameExplorer_AddGame(ge, bstrExeName, bstrExePath, GIS_CURRENT_USER, &guid);
todo_wine ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
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))
{
todo_wine _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
_validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
hr = IGameExplorer_RemoveGame(ge, guid);
todo_wine ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
}
_validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
todo_wine _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);
todo_wine ok(SUCCEEDED(hr), "IGameExplorer::AddGame failed (error 0x%08x)\n", hr);
todo_wine ok(memcmp(&guid, &GUID_NULL, sizeof (guid)) != 0, "AddGame did not modify GUID\n");
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))
{
todo_wine _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
_validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, TRUE);
hr = IGameExplorer_RemoveGame(ge, guid);
todo_wine ok(SUCCEEDED(hr), "IGameExplorer::RemoveGame failed (error 0x%08x)\n", hr);
}
_validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
todo_wine _validateGameRegistryKey(__LINE__, GIS_CURRENT_USER, &guid, &applicationId, sExePath, sExeName, FALSE);
}
/* free allocated resources */