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
28 #include "gameux_private.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(gameux
);
38 /*******************************************************************************
39 * GameUX helper functions
41 /*******************************************************************************
44 * Internal helper function.
45 * Initializes GAME_DATA structure fields with proper values. Should be
46 * called always before first usage of this structure. Implemented in gameexplorer.c
49 * GameData [I/O] pointer to structure to initialize
51 static void GAMEUX_initGameData(struct GAMEUX_GAME_DATA
*GameData
)
53 GameData
->sGDFBinaryPath
= NULL
;
54 GameData
->sGameInstallDirectory
= NULL
;
55 GameData
->bstrName
= NULL
;
56 GameData
->bstrDescription
= NULL
;
58 /*******************************************************************************
59 * GAMEUX_uninitGameData
61 * Internal helper function.
62 * Properly frees all data stored or pointed by fields of GAME_DATA structure.
63 * Should be called before freeing this structure. Implemented in gameexplorer.c
66 * GameData [I/O] pointer to structure to uninitialize
68 static void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA
*GameData
)
70 HeapFree(GetProcessHeap(), 0, GameData
->sGDFBinaryPath
);
71 HeapFree(GetProcessHeap(), 0, GameData
->sGameInstallDirectory
);
72 SysFreeString(GameData
->bstrName
);
73 SysFreeString(GameData
->bstrDescription
);
75 /*******************************************************************************
76 * GAMEUX_buildGameRegistryPath
78 * Internal helper function. Description available in gameux_private.h file
80 HRESULT
GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope
,
81 LPCGUID gameInstanceId
,
82 LPWSTR
* lpRegistryPath
)
84 static const WCHAR sGameUxRegistryPath
[] = {'S','O','F','T','W','A','R','E','\\',
85 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
86 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
87 static const WCHAR sGames
[] = {'G','a','m','e','s',0};
88 static const WCHAR sBackslash
[] = {'\\',0};
92 PTOKEN_USER pTokenUser
= NULL
;
95 WCHAR sInstanceId
[40];
96 WCHAR sRegistryPath
[8192];
98 TRACE("(0x%x, %s, %p)\n", installScope
, debugstr_guid(gameInstanceId
), lpRegistryPath
);
100 /* this will make freeing it easier for user */
101 *lpRegistryPath
= NULL
;
103 lstrcpyW(sRegistryPath
, sGameUxRegistryPath
);
104 lstrcatW(sRegistryPath
, sBackslash
);
106 if(installScope
== GIS_CURRENT_USER
)
108 /* build registry path containing user's SID */
109 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
110 hr
= HRESULT_FROM_WIN32(GetLastError());
114 if(!GetTokenInformation(hToken
, TokenUser
, NULL
, 0, &dwLength
) &&
115 GetLastError()!=ERROR_INSUFFICIENT_BUFFER
)
116 hr
= HRESULT_FROM_WIN32(GetLastError());
120 pTokenUser
= HeapAlloc(GetProcessHeap(), 0, dwLength
);
126 if(!GetTokenInformation(hToken
, TokenUser
, (LPVOID
)pTokenUser
, dwLength
, &dwLength
))
127 hr
= HRESULT_FROM_WIN32(GetLastError());
130 if(!ConvertSidToStringSidW(pTokenUser
->User
.Sid
, &lpSID
))
131 hr
= HRESULT_FROM_WIN32(GetLastError());
135 lstrcatW(sRegistryPath
, lpSID
);
139 HeapFree(GetProcessHeap(), 0, pTokenUser
);
143 else if(installScope
== GIS_ALL_USERS
)
144 /* build registry path without SID */
145 lstrcatW(sRegistryPath
, sGames
);
149 /* put game's instance id on the end of path, only if instance id was given */
153 hr
= (StringFromGUID2(gameInstanceId
, sInstanceId
, sizeof(sInstanceId
)/sizeof(sInstanceId
[0])) ? S_OK
: E_FAIL
);
157 lstrcatW(sRegistryPath
, sBackslash
);
158 lstrcatW(sRegistryPath
, sInstanceId
);
164 *lpRegistryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath
)+1)*sizeof(WCHAR
));
170 lstrcpyW(*lpRegistryPath
, sRegistryPath
);
172 TRACE("result: 0x%x, path: %s\n", hr
, debugstr_w(*lpRegistryPath
));
175 /*******************************************************************************
176 * GAMEUX_WriteRegistryRecord
178 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
179 * structure) into expected place in registry.
182 * GameData [I] structure with data which will
183 * be written into registry.
184 * Proper values of fields installScope
185 * and guidInstanceId are required
186 * to create registry key.
188 * Schema of naming registry keys associated with games is available in
189 * description of _buildGameRegistryPath internal function.
191 * List of registry keys associated with structure fields:
192 * Key Field in GAMEUX_GAME_DATA structure
193 * ApplicationId guidApplicationId
194 * ConfigApplicationPath sGameInstallDirectory
195 * ConfigGDFBinaryPath sGDFBinaryPath
199 static HRESULT
GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA
*GameData
)
201 static const WCHAR sApplicationId
[] =
202 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
203 static const WCHAR sConfigApplicationPath
[] =
204 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
205 static const WCHAR sConfigGDFBinaryPath
[] =
206 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
207 static const WCHAR sTitle
[] =
208 {'T','i','t','l','e',0};
209 static const WCHAR sDescription
[] =
210 {'D','e','s','c','r','i','p','t','i','o','n',0};
213 LPWSTR lpRegistryKey
;
215 WCHAR sGameApplicationId
[40];
217 TRACE("(%p)\n", GameData
);
219 hr
= GAMEUX_buildGameRegistryPath(GameData
->installScope
, &GameData
->guidInstanceId
, &lpRegistryKey
);
222 hr
= (StringFromGUID2(&GameData
->guidApplicationId
, sGameApplicationId
, sizeof(sGameApplicationId
)/sizeof(sGameApplicationId
[0])) ? S_OK
: E_FAIL
);
225 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
,
226 0, NULL
, 0, KEY_ALL_ACCESS
| KEY_WOW64_64KEY
, NULL
,
231 /* write game data to registry key */
232 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigApplicationPath
, 0,
233 REG_SZ
, (LPBYTE
)(GameData
->sGameInstallDirectory
),
234 (lstrlenW(GameData
->sGameInstallDirectory
)+1)*sizeof(WCHAR
)));
237 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigGDFBinaryPath
, 0,
238 REG_SZ
, (LPBYTE
)(GameData
->sGDFBinaryPath
),
239 (lstrlenW(GameData
->sGDFBinaryPath
)+1)*sizeof(WCHAR
)));
242 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sApplicationId
, 0,
243 REG_SZ
, (LPBYTE
)(sGameApplicationId
),
244 (lstrlenW(sGameApplicationId
)+1)*sizeof(WCHAR
)));
247 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sTitle
, 0,
248 REG_SZ
, (LPBYTE
)(GameData
->bstrName
),
249 (lstrlenW(GameData
->bstrName
)+1)*sizeof(WCHAR
)));
252 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sDescription
, 0,
253 REG_SZ
, (LPBYTE
)(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
),
254 (lstrlenW(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
)+1)*sizeof(WCHAR
)));
260 /* if something failed, remove whole key */
261 hr2
= RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
, KEY_WOW64_64KEY
, 0);
262 /* do not overwrite old failure code with new success code */
268 HeapFree(GetProcessHeap(), 0, lpRegistryKey
);
269 TRACE("returning 0x%x\n", hr
);
272 /*******************************************************************************
273 * GAMEUX_ProcessGameDefinitionElement
275 * Helper function, parses single element from Game Definition
278 * lpXMLElement [I] game definition element
279 * GameData [O] structure, where parsed
280 * data will be stored
282 static HRESULT
GAMEUX_ProcessGameDefinitionElement(
283 IXMLDOMElement
*element
,
284 struct GAMEUX_GAME_DATA
*GameData
)
286 static const WCHAR sName
[] =
288 static const WCHAR sDescription
[] =
289 {'D','e','s','c','r','i','p','t','i','o','n',0};
292 BSTR bstrElementName
;
294 TRACE("(%p, %p)\n", element
, GameData
);
296 hr
= IXMLDOMElement_get_nodeName(element
, &bstrElementName
);
299 /* check element name */
300 if(lstrcmpW(bstrElementName
, sName
) == 0)
301 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrName
);
303 else if(lstrcmpW(bstrElementName
, sDescription
) == 0)
304 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrDescription
);
307 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName
));
309 SysFreeString(bstrElementName
);
314 /*******************************************************************************
315 * GAMEUX_ParseGameDefinition
317 * Helper function, loads data from given XML element into fields of GAME_DATA
321 * lpXMLGameDefinitionElement [I] Game Definition XML element
322 * GameData [O] structure where data loaded from
323 * XML element will be stored in
325 static HRESULT
GAMEUX_ParseGameDefinition(IXMLDOMElement
*gamedef
, struct GAMEUX_GAME_DATA
*game_data
)
327 static const WCHAR gameidW
[] = {'g','a','m','e','I','D',0};
328 IXMLDOMNodeList
*props
;
333 TRACE("(%p, %p)\n", gamedef
, game_data
);
335 attr
= SysAllocString(gameidW
);
337 return E_OUTOFMEMORY
;
339 hr
= IXMLDOMElement_getAttribute(gamedef
, attr
, &var
);
344 hr
= CLSIDFromString(V_BSTR(&var
), &game_data
->guidApplicationId
);
349 hr
= IXMLDOMElement_get_childNodes(gamedef
, &props
);
358 hr
= IXMLDOMNodeList_nextNode(props
, &prop
);
361 IXMLDOMElement
*element
;
363 hr
= IXMLDOMNode_QueryInterface(prop
, &IID_IXMLDOMElement
, (void**)&element
);
366 hr
= GAMEUX_ProcessGameDefinitionElement(element
, game_data
);
367 IXMLDOMElement_Release(element
);
370 IXMLDOMNode_Release(prop
);
374 IXMLDOMNodeList_Release(props
);
376 return FAILED(hr
) ? hr
: S_OK
;
379 struct parse_gdf_thread_param
381 struct GAMEUX_GAME_DATA
*GameData
;
385 /*******************************************************************************
386 * GAMEUX_ParseGDFBinary
388 * Helper function, loads given binary and parses embed GDF if there's any.
391 * GameData [I/O] Structure with game's data. Content of field
392 * sGDFBinaryPath defines path to binary, from
393 * which embed GDF will be loaded. Data from
394 * GDF will be stored in other fields of this
397 static DWORD WINAPI
GAMEUX_ParseGDFBinary(void *thread_param
)
399 struct parse_gdf_thread_param
*ctx
= thread_param
;
400 struct GAMEUX_GAME_DATA
*GameData
= ctx
->GameData
;
401 static const WCHAR sRes
[] = {'r','e','s',':','/','/',0};
402 static const WCHAR sDATA
[] = {'D','A','T','A',0};
403 static const WCHAR sSlash
[] = {'/',0};
406 WCHAR sResourcePath
[MAX_PATH
];
408 VARIANT_BOOL isSuccessful
;
409 IXMLDOMDocument
*document
;
411 IXMLDOMElement
*root
, *gdElement
;
413 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData
, debugstr_w(GameData
->sGDFBinaryPath
));
415 /* prepare path to GDF, using res:// prefix */
416 lstrcpyW(sResourcePath
, sRes
);
417 lstrcatW(sResourcePath
, GameData
->sGDFBinaryPath
);
418 lstrcatW(sResourcePath
, sSlash
);
419 lstrcatW(sResourcePath
, sDATA
);
420 lstrcatW(sResourcePath
, sSlash
);
421 lstrcatW(sResourcePath
, ID_GDF_XML_STR
);
425 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
426 &IID_IXMLDOMDocument
, (void**)&document
);
430 /* load GDF into MSXML */
431 V_VT(&variant
) = VT_BSTR
;
432 V_BSTR(&variant
) = SysAllocString(sResourcePath
);
433 if(!V_BSTR(&variant
))
438 hr
= IXMLDOMDocument_load(document
, variant
, &isSuccessful
);
439 if(hr
== S_FALSE
|| isSuccessful
== VARIANT_FALSE
)
443 SysFreeString(V_BSTR(&variant
));
447 hr
= IXMLDOMDocument_get_documentElement(document
, &root
);
454 hr
= IXMLDOMElement_get_firstChild(root
, &gdNode
);
460 hr
= IXMLDOMNode_QueryInterface(gdNode
, &IID_IXMLDOMElement
, (LPVOID
*)&gdElement
);
463 hr
= GAMEUX_ParseGameDefinition(gdElement
, GameData
);
464 IXMLDOMElement_Release(gdElement
);
467 IXMLDOMNode_Release(gdNode
);
470 IXMLDOMElement_Release(root
);
473 IXMLDOMDocument_Release(document
);
481 /*******************************************************************
482 * GAMEUX_RemoveRegistryRecord
484 * Helper function, removes registry key associated with given game instance
486 static HRESULT
GAMEUX_RemoveRegistryRecord(GUID
* pInstanceID
)
489 LPWSTR lpRegistryPath
= NULL
;
490 TRACE("(%s)\n", debugstr_guid(pInstanceID
));
492 /* first, check is game installed for all users */
493 hr
= GAMEUX_buildGameRegistryPath(GIS_ALL_USERS
, pInstanceID
, &lpRegistryPath
);
495 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
497 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
499 /* if not, check current user */
502 hr
= GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER
, pInstanceID
, &lpRegistryPath
);
504 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
506 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
511 /*******************************************************************************
512 * GAMEUX_RegisterGame
514 * Internal helper function. Registers game associated with given GDF binary in
515 * Game Explorer. Implemented in gameexplorer.c
518 * sGDFBinaryPath [I] path to binary containing GDF file in
520 * sGameInstallDirectory [I] path to directory, where game installed
522 * installScope [I] scope of game installation
523 * pInstanceID [I/O] pointer to game instance identifier.
524 * If pointing to GUID_NULL, then new
525 * identifier will be generated automatically
526 * and returned via this parameter
528 static HRESULT
GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath
,
529 LPCWSTR sGameInstallDirectory
,
530 GAME_INSTALL_SCOPE installScope
,
534 struct GAMEUX_GAME_DATA GameData
;
536 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
538 GAMEUX_initGameData(&GameData
);
539 GameData
.sGDFBinaryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath
)+1)*sizeof(WCHAR
));
540 lstrcpyW(GameData
.sGDFBinaryPath
, sGDFBinaryPath
);
541 GameData
.sGameInstallDirectory
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory
)+1)*sizeof(WCHAR
));
542 lstrcpyW(GameData
.sGameInstallDirectory
, sGameInstallDirectory
);
543 GameData
.installScope
= installScope
;
545 /* generate GUID if it was not provided by user */
546 if(IsEqualGUID(pInstanceID
, &GUID_NULL
))
547 hr
= CoCreateGuid(pInstanceID
);
549 GameData
.guidInstanceId
= *pInstanceID
;
551 /* load data from GDF binary */
554 struct parse_gdf_thread_param thread_param
;
558 thread_param
.GameData
= &GameData
;
559 if(!(thread
= CreateThread(NULL
, 0, GAMEUX_ParseGDFBinary
, &thread_param
, 0, &ret
)))
561 ERR("Failed to create thread.\n");
565 ret
= WaitForSingleObject(thread
, INFINITE
);
567 if(ret
!= WAIT_OBJECT_0
)
569 ERR("Wait failed (%#x).\n", ret
);
573 hr
= thread_param
.hr
;
576 /* save data to registry */
578 hr
= GAMEUX_WriteRegistryRecord(&GameData
);
581 GAMEUX_uninitGameData(&GameData
);
582 TRACE("returning 0x%08x\n", hr
);
585 /*******************************************************************************
586 * GAMEUX_IsGameKeyExist
588 * Helper function, checks if game's registry ath exists in given scope
591 * installScope [I] scope to search game in
592 * InstanceID [I] game instance identifier
593 * lpRegistryPath [O] place to store address of registry path to
594 * the game. It is filled only if key exists.
595 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
598 * S_OK key was found properly
599 * S_FALSE key does not exists
602 static HRESULT
GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope
,
604 LPWSTR
* lpRegistryPath
) {
609 hr
= GAMEUX_buildGameRegistryPath(installScope
, InstanceID
, lpRegistryPath
);
612 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, *lpRegistryPath
,
613 0, KEY_WOW64_64KEY
, &hKey
));
615 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
622 /* if the key does not exist or another error occurred, do not return the path */
623 HeapFree(GetProcessHeap(), 0, *lpRegistryPath
);
624 *lpRegistryPath
= NULL
;
629 /*******************************************************************************
630 * GAMEUX_LoadRegistryString
632 * Helper function, loads string from registry value and allocates buffer for it
634 static HRESULT
GAMEUX_LoadRegistryString(HKEY hRootKey
,
635 LPCWSTR lpRegistryKey
,
636 LPCWSTR lpRegistryValue
,
644 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
645 RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
649 *lpValue
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
655 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
656 RRF_RT_REG_SZ
, NULL
, *lpValue
, &dwSize
));
660 /*******************************************************************************
663 * Helper function, updates stored data about game with given InstanceID
665 static HRESULT
GAMEUX_UpdateGame(LPGUID InstanceID
) {
666 static const WCHAR sConfigGDFBinaryPath
[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
667 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};
670 GAME_INSTALL_SCOPE installScope
;
671 LPWSTR lpRegistryPath
;
672 LPWSTR lpGDFBinaryPath
;
674 TRACE("(%s)\n", debugstr_guid(InstanceID
));
676 /* first, check is game exists in CURRENT_USER scope */
677 installScope
= GIS_CURRENT_USER
;
678 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
682 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
683 installScope
= GIS_ALL_USERS
;
684 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
688 /* still not found? let's inform user that game does not exists */
689 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
693 WCHAR
*lpGameInstallDirectory
= NULL
;
695 /* game found, its registry path is in lpRegistryPath and install
696 * scope in installScope */
697 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath
));
699 /* first, read required data about game */
700 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
701 sConfigGDFBinaryPath
, &lpGDFBinaryPath
);
704 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
705 sConfigApplicationPath
, &lpGameInstallDirectory
);
707 /* now remove currently existing registry key */
709 hr
= GAMEUX_RemoveRegistryRecord(InstanceID
);
711 /* and add it again, it will cause in reparsing of whole GDF */
713 hr
= GAMEUX_RegisterGame(lpGDFBinaryPath
, lpGameInstallDirectory
,
714 installScope
, InstanceID
);
716 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath
);
717 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory
);
720 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
721 TRACE("returning 0x%x\n", hr
);
724 /*******************************************************************************
725 * GAMEUX_FindGameInstanceId
727 * Internal helper function. Description available in gameux_private.h file
729 HRESULT
GAMEUX_FindGameInstanceId(
730 LPCWSTR sGDFBinaryPath
,
731 GAME_INSTALL_SCOPE installScope
,
734 static const WCHAR sConfigGDFBinaryPath
[] =
735 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
739 LPWSTR lpRegistryPath
= NULL
;
741 DWORD dwSubKeys
, dwSubKeyLen
, dwMaxSubKeyLen
, i
;
742 LPWSTR lpName
= NULL
, lpValue
= NULL
;
744 hr
= GAMEUX_buildGameRegistryPath(installScope
, NULL
, &lpRegistryPath
);
747 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
748 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
749 lpRegistryPath
, 0, KEY_READ
| KEY_WOW64_64KEY
, &hRootKey
));
753 hr
= HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey
, NULL
, NULL
, NULL
,
754 &dwSubKeys
, &dwMaxSubKeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
));
758 ++dwMaxSubKeyLen
; /* for string terminator */
759 lpName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen
*sizeof(WCHAR
));
760 if(!lpName
) hr
= E_OUTOFMEMORY
;
765 for(i
=0; i
<dwSubKeys
&& !found
; ++i
)
767 dwSubKeyLen
= dwMaxSubKeyLen
;
768 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey
, i
, lpName
, &dwSubKeyLen
,
769 NULL
, NULL
, NULL
, NULL
));
772 hr
= GAMEUX_LoadRegistryString(hRootKey
, lpName
,
773 sConfigGDFBinaryPath
, &lpValue
);
777 if(lstrcmpW(lpValue
, sGDFBinaryPath
)==0)
779 /* key found, let's copy instance id and exit */
780 hr
= CLSIDFromString(lpName
, pInstanceId
);
783 HeapFree(GetProcessHeap(), 0, lpValue
);
788 HeapFree(GetProcessHeap(), 0, lpName
);
789 RegCloseKey(hRootKey
);
792 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
794 if((SUCCEEDED(hr
) && !found
) || hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
799 /*******************************************************************************
800 * GameExplorer implementation
803 typedef struct _GameExplorerImpl
805 IGameExplorer IGameExplorer_iface
;
806 IGameExplorer2 IGameExplorer2_iface
;
810 static inline GameExplorerImpl
*impl_from_IGameExplorer(IGameExplorer
*iface
)
812 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer_iface
);
815 static inline GameExplorerImpl
*impl_from_IGameExplorer2(IGameExplorer2
*iface
)
817 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer2_iface
);
820 static HRESULT WINAPI
GameExplorerImpl_QueryInterface(
821 IGameExplorer
*iface
,
825 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
827 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
831 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
832 IsEqualGUID(riid
, &IID_IGameExplorer
))
834 *ppvObject
= &This
->IGameExplorer_iface
;
836 else if(IsEqualGUID(riid
, &IID_IGameExplorer2
))
838 *ppvObject
= &This
->IGameExplorer2_iface
;
842 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
843 return E_NOINTERFACE
;
846 IGameExplorer_AddRef(iface
);
850 static ULONG WINAPI
GameExplorerImpl_AddRef(IGameExplorer
*iface
)
852 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
855 ref
= InterlockedIncrement(&This
->ref
);
857 TRACE("(%p): ref=%d\n", This
, ref
);
861 static ULONG WINAPI
GameExplorerImpl_Release(IGameExplorer
*iface
)
863 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
866 ref
= InterlockedDecrement(&This
->ref
);
867 TRACE("(%p): ref=%d\n", This
, ref
);
871 TRACE("freeing GameExplorer object\n");
872 HeapFree(GetProcessHeap(), 0, This
);
878 static HRESULT WINAPI
GameExplorerImpl_AddGame(
879 IGameExplorer
*iface
,
880 BSTR bstrGDFBinaryPath
,
881 BSTR sGameInstallDirectory
,
882 GAME_INSTALL_SCOPE installScope
,
885 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
886 TRACE("(%p, %s, %s, 0x%x, %s)\n", This
, debugstr_w(bstrGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
887 return GAMEUX_RegisterGame(bstrGDFBinaryPath
, sGameInstallDirectory
, installScope
, pInstanceID
);
890 static HRESULT WINAPI
GameExplorerImpl_RemoveGame(
891 IGameExplorer
*iface
,
894 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
896 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
897 return GAMEUX_RemoveRegistryRecord(&instanceID
);
900 static HRESULT WINAPI
GameExplorerImpl_UpdateGame(
901 IGameExplorer
*iface
,
904 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
906 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
907 return GAMEUX_UpdateGame(&instanceID
);
910 static HRESULT WINAPI
GameExplorerImpl_VerifyAccess(
911 IGameExplorer
*iface
,
915 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
917 FIXME("(%p, %s, %p)\n", This
, debugstr_w(sGDFBinaryPath
), pHasAccess
);
922 static const struct IGameExplorerVtbl GameExplorerImplVtbl
=
924 GameExplorerImpl_QueryInterface
,
925 GameExplorerImpl_AddRef
,
926 GameExplorerImpl_Release
,
927 GameExplorerImpl_AddGame
,
928 GameExplorerImpl_RemoveGame
,
929 GameExplorerImpl_UpdateGame
,
930 GameExplorerImpl_VerifyAccess
934 static HRESULT WINAPI
GameExplorer2Impl_QueryInterface(
935 IGameExplorer2
*iface
,
939 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
940 return GameExplorerImpl_QueryInterface(&This
->IGameExplorer_iface
, riid
, ppvObject
);
943 static ULONG WINAPI
GameExplorer2Impl_AddRef(IGameExplorer2
*iface
)
945 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
946 return GameExplorerImpl_AddRef(&This
->IGameExplorer_iface
);
949 static ULONG WINAPI
GameExplorer2Impl_Release(IGameExplorer2
*iface
)
951 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
952 return GameExplorerImpl_Release(&This
->IGameExplorer_iface
);
955 static HRESULT WINAPI
GameExplorer2Impl_CheckAccess(
956 IGameExplorer2
*iface
,
957 LPCWSTR binaryGDFPath
,
960 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
961 FIXME("stub (%p, %s, %p)\n", This
, debugstr_w(binaryGDFPath
), pHasAccess
);
965 static HRESULT WINAPI
GameExplorer2Impl_InstallGame(
966 IGameExplorer2
*iface
,
967 LPCWSTR binaryGDFPath
,
968 LPCWSTR installDirectory
,
969 GAME_INSTALL_SCOPE installScope
)
973 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
975 TRACE("(%p, %s, %s, 0x%x)\n", This
, debugstr_w(binaryGDFPath
), debugstr_w(installDirectory
), installScope
);
980 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
983 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
987 /* if game isn't yet registered, then install it */
988 instanceId
= GUID_NULL
;
989 hr
= GAMEUX_RegisterGame(binaryGDFPath
, installDirectory
, installScope
, &instanceId
);
992 /* otherwise, update game */
993 hr
= GAMEUX_UpdateGame(&instanceId
);
998 static HRESULT WINAPI
GameExplorer2Impl_UninstallGame(
999 IGameExplorer2
*iface
,
1000 LPCWSTR binaryGDFPath
)
1004 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
1005 TRACE("(%p, %s)\n", This
, debugstr_w(binaryGDFPath
));
1008 return E_INVALIDARG
;
1010 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
1013 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
1016 hr
= GAMEUX_RemoveRegistryRecord(&instanceId
);
1021 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl
=
1023 GameExplorer2Impl_QueryInterface
,
1024 GameExplorer2Impl_AddRef
,
1025 GameExplorer2Impl_Release
,
1026 GameExplorer2Impl_InstallGame
,
1027 GameExplorer2Impl_UninstallGame
,
1028 GameExplorer2Impl_CheckAccess
1032 * Construction routine
1034 HRESULT
GameExplorer_create(
1035 IUnknown
* pUnkOuter
,
1038 GameExplorerImpl
*pGameExplorer
;
1040 TRACE("(%p, %p)\n", pUnkOuter
, ppObj
);
1042 pGameExplorer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer
));
1045 return E_OUTOFMEMORY
;
1047 pGameExplorer
->IGameExplorer_iface
.lpVtbl
= &GameExplorerImplVtbl
;
1048 pGameExplorer
->IGameExplorer2_iface
.lpVtbl
= &GameExplorer2ImplVtbl
;
1049 pGameExplorer
->ref
= 1;
1051 *ppObj
= (IUnknown
*)&pGameExplorer
->IGameExplorer_iface
;
1053 TRACE("returning iface: %p\n", *ppObj
);