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