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. Description available in gameux_private.h file
49 void GAMEUX_initGameData(struct GAMEUX_GAME_DATA
*GameData
)
51 GameData
->sGDFBinaryPath
= NULL
;
52 GameData
->sGameInstallDirectory
= NULL
;
53 GameData
->bstrName
= NULL
;
54 GameData
->bstrDescription
= NULL
;
56 /*******************************************************************************
57 * GAMEUX_uninitGameData
59 * Internal helper function. Description available in gameux_private.h file
61 void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA
*GameData
)
63 HeapFree(GetProcessHeap(), 0, GameData
->sGDFBinaryPath
);
64 HeapFree(GetProcessHeap(), 0, GameData
->sGameInstallDirectory
);
65 SysFreeString(GameData
->bstrName
);
66 SysFreeString(GameData
->bstrDescription
);
68 /*******************************************************************************
69 * GAMEUX_buildGameRegistryPath
71 * Internal helper function. Description available in gameux_private.h file
73 HRESULT
GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope
,
74 LPCGUID gameInstanceId
,
75 LPWSTR
* lpRegistryPath
)
77 static const WCHAR sGameUxRegistryPath
[] = {'S','O','F','T','W','A','R','E','\\',
78 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
79 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
80 static const WCHAR sGames
[] = {'G','a','m','e','s',0};
81 static const WCHAR sBackslash
[] = {'\\',0};
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
, sGameUxRegistryPath
);
97 lstrcatW(sRegistryPath
, sBackslash
);
99 if(installScope
== GIS_CURRENT_USER
)
101 /* build registry path containing user's SID */
102 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
103 hr
= HRESULT_FROM_WIN32(GetLastError());
107 if(!GetTokenInformation(hToken
, TokenUser
, NULL
, 0, &dwLength
) &&
108 GetLastError()!=ERROR_INSUFFICIENT_BUFFER
)
109 hr
= HRESULT_FROM_WIN32(GetLastError());
113 pTokenUser
= HeapAlloc(GetProcessHeap(), 0, dwLength
);
119 if(!GetTokenInformation(hToken
, TokenUser
, (LPVOID
)pTokenUser
, dwLength
, &dwLength
))
120 hr
= HRESULT_FROM_WIN32(GetLastError());
123 if(!ConvertSidToStringSidW(pTokenUser
->User
.Sid
, &lpSID
))
124 hr
= HRESULT_FROM_WIN32(GetLastError());
128 lstrcatW(sRegistryPath
, lpSID
);
132 HeapFree(GetProcessHeap(), 0, pTokenUser
);
136 else if(installScope
== GIS_ALL_USERS
)
137 /* build registry path without SID */
138 lstrcatW(sRegistryPath
, sGames
);
142 /* put game's instance id on the end of path, only if instance id was given */
146 hr
= (StringFromGUID2(gameInstanceId
, sInstanceId
, sizeof(sInstanceId
)/sizeof(sInstanceId
[0])) ? S_OK
: E_FAIL
);
150 lstrcatW(sRegistryPath
, sBackslash
);
151 lstrcatW(sRegistryPath
, sInstanceId
);
157 *lpRegistryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath
)+1)*sizeof(WCHAR
));
163 lstrcpyW(*lpRegistryPath
, sRegistryPath
);
165 TRACE("result: 0x%x, path: %s\n", hr
, debugstr_w(*lpRegistryPath
));
168 /*******************************************************************************
169 * GAMEUX_WriteRegistryRecord
171 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
172 * structure) into expected place in registry.
175 * GameData [I] structure with data which will
176 * be written into registry.
177 * Proper values of fields installScope
178 * and guidInstanceId are required
179 * to create registry key.
181 * Schema of naming registry keys associated with games is available in
182 * description of _buildGameRegistryPath internal function.
184 * List of registry keys associated with structure fields:
185 * Key Field in GAMEUX_GAME_DATA structure
186 * ApplicationId guidApplicationId
187 * ConfigApplicationPath sGameInstallDirectory
188 * ConfigGDFBinaryPath sGDFBinaryPath
192 static HRESULT
GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA
*GameData
)
194 static const WCHAR sApplicationId
[] =
195 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
196 static const WCHAR sConfigApplicationPath
[] =
197 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
198 static const WCHAR sConfigGDFBinaryPath
[] =
199 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
200 static const WCHAR sTitle
[] =
201 {'T','i','t','l','e',0};
202 static const WCHAR sDescription
[] =
203 {'D','e','s','c','r','i','p','t','i','o','n',0};
206 LPWSTR lpRegistryKey
;
208 WCHAR sGameApplicationId
[40];
210 TRACE("(%p)\n", GameData
);
212 hr
= GAMEUX_buildGameRegistryPath(GameData
->installScope
, &GameData
->guidInstanceId
, &lpRegistryKey
);
215 hr
= (StringFromGUID2(&GameData
->guidApplicationId
, sGameApplicationId
, sizeof(sGameApplicationId
)/sizeof(sGameApplicationId
[0])) ? S_OK
: E_FAIL
);
218 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
,
219 0, NULL
, 0, KEY_ALL_ACCESS
| KEY_WOW64_64KEY
, NULL
,
224 /* write game data to registry key */
225 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigApplicationPath
, 0,
226 REG_SZ
, (LPBYTE
)(GameData
->sGameInstallDirectory
),
227 (lstrlenW(GameData
->sGameInstallDirectory
)+1)*sizeof(WCHAR
)));
230 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigGDFBinaryPath
, 0,
231 REG_SZ
, (LPBYTE
)(GameData
->sGDFBinaryPath
),
232 (lstrlenW(GameData
->sGDFBinaryPath
)+1)*sizeof(WCHAR
)));
235 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sApplicationId
, 0,
236 REG_SZ
, (LPBYTE
)(sGameApplicationId
),
237 (lstrlenW(sGameApplicationId
)+1)*sizeof(WCHAR
)));
240 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sTitle
, 0,
241 REG_SZ
, (LPBYTE
)(GameData
->bstrName
),
242 (lstrlenW(GameData
->bstrName
)+1)*sizeof(WCHAR
)));
245 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sDescription
, 0,
246 REG_SZ
, (LPBYTE
)(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
),
247 (lstrlenW(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
)+1)*sizeof(WCHAR
)));
253 /* if something failed, remove whole key */
254 hr2
= RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
, KEY_WOW64_64KEY
, 0);
255 /* do not overwrite old failure code with new success code */
261 HeapFree(GetProcessHeap(), 0, lpRegistryKey
);
262 TRACE("returning 0x%x\n", hr
);
265 /*******************************************************************************
266 * GAMEUX_ProcessGameDefinitionElement
268 * Helper function, parses single element from Game Definition
271 * lpXMLElement [I] game definition element
272 * GameData [O] structure, where parsed
273 * data will be stored
275 static HRESULT
GAMEUX_ProcessGameDefinitionElement(
276 IXMLDOMElement
*element
,
277 struct GAMEUX_GAME_DATA
*GameData
)
279 static const WCHAR sName
[] =
281 static const WCHAR sDescription
[] =
282 {'D','e','s','c','r','i','p','t','i','o','n',0};
285 BSTR bstrElementName
;
287 TRACE("(%p, %p)\n", element
, GameData
);
289 hr
= IXMLDOMElement_get_nodeName(element
, &bstrElementName
);
292 /* check element name */
293 if(lstrcmpW(bstrElementName
, sName
) == 0)
294 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrName
);
296 else if(lstrcmpW(bstrElementName
, sDescription
) == 0)
297 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrDescription
);
300 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName
));
302 SysFreeString(bstrElementName
);
307 /*******************************************************************************
308 * GAMEUX_ParseGameDefinition
310 * Helper function, loads data from given XML element into fields of GAME_DATA
314 * lpXMLGameDefinitionElement [I] Game Definition XML element
315 * GameData [O] structure where data loaded from
316 * XML element will be stored in
318 static HRESULT
GAMEUX_ParseGameDefinition(
319 IXMLDOMElement
*gdElement
,
320 struct GAMEUX_GAME_DATA
*GameData
)
322 static const WCHAR sGameId
[] = {'g','a','m','e','I','D',0};
327 IXMLDOMNodeList
*childrenList
;
328 IXMLDOMNode
*nextNode
;
329 IXMLDOMElement
*nextElement
;
331 TRACE("(%p, %p)\n", gdElement
, GameData
);
333 bstrAttribute
= SysAllocString(sGameId
);
337 hr
= IXMLDOMElement_getAttribute(gdElement
, bstrAttribute
, &variant
);
341 hr
= ( GUIDFromStringW(V_BSTR(&variant
), &GameData
->guidApplicationId
)==TRUE
? S_OK
: E_FAIL
);
343 SysFreeString(V_BSTR(&variant
));
346 SysFreeString(bstrAttribute
);
348 /* browse subnodes */
350 hr
= IXMLDOMElement_get_childNodes(gdElement
, &childrenList
);
356 hr
= IXMLDOMNodeList_nextNode(childrenList
, &nextNode
);
360 hr
= IXMLDOMNode_QueryInterface(nextNode
, &IID_IXMLDOMElement
,
361 (LPVOID
*)&nextElement
);
365 hr
= GAMEUX_ProcessGameDefinitionElement(nextElement
, GameData
);
366 IXMLDOMElement_Release(nextElement
);
369 IXMLDOMElement_Release(nextNode
);
375 IXMLDOMNodeList_Release(childrenList
);
380 /*******************************************************************************
381 * GAMEUX_ParseGDFBinary
383 * Helper function, loads given binary and parses embed GDF if there's any.
386 * GameData [I/O] Structure with game's data. Content of field
387 * sGDFBinaryPath defines path to binary, from
388 * which embed GDF will be loaded. Data from
389 * GDF will be stored in other fields of this
392 static HRESULT
GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA
*GameData
)
394 static const WCHAR sRes
[] = {'r','e','s',':','/','/',0};
395 static const WCHAR sDATA
[] = {'D','A','T','A',0};
396 static const WCHAR sSlash
[] = {'/',0};
399 WCHAR sResourcePath
[MAX_PATH
];
401 VARIANT_BOOL isSuccessful
;
402 IXMLDOMDocument
*document
;
404 IXMLDOMElement
*root
, *gdElement
;
406 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData
, debugstr_w(GameData
->sGDFBinaryPath
));
408 /* prepare path to GDF, using res:// prefix */
409 lstrcpyW(sResourcePath
, sRes
);
410 lstrcatW(sResourcePath
, GameData
->sGDFBinaryPath
);
411 lstrcatW(sResourcePath
, sSlash
);
412 lstrcatW(sResourcePath
, sDATA
);
413 lstrcatW(sResourcePath
, sSlash
);
414 lstrcatW(sResourcePath
, ID_GDF_XML_STR
);
416 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
417 &IID_IXMLDOMDocument
, (void**)&document
);
421 /* load GDF into MSXML */
422 V_VT(&variant
) = VT_BSTR
;
423 V_BSTR(&variant
) = SysAllocString(sResourcePath
);
424 if(!V_BSTR(&variant
))
429 hr
= IXMLDOMDocument_load(document
, variant
, &isSuccessful
);
430 if(hr
== S_FALSE
|| isSuccessful
== VARIANT_FALSE
)
434 SysFreeString(V_BSTR(&variant
));
438 hr
= IXMLDOMDocument_get_documentElement(document
, &root
);
445 hr
= IXMLDOMElement_get_firstChild(root
, &gdNode
);
451 hr
= IXMLDOMNode_QueryInterface(gdNode
, &IID_IXMLDOMElement
, (LPVOID
*)&gdElement
);
454 hr
= GAMEUX_ParseGameDefinition(gdElement
, GameData
);
455 IXMLDOMElement_Release(gdElement
);
458 IXMLDOMNode_Release(gdNode
);
461 IXMLDOMElement_Release(root
);
464 IXMLDOMDocument_Release(document
);
469 /*******************************************************************
470 * GAMEUX_RemoveRegistryRecord
472 * Helper function, removes registry key associated with given game instance
474 static HRESULT
GAMEUX_RemoveRegistryRecord(GUID
* pInstanceID
)
477 LPWSTR lpRegistryPath
= NULL
;
478 TRACE("(%s)\n", debugstr_guid(pInstanceID
));
480 /* first, check is game installed for all users */
481 hr
= GAMEUX_buildGameRegistryPath(GIS_ALL_USERS
, pInstanceID
, &lpRegistryPath
);
483 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
485 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
487 /* if not, check current user */
490 hr
= GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER
, pInstanceID
, &lpRegistryPath
);
492 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, KEY_WOW64_64KEY
, 0));
494 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
499 /*******************************************************************************
500 * GAMEUX_RegisterGame
502 * Internal helper function. Description available in gameux_private.h file
504 HRESULT WINAPI
GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath
,
505 LPCWSTR sGameInstallDirectory
,
506 GAME_INSTALL_SCOPE installScope
,
510 struct GAMEUX_GAME_DATA GameData
;
512 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
514 GAMEUX_initGameData(&GameData
);
515 GameData
.sGDFBinaryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath
)+1)*sizeof(WCHAR
));
516 lstrcpyW(GameData
.sGDFBinaryPath
, sGDFBinaryPath
);
517 GameData
.sGameInstallDirectory
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory
)+1)*sizeof(WCHAR
));
518 lstrcpyW(GameData
.sGameInstallDirectory
, sGameInstallDirectory
);
519 GameData
.installScope
= installScope
;
521 /* generate GUID if it was not provided by user */
522 if(IsEqualGUID(pInstanceID
, &GUID_NULL
))
523 hr
= CoCreateGuid(pInstanceID
);
525 GameData
.guidInstanceId
= *pInstanceID
;
527 /* load data from GDF binary */
529 hr
= GAMEUX_ParseGDFBinary(&GameData
);
531 /* save data to registry */
533 hr
= GAMEUX_WriteRegistryRecord(&GameData
);
535 GAMEUX_uninitGameData(&GameData
);
536 TRACE("returning 0x%08x\n", hr
);
539 /*******************************************************************************
540 * GAMEUX_IsGameKeyExist
542 * Helper function, checks if game's registry ath exists in given scope
545 * installScope [I] scope to search game in
546 * InstanceID [I] game instance identifier
547 * lpRegistryPath [O] place to store address of registry path to
548 * the game. It is filled only if key exists.
549 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
552 * S_OK key was found properly
553 * S_FALSE key does not exists
556 static HRESULT
GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope
,
558 LPWSTR
* lpRegistryPath
) {
563 hr
= GAMEUX_buildGameRegistryPath(installScope
, InstanceID
, lpRegistryPath
);
566 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, *lpRegistryPath
,
567 0, KEY_WOW64_64KEY
, &hKey
));
569 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
576 /* if the key does not exist or another error occurred, do not return the path */
577 HeapFree(GetProcessHeap(), 0, *lpRegistryPath
);
578 *lpRegistryPath
= NULL
;
583 /*******************************************************************************
584 * GAMEUX_LoadRegistryString
586 * Helper function, loads string from registry value and allocates buffer for it
588 static HRESULT
GAMEUX_LoadRegistryString(HKEY hRootKey
,
589 LPCWSTR lpRegistryKey
,
590 LPCWSTR lpRegistryValue
,
598 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
599 RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
603 *lpValue
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
609 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
610 RRF_RT_REG_SZ
, NULL
, *lpValue
, &dwSize
));
614 /*******************************************************************************
617 * Helper function, updates stored data about game with given InstanceID
619 static HRESULT
GAMEUX_UpdateGame(LPGUID InstanceID
) {
620 static const WCHAR sConfigGDFBinaryPath
[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
621 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};
624 GAME_INSTALL_SCOPE installScope
;
625 LPWSTR lpRegistryPath
;
626 LPWSTR lpGDFBinaryPath
, lpGameInstallDirectory
;
628 TRACE("(%p)\n", debugstr_guid(InstanceID
));
630 /* first, check is game exists in CURRENT_USER scope */
631 installScope
= GIS_CURRENT_USER
;
632 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
636 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
637 installScope
= GIS_ALL_USERS
;
638 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
642 /* still not found? let's inform user that game does not exists */
643 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
647 /* game found, it's registry path is in lpRegistryPath and install
648 * scope in installScope */
649 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath
));
651 /* first, read required data about game */
652 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
653 sConfigGDFBinaryPath
, &lpGDFBinaryPath
);
656 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
657 sConfigApplicationPath
, &lpGameInstallDirectory
);
659 /* now remove currently existing registry key */
661 hr
= GAMEUX_RemoveRegistryRecord(InstanceID
);
663 /* and add it again, it will cause in reparsing of whole GDF */
665 hr
= GAMEUX_RegisterGame(lpGDFBinaryPath
, lpGameInstallDirectory
,
666 installScope
, InstanceID
);
668 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath
);
669 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory
);
672 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
673 TRACE("returning 0x%x\n", hr
);
676 /*******************************************************************************
677 * GAMEUX_FindGameInstanceId
679 * Internal helper function. Description available in gameux_private.h file
681 HRESULT
GAMEUX_FindGameInstanceId(
682 LPCWSTR sGDFBinaryPath
,
683 GAME_INSTALL_SCOPE installScope
,
686 static const WCHAR sConfigGDFBinaryPath
[] =
687 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
691 LPWSTR lpRegistryPath
= NULL
;
693 DWORD dwSubKeys
, dwSubKeyLen
, dwMaxSubKeyLen
, i
;
694 LPWSTR lpName
= NULL
, lpValue
= NULL
;
696 hr
= GAMEUX_buildGameRegistryPath(installScope
, NULL
, &lpRegistryPath
);
699 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
700 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
701 lpRegistryPath
, 0, KEY_READ
| KEY_WOW64_64KEY
, &hRootKey
));
705 hr
= HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey
, NULL
, NULL
, NULL
,
706 &dwSubKeys
, &dwMaxSubKeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
));
710 ++dwMaxSubKeyLen
; /* for string terminator */
711 lpName
= CoTaskMemAlloc(dwMaxSubKeyLen
*sizeof(WCHAR
));
712 if(!lpName
) hr
= E_OUTOFMEMORY
;
717 for(i
=0; i
<dwSubKeys
&& !found
; ++i
)
719 dwSubKeyLen
= dwMaxSubKeyLen
;
720 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey
, i
, lpName
, &dwSubKeyLen
,
721 NULL
, NULL
, NULL
, NULL
));
724 hr
= GAMEUX_LoadRegistryString(hRootKey
, lpName
,
725 sConfigGDFBinaryPath
, &lpValue
);
728 if(lstrcmpW(lpValue
, sGDFBinaryPath
)==0)
730 /* key found, let's copy instance id and exit */
731 hr
= (GUIDFromStringW(lpName
, pInstanceId
) ? S_OK
: E_FAIL
);
734 HeapFree(GetProcessHeap(), 0, lpValue
);
738 HeapFree(GetProcessHeap(), 0, lpName
);
739 RegCloseKey(hRootKey
);
742 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
744 if((SUCCEEDED(hr
) && !found
) || hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
749 /*******************************************************************************
750 * GameExplorer implementation
753 typedef struct _GameExplorerImpl
755 const struct IGameExplorerVtbl
*lpGameExplorerVtbl
;
756 const struct IGameExplorer2Vtbl
*lpGameExplorer2Vtbl
;
760 static inline GameExplorerImpl
*impl_from_IGameExplorer(IGameExplorer
*iface
)
762 return (GameExplorerImpl
*)((char*)iface
- FIELD_OFFSET(GameExplorerImpl
, lpGameExplorerVtbl
));
765 static inline IGameExplorer
* IGameExplorer_from_impl(GameExplorerImpl
* This
)
767 return (struct IGameExplorer
*)&This
->lpGameExplorerVtbl
;
770 static inline GameExplorerImpl
*impl_from_IGameExplorer2(IGameExplorer2
*iface
)
772 return (GameExplorerImpl
*)((char*)iface
- FIELD_OFFSET(GameExplorerImpl
, lpGameExplorer2Vtbl
));
775 static inline IGameExplorer2
* IGameExplorer2_from_impl(GameExplorerImpl
* This
)
777 return (struct IGameExplorer2
*)&This
->lpGameExplorer2Vtbl
;
780 static HRESULT WINAPI
GameExplorerImpl_QueryInterface(
781 IGameExplorer
*iface
,
785 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
787 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
791 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
792 IsEqualGUID(riid
, &IID_IGameExplorer
))
794 *ppvObject
= IGameExplorer_from_impl(This
);
796 else if(IsEqualGUID(riid
, &IID_IGameExplorer2
))
798 *ppvObject
= IGameExplorer2_from_impl(This
);
802 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
803 return E_NOINTERFACE
;
806 IGameExplorer_AddRef(iface
);
810 static ULONG WINAPI
GameExplorerImpl_AddRef(IGameExplorer
*iface
)
812 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
815 ref
= InterlockedIncrement(&This
->ref
);
817 TRACE("(%p): ref=%d\n", This
, ref
);
821 static ULONG WINAPI
GameExplorerImpl_Release(IGameExplorer
*iface
)
823 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
826 ref
= InterlockedDecrement(&This
->ref
);
827 TRACE("(%p): ref=%d\n", This
, ref
);
831 TRACE("freeing GameExplorer object\n");
832 HeapFree(GetProcessHeap(), 0, This
);
838 static HRESULT WINAPI
GameExplorerImpl_AddGame(
839 IGameExplorer
*iface
,
840 BSTR bstrGDFBinaryPath
,
841 BSTR sGameInstallDirectory
,
842 GAME_INSTALL_SCOPE installScope
,
845 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
846 TRACE("(%p, %s, %s, 0x%x, %s)\n", This
, debugstr_w(bstrGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
847 return GAMEUX_RegisterGame(bstrGDFBinaryPath
, sGameInstallDirectory
, installScope
, pInstanceID
);
850 static HRESULT WINAPI
GameExplorerImpl_RemoveGame(
851 IGameExplorer
*iface
,
854 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
856 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
857 return GAMEUX_RemoveRegistryRecord(&instanceID
);
860 static HRESULT WINAPI
GameExplorerImpl_UpdateGame(
861 IGameExplorer
*iface
,
864 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
866 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
867 return GAMEUX_UpdateGame(&instanceID
);
870 static HRESULT WINAPI
GameExplorerImpl_VerifyAccess(
871 IGameExplorer
*iface
,
875 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
877 FIXME("(%p, %s, %p)\n", This
, debugstr_w(sGDFBinaryPath
), pHasAccess
);
882 static const struct IGameExplorerVtbl GameExplorerImplVtbl
=
884 GameExplorerImpl_QueryInterface
,
885 GameExplorerImpl_AddRef
,
886 GameExplorerImpl_Release
,
887 GameExplorerImpl_AddGame
,
888 GameExplorerImpl_RemoveGame
,
889 GameExplorerImpl_UpdateGame
,
890 GameExplorerImpl_VerifyAccess
894 static HRESULT WINAPI
GameExplorer2Impl_QueryInterface(
895 IGameExplorer2
*iface
,
899 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
900 return GameExplorerImpl_QueryInterface(IGameExplorer_from_impl(This
), riid
, ppvObject
);
903 static ULONG WINAPI
GameExplorer2Impl_AddRef(IGameExplorer2
*iface
)
905 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
906 return GameExplorerImpl_AddRef(IGameExplorer_from_impl(This
));
909 static ULONG WINAPI
GameExplorer2Impl_Release(IGameExplorer2
*iface
)
911 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
912 return GameExplorerImpl_Release(IGameExplorer_from_impl(This
));
915 static HRESULT WINAPI
GameExplorer2Impl_CheckAccess(
916 IGameExplorer2
*iface
,
917 LPCWSTR binaryGDFPath
,
920 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
921 FIXME("stub (%p, %s, %p)\n", This
, debugstr_w(binaryGDFPath
), pHasAccess
);
925 static HRESULT WINAPI
GameExplorer2Impl_InstallGame(
926 IGameExplorer2
*iface
,
927 LPCWSTR binaryGDFPath
,
928 LPCWSTR installDirectory
,
929 GAME_INSTALL_SCOPE installScope
)
933 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
935 TRACE("(%p, %s, %s, 0x%x)\n", This
, debugstr_w(binaryGDFPath
), debugstr_w(installDirectory
), installScope
);
940 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
943 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
947 /* if game isn't yet registered, then install it */
948 instanceId
= GUID_NULL
;
949 hr
= GAMEUX_RegisterGame(binaryGDFPath
, installDirectory
, installScope
, &instanceId
);
952 /* otherwise, update game */
953 hr
= GAMEUX_UpdateGame(&instanceId
);
958 static HRESULT WINAPI
GameExplorer2Impl_UninstallGame(
959 IGameExplorer2
*iface
,
960 LPCWSTR binaryGDFPath
)
964 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
965 TRACE("(%p, %s)\n", This
, debugstr_w(binaryGDFPath
));
970 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
973 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
976 hr
= GAMEUX_RemoveRegistryRecord(&instanceId
);
981 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl
=
983 GameExplorer2Impl_QueryInterface
,
984 GameExplorer2Impl_AddRef
,
985 GameExplorer2Impl_Release
,
986 GameExplorer2Impl_InstallGame
,
987 GameExplorer2Impl_UninstallGame
,
988 GameExplorer2Impl_CheckAccess
992 * Construction routine
994 HRESULT
GameExplorer_create(
998 GameExplorerImpl
*pGameExplorer
;
1000 TRACE("(%p, %p)\n", pUnkOuter
, ppObj
);
1002 pGameExplorer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer
));
1005 return E_OUTOFMEMORY
;
1007 pGameExplorer
->lpGameExplorerVtbl
= &GameExplorerImplVtbl
;
1008 pGameExplorer
->lpGameExplorer2Vtbl
= &GameExplorer2ImplVtbl
;
1009 pGameExplorer
->ref
= 1;
1011 *ppObj
= (IUnknown
*)(&pGameExplorer
->lpGameExplorerVtbl
);
1013 TRACE("returning iface: %p\n", *ppObj
);