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 /* function from Shell32, not defined in header */
39 extern BOOL WINAPI
GUIDFromStringW(LPCWSTR psz
, LPGUID pguid
);
41 /*******************************************************************************
42 * GameUX helper functions
44 /*******************************************************************************
47 * Internal helper function.
48 * Initializes GAME_DATA structure fields with proper values. Should be
49 * called always before first usage of this structure. Implemented in gameexplorer.c
52 * GameData [I/O] pointer to structure to initialize
54 static void GAMEUX_initGameData(struct GAMEUX_GAME_DATA
*GameData
)
56 GameData
->sGDFBinaryPath
= NULL
;
57 GameData
->sGameInstallDirectory
= NULL
;
58 GameData
->bstrName
= NULL
;
59 GameData
->bstrDescription
= NULL
;
61 /*******************************************************************************
62 * GAMEUX_uninitGameData
64 * Internal helper function.
65 * Properly frees all data stored or pointed by fields of GAME_DATA structure.
66 * Should be called before freeing this structure. Implemented in gameexplorer.c
69 * GameData [I/O] pointer to structure to uninitialize
71 static void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA
*GameData
)
73 HeapFree(GetProcessHeap(), 0, GameData
->sGDFBinaryPath
);
74 HeapFree(GetProcessHeap(), 0, GameData
->sGameInstallDirectory
);
75 SysFreeString(GameData
->bstrName
);
76 SysFreeString(GameData
->bstrDescription
);
78 /*******************************************************************************
79 * GAMEUX_buildGameRegistryPath
81 * Internal helper function. Description available in gameux_private.h file
83 HRESULT
GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope
,
84 LPCGUID gameInstanceId
,
85 LPWSTR
* lpRegistryPath
)
87 static const WCHAR sGameUxRegistryPath
[] = {'S','O','F','T','W','A','R','E','\\',
88 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
89 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
90 static const WCHAR sGames
[] = {'G','a','m','e','s',0};
91 static const WCHAR sBackslash
[] = {'\\',0};
95 PTOKEN_USER pTokenUser
= NULL
;
98 WCHAR sInstanceId
[40];
99 WCHAR sRegistryPath
[8192];
101 TRACE("(0x%x, %s, %p)\n", installScope
, debugstr_guid(gameInstanceId
), lpRegistryPath
);
103 /* this will make freeing it easier for user */
104 *lpRegistryPath
= NULL
;
106 lstrcpyW(sRegistryPath
, sGameUxRegistryPath
);
107 lstrcatW(sRegistryPath
, sBackslash
);
109 if(installScope
== GIS_CURRENT_USER
)
111 /* build registry path containing user's SID */
112 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
113 hr
= HRESULT_FROM_WIN32(GetLastError());
117 if(!GetTokenInformation(hToken
, TokenUser
, NULL
, 0, &dwLength
) &&
118 GetLastError()!=ERROR_INSUFFICIENT_BUFFER
)
119 hr
= HRESULT_FROM_WIN32(GetLastError());
123 pTokenUser
= HeapAlloc(GetProcessHeap(), 0, dwLength
);
129 if(!GetTokenInformation(hToken
, TokenUser
, (LPVOID
)pTokenUser
, dwLength
, &dwLength
))
130 hr
= HRESULT_FROM_WIN32(GetLastError());
133 if(!ConvertSidToStringSidW(pTokenUser
->User
.Sid
, &lpSID
))
134 hr
= HRESULT_FROM_WIN32(GetLastError());
138 lstrcatW(sRegistryPath
, lpSID
);
142 HeapFree(GetProcessHeap(), 0, pTokenUser
);
146 else if(installScope
== GIS_ALL_USERS
)
147 /* build registry path without SID */
148 lstrcatW(sRegistryPath
, sGames
);
152 /* put game's instance id on the end of path, only if instance id was given */
156 hr
= (StringFromGUID2(gameInstanceId
, sInstanceId
, sizeof(sInstanceId
)/sizeof(sInstanceId
[0])) ? S_OK
: E_FAIL
);
160 lstrcatW(sRegistryPath
, sBackslash
);
161 lstrcatW(sRegistryPath
, sInstanceId
);
167 *lpRegistryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath
)+1)*sizeof(WCHAR
));
173 lstrcpyW(*lpRegistryPath
, sRegistryPath
);
175 TRACE("result: 0x%x, path: %s\n", hr
, debugstr_w(*lpRegistryPath
));
178 /*******************************************************************************
179 * GAMEUX_WriteRegistryRecord
181 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
182 * structure) into expected place in registry.
185 * GameData [I] structure with data which will
186 * be written into registry.
187 * Proper values of fields installScope
188 * and guidInstanceId are required
189 * to create registry key.
191 * Schema of naming registry keys associated with games is available in
192 * description of _buildGameRegistryPath internal function.
194 * List of registry keys associated with structure fields:
195 * Key Field in GAMEUX_GAME_DATA structure
196 * ApplicationId guidApplicationId
197 * ConfigApplicationPath sGameInstallDirectory
198 * ConfigGDFBinaryPath sGDFBinaryPath
202 static HRESULT
GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA
*GameData
)
204 static const WCHAR sApplicationId
[] =
205 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
206 static const WCHAR sConfigApplicationPath
[] =
207 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
208 static const WCHAR sConfigGDFBinaryPath
[] =
209 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
210 static const WCHAR sTitle
[] =
211 {'T','i','t','l','e',0};
212 static const WCHAR sDescription
[] =
213 {'D','e','s','c','r','i','p','t','i','o','n',0};
216 LPWSTR lpRegistryKey
;
218 WCHAR sGameApplicationId
[40];
220 TRACE("(%p)\n", GameData
);
222 hr
= GAMEUX_buildGameRegistryPath(GameData
->installScope
, &GameData
->guidInstanceId
, &lpRegistryKey
);
225 hr
= (StringFromGUID2(&GameData
->guidApplicationId
, sGameApplicationId
, sizeof(sGameApplicationId
)/sizeof(sGameApplicationId
[0])) ? S_OK
: E_FAIL
);
228 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
,
229 0, NULL
, 0, KEY_ALL_ACCESS
| KEY_WOW64_64KEY
, NULL
,
234 /* write game data to registry key */
235 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigApplicationPath
, 0,
236 REG_SZ
, (LPBYTE
)(GameData
->sGameInstallDirectory
),
237 (lstrlenW(GameData
->sGameInstallDirectory
)+1)*sizeof(WCHAR
)));
240 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigGDFBinaryPath
, 0,
241 REG_SZ
, (LPBYTE
)(GameData
->sGDFBinaryPath
),
242 (lstrlenW(GameData
->sGDFBinaryPath
)+1)*sizeof(WCHAR
)));
245 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sApplicationId
, 0,
246 REG_SZ
, (LPBYTE
)(sGameApplicationId
),
247 (lstrlenW(sGameApplicationId
)+1)*sizeof(WCHAR
)));
250 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sTitle
, 0,
251 REG_SZ
, (LPBYTE
)(GameData
->bstrName
),
252 (lstrlenW(GameData
->bstrName
)+1)*sizeof(WCHAR
)));
255 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sDescription
, 0,
256 REG_SZ
, (LPBYTE
)(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
),
257 (lstrlenW(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
)+1)*sizeof(WCHAR
)));
263 /* if something failed, remove whole key */
264 hr2
= RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
, KEY_WOW64_64KEY
, 0);
265 /* do not overwrite old failure code with new success code */
271 HeapFree(GetProcessHeap(), 0, lpRegistryKey
);
272 TRACE("returning 0x%x\n", hr
);
275 /*******************************************************************************
276 * GAMEUX_ProcessGameDefinitionElement
278 * Helper function, parses single element from Game Definition
281 * lpXMLElement [I] game definition element
282 * GameData [O] structure, where parsed
283 * data will be stored
285 static HRESULT
GAMEUX_ProcessGameDefinitionElement(
286 IXMLDOMElement
*element
,
287 struct GAMEUX_GAME_DATA
*GameData
)
289 static const WCHAR sName
[] =
291 static const WCHAR sDescription
[] =
292 {'D','e','s','c','r','i','p','t','i','o','n',0};
295 BSTR bstrElementName
;
297 TRACE("(%p, %p)\n", element
, GameData
);
299 hr
= IXMLDOMElement_get_nodeName(element
, &bstrElementName
);
302 /* check element name */
303 if(lstrcmpW(bstrElementName
, sName
) == 0)
304 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrName
);
306 else if(lstrcmpW(bstrElementName
, sDescription
) == 0)
307 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrDescription
);
310 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName
));
312 SysFreeString(bstrElementName
);
317 /*******************************************************************************
318 * GAMEUX_ParseGameDefinition
320 * Helper function, loads data from given XML element into fields of GAME_DATA
324 * lpXMLGameDefinitionElement [I] Game Definition XML element
325 * GameData [O] structure where data loaded from
326 * XML element will be stored in
328 static HRESULT
GAMEUX_ParseGameDefinition(
329 IXMLDOMElement
*gdElement
,
330 struct GAMEUX_GAME_DATA
*GameData
)
332 static const WCHAR sGameId
[] = {'g','a','m','e','I','D',0};
337 IXMLDOMNodeList
*childrenList
;
338 IXMLDOMNode
*nextNode
;
339 IXMLDOMElement
*nextElement
;
341 TRACE("(%p, %p)\n", gdElement
, GameData
);
343 bstrAttribute
= SysAllocString(sGameId
);
347 hr
= IXMLDOMElement_getAttribute(gdElement
, bstrAttribute
, &variant
);
351 hr
= ( GUIDFromStringW(V_BSTR(&variant
), &GameData
->guidApplicationId
)==TRUE
? S_OK
: E_FAIL
);
353 SysFreeString(V_BSTR(&variant
));
356 SysFreeString(bstrAttribute
);
358 /* browse subnodes */
360 hr
= IXMLDOMElement_get_childNodes(gdElement
, &childrenList
);
366 hr
= IXMLDOMNodeList_nextNode(childrenList
, &nextNode
);
370 hr
= IXMLDOMNode_QueryInterface(nextNode
, &IID_IXMLDOMElement
,
371 (LPVOID
*)&nextElement
);
375 hr
= GAMEUX_ProcessGameDefinitionElement(nextElement
, GameData
);
376 IXMLDOMElement_Release(nextElement
);
379 IXMLDOMElement_Release(nextNode
);
385 IXMLDOMNodeList_Release(childrenList
);
390 /*******************************************************************************
391 * GAMEUX_ParseGDFBinary
393 * Helper function, loads given binary and parses embed GDF if there's any.
396 * GameData [I/O] Structure with game's data. Content of field
397 * sGDFBinaryPath defines path to binary, from
398 * which embed GDF will be loaded. Data from
399 * GDF will be stored in other fields of this
402 static HRESULT
GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA
*GameData
)
404 static const WCHAR sRes
[] = {'r','e','s',':','/','/',0};
405 static const WCHAR sDATA
[] = {'D','A','T','A',0};
406 static const WCHAR sSlash
[] = {'/',0};
409 WCHAR sResourcePath
[MAX_PATH
];
411 VARIANT_BOOL isSuccessful
;
412 IXMLDOMDocument
*document
;
414 IXMLDOMElement
*root
, *gdElement
;
416 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData
, debugstr_w(GameData
->sGDFBinaryPath
));
418 /* prepare path to GDF, using res:// prefix */
419 lstrcpyW(sResourcePath
, sRes
);
420 lstrcatW(sResourcePath
, GameData
->sGDFBinaryPath
);
421 lstrcatW(sResourcePath
, sSlash
);
422 lstrcatW(sResourcePath
, sDATA
);
423 lstrcatW(sResourcePath
, sSlash
);
424 lstrcatW(sResourcePath
, ID_GDF_XML_STR
);
426 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
427 &IID_IXMLDOMDocument
, (void**)&document
);
431 /* load GDF into MSXML */
432 V_VT(&variant
) = VT_BSTR
;
433 V_BSTR(&variant
) = SysAllocString(sResourcePath
);
434 if(!V_BSTR(&variant
))
439 hr
= IXMLDOMDocument_load(document
, variant
, &isSuccessful
);
440 if(hr
== S_FALSE
|| isSuccessful
== VARIANT_FALSE
)
444 SysFreeString(V_BSTR(&variant
));
448 hr
= IXMLDOMDocument_get_documentElement(document
, &root
);
455 hr
= IXMLDOMElement_get_firstChild(root
, &gdNode
);
461 hr
= IXMLDOMNode_QueryInterface(gdNode
, &IID_IXMLDOMElement
, (LPVOID
*)&gdElement
);
464 hr
= GAMEUX_ParseGameDefinition(gdElement
, GameData
);
465 IXMLDOMElement_Release(gdElement
);
468 IXMLDOMNode_Release(gdNode
);
471 IXMLDOMElement_Release(root
);
474 IXMLDOMDocument_Release(document
);
479 /*******************************************************************
480 * GAMEUX_RemoveRegistryRecord
482 * Helper function, removes registry key associated with given game instance
484 static HRESULT
GAMEUX_RemoveRegistryRecord(GUID
* pInstanceID
)
487 LPWSTR lpRegistryPath
= NULL
;
488 TRACE("(%s)\n", debugstr_guid(pInstanceID
));
490 /* first, check is game installed for all users */
491 hr
= GAMEUX_buildGameRegistryPath(GIS_ALL_USERS
, pInstanceID
, &lpRegistryPath
);
493 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
495 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
497 /* if not, check current user */
500 hr
= GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER
, pInstanceID
, &lpRegistryPath
);
502 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
504 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
509 /*******************************************************************************
510 * GAMEUX_RegisterGame
512 * Internal helper function. Registers game associated with given GDF binary in
513 * Game Explorer. Implemented in gameexplorer.c
516 * sGDFBinaryPath [I] path to binary containing GDF file in
518 * sGameInstallDirectory [I] path to directory, where game installed
520 * installScope [I] scope of game installation
521 * pInstanceID [I/O] pointer to game instance identifier.
522 * If pointing to GUID_NULL, then new
523 * identifier will be generated automatically
524 * and returned via this parameter
526 static HRESULT
GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath
,
527 LPCWSTR sGameInstallDirectory
,
528 GAME_INSTALL_SCOPE installScope
,
532 struct GAMEUX_GAME_DATA GameData
;
534 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
536 GAMEUX_initGameData(&GameData
);
537 GameData
.sGDFBinaryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath
)+1)*sizeof(WCHAR
));
538 lstrcpyW(GameData
.sGDFBinaryPath
, sGDFBinaryPath
);
539 GameData
.sGameInstallDirectory
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory
)+1)*sizeof(WCHAR
));
540 lstrcpyW(GameData
.sGameInstallDirectory
, sGameInstallDirectory
);
541 GameData
.installScope
= installScope
;
543 /* generate GUID if it was not provided by user */
544 if(IsEqualGUID(pInstanceID
, &GUID_NULL
))
545 hr
= CoCreateGuid(pInstanceID
);
547 GameData
.guidInstanceId
= *pInstanceID
;
549 /* load data from GDF binary */
551 hr
= GAMEUX_ParseGDFBinary(&GameData
);
553 /* save data to registry */
555 hr
= GAMEUX_WriteRegistryRecord(&GameData
);
557 GAMEUX_uninitGameData(&GameData
);
558 TRACE("returning 0x%08x\n", hr
);
561 /*******************************************************************************
562 * GAMEUX_IsGameKeyExist
564 * Helper function, checks if game's registry ath exists in given scope
567 * installScope [I] scope to search game in
568 * InstanceID [I] game instance identifier
569 * lpRegistryPath [O] place to store address of registry path to
570 * the game. It is filled only if key exists.
571 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
574 * S_OK key was found properly
575 * S_FALSE key does not exists
578 static HRESULT
GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope
,
580 LPWSTR
* lpRegistryPath
) {
585 hr
= GAMEUX_buildGameRegistryPath(installScope
, InstanceID
, lpRegistryPath
);
588 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, *lpRegistryPath
,
589 0, KEY_WOW64_64KEY
, &hKey
));
591 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
598 /* if the key does not exist or another error occurred, do not return the path */
599 HeapFree(GetProcessHeap(), 0, *lpRegistryPath
);
600 *lpRegistryPath
= NULL
;
605 /*******************************************************************************
606 * GAMEUX_LoadRegistryString
608 * Helper function, loads string from registry value and allocates buffer for it
610 static HRESULT
GAMEUX_LoadRegistryString(HKEY hRootKey
,
611 LPCWSTR lpRegistryKey
,
612 LPCWSTR lpRegistryValue
,
620 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
621 RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
625 *lpValue
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
631 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
632 RRF_RT_REG_SZ
, NULL
, *lpValue
, &dwSize
));
636 /*******************************************************************************
639 * Helper function, updates stored data about game with given InstanceID
641 static HRESULT
GAMEUX_UpdateGame(LPGUID InstanceID
) {
642 static const WCHAR sConfigGDFBinaryPath
[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
643 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};
646 GAME_INSTALL_SCOPE installScope
;
647 LPWSTR lpRegistryPath
;
648 LPWSTR lpGDFBinaryPath
, lpGameInstallDirectory
;
650 TRACE("(%p)\n", debugstr_guid(InstanceID
));
652 /* first, check is game exists in CURRENT_USER scope */
653 installScope
= GIS_CURRENT_USER
;
654 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
658 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
659 installScope
= GIS_ALL_USERS
;
660 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
664 /* still not found? let's inform user that game does not exists */
665 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
669 /* game found, it's registry path is in lpRegistryPath and install
670 * scope in installScope */
671 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath
));
673 /* first, read required data about game */
674 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
675 sConfigGDFBinaryPath
, &lpGDFBinaryPath
);
678 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
679 sConfigApplicationPath
, &lpGameInstallDirectory
);
681 /* now remove currently existing registry key */
683 hr
= GAMEUX_RemoveRegistryRecord(InstanceID
);
685 /* and add it again, it will cause in reparsing of whole GDF */
687 hr
= GAMEUX_RegisterGame(lpGDFBinaryPath
, lpGameInstallDirectory
,
688 installScope
, InstanceID
);
690 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath
);
691 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory
);
694 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
695 TRACE("returning 0x%x\n", hr
);
698 /*******************************************************************************
699 * GAMEUX_FindGameInstanceId
701 * Internal helper function. Description available in gameux_private.h file
703 HRESULT
GAMEUX_FindGameInstanceId(
704 LPCWSTR sGDFBinaryPath
,
705 GAME_INSTALL_SCOPE installScope
,
708 static const WCHAR sConfigGDFBinaryPath
[] =
709 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
713 LPWSTR lpRegistryPath
= NULL
;
715 DWORD dwSubKeys
, dwSubKeyLen
, dwMaxSubKeyLen
, i
;
716 LPWSTR lpName
= NULL
, lpValue
= NULL
;
718 hr
= GAMEUX_buildGameRegistryPath(installScope
, NULL
, &lpRegistryPath
);
721 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
722 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
723 lpRegistryPath
, 0, KEY_READ
| KEY_WOW64_64KEY
, &hRootKey
));
727 hr
= HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey
, NULL
, NULL
, NULL
,
728 &dwSubKeys
, &dwMaxSubKeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
));
732 ++dwMaxSubKeyLen
; /* for string terminator */
733 lpName
= CoTaskMemAlloc(dwMaxSubKeyLen
*sizeof(WCHAR
));
734 if(!lpName
) hr
= E_OUTOFMEMORY
;
739 for(i
=0; i
<dwSubKeys
&& !found
; ++i
)
741 dwSubKeyLen
= dwMaxSubKeyLen
;
742 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey
, i
, lpName
, &dwSubKeyLen
,
743 NULL
, NULL
, NULL
, NULL
));
746 hr
= GAMEUX_LoadRegistryString(hRootKey
, lpName
,
747 sConfigGDFBinaryPath
, &lpValue
);
750 if(lstrcmpW(lpValue
, sGDFBinaryPath
)==0)
752 /* key found, let's copy instance id and exit */
753 hr
= (GUIDFromStringW(lpName
, pInstanceId
) ? S_OK
: E_FAIL
);
756 HeapFree(GetProcessHeap(), 0, lpValue
);
760 HeapFree(GetProcessHeap(), 0, lpName
);
761 RegCloseKey(hRootKey
);
764 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
766 if((SUCCEEDED(hr
) && !found
) || hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
771 /*******************************************************************************
772 * GameExplorer implementation
775 typedef struct _GameExplorerImpl
777 IGameExplorer IGameExplorer_iface
;
778 IGameExplorer2 IGameExplorer2_iface
;
782 static inline GameExplorerImpl
*impl_from_IGameExplorer(IGameExplorer
*iface
)
784 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer_iface
);
787 static inline GameExplorerImpl
*impl_from_IGameExplorer2(IGameExplorer2
*iface
)
789 return CONTAINING_RECORD(iface
, GameExplorerImpl
, IGameExplorer2_iface
);
792 static HRESULT WINAPI
GameExplorerImpl_QueryInterface(
793 IGameExplorer
*iface
,
797 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
799 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
803 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
804 IsEqualGUID(riid
, &IID_IGameExplorer
))
806 *ppvObject
= &This
->IGameExplorer_iface
;
808 else if(IsEqualGUID(riid
, &IID_IGameExplorer2
))
810 *ppvObject
= &This
->IGameExplorer2_iface
;
814 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
815 return E_NOINTERFACE
;
818 IGameExplorer_AddRef(iface
);
822 static ULONG WINAPI
GameExplorerImpl_AddRef(IGameExplorer
*iface
)
824 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
827 ref
= InterlockedIncrement(&This
->ref
);
829 TRACE("(%p): ref=%d\n", This
, ref
);
833 static ULONG WINAPI
GameExplorerImpl_Release(IGameExplorer
*iface
)
835 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
838 ref
= InterlockedDecrement(&This
->ref
);
839 TRACE("(%p): ref=%d\n", This
, ref
);
843 TRACE("freeing GameExplorer object\n");
844 HeapFree(GetProcessHeap(), 0, This
);
850 static HRESULT WINAPI
GameExplorerImpl_AddGame(
851 IGameExplorer
*iface
,
852 BSTR bstrGDFBinaryPath
,
853 BSTR sGameInstallDirectory
,
854 GAME_INSTALL_SCOPE installScope
,
857 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
858 TRACE("(%p, %s, %s, 0x%x, %s)\n", This
, debugstr_w(bstrGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
859 return GAMEUX_RegisterGame(bstrGDFBinaryPath
, sGameInstallDirectory
, installScope
, pInstanceID
);
862 static HRESULT WINAPI
GameExplorerImpl_RemoveGame(
863 IGameExplorer
*iface
,
866 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
868 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
869 return GAMEUX_RemoveRegistryRecord(&instanceID
);
872 static HRESULT WINAPI
GameExplorerImpl_UpdateGame(
873 IGameExplorer
*iface
,
876 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
878 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
879 return GAMEUX_UpdateGame(&instanceID
);
882 static HRESULT WINAPI
GameExplorerImpl_VerifyAccess(
883 IGameExplorer
*iface
,
887 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
889 FIXME("(%p, %s, %p)\n", This
, debugstr_w(sGDFBinaryPath
), pHasAccess
);
894 static const struct IGameExplorerVtbl GameExplorerImplVtbl
=
896 GameExplorerImpl_QueryInterface
,
897 GameExplorerImpl_AddRef
,
898 GameExplorerImpl_Release
,
899 GameExplorerImpl_AddGame
,
900 GameExplorerImpl_RemoveGame
,
901 GameExplorerImpl_UpdateGame
,
902 GameExplorerImpl_VerifyAccess
906 static HRESULT WINAPI
GameExplorer2Impl_QueryInterface(
907 IGameExplorer2
*iface
,
911 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
912 return GameExplorerImpl_QueryInterface(&This
->IGameExplorer_iface
, riid
, ppvObject
);
915 static ULONG WINAPI
GameExplorer2Impl_AddRef(IGameExplorer2
*iface
)
917 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
918 return GameExplorerImpl_AddRef(&This
->IGameExplorer_iface
);
921 static ULONG WINAPI
GameExplorer2Impl_Release(IGameExplorer2
*iface
)
923 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
924 return GameExplorerImpl_Release(&This
->IGameExplorer_iface
);
927 static HRESULT WINAPI
GameExplorer2Impl_CheckAccess(
928 IGameExplorer2
*iface
,
929 LPCWSTR binaryGDFPath
,
932 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
933 FIXME("stub (%p, %s, %p)\n", This
, debugstr_w(binaryGDFPath
), pHasAccess
);
937 static HRESULT WINAPI
GameExplorer2Impl_InstallGame(
938 IGameExplorer2
*iface
,
939 LPCWSTR binaryGDFPath
,
940 LPCWSTR installDirectory
,
941 GAME_INSTALL_SCOPE installScope
)
945 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
947 TRACE("(%p, %s, %s, 0x%x)\n", This
, debugstr_w(binaryGDFPath
), debugstr_w(installDirectory
), installScope
);
952 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
955 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
959 /* if game isn't yet registered, then install it */
960 instanceId
= GUID_NULL
;
961 hr
= GAMEUX_RegisterGame(binaryGDFPath
, installDirectory
, installScope
, &instanceId
);
964 /* otherwise, update game */
965 hr
= GAMEUX_UpdateGame(&instanceId
);
970 static HRESULT WINAPI
GameExplorer2Impl_UninstallGame(
971 IGameExplorer2
*iface
,
972 LPCWSTR binaryGDFPath
)
976 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
977 TRACE("(%p, %s)\n", This
, debugstr_w(binaryGDFPath
));
982 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
985 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
988 hr
= GAMEUX_RemoveRegistryRecord(&instanceId
);
993 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl
=
995 GameExplorer2Impl_QueryInterface
,
996 GameExplorer2Impl_AddRef
,
997 GameExplorer2Impl_Release
,
998 GameExplorer2Impl_InstallGame
,
999 GameExplorer2Impl_UninstallGame
,
1000 GameExplorer2Impl_CheckAccess
1004 * Construction routine
1006 HRESULT
GameExplorer_create(
1007 IUnknown
* pUnkOuter
,
1010 GameExplorerImpl
*pGameExplorer
;
1012 TRACE("(%p, %p)\n", pUnkOuter
, ppObj
);
1014 pGameExplorer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer
));
1017 return E_OUTOFMEMORY
;
1019 pGameExplorer
->IGameExplorer_iface
.lpVtbl
= &GameExplorerImplVtbl
;
1020 pGameExplorer
->IGameExplorer2_iface
.lpVtbl
= &GameExplorer2ImplVtbl
;
1021 pGameExplorer
->ref
= 1;
1023 *ppObj
= (IUnknown
*)&pGameExplorer
->IGameExplorer_iface
;
1025 TRACE("returning iface: %p\n", *ppObj
);