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 * Helper function, builds registry path to key, where game's data are stored
75 * installScope [I] the scope which was used in AddGame/InstallGame call
76 * gameInstanceId [I] game instance GUID. If NULL, then only
77 * path to scope will be returned
78 * lpRegistryPath [O] pointer which will receive address to string
79 * containing expected registry path. Path
80 * is relative to HKLM registry key. It
81 * must be freed by calling HeapFree(GetProcessHeap(), 0, ...)
83 * Name of game's registry key always follows patterns below:
84 * When game is installed for current user only (installScope is GIS_CURRENT_USER):
85 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
86 * GameUX\[user's security ID]\[game instance ID]
88 * When game is installed for all users (installScope is GIS_ALL_USERS):
89 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\
90 * GameUX\Games\[game instance ID]
94 static HRESULT
GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope
,
95 LPCGUID gameInstanceId
,
96 LPWSTR
* lpRegistryPath
)
98 static const WCHAR sGameUxRegistryPath
[] = {'S','O','F','T','W','A','R','E','\\',
99 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
100 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
101 static const WCHAR sGames
[] = {'G','a','m','e','s',0};
102 static const WCHAR sBackslash
[] = {'\\',0};
105 HANDLE hToken
= NULL
;
106 PTOKEN_USER pTokenUser
= NULL
;
109 WCHAR sInstanceId
[40];
110 WCHAR sRegistryPath
[8192];
112 TRACE("(0x%x, %s, %p)\n", installScope
, debugstr_guid(gameInstanceId
), lpRegistryPath
);
114 /* this will make freeing it easier for user */
115 *lpRegistryPath
= NULL
;
117 lstrcpyW(sRegistryPath
, sGameUxRegistryPath
);
118 lstrcatW(sRegistryPath
, sBackslash
);
120 if(installScope
== GIS_CURRENT_USER
)
122 /* build registry path containing user's SID */
123 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
124 hr
= HRESULT_FROM_WIN32(GetLastError());
128 if(!GetTokenInformation(hToken
, TokenUser
, NULL
, 0, &dwLength
) &&
129 GetLastError()!=ERROR_INSUFFICIENT_BUFFER
)
130 hr
= HRESULT_FROM_WIN32(GetLastError());
134 pTokenUser
= HeapAlloc(GetProcessHeap(), 0, dwLength
);
140 if(!GetTokenInformation(hToken
, TokenUser
, (LPVOID
)pTokenUser
, dwLength
, &dwLength
))
141 hr
= HRESULT_FROM_WIN32(GetLastError());
144 if(!ConvertSidToStringSidW(pTokenUser
->User
.Sid
, &lpSID
))
145 hr
= HRESULT_FROM_WIN32(GetLastError());
149 lstrcatW(sRegistryPath
, lpSID
);
153 HeapFree(GetProcessHeap(), 0, pTokenUser
);
157 else if(installScope
== GIS_ALL_USERS
)
158 /* build registry path without SID */
159 lstrcatW(sRegistryPath
, sGames
);
163 /* put game's instance id on the end of path, only if instance id was given */
167 hr
= (StringFromGUID2(gameInstanceId
, sInstanceId
, sizeof(sInstanceId
)/sizeof(sInstanceId
[0])) ? S_OK
: E_FAIL
);
171 lstrcatW(sRegistryPath
, sBackslash
);
172 lstrcatW(sRegistryPath
, sInstanceId
);
178 *lpRegistryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath
)+1)*sizeof(WCHAR
));
184 lstrcpyW(*lpRegistryPath
, sRegistryPath
);
186 TRACE("result: 0x%x, path: %s\n", hr
, debugstr_w(*lpRegistryPath
));
189 /*******************************************************************************
190 * GAMEUX_WriteRegistryRecord
192 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
193 * structure) into expected place in registry.
196 * GameData [I] structure with data which will
197 * be written into registry.
198 * Proper values of fields installScope
199 * and guidInstanceId are required
200 * to create registry key.
202 * Schema of naming registry keys associated with games is available in
203 * description of _buildGameRegistryPath internal function.
205 * List of registry keys associated with structure fields:
206 * Key Field in GAMEUX_GAME_DATA structure
207 * ApplicationId guidApplicationId
208 * ConfigApplicationPath sGameInstallDirectory
209 * ConfigGDFBinaryPath sGDFBinaryPath
213 static HRESULT
GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA
*GameData
)
215 static const WCHAR sApplicationId
[] =
216 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
217 static const WCHAR sConfigApplicationPath
[] =
218 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
219 static const WCHAR sConfigGDFBinaryPath
[] =
220 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
221 static const WCHAR sTitle
[] =
222 {'T','i','t','l','e',0};
223 static const WCHAR sDescription
[] =
224 {'D','e','s','c','r','i','p','t','i','o','n',0};
227 LPWSTR lpRegistryKey
;
229 WCHAR sGameApplicationId
[40];
231 TRACE("(%p)\n", GameData
);
233 hr
= GAMEUX_buildGameRegistryPath(GameData
->installScope
, &GameData
->guidInstanceId
, &lpRegistryKey
);
236 hr
= (StringFromGUID2(&GameData
->guidApplicationId
, sGameApplicationId
, sizeof(sGameApplicationId
)/sizeof(sGameApplicationId
[0])) ? S_OK
: E_FAIL
);
239 hr
= HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
,
240 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
245 /* write game data to registry key */
246 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigApplicationPath
, 0,
247 REG_SZ
, (LPBYTE
)(GameData
->sGameInstallDirectory
),
248 (lstrlenW(GameData
->sGameInstallDirectory
)+1)*sizeof(WCHAR
)));
251 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sConfigGDFBinaryPath
, 0,
252 REG_SZ
, (LPBYTE
)(GameData
->sGDFBinaryPath
),
253 (lstrlenW(GameData
->sGDFBinaryPath
)+1)*sizeof(WCHAR
)));
256 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sApplicationId
, 0,
257 REG_SZ
, (LPBYTE
)(sGameApplicationId
),
258 (lstrlenW(sGameApplicationId
)+1)*sizeof(WCHAR
)));
261 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sTitle
, 0,
262 REG_SZ
, (LPBYTE
)(GameData
->bstrName
),
263 (lstrlenW(GameData
->bstrName
)+1)*sizeof(WCHAR
)));
266 hr
= HRESULT_FROM_WIN32(RegSetValueExW(hKey
, sDescription
, 0,
267 REG_SZ
, (LPBYTE
)(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
),
268 (lstrlenW(GameData
->bstrDescription
? GameData
->bstrDescription
: GameData
->bstrName
)+1)*sizeof(WCHAR
)));
274 /* if something failed, remove whole key */
275 hr2
= RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryKey
, 0, 0);
276 /* do not overwrite old failure code with new success code */
282 HeapFree(GetProcessHeap(), 0, lpRegistryKey
);
283 TRACE("returning 0x%x\n", hr
);
286 /*******************************************************************************
287 * GAMEUX_ProcessGameDefinitionElement
289 * Helper function, parses single element from Game Definition
292 * lpXMLElement [I] game definition element
293 * GameData [O] structure, where parsed
294 * data will be stored
296 static HRESULT
GAMEUX_ProcessGameDefinitionElement(
297 IXMLDOMElement
*element
,
298 struct GAMEUX_GAME_DATA
*GameData
)
300 static const WCHAR sName
[] =
302 static const WCHAR sDescription
[] =
303 {'D','e','s','c','r','i','p','t','i','o','n',0};
306 BSTR bstrElementName
;
308 TRACE("(%p, %p)\n", element
, GameData
);
310 hr
= IXMLDOMElement_get_nodeName(element
, &bstrElementName
);
313 /* check element name */
314 if(lstrcmpW(bstrElementName
, sName
) == 0)
315 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrName
);
317 else if(lstrcmpW(bstrElementName
, sDescription
) == 0)
318 hr
= IXMLDOMElement_get_text(element
, &GameData
->bstrDescription
);
321 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName
));
323 SysFreeString(bstrElementName
);
328 /*******************************************************************************
329 * GAMEUX_ParseGameDefinition
331 * Helper function, loads data from given XML element into fields of GAME_DATA
335 * lpXMLGameDefinitionElement [I] Game Definition XML element
336 * GameData [O] structure where data loaded from
337 * XML element will be stored in
339 static HRESULT
GAMEUX_ParseGameDefinition(
340 IXMLDOMElement
*gdElement
,
341 struct GAMEUX_GAME_DATA
*GameData
)
343 static const WCHAR sGameId
[] = {'g','a','m','e','I','D',0};
348 IXMLDOMNodeList
*childrenList
;
349 IXMLDOMNode
*nextNode
;
350 IXMLDOMElement
*nextElement
;
352 TRACE("(%p, %p)\n", gdElement
, GameData
);
354 bstrAttribute
= SysAllocString(sGameId
);
358 hr
= IXMLDOMElement_getAttribute(gdElement
, bstrAttribute
, &variant
);
362 hr
= ( GUIDFromStringW(V_BSTR(&variant
), &GameData
->guidApplicationId
)==TRUE
? S_OK
: E_FAIL
);
364 SysFreeString(V_BSTR(&variant
));
367 SysFreeString(bstrAttribute
);
369 /* browse subnodes */
371 hr
= IXMLDOMElement_get_childNodes(gdElement
, &childrenList
);
377 hr
= IXMLDOMNodeList_nextNode(childrenList
, &nextNode
);
381 hr
= IXMLDOMNode_QueryInterface(nextNode
, &IID_IXMLDOMElement
,
382 (LPVOID
*)&nextElement
);
386 hr
= GAMEUX_ProcessGameDefinitionElement(nextElement
, GameData
);
387 IXMLDOMElement_Release(nextElement
);
390 IXMLDOMElement_Release(nextNode
);
396 IXMLDOMNodeList_Release(childrenList
);
401 /*******************************************************************************
402 * GAMEUX_ParseGDFBinary
404 * Helper funtion, loads given binary and parses embed GDF if there's any.
407 * GameData [I/O] Structure with game's data. Content of field
408 * sGDFBinaryPath defines path to binary, from
409 * which embed GDF will be loaded. Data from
410 * GDF will be stored in other fields of this
413 static HRESULT
GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA
*GameData
)
415 static const WCHAR sRes
[] = {'r','e','s',':','/','/',0};
416 static const WCHAR sDATA
[] = {'D','A','T','A',0};
417 static const WCHAR sSlash
[] = {'/',0};
420 WCHAR sResourcePath
[MAX_PATH
];
422 VARIANT_BOOL isSuccessful
;
423 IXMLDOMDocument
*document
;
425 IXMLDOMElement
*root
, *gdElement
;
427 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData
, debugstr_w(GameData
->sGDFBinaryPath
));
429 /* prepare path to GDF, using res:// prefix */
430 lstrcpyW(sResourcePath
, sRes
);
431 lstrcatW(sResourcePath
, GameData
->sGDFBinaryPath
);
432 lstrcatW(sResourcePath
, sSlash
);
433 lstrcatW(sResourcePath
, sDATA
);
434 lstrcatW(sResourcePath
, sSlash
);
435 lstrcatW(sResourcePath
, ID_GDF_XML_STR
);
437 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
438 &IID_IXMLDOMDocument
, (void**)&document
);
442 /* load GDF into MSXML */
443 V_VT(&variant
) = VT_BSTR
;
444 V_BSTR(&variant
) = SysAllocString(sResourcePath
);
445 if(!V_BSTR(&variant
))
450 hr
= IXMLDOMDocument_load(document
, variant
, &isSuccessful
);
451 if(hr
== S_FALSE
|| isSuccessful
== VARIANT_FALSE
)
455 SysFreeString(V_BSTR(&variant
));
459 hr
= IXMLDOMDocument_get_documentElement(document
, &root
);
466 hr
= IXMLDOMElement_get_firstChild(root
, &gdNode
);
472 hr
= IXMLDOMNode_QueryInterface(gdNode
, &IID_IXMLDOMElement
, (LPVOID
*)&gdElement
);
475 hr
= GAMEUX_ParseGameDefinition(gdElement
, GameData
);
476 IXMLDOMElement_Release(gdElement
);
479 IXMLDOMNode_Release(gdNode
);
482 IXMLDOMElement_Release(root
);
485 IXMLDOMDocument_Release(document
);
490 /*******************************************************************
491 * GAMEUX_RemoveRegistryRecord
493 * Helper function, removes registry key associated with given game instance
495 static HRESULT
GAMEUX_RemoveRegistryRecord(GUID
* pInstanceID
)
498 LPWSTR lpRegistryPath
= NULL
;
499 TRACE("(%s)\n", debugstr_guid(pInstanceID
));
501 /* first, check is game installed for all users */
502 hr
= GAMEUX_buildGameRegistryPath(GIS_ALL_USERS
, pInstanceID
, &lpRegistryPath
);
504 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, 0, 0));
506 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
508 /* if not, check current user */
511 hr
= GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER
, pInstanceID
, &lpRegistryPath
);
513 hr
= HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE
, lpRegistryPath
, 0, 0));
515 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
520 /*******************************************************************************
521 * GAMEUX_RegisterGame
523 * Internal helper function. Description available in gameux_private.h file
525 HRESULT WINAPI
GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath
,
526 LPCWSTR sGameInstallDirectory
,
527 GAME_INSTALL_SCOPE installScope
,
531 struct GAMEUX_GAME_DATA GameData
;
533 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
535 GAMEUX_initGameData(&GameData
);
536 GameData
.sGDFBinaryPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath
)+1)*sizeof(WCHAR
));
537 lstrcpyW(GameData
.sGDFBinaryPath
, sGDFBinaryPath
);
538 GameData
.sGameInstallDirectory
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory
)+1)*sizeof(WCHAR
));
539 lstrcpyW(GameData
.sGameInstallDirectory
, sGameInstallDirectory
);
540 GameData
.installScope
= installScope
;
542 /* generate GUID if it was not provided by user */
543 if(IsEqualGUID(pInstanceID
, &GUID_NULL
))
544 hr
= CoCreateGuid(pInstanceID
);
546 GameData
.guidInstanceId
= *pInstanceID
;
548 /* load data from GDF binary */
550 hr
= GAMEUX_ParseGDFBinary(&GameData
);
552 /* save data to registry */
554 hr
= GAMEUX_WriteRegistryRecord(&GameData
);
556 GAMEUX_uninitGameData(&GameData
);
557 TRACE("returing 0x%08x\n", hr
);
560 /*******************************************************************************
561 * GAMEUX_IsGameKeyExist
563 * Helper function, checks if game's registry ath exists in given scope
566 * installScope [I] scope to search game in
567 * InstanceID [I] game instance identifier
568 * lpRegistryPath [O] place to store address of registry path to
569 * the game. It is filled only if key exists.
570 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
573 * S_OK key was found properly
574 * S_FALSE key does not exists
577 static HRESULT
GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope
,
579 LPWSTR
* lpRegistryPath
) {
584 hr
= GAMEUX_buildGameRegistryPath(installScope
, InstanceID
, lpRegistryPath
);
587 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, *lpRegistryPath
,
588 0, KEY_WOW64_64KEY
, &hKey
));
590 if(hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
597 /* if key does not exist or other error occured, do not return the path */
598 HeapFree(GetProcessHeap(), 0, *lpRegistryPath
);
599 *lpRegistryPath
= NULL
;
604 /*******************************************************************************
605 * GAMEUX_LoadRegistryString
607 * Helper function, loads string from registry value and allocates buffer for it
609 static HRESULT
GAMEUX_LoadRegistryString(HKEY hRootKey
,
610 LPCWSTR lpRegistryKey
,
611 LPCWSTR lpRegistryValue
,
619 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
620 RRF_RT_REG_SZ
, NULL
, NULL
, &dwSize
));
624 *lpValue
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
630 hr
= HRESULT_FROM_WIN32(RegGetValueW(hRootKey
, lpRegistryKey
, lpRegistryValue
,
631 RRF_RT_REG_SZ
, NULL
, *lpValue
, &dwSize
));
635 /*******************************************************************************
638 * Helper function, updates stored data about game with given InstanceID
640 static HRESULT
GAMEUX_UpdateGame(LPGUID InstanceID
) {
641 static const WCHAR sConfigGDFBinaryPath
[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
642 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};
645 GAME_INSTALL_SCOPE installScope
;
646 LPWSTR lpRegistryPath
;
647 LPWSTR lpGDFBinaryPath
, lpGameInstallDirectory
;
649 TRACE("(%p)\n", debugstr_guid(InstanceID
));
651 /* first, check is game exists in CURRENT_USER scope */
652 installScope
= GIS_CURRENT_USER
;
653 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
657 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
658 installScope
= GIS_ALL_USERS
;
659 hr
= GAMEUX_IsGameKeyExist(installScope
, InstanceID
, &lpRegistryPath
);
663 /* still not found? let's inform user that game does not exists */
664 hr
= HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
668 /* game found, it's registry path is in lpRegistryPath and install
669 * scope in installScope */
670 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath
));
672 /* first, read required data about game */
673 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
674 sConfigGDFBinaryPath
, &lpGDFBinaryPath
);
677 hr
= GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE
, lpRegistryPath
,
678 sConfigApplicationPath
, &lpGameInstallDirectory
);
680 /* now remove currently existing registry key */
682 hr
= GAMEUX_RemoveRegistryRecord(InstanceID
);
684 /* and add it again, it will cause in reparsing of whole GDF */
686 hr
= GAMEUX_RegisterGame(lpGDFBinaryPath
, lpGameInstallDirectory
,
687 installScope
, InstanceID
);
689 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath
);
690 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory
);
693 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
694 TRACE("returning 0x%x\n", hr
);
697 /*******************************************************************************
698 * GAMEUX_FindGameInstanceId
700 * Helper funtion. Searches for instance identifier of given game in given
701 * installation scope.
704 * sGDFBinaryPath [I] path to binary containing GDF
705 * installScope [I] game install scope to search in
706 * pInstanceId [O] instance identifier of given game
709 * S_OK id was returned properly
710 * S_FALSE id was not found in the registry
711 * E_OUTOFMEMORY problem while memory allocation
713 static HRESULT
GAMEUX_FindGameInstanceId(
714 LPCWSTR sGDFBinaryPath
,
715 GAME_INSTALL_SCOPE installScope
,
718 static const WCHAR sConfigGDFBinaryPath
[] =
719 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
723 LPWSTR lpRegistryPath
= NULL
;
725 DWORD dwSubKeys
, dwSubKeyLen
, dwMaxSubKeyLen
, i
;
726 LPWSTR lpName
= NULL
, lpValue
= NULL
;
728 hr
= GAMEUX_buildGameRegistryPath(installScope
, NULL
, &lpRegistryPath
);
731 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
732 hr
= HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
733 lpRegistryPath
, 0, KEY_READ
| KEY_WOW64_64KEY
, &hRootKey
));
737 hr
= HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey
, NULL
, NULL
, NULL
,
738 &dwSubKeys
, &dwMaxSubKeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
));
742 ++dwMaxSubKeyLen
; /* for string terminator */
743 lpName
= CoTaskMemAlloc(dwMaxSubKeyLen
*sizeof(WCHAR
));
744 if(!lpName
) hr
= E_OUTOFMEMORY
;
749 for(i
=0; i
<dwSubKeys
&& !found
; ++i
)
751 dwSubKeyLen
= dwMaxSubKeyLen
;
752 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey
, i
, lpName
, &dwSubKeyLen
,
753 NULL
, NULL
, NULL
, NULL
));
756 hr
= GAMEUX_LoadRegistryString(hRootKey
, lpName
,
757 sConfigGDFBinaryPath
, &lpValue
);
760 if(lstrcmpW(lpValue
, sGDFBinaryPath
)==0)
762 /* key found, let's copy instance id and exit */
763 hr
= (GUIDFromStringW(lpName
, pInstanceId
) ? S_OK
: E_FAIL
);
766 HeapFree(GetProcessHeap(), 0, lpValue
);
770 HeapFree(GetProcessHeap(), 0, lpName
);
771 RegCloseKey(hRootKey
);
774 HeapFree(GetProcessHeap(), 0, lpRegistryPath
);
776 if((SUCCEEDED(hr
) && !found
) || hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
781 /*******************************************************************************
782 * GameExplorer implementation
785 typedef struct _GameExplorerImpl
787 const struct IGameExplorerVtbl
*lpGameExplorerVtbl
;
788 const struct IGameExplorer2Vtbl
*lpGameExplorer2Vtbl
;
792 static inline GameExplorerImpl
*impl_from_IGameExplorer(IGameExplorer
*iface
)
794 return (GameExplorerImpl
*)((char*)iface
- FIELD_OFFSET(GameExplorerImpl
, lpGameExplorerVtbl
));
797 static inline IGameExplorer
* IGameExplorer_from_impl(GameExplorerImpl
* This
)
799 return (struct IGameExplorer
*)&This
->lpGameExplorerVtbl
;
802 static inline GameExplorerImpl
*impl_from_IGameExplorer2(IGameExplorer2
*iface
)
804 return (GameExplorerImpl
*)((char*)iface
- FIELD_OFFSET(GameExplorerImpl
, lpGameExplorer2Vtbl
));
807 static inline IGameExplorer2
* IGameExplorer2_from_impl(GameExplorerImpl
* This
)
809 return (struct IGameExplorer2
*)&This
->lpGameExplorer2Vtbl
;
812 static HRESULT WINAPI
GameExplorerImpl_QueryInterface(
813 IGameExplorer
*iface
,
817 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
819 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
823 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
824 IsEqualGUID(riid
, &IID_IGameExplorer
))
826 *ppvObject
= IGameExplorer_from_impl(This
);
828 else if(IsEqualGUID(riid
, &IID_IGameExplorer2
))
830 *ppvObject
= IGameExplorer2_from_impl(This
);
834 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
835 return E_NOINTERFACE
;
838 IGameExplorer_AddRef(iface
);
842 static ULONG WINAPI
GameExplorerImpl_AddRef(IGameExplorer
*iface
)
844 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
847 ref
= InterlockedIncrement(&This
->ref
);
849 TRACE("(%p): ref=%d\n", This
, ref
);
853 static ULONG WINAPI
GameExplorerImpl_Release(IGameExplorer
*iface
)
855 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
858 ref
= InterlockedDecrement(&This
->ref
);
859 TRACE("(%p): ref=%d\n", This
, ref
);
863 TRACE("freeing GameExplorer object\n");
864 HeapFree(GetProcessHeap(), 0, This
);
870 static HRESULT WINAPI
GameExplorerImpl_AddGame(
871 IGameExplorer
*iface
,
872 BSTR bstrGDFBinaryPath
,
873 BSTR sGameInstallDirectory
,
874 GAME_INSTALL_SCOPE installScope
,
877 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
878 TRACE("(%p, %s, %s, 0x%x, %s)\n", This
, debugstr_w(bstrGDFBinaryPath
), debugstr_w(sGameInstallDirectory
), installScope
, debugstr_guid(pInstanceID
));
879 return GAMEUX_RegisterGame(bstrGDFBinaryPath
, sGameInstallDirectory
, installScope
, pInstanceID
);
882 static HRESULT WINAPI
GameExplorerImpl_RemoveGame(
883 IGameExplorer
*iface
,
886 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
888 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
889 return GAMEUX_RemoveRegistryRecord(&instanceID
);
892 static HRESULT WINAPI
GameExplorerImpl_UpdateGame(
893 IGameExplorer
*iface
,
896 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
898 TRACE("(%p, %s)\n", This
, debugstr_guid(&instanceID
));
899 return GAMEUX_UpdateGame(&instanceID
);
902 static HRESULT WINAPI
GameExplorerImpl_VerifyAccess(
903 IGameExplorer
*iface
,
907 GameExplorerImpl
*This
= impl_from_IGameExplorer(iface
);
909 TRACE("(%p, %s, %p)\n", This
, debugstr_w(sGDFBinaryPath
), pHasAccess
);
914 static const struct IGameExplorerVtbl GameExplorerImplVtbl
=
916 GameExplorerImpl_QueryInterface
,
917 GameExplorerImpl_AddRef
,
918 GameExplorerImpl_Release
,
919 GameExplorerImpl_AddGame
,
920 GameExplorerImpl_RemoveGame
,
921 GameExplorerImpl_UpdateGame
,
922 GameExplorerImpl_VerifyAccess
926 static HRESULT WINAPI
GameExplorer2Impl_QueryInterface(
927 IGameExplorer2
*iface
,
931 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
932 return GameExplorerImpl_QueryInterface(IGameExplorer_from_impl(This
), riid
, ppvObject
);
935 static ULONG WINAPI
GameExplorer2Impl_AddRef(IGameExplorer2
*iface
)
937 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
938 return GameExplorerImpl_AddRef(IGameExplorer_from_impl(This
));
941 static ULONG WINAPI
GameExplorer2Impl_Release(IGameExplorer2
*iface
)
943 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
944 return GameExplorerImpl_Release(IGameExplorer_from_impl(This
));
947 static HRESULT WINAPI
GameExplorer2Impl_CheckAccess(
948 IGameExplorer2
*iface
,
949 LPCWSTR binaryGDFPath
,
952 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
953 FIXME("stub (%p, %s, %p)\n", This
, debugstr_w(binaryGDFPath
), pHasAccess
);
957 static HRESULT WINAPI
GameExplorer2Impl_InstallGame(
958 IGameExplorer2
*iface
,
959 LPCWSTR binaryGDFPath
,
960 LPCWSTR installDirectory
,
961 GAME_INSTALL_SCOPE installScope
)
965 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
967 TRACE("(%p, %s, %s, 0x%x)\n", This
, debugstr_w(binaryGDFPath
), debugstr_w(installDirectory
), installScope
);
972 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_CURRENT_USER
, &instanceId
);
975 hr
= GAMEUX_FindGameInstanceId(binaryGDFPath
, GIS_ALL_USERS
, &instanceId
);
979 /* if game isn't yet registered, then install it */
980 instanceId
= GUID_NULL
;
981 hr
= GAMEUX_RegisterGame(binaryGDFPath
, installDirectory
, installScope
, &instanceId
);
984 /* otherwise, update game */
985 hr
= GAMEUX_UpdateGame(&instanceId
);
990 static HRESULT WINAPI
GameExplorer2Impl_UninstallGame(
991 IGameExplorer2
*iface
,
992 LPCWSTR binaryGDFPath
)
994 GameExplorerImpl
*This
= impl_from_IGameExplorer2(iface
);
995 FIXME("stub (%p, %s)\n", This
, debugstr_w(binaryGDFPath
));
999 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl
=
1001 GameExplorer2Impl_QueryInterface
,
1002 GameExplorer2Impl_AddRef
,
1003 GameExplorer2Impl_Release
,
1004 GameExplorer2Impl_InstallGame
,
1005 GameExplorer2Impl_UninstallGame
,
1006 GameExplorer2Impl_CheckAccess
1010 * Construction routine
1012 HRESULT
GameExplorer_create(
1013 IUnknown
* pUnkOuter
,
1016 GameExplorerImpl
*pGameExplorer
;
1018 TRACE("(%p, %p)\n", pUnkOuter
, ppObj
);
1020 pGameExplorer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer
));
1023 return E_OUTOFMEMORY
;
1025 pGameExplorer
->lpGameExplorerVtbl
= &GameExplorerImplVtbl
;
1026 pGameExplorer
->lpGameExplorer2Vtbl
= &GameExplorer2ImplVtbl
;
1027 pGameExplorer
->ref
= 1;
1029 *ppObj
= (IUnknown
*)(&pGameExplorer
->lpGameExplorerVtbl
);
1031 TRACE("returning iface: %p\n", *ppObj
);