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
27 #include "gameux_private.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gameux
);
37 /*******************************************************************************
38 * GameUX helper functions
40 /*******************************************************************************
43 * Internal helper function.
44 * Initializes GAME_DATA structure fields with proper values. Should be
45 * called always before first usage of this structure. Implemented in gameexplorer.c
48 * GameData [I/O] pointer to structure to initialize
50 static 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.
61 * Properly frees all data stored or pointed by fields of GAME_DATA structure.
62 * Should be called before freeing this structure. Implemented in gameexplorer.c
65 * GameData [I/O] pointer to structure to uninitialize
67 static void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA
*GameData
)
69 HeapFree(GetProcessHeap(), 0, GameData
->sGDFBinaryPath
);
70 HeapFree(GetProcessHeap(), 0, GameData
->sGameInstallDirectory
);
71 SysFreeString(GameData
->bstrName
);
72 SysFreeString(GameData
->bstrDescription
);
74 /*******************************************************************************
75 * GAMEUX_buildGameRegistryPath
77 * Internal helper function. Description available in gameux_private.h file
79 HRESULT
GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope
,
80 LPCGUID gameInstanceId
,
81 LPWSTR
* lpRegistryPath
)
85 PTOKEN_USER pTokenUser
= NULL
;
88 WCHAR sInstanceId
[40];
89 WCHAR sRegistryPath
[8192];
91 TRACE("(0x%x, %s, %p)\n", installScope
, debugstr_guid(gameInstanceId
), lpRegistryPath
);
93 /* this will make freeing it easier for user */
94 *lpRegistryPath
= NULL
;
96 lstrcpyW(sRegistryPath
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\GameUX\\");
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
= HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, pTokenUser
);
135 else if(installScope
== GIS_ALL_USERS
)
136 /* build registry path without SID */
137 lstrcatW(sRegistryPath
, L
"Games");
141 /* put game's instance id on the end of path, only if instance id was given */
145 hr
= (StringFromGUID2(gameInstanceId
, sInstanceId
, ARRAY_SIZE(sInstanceId
)) ? S_OK
: E_FAIL
);
149 lstrcatW(sRegistryPath
, L
"\\");
150 lstrcatW(sRegistryPath
, sInstanceId
);
156 *lpRegistryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath
)+1)*sizeof(WCHAR
));
162 lstrcpyW(*lpRegistryPath
, sRegistryPath
);
164 TRACE("result: 0x%x, path: %s\n", hr
, debugstr_w(*lpRegistryPath
));
167 /*******************************************************************************
168 * GAMEUX_WriteRegistryRecord
170 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
171 * structure) into expected place in registry.
174 * GameData [I] structure with data which will
175 * be written into registry.
176 * Proper values of fields installScope
177 * and guidInstanceId are required
178 * to create registry key.
180 * Schema of naming registry keys associated with games is available in
181 * description of _buildGameRegistryPath internal function.
183 * List of registry keys associated with structure fields:
184 * Key Field in GAMEUX_GAME_DATA structure
185 * ApplicationId guidApplicationId
186 * ConfigApplicationPath sGameInstallDirectory
187 * ConfigGDFBinaryPath sGDFBinaryPath
191 static HRESULT
GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA
*GameData
)
194 LPWSTR lpRegistryKey
;
196 WCHAR sGameApplicationId
[40];
198 TRACE("(%p)\n", GameData
);
200 hr
= GAMEUX_buildGameRegistryPath(GameData
->installScope
, &GameData
->guidInstanceId
, &lpRegistryKey
);
203 hr
= (StringFromGUID2(&GameData
->guidApplicationId
, sGameApplicationId
, ARRAY_SIZE(sGameApplicationId
)) ? S_OK
: E_FAIL
);
206 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
,
207 0, NULL
, 0, KEY_ALL_ACCESS
| KEY_WOW64_64KEY
, NULL
,
212 /* write game data to registry key */
213 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"ConfigApplicationPath", 0,
214 REG_SZ
, (LPBYTE
)(GameData
->sGameInstallDirectory
),
215 (lstrlenW(GameData
->sGameInstallDirectory
)+1)*sizeof(WCHAR
)));
218 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"ConfigGDFBinaryPath", 0,
219 REG_SZ
, (LPBYTE
)(GameData
->sGDFBinaryPath
),
220 (lstrlenW(GameData
->sGDFBinaryPath
)+1)*sizeof(WCHAR
)));
223 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"ApplicationId", 0,
224 REG_SZ
, (LPBYTE
)(sGameApplicationId
),
225 (lstrlenW(sGameApplicationId
)+1)*sizeof(WCHAR
)));
228 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"Title", 0,
229 REG_SZ
, (LPBYTE
)(GameData
->bstrName
),
230 (lstrlenW(GameData
->bstrName
)+1)*sizeof(WCHAR
)));
233 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, L
"Description", 0,
234 REG_SZ
, (LPBYTE
)(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
),
235 (lstrlenW(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
)+1)*sizeof(WCHAR
)));
241 /* if something failed, remove whole key */
242 hr2
= RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
, KEY_WOW64_64KEY
, 0);
243 /* do not overwrite old failure code with new success code */
249 HeapFree(GetProcessHeap(), 0, lpRegistryKey
);
250 TRACE("returning 0x%x\n", hr
);
253 /*******************************************************************************
254 * GAMEUX_ProcessGameDefinitionElement
256 * Helper function, parses single element from Game Definition
259 * lpXMLElement [I] game definition element
260 * GameData [O] structure, where parsed
261 * data will be stored
263 static HRESULT
GAMEUX_ProcessGameDefinitionElement(
264 IXMLDOMElement
*element
,
265 struct GAMEUX_GAME_DATA
*GameData
)
268 BSTR bstrElementName
;
270 TRACE("(%p, %p)\n", element
, GameData
);
272 hr
= IXMLDOMElement_get_nodeName(element
, &bstrElementName
);
275 /* check element name */
276 if(lstrcmpW(bstrElementName
, L
"Name") == 0)
277 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrName
);
279 else if(lstrcmpW(bstrElementName
, L
"Description") == 0)
280 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrDescription
);
283 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName
));
285 SysFreeString(bstrElementName
);
290 /*******************************************************************************
291 * GAMEUX_ParseGameDefinition
293 * Helper function, loads data from given XML element into fields of GAME_DATA
297 * lpXMLGameDefinitionElement [I] Game Definition XML element
298 * GameData [O] structure where data loaded from
299 * XML element will be stored in
301 static HRESULT
GAMEUX_ParseGameDefinition(IXMLDOMElement
*gamedef
, struct GAMEUX_GAME_DATA
*game_data
)
303 IXMLDOMNodeList
*props
;
308 TRACE("(%p, %p)\n", gamedef
, game_data
);
310 attr
= SysAllocString(L
"gameID");
312 return E_OUTOFMEMORY
;
314 hr
= IXMLDOMElement_getAttribute(gamedef
, attr
, &var
);
319 hr
= CLSIDFromString(V_BSTR(&var
), &game_data
->guidApplicationId
);
324 hr
= IXMLDOMElement_get_childNodes(gamedef
, &props
);
333 hr
= IXMLDOMNodeList_nextNode(props
, &prop
);
336 IXMLDOMElement
*element
;
338 hr
= IXMLDOMNode_QueryInterface(prop
, &IID_IXMLDOMElement
, (void**)&element
);
341 hr
= GAMEUX_ProcessGameDefinitionElement(element
, game_data
);
342 IXMLDOMElement_Release(element
);
345 IXMLDOMNode_Release(prop
);
349 IXMLDOMNodeList_Release(props
);
351 return FAILED(hr
) ? hr
: S_OK
;
354 struct parse_gdf_thread_param
356 struct GAMEUX_GAME_DATA
*GameData
;
360 /*******************************************************************************
361 * GAMEUX_ParseGDFBinary
363 * Helper function, loads given binary and parses embed GDF if there's any.
366 * GameData [I/O] Structure with game's data. Content of field
367 * sGDFBinaryPath defines path to binary, from
368 * which embed GDF will be loaded. Data from
369 * GDF will be stored in other fields of this
372 static DWORD WINAPI
GAMEUX_ParseGDFBinary(void *thread_param
)
374 struct parse_gdf_thread_param
*ctx
= thread_param
;
375 struct GAMEUX_GAME_DATA
*GameData
= ctx
->GameData
;
378 WCHAR sResourcePath
[MAX_PATH
];
380 VARIANT_BOOL isSuccessful
;
381 IXMLDOMDocument
*document
;
383 IXMLDOMElement
*root
, *gdElement
;
385 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData
, debugstr_w(GameData
->sGDFBinaryPath
));
387 /* prepare path to GDF, using res:// prefix */
388 lstrcpyW(sResourcePath
, L
"res://");
389 lstrcatW(sResourcePath
, GameData
->sGDFBinaryPath
);
390 lstrcatW(sResourcePath
, L
"/DATA/");
391 lstrcatW(sResourcePath
, ID_GDF_XML_STR
);
395 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
396 &IID_IXMLDOMDocument
, (void**)&document
);
400 /* load GDF into MSXML */
401 V_VT(&variant
) = VT_BSTR
;
402 V_BSTR(&variant
) = SysAllocString(sResourcePath
);
403 if(!V_BSTR(&variant
))
408 hr
= IXMLDOMDocument_load(document
, variant
, &isSuccessful
);
409 if(hr
== S_FALSE
|| isSuccessful
== VARIANT_FALSE
)
413 SysFreeString(V_BSTR(&variant
));
417 hr
= IXMLDOMDocument_get_documentElement(document
, &root
);
424 hr
= IXMLDOMElement_get_firstChild(root
, &gdNode
);
430 hr
= IXMLDOMNode_QueryInterface(gdNode
, &IID_IXMLDOMElement
, (LPVOID
*)&gdElement
);
433 hr
= GAMEUX_ParseGameDefinition(gdElement
, GameData
);
434 IXMLDOMElement_Release(gdElement
);
437 IXMLDOMNode_Release(gdNode
);
440 IXMLDOMElement_Release(root
);
443 IXMLDOMDocument_Release(document
);
451 /*******************************************************************
452 * GAMEUX_RemoveRegistryRecord
454 * Helper function, removes registry key associated with given game instance
456 static HRESULT
GAMEUX_RemoveRegistryRecord(GUID
* pInstanceID
)
459 LPWSTR lpRegistryPath
= NULL
;
460 TRACE("(%s)\n", debugstr_guid(pInstanceID
));
462 /* first, check is game installed for all users */
463 hr
= GAMEUX_buildGameRegistryPath(GIS_ALL_USERS
, pInstanceID
, &lpRegistryPath
);
465 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
467 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
469 /* if not, check current user */
472 hr
= GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER
, pInstanceID
, &lpRegistryPath
);
474 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
476 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
481 /*******************************************************************************
482 * GAMEUX_RegisterGame
484 * Internal helper function. Registers game associated with given GDF binary in
485 * Game Explorer. Implemented in gameexplorer.c
488 * sGDFBinaryPath [I] path to binary containing GDF file in
490 * sGameInstallDirectory [I] path to directory, where game installed
492 * installScope [I] scope of game installation
493 * pInstanceID [I/O] pointer to game instance identifier.
494 * If pointing to GUID_NULL, then new
495 * identifier will be generated automatically
496 * and returned via this parameter
498 static HRESULT
GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath
,
499 LPCWSTR sGameInstallDirectory
,
500 GAME_INSTALL_SCOPE installScope
,
504 struct GAMEUX_GAME_DATA GameData
;
506 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
508 GAMEUX_initGameData(&GameData
);
509 GameData
.sGDFBinaryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath
)+1)*sizeof(WCHAR
));
510 lstrcpyW(GameData
.sGDFBinaryPath
, sGDFBinaryPath
);
511 GameData
.sGameInstallDirectory
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory
)+1)*sizeof(WCHAR
));
512 lstrcpyW(GameData
.sGameInstallDirectory
, sGameInstallDirectory
);
513 GameData
.installScope
= installScope
;
515 /* generate GUID if it was not provided by user */
516 if(IsEqualGUID(pInstanceID
, &GUID_NULL
))
517 hr
= CoCreateGuid(pInstanceID
);
519 GameData
.guidInstanceId
= *pInstanceID
;
521 /* load data from GDF binary */
524 struct parse_gdf_thread_param thread_param
;
528 thread_param
.GameData
= &GameData
;
529 if(!(thread
= CreateThread(NULL
, 0, GAMEUX_ParseGDFBinary
, &thread_param
, 0, &ret
)))
531 ERR("Failed to create thread.\n");
535 ret
= WaitForSingleObject(thread
, INFINITE
);
537 if(ret
!= WAIT_OBJECT_0
)
539 ERR("Wait failed (%#x).\n", ret
);
543 hr
= thread_param
.hr
;
546 /* save data to registry */
548 hr
= GAMEUX_WriteRegistryRecord(&GameData
);
551 GAMEUX_uninitGameData(&GameData
);
552 TRACE("returning 0x%08x\n", hr
);
555 /*******************************************************************************
556 * GAMEUX_IsGameKeyExist
558 * Helper function, checks if game's registry ath exists in given scope
561 * installScope [I] scope to search game in
562 * InstanceID [I] game instance identifier
563 * lpRegistryPath [O] place to store address of registry path to
564 * the game. It is filled only if key exists.
565 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
568 * S_OK key was found properly
569 * S_FALSE key does not exists
572 static HRESULT
GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope
,
574 LPWSTR
* lpRegistryPath
) {
579 hr
= GAMEUX_buildGameRegistryPath(installScope
, InstanceID
, lpRegistryPath
);
582 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, *lpRegistryPath
,
583 0, KEY_WOW64_64KEY
, &hKey
));
585 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
592 /* if the key does not exist or another error occurred, do not return the path */
593 HeapFree(GetProcessHeap(), 0, *lpRegistryPath
);
594 *lpRegistryPath
= NULL
;
599 /*******************************************************************************
600 * GAMEUX_LoadRegistryString
602 * Helper function, loads string from registry value and allocates buffer for it
604 static HRESULT
GAMEUX_LoadRegistryString(HKEY hRootKey
,
605 LPCWSTR lpRegistryKey
,
606 LPCWSTR lpRegistryValue
,
614 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
615 RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
619 *lpValue
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
625 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
626 RRF_RT_REG_SZ
, NULL
, *lpValue
, &dwSize
));
630 /*******************************************************************************
633 * Helper function, updates stored data about game with given InstanceID
635 static HRESULT
GAMEUX_UpdateGame(LPGUID InstanceID
) {
637 GAME_INSTALL_SCOPE installScope
;
638 LPWSTR lpRegistryPath
;
639 LPWSTR lpGDFBinaryPath
;
641 TRACE("(%s)\n", debugstr_guid(InstanceID
));
643 /* first, check is game exists in CURRENT_USER scope */
644 installScope
= GIS_CURRENT_USER
;
645 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
649 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
650 installScope
= GIS_ALL_USERS
;
651 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
655 /* still not found? let's inform user that game does not exists */
656 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
660 WCHAR
*lpGameInstallDirectory
= NULL
;
662 /* game found, its registry path is in lpRegistryPath and install
663 * scope in installScope */
664 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath
));
666 /* first, read required data about game */
667 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
668 L
"ConfigGDFBinaryPath", &lpGDFBinaryPath
);
671 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
672 L
"ConfigApplicationPath", &lpGameInstallDirectory
);
674 /* now remove currently existing registry key */
676 hr
= GAMEUX_RemoveRegistryRecord(InstanceID
);
678 /* and add it again, it will cause in reparsing of whole GDF */
680 hr
= GAMEUX_RegisterGame(lpGDFBinaryPath
, lpGameInstallDirectory
,
681 installScope
, InstanceID
);
683 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath
);
684 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory
);
687 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
688 TRACE("returning 0x%x\n", hr
);
691 /*******************************************************************************
692 * GAMEUX_FindGameInstanceId
694 * Internal helper function. Description available in gameux_private.h file
696 HRESULT
GAMEUX_FindGameInstanceId(
697 LPCWSTR sGDFBinaryPath
,
698 GAME_INSTALL_SCOPE installScope
,
703 LPWSTR lpRegistryPath
= NULL
;
705 DWORD dwSubKeys
, dwSubKeyLen
, dwMaxSubKeyLen
, i
;
706 LPWSTR lpName
= NULL
, lpValue
= NULL
;
708 hr
= GAMEUX_buildGameRegistryPath(installScope
, NULL
, &lpRegistryPath
);
711 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
712 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
713 lpRegistryPath
, 0, KEY_READ
| KEY_WOW64_64KEY
, &hRootKey
));
717 hr
= HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey
, NULL
, NULL
, NULL
,
718 &dwSubKeys
, &dwMaxSubKeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
));
722 ++dwMaxSubKeyLen
; /* for string terminator */
723 lpName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen
*sizeof(WCHAR
));
724 if(!lpName
) hr
= E_OUTOFMEMORY
;
729 for(i
=0; i
<dwSubKeys
&& !found
; ++i
)
731 dwSubKeyLen
= dwMaxSubKeyLen
;
732 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey
, i
, lpName
, &dwSubKeyLen
,
733 NULL
, NULL
, NULL
, NULL
));
736 hr
= GAMEUX_LoadRegistryString(hRootKey
, lpName
,
737 L
"ConfigGDFBinaryPath", &lpValue
);
741 if(lstrcmpW(lpValue
, sGDFBinaryPath
)==0)
743 /* key found, let's copy instance id and exit */
744 hr
= CLSIDFromString(lpName
, pInstanceId
);
747 HeapFree(GetProcessHeap(), 0, lpValue
);
752 HeapFree(GetProcessHeap(), 0, lpName
);
753 RegCloseKey(hRootKey
);
756 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
758 if((SUCCEEDED(hr
) && !found
) || hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
763 /*******************************************************************************
764 * GameExplorer implementation
767 typedef struct _GameExplorerImpl
769 IGameExplorer IGameExplorer_iface
;
770 IGameExplorer2 IGameExplorer2_iface
;
774 static inline GameExplorerImpl
*impl_from_IGameExplorer(IGameExplorer
*iface
)
776 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer_iface
);
779 static inline GameExplorerImpl
*impl_from_IGameExplorer2(IGameExplorer2
*iface
)
781 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer2_iface
);
784 static HRESULT WINAPI
GameExplorerImpl_QueryInterface(
785 IGameExplorer
*iface
,
789 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
791 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
795 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
796 IsEqualGUID(riid
, &IID_IGameExplorer
))
798 *ppvObject
= &This
->IGameExplorer_iface
;
800 else if(IsEqualGUID(riid
, &IID_IGameExplorer2
))
802 *ppvObject
= &This
->IGameExplorer2_iface
;
806 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
807 return E_NOINTERFACE
;
810 IGameExplorer_AddRef(iface
);
814 static ULONG WINAPI
GameExplorerImpl_AddRef(IGameExplorer
*iface
)
816 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
819 ref
= InterlockedIncrement(&This
->ref
);
821 TRACE("(%p): ref=%d\n", This
, ref
);
825 static ULONG WINAPI
GameExplorerImpl_Release(IGameExplorer
*iface
)
827 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
830 ref
= InterlockedDecrement(&This
->ref
);
831 TRACE("(%p): ref=%d\n", This
, ref
);
835 TRACE("freeing GameExplorer object\n");
836 HeapFree(GetProcessHeap(), 0, This
);
842 static HRESULT WINAPI
GameExplorerImpl_AddGame(
843 IGameExplorer
*iface
,
844 BSTR bstrGDFBinaryPath
,
845 BSTR sGameInstallDirectory
,
846 GAME_INSTALL_SCOPE installScope
,
849 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
850 TRACE("(%p, %s, %s, 0x%x, %s)\n", This
, debugstr_w(bstrGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
851 return GAMEUX_RegisterGame(bstrGDFBinaryPath
, sGameInstallDirectory
, installScope
, pInstanceID
);
854 static HRESULT WINAPI
GameExplorerImpl_RemoveGame(
855 IGameExplorer
*iface
,
858 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
860 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
861 return GAMEUX_RemoveRegistryRecord(&instanceID
);
864 static HRESULT WINAPI
GameExplorerImpl_UpdateGame(
865 IGameExplorer
*iface
,
868 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
870 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
871 return GAMEUX_UpdateGame(&instanceID
);
874 static HRESULT WINAPI
GameExplorerImpl_VerifyAccess(
875 IGameExplorer
*iface
,
879 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
881 FIXME("(%p, %s, %p)\n", This
, debugstr_w(sGDFBinaryPath
), pHasAccess
);
886 static const struct IGameExplorerVtbl GameExplorerImplVtbl
=
888 GameExplorerImpl_QueryInterface
,
889 GameExplorerImpl_AddRef
,
890 GameExplorerImpl_Release
,
891 GameExplorerImpl_AddGame
,
892 GameExplorerImpl_RemoveGame
,
893 GameExplorerImpl_UpdateGame
,
894 GameExplorerImpl_VerifyAccess
898 static HRESULT WINAPI
GameExplorer2Impl_QueryInterface(
899 IGameExplorer2
*iface
,
903 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
904 return GameExplorerImpl_QueryInterface(&This
->IGameExplorer_iface
, riid
, ppvObject
);
907 static ULONG WINAPI
GameExplorer2Impl_AddRef(IGameExplorer2
*iface
)
909 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
910 return GameExplorerImpl_AddRef(&This
->IGameExplorer_iface
);
913 static ULONG WINAPI
GameExplorer2Impl_Release(IGameExplorer2
*iface
)
915 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
916 return GameExplorerImpl_Release(&This
->IGameExplorer_iface
);
919 static HRESULT WINAPI
GameExplorer2Impl_CheckAccess(
920 IGameExplorer2
*iface
,
921 LPCWSTR binaryGDFPath
,
924 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
925 FIXME("stub (%p, %s, %p)\n", This
, debugstr_w(binaryGDFPath
), pHasAccess
);
929 static HRESULT WINAPI
GameExplorer2Impl_InstallGame(
930 IGameExplorer2
*iface
,
931 LPCWSTR binaryGDFPath
,
932 LPCWSTR installDirectory
,
933 GAME_INSTALL_SCOPE installScope
)
937 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
939 TRACE("(%p, %s, %s, 0x%x)\n", This
, debugstr_w(binaryGDFPath
), debugstr_w(installDirectory
), installScope
);
944 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
947 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
951 /* if game isn't yet registered, then install it */
952 instanceId
= GUID_NULL
;
953 hr
= GAMEUX_RegisterGame(binaryGDFPath
, installDirectory
, installScope
, &instanceId
);
956 /* otherwise, update game */
957 hr
= GAMEUX_UpdateGame(&instanceId
);
962 static HRESULT WINAPI
GameExplorer2Impl_UninstallGame(
963 IGameExplorer2
*iface
,
964 LPCWSTR binaryGDFPath
)
968 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
969 TRACE("(%p, %s)\n", This
, debugstr_w(binaryGDFPath
));
974 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
977 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
980 hr
= GAMEUX_RemoveRegistryRecord(&instanceId
);
985 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl
=
987 GameExplorer2Impl_QueryInterface
,
988 GameExplorer2Impl_AddRef
,
989 GameExplorer2Impl_Release
,
990 GameExplorer2Impl_InstallGame
,
991 GameExplorer2Impl_UninstallGame
,
992 GameExplorer2Impl_CheckAccess
996 * Construction routine
998 HRESULT
GameExplorer_create(
1002 GameExplorerImpl
*pGameExplorer
;
1004 TRACE("(%p, %p)\n", pUnkOuter
, ppObj
);
1006 pGameExplorer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer
));
1009 return E_OUTOFMEMORY
;
1011 pGameExplorer
->IGameExplorer_iface
.lpVtbl
= &GameExplorerImplVtbl
;
1012 pGameExplorer
->IGameExplorer2_iface
.lpVtbl
= &GameExplorer2ImplVtbl
;
1013 pGameExplorer
->ref
= 1;
1015 *ppObj
= (IUnknown
*)&pGameExplorer
->IGameExplorer_iface
;
1017 TRACE("returning iface: %p\n", *ppObj
);