usp10: Correct matra type for Oriya 0x0B57.
[wine/multimedia.git] / dlls / gameux / gameexplorer.c
blob8b57247ed5492444d7b1a1778562826d5ef97cd2
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"
27 #include "gameux.h"
28 #include "gameux_private.h"
30 #include "initguid.h"
31 #include "msxml2.h"
33 #include "wine/debug.h"
34 #include "winreg.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 /*******************************************************************************
45 * GAMEUX_initGameData
47 * Internal helper function.
48 * Initializes GAME_DATA structure fields with proper values. Should be
49 * called always before first usage of this structure. Implemented in gameexplorer.c
51 * Parameters:
52 * GameData [I/O] pointer to structure to initialize
54 static void GAMEUX_initGameData(struct GAMEUX_GAME_DATA *GameData)
56 GameData->sGDFBinaryPath = NULL;
57 GameData->sGameInstallDirectory = NULL;
58 GameData->bstrName = NULL;
59 GameData->bstrDescription = NULL;
61 /*******************************************************************************
62 * GAMEUX_uninitGameData
64 * Internal helper function.
65 * Properly frees all data stored or pointed by fields of GAME_DATA structure.
66 * Should be called before freeing this structure. Implemented in gameexplorer.c
68 * Parameters:
69 * GameData [I/O] pointer to structure to uninitialize
71 static void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA *GameData)
73 HeapFree(GetProcessHeap(), 0, GameData->sGDFBinaryPath);
74 HeapFree(GetProcessHeap(), 0, GameData->sGameInstallDirectory);
75 SysFreeString(GameData->bstrName);
76 SysFreeString(GameData->bstrDescription);
78 /*******************************************************************************
79 * GAMEUX_buildGameRegistryPath
81 * Internal helper function. Description available in gameux_private.h file
83 HRESULT GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
84 LPCGUID gameInstanceId,
85 LPWSTR* lpRegistryPath)
87 static const WCHAR sGameUxRegistryPath[] = {'S','O','F','T','W','A','R','E','\\',
88 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
89 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','G','a','m','e','U','X',0};
90 static const WCHAR sGames[] = {'G','a','m','e','s',0};
91 static const WCHAR sBackslash[] = {'\\',0};
93 HRESULT hr = S_OK;
94 HANDLE hToken = NULL;
95 PTOKEN_USER pTokenUser = NULL;
96 DWORD dwLength;
97 LPWSTR lpSID = NULL;
98 WCHAR sInstanceId[40];
99 WCHAR sRegistryPath[8192];
101 TRACE("(0x%x, %s, %p)\n", installScope, debugstr_guid(gameInstanceId), lpRegistryPath);
103 /* this will make freeing it easier for user */
104 *lpRegistryPath = NULL;
106 lstrcpyW(sRegistryPath, sGameUxRegistryPath);
107 lstrcatW(sRegistryPath, sBackslash);
109 if(installScope == GIS_CURRENT_USER)
111 /* build registry path containing user's SID */
112 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
113 hr = HRESULT_FROM_WIN32(GetLastError());
115 if(SUCCEEDED(hr))
117 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
118 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
119 hr = HRESULT_FROM_WIN32(GetLastError());
121 if(SUCCEEDED(hr))
123 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
124 if(!pTokenUser)
125 hr = E_OUTOFMEMORY;
128 if(SUCCEEDED(hr))
129 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
130 hr = HRESULT_FROM_WIN32(GetLastError());
132 if(SUCCEEDED(hr))
133 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
134 hr = HRESULT_FROM_WIN32(GetLastError());
136 if(SUCCEEDED(hr))
138 lstrcatW(sRegistryPath, lpSID);
139 LocalFree(lpSID);
142 HeapFree(GetProcessHeap(), 0, pTokenUser);
143 CloseHandle(hToken);
146 else if(installScope == GIS_ALL_USERS)
147 /* build registry path without SID */
148 lstrcatW(sRegistryPath, sGames);
149 else
150 hr = E_INVALIDARG;
152 /* put game's instance id on the end of path, only if instance id was given */
153 if(gameInstanceId)
155 if(SUCCEEDED(hr))
156 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
158 if(SUCCEEDED(hr))
160 lstrcatW(sRegistryPath, sBackslash);
161 lstrcatW(sRegistryPath, sInstanceId);
165 if(SUCCEEDED(hr))
167 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
168 if(!*lpRegistryPath)
169 hr = E_OUTOFMEMORY;
172 if(SUCCEEDED(hr))
173 lstrcpyW(*lpRegistryPath, sRegistryPath);
175 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
176 return hr;
178 /*******************************************************************************
179 * GAMEUX_WriteRegistryRecord
181 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
182 * structure) into expected place in registry.
184 * Parameters:
185 * GameData [I] structure with data which will
186 * be written into registry.
187 * Proper values of fields installScope
188 * and guidInstanceId are required
189 * to create registry key.
191 * Schema of naming registry keys associated with games is available in
192 * description of _buildGameRegistryPath internal function.
194 * List of registry keys associated with structure fields:
195 * Key Field in GAMEUX_GAME_DATA structure
196 * ApplicationId guidApplicationId
197 * ConfigApplicationPath sGameInstallDirectory
198 * ConfigGDFBinaryPath sGDFBinaryPath
199 * Title bstrName
202 static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
204 static const WCHAR sApplicationId[] =
205 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
206 static const WCHAR sConfigApplicationPath[] =
207 {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
208 static const WCHAR sConfigGDFBinaryPath[] =
209 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
210 static const WCHAR sTitle[] =
211 {'T','i','t','l','e',0};
212 static const WCHAR sDescription[] =
213 {'D','e','s','c','r','i','p','t','i','o','n',0};
215 HRESULT hr, hr2;
216 LPWSTR lpRegistryKey;
217 HKEY hKey;
218 WCHAR sGameApplicationId[40];
220 TRACE("(%p)\n", GameData);
222 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
224 if(SUCCEEDED(hr))
225 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
227 if(SUCCEEDED(hr))
228 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
229 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL,
230 &hKey, NULL));
232 if(SUCCEEDED(hr))
234 /* write game data to registry key */
235 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigApplicationPath, 0,
236 REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
237 (lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
239 if(SUCCEEDED(hr))
240 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
241 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
242 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
244 if(SUCCEEDED(hr))
245 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sApplicationId, 0,
246 REG_SZ, (LPBYTE)(sGameApplicationId),
247 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
249 if(SUCCEEDED(hr))
250 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sTitle, 0,
251 REG_SZ, (LPBYTE)(GameData->bstrName),
252 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
254 if(SUCCEEDED(hr))
255 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sDescription, 0,
256 REG_SZ, (LPBYTE)(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName),
257 (lstrlenW(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName)+1)*sizeof(WCHAR)));
259 RegCloseKey(hKey);
261 if(FAILED(hr))
263 /* if something failed, remove whole key */
264 hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, KEY_WOW64_64KEY, 0);
265 /* do not overwrite old failure code with new success code */
266 if(FAILED(hr2))
267 hr = hr2;
271 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
272 TRACE("returning 0x%x\n", hr);
273 return hr;
275 /*******************************************************************************
276 * GAMEUX_ProcessGameDefinitionElement
278 * Helper function, parses single element from Game Definition
280 * Parameters:
281 * lpXMLElement [I] game definition element
282 * GameData [O] structure, where parsed
283 * data will be stored
285 static HRESULT GAMEUX_ProcessGameDefinitionElement(
286 IXMLDOMElement *element,
287 struct GAMEUX_GAME_DATA *GameData)
289 static const WCHAR sName[] =
290 {'N','a','m','e',0};
291 static const WCHAR sDescription[] =
292 {'D','e','s','c','r','i','p','t','i','o','n',0};
294 HRESULT hr;
295 BSTR bstrElementName;
297 TRACE("(%p, %p)\n", element, GameData);
299 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
300 if(SUCCEEDED(hr))
302 /* check element name */
303 if(lstrcmpW(bstrElementName, sName) == 0)
304 hr = IXMLDOMElement_get_text(element, &GameData->bstrName);
306 else if(lstrcmpW(bstrElementName, sDescription) == 0)
307 hr = IXMLDOMElement_get_text(element, &GameData->bstrDescription);
309 else
310 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
312 SysFreeString(bstrElementName);
315 return hr;
317 /*******************************************************************************
318 * GAMEUX_ParseGameDefinition
320 * Helper function, loads data from given XML element into fields of GAME_DATA
321 * structure
323 * Parameters:
324 * lpXMLGameDefinitionElement [I] Game Definition XML element
325 * GameData [O] structure where data loaded from
326 * XML element will be stored in
328 static HRESULT GAMEUX_ParseGameDefinition(
329 IXMLDOMElement *gdElement,
330 struct GAMEUX_GAME_DATA *GameData)
332 static const WCHAR sGameId[] = {'g','a','m','e','I','D',0};
334 HRESULT hr = S_OK;
335 BSTR bstrAttribute;
336 VARIANT variant;
337 IXMLDOMNodeList *childrenList;
338 IXMLDOMNode *nextNode;
339 IXMLDOMElement *nextElement;
341 TRACE("(%p, %p)\n", gdElement, GameData);
343 bstrAttribute = SysAllocString(sGameId);
344 if(!bstrAttribute)
345 hr = E_OUTOFMEMORY;
347 hr = IXMLDOMElement_getAttribute(gdElement, bstrAttribute, &variant);
349 if(SUCCEEDED(hr))
351 hr = ( GUIDFromStringW(V_BSTR(&variant), &GameData->guidApplicationId)==TRUE ? S_OK : E_FAIL);
353 SysFreeString(V_BSTR(&variant));
356 SysFreeString(bstrAttribute);
358 /* browse subnodes */
359 if(SUCCEEDED(hr))
360 hr = IXMLDOMElement_get_childNodes(gdElement, &childrenList);
362 if(SUCCEEDED(hr))
366 hr = IXMLDOMNodeList_nextNode(childrenList, &nextNode);
368 if(hr == S_OK)
370 hr = IXMLDOMNode_QueryInterface(nextNode, &IID_IXMLDOMElement,
371 (LPVOID*)&nextElement);
373 if(SUCCEEDED(hr))
375 hr = GAMEUX_ProcessGameDefinitionElement(nextElement, GameData);
376 IXMLDOMElement_Release(nextElement);
379 IXMLDOMElement_Release(nextNode);
382 while(hr == S_OK);
383 hr = S_OK;
385 IXMLDOMNodeList_Release(childrenList);
388 return hr;
390 /*******************************************************************************
391 * GAMEUX_ParseGDFBinary
393 * Helper function, loads given binary and parses embed GDF if there's any.
395 * Parameters:
396 * GameData [I/O] Structure with game's data. Content of field
397 * sGDFBinaryPath defines path to binary, from
398 * which embed GDF will be loaded. Data from
399 * GDF will be stored in other fields of this
400 * structure.
402 static HRESULT GAMEUX_ParseGDFBinary(struct GAMEUX_GAME_DATA *GameData)
404 static const WCHAR sRes[] = {'r','e','s',':','/','/',0};
405 static const WCHAR sDATA[] = {'D','A','T','A',0};
406 static const WCHAR sSlash[] = {'/',0};
408 HRESULT hr = S_OK;
409 WCHAR sResourcePath[MAX_PATH];
410 VARIANT variant;
411 VARIANT_BOOL isSuccessful;
412 IXMLDOMDocument *document;
413 IXMLDOMNode *gdNode;
414 IXMLDOMElement *root, *gdElement;
416 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData, debugstr_w(GameData->sGDFBinaryPath));
418 /* prepare path to GDF, using res:// prefix */
419 lstrcpyW(sResourcePath, sRes);
420 lstrcatW(sResourcePath, GameData->sGDFBinaryPath);
421 lstrcatW(sResourcePath, sSlash);
422 lstrcatW(sResourcePath, sDATA);
423 lstrcatW(sResourcePath, sSlash);
424 lstrcatW(sResourcePath, ID_GDF_XML_STR);
426 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
427 &IID_IXMLDOMDocument, (void**)&document);
429 if(SUCCEEDED(hr))
431 /* load GDF into MSXML */
432 V_VT(&variant) = VT_BSTR;
433 V_BSTR(&variant) = SysAllocString(sResourcePath);
434 if(!V_BSTR(&variant))
435 hr = E_OUTOFMEMORY;
437 if(SUCCEEDED(hr))
439 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
440 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
441 hr = E_FAIL;
444 SysFreeString(V_BSTR(&variant));
446 if(SUCCEEDED(hr))
448 hr = IXMLDOMDocument_get_documentElement(document, &root);
449 if(hr == S_FALSE)
450 hr = E_FAIL;
453 if(SUCCEEDED(hr))
455 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
456 if(hr == S_FALSE)
457 hr = E_FAIL;
459 if(SUCCEEDED(hr))
461 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
462 if(SUCCEEDED(hr))
464 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
465 IXMLDOMElement_Release(gdElement);
468 IXMLDOMNode_Release(gdNode);
471 IXMLDOMElement_Release(root);
474 IXMLDOMDocument_Release(document);
477 return hr;
479 /*******************************************************************
480 * GAMEUX_RemoveRegistryRecord
482 * Helper function, removes registry key associated with given game instance
484 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
486 HRESULT hr;
487 LPWSTR lpRegistryPath = NULL;
488 TRACE("(%s)\n", debugstr_guid(pInstanceID));
490 /* first, check is game installed for all users */
491 hr = GAMEUX_buildGameRegistryPath(GIS_ALL_USERS, pInstanceID, &lpRegistryPath);
492 if(SUCCEEDED(hr))
493 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
495 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
497 /* if not, check current user */
498 if(FAILED(hr))
500 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
501 if(SUCCEEDED(hr))
502 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
504 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
507 return hr;
509 /*******************************************************************************
510 * GAMEUX_RegisterGame
512 * Internal helper function. Registers game associated with given GDF binary in
513 * Game Explorer. Implemented in gameexplorer.c
515 * Parameters:
516 * sGDFBinaryPath [I] path to binary containing GDF file in
517 * resources
518 * sGameInstallDirectory [I] path to directory, where game installed
519 * it's files.
520 * installScope [I] scope of game installation
521 * pInstanceID [I/O] pointer to game instance identifier.
522 * If pointing to GUID_NULL, then new
523 * identifier will be generated automatically
524 * and returned via this parameter
526 static HRESULT GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
527 LPCWSTR sGameInstallDirectory,
528 GAME_INSTALL_SCOPE installScope,
529 GUID *pInstanceID)
531 HRESULT hr = S_OK;
532 struct GAMEUX_GAME_DATA GameData;
534 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
536 GAMEUX_initGameData(&GameData);
537 GameData.sGDFBinaryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath)+1)*sizeof(WCHAR));
538 lstrcpyW(GameData.sGDFBinaryPath, sGDFBinaryPath);
539 GameData.sGameInstallDirectory = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory)+1)*sizeof(WCHAR));
540 lstrcpyW(GameData.sGameInstallDirectory, sGameInstallDirectory);
541 GameData.installScope = installScope;
543 /* generate GUID if it was not provided by user */
544 if(IsEqualGUID(pInstanceID, &GUID_NULL))
545 hr = CoCreateGuid(pInstanceID);
547 GameData.guidInstanceId = *pInstanceID;
549 /* load data from GDF binary */
550 if(SUCCEEDED(hr))
551 hr = GAMEUX_ParseGDFBinary(&GameData);
553 /* save data to registry */
554 if(SUCCEEDED(hr))
555 hr = GAMEUX_WriteRegistryRecord(&GameData);
557 GAMEUX_uninitGameData(&GameData);
558 TRACE("returning 0x%08x\n", hr);
559 return hr;
561 /*******************************************************************************
562 * GAMEUX_IsGameKeyExist
564 * Helper function, checks if game's registry ath exists in given scope
566 * Parameters:
567 * installScope [I] scope to search game in
568 * InstanceID [I] game instance identifier
569 * lpRegistryPath [O] place to store address of registry path to
570 * the game. It is filled only if key exists.
571 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
573 * Returns:
574 * S_OK key was found properly
575 * S_FALSE key does not exists
578 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
579 LPCGUID InstanceID,
580 LPWSTR* lpRegistryPath) {
582 HRESULT hr;
583 HKEY hKey;
585 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
587 if(SUCCEEDED(hr))
588 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, *lpRegistryPath,
589 0, KEY_WOW64_64KEY, &hKey));
591 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
592 hr = S_FALSE;
594 if(hr == S_OK)
595 RegCloseKey(hKey);
596 else
598 /* if the key does not exist or another error occurred, do not return the path */
599 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
600 *lpRegistryPath = NULL;
603 return hr;
605 /*******************************************************************************
606 * GAMEUX_LoadRegistryString
608 * Helper function, loads string from registry value and allocates buffer for it
610 static HRESULT GAMEUX_LoadRegistryString(HKEY hRootKey,
611 LPCWSTR lpRegistryKey,
612 LPCWSTR lpRegistryValue,
613 LPWSTR* lpValue)
615 HRESULT hr;
616 DWORD dwSize;
618 *lpValue = NULL;
620 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
621 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
623 if(SUCCEEDED(hr))
625 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
626 if(!*lpValue)
627 hr = E_OUTOFMEMORY;
630 if(SUCCEEDED(hr))
631 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
632 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
634 return hr;
636 /*******************************************************************************
637 * GAMEUX_UpdateGame
639 * Helper function, updates stored data about game with given InstanceID
641 static HRESULT GAMEUX_UpdateGame(LPGUID InstanceID) {
642 static const WCHAR sConfigGDFBinaryPath[] = {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
643 static const WCHAR sConfigApplicationPath[] = {'C','o','n','f','i','g','A','p','p','l','i','c','a','t','i','o','n','P','a','t','h',0};
645 HRESULT hr;
646 GAME_INSTALL_SCOPE installScope;
647 LPWSTR lpRegistryPath;
648 LPWSTR lpGDFBinaryPath, lpGameInstallDirectory;
650 TRACE("(%p)\n", debugstr_guid(InstanceID));
652 /* first, check is game exists in CURRENT_USER scope */
653 installScope = GIS_CURRENT_USER;
654 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
656 if(hr == S_FALSE)
658 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
659 installScope = GIS_ALL_USERS;
660 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
663 if(hr == S_FALSE)
664 /* still not found? let's inform user that game does not exists */
665 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
667 if(SUCCEEDED(hr))
669 /* game found, it's registry path is in lpRegistryPath and install
670 * scope in installScope */
671 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath));
673 /* first, read required data about game */
674 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
675 sConfigGDFBinaryPath, &lpGDFBinaryPath);
677 if(SUCCEEDED(hr))
678 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
679 sConfigApplicationPath, &lpGameInstallDirectory);
681 /* now remove currently existing registry key */
682 if(SUCCEEDED(hr))
683 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
685 /* and add it again, it will cause in reparsing of whole GDF */
686 if(SUCCEEDED(hr))
687 hr = GAMEUX_RegisterGame(lpGDFBinaryPath, lpGameInstallDirectory,
688 installScope, InstanceID);
690 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath);
691 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory);
694 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
695 TRACE("returning 0x%x\n", hr);
696 return hr;
698 /*******************************************************************************
699 * GAMEUX_FindGameInstanceId
701 * Internal helper function. Description available in gameux_private.h file
703 HRESULT GAMEUX_FindGameInstanceId(
704 LPCWSTR sGDFBinaryPath,
705 GAME_INSTALL_SCOPE installScope,
706 GUID* pInstanceId)
708 static const WCHAR sConfigGDFBinaryPath[] =
709 {'C','o','n','f','i','g','G','D','F','B','i','n','a','r','y','P','a','t','h',0};
711 HRESULT hr;
712 BOOL found = FALSE;
713 LPWSTR lpRegistryPath = NULL;
714 HKEY hRootKey;
715 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
716 LPWSTR lpName = NULL, lpValue = NULL;
718 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
720 if(SUCCEEDED(hr))
721 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
722 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
723 lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey));
725 if(SUCCEEDED(hr))
727 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
728 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
730 if(SUCCEEDED(hr))
732 ++dwMaxSubKeyLen; /* for string terminator */
733 lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR));
734 if(!lpName) hr = E_OUTOFMEMORY;
737 if(SUCCEEDED(hr))
739 for(i=0; i<dwSubKeys && !found; ++i)
741 dwSubKeyLen = dwMaxSubKeyLen;
742 hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen,
743 NULL, NULL, NULL, NULL));
745 if(SUCCEEDED(hr))
746 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
747 sConfigGDFBinaryPath, &lpValue);
749 if(SUCCEEDED(hr))
750 if(lstrcmpW(lpValue, sGDFBinaryPath)==0)
752 /* key found, let's copy instance id and exit */
753 hr = (GUIDFromStringW(lpName, pInstanceId) ? S_OK : E_FAIL);
754 found = TRUE;
756 HeapFree(GetProcessHeap(), 0, lpValue);
760 HeapFree(GetProcessHeap(), 0, lpName);
761 RegCloseKey(hRootKey);
764 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
766 if((SUCCEEDED(hr) && !found) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
767 hr = S_FALSE;
769 return hr;
771 /*******************************************************************************
772 * GameExplorer implementation
775 typedef struct _GameExplorerImpl
777 const struct IGameExplorerVtbl *lpGameExplorerVtbl;
778 const struct IGameExplorer2Vtbl *lpGameExplorer2Vtbl;
779 LONG ref;
780 } GameExplorerImpl;
782 static inline GameExplorerImpl *impl_from_IGameExplorer(IGameExplorer *iface)
784 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorerVtbl));
787 static inline IGameExplorer* IGameExplorer_from_impl(GameExplorerImpl* This)
789 return (struct IGameExplorer*)&This->lpGameExplorerVtbl;
792 static inline GameExplorerImpl *impl_from_IGameExplorer2(IGameExplorer2 *iface)
794 return (GameExplorerImpl*)((char*)iface - FIELD_OFFSET(GameExplorerImpl, lpGameExplorer2Vtbl));
797 static inline IGameExplorer2* IGameExplorer2_from_impl(GameExplorerImpl* This)
799 return (struct IGameExplorer2*)&This->lpGameExplorer2Vtbl;
802 static HRESULT WINAPI GameExplorerImpl_QueryInterface(
803 IGameExplorer *iface,
804 REFIID riid,
805 void **ppvObject)
807 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
809 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
811 *ppvObject = NULL;
813 if(IsEqualGUID(riid, &IID_IUnknown) ||
814 IsEqualGUID(riid, &IID_IGameExplorer))
816 *ppvObject = IGameExplorer_from_impl(This);
818 else if(IsEqualGUID(riid, &IID_IGameExplorer2))
820 *ppvObject = IGameExplorer2_from_impl(This);
822 else
824 FIXME("interface %s not implemented\n", debugstr_guid(riid));
825 return E_NOINTERFACE;
828 IGameExplorer_AddRef(iface);
829 return S_OK;
832 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
834 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
835 LONG ref;
837 ref = InterlockedIncrement(&This->ref);
839 TRACE("(%p): ref=%d\n", This, ref);
840 return ref;
843 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
845 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
846 LONG ref;
848 ref = InterlockedDecrement(&This->ref);
849 TRACE("(%p): ref=%d\n", This, ref);
851 if(ref == 0)
853 TRACE("freeing GameExplorer object\n");
854 HeapFree(GetProcessHeap(), 0, This);
857 return ref;
860 static HRESULT WINAPI GameExplorerImpl_AddGame(
861 IGameExplorer *iface,
862 BSTR bstrGDFBinaryPath,
863 BSTR sGameInstallDirectory,
864 GAME_INSTALL_SCOPE installScope,
865 GUID *pInstanceID)
867 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
868 TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
869 return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
872 static HRESULT WINAPI GameExplorerImpl_RemoveGame(
873 IGameExplorer *iface,
874 GUID instanceID)
876 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
878 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
879 return GAMEUX_RemoveRegistryRecord(&instanceID);
882 static HRESULT WINAPI GameExplorerImpl_UpdateGame(
883 IGameExplorer *iface,
884 GUID instanceID)
886 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
888 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
889 return GAMEUX_UpdateGame(&instanceID);
892 static HRESULT WINAPI GameExplorerImpl_VerifyAccess(
893 IGameExplorer *iface,
894 BSTR sGDFBinaryPath,
895 BOOL *pHasAccess)
897 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
899 FIXME("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
900 *pHasAccess = TRUE;
901 return S_OK;
904 static const struct IGameExplorerVtbl GameExplorerImplVtbl =
906 GameExplorerImpl_QueryInterface,
907 GameExplorerImpl_AddRef,
908 GameExplorerImpl_Release,
909 GameExplorerImpl_AddGame,
910 GameExplorerImpl_RemoveGame,
911 GameExplorerImpl_UpdateGame,
912 GameExplorerImpl_VerifyAccess
916 static HRESULT WINAPI GameExplorer2Impl_QueryInterface(
917 IGameExplorer2 *iface,
918 REFIID riid,
919 void **ppvObject)
921 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
922 return GameExplorerImpl_QueryInterface(IGameExplorer_from_impl(This), riid, ppvObject);
925 static ULONG WINAPI GameExplorer2Impl_AddRef(IGameExplorer2 *iface)
927 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
928 return GameExplorerImpl_AddRef(IGameExplorer_from_impl(This));
931 static ULONG WINAPI GameExplorer2Impl_Release(IGameExplorer2 *iface)
933 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
934 return GameExplorerImpl_Release(IGameExplorer_from_impl(This));
937 static HRESULT WINAPI GameExplorer2Impl_CheckAccess(
938 IGameExplorer2 *iface,
939 LPCWSTR binaryGDFPath,
940 BOOL *pHasAccess)
942 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
943 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
944 return E_NOTIMPL;
947 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
948 IGameExplorer2 *iface,
949 LPCWSTR binaryGDFPath,
950 LPCWSTR installDirectory,
951 GAME_INSTALL_SCOPE installScope)
953 HRESULT hr;
954 GUID instanceId;
955 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
957 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
959 if(!binaryGDFPath)
960 return E_INVALIDARG;
962 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
964 if(hr == S_FALSE)
965 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
967 if(hr == S_FALSE)
969 /* if game isn't yet registered, then install it */
970 instanceId = GUID_NULL;
971 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
973 else if(hr == S_OK)
974 /* otherwise, update game */
975 hr = GAMEUX_UpdateGame(&instanceId);
977 return hr;
980 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
981 IGameExplorer2 *iface,
982 LPCWSTR binaryGDFPath)
984 HRESULT hr;
985 GUID instanceId;
986 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
987 TRACE("(%p, %s)\n", This, debugstr_w(binaryGDFPath));
989 if(!binaryGDFPath)
990 return E_INVALIDARG;
992 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
994 if(hr == S_FALSE)
995 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
997 if(hr == S_OK)
998 hr = GAMEUX_RemoveRegistryRecord(&instanceId);
1000 return hr;
1003 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl =
1005 GameExplorer2Impl_QueryInterface,
1006 GameExplorer2Impl_AddRef,
1007 GameExplorer2Impl_Release,
1008 GameExplorer2Impl_InstallGame,
1009 GameExplorer2Impl_UninstallGame,
1010 GameExplorer2Impl_CheckAccess
1014 * Construction routine
1016 HRESULT GameExplorer_create(
1017 IUnknown* pUnkOuter,
1018 IUnknown** ppObj)
1020 GameExplorerImpl *pGameExplorer;
1022 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1024 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
1026 if(!pGameExplorer)
1027 return E_OUTOFMEMORY;
1029 pGameExplorer->lpGameExplorerVtbl = &GameExplorerImplVtbl;
1030 pGameExplorer->lpGameExplorer2Vtbl = &GameExplorer2ImplVtbl;
1031 pGameExplorer->ref = 1;
1033 *ppObj = (IUnknown*)(&pGameExplorer->lpGameExplorerVtbl);
1035 TRACE("returning iface: %p\n", *ppObj);
1036 return S_OK;