gameux: Add InstallGame implementation.
[wine/multimedia.git] / dlls / gameux / gameexplorer.c
blob66173f2959d074b24b62c852a2e35b3a96691929
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 * Helper function, builds registry path to key, where game's data are stored
74 * Parameters:
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};
104 HRESULT hr = S_OK;
105 HANDLE hToken = NULL;
106 PTOKEN_USER pTokenUser = NULL;
107 DWORD dwLength;
108 LPWSTR lpSID = 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());
126 if(SUCCEEDED(hr))
128 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
129 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
130 hr = HRESULT_FROM_WIN32(GetLastError());
132 if(SUCCEEDED(hr))
134 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
135 if(!pTokenUser)
136 hr = E_OUTOFMEMORY;
139 if(SUCCEEDED(hr))
140 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
141 hr = HRESULT_FROM_WIN32(GetLastError());
143 if(SUCCEEDED(hr))
144 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
145 hr = HRESULT_FROM_WIN32(GetLastError());
147 if(SUCCEEDED(hr))
149 lstrcatW(sRegistryPath, lpSID);
150 LocalFree(lpSID);
153 HeapFree(GetProcessHeap(), 0, pTokenUser);
154 CloseHandle(hToken);
157 else if(installScope == GIS_ALL_USERS)
158 /* build registry path without SID */
159 lstrcatW(sRegistryPath, sGames);
160 else
161 hr = E_INVALIDARG;
163 /* put game's instance id on the end of path, only if instance id was given */
164 if(gameInstanceId)
166 if(SUCCEEDED(hr))
167 hr = (StringFromGUID2(gameInstanceId, sInstanceId, sizeof(sInstanceId)/sizeof(sInstanceId[0])) ? S_OK : E_FAIL);
169 if(SUCCEEDED(hr))
171 lstrcatW(sRegistryPath, sBackslash);
172 lstrcatW(sRegistryPath, sInstanceId);
176 if(SUCCEEDED(hr))
178 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
179 if(!*lpRegistryPath)
180 hr = E_OUTOFMEMORY;
183 if(SUCCEEDED(hr))
184 lstrcpyW(*lpRegistryPath, sRegistryPath);
186 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
187 return hr;
189 /*******************************************************************************
190 * GAMEUX_WriteRegistryRecord
192 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
193 * structure) into expected place in registry.
195 * Parameters:
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
210 * Title bstrName
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};
226 HRESULT hr, hr2;
227 LPWSTR lpRegistryKey;
228 HKEY hKey;
229 WCHAR sGameApplicationId[40];
231 TRACE("(%p)\n", GameData);
233 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
235 if(SUCCEEDED(hr))
236 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, sizeof(sGameApplicationId)/sizeof(sGameApplicationId[0])) ? S_OK : E_FAIL);
238 if(SUCCEEDED(hr))
239 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
240 0, NULL, 0, KEY_ALL_ACCESS, NULL,
241 &hKey, NULL));
243 if(SUCCEEDED(hr))
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)));
250 if(SUCCEEDED(hr))
251 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sConfigGDFBinaryPath, 0,
252 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
253 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
255 if(SUCCEEDED(hr))
256 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sApplicationId, 0,
257 REG_SZ, (LPBYTE)(sGameApplicationId),
258 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
260 if(SUCCEEDED(hr))
261 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, sTitle, 0,
262 REG_SZ, (LPBYTE)(GameData->bstrName),
263 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
265 if(SUCCEEDED(hr))
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)));
270 RegCloseKey(hKey);
272 if(FAILED(hr))
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 */
277 if(FAILED(hr2))
278 hr = hr2;
282 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
283 TRACE("returning 0x%x\n", hr);
284 return hr;
286 /*******************************************************************************
287 * GAMEUX_ProcessGameDefinitionElement
289 * Helper function, parses single element from Game Definition
291 * Parameters:
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[] =
301 {'N','a','m','e',0};
302 static const WCHAR sDescription[] =
303 {'D','e','s','c','r','i','p','t','i','o','n',0};
305 HRESULT hr;
306 BSTR bstrElementName;
308 TRACE("(%p, %p)\n", element, GameData);
310 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
311 if(SUCCEEDED(hr))
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);
320 else
321 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
323 SysFreeString(bstrElementName);
326 return hr;
328 /*******************************************************************************
329 * GAMEUX_ParseGameDefinition
331 * Helper function, loads data from given XML element into fields of GAME_DATA
332 * structure
334 * Parameters:
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};
345 HRESULT hr = S_OK;
346 BSTR bstrAttribute;
347 VARIANT variant;
348 IXMLDOMNodeList *childrenList;
349 IXMLDOMNode *nextNode;
350 IXMLDOMElement *nextElement;
352 TRACE("(%p, %p)\n", gdElement, GameData);
354 bstrAttribute = SysAllocString(sGameId);
355 if(!bstrAttribute)
356 hr = E_OUTOFMEMORY;
358 hr = IXMLDOMElement_getAttribute(gdElement, bstrAttribute, &variant);
360 if(SUCCEEDED(hr))
362 hr = ( GUIDFromStringW(V_BSTR(&variant), &GameData->guidApplicationId)==TRUE ? S_OK : E_FAIL);
364 SysFreeString(V_BSTR(&variant));
367 SysFreeString(bstrAttribute);
369 /* browse subnodes */
370 if(SUCCEEDED(hr))
371 hr = IXMLDOMElement_get_childNodes(gdElement, &childrenList);
373 if(SUCCEEDED(hr))
377 hr = IXMLDOMNodeList_nextNode(childrenList, &nextNode);
379 if(hr == S_OK)
381 hr = IXMLDOMNode_QueryInterface(nextNode, &IID_IXMLDOMElement,
382 (LPVOID*)&nextElement);
384 if(SUCCEEDED(hr))
386 hr = GAMEUX_ProcessGameDefinitionElement(nextElement, GameData);
387 IXMLDOMElement_Release(nextElement);
390 IXMLDOMElement_Release(nextNode);
393 while(hr == S_OK);
394 hr = S_OK;
396 IXMLDOMNodeList_Release(childrenList);
399 return hr;
401 /*******************************************************************************
402 * GAMEUX_ParseGDFBinary
404 * Helper funtion, loads given binary and parses embed GDF if there's any.
406 * Parameters:
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
411 * structure.
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};
419 HRESULT hr = S_OK;
420 WCHAR sResourcePath[MAX_PATH];
421 VARIANT variant;
422 VARIANT_BOOL isSuccessful;
423 IXMLDOMDocument *document;
424 IXMLDOMNode *gdNode;
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);
440 if(SUCCEEDED(hr))
442 /* load GDF into MSXML */
443 V_VT(&variant) = VT_BSTR;
444 V_BSTR(&variant) = SysAllocString(sResourcePath);
445 if(!V_BSTR(&variant))
446 hr = E_OUTOFMEMORY;
448 if(SUCCEEDED(hr))
450 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
451 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
452 hr = E_FAIL;
455 SysFreeString(V_BSTR(&variant));
457 if(SUCCEEDED(hr))
459 hr = IXMLDOMDocument_get_documentElement(document, &root);
460 if(hr == S_FALSE)
461 hr = E_FAIL;
464 if(SUCCEEDED(hr))
466 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
467 if(hr == S_FALSE)
468 hr = E_FAIL;
470 if(SUCCEEDED(hr))
472 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
473 if(SUCCEEDED(hr))
475 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
476 IXMLDOMElement_Release(gdElement);
479 IXMLDOMNode_Release(gdNode);
482 IXMLDOMElement_Release(root);
485 IXMLDOMDocument_Release(document);
488 return hr;
490 /*******************************************************************
491 * GAMEUX_RemoveRegistryRecord
493 * Helper function, removes registry key associated with given game instance
495 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
497 HRESULT hr;
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);
503 if(SUCCEEDED(hr))
504 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
506 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
508 /* if not, check current user */
509 if(FAILED(hr))
511 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
512 if(SUCCEEDED(hr))
513 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, 0, 0));
515 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
518 return hr;
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,
528 GUID *pInstanceID)
530 HRESULT hr = S_OK;
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 */
549 if(SUCCEEDED(hr))
550 hr = GAMEUX_ParseGDFBinary(&GameData);
552 /* save data to registry */
553 if(SUCCEEDED(hr))
554 hr = GAMEUX_WriteRegistryRecord(&GameData);
556 GAMEUX_uninitGameData(&GameData);
557 TRACE("returing 0x%08x\n", hr);
558 return hr;
560 /*******************************************************************************
561 * GAMEUX_IsGameKeyExist
563 * Helper function, checks if game's registry ath exists in given scope
565 * Parameters:
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, ...)
572 * Returns:
573 * S_OK key was found properly
574 * S_FALSE key does not exists
577 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
578 LPCGUID InstanceID,
579 LPWSTR* lpRegistryPath) {
581 HRESULT hr;
582 HKEY hKey;
584 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
586 if(SUCCEEDED(hr))
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))
591 hr = S_FALSE;
593 if(hr == S_OK)
594 RegCloseKey(hKey);
595 else
597 /* if key does not exist or other error occured, do not return the path */
598 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
599 *lpRegistryPath = NULL;
602 return hr;
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,
612 LPWSTR* lpValue)
614 HRESULT hr;
615 DWORD dwSize;
617 *lpValue = NULL;
619 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
620 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
622 if(SUCCEEDED(hr))
624 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
625 if(!*lpValue)
626 hr = E_OUTOFMEMORY;
629 if(SUCCEEDED(hr))
630 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
631 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
633 return hr;
635 /*******************************************************************************
636 * GAMEUX_UpdateGame
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};
644 HRESULT hr;
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);
655 if(hr == S_FALSE)
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);
662 if(hr == S_FALSE)
663 /* still not found? let's inform user that game does not exists */
664 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
666 if(SUCCEEDED(hr))
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);
676 if(SUCCEEDED(hr))
677 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
678 sConfigApplicationPath, &lpGameInstallDirectory);
680 /* now remove currently existing registry key */
681 if(SUCCEEDED(hr))
682 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
684 /* and add it again, it will cause in reparsing of whole GDF */
685 if(SUCCEEDED(hr))
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);
695 return hr;
697 /*******************************************************************************
698 * GAMEUX_FindGameInstanceId
700 * Helper funtion. Searches for instance identifier of given game in given
701 * installation scope.
703 * Parameters:
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
708 * Returns:
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,
716 GUID* pInstanceId)
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};
721 HRESULT hr;
722 BOOL found = FALSE;
723 LPWSTR lpRegistryPath = NULL;
724 HKEY hRootKey;
725 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
726 LPWSTR lpName = NULL, lpValue = NULL;
728 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
730 if(SUCCEEDED(hr))
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));
735 if(SUCCEEDED(hr))
737 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
738 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
740 if(SUCCEEDED(hr))
742 ++dwMaxSubKeyLen; /* for string terminator */
743 lpName = CoTaskMemAlloc(dwMaxSubKeyLen*sizeof(WCHAR));
744 if(!lpName) hr = E_OUTOFMEMORY;
747 if(SUCCEEDED(hr))
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));
755 if(SUCCEEDED(hr))
756 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
757 sConfigGDFBinaryPath, &lpValue);
759 if(SUCCEEDED(hr))
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);
764 found = TRUE;
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))
777 hr = S_FALSE;
779 return hr;
781 /*******************************************************************************
782 * GameExplorer implementation
785 typedef struct _GameExplorerImpl
787 const struct IGameExplorerVtbl *lpGameExplorerVtbl;
788 const struct IGameExplorer2Vtbl *lpGameExplorer2Vtbl;
789 LONG ref;
790 } GameExplorerImpl;
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,
814 REFIID riid,
815 void **ppvObject)
817 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
819 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
821 *ppvObject = NULL;
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);
832 else
834 FIXME("interface %s not implemented\n", debugstr_guid(riid));
835 return E_NOINTERFACE;
838 IGameExplorer_AddRef(iface);
839 return S_OK;
842 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
844 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
845 LONG ref;
847 ref = InterlockedIncrement(&This->ref);
849 TRACE("(%p): ref=%d\n", This, ref);
850 return ref;
853 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
855 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
856 LONG ref;
858 ref = InterlockedDecrement(&This->ref);
859 TRACE("(%p): ref=%d\n", This, ref);
861 if(ref == 0)
863 TRACE("freeing GameExplorer object\n");
864 HeapFree(GetProcessHeap(), 0, This);
867 return ref;
870 static HRESULT WINAPI GameExplorerImpl_AddGame(
871 IGameExplorer *iface,
872 BSTR bstrGDFBinaryPath,
873 BSTR sGameInstallDirectory,
874 GAME_INSTALL_SCOPE installScope,
875 GUID *pInstanceID)
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,
884 GUID instanceID)
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,
894 GUID instanceID)
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,
904 BSTR sGDFBinaryPath,
905 BOOL *pHasAccess)
907 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
909 TRACE("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
910 FIXME("stub\n");
911 return E_NOTIMPL;
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,
928 REFIID riid,
929 void **ppvObject)
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,
950 BOOL *pHasAccess)
952 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
953 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
954 return E_NOTIMPL;
957 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
958 IGameExplorer2 *iface,
959 LPCWSTR binaryGDFPath,
960 LPCWSTR installDirectory,
961 GAME_INSTALL_SCOPE installScope)
963 HRESULT hr;
964 GUID instanceId;
965 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
967 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
969 if(!binaryGDFPath)
970 return E_INVALIDARG;
972 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
974 if(hr == S_FALSE)
975 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
977 if(hr == S_FALSE)
979 /* if game isn't yet registered, then install it */
980 instanceId = GUID_NULL;
981 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
983 else if(hr == S_OK)
984 /* otherwise, update game */
985 hr = GAMEUX_UpdateGame(&instanceId);
987 return hr;
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));
996 return E_NOTIMPL;
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,
1014 IUnknown** ppObj)
1016 GameExplorerImpl *pGameExplorer;
1018 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1020 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
1022 if(!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);
1032 return S_OK;