crypt32/tests: CertAddCertificateLinkToStore is not present on W98.
[wine/multimedia.git] / dlls / gameux / gamestatistics.c
blobbedcfd2ac2b4471205bb50ad5416b59e0f0e82fb
1 /*
2 * Gameux library coclass GameStatistics 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 "winreg.h"
26 #include "msxml2.h"
27 #include "shlwapi.h"
28 #include "shlobj.h"
30 #include "gameux.h"
31 #include "gameux_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gameux);
38 * constant definitions
40 #define MAX_CATEGORY_LENGTH 60
41 #define MAX_NAME_LENGTH 30
42 #define MAX_VALUE_LENGTH 30
43 #define MAX_CATEGORIES 10
44 #define MAX_STATS_PER_CATEGORY 10
45 /*******************************************************************************
46 * Game statistics helper components
48 /*******************************************************************************
49 * struct GAMEUX_STATS
51 * set of structures for containing game's data
53 struct GAMEUX_STATS_STAT
55 WCHAR sName[MAX_NAME_LENGTH+1];
56 WCHAR sValue[MAX_VALUE_LENGTH+1];
58 struct GAMEUX_STATS_CATEGORY
60 WCHAR sName[MAX_CATEGORY_LENGTH+1];
61 struct GAMEUX_STATS_STAT stats[MAX_STATS_PER_CATEGORY];
63 struct GAMEUX_STATS
65 WCHAR sStatsFile[MAX_PATH];
66 struct GAMEUX_STATS_CATEGORY categories[MAX_CATEGORIES];
68 /*******************************************************************************
69 * GAMEUX_createStatsDirectory
71 * Helper function, creates directory to store game statistics
73 * Parameters
74 * path [I] path to game statistics file.
75 * base directory of this file will
76 * be created if it doesn't exists
78 static HRESULT GAMEUX_createStatsDirectory(LPCWSTR lpFilePath)
80 HRESULT hr;
81 WCHAR lpDirectoryPath[MAX_PATH];
82 LPCWSTR lpEnd;
84 lpEnd = StrRChrW(lpFilePath, NULL, '\\');
85 lstrcpynW(lpDirectoryPath, lpFilePath, lpEnd-lpFilePath+1);
87 hr = HRESULT_FROM_WIN32(SHCreateDirectoryExW(NULL, lpDirectoryPath, NULL));
89 if(hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) ||
90 hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
91 hr = S_FALSE;
93 return hr;
95 /*******************************************************************
96 * GAMEUX_updateStatisticsFile
98 * Helper function updating data stored in statistics file
100 * Parameters:
101 * data [I] pointer to struct containing
102 * statistics data
104 static HRESULT GAMEUX_updateStatisticsFile(struct GAMEUX_STATS *stats)
106 static const WCHAR sStatistics[] = {'S','t','a','t','i','s','t','i','c','s',0};
107 static const WCHAR sCategory[] = {'C','a','t','e','g','o','r','y',0};
108 static const WCHAR sIndex[] = {'I','n','d','e','x',0};
109 static const WCHAR sStatistic[] = {'S','t','a','t','i','s','t','i','c',0};
110 static const WCHAR sName[] = {'N','a','m','e',0};
111 static const WCHAR sValue[] = {'V','a','l','u','e',0};
113 HRESULT hr = S_OK;
114 IXMLDOMDocument *document;
115 IXMLDOMElement *root, *categoryElement, *statisticsElement;
116 IXMLDOMNode *categoryNode, *statisticsNode;
117 VARIANT vStatsFilePath, vValue;
118 BSTR bstrStatistics = NULL, bstrCategory = NULL, bstrIndex = NULL,
119 bstrStatistic = NULL, bstrName = NULL, bstrValue = NULL;
120 int i, j;
122 TRACE("(%p)\n", stats);
124 V_VT(&vStatsFilePath) = VT_BSTR;
125 V_BSTR(&vStatsFilePath) = SysAllocString(stats->sStatsFile);
126 if(!V_BSTR(&vStatsFilePath))
127 hr = E_OUTOFMEMORY;
129 if(SUCCEEDED(hr))
130 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
131 &IID_IXMLDOMDocument, (void**)&document);
133 if(SUCCEEDED(hr))
135 bstrStatistics = SysAllocString(sStatistics);
136 if(!bstrStatistics)
137 hr = E_OUTOFMEMORY;
140 if(SUCCEEDED(hr))
141 hr = IXMLDOMDocument_createElement(document, bstrStatistics, &root);
143 if(SUCCEEDED(hr))
145 bstrCategory = SysAllocString(sCategory);
146 if(!bstrCategory)
147 hr = E_OUTOFMEMORY;
150 if(SUCCEEDED(hr))
152 bstrIndex = SysAllocString(sIndex);
153 if(!bstrIndex)
154 hr = E_OUTOFMEMORY;
157 if(SUCCEEDED(hr))
159 bstrStatistic = SysAllocString(sStatistic);
160 if(!bstrStatistic)
161 hr = E_OUTOFMEMORY;
164 if(SUCCEEDED(hr))
166 bstrName = SysAllocString(sName);
167 if(!bstrName)
168 hr = E_OUTOFMEMORY;
171 if(SUCCEEDED(hr))
173 bstrValue = SysAllocString(sValue);
174 if(!bstrValue)
175 hr = E_OUTOFMEMORY;
178 if(SUCCEEDED(hr))
180 if(SUCCEEDED(hr))
181 for(i=0; i<MAX_CATEGORIES; ++i)
183 if(lstrlenW(stats->categories[i].sName)==0)
184 continue;
186 V_VT(&vValue) = VT_INT;
187 V_INT(&vValue) = NODE_ELEMENT;
189 hr = IXMLDOMDocument_createNode(document, vValue, bstrCategory, NULL, &categoryNode);
191 if(SUCCEEDED(hr))
192 hr = IXMLDOMNode_QueryInterface(categoryNode, &IID_IXMLDOMElement, (LPVOID*)&categoryElement);
194 V_INT(&vValue) = i;
195 if(SUCCEEDED(hr))
196 hr = IXMLDOMElement_setAttribute(categoryElement, bstrIndex, vValue);
198 if(SUCCEEDED(hr))
200 V_VT(&vValue) = VT_BSTR;
201 V_BSTR(&vValue) = SysAllocString(stats->categories[i].sName);
202 if(!V_BSTR(&vValue))
203 hr = E_OUTOFMEMORY;
206 if(SUCCEEDED(hr))
208 TRACE("storing category %d: %s\n", i, debugstr_w(V_BSTR(&vValue)));
209 hr = IXMLDOMElement_setAttribute(categoryElement, bstrName, vValue);
212 SysFreeString(V_BSTR(&vValue));
214 if(SUCCEEDED(hr))
216 for(j=0; j<MAX_STATS_PER_CATEGORY; ++j)
218 if(lstrlenW(stats->categories[i].stats[j].sName)==0)
219 continue;
221 V_VT(&vValue) = VT_INT;
222 V_INT(&vValue) = NODE_ELEMENT;
224 hr = IXMLDOMDocument_createNode(document, vValue, bstrStatistic, NULL, &statisticsNode);
226 if(SUCCEEDED(hr))
227 hr = IXMLDOMNode_QueryInterface(statisticsNode, &IID_IXMLDOMElement, (LPVOID*)&statisticsElement);
229 V_INT(&vValue) = j;
230 if(SUCCEEDED(hr))
231 hr = IXMLDOMElement_setAttribute(statisticsElement, bstrIndex, vValue);
233 if(SUCCEEDED(hr))
235 V_VT(&vValue) = VT_BSTR;
236 V_BSTR(&vValue) = SysAllocString(stats->categories[i].stats[j].sName);
237 if(!V_BSTR(&vValue))
238 hr = E_OUTOFMEMORY;
241 if(SUCCEEDED(hr))
243 TRACE(" storing statistic %d: name: %s\n", j, debugstr_w(V_BSTR(&vValue)));
244 hr = IXMLDOMElement_setAttribute(statisticsElement, bstrName, vValue);
247 SysFreeString(V_BSTR(&vValue));
249 if(SUCCEEDED(hr))
251 V_VT(&vValue) = VT_BSTR;
252 V_BSTR(&vValue) = SysAllocString(stats->categories[i].stats[j].sValue);
253 if(!V_BSTR(&vValue))
254 hr = E_OUTOFMEMORY;
257 if(SUCCEEDED(hr))
259 TRACE(" storing statistic %d: name: %s\n", j, debugstr_w(V_BSTR(&vValue)));
260 hr = IXMLDOMElement_setAttribute(statisticsElement, bstrValue, vValue);
263 SysFreeString(V_BSTR(&vValue));
265 if(SUCCEEDED(hr))
266 hr = IXMLDOMElement_appendChild(categoryNode, statisticsNode, &statisticsNode);
268 IXMLDOMElement_Release(statisticsElement);
269 IXMLDOMNode_Release(statisticsNode);
273 if(SUCCEEDED(hr))
274 hr = IXMLDOMElement_appendChild(root, categoryNode, &categoryNode);
276 IXMLDOMElement_Release(categoryElement);
277 IXMLDOMNode_Release(categoryNode);
279 if(FAILED(hr))
280 break;
283 if(SUCCEEDED(hr))
284 hr = IXMLDOMDocument_putref_documentElement(document, root);
286 IXMLDOMElement_Release(root);
288 TRACE("saving game statistics in %s file\n", debugstr_w(stats->sStatsFile));
289 if(SUCCEEDED(hr))
290 hr = GAMEUX_createStatsDirectory(stats->sStatsFile);
292 if(SUCCEEDED(hr))
293 hr = IXMLDOMDocument_save(document, vStatsFilePath);
295 IXMLDOMDocument_Release(document);
297 SysFreeString(bstrValue);
298 SysFreeString(bstrName);
299 SysFreeString(bstrStatistic);
300 SysFreeString(bstrIndex);
301 SysFreeString(bstrCategory);
302 SysFreeString(bstrStatistics);
303 SysFreeString(V_BSTR(&vStatsFilePath));
304 TRACE("ret=0x%x\n", hr);
305 return hr;
307 /*******************************************************************************
308 * GAMEUX_buildStatisticsFilePath
309 * Creates path to file contaning statistics of game with given id.
311 * Parameters:
312 * lpApplicationId [I] application id of game,
313 * as string
314 * lpStatisticsFile [O] array where path will be
315 * stored. It's size must be
316 * at least MAX_PATH
318 static HRESULT GAMEUX_buildStatisticsFilePath(
319 LPCWSTR lpApplicationId,
320 LPWSTR lpStatisticsFile)
322 static const WCHAR sBackslash[] = {'\\',0};
323 static const WCHAR sStatisticsDir[] = {'\\','M','i','c','r','o','s','o','f','t',
324 '\\','W','i','n','d','o','w','s','\\','G','a','m','e','E','x','p',
325 'l','o','r','e','r','\\','G','a','m','e','S','t','a','t','i','s',
326 't','i','c','s',0};
327 static const WCHAR sDotGamestats[] = {'.','g','a','m','e','s','t','a','t','s',0};
329 HRESULT hr;
331 hr = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, lpStatisticsFile);
333 if(SUCCEEDED(hr))
335 lstrcatW(lpStatisticsFile, sStatisticsDir);
336 lstrcatW(lpStatisticsFile, lpApplicationId);
337 lstrcatW(lpStatisticsFile, sBackslash);
338 lstrcatW(lpStatisticsFile, lpApplicationId);
339 lstrcatW(lpStatisticsFile, sDotGamestats);
342 return hr;
344 /*******************************************************************************
345 * GAMEUX_getAppIdFromGDFPath
347 * Loads application identifier associated with given GDF binary.
348 * Routine reads identifier from registry, so will fail if game
349 * is not registered.
351 * Parameters:
352 * GDFBinaryPath [I] path to gdf binary
353 * lpApplicationId [O] place to store application id.
354 * must be at least 49 characters
355 * to store guid and termination 0
357 static HRESULT GAMEUX_getAppIdFromGDFPath(
358 LPCWSTR GDFBinaryPath,
359 LPWSTR lpApplicationId)
361 static const WCHAR sApplicationId[] =
362 {'A','p','p','l','i','c','a','t','i','o','n','I','d',0};
364 HRESULT hr;
365 GAME_INSTALL_SCOPE installScope;
366 GUID instanceId;
367 LPWSTR lpRegistryPath;
368 DWORD dwLength = 49*sizeof(WCHAR);/* place for GUID */
370 TRACE("(%s, %p)\n", debugstr_w(GDFBinaryPath), lpApplicationId);
372 if(!GDFBinaryPath)
373 return E_INVALIDARG;
375 installScope = GIS_CURRENT_USER;
376 hr = GAMEUX_FindGameInstanceId(GDFBinaryPath, installScope, &instanceId);
378 if(hr == S_FALSE)
380 installScope = GIS_ALL_USERS;
381 hr = GAMEUX_FindGameInstanceId(GDFBinaryPath, installScope, &instanceId);
384 if(hr == S_FALSE)
385 /* game not registered, so statistics cannot be used */
386 hr = E_FAIL;
388 if(SUCCEEDED(hr))
389 /* game is registered, let's read it's application id from registry */
390 hr = GAMEUX_buildGameRegistryPath(installScope, &instanceId, &lpRegistryPath);
392 if(SUCCEEDED(hr))
393 hr = HRESULT_FROM_WIN32(RegGetValueW(HKEY_LOCAL_MACHINE,
394 lpRegistryPath, sApplicationId, RRF_RT_REG_SZ,
395 NULL, lpApplicationId, &dwLength));
397 HeapFree(GetProcessHeap(), 0, lpRegistryPath);
399 TRACE("found app id: %s, return: %#x\n", debugstr_w(lpApplicationId), hr);
400 return hr;
402 /*******************************************************************
403 * IGameStatistics implementation
405 typedef struct _GameStatisticsImpl
407 const struct IGameStatisticsVtbl *lpVtbl;
408 LONG ref;
409 struct GAMEUX_STATS stats;
410 } GameStatisticsImpl;
412 static inline GameStatisticsImpl *impl_from_IGameStatistics( IGameStatistics *iface )
414 return (GameStatisticsImpl *)((char*)iface - FIELD_OFFSET(GameStatisticsImpl, lpVtbl));
416 static inline IGameStatistics *IGameStatistics_from_impl( GameStatisticsImpl* This )
418 return (struct IGameStatistics*)&This->lpVtbl;
422 static HRESULT WINAPI GameStatisticsImpl_QueryInterface(
423 IGameStatistics *iface,
424 REFIID riid,
425 void **ppvObject)
427 GameStatisticsImpl *This = impl_from_IGameStatistics( iface );
429 TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
431 *ppvObject = NULL;
433 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
434 IsEqualGUID( riid, &IID_IGameStatistics ) )
436 *ppvObject = iface;
438 else
440 FIXME("interface %s not implemented\n", debugstr_guid(riid));
441 return E_NOINTERFACE;
444 IGameStatistics_AddRef( iface );
445 return S_OK;
448 static ULONG WINAPI GameStatisticsImpl_AddRef(IGameStatistics *iface)
450 GameStatisticsImpl *This = impl_from_IGameStatistics( iface );
451 LONG ref;
453 ref = InterlockedIncrement(&This->ref);
455 TRACE("(%p): ref=%d\n", This, ref);
456 return ref;
459 static ULONG WINAPI GameStatisticsImpl_Release(IGameStatistics *iface)
461 GameStatisticsImpl *This = impl_from_IGameStatistics( iface );
462 LONG ref;
464 ref = InterlockedDecrement( &This->ref );
465 TRACE("(%p): ref=%d\n", This, ref);
467 if ( ref == 0 )
469 TRACE("freeing IGameStatistics\n");
470 HeapFree( GetProcessHeap(), 0, This );
473 return ref;
476 static HRESULT WINAPI GameStatisticsImpl_GetMaxCategoryLength(
477 IGameStatistics *iface,
478 UINT *cch)
480 TRACE("(%p, %p)\n", iface, cch);
481 if(!cch)
482 return E_INVALIDARG;
484 *cch = MAX_CATEGORY_LENGTH;
485 return S_OK;
488 static HRESULT WINAPI GameStatisticsImpl_GetMaxNameLength(
489 IGameStatistics *iface,
490 UINT *cch)
492 TRACE("(%p, %p)\n", iface, cch);
493 if(!cch)
494 return E_INVALIDARG;
496 *cch = MAX_NAME_LENGTH;
497 return S_OK;
500 static HRESULT WINAPI GameStatisticsImpl_GetMaxValueLength(
501 IGameStatistics *iface,
502 UINT *cch)
504 TRACE("(%p, %p)\n", iface, cch);
505 if(!cch)
506 return E_INVALIDARG;
508 *cch = MAX_VALUE_LENGTH;
509 return S_OK;
512 static HRESULT WINAPI GameStatisticsImpl_GetMaxCategories(
513 IGameStatistics *iface,
514 WORD *pMax)
516 TRACE("(%p, %p)\n", iface, pMax);
517 if(!pMax)
518 return E_INVALIDARG;
520 *pMax = MAX_CATEGORIES;
521 return S_OK;
524 static HRESULT WINAPI GameStatisticsImpl_GetMaxStatsPerCategory(
525 IGameStatistics *iface,
526 WORD *pMax)
528 TRACE("(%p, %p)\n", iface, pMax);
529 if(!pMax)
530 return E_INVALIDARG;
532 *pMax = MAX_STATS_PER_CATEGORY;
533 return S_OK;
536 static HRESULT WINAPI GameStatisticsImpl_SetCategoryTitle(
537 IGameStatistics *iface,
538 WORD categoryIndex,
539 LPCWSTR title)
541 HRESULT hr = S_OK;
542 DWORD dwLength;
543 GameStatisticsImpl *This = impl_from_IGameStatistics(iface);
545 TRACE("(%p, %d, %s)\n", This, categoryIndex, debugstr_w(title));
547 if(!title || categoryIndex >= MAX_CATEGORIES)
548 return E_INVALIDARG;
550 dwLength = lstrlenW(title);
552 if(dwLength > MAX_CATEGORY_LENGTH)
554 hr = S_FALSE;
555 dwLength = MAX_CATEGORY_LENGTH;
558 lstrcpynW(This->stats.categories[categoryIndex].sName,
559 title, dwLength+1);
561 return hr;
564 static HRESULT WINAPI GameStatisticsImpl_GetCategoryTitle(
565 IGameStatistics *iface,
566 WORD categoryIndex,
567 LPWSTR *pTitle)
569 FIXME("stub\n");
570 return E_NOTIMPL;
573 static HRESULT WINAPI GameStatisticsImpl_GetStatistic(
574 IGameStatistics *iface,
575 WORD categoryIndex,
576 WORD statIndex,
577 LPWSTR *pName,
578 LPWSTR *pValue)
580 FIXME("stub\n");
581 return E_NOTIMPL;
584 static HRESULT WINAPI GameStatisticsImpl_SetStatistic(
585 IGameStatistics *iface,
586 WORD categoryIndex,
587 WORD statIndex,
588 LPCWSTR name,
589 LPCWSTR value)
591 HRESULT hr = S_OK;
592 DWORD dwNameLen, dwValueLen;
593 GameStatisticsImpl *This = impl_from_IGameStatistics(iface);
595 TRACE("(%p, %d, %d, %s, %s)\n", This, categoryIndex, statIndex,
596 debugstr_w(name), debugstr_w(value));
598 if(!name)
599 return S_FALSE;
601 if(categoryIndex >= MAX_CATEGORIES || statIndex >= MAX_STATS_PER_CATEGORY)
602 return E_INVALIDARG;
604 dwNameLen = lstrlenW(name);
606 if(dwNameLen > MAX_NAME_LENGTH)
608 hr = S_FALSE;
609 dwNameLen = MAX_NAME_LENGTH;
612 lstrcpynW(This->stats.categories[categoryIndex].stats[statIndex].sName,
613 name, dwNameLen+1);
615 if(value)
617 dwValueLen = lstrlenW(value);
619 if(dwValueLen > MAX_VALUE_LENGTH)
621 hr = S_FALSE;
622 dwValueLen = MAX_VALUE_LENGTH;
625 lstrcpynW(This->stats.categories[categoryIndex].stats[statIndex].sValue,
626 value, dwValueLen+1);
628 else
629 /* Windows allows to pass NULL as value */
630 This->stats.categories[categoryIndex].stats[statIndex].sValue[0] = 0;
632 return hr;
635 static HRESULT WINAPI GameStatisticsImpl_Save(
636 IGameStatistics *iface,
637 BOOL trackChanges)
639 GameStatisticsImpl *This = impl_from_IGameStatistics(iface);
640 HRESULT hr = S_OK;
642 TRACE("(%p, %d)\n", This, trackChanges);
644 if(trackChanges == TRUE)
645 FIXME("tracking changes not yet implemented\n");
647 hr = GAMEUX_updateStatisticsFile(&This->stats);
649 return hr;
652 static HRESULT WINAPI GameStatisticsImpl_SetLastPlayedCategory(
653 IGameStatistics *iface,
654 UINT categoryIndex)
656 FIXME("stub\n");
657 return E_NOTIMPL;
660 static HRESULT WINAPI GameStatisticsImpl_GetLastPlayedCategory(
661 IGameStatistics *iface,
662 UINT *pCategoryIndex)
664 FIXME("stub\n");
665 return E_NOTIMPL;
668 static const struct IGameStatisticsVtbl GameStatisticsImplVtbl =
670 GameStatisticsImpl_QueryInterface,
671 GameStatisticsImpl_AddRef,
672 GameStatisticsImpl_Release,
673 GameStatisticsImpl_GetMaxCategoryLength,
674 GameStatisticsImpl_GetMaxNameLength,
675 GameStatisticsImpl_GetMaxValueLength,
676 GameStatisticsImpl_GetMaxCategories,
677 GameStatisticsImpl_GetMaxStatsPerCategory,
678 GameStatisticsImpl_SetCategoryTitle,
679 GameStatisticsImpl_GetCategoryTitle,
680 GameStatisticsImpl_GetStatistic,
681 GameStatisticsImpl_SetStatistic,
682 GameStatisticsImpl_Save,
683 GameStatisticsImpl_SetLastPlayedCategory,
684 GameStatisticsImpl_GetLastPlayedCategory
688 HRESULT create_IGameStatistics(GameStatisticsImpl** ppStats)
690 TRACE("(%p)\n", ppStats);
692 *ppStats = HeapAlloc( GetProcessHeap(), 0, sizeof(**ppStats));
693 if(!(*ppStats))
694 return E_OUTOFMEMORY;
696 (*ppStats)->lpVtbl = &GameStatisticsImplVtbl;
697 (*ppStats)->ref = 1;
699 TRACE("returning coclass: %p\n", *ppStats);
700 return S_OK;
703 /*******************************************************************************
704 * IGameStatisticsMgr implementation
706 typedef struct _GameStatisticsMgrImpl
708 const struct IGameStatisticsMgrVtbl *lpVtbl;
709 LONG ref;
710 } GameStatisticsMgrImpl;
712 static inline GameStatisticsMgrImpl *impl_from_IGameStatisticsMgr( IGameStatisticsMgr *iface )
714 return (GameStatisticsMgrImpl *)((char*)iface - FIELD_OFFSET(GameStatisticsMgrImpl, lpVtbl));
718 static HRESULT WINAPI GameStatisticsMgrImpl_QueryInterface(
719 IGameStatisticsMgr *iface,
720 REFIID riid,
721 void **ppvObject)
723 GameStatisticsMgrImpl *This = impl_from_IGameStatisticsMgr( iface );
725 TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
727 *ppvObject = NULL;
729 if(IsEqualGUID(riid, &IID_IUnknown) ||
730 IsEqualGUID(riid, &IID_IGameStatisticsMgr) )
732 *ppvObject = iface;
734 else
736 FIXME("interface %s not implemented\n", debugstr_guid(riid));
737 return E_NOINTERFACE;
740 IGameStatisticsMgr_AddRef( iface );
741 return S_OK;
744 static ULONG WINAPI GameStatisticsMgrImpl_AddRef(IGameStatisticsMgr *iface)
746 GameStatisticsMgrImpl *This = impl_from_IGameStatisticsMgr( iface );
747 LONG ref;
749 ref = InterlockedIncrement(&This->ref);
751 TRACE("(%p): ref=%d\n", This, ref);
752 return ref;
755 static ULONG WINAPI GameStatisticsMgrImpl_Release(IGameStatisticsMgr *iface)
757 GameStatisticsMgrImpl *This = impl_from_IGameStatisticsMgr( iface );
758 LONG ref;
760 ref = InterlockedDecrement(&This->ref);
761 TRACE("(%p): ref=%d\n", This, ref);
763 if ( ref == 0 )
765 TRACE("freeing GameStatistics object\n");
766 HeapFree( GetProcessHeap(), 0, This);
769 return ref;
772 static HRESULT STDMETHODCALLTYPE GameStatisticsMgrImpl_GetGameStatistics(
773 IGameStatisticsMgr* iface,
774 LPCWSTR GDFBinaryPath,
775 GAMESTATS_OPEN_TYPE openType,
776 GAMESTATS_OPEN_RESULT *pOpenResult,
777 IGameStatistics **ppiStats)
779 HRESULT hr;
780 WCHAR lpApplicationId[49];
781 GameStatisticsImpl *statisticsImpl;
783 TRACE("(%p, %s, 0x%x, %p, %p)\n", iface, debugstr_w(GDFBinaryPath), openType, pOpenResult, ppiStats);
785 hr = GAMEUX_getAppIdFromGDFPath(GDFBinaryPath, lpApplicationId);
787 if(SUCCEEDED(hr))
788 hr = create_IGameStatistics(&statisticsImpl);
790 if(SUCCEEDED(hr))
792 *ppiStats = IGameStatistics_from_impl(statisticsImpl);
793 hr = GAMEUX_buildStatisticsFilePath(lpApplicationId, statisticsImpl->stats.sStatsFile);
796 if(SUCCEEDED(hr))
798 FIXME("loading game statistics not yet implemented\n");
799 hr = E_NOTIMPL;
802 return hr;
805 static HRESULT STDMETHODCALLTYPE GameStatisticsMgrImpl_RemoveGameStatistics(
806 IGameStatisticsMgr* iface,
807 LPCWSTR GDFBinaryPath)
809 HRESULT hr;
810 WCHAR lpApplicationId[49];
811 WCHAR sStatsFile[MAX_PATH];
813 TRACE("(%p, %s)\n", iface, debugstr_w(GDFBinaryPath));
815 hr = GAMEUX_getAppIdFromGDFPath(GDFBinaryPath, lpApplicationId);
817 if(SUCCEEDED(hr))
818 hr = GAMEUX_buildStatisticsFilePath(lpApplicationId, sStatsFile);
820 if(SUCCEEDED(hr))
821 hr = (DeleteFileW(sStatsFile)==TRUE ? S_OK : HRESULT_FROM_WIN32(GetLastError()));
823 return hr;
826 static const struct IGameStatisticsMgrVtbl GameStatisticsMgrImplVtbl =
828 GameStatisticsMgrImpl_QueryInterface,
829 GameStatisticsMgrImpl_AddRef,
830 GameStatisticsMgrImpl_Release,
831 GameStatisticsMgrImpl_GetGameStatistics,
832 GameStatisticsMgrImpl_RemoveGameStatistics,
835 HRESULT GameStatistics_create(
836 IUnknown *pUnkOuter,
837 IUnknown **ppObj)
839 GameStatisticsMgrImpl *pGameStatistics;
841 TRACE("(%p, %p)\n", pUnkOuter, ppObj);
843 pGameStatistics = HeapAlloc( GetProcessHeap(), 0, sizeof (*pGameStatistics) );
845 if( !pGameStatistics )
846 return E_OUTOFMEMORY;
848 pGameStatistics->lpVtbl = &GameStatisticsMgrImplVtbl;
849 pGameStatistics->ref = 1;
851 *ppObj = (IUnknown*)(&pGameStatistics->lpVtbl);
853 TRACE("returning iface %p\n", *ppObj);
854 return S_OK;