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 * Helper function, builds registry path to key, where game's data are stored
75 * installScope [I] the scope which was used in AddGame/InstallGame call
76 * gameInstanceId [I] game instance GUID
77 * lpRegistryPath [O] pointer which will receive address to string
78 * containing expected registry path. Path
79 * is relative to HKLM registry key. It
80 * must be freed by calling HeapFree(GetProcessHeap(), 0, ...)
82 * Name of game's registry key always follows patterns below:
83 * When game is installed for current user only (installScope is GIS_CURRENT_USER):
84 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
85 * GameUX\[user's security ID]\[game instance ID]
87 * When game is installed for all users (installScope is GIS_ALL_USERS):
88 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
89 * GameUX\Games\[game instance ID]
93 static HRESULT GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
94 LPCGUID gameInstanceId,
95 LPWSTR* lpRegistryPath)
97 static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\',
98 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
99 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
100 static const WCHAR sGames[] = {'G','a','m','e','s',0};
101 static const WCHAR sBackslash[] = {'\\',0};
104 HANDLE hToken = NULL;
105 PTOKEN_USER pTokenUser = NULL;
108 WCHAR sInstanceId[40];
109 WCHAR sRegistryPath[8192];
111 TRACE("(0x%x, %s, %p)\n", installScope, debugstr_guid(gameInstanceId), lpRegistryPath);
113 /* this will make freeing it easier for user */
114 *lpRegistryPath = NULL;
116 lstrcpyW(sRegistryPath, sGameUxRegistryPath);
117 lstrcatW(sRegistryPath, sBackslash);
119 if(installScope == GIS_CURRENT_USER)
121 /* build registry path containing user's SID */
122 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
123 hr = HRESULT_FROM_WIN32(GetLastError());
127 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
128 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
129 hr = HRESULT_FROM_WIN32(GetLastError());
133 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
139 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
140 hr = HRESULT_FROM_WIN32(GetLastError());
143 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
144 hr = HRESULT_FROM_WIN32(GetLastError());
148 lstrcatW(sRegistryPath, lpSID);
152 HeapFree(GetProcessHeap(), 0, pTokenUser);
156 else if(installScope == GIS_ALL_USERS)
157 /* build registry path without SID */
158 lstrcatW(sRegistryPath, sGames);
162 /* put game's instance id on the end of path */
164 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
168 lstrcatW(sRegistryPath, sBackslash);
169 lstrcatW(sRegistryPath, sInstanceId);
174 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
180 lstrcpyW(*lpRegistryPath, sRegistryPath);
182 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
185 /*******************************************************************************
186 * GAMEUX_WriteRegistryRecord
188 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
189 * structure) into expected place in registry.
192 * GameData [I] structure with data which will
193 * be written into registry.
194 * Proper values of fields installScope
195 * and guidInstanceId are required
196 * to create registry key.
198 * Schema of naming registry keys associated with games is available in
199 * description of _buildGameRegistryPath internal function.
201 * List of registry keys associated with structure fields:
202 * Key Field in GAMEUX_GAME_DATA structure
203 * ApplicationId guidApplicationId
204 * ConfigApplicationPath sGameInstallDirectory
205 * ConfigGDFBinaryPath sGDFBinaryPath
209 static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
211 static const WCHAR sApplicationId[] =
212 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
213 static const WCHAR sConfigApplicationPath[] =
214 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
215 static const WCHAR sConfigGDFBinaryPath[] =
216 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
217 static const WCHAR sTitle[] =
218 {'T','i','t','l','e',0};
219 static const WCHAR sDescription[] =
220 {'D','e','s','c','r','i','p','t','i','o','n',0};
223 LPWSTR lpRegistryKey;
225 WCHAR sGameApplicationId[40];
227 TRACE("(%p)\n", GameData);
229 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
232 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
235 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
236 0, NULL, 0, KEY_ALL_ACCESS, NULL,
241 /* write game data to registry key */
242 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigApplicationPath, 0,
243 REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
244 (lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
247 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
248 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
249 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
252 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sApplicationId, 0,
253 REG_SZ, (LPBYTE)(sGameApplicationId),
254 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
257 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sTitle, 0,
258 REG_SZ, (LPBYTE)(GameData->bstrName),
259 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
262 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sDescription, 0,
263 REG_SZ, (LPBYTE)(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName),
264 (lstrlenW(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName)+1)*sizeof(WCHAR)));
270 /* if something failed, remove whole key */
271 hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, 0, 0);
272 /* do not overwrite old failure code with new success code */
278 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
279 TRACE("returning 0x%x\n", hr);
282 /*******************************************************************************
283 * GAMEUX_ProcessGameDefinitionElement
285 * Helper function, parses single element from Game Definition
288 * lpXMLElement [I] game definition element
289 * GameData [O] structure, where parsed
290 * data will be stored
292 static HRESULT GAMEUX_ProcessGameDefinitionElement(
293 IXMLDOMElement *element,
294 struct GAMEUX_GAME_DATA *GameData)
296 static const WCHAR sName[] =
298 static const WCHAR sDescription[] =
299 {'D','e','s','c','r','i','p','t','i','o','n',0};
302 BSTR bstrElementName;
304 TRACE("(%p, %p)\n", element, GameData);
306 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
309 /* check element name */
310 if(lstrcmpW(bstrElementName, sName) == 0)
311 hr = IXMLDOMElement_get_text(element, &GameData->bstrName);
313 else if(lstrcmpW(bstrElementName, sDescription) == 0)
314 hr = IXMLDOMElement_get_text(element, &GameData->bstrDescription);
317 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
319 SysFreeString(bstrElementName);
324 /*******************************************************************************
325 * GAMEUX_ParseGameDefinition
327 * Helper function, loads data from given XML element into fields of GAME_DATA
331 * lpXMLGameDefinitionElement [I] Game Definition XML element
332 * GameData [O] structure where data loaded from
333 * XML element will be stored in
335 static HRESULT GAMEUX_ParseGameDefinition(
336 IXMLDOMElement *gdElement,
337 struct GAMEUX_GAME_DATA *GameData)
339 static const WCHAR sGameId[] = {'g','a','m','e','I','D',0};
344 IXMLDOMNodeList *childrenList;
345 IXMLDOMNode *nextNode;
346 IXMLDOMElement *nextElement;
348 TRACE("(%p, %p)\n", gdElement, GameData);
350 bstrAttribute = SysAllocString(sGameId);
354 hr = IXMLDOMElement_getAttribute(gdElement, bstrAttribute, &variant);
358 hr = ( GUIDFromStringW(V_BSTR(&variant), &GameData->guidApplicationId)==TRUE ? S_OK : E_FAIL);
360 SysFreeString(V_BSTR(&variant));
363 SysFreeString(bstrAttribute);
365 /* browse subnodes */
367 hr = IXMLDOMElement_get_childNodes(gdElement, &childrenList);
373 hr = IXMLDOMNodeList_nextNode(childrenList, &nextNode);
377 hr = IXMLDOMNode_QueryInterface(nextNode, &IID_IXMLDOMElement,
378 (LPVOID*)&nextElement);
382 hr = GAMEUX_ProcessGameDefinitionElement(nextElement, GameData);
383 IXMLDOMElement_Release(nextElement);
386 IXMLDOMElement_Release(nextNode);
392 IXMLDOMNodeList_Release(childrenList);
397 /*******************************************************************************
398 * GAMEUX_ParseGDFBinary
400 * Helper funtion, loads given binary and parses embed GDF if there's any.
403 * GameData [I/O] Structure with game's data. Content of field
404 * sGDFBinaryPath defines path to binary, from
405 * which embed GDF will be loaded. Data from
406 * GDF will be stored in other fields of this
409 static HRESULT GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA *GameData)
411 static const WCHAR sRes[] = {'r','e','s',':','/','/',0};
412 static const WCHAR sDATA[] = {'D','A','T','A',0};
413 static const WCHAR sSlash[] = {'/',0};
416 WCHAR sResourcePath[MAX_PATH];
418 VARIANT_BOOL isSuccessful;
419 IXMLDOMDocument *document;
421 IXMLDOMElement *root, *gdElement;
423 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData, debugstr_w(GameData->sGDFBinaryPath));
425 /* prepare path to GDF, using res:// prefix */
426 lstrcpyW(sResourcePath, sRes);
427 lstrcatW(sResourcePath, GameData->sGDFBinaryPath);
428 lstrcatW(sResourcePath, sSlash);
429 lstrcatW(sResourcePath, sDATA);
430 lstrcatW(sResourcePath, sSlash);
431 lstrcatW(sResourcePath, ID_GDF_XML_STR);
433 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
434 &IID_IXMLDOMDocument, (void**)&document);
438 /* load GDF into MSXML */
439 V_VT(&variant) = VT_BSTR;
440 V_BSTR(&variant) = SysAllocString(sResourcePath);
441 if(!V_BSTR(&variant))
446 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
447 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
451 SysFreeString(V_BSTR(&variant));
455 hr = IXMLDOMDocument_get_documentElement(document, &root);
462 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
468 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
471 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
472 IXMLDOMElement_Release(gdElement);
475 IXMLDOMNode_Release(gdNode);
478 IXMLDOMElement_Release(root);
481 IXMLDOMDocument_Release(document);
486 /*******************************************************************
487 * GAMEUX_RemoveRegistryRecord
489 * Helper function, removes registry key associated with given game instance
491 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
494 LPWSTR lpRegistryPath = NULL;
495 TRACE("(%s)\n", debugstr_guid(pInstanceID));
497 /* first, check is game installed for all users */
498 hr = GAMEUX_buildGameRegistryPath(GIS_ALL_USERS, pInstanceID, &lpRegistryPath);
500 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
502 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
504 /* if not, check current user */
507 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
509 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
511 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
516 /*******************************************************************************
517 * GAMEUX_RegisterGame
519 * Internal helper function. Description available in gameux_private.h file
521 HRESULT WINAPI GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
522 LPCWSTR sGameInstallDirectory,
523 GAME_INSTALL_SCOPE installScope,
527 struct GAMEUX_GAME_DATA GameData;
529 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
531 GAMEUX_initGameData(&GameData);
532 GameData.sGDFBinaryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath)+1)*sizeof(WCHAR));
533 lstrcpyW(GameData.sGDFBinaryPath, sGDFBinaryPath);
534 GameData.sGameInstallDirectory = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory)+1)*sizeof(WCHAR));
535 lstrcpyW(GameData.sGameInstallDirectory, sGameInstallDirectory);
536 GameData.installScope = installScope;
538 /* generate GUID if it was not provided by user */
539 if(IsEqualGUID(pInstanceID, &GUID_NULL))
540 hr = CoCreateGuid(pInstanceID);
542 GameData.guidInstanceId = *pInstanceID;
544 /* load data from GDF binary */
546 hr = GAMEUX_ParseGDFBinary(&GameData);
548 /* save data to registry */
550 hr = GAMEUX_WriteRegistryRecord(&GameData);
552 GAMEUX_uninitGameData(&GameData);
553 TRACE("returing 0x%08x\n", hr);
556 /*******************************************************************************
557 * GAMEUX_IsGameKeyExist
559 * Helper function, checks if game's registry ath exists in given scope
562 * installScope [I] scope to search game in
563 * InstanceID [I] game instance identifier
564 * lpRegistryPath [O] place to store address of registry path to
565 * the game. It is filled only if key exists.
566 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
569 * S_OK key was found properly
570 * S_FALSE key does not exists
573 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
575 LPWSTR* lpRegistryPath) {
580 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
583 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, *lpRegistryPath,
584 0, KEY_WOW64_64KEY, &hKey));
586 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
593 /* if key does not exist or other error occured, do not return the path */
594 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
595 *lpRegistryPath = NULL;
600 /*******************************************************************************
601 * GAMEUX_LoadRegistryString
603 * Helper function, loads string from registry value and allocates buffer for it
605 static HRESULT GAMEUX_LoadRegistryString(HKEY hRootKey,
606 LPCWSTR lpRegistryKey,
607 LPCWSTR lpRegistryValue,
615 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
616 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
620 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
626 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
627 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
631 /*******************************************************************************
634 * Helper function, updates stored data about game with given InstanceID
636 static HRESULT GAMEUX_UpdateGame(LPGUID InstanceID) {
637 static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
638 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};
641 GAME_INSTALL_SCOPE installScope;
642 LPWSTR lpRegistryPath;
643 LPWSTR lpGDFBinaryPath, lpGameInstallDirectory;
645 TRACE("(%p)\n", debugstr_guid(InstanceID));
647 /* first, check is game exists in CURRENT_USER scope */
648 installScope = GIS_CURRENT_USER;
649 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
653 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
654 installScope = GIS_ALL_USERS;
655 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
659 /* still not found? let's inform user that game does not exists */
660 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
664 /* game found, it's registry path is in lpRegistryPath and install
665 * scope in installScope */
666 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath));
668 /* first, read required data about game */
669 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
670 sConfigGDFBinaryPath, &lpGDFBinaryPath);
673 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
674 sConfigApplicationPath, &lpGameInstallDirectory);
676 /* now remove currently existing registry key */
678 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
680 /* and add it again, it will cause in reparsing of whole GDF */
682 hr = GAMEUX_RegisterGame(lpGDFBinaryPath, lpGameInstallDirectory,
683 installScope, InstanceID);
685 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath);
686 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory);
689 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
690 TRACE("returning 0x%x\n", hr);
693 /*******************************************************************************
694 * GameExplorer implementation
697 typedef struct _GameExplorerImpl
699 const struct IGameExplorerVtbl *lpGameExplorerVtbl;
700 const struct IGameExplorer2Vtbl *lpGameExplorer2Vtbl;
704 static inline GameExplorerImpl *impl_from_IGameExplorer(IGameExplorer *iface)
706 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorerVtbl));
709 static inline IGameExplorer* IGameExplorer_from_impl(GameExplorerImpl* This)
711 return (struct IGameExplorer*)&This->lpGameExplorerVtbl;
714 static inline GameExplorerImpl *impl_from_IGameExplorer2(IGameExplorer2 *iface)
716 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorer2Vtbl));
719 static inline IGameExplorer2* IGameExplorer2_from_impl(GameExplorerImpl* This)
721 return (struct IGameExplorer2*)&This->lpGameExplorer2Vtbl;
724 static HRESULT WINAPI GameExplorerImpl_QueryInterface(
725 IGameExplorer *iface,
729 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
731 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
735 if(IsEqualGUID(riid, &IID_IUnknown) ||
736 IsEqualGUID(riid, &IID_IGameExplorer))
738 *ppvObject = IGameExplorer_from_impl(This);
740 else if(IsEqualGUID(riid, &IID_IGameExplorer2))
742 *ppvObject = IGameExplorer2_from_impl(This);
746 FIXME("interface %s not implemented\n", debugstr_guid(riid));
747 return E_NOINTERFACE;
750 IGameExplorer_AddRef(iface);
754 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
756 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
759 ref = InterlockedIncrement(&This->ref);
761 TRACE("(%p): ref=%d\n", This, ref);
765 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
767 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
770 ref = InterlockedDecrement(&This->ref);
771 TRACE("(%p): ref=%d\n", This, ref);
775 TRACE("freeing GameExplorer object\n");
776 HeapFree(GetProcessHeap(), 0, This);
782 static HRESULT WINAPI GameExplorerImpl_AddGame(
783 IGameExplorer *iface,
784 BSTR bstrGDFBinaryPath,
785 BSTR sGameInstallDirectory,
786 GAME_INSTALL_SCOPE installScope,
789 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
790 TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
791 return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
794 static HRESULT WINAPI GameExplorerImpl_RemoveGame(
795 IGameExplorer *iface,
798 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
800 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
801 return GAMEUX_RemoveRegistryRecord(&instanceID);
804 static HRESULT WINAPI GameExplorerImpl_UpdateGame(
805 IGameExplorer *iface,
808 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
810 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
811 return GAMEUX_UpdateGame(&instanceID);
814 static HRESULT WINAPI GameExplorerImpl_VerifyAccess(
815 IGameExplorer *iface,
819 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
821 TRACE("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
826 static const struct IGameExplorerVtbl GameExplorerImplVtbl =
828 GameExplorerImpl_QueryInterface,
829 GameExplorerImpl_AddRef,
830 GameExplorerImpl_Release,
831 GameExplorerImpl_AddGame,
832 GameExplorerImpl_RemoveGame,
833 GameExplorerImpl_UpdateGame,
834 GameExplorerImpl_VerifyAccess
838 static HRESULT WINAPI GameExplorer2Impl_QueryInterface(
839 IGameExplorer2 *iface,
843 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
844 return GameExplorerImpl_QueryInterface(IGameExplorer_from_impl(This), riid, ppvObject);
847 static ULONG WINAPI GameExplorer2Impl_AddRef(IGameExplorer2 *iface)
849 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
850 return GameExplorerImpl_AddRef(IGameExplorer_from_impl(This));
853 static ULONG WINAPI GameExplorer2Impl_Release(IGameExplorer2 *iface)
855 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
856 return GameExplorerImpl_Release(IGameExplorer_from_impl(This));
859 static HRESULT WINAPI GameExplorer2Impl_CheckAccess(
860 IGameExplorer2 *iface,
861 LPCWSTR binaryGDFPath,
864 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
865 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
869 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
870 IGameExplorer2 *iface,
871 LPCWSTR binaryGDFPath,
872 LPCWSTR installDirectory,
873 GAME_INSTALL_SCOPE installScope)
875 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
876 FIXME("stub (%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
880 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
881 IGameExplorer2 *iface,
882 LPCWSTR binaryGDFPath)
884 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
885 FIXME("stub (%p, %s)\n", This, debugstr_w(binaryGDFPath));
889 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl =
891 GameExplorer2Impl_QueryInterface,
892 GameExplorer2Impl_AddRef,
893 GameExplorer2Impl_Release,
894 GameExplorer2Impl_InstallGame,
895 GameExplorer2Impl_UninstallGame,
896 GameExplorer2Impl_CheckAccess
900 * Construction routine
902 HRESULT GameExplorer_create(
906 GameExplorerImpl *pGameExplorer;
908 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
910 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
913 return E_OUTOFMEMORY;
915 pGameExplorer->lpGameExplorerVtbl = &GameExplorerImplVtbl;
916 pGameExplorer->lpGameExplorer2Vtbl = &GameExplorer2ImplVtbl;
917 pGameExplorer->ref = 1;
919 *ppObj = (IUnknown*)(&pGameExplorer->lpGameExplorerVtbl);
921 TRACE("returning iface: %p\n", *ppObj);