d3d11/tests: Add some tests for ID3DUserDefinedAnnotation.
[wine.git] / dlls / gameux / gameexplorer.c
blob5fdacacf4b2ea837a3405b72e3d7e1d6b62b4113
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
23 #include "ole2.h"
24 #include "sddl.h"
26 #include "gameux.h"
27 #include "gameux_private.h"
29 #include "initguid.h"
30 #include "msxml2.h"
32 #include "wine/debug.h"
33 #include "winreg.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gameux);
37 /*******************************************************************************
38 * GameUX helper functions
40 /*******************************************************************************
41 * GAMEUX_initGameData
43 * Internal helper function.
44 * Initializes GAME_DATA structure fields with proper values. Should be
45 * called always before first usage of this structure. Implemented in gameexplorer.c
47 * Parameters:
48 * GameData [I/O] pointer to structure to initialize
50 static 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.
61 * Properly frees all data stored or pointed by fields of GAME_DATA structure.
62 * Should be called before freeing this structure. Implemented in gameexplorer.c
64 * Parameters:
65 * GameData [I/O] pointer to structure to uninitialize
67 static void GAMEUX_uninitGameData(struct GAMEUX_GAME_DATA *GameData)
69 HeapFree(GetProcessHeap(), 0, GameData->sGDFBinaryPath);
70 HeapFree(GetProcessHeap(), 0, GameData->sGameInstallDirectory);
71 SysFreeString(GameData->bstrName);
72 SysFreeString(GameData->bstrDescription);
74 /*******************************************************************************
75 * GAMEUX_buildGameRegistryPath
77 * Internal helper function. Description available in gameux_private.h file
79 HRESULT GAMEUX_buildGameRegistryPath(GAME_INSTALL_SCOPE installScope,
80 LPCGUID gameInstanceId,
81 LPWSTR* lpRegistryPath)
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, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\GameUX\\");
98 if(installScope == GIS_CURRENT_USER)
100 /* build registry path containing user's SID */
101 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
102 hr = HRESULT_FROM_WIN32(GetLastError());
104 if(SUCCEEDED(hr))
106 if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) &&
107 GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
108 hr = HRESULT_FROM_WIN32(GetLastError());
110 if(SUCCEEDED(hr))
112 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwLength);
113 if(!pTokenUser)
114 hr = E_OUTOFMEMORY;
117 if(SUCCEEDED(hr))
118 if(!GetTokenInformation(hToken, TokenUser, (LPVOID)pTokenUser, dwLength, &dwLength))
119 hr = HRESULT_FROM_WIN32(GetLastError());
121 if(SUCCEEDED(hr))
122 if(!ConvertSidToStringSidW(pTokenUser->User.Sid, &lpSID))
123 hr = HRESULT_FROM_WIN32(GetLastError());
125 if(SUCCEEDED(hr))
127 lstrcatW(sRegistryPath, lpSID);
128 LocalFree(lpSID);
131 HeapFree(GetProcessHeap(), 0, pTokenUser);
132 CloseHandle(hToken);
135 else if(installScope == GIS_ALL_USERS)
136 /* build registry path without SID */
137 lstrcatW(sRegistryPath, L"Games");
138 else
139 hr = E_INVALIDARG;
141 /* put game's instance id on the end of path, only if instance id was given */
142 if(gameInstanceId)
144 if(SUCCEEDED(hr))
145 hr = (StringFromGUID2(gameInstanceId, sInstanceId, ARRAY_SIZE(sInstanceId)) ? S_OK : E_FAIL);
147 if(SUCCEEDED(hr))
149 lstrcatW(sRegistryPath, L"\\");
150 lstrcatW(sRegistryPath, sInstanceId);
154 if(SUCCEEDED(hr))
156 *lpRegistryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sRegistryPath)+1)*sizeof(WCHAR));
157 if(!*lpRegistryPath)
158 hr = E_OUTOFMEMORY;
161 if(SUCCEEDED(hr))
162 lstrcpyW(*lpRegistryPath, sRegistryPath);
164 TRACE("result: 0x%x, path: %s\n", hr, debugstr_w(*lpRegistryPath));
165 return hr;
167 /*******************************************************************************
168 * GAMEUX_WriteRegistryRecord
170 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
171 * structure) into expected place in registry.
173 * Parameters:
174 * GameData [I] structure with data which will
175 * be written into registry.
176 * Proper values of fields installScope
177 * and guidInstanceId are required
178 * to create registry key.
180 * Schema of naming registry keys associated with games is available in
181 * description of _buildGameRegistryPath internal function.
183 * List of registry keys associated with structure fields:
184 * Key Field in GAMEUX_GAME_DATA structure
185 * ApplicationId guidApplicationId
186 * ConfigApplicationPath sGameInstallDirectory
187 * ConfigGDFBinaryPath sGDFBinaryPath
188 * Title bstrName
191 static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
193 HRESULT hr, hr2;
194 LPWSTR lpRegistryKey;
195 HKEY hKey;
196 WCHAR sGameApplicationId[40];
198 TRACE("(%p)\n", GameData);
200 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
202 if(SUCCEEDED(hr))
203 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, ARRAY_SIZE(sGameApplicationId)) ? S_OK : E_FAIL);
205 if(SUCCEEDED(hr))
206 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
207 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL,
208 &hKey, NULL));
210 if(SUCCEEDED(hr))
212 /* write game data to registry key */
213 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ConfigApplicationPath", 0,
214 REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
215 (lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
217 if(SUCCEEDED(hr))
218 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ConfigGDFBinaryPath", 0,
219 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
220 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
222 if(SUCCEEDED(hr))
223 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ApplicationId", 0,
224 REG_SZ, (LPBYTE)(sGameApplicationId),
225 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
227 if(SUCCEEDED(hr))
228 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"Title", 0,
229 REG_SZ, (LPBYTE)(GameData->bstrName),
230 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
232 if(SUCCEEDED(hr))
233 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"Description", 0,
234 REG_SZ, (LPBYTE)(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName),
235 (lstrlenW(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName)+1)*sizeof(WCHAR)));
237 RegCloseKey(hKey);
239 if(FAILED(hr))
241 /* if something failed, remove whole key */
242 hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, KEY_WOW64_64KEY, 0);
243 /* do not overwrite old failure code with new success code */
244 if(FAILED(hr2))
245 hr = hr2;
249 HeapFree(GetProcessHeap(), 0, lpRegistryKey);
250 TRACE("returning 0x%x\n", hr);
251 return hr;
253 /*******************************************************************************
254 * GAMEUX_ProcessGameDefinitionElement
256 * Helper function, parses single element from Game Definition
258 * Parameters:
259 * lpXMLElement [I] game definition element
260 * GameData [O] structure, where parsed
261 * data will be stored
263 static HRESULT GAMEUX_ProcessGameDefinitionElement(
264 IXMLDOMElement *element,
265 struct GAMEUX_GAME_DATA *GameData)
267 HRESULT hr;
268 BSTR bstrElementName;
270 TRACE("(%p, %p)\n", element, GameData);
272 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
273 if(SUCCEEDED(hr))
275 /* check element name */
276 if(lstrcmpW(bstrElementName, L"Name") == 0)
277 hr = IXMLDOMElement_get_text(element, &GameData->bstrName);
279 else if(lstrcmpW(bstrElementName, L"Description") == 0)
280 hr = IXMLDOMElement_get_text(element, &GameData->bstrDescription);
282 else
283 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
285 SysFreeString(bstrElementName);
288 return hr;
290 /*******************************************************************************
291 * GAMEUX_ParseGameDefinition
293 * Helper function, loads data from given XML element into fields of GAME_DATA
294 * structure
296 * Parameters:
297 * lpXMLGameDefinitionElement [I] Game Definition XML element
298 * GameData [O] structure where data loaded from
299 * XML element will be stored in
301 static HRESULT GAMEUX_ParseGameDefinition(IXMLDOMElement *gamedef, struct GAMEUX_GAME_DATA *game_data)
303 IXMLDOMNodeList *props;
304 VARIANT var;
305 HRESULT hr;
306 BSTR attr;
308 TRACE("(%p, %p)\n", gamedef, game_data);
310 attr = SysAllocString(L"gameID");
311 if (!attr)
312 return E_OUTOFMEMORY;
314 hr = IXMLDOMElement_getAttribute(gamedef, attr, &var);
315 SysFreeString(attr);
317 if (SUCCEEDED(hr))
319 hr = CLSIDFromString(V_BSTR(&var), &game_data->guidApplicationId);
320 VariantClear(&var);
323 if (SUCCEEDED(hr))
324 hr = IXMLDOMElement_get_childNodes(gamedef, &props);
326 if (FAILED(hr))
327 return hr;
331 IXMLDOMNode *prop;
333 hr = IXMLDOMNodeList_nextNode(props, &prop);
334 if (hr == S_OK)
336 IXMLDOMElement *element;
338 hr = IXMLDOMNode_QueryInterface(prop, &IID_IXMLDOMElement, (void**)&element);
339 if (hr == S_OK)
341 hr = GAMEUX_ProcessGameDefinitionElement(element, game_data);
342 IXMLDOMElement_Release(element);
345 IXMLDOMNode_Release(prop);
348 while (hr == S_OK);
349 IXMLDOMNodeList_Release(props);
351 return FAILED(hr) ? hr : S_OK;
354 struct parse_gdf_thread_param
356 struct GAMEUX_GAME_DATA *GameData;
357 HRESULT hr;
360 /*******************************************************************************
361 * GAMEUX_ParseGDFBinary
363 * Helper function, loads given binary and parses embed GDF if there's any.
365 * Parameters:
366 * GameData [I/O] Structure with game's data. Content of field
367 * sGDFBinaryPath defines path to binary, from
368 * which embed GDF will be loaded. Data from
369 * GDF will be stored in other fields of this
370 * structure.
372 static DWORD WINAPI GAMEUX_ParseGDFBinary(void *thread_param)
374 struct parse_gdf_thread_param *ctx = thread_param;
375 struct GAMEUX_GAME_DATA *GameData = ctx->GameData;
377 HRESULT hr = S_OK;
378 WCHAR sResourcePath[MAX_PATH];
379 VARIANT variant;
380 VARIANT_BOOL isSuccessful;
381 IXMLDOMDocument *document;
382 IXMLDOMNode *gdNode;
383 IXMLDOMElement *root, *gdElement;
385 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData, debugstr_w(GameData->sGDFBinaryPath));
387 /* prepare path to GDF, using res:// prefix */
388 lstrcpyW(sResourcePath, L"res://");
389 lstrcatW(sResourcePath, GameData->sGDFBinaryPath);
390 lstrcatW(sResourcePath, L"/DATA/");
391 lstrcatW(sResourcePath, ID_GDF_XML_STR);
393 CoInitialize(NULL);
395 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
396 &IID_IXMLDOMDocument, (void**)&document);
398 if(SUCCEEDED(hr))
400 /* load GDF into MSXML */
401 V_VT(&variant) = VT_BSTR;
402 V_BSTR(&variant) = SysAllocString(sResourcePath);
403 if(!V_BSTR(&variant))
404 hr = E_OUTOFMEMORY;
406 if(SUCCEEDED(hr))
408 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
409 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
410 hr = E_FAIL;
413 SysFreeString(V_BSTR(&variant));
415 if(SUCCEEDED(hr))
417 hr = IXMLDOMDocument_get_documentElement(document, &root);
418 if(hr == S_FALSE)
419 hr = E_FAIL;
422 if(SUCCEEDED(hr))
424 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
425 if(hr == S_FALSE)
426 hr = E_FAIL;
428 if(SUCCEEDED(hr))
430 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
431 if(SUCCEEDED(hr))
433 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
434 IXMLDOMElement_Release(gdElement);
437 IXMLDOMNode_Release(gdNode);
440 IXMLDOMElement_Release(root);
443 IXMLDOMDocument_Release(document);
446 CoUninitialize();
447 ctx->hr = hr;
448 return 0;
451 /*******************************************************************
452 * GAMEUX_RemoveRegistryRecord
454 * Helper function, removes registry key associated with given game instance
456 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
458 HRESULT hr;
459 LPWSTR lpRegistryPath = NULL;
460 TRACE("(%s)\n", debugstr_guid(pInstanceID));
462 /* first, check is game installed for all users */
463 hr = GAMEUX_buildGameRegistryPath(GIS_ALL_USERS, pInstanceID, &lpRegistryPath);
464 if(SUCCEEDED(hr))
465 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
467 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
469 /* if not, check current user */
470 if(FAILED(hr))
472 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
473 if(SUCCEEDED(hr))
474 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
476 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
479 return hr;
481 /*******************************************************************************
482 * GAMEUX_RegisterGame
484 * Internal helper function. Registers game associated with given GDF binary in
485 * Game Explorer. Implemented in gameexplorer.c
487 * Parameters:
488 * sGDFBinaryPath [I] path to binary containing GDF file in
489 * resources
490 * sGameInstallDirectory [I] path to directory, where game installed
491 * its files.
492 * installScope [I] scope of game installation
493 * pInstanceID [I/O] pointer to game instance identifier.
494 * If pointing to GUID_NULL, then new
495 * identifier will be generated automatically
496 * and returned via this parameter
498 static HRESULT GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
499 LPCWSTR sGameInstallDirectory,
500 GAME_INSTALL_SCOPE installScope,
501 GUID *pInstanceID)
503 HRESULT hr = S_OK;
504 struct GAMEUX_GAME_DATA GameData;
506 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
508 GAMEUX_initGameData(&GameData);
509 GameData.sGDFBinaryPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGDFBinaryPath)+1)*sizeof(WCHAR));
510 lstrcpyW(GameData.sGDFBinaryPath, sGDFBinaryPath);
511 GameData.sGameInstallDirectory = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(sGameInstallDirectory)+1)*sizeof(WCHAR));
512 lstrcpyW(GameData.sGameInstallDirectory, sGameInstallDirectory);
513 GameData.installScope = installScope;
515 /* generate GUID if it was not provided by user */
516 if(IsEqualGUID(pInstanceID, &GUID_NULL))
517 hr = CoCreateGuid(pInstanceID);
519 GameData.guidInstanceId = *pInstanceID;
521 /* load data from GDF binary */
522 if(SUCCEEDED(hr))
524 struct parse_gdf_thread_param thread_param;
525 HANDLE thread;
526 DWORD ret;
528 thread_param.GameData = &GameData;
529 if(!(thread = CreateThread(NULL, 0, GAMEUX_ParseGDFBinary, &thread_param, 0, &ret)))
531 ERR("Failed to create thread.\n");
532 hr = E_FAIL;
533 goto done;
535 ret = WaitForSingleObject(thread, INFINITE);
536 CloseHandle(thread);
537 if(ret != WAIT_OBJECT_0)
539 ERR("Wait failed (%#x).\n", ret);
540 hr = E_FAIL;
541 goto done;
543 hr = thread_param.hr;
546 /* save data to registry */
547 if(SUCCEEDED(hr))
548 hr = GAMEUX_WriteRegistryRecord(&GameData);
550 done:
551 GAMEUX_uninitGameData(&GameData);
552 TRACE("returning 0x%08x\n", hr);
553 return hr;
555 /*******************************************************************************
556 * GAMEUX_IsGameKeyExist
558 * Helper function, checks if game's registry ath exists in given scope
560 * Parameters:
561 * installScope [I] scope to search game in
562 * InstanceID [I] game instance identifier
563 * lpRegistryPath [O] place to store address of registry path to
564 * the game. It is filled only if key exists.
565 * It must be freed by HeapFree(GetProcessHeap(), 0, ...)
567 * Returns:
568 * S_OK key was found properly
569 * S_FALSE key does not exists
572 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
573 LPCGUID InstanceID,
574 LPWSTR* lpRegistryPath) {
576 HRESULT hr;
577 HKEY hKey;
579 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
581 if(SUCCEEDED(hr))
582 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, *lpRegistryPath,
583 0, KEY_WOW64_64KEY, &hKey));
585 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
586 hr = S_FALSE;
588 if(hr == S_OK)
589 RegCloseKey(hKey);
590 else
592 /* if the key does not exist or another error occurred, do not return the path */
593 HeapFree(GetProcessHeap(), 0, *lpRegistryPath);
594 *lpRegistryPath = NULL;
597 return hr;
599 /*******************************************************************************
600 * GAMEUX_LoadRegistryString
602 * Helper function, loads string from registry value and allocates buffer for it
604 static HRESULT GAMEUX_LoadRegistryString(HKEY hRootKey,
605 LPCWSTR lpRegistryKey,
606 LPCWSTR lpRegistryValue,
607 LPWSTR* lpValue)
609 HRESULT hr;
610 DWORD dwSize;
612 *lpValue = NULL;
614 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
615 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
617 if(SUCCEEDED(hr))
619 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
620 if(!*lpValue)
621 hr = E_OUTOFMEMORY;
624 if(SUCCEEDED(hr))
625 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
626 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
628 return hr;
630 /*******************************************************************************
631 * GAMEUX_UpdateGame
633 * Helper function, updates stored data about game with given InstanceID
635 static HRESULT GAMEUX_UpdateGame(LPGUID InstanceID) {
636 HRESULT hr;
637 GAME_INSTALL_SCOPE installScope;
638 LPWSTR lpRegistryPath;
639 LPWSTR lpGDFBinaryPath;
641 TRACE("(%s)\n", debugstr_guid(InstanceID));
643 /* first, check is game exists in CURRENT_USER scope */
644 installScope = GIS_CURRENT_USER;
645 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
647 if(hr == S_FALSE)
649 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
650 installScope = GIS_ALL_USERS;
651 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
654 if(hr == S_FALSE)
655 /* still not found? let's inform user that game does not exists */
656 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
658 if(SUCCEEDED(hr))
660 WCHAR *lpGameInstallDirectory = NULL;
662 /* game found, its registry path is in lpRegistryPath and install
663 * scope in installScope */
664 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath));
666 /* first, read required data about game */
667 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
668 L"ConfigGDFBinaryPath", &lpGDFBinaryPath);
670 if(SUCCEEDED(hr))
671 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
672 L"ConfigApplicationPath", &lpGameInstallDirectory);
674 /* now remove currently existing registry key */
675 if(SUCCEEDED(hr))
676 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
678 /* and add it again, it will cause in reparsing of whole GDF */
679 if(SUCCEEDED(hr))
680 hr = GAMEUX_RegisterGame(lpGDFBinaryPath, lpGameInstallDirectory,
681 installScope, InstanceID);
683 HeapFree(GetProcessHeap(), 0, lpGDFBinaryPath);
684 HeapFree(GetProcessHeap(), 0, lpGameInstallDirectory);
687 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
688 TRACE("returning 0x%x\n", hr);
689 return hr;
691 /*******************************************************************************
692 * GAMEUX_FindGameInstanceId
694 * Internal helper function. Description available in gameux_private.h file
696 HRESULT GAMEUX_FindGameInstanceId(
697 LPCWSTR sGDFBinaryPath,
698 GAME_INSTALL_SCOPE installScope,
699 GUID* pInstanceId)
701 HRESULT hr;
702 BOOL found = FALSE;
703 LPWSTR lpRegistryPath = NULL;
704 HKEY hRootKey;
705 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
706 LPWSTR lpName = NULL, lpValue = NULL;
708 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
710 if(SUCCEEDED(hr))
711 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
712 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
713 lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey));
715 if(SUCCEEDED(hr))
717 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
718 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
720 if(SUCCEEDED(hr))
722 ++dwMaxSubKeyLen; /* for string terminator */
723 lpName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen*sizeof(WCHAR));
724 if(!lpName) hr = E_OUTOFMEMORY;
727 if(SUCCEEDED(hr))
729 for(i=0; i<dwSubKeys && !found; ++i)
731 dwSubKeyLen = dwMaxSubKeyLen;
732 hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen,
733 NULL, NULL, NULL, NULL));
735 if(SUCCEEDED(hr))
736 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
737 L"ConfigGDFBinaryPath", &lpValue);
739 if(SUCCEEDED(hr))
741 if(lstrcmpW(lpValue, sGDFBinaryPath)==0)
743 /* key found, let's copy instance id and exit */
744 hr = CLSIDFromString(lpName, pInstanceId);
745 found = TRUE;
747 HeapFree(GetProcessHeap(), 0, lpValue);
752 HeapFree(GetProcessHeap(), 0, lpName);
753 RegCloseKey(hRootKey);
756 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
758 if((SUCCEEDED(hr) && !found) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
759 hr = S_FALSE;
761 return hr;
763 /*******************************************************************************
764 * GameExplorer implementation
767 typedef struct _GameExplorerImpl
769 IGameExplorer IGameExplorer_iface;
770 IGameExplorer2 IGameExplorer2_iface;
771 LONG ref;
772 } GameExplorerImpl;
774 static inline GameExplorerImpl *impl_from_IGameExplorer(IGameExplorer *iface)
776 return CONTAINING_RECORD(iface, GameExplorerImpl, IGameExplorer_iface);
779 static inline GameExplorerImpl *impl_from_IGameExplorer2(IGameExplorer2 *iface)
781 return CONTAINING_RECORD(iface, GameExplorerImpl, IGameExplorer2_iface);
784 static HRESULT WINAPI GameExplorerImpl_QueryInterface(
785 IGameExplorer *iface,
786 REFIID riid,
787 void **ppvObject)
789 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
791 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
793 *ppvObject = NULL;
795 if(IsEqualGUID(riid, &IID_IUnknown) ||
796 IsEqualGUID(riid, &IID_IGameExplorer))
798 *ppvObject = &This->IGameExplorer_iface;
800 else if(IsEqualGUID(riid, &IID_IGameExplorer2))
802 *ppvObject = &This->IGameExplorer2_iface;
804 else
806 FIXME("interface %s not implemented\n", debugstr_guid(riid));
807 return E_NOINTERFACE;
810 IGameExplorer_AddRef(iface);
811 return S_OK;
814 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
816 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
817 LONG ref;
819 ref = InterlockedIncrement(&This->ref);
821 TRACE("(%p): ref=%d\n", This, ref);
822 return ref;
825 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
827 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
828 LONG ref;
830 ref = InterlockedDecrement(&This->ref);
831 TRACE("(%p): ref=%d\n", This, ref);
833 if(ref == 0)
835 TRACE("freeing GameExplorer object\n");
836 HeapFree(GetProcessHeap(), 0, This);
839 return ref;
842 static HRESULT WINAPI GameExplorerImpl_AddGame(
843 IGameExplorer *iface,
844 BSTR bstrGDFBinaryPath,
845 BSTR sGameInstallDirectory,
846 GAME_INSTALL_SCOPE installScope,
847 GUID *pInstanceID)
849 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
850 TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
851 return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
854 static HRESULT WINAPI GameExplorerImpl_RemoveGame(
855 IGameExplorer *iface,
856 GUID instanceID)
858 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
860 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
861 return GAMEUX_RemoveRegistryRecord(&instanceID);
864 static HRESULT WINAPI GameExplorerImpl_UpdateGame(
865 IGameExplorer *iface,
866 GUID instanceID)
868 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
870 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
871 return GAMEUX_UpdateGame(&instanceID);
874 static HRESULT WINAPI GameExplorerImpl_VerifyAccess(
875 IGameExplorer *iface,
876 BSTR sGDFBinaryPath,
877 BOOL *pHasAccess)
879 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
881 FIXME("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
882 *pHasAccess = TRUE;
883 return S_OK;
886 static const struct IGameExplorerVtbl GameExplorerImplVtbl =
888 GameExplorerImpl_QueryInterface,
889 GameExplorerImpl_AddRef,
890 GameExplorerImpl_Release,
891 GameExplorerImpl_AddGame,
892 GameExplorerImpl_RemoveGame,
893 GameExplorerImpl_UpdateGame,
894 GameExplorerImpl_VerifyAccess
898 static HRESULT WINAPI GameExplorer2Impl_QueryInterface(
899 IGameExplorer2 *iface,
900 REFIID riid,
901 void **ppvObject)
903 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
904 return GameExplorerImpl_QueryInterface(&This->IGameExplorer_iface, riid, ppvObject);
907 static ULONG WINAPI GameExplorer2Impl_AddRef(IGameExplorer2 *iface)
909 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
910 return GameExplorerImpl_AddRef(&This->IGameExplorer_iface);
913 static ULONG WINAPI GameExplorer2Impl_Release(IGameExplorer2 *iface)
915 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
916 return GameExplorerImpl_Release(&This->IGameExplorer_iface);
919 static HRESULT WINAPI GameExplorer2Impl_CheckAccess(
920 IGameExplorer2 *iface,
921 LPCWSTR binaryGDFPath,
922 BOOL *pHasAccess)
924 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
925 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
926 return E_NOTIMPL;
929 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
930 IGameExplorer2 *iface,
931 LPCWSTR binaryGDFPath,
932 LPCWSTR installDirectory,
933 GAME_INSTALL_SCOPE installScope)
935 HRESULT hr;
936 GUID instanceId;
937 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
939 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
941 if(!binaryGDFPath)
942 return E_INVALIDARG;
944 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
946 if(hr == S_FALSE)
947 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
949 if(hr == S_FALSE)
951 /* if game isn't yet registered, then install it */
952 instanceId = GUID_NULL;
953 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
955 else if(hr == S_OK)
956 /* otherwise, update game */
957 hr = GAMEUX_UpdateGame(&instanceId);
959 return hr;
962 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
963 IGameExplorer2 *iface,
964 LPCWSTR binaryGDFPath)
966 HRESULT hr;
967 GUID instanceId;
968 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
969 TRACE("(%p, %s)\n", This, debugstr_w(binaryGDFPath));
971 if(!binaryGDFPath)
972 return E_INVALIDARG;
974 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
976 if(hr == S_FALSE)
977 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
979 if(hr == S_OK)
980 hr = GAMEUX_RemoveRegistryRecord(&instanceId);
982 return hr;
985 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl =
987 GameExplorer2Impl_QueryInterface,
988 GameExplorer2Impl_AddRef,
989 GameExplorer2Impl_Release,
990 GameExplorer2Impl_InstallGame,
991 GameExplorer2Impl_UninstallGame,
992 GameExplorer2Impl_CheckAccess
996 * Construction routine
998 HRESULT GameExplorer_create(
999 IUnknown* pUnkOuter,
1000 IUnknown** ppObj)
1002 GameExplorerImpl *pGameExplorer;
1004 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1006 pGameExplorer = HeapAlloc(GetProcessHeap(), 0, sizeof(*pGameExplorer));
1008 if(!pGameExplorer)
1009 return E_OUTOFMEMORY;
1011 pGameExplorer->IGameExplorer_iface.lpVtbl = &GameExplorerImplVtbl;
1012 pGameExplorer->IGameExplorer2_iface.lpVtbl = &GameExplorer2ImplVtbl;
1013 pGameExplorer->ref = 1;
1015 *ppObj = (IUnknown*)&pGameExplorer->IGameExplorer_iface;
1017 TRACE("returning iface: %p\n", *ppObj);
1018 return S_OK;