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