2 * Gameux library coclass GameExplorer implementation
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
29 #include "gameux_private.h"
34 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(gameux);
39 /* function from Shell32, not defined in header */
40 extern BOOL WINAPI GUIDFromStringW(LPCWSTR psz, LPGUID pguid);
42 /*******************************************************************************
43 * GameUX helper functions
45 /*******************************************************************************
48 * Internal helper function. Description available in gameux_private.h file
50 void GAMEUX_initGameData(struct GAMEUX_GAME_DATA *GameData)
52 GameData->sGDFBinaryPath = NULL;
53 GameData->sGameInstallDirectory = NULL;
54 GameData->bstrName = NULL;
55 GameData->bstrDescription = NULL;
57 /*******************************************************************************
58 * GAMEUX_uninitGameData
60 * Internal helper function. Description available in gameux_private.h file
62 void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA *GameData)
64 HeapFree(GetProcessHeap(), 0, GameData->sGDFBinaryPath);
65 HeapFree(GetProcessHeap(), 0, GameData->sGameInstallDirectory);
66 SysFreeString(GameData->bstrName);
67 SysFreeString(GameData->bstrDescription);
69 /*******************************************************************************
70 * GAMEUX_buildGameRegistryPath
72 * Internal helper function. Description available in gameux_private.h file
74 HRESULT GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
75 LPCGUID gameInstanceId,
76 LPWSTR* lpRegistryPath)
78 static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\',
79 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
80 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
81 static const WCHAR sGames[] = {'G','a','m','e','s',0};
82 static const WCHAR sBackslash[] = {'\\',0};
86 PTOKEN_USER pTokenUser = NULL;
89 WCHAR sInstanceId[40];
90 WCHAR sRegistryPath[8192];
92 TRACE("(0x%x, %s, %p)\n", installScope, debugstr_guid(gameInstanceId), lpRegistryPath);
94 /* this will make freeing it easier for user */
95 *lpRegistryPath = NULL;
97 lstrcpyW(sRegistryPath, sGameUxRegistryPath);
98 lstrcatW(sRegistryPath, sBackslash);
100 if(installScope == GIS_CURRENT_USER)
102 /* build registry path containing user's SID */
103 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
104 hr = HRESULT_FROM_WIN32(GetLastError());
108 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
109 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
110 hr = HRESULT_FROM_WIN32(GetLastError());
114 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
120 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
121 hr = HRESULT_FROM_WIN32(GetLastError());
124 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
125 hr = HRESULT_FROM_WIN32(GetLastError());
129 lstrcatW(sRegistryPath, lpSID);
133 HeapFree(GetProcessHeap(), 0, pTokenUser);
137 else if(installScope == GIS_ALL_USERS)
138 /* build registry path without SID */
139 lstrcatW(sRegistryPath, sGames);
143 /* put game's instance id on the end of path, only if instance id was given */
147 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
151 lstrcatW(sRegistryPath, sBackslash);
152 lstrcatW(sRegistryPath, sInstanceId);
158 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
164 lstrcpyW(*lpRegistryPath, sRegistryPath);
166 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
169 /*******************************************************************************
170 * GAMEUX_WriteRegistryRecord
172 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
173 * structure) into expected place in registry.
176 * GameData [I] structure with data which will
177 * be written into registry.
178 * Proper values of fields installScope
179 * and guidInstanceId are required
180 * to create registry key.
182 * Schema of naming registry keys associated with games is available in
183 * description of _buildGameRegistryPath internal function.
185 * List of registry keys associated with structure fields:
186 * Key Field in GAMEUX_GAME_DATA structure
187 * ApplicationId guidApplicationId
188 * ConfigApplicationPath sGameInstallDirectory
189 * ConfigGDFBinaryPath sGDFBinaryPath
193 static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
195 static const WCHAR sApplicationId[] =
196 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
197 static const WCHAR sConfigApplicationPath[] =
198 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
199 static const WCHAR sConfigGDFBinaryPath[] =
200 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
201 static const WCHAR sTitle[] =
202 {'T','i','t','l','e',0};
203 static const WCHAR sDescription[] =
204 {'D','e','s','c','r','i','p','t','i','o','n',0};
207 LPWSTR lpRegistryKey;
209 WCHAR sGameApplicationId[40];
211 TRACE("(%p)\n", GameData);
213 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
216 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
219 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
220 0, NULL, 0, KEY_ALL_ACCESS, NULL,
225 /* write game data to registry key */
226 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigApplicationPath, 0,
227 REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
228 (lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
231 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
232 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
233 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
236 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sApplicationId, 0,
237 REG_SZ, (LPBYTE)(sGameApplicationId),
238 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
241 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sTitle, 0,
242 REG_SZ, (LPBYTE)(GameData->bstrName),
243 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
246 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sDescription, 0,
247 REG_SZ, (LPBYTE)(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName),
248 (lstrlenW(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName)+1)*sizeof(WCHAR)));
254 /* if something failed, remove whole key */
255 hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, 0, 0);
256 /* do not overwrite old failure code with new success code */
262 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
263 TRACE("returning 0x%x\n", hr);
266 /*******************************************************************************
267 * GAMEUX_ProcessGameDefinitionElement
269 * Helper function, parses single element from Game Definition
272 * lpXMLElement [I] game definition element
273 * GameData [O] structure, where parsed
274 * data will be stored
276 static HRESULT GAMEUX_ProcessGameDefinitionElement(
277 IXMLDOMElement *element,
278 struct GAMEUX_GAME_DATA *GameData)
280 static const WCHAR sName[] =
282 static const WCHAR sDescription[] =
283 {'D','e','s','c','r','i','p','t','i','o','n',0};
286 BSTR bstrElementName;
288 TRACE("(%p, %p)\n", element, GameData);
290 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
293 /* check element name */
294 if(lstrcmpW(bstrElementName, sName) == 0)
295 hr = IXMLDOMElement_get_text(element, &GameData->bstrName);
297 else if(lstrcmpW(bstrElementName, sDescription) == 0)
298 hr = IXMLDOMElement_get_text(element, &GameData->bstrDescription);
301 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
303 SysFreeString(bstrElementName);
308 /*******************************************************************************
309 * GAMEUX_ParseGameDefinition
311 * Helper function, loads data from given XML element into fields of GAME_DATA
315 * lpXMLGameDefinitionElement [I] Game Definition XML element
316 * GameData [O] structure where data loaded from
317 * XML element will be stored in
319 static HRESULT GAMEUX_ParseGameDefinition(
320 IXMLDOMElement *gdElement,
321 struct GAMEUX_GAME_DATA *GameData)
323 static const WCHAR sGameId[] = {'g','a','m','e','I','D',0};
328 IXMLDOMNodeList *childrenList;
329 IXMLDOMNode *nextNode;
330 IXMLDOMElement *nextElement;
332 TRACE("(%p, %p)\n", gdElement, GameData);
334 bstrAttribute = SysAllocString(sGameId);
338 hr = IXMLDOMElement_getAttribute(gdElement, bstrAttribute, &variant);
342 hr = ( GUIDFromStringW(V_BSTR(&variant), &GameData->guidApplicationId)==TRUE ? S_OK : E_FAIL);
344 SysFreeString(V_BSTR(&variant));
347 SysFreeString(bstrAttribute);
349 /* browse subnodes */
351 hr = IXMLDOMElement_get_childNodes(gdElement, &childrenList);
357 hr = IXMLDOMNodeList_nextNode(childrenList, &nextNode);
361 hr = IXMLDOMNode_QueryInterface(nextNode, &IID_IXMLDOMElement,
362 (LPVOID*)&nextElement);
366 hr = GAMEUX_ProcessGameDefinitionElement(nextElement, GameData);
367 IXMLDOMElement_Release(nextElement);
370 IXMLDOMElement_Release(nextNode);
376 IXMLDOMNodeList_Release(childrenList);
381 /*******************************************************************************
382 * GAMEUX_ParseGDFBinary
384 * Helper function, loads given binary and parses embed GDF if there's any.
387 * GameData [I/O] Structure with game's data. Content of field
388 * sGDFBinaryPath defines path to binary, from
389 * which embed GDF will be loaded. Data from
390 * GDF will be stored in other fields of this
393 static HRESULT GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA *GameData)
395 static const WCHAR sRes[] = {'r','e','s',':','/','/',0};
396 static const WCHAR sDATA[] = {'D','A','T','A',0};
397 static const WCHAR sSlash[] = {'/',0};
400 WCHAR sResourcePath[MAX_PATH];
402 VARIANT_BOOL isSuccessful;
403 IXMLDOMDocument *document;
405 IXMLDOMElement *root, *gdElement;
407 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData, debugstr_w(GameData->sGDFBinaryPath));
409 /* prepare path to GDF, using res:// prefix */
410 lstrcpyW(sResourcePath, sRes);
411 lstrcatW(sResourcePath, GameData->sGDFBinaryPath);
412 lstrcatW(sResourcePath, sSlash);
413 lstrcatW(sResourcePath, sDATA);
414 lstrcatW(sResourcePath, sSlash);
415 lstrcatW(sResourcePath, ID_GDF_XML_STR);
417 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
418 &IID_IXMLDOMDocument, (void**)&document);
422 /* load GDF into MSXML */
423 V_VT(&variant) = VT_BSTR;
424 V_BSTR(&variant) = SysAllocString(sResourcePath);
425 if(!V_BSTR(&variant))
430 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
431 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
435 SysFreeString(V_BSTR(&variant));
439 hr = IXMLDOMDocument_get_documentElement(document, &root);
446 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
452 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
455 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
456 IXMLDOMElement_Release(gdElement);
459 IXMLDOMNode_Release(gdNode);
462 IXMLDOMElement_Release(root);
465 IXMLDOMDocument_Release(document);
470 /*******************************************************************
471 * GAMEUX_RemoveRegistryRecord
473 * Helper function, removes registry key associated with given game instance
475 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
478 LPWSTR lpRegistryPath = NULL;
479 TRACE("(%s)\n", debugstr_guid(pInstanceID));
481 /* first, check is game installed for all users */
482 hr = GAMEUX_buildGameRegistryPath(GIS_ALL_USERS, pInstanceID, &lpRegistryPath);
484 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
486 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
488 /* if not, check current user */
491 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
493 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
495 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
500 /*******************************************************************************
501 * GAMEUX_RegisterGame
503 * Internal helper function. Description available in gameux_private.h file
505 HRESULT WINAPI GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
506 LPCWSTR sGameInstallDirectory,
507 GAME_INSTALL_SCOPE installScope,
511 struct GAMEUX_GAME_DATA GameData;
513 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
515 GAMEUX_initGameData(&GameData);
516 GameData.sGDFBinaryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath)+1)*sizeof(WCHAR));
517 lstrcpyW(GameData.sGDFBinaryPath, sGDFBinaryPath);
518 GameData.sGameInstallDirectory = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory)+1)*sizeof(WCHAR));
519 lstrcpyW(GameData.sGameInstallDirectory, sGameInstallDirectory);
520 GameData.installScope = installScope;
522 /* generate GUID if it was not provided by user */
523 if(IsEqualGUID(pInstanceID, &GUID_NULL))
524 hr = CoCreateGuid(pInstanceID);
526 GameData.guidInstanceId = *pInstanceID;
528 /* load data from GDF binary */
530 hr = GAMEUX_ParseGDFBinary(&GameData);
532 /* save data to registry */
534 hr = GAMEUX_WriteRegistryRecord(&GameData);
536 GAMEUX_uninitGameData(&GameData);
537 TRACE("returning 0x%08x\n", hr);
540 /*******************************************************************************
541 * GAMEUX_IsGameKeyExist
543 * Helper function, checks if game's registry ath exists in given scope
546 * installScope [I] scope to search game in
547 * InstanceID [I] game instance identifier
548 * lpRegistryPath [O] place to store address of registry path to
549 * the game. It is filled only if key exists.
550 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
553 * S_OK key was found properly
554 * S_FALSE key does not exists
557 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
559 LPWSTR* lpRegistryPath) {
564 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
567 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, *lpRegistryPath,
568 0, KEY_WOW64_64KEY, &hKey));
570 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
577 /* if the key does not exist or another error occurred, do not return the path */
578 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
579 *lpRegistryPath = NULL;
584 /*******************************************************************************
585 * GAMEUX_LoadRegistryString
587 * Helper function, loads string from registry value and allocates buffer for it
589 static HRESULT GAMEUX_LoadRegistryString(HKEY hRootKey,
590 LPCWSTR lpRegistryKey,
591 LPCWSTR lpRegistryValue,
599 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
600 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
604 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
610 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
611 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
615 /*******************************************************************************
618 * Helper function, updates stored data about game with given InstanceID
620 static HRESULT GAMEUX_UpdateGame(LPGUID InstanceID) {
621 static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
622 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};
625 GAME_INSTALL_SCOPE installScope;
626 LPWSTR lpRegistryPath;
627 LPWSTR lpGDFBinaryPath, lpGameInstallDirectory;
629 TRACE("(%p)\n", debugstr_guid(InstanceID));
631 /* first, check is game exists in CURRENT_USER scope */
632 installScope = GIS_CURRENT_USER;
633 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
637 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
638 installScope = GIS_ALL_USERS;
639 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
643 /* still not found? let's inform user that game does not exists */
644 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
648 /* game found, it's registry path is in lpRegistryPath and install
649 * scope in installScope */
650 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath));
652 /* first, read required data about game */
653 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
654 sConfigGDFBinaryPath, &lpGDFBinaryPath);
657 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
658 sConfigApplicationPath, &lpGameInstallDirectory);
660 /* now remove currently existing registry key */
662 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
664 /* and add it again, it will cause in reparsing of whole GDF */
666 hr = GAMEUX_RegisterGame(lpGDFBinaryPath, lpGameInstallDirectory,
667 installScope, InstanceID);
669 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath);
670 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory);
673 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
674 TRACE("returning 0x%x\n", hr);
677 /*******************************************************************************
678 * GAMEUX_FindGameInstanceId
680 * Internal helper function. Description available in gameux_private.h file
682 HRESULT GAMEUX_FindGameInstanceId(
683 LPCWSTR sGDFBinaryPath,
684 GAME_INSTALL_SCOPE installScope,
687 static const WCHAR sConfigGDFBinaryPath[] =
688 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
692 LPWSTR lpRegistryPath = NULL;
694 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
695 LPWSTR lpName = NULL, lpValue = NULL;
697 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
700 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
701 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
702 lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey));
706 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
707 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
711 ++dwMaxSubKeyLen; /* for string terminator */
712 lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR));
713 if(!lpName) hr = E_OUTOFMEMORY;
718 for(i=0; i<dwSubKeys && !found; ++i)
720 dwSubKeyLen = dwMaxSubKeyLen;
721 hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen,
722 NULL, NULL, NULL, NULL));
725 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
726 sConfigGDFBinaryPath, &lpValue);
729 if(lstrcmpW(lpValue, sGDFBinaryPath)==0)
731 /* key found, let's copy instance id and exit */
732 hr = (GUIDFromStringW(lpName, pInstanceId) ? S_OK : E_FAIL);
735 HeapFree(GetProcessHeap(), 0, lpValue);
739 HeapFree(GetProcessHeap(), 0, lpName);
740 RegCloseKey(hRootKey);
743 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
745 if((SUCCEEDED(hr) && !found) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
750 /*******************************************************************************
751 * GameExplorer implementation
754 typedef struct _GameExplorerImpl
756 const struct IGameExplorerVtbl *lpGameExplorerVtbl;
757 const struct IGameExplorer2Vtbl *lpGameExplorer2Vtbl;
761 static inline GameExplorerImpl *impl_from_IGameExplorer(IGameExplorer *iface)
763 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorerVtbl));
766 static inline IGameExplorer* IGameExplorer_from_impl(GameExplorerImpl* This)
768 return (struct IGameExplorer*)&This->lpGameExplorerVtbl;
771 static inline GameExplorerImpl *impl_from_IGameExplorer2(IGameExplorer2 *iface)
773 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorer2Vtbl));
776 static inline IGameExplorer2* IGameExplorer2_from_impl(GameExplorerImpl* This)
778 return (struct IGameExplorer2*)&This->lpGameExplorer2Vtbl;
781 static HRESULT WINAPI GameExplorerImpl_QueryInterface(
782 IGameExplorer *iface,
786 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
788 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
792 if(IsEqualGUID(riid, &IID_IUnknown) ||
793 IsEqualGUID(riid, &IID_IGameExplorer))
795 *ppvObject = IGameExplorer_from_impl(This);
797 else if(IsEqualGUID(riid, &IID_IGameExplorer2))
799 *ppvObject = IGameExplorer2_from_impl(This);
803 FIXME("interface %s not implemented\n", debugstr_guid(riid));
804 return E_NOINTERFACE;
807 IGameExplorer_AddRef(iface);
811 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
813 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
816 ref = InterlockedIncrement(&This->ref);
818 TRACE("(%p): ref=%d\n", This, ref);
822 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
824 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
827 ref = InterlockedDecrement(&This->ref);
828 TRACE("(%p): ref=%d\n", This, ref);
832 TRACE("freeing GameExplorer object\n");
833 HeapFree(GetProcessHeap(), 0, This);
839 static HRESULT WINAPI GameExplorerImpl_AddGame(
840 IGameExplorer *iface,
841 BSTR bstrGDFBinaryPath,
842 BSTR sGameInstallDirectory,
843 GAME_INSTALL_SCOPE installScope,
846 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
847 TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
848 return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
851 static HRESULT WINAPI GameExplorerImpl_RemoveGame(
852 IGameExplorer *iface,
855 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
857 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
858 return GAMEUX_RemoveRegistryRecord(&instanceID);
861 static HRESULT WINAPI GameExplorerImpl_UpdateGame(
862 IGameExplorer *iface,
865 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
867 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
868 return GAMEUX_UpdateGame(&instanceID);
871 static HRESULT WINAPI GameExplorerImpl_VerifyAccess(
872 IGameExplorer *iface,
876 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
878 FIXME("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
883 static const struct IGameExplorerVtbl GameExplorerImplVtbl =
885 GameExplorerImpl_QueryInterface,
886 GameExplorerImpl_AddRef,
887 GameExplorerImpl_Release,
888 GameExplorerImpl_AddGame,
889 GameExplorerImpl_RemoveGame,
890 GameExplorerImpl_UpdateGame,
891 GameExplorerImpl_VerifyAccess
895 static HRESULT WINAPI GameExplorer2Impl_QueryInterface(
896 IGameExplorer2 *iface,
900 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
901 return GameExplorerImpl_QueryInterface(IGameExplorer_from_impl(This), riid, ppvObject);
904 static ULONG WINAPI GameExplorer2Impl_AddRef(IGameExplorer2 *iface)
906 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
907 return GameExplorerImpl_AddRef(IGameExplorer_from_impl(This));
910 static ULONG WINAPI GameExplorer2Impl_Release(IGameExplorer2 *iface)
912 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
913 return GameExplorerImpl_Release(IGameExplorer_from_impl(This));
916 static HRESULT WINAPI GameExplorer2Impl_CheckAccess(
917 IGameExplorer2 *iface,
918 LPCWSTR binaryGDFPath,
921 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
922 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
926 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
927 IGameExplorer2 *iface,
928 LPCWSTR binaryGDFPath,
929 LPCWSTR installDirectory,
930 GAME_INSTALL_SCOPE installScope)
934 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
936 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
941 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
944 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
948 /* if game isn't yet registered, then install it */
949 instanceId = GUID_NULL;
950 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
953 /* otherwise, update game */
954 hr = GAMEUX_UpdateGame(&instanceId);
959 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
960 IGameExplorer2 *iface,
961 LPCWSTR binaryGDFPath)
965 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
966 TRACE("(%p, %s)\n", This, debugstr_w(binaryGDFPath));
971 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
974 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
977 hr = GAMEUX_RemoveRegistryRecord(&instanceId);
982 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl =
984 GameExplorer2Impl_QueryInterface,
985 GameExplorer2Impl_AddRef,
986 GameExplorer2Impl_Release,
987 GameExplorer2Impl_InstallGame,
988 GameExplorer2Impl_UninstallGame,
989 GameExplorer2Impl_CheckAccess
993 * Construction routine
995 HRESULT GameExplorer_create(
999 GameExplorerImpl *pGameExplorer;
1001 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1003 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
1006 return E_OUTOFMEMORY;
1008 pGameExplorer->lpGameExplorerVtbl = &GameExplorerImplVtbl;
1009 pGameExplorer->lpGameExplorer2Vtbl = &GameExplorer2ImplVtbl;
1010 pGameExplorer->ref = 1;
1012 *ppObj = (IUnknown*)(&pGameExplorer->lpGameExplorerVtbl);
1014 TRACE("returning iface: %p\n", *ppObj);