http.sys: Keep connection sockets open after sending a 400 response.
[wine.git] / dlls / gameux / gameexplorer.c
blobb352d7344bc5f5463bdf30d428fc9486a3403095
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 free(GameData->sGDFBinaryPath);
70 free(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 = malloc(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 free(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 = wcsdup(sRegistryPath);
157 if(!*lpRegistryPath)
158 hr = E_OUTOFMEMORY;
161 TRACE("result: 0x%lx, path: %s\n", hr, debugstr_w(*lpRegistryPath));
162 return hr;
164 /*******************************************************************************
165 * GAMEUX_WriteRegistryRecord
167 * Helper function, writes data associated with game (stored in GAMEUX_GAME_DATA
168 * structure) into expected place in registry.
170 * Parameters:
171 * GameData [I] structure with data which will
172 * be written into registry.
173 * Proper values of fields installScope
174 * and guidInstanceId are required
175 * to create registry key.
177 * Schema of naming registry keys associated with games is available in
178 * description of _buildGameRegistryPath internal function.
180 * List of registry keys associated with structure fields:
181 * Key Field in GAMEUX_GAME_DATA structure
182 * ApplicationId guidApplicationId
183 * ConfigApplicationPath sGameInstallDirectory
184 * ConfigGDFBinaryPath sGDFBinaryPath
185 * Title bstrName
188 static HRESULT GAMEUX_WriteRegistryRecord(struct GAMEUX_GAME_DATA *GameData)
190 HRESULT hr, hr2;
191 LPWSTR lpRegistryKey;
192 HKEY hKey;
193 WCHAR sGameApplicationId[40];
195 TRACE("(%p)\n", GameData);
197 hr = GAMEUX_buildGameRegistryPath(GameData->installScope, &GameData->guidInstanceId, &lpRegistryKey);
199 if(SUCCEEDED(hr))
200 hr = (StringFromGUID2(&GameData->guidApplicationId, sGameApplicationId, ARRAY_SIZE(sGameApplicationId)) ? S_OK : E_FAIL);
202 if(SUCCEEDED(hr))
203 hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey,
204 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL,
205 &hKey, NULL));
207 if(SUCCEEDED(hr))
209 /* write game data to registry key */
210 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ConfigApplicationPath", 0,
211 REG_SZ, (LPBYTE)(GameData->sGameInstallDirectory),
212 (lstrlenW(GameData->sGameInstallDirectory)+1)*sizeof(WCHAR)));
214 if(SUCCEEDED(hr))
215 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ConfigGDFBinaryPath", 0,
216 REG_SZ, (LPBYTE)(GameData->sGDFBinaryPath),
217 (lstrlenW(GameData->sGDFBinaryPath)+1)*sizeof(WCHAR)));
219 if(SUCCEEDED(hr))
220 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ApplicationId", 0,
221 REG_SZ, (LPBYTE)(sGameApplicationId),
222 (lstrlenW(sGameApplicationId)+1)*sizeof(WCHAR)));
224 if(SUCCEEDED(hr))
225 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"Title", 0,
226 REG_SZ, (LPBYTE)(GameData->bstrName),
227 (lstrlenW(GameData->bstrName)+1)*sizeof(WCHAR)));
229 if(SUCCEEDED(hr))
230 hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"Description", 0,
231 REG_SZ, (LPBYTE)(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName),
232 (lstrlenW(GameData->bstrDescription ? GameData->bstrDescription : GameData->bstrName)+1)*sizeof(WCHAR)));
234 RegCloseKey(hKey);
236 if(FAILED(hr))
238 /* if something failed, remove whole key */
239 hr2 = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryKey, KEY_WOW64_64KEY, 0);
240 /* do not overwrite old failure code with new success code */
241 if(FAILED(hr2))
242 hr = hr2;
246 free(lpRegistryKey);
247 TRACE("returning 0x%lx\n", hr);
248 return hr;
250 /*******************************************************************************
251 * GAMEUX_ProcessGameDefinitionElement
253 * Helper function, parses single element from Game Definition
255 * Parameters:
256 * lpXMLElement [I] game definition element
257 * GameData [O] structure, where parsed
258 * data will be stored
260 static HRESULT GAMEUX_ProcessGameDefinitionElement(
261 IXMLDOMElement *element,
262 struct GAMEUX_GAME_DATA *GameData)
264 HRESULT hr;
265 BSTR bstrElementName;
267 TRACE("(%p, %p)\n", element, GameData);
269 hr = IXMLDOMElement_get_nodeName(element, &bstrElementName);
270 if(SUCCEEDED(hr))
272 /* check element name */
273 if(lstrcmpW(bstrElementName, L"Name") == 0)
274 hr = IXMLDOMElement_get_text(element, &GameData->bstrName);
276 else if(lstrcmpW(bstrElementName, L"Description") == 0)
277 hr = IXMLDOMElement_get_text(element, &GameData->bstrDescription);
279 else
280 FIXME("entry %s in Game Definition File not yet supported\n", debugstr_w(bstrElementName));
282 SysFreeString(bstrElementName);
285 return hr;
287 /*******************************************************************************
288 * GAMEUX_ParseGameDefinition
290 * Helper function, loads data from given XML element into fields of GAME_DATA
291 * structure
293 * Parameters:
294 * lpXMLGameDefinitionElement [I] Game Definition XML element
295 * GameData [O] structure where data loaded from
296 * XML element will be stored in
298 static HRESULT GAMEUX_ParseGameDefinition(IXMLDOMElement *gamedef, struct GAMEUX_GAME_DATA *game_data)
300 IXMLDOMNodeList *props;
301 VARIANT var;
302 HRESULT hr;
303 BSTR attr;
305 TRACE("(%p, %p)\n", gamedef, game_data);
307 attr = SysAllocString(L"gameID");
308 if (!attr)
309 return E_OUTOFMEMORY;
311 hr = IXMLDOMElement_getAttribute(gamedef, attr, &var);
312 SysFreeString(attr);
314 if (SUCCEEDED(hr))
316 hr = CLSIDFromString(V_BSTR(&var), &game_data->guidApplicationId);
317 VariantClear(&var);
320 if (SUCCEEDED(hr))
321 hr = IXMLDOMElement_get_childNodes(gamedef, &props);
323 if (FAILED(hr))
324 return hr;
328 IXMLDOMNode *prop;
330 hr = IXMLDOMNodeList_nextNode(props, &prop);
331 if (hr == S_OK)
333 IXMLDOMElement *element;
335 hr = IXMLDOMNode_QueryInterface(prop, &IID_IXMLDOMElement, (void**)&element);
336 if (hr == S_OK)
338 hr = GAMEUX_ProcessGameDefinitionElement(element, game_data);
339 IXMLDOMElement_Release(element);
342 IXMLDOMNode_Release(prop);
345 while (hr == S_OK);
346 IXMLDOMNodeList_Release(props);
348 return FAILED(hr) ? hr : S_OK;
351 struct parse_gdf_thread_param
353 struct GAMEUX_GAME_DATA *GameData;
354 HRESULT hr;
357 /*******************************************************************************
358 * GAMEUX_ParseGDFBinary
360 * Helper function, loads given binary and parses embed GDF if there's any.
362 * Parameters:
363 * GameData [I/O] Structure with game's data. Content of field
364 * sGDFBinaryPath defines path to binary, from
365 * which embed GDF will be loaded. Data from
366 * GDF will be stored in other fields of this
367 * structure.
369 static DWORD WINAPI GAMEUX_ParseGDFBinary(void *thread_param)
371 struct parse_gdf_thread_param *ctx = thread_param;
372 struct GAMEUX_GAME_DATA *GameData = ctx->GameData;
374 HRESULT hr = S_OK;
375 WCHAR sResourcePath[MAX_PATH];
376 VARIANT variant;
377 VARIANT_BOOL isSuccessful;
378 IXMLDOMDocument *document;
379 IXMLDOMNode *gdNode;
380 IXMLDOMElement *root, *gdElement;
382 TRACE("(%p)->sGDFBinaryPath = %s\n", GameData, debugstr_w(GameData->sGDFBinaryPath));
384 /* prepare path to GDF, using res:// prefix */
385 lstrcpyW(sResourcePath, L"res://");
386 lstrcatW(sResourcePath, GameData->sGDFBinaryPath);
387 lstrcatW(sResourcePath, L"/DATA/");
388 lstrcatW(sResourcePath, ID_GDF_XML_STR);
390 CoInitialize(NULL);
392 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
393 &IID_IXMLDOMDocument, (void**)&document);
395 if(SUCCEEDED(hr))
397 /* load GDF into MSXML */
398 V_VT(&variant) = VT_BSTR;
399 V_BSTR(&variant) = SysAllocString(sResourcePath);
400 if(!V_BSTR(&variant))
401 hr = E_OUTOFMEMORY;
403 if(SUCCEEDED(hr))
405 hr = IXMLDOMDocument_load(document, variant, &isSuccessful);
406 if(hr == S_FALSE || isSuccessful == VARIANT_FALSE)
407 hr = E_FAIL;
410 SysFreeString(V_BSTR(&variant));
412 if(SUCCEEDED(hr))
414 hr = IXMLDOMDocument_get_documentElement(document, &root);
415 if(hr == S_FALSE)
416 hr = E_FAIL;
419 if(SUCCEEDED(hr))
421 hr = IXMLDOMElement_get_firstChild(root, &gdNode);
422 if(hr == S_FALSE)
423 hr = E_FAIL;
425 if(SUCCEEDED(hr))
427 hr = IXMLDOMNode_QueryInterface(gdNode, &IID_IXMLDOMElement, (LPVOID*)&gdElement);
428 if(SUCCEEDED(hr))
430 hr = GAMEUX_ParseGameDefinition(gdElement, GameData);
431 IXMLDOMElement_Release(gdElement);
434 IXMLDOMNode_Release(gdNode);
437 IXMLDOMElement_Release(root);
440 IXMLDOMDocument_Release(document);
443 CoUninitialize();
444 ctx->hr = hr;
445 return 0;
448 /*******************************************************************
449 * GAMEUX_RemoveRegistryRecord
451 * Helper function, removes registry key associated with given game instance
453 static HRESULT GAMEUX_RemoveRegistryRecord(GUID* pInstanceID)
455 HRESULT hr;
456 LPWSTR lpRegistryPath = NULL;
457 TRACE("(%s)\n", debugstr_guid(pInstanceID));
459 /* first, check is game installed for all users */
460 hr = GAMEUX_buildGameRegistryPath(GIS_ALL_USERS, pInstanceID, &lpRegistryPath);
461 if(SUCCEEDED(hr))
462 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
464 free(lpRegistryPath);
466 /* if not, check current user */
467 if(FAILED(hr))
469 hr = GAMEUX_buildGameRegistryPath(GIS_CURRENT_USER, pInstanceID, &lpRegistryPath);
470 if(SUCCEEDED(hr))
471 hr = HRESULT_FROM_WIN32(RegDeleteKeyExW(HKEY_LOCAL_MACHINE, lpRegistryPath, KEY_WOW64_64KEY, 0));
473 free(lpRegistryPath);
476 return hr;
478 /*******************************************************************************
479 * GAMEUX_RegisterGame
481 * Internal helper function. Registers game associated with given GDF binary in
482 * Game Explorer. Implemented in gameexplorer.c
484 * Parameters:
485 * sGDFBinaryPath [I] path to binary containing GDF file in
486 * resources
487 * sGameInstallDirectory [I] path to directory, where game installed
488 * its files.
489 * installScope [I] scope of game installation
490 * pInstanceID [I/O] pointer to game instance identifier.
491 * If pointing to GUID_NULL, then new
492 * identifier will be generated automatically
493 * and returned via this parameter
495 static HRESULT GAMEUX_RegisterGame(LPCWSTR sGDFBinaryPath,
496 LPCWSTR sGameInstallDirectory,
497 GAME_INSTALL_SCOPE installScope,
498 GUID *pInstanceID)
500 HRESULT hr = S_OK;
501 struct GAMEUX_GAME_DATA GameData;
503 TRACE("(%s, %s, 0x%x, %s)\n", debugstr_w(sGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
505 GAMEUX_initGameData(&GameData);
506 GameData.sGDFBinaryPath = wcsdup(sGDFBinaryPath);
507 GameData.sGameInstallDirectory = wcsdup(sGameInstallDirectory);
508 GameData.installScope = installScope;
510 /* generate GUID if it was not provided by user */
511 if(IsEqualGUID(pInstanceID, &GUID_NULL))
512 hr = CoCreateGuid(pInstanceID);
514 GameData.guidInstanceId = *pInstanceID;
516 /* load data from GDF binary */
517 if(SUCCEEDED(hr))
519 struct parse_gdf_thread_param thread_param;
520 HANDLE thread;
521 DWORD ret;
523 thread_param.GameData = &GameData;
524 if(!(thread = CreateThread(NULL, 0, GAMEUX_ParseGDFBinary, &thread_param, 0, &ret)))
526 ERR("Failed to create thread.\n");
527 hr = E_FAIL;
528 goto done;
530 ret = WaitForSingleObject(thread, INFINITE);
531 CloseHandle(thread);
532 if(ret != WAIT_OBJECT_0)
534 ERR("Wait failed (%#lx).\n", ret);
535 hr = E_FAIL;
536 goto done;
538 hr = thread_param.hr;
541 /* save data to registry */
542 if(SUCCEEDED(hr))
543 hr = GAMEUX_WriteRegistryRecord(&GameData);
545 done:
546 GAMEUX_uninitGameData(&GameData);
547 TRACE("returning 0x%08lx\n", hr);
548 return hr;
550 /*******************************************************************************
551 * GAMEUX_IsGameKeyExist
553 * Helper function, checks if game's registry ath exists in given scope
555 * Parameters:
556 * installScope [I] scope to search game in
557 * InstanceID [I] game instance identifier
558 * lpRegistryPath [O] place to store address of registry path to
559 * the game. It is filled only if key exists.
560 * It must be freed by free(...)
562 * Returns:
563 * S_OK key was found properly
564 * S_FALSE key does not exists
567 static HRESULT GAMEUX_IsGameKeyExist(GAME_INSTALL_SCOPE installScope,
568 LPCGUID InstanceID,
569 LPWSTR* lpRegistryPath) {
571 HRESULT hr;
572 HKEY hKey;
574 hr = GAMEUX_buildGameRegistryPath(installScope, InstanceID, lpRegistryPath);
576 if(SUCCEEDED(hr))
577 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE, *lpRegistryPath,
578 0, KEY_WOW64_64KEY, &hKey));
580 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
581 hr = S_FALSE;
583 if(hr == S_OK)
584 RegCloseKey(hKey);
585 else
587 /* if the key does not exist or another error occurred, do not return the path */
588 free(*lpRegistryPath);
589 *lpRegistryPath = NULL;
592 return hr;
594 /*******************************************************************************
595 * GAMEUX_LoadRegistryString
597 * Helper function, loads string from registry value and allocates buffer for it
599 static HRESULT GAMEUX_LoadRegistryString(HKEY hRootKey,
600 LPCWSTR lpRegistryKey,
601 LPCWSTR lpRegistryValue,
602 LPWSTR* lpValue)
604 HRESULT hr;
605 DWORD dwSize;
607 *lpValue = NULL;
609 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
610 RRF_RT_REG_SZ, NULL, NULL, &dwSize));
612 if(SUCCEEDED(hr))
614 *lpValue = malloc(dwSize);
615 if(!*lpValue)
616 hr = E_OUTOFMEMORY;
619 if(SUCCEEDED(hr))
620 hr = HRESULT_FROM_WIN32(RegGetValueW(hRootKey, lpRegistryKey, lpRegistryValue,
621 RRF_RT_REG_SZ, NULL, *lpValue, &dwSize));
623 return hr;
625 /*******************************************************************************
626 * GAMEUX_UpdateGame
628 * Helper function, updates stored data about game with given InstanceID
630 static HRESULT GAMEUX_UpdateGame(LPGUID InstanceID) {
631 HRESULT hr;
632 GAME_INSTALL_SCOPE installScope;
633 LPWSTR lpRegistryPath;
634 LPWSTR lpGDFBinaryPath;
636 TRACE("(%s)\n", debugstr_guid(InstanceID));
638 /* first, check is game exists in CURRENT_USER scope */
639 installScope = GIS_CURRENT_USER;
640 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
642 if(hr == S_FALSE)
644 /* game not found in CURRENT_USER scope, let's check in ALL_USERS */
645 installScope = GIS_ALL_USERS;
646 hr = GAMEUX_IsGameKeyExist(installScope, InstanceID, &lpRegistryPath);
649 if(hr == S_FALSE)
650 /* still not found? let's inform user that game does not exists */
651 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
653 if(SUCCEEDED(hr))
655 WCHAR *lpGameInstallDirectory = NULL;
657 /* game found, its registry path is in lpRegistryPath and install
658 * scope in installScope */
659 TRACE("game found in registry (path %s), updating\n", debugstr_w(lpRegistryPath));
661 /* first, read required data about game */
662 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
663 L"ConfigGDFBinaryPath", &lpGDFBinaryPath);
665 if(SUCCEEDED(hr))
666 hr = GAMEUX_LoadRegistryString(HKEY_LOCAL_MACHINE, lpRegistryPath,
667 L"ConfigApplicationPath", &lpGameInstallDirectory);
669 /* now remove currently existing registry key */
670 if(SUCCEEDED(hr))
671 hr = GAMEUX_RemoveRegistryRecord(InstanceID);
673 /* and add it again, it will cause in reparsing of whole GDF */
674 if(SUCCEEDED(hr))
675 hr = GAMEUX_RegisterGame(lpGDFBinaryPath, lpGameInstallDirectory,
676 installScope, InstanceID);
678 free(lpGDFBinaryPath);
679 free(lpGameInstallDirectory);
682 free(lpRegistryPath);
683 TRACE("returning 0x%lx\n", hr);
684 return hr;
686 /*******************************************************************************
687 * GAMEUX_FindGameInstanceId
689 * Internal helper function. Description available in gameux_private.h file
691 HRESULT GAMEUX_FindGameInstanceId(
692 LPCWSTR sGDFBinaryPath,
693 GAME_INSTALL_SCOPE installScope,
694 GUID* pInstanceId)
696 HRESULT hr;
697 BOOL found = FALSE;
698 LPWSTR lpRegistryPath = NULL;
699 HKEY hRootKey;
700 DWORD dwSubKeys, dwSubKeyLen, dwMaxSubKeyLen, i;
701 LPWSTR lpName = NULL, lpValue = NULL;
703 hr = GAMEUX_buildGameRegistryPath(installScope, NULL, &lpRegistryPath);
705 if(SUCCEEDED(hr))
706 /* enumerate all subkeys of received one and search them for value "ConfigGGDFBinaryPath" */
707 hr = HRESULT_FROM_WIN32(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
708 lpRegistryPath, 0, KEY_READ | KEY_WOW64_64KEY, &hRootKey));
710 if(SUCCEEDED(hr))
712 hr = HRESULT_FROM_WIN32(RegQueryInfoKeyW(hRootKey, NULL, NULL, NULL,
713 &dwSubKeys, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL));
715 if(SUCCEEDED(hr))
717 ++dwMaxSubKeyLen; /* for string terminator */
718 lpName = malloc(dwMaxSubKeyLen * sizeof(WCHAR));
719 if(!lpName) hr = E_OUTOFMEMORY;
722 if(SUCCEEDED(hr))
724 for(i=0; i<dwSubKeys && !found; ++i)
726 dwSubKeyLen = dwMaxSubKeyLen;
727 hr = HRESULT_FROM_WIN32(RegEnumKeyExW(hRootKey, i, lpName, &dwSubKeyLen,
728 NULL, NULL, NULL, NULL));
730 if(SUCCEEDED(hr))
731 hr = GAMEUX_LoadRegistryString(hRootKey, lpName,
732 L"ConfigGDFBinaryPath", &lpValue);
734 if(SUCCEEDED(hr))
736 if(lstrcmpW(lpValue, sGDFBinaryPath)==0)
738 /* key found, let's copy instance id and exit */
739 hr = CLSIDFromString(lpName, pInstanceId);
740 found = TRUE;
742 free(lpValue);
747 free(lpName);
748 RegCloseKey(hRootKey);
751 free(lpRegistryPath);
753 if((SUCCEEDED(hr) && !found) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
754 hr = S_FALSE;
756 return hr;
758 /*******************************************************************************
759 * GameExplorer implementation
762 typedef struct _GameExplorerImpl
764 IGameExplorer IGameExplorer_iface;
765 IGameExplorer2 IGameExplorer2_iface;
766 LONG ref;
767 } GameExplorerImpl;
769 static inline GameExplorerImpl *impl_from_IGameExplorer(IGameExplorer *iface)
771 return CONTAINING_RECORD(iface, GameExplorerImpl, IGameExplorer_iface);
774 static inline GameExplorerImpl *impl_from_IGameExplorer2(IGameExplorer2 *iface)
776 return CONTAINING_RECORD(iface, GameExplorerImpl, IGameExplorer2_iface);
779 static HRESULT WINAPI GameExplorerImpl_QueryInterface(
780 IGameExplorer *iface,
781 REFIID riid,
782 void **ppvObject)
784 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
786 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
788 *ppvObject = NULL;
790 if(IsEqualGUID(riid, &IID_IUnknown) ||
791 IsEqualGUID(riid, &IID_IGameExplorer))
793 *ppvObject = &This->IGameExplorer_iface;
795 else if(IsEqualGUID(riid, &IID_IGameExplorer2))
797 *ppvObject = &This->IGameExplorer2_iface;
799 else
801 FIXME("interface %s not implemented\n", debugstr_guid(riid));
802 return E_NOINTERFACE;
805 IGameExplorer_AddRef(iface);
806 return S_OK;
809 static ULONG WINAPI GameExplorerImpl_AddRef(IGameExplorer *iface)
811 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
812 LONG ref;
814 ref = InterlockedIncrement(&This->ref);
816 TRACE("(%p): ref=%ld\n", This, ref);
817 return ref;
820 static ULONG WINAPI GameExplorerImpl_Release(IGameExplorer *iface)
822 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
823 LONG ref;
825 ref = InterlockedDecrement(&This->ref);
826 TRACE("(%p): ref=%ld\n", This, ref);
828 if(ref == 0)
830 TRACE("freeing GameExplorer object\n");
831 free(This);
834 return ref;
837 static HRESULT WINAPI GameExplorerImpl_AddGame(
838 IGameExplorer *iface,
839 BSTR bstrGDFBinaryPath,
840 BSTR sGameInstallDirectory,
841 GAME_INSTALL_SCOPE installScope,
842 GUID *pInstanceID)
844 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
845 TRACE("(%p, %s, %s, 0x%x, %s)\n", This, debugstr_w(bstrGDFBinaryPath), debugstr_w(sGameInstallDirectory), installScope, debugstr_guid(pInstanceID));
846 return GAMEUX_RegisterGame(bstrGDFBinaryPath, sGameInstallDirectory, installScope, pInstanceID);
849 static HRESULT WINAPI GameExplorerImpl_RemoveGame(
850 IGameExplorer *iface,
851 GUID instanceID)
853 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
855 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
856 return GAMEUX_RemoveRegistryRecord(&instanceID);
859 static HRESULT WINAPI GameExplorerImpl_UpdateGame(
860 IGameExplorer *iface,
861 GUID instanceID)
863 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
865 TRACE("(%p, %s)\n", This, debugstr_guid(&instanceID));
866 return GAMEUX_UpdateGame(&instanceID);
869 static HRESULT WINAPI GameExplorerImpl_VerifyAccess(
870 IGameExplorer *iface,
871 BSTR sGDFBinaryPath,
872 BOOL *pHasAccess)
874 GameExplorerImpl *This = impl_from_IGameExplorer(iface);
876 FIXME("(%p, %s, %p)\n", This, debugstr_w(sGDFBinaryPath), pHasAccess);
877 *pHasAccess = TRUE;
878 return S_OK;
881 static const struct IGameExplorerVtbl GameExplorerImplVtbl =
883 GameExplorerImpl_QueryInterface,
884 GameExplorerImpl_AddRef,
885 GameExplorerImpl_Release,
886 GameExplorerImpl_AddGame,
887 GameExplorerImpl_RemoveGame,
888 GameExplorerImpl_UpdateGame,
889 GameExplorerImpl_VerifyAccess
893 static HRESULT WINAPI GameExplorer2Impl_QueryInterface(
894 IGameExplorer2 *iface,
895 REFIID riid,
896 void **ppvObject)
898 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
899 return GameExplorerImpl_QueryInterface(&This->IGameExplorer_iface, riid, ppvObject);
902 static ULONG WINAPI GameExplorer2Impl_AddRef(IGameExplorer2 *iface)
904 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
905 return GameExplorerImpl_AddRef(&This->IGameExplorer_iface);
908 static ULONG WINAPI GameExplorer2Impl_Release(IGameExplorer2 *iface)
910 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
911 return GameExplorerImpl_Release(&This->IGameExplorer_iface);
914 static HRESULT WINAPI GameExplorer2Impl_CheckAccess(
915 IGameExplorer2 *iface,
916 LPCWSTR binaryGDFPath,
917 BOOL *pHasAccess)
919 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
920 FIXME("stub (%p, %s, %p)\n", This, debugstr_w(binaryGDFPath), pHasAccess);
921 return E_NOTIMPL;
924 static HRESULT WINAPI GameExplorer2Impl_InstallGame(
925 IGameExplorer2 *iface,
926 LPCWSTR binaryGDFPath,
927 LPCWSTR installDirectory,
928 GAME_INSTALL_SCOPE installScope)
930 HRESULT hr;
931 GUID instanceId;
932 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
934 TRACE("(%p, %s, %s, 0x%x)\n", This, debugstr_w(binaryGDFPath), debugstr_w(installDirectory), installScope);
936 if(!binaryGDFPath)
937 return E_INVALIDARG;
939 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
941 if(hr == S_FALSE)
942 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
944 if(hr == S_FALSE)
946 /* if game isn't yet registered, then install it */
947 instanceId = GUID_NULL;
948 hr = GAMEUX_RegisterGame(binaryGDFPath, installDirectory, installScope, &instanceId);
950 else if(hr == S_OK)
951 /* otherwise, update game */
952 hr = GAMEUX_UpdateGame(&instanceId);
954 return hr;
957 static HRESULT WINAPI GameExplorer2Impl_UninstallGame(
958 IGameExplorer2 *iface,
959 LPCWSTR binaryGDFPath)
961 HRESULT hr;
962 GUID instanceId;
963 GameExplorerImpl *This = impl_from_IGameExplorer2(iface);
964 TRACE("(%p, %s)\n", This, debugstr_w(binaryGDFPath));
966 if(!binaryGDFPath)
967 return E_INVALIDARG;
969 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_CURRENT_USER, &instanceId);
971 if(hr == S_FALSE)
972 hr = GAMEUX_FindGameInstanceId(binaryGDFPath, GIS_ALL_USERS, &instanceId);
974 if(hr == S_OK)
975 hr = GAMEUX_RemoveRegistryRecord(&instanceId);
977 return hr;
980 static const struct IGameExplorer2Vtbl GameExplorer2ImplVtbl =
982 GameExplorer2Impl_QueryInterface,
983 GameExplorer2Impl_AddRef,
984 GameExplorer2Impl_Release,
985 GameExplorer2Impl_InstallGame,
986 GameExplorer2Impl_UninstallGame,
987 GameExplorer2Impl_CheckAccess
991 * Construction routine
993 HRESULT GameExplorer_create(
994 IUnknown* pUnkOuter,
995 IUnknown** ppObj)
997 GameExplorerImpl *pGameExplorer;
999 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
1001 pGameExplorer = malloc(sizeof(*pGameExplorer));
1003 if(!pGameExplorer)
1004 return E_OUTOFMEMORY;
1006 pGameExplorer->IGameExplorer_iface.lpVtbl = &GameExplorerImplVtbl;
1007 pGameExplorer->IGameExplorer2_iface.lpVtbl = &GameExplorer2ImplVtbl;
1008 pGameExplorer->ref = 1;
1010 *ppObj = (IUnknown*)&pGameExplorer->IGameExplorer_iface;
1012 TRACE("returning iface: %p\n", *ppObj);
1013 return S_OK;