Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / gameux / gameexplorer.c
blobbddc131f511b9da8b22243de2e9598add6742342
1 /*
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
20 #define COBJMACROS
22 #include "config.h"
24 #include "ole2.h"
25 #include "sddl.h"
26 #include "xmldom.h"
28 #include "gameux.h"
29 #include "gameux_private.h"
31 #include "initguid.h"
32 #include "msxml2.h"
34 #include "wine/debug.h"
35 #include "winreg.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 /*******************************************************************************
46 * GAMEUX_initGameData
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};
84 HRESULT hr = S_OK;
85 HANDLE hToken = NULL;
86 PTOKEN_USER pTokenUser = NULL;
87 DWORD dwLength;
88 LPWSTR lpSID = 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());
106 if(SUCCEEDED(hr))
108 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
109 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
110 hr = HRESULT_FROM_WIN32(GetLastError());
112 if(SUCCEEDED(hr))
114 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
115 if(!pTokenUser)
116 hr = E_OUTOFMEMORY;
119 if(SUCCEEDED(hr))
120 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
121 hr = HRESULT_FROM_WIN32(GetLastError());
123 if(SUCCEEDED(hr))
124 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
125 hr = HRESULT_FROM_WIN32(GetLastError());
127 if(SUCCEEDED(hr))
129 lstrcatW(sRegistryPath, lpSID);
130 LocalFree(lpSID);
133 HeapFree(GetProcessHeap(), 0, pTokenUser);
134 CloseHandle(hToken);
137 else if(installScope == GIS_ALL_USERS)
138 /* build registry path without SID */
139 lstrcatW(sRegistryPath, sGames);
140 else
141 hr = E_INVALIDARG;
143 /* put game's instance id on the end of path, only if instance id was given */
144 if(gameInstanceId)
146 if(SUCCEEDED(hr))
147 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
149 if(SUCCEEDED(hr))
151 lstrcatW(sRegistryPath, sBackslash);
152 lstrcatW(sRegistryPath, sInstanceId);
156 if(SUCCEEDED(hr))
158 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
159 if(!*lpRegistryPath)
160 hr = E_OUTOFMEMORY;
163 if(SUCCEEDED(hr))
164 lstrcpyW(*lpRegistryPath, sRegistryPath);
166 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
167 return hr;
169 /*******************************************************************************
170 * GAMEUX_WriteRegistryRecord
172 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
173 * structure) into expected place in registry.
175 * Parameters:
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
190 * Title bstrName
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};
206 HRESULT hr, hr2;
207 LPWSTR lpRegistryKey;
208 HKEY hKey;
209 WCHAR sGameApplicationId[40];
211 TRACE("(%p)\n", GameData);
213 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
215 if(SUCCEEDED(hr))
216 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
218 if(SUCCEEDED(hr))
219 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
220 0, NULL, 0, KEY_ALL_ACCESS, NULL,
221 &hKey, NULL));
223 if(SUCCEEDED(hr))
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)));
230 if(SUCCEEDED(hr))
231 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
232 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
233 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
235 if(SUCCEEDED(hr))
236 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sApplicationId, 0,
237 REG_SZ, (LPBYTE)(sGameApplicationId),
238 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
240 if(SUCCEEDED(hr))
241 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sTitle, 0,
242 REG_SZ, (LPBYTE)(GameData->bstrName),
243 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
245 if(SUCCEEDED(hr))
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)));
250 RegCloseKey(hKey);
252 if(FAILED(hr))
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 */
257 if(FAILED(hr2))
258 hr = hr2;
262 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
263 TRACE("returning 0x%x\n", hr);
264 return hr;
266 /*******************************************************************************
267 * GAMEUX_ProcessGameDefinitionElement
269 * Helper function, parses single element from Game Definition
271 * Parameters:
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[] =
281 {'N','a','m','e',0};
282 static const WCHAR sDescription[] =
283 {'D','e','s','c','r','i','p','t','i','o','n',0};
285 HRESULT hr;
286 BSTR bstrElementName;
288 TRACE("(%p, %p)\n", element, GameData);
290 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
291 if(SUCCEEDED(hr))
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);
300 else
301 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
303 SysFreeString(bstrElementName);
306 return hr;
308 /*******************************************************************************
309 * GAMEUX_ParseGameDefinition
311 * Helper function, loads data from given XML element into fields of GAME_DATA
312 * structure
314 * Parameters:
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};
325 HRESULT hr = S_OK;
326 BSTR bstrAttribute;
327 VARIANT variant;
328 IXMLDOMNodeList *childrenList;
329 IXMLDOMNode *nextNode;
330 IXMLDOMElement *nextElement;
332 TRACE("(%p, %p)\n", gdElement, GameData);
334 bstrAttribute = SysAllocString(sGameId);
335 if(!bstrAttribute)
336 hr = E_OUTOFMEMORY;
338 hr = IXMLDOMElement_getAttribute(gdElement, bstrAttribute, &variant);
340 if(SUCCEEDED(hr))
342 hr = ( GUIDFromStringW(V_BSTR(&variant), &GameData->guidApplicationId)==TRUE ? S_OK : E_FAIL);
344 SysFreeString(V_BSTR(&variant));
347 SysFreeString(bstrAttribute);
349 /* browse subnodes */
350 if(SUCCEEDED(hr))
351 hr = IXMLDOMElement_get_childNodes(gdElement, &childrenList);
353 if(SUCCEEDED(hr))
357 hr = IXMLDOMNodeList_nextNode(childrenList, &nextNode);
359 if(hr == S_OK)
361 hr = IXMLDOMNode_QueryInterface(nextNode, &IID_IXMLDOMElement,
362 (LPVOID*)&nextElement);
364 if(SUCCEEDED(hr))
366 hr = GAMEUX_ProcessGameDefinitionElement(nextElement, GameData);
367 IXMLDOMElement_Release(nextElement);
370 IXMLDOMElement_Release(nextNode);
373 while(hr == S_OK);
374 hr = S_OK;
376 IXMLDOMNodeList_Release(childrenList);
379 return hr;
381 /*******************************************************************************
382 * GAMEUX_ParseGDFBinary
384 * Helper function, loads given binary and parses embed GDF if there's any.
386 * Parameters:
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
391 * structure.
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};
399 HRESULT hr = S_OK;
400 WCHAR sResourcePath[MAX_PATH];
401 VARIANT variant;
402 VARIANT_BOOL isSuccessful;
403 IXMLDOMDocument *document;
404 IXMLDOMNode *gdNode;
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);
420 if(SUCCEEDED(hr))
422 /* load GDF into MSXML */
423 V_VT(&variant) = VT_BSTR;
424 V_BSTR(&variant) = SysAllocString(sResourcePath);
425 if(!V_BSTR(&variant))
426 hr = E_OUTOFMEMORY;
428 if(SUCCEEDED(hr))
430 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
431 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
432 hr = E_FAIL;
435 SysFreeString(V_BSTR(&variant));
437 if(SUCCEEDED(hr))
439 hr = IXMLDOMDocument_get_documentElement(document, &root);
440 if(hr == S_FALSE)
441 hr = E_FAIL;
444 if(SUCCEEDED(hr))
446 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
447 if(hr == S_FALSE)
448 hr = E_FAIL;
450 if(SUCCEEDED(hr))
452 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
453 if(SUCCEEDED(hr))
455 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
456 IXMLDOMElement_Release(gdElement);
459 IXMLDOMNode_Release(gdNode);
462 IXMLDOMElement_Release(root);
465 IXMLDOMDocument_Release(document);
468 return hr;
470 /*******************************************************************
471 * GAMEUX_RemoveRegistryRecord
473 * Helper function, removes registry key associated with given game instance
475 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
477 HRESULT hr;
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);
483 if(SUCCEEDED(hr))
484 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
486 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
488 /* if not, check current user */
489 if(FAILED(hr))
491 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
492 if(SUCCEEDED(hr))
493 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
495 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
498 return hr;
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,
508 GUID *pInstanceID)
510 HRESULT hr = S_OK;
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 */
529 if(SUCCEEDED(hr))
530 hr = GAMEUX_ParseGDFBinary(&GameData);
532 /* save data to registry */
533 if(SUCCEEDED(hr))
534 hr = GAMEUX_WriteRegistryRecord(&GameData);
536 GAMEUX_uninitGameData(&GameData);
537 TRACE("returning 0x%08x\n", hr);
538 return hr;
540 /*******************************************************************************
541 * GAMEUX_IsGameKeyExist
543 * Helper function, checks if game's registry ath exists in given scope
545 * Parameters:
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, ...)
552 * Returns:
553 * S_OK key was found properly
554 * S_FALSE key does not exists
557 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
558 LPCGUID InstanceID,
559 LPWSTR* lpRegistryPath) {
561 HRESULT hr;
562 HKEY hKey;
564 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
566 if(SUCCEEDED(hr))
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))
571 hr = S_FALSE;
573 if(hr == S_OK)
574 RegCloseKey(hKey);
575 else
577 /* if the key does not exist or another error occurred, do not return the path */
578 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
579 *lpRegistryPath = NULL;
582 return hr;
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,
592 LPWSTR* lpValue)
594 HRESULT hr;
595 DWORD dwSize;
597 *lpValue = NULL;
599 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
600 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
602 if(SUCCEEDED(hr))
604 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
605 if(!*lpValue)
606 hr = E_OUTOFMEMORY;
609 if(SUCCEEDED(hr))
610 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
611 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
613 return hr;
615 /*******************************************************************************
616 * GAMEUX_UpdateGame
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};
624 HRESULT hr;
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);
635 if(hr == S_FALSE)
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);
642 if(hr == S_FALSE)
643 /* still not found? let's inform user that game does not exists */
644 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
646 if(SUCCEEDED(hr))
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);
656 if(SUCCEEDED(hr))
657 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
658 sConfigApplicationPath, &lpGameInstallDirectory);
660 /* now remove currently existing registry key */
661 if(SUCCEEDED(hr))
662 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
664 /* and add it again, it will cause in reparsing of whole GDF */
665 if(SUCCEEDED(hr))
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);
675 return 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,
685 GUID* pInstanceId)
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};
690 HRESULT hr;
691 BOOL found = FALSE;
692 LPWSTR lpRegistryPath = NULL;
693 HKEY hRootKey;
694 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
695 LPWSTR lpName = NULL, lpValue = NULL;
697 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
699 if(SUCCEEDED(hr))
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));
704 if(SUCCEEDED(hr))
706 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
707 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
709 if(SUCCEEDED(hr))
711 ++dwMaxSubKeyLen; /* for string terminator */
712 lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR));
713 if(!lpName) hr = E_OUTOFMEMORY;
716 if(SUCCEEDED(hr))
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));
724 if(SUCCEEDED(hr))
725 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
726 sConfigGDFBinaryPath, &lpValue);
728 if(SUCCEEDED(hr))
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);
733 found = TRUE;
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))
746 hr = S_FALSE;
748 return hr;
750 /*******************************************************************************
751 * GameExplorer implementation
754 typedef struct _GameExplorerImpl
756 const struct IGameExplorerVtbl *lpGameExplorerVtbl;
757 const struct IGameExplorer2Vtbl *lpGameExplorer2Vtbl;
758 LONG ref;
759 } GameExplorerImpl;
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,
783 REFIID riid,
784 void **ppvObject)
786 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
788 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
790 *ppvObject = NULL;
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);
801 else
803 FIXME("interface %s not implemented\n", debugstr_guid(riid));
804 return E_NOINTERFACE;
807 IGameExplorer_AddRef(iface);
808 return S_OK;
811 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
813 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
814 LONG ref;
816 ref = InterlockedIncrement(&This->ref);
818 TRACE("(%p): ref=%d\n", This, ref);
819 return ref;
822 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
824 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
825 LONG ref;
827 ref = InterlockedDecrement(&This->ref);
828 TRACE("(%p): ref=%d\n", This, ref);
830 if(ref == 0)
832 TRACE("freeing GameExplorer object\n");
833 HeapFree(GetProcessHeap(), 0, This);
836 return ref;
839 static HRESULT WINAPI GameExplorerImpl_AddGame(
840 IGameExplorer *iface,
841 BSTR bstrGDFBinaryPath,
842 BSTR sGameInstallDirectory,
843 GAME_INSTALL_SCOPE installScope,
844 GUID *pInstanceID)
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,
853 GUID instanceID)
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,
863 GUID instanceID)
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,
873 BSTR sGDFBinaryPath,
874 BOOL *pHasAccess)
876 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
878 FIXME("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
879 *pHasAccess = TRUE;
880 return S_OK;
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,
897 REFIID riid,
898 void **ppvObject)
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,
919 BOOL *pHasAccess)
921 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
922 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
923 return E_NOTIMPL;
926 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
927 IGameExplorer2 *iface,
928 LPCWSTR binaryGDFPath,
929 LPCWSTR installDirectory,
930 GAME_INSTALL_SCOPE installScope)
932 HRESULT hr;
933 GUID instanceId;
934 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
936 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
938 if(!binaryGDFPath)
939 return E_INVALIDARG;
941 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
943 if(hr == S_FALSE)
944 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
946 if(hr == S_FALSE)
948 /* if game isn't yet registered, then install it */
949 instanceId = GUID_NULL;
950 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
952 else if(hr == S_OK)
953 /* otherwise, update game */
954 hr = GAMEUX_UpdateGame(&instanceId);
956 return hr;
959 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
960 IGameExplorer2 *iface,
961 LPCWSTR binaryGDFPath)
963 HRESULT hr;
964 GUID instanceId;
965 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
966 TRACE("(%p, %s)\n", This, debugstr_w(binaryGDFPath));
968 if(!binaryGDFPath)
969 return E_INVALIDARG;
971 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
973 if(hr == S_FALSE)
974 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
976 if(hr == S_OK)
977 hr = GAMEUX_RemoveRegistryRecord(&instanceId);
979 return hr;
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(
996 IUnknown* pUnkOuter,
997 IUnknown** ppObj)
999 GameExplorerImpl *pGameExplorer;
1001 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1003 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
1005 if(!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);
1015 return S_OK;