xref: /reactos/dll/directx/wine/dxdiagn/container.c (revision 7abc8be1)
1 /*
2  * IDxDiagContainer Implementation
3  *
4  * Copyright 2004 Raphael Junqueira
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21 
22 #include "config.h"
23 
24 #define COBJMACROS
25 #include "dxdiag_private.h"
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 
29 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
30 
31 static inline IDxDiagContainerImpl *impl_from_IDxDiagContainer(IDxDiagContainer *iface)
32 {
33     return CONTAINING_RECORD(iface, IDxDiagContainerImpl, IDxDiagContainer_iface);
34 }
35 
36 /* IDxDiagContainer IUnknown parts follow: */
37 static HRESULT WINAPI IDxDiagContainerImpl_QueryInterface(IDxDiagContainer *iface, REFIID riid,
38         void **ppobj)
39 {
40     IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
41 
42     if (!ppobj) return E_INVALIDARG;
43 
44     if (IsEqualGUID(riid, &IID_IUnknown)
45         || IsEqualGUID(riid, &IID_IDxDiagContainer)) {
46         IUnknown_AddRef(iface);
47         *ppobj = This;
48         return S_OK;
49     }
50 
51     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
52     *ppobj = NULL;
53     return E_NOINTERFACE;
54 }
55 
56 static ULONG WINAPI IDxDiagContainerImpl_AddRef(IDxDiagContainer *iface)
57 {
58     IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
59     ULONG refCount = InterlockedIncrement(&This->ref);
60 
61     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
62 
63     DXDIAGN_LockModule();
64 
65     return refCount;
66 }
67 
68 static ULONG WINAPI IDxDiagContainerImpl_Release(IDxDiagContainer *iface)
69 {
70     IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
71     ULONG refCount = InterlockedDecrement(&This->ref);
72 
73     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
74 
75     if (!refCount) {
76         IDxDiagProvider_Release(This->pProv);
77         HeapFree(GetProcessHeap(), 0, This);
78     }
79 
80     DXDIAGN_UnlockModule();
81 
82     return refCount;
83 }
84 
85 /* IDxDiagContainer Interface follow: */
86 static HRESULT WINAPI IDxDiagContainerImpl_GetNumberOfChildContainers(IDxDiagContainer *iface,
87         DWORD *pdwCount)
88 {
89   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
90 
91   TRACE("(%p)\n", iface);
92   if (NULL == pdwCount) {
93     return E_INVALIDARG;
94   }
95   *pdwCount = This->cont->nSubContainers;
96   return S_OK;
97 }
98 
99 static HRESULT WINAPI IDxDiagContainerImpl_EnumChildContainerNames(IDxDiagContainer *iface,
100         DWORD dwIndex, LPWSTR pwszContainer, DWORD cchContainer)
101 {
102   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
103   IDxDiagContainerImpl_Container *p;
104   DWORD i = 0;
105 
106   TRACE("(%p, %u, %p, %u)\n", iface, dwIndex, pwszContainer, cchContainer);
107 
108   if (NULL == pwszContainer || 0 == cchContainer) {
109     return E_INVALIDARG;
110   }
111 
112   LIST_FOR_EACH_ENTRY(p, &This->cont->subContainers, IDxDiagContainerImpl_Container, entry)
113   {
114     if (dwIndex == i) {
115       TRACE("Found container name %s, copying string\n", debugstr_w(p->contName));
116       lstrcpynW(pwszContainer, p->contName, cchContainer);
117       return (cchContainer <= strlenW(p->contName)) ?
118               DXDIAG_E_INSUFFICIENT_BUFFER : S_OK;
119     }
120     ++i;
121   }
122 
123   TRACE("Failed to find container name at specified index\n");
124   *pwszContainer = '\0';
125   return E_INVALIDARG;
126 }
127 
128 static HRESULT IDxDiagContainerImpl_GetChildContainerInternal(IDxDiagContainerImpl_Container *cont, LPCWSTR pwszContainer, IDxDiagContainerImpl_Container **subcont) {
129   IDxDiagContainerImpl_Container *p;
130 
131   LIST_FOR_EACH_ENTRY(p, &cont->subContainers, IDxDiagContainerImpl_Container, entry)
132   {
133     if (0 == lstrcmpW(p->contName, pwszContainer)) {
134       *subcont = p;
135       return S_OK;
136     }
137   }
138 
139   return E_INVALIDARG;
140 }
141 
142 static HRESULT WINAPI IDxDiagContainerImpl_GetChildContainer(IDxDiagContainer *iface,
143         LPCWSTR pwszContainer, IDxDiagContainer **ppInstance)
144 {
145   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
146   IDxDiagContainerImpl_Container *pContainer = This->cont;
147   LPWSTR tmp, orig_tmp;
148   INT tmp_len;
149   WCHAR* cur;
150   HRESULT hr = E_INVALIDARG;
151 
152   TRACE("(%p, %s, %p)\n", iface, debugstr_w(pwszContainer), ppInstance);
153 
154   if (NULL == ppInstance || NULL == pwszContainer) {
155     return E_INVALIDARG;
156   }
157 
158   *ppInstance = NULL;
159 
160   tmp_len = strlenW(pwszContainer) + 1;
161   orig_tmp = tmp = HeapAlloc(GetProcessHeap(), 0, tmp_len * sizeof(WCHAR));
162   if (NULL == tmp) return E_FAIL;
163   lstrcpynW(tmp, pwszContainer, tmp_len);
164 
165   /* special handling for an empty string and leaf container */
166   if (!tmp[0] && list_empty(&pContainer->subContainers)) {
167     hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pContainer, This->pProv, (void **)ppInstance);
168     if (SUCCEEDED(hr))
169       TRACE("Succeeded in getting the container instance\n");
170     goto out;
171   }
172 
173   cur = strchrW(tmp, '.');
174   while (NULL != cur) {
175     *cur = '\0'; /* cut tmp string to '.' */
176     if (!*(cur + 1)) break; /* Account for a lone terminating period, as in "cont1.cont2.". */
177     TRACE("Trying to get parent container %s\n", debugstr_w(tmp));
178     hr = IDxDiagContainerImpl_GetChildContainerInternal(pContainer, tmp, &pContainer);
179     if (FAILED(hr))
180       goto out;
181     cur++; /* go after '.' (just replaced by \0) */
182     tmp = cur;
183     cur = strchrW(tmp, '.');
184   }
185 
186   TRACE("Trying to get container %s\n", debugstr_w(tmp));
187   hr = IDxDiagContainerImpl_GetChildContainerInternal(pContainer, tmp, &pContainer);
188   if (SUCCEEDED(hr)) {
189     hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pContainer, This->pProv, (void **)ppInstance);
190     if (SUCCEEDED(hr))
191         TRACE("Succeeded in getting the container instance\n");
192   }
193 
194 out:
195   HeapFree(GetProcessHeap(), 0, orig_tmp);
196   return hr;
197 }
198 
199 static HRESULT WINAPI IDxDiagContainerImpl_GetNumberOfProps(IDxDiagContainer *iface,
200         DWORD *pdwCount)
201 {
202   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
203 
204   TRACE("(%p)\n", iface);
205   if (NULL == pdwCount) {
206     return E_INVALIDARG;
207   }
208   *pdwCount = This->cont->nProperties;
209   return S_OK;
210 }
211 
212 static HRESULT WINAPI IDxDiagContainerImpl_EnumPropNames(IDxDiagContainer *iface, DWORD dwIndex,
213         LPWSTR pwszPropName, DWORD cchPropName)
214 {
215   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
216   IDxDiagContainerImpl_Property *p;
217   DWORD i = 0;
218 
219   TRACE("(%p, %u, %p, %u)\n", iface, dwIndex, pwszPropName, cchPropName);
220 
221   if (NULL == pwszPropName || 0 == cchPropName) {
222     return E_INVALIDARG;
223   }
224 
225   LIST_FOR_EACH_ENTRY(p, &This->cont->properties, IDxDiagContainerImpl_Property, entry)
226   {
227     if (dwIndex == i) {
228       TRACE("Found property name %s, copying string\n", debugstr_w(p->propName));
229       lstrcpynW(pwszPropName, p->propName, cchPropName);
230       return (cchPropName <= strlenW(p->propName)) ?
231               DXDIAG_E_INSUFFICIENT_BUFFER : S_OK;
232     }
233     ++i;
234   }
235 
236   TRACE("Failed to find property name at specified index\n");
237   return E_INVALIDARG;
238 }
239 
240 static HRESULT WINAPI IDxDiagContainerImpl_GetProp(IDxDiagContainer *iface, LPCWSTR pwszPropName,
241         VARIANT *pvarProp)
242 {
243   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
244   IDxDiagContainerImpl_Property *p;
245 
246   TRACE("(%p, %s, %p)\n", iface, debugstr_w(pwszPropName), pvarProp);
247 
248   if (NULL == pvarProp || NULL == pwszPropName) {
249     return E_INVALIDARG;
250   }
251 
252   LIST_FOR_EACH_ENTRY(p, &This->cont->properties, IDxDiagContainerImpl_Property, entry)
253   {
254     if (0 == lstrcmpW(p->propName, pwszPropName)) {
255       VariantInit(pvarProp);
256       return VariantCopy(pvarProp, &p->vProp);
257     }
258   }
259 
260   return E_INVALIDARG;
261 }
262 
263 static const IDxDiagContainerVtbl DxDiagContainer_Vtbl =
264 {
265     IDxDiagContainerImpl_QueryInterface,
266     IDxDiagContainerImpl_AddRef,
267     IDxDiagContainerImpl_Release,
268     IDxDiagContainerImpl_GetNumberOfChildContainers,
269     IDxDiagContainerImpl_EnumChildContainerNames,
270     IDxDiagContainerImpl_GetChildContainer,
271     IDxDiagContainerImpl_GetNumberOfProps,
272     IDxDiagContainerImpl_EnumPropNames,
273     IDxDiagContainerImpl_GetProp
274 };
275 
276 
277 HRESULT DXDiag_CreateDXDiagContainer(REFIID riid, IDxDiagContainerImpl_Container *cont, IDxDiagProvider *pProv, LPVOID *ppobj) {
278   IDxDiagContainerImpl* container;
279 
280   TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
281 
282   container = HeapAlloc(GetProcessHeap(), 0, sizeof(IDxDiagContainerImpl));
283   if (NULL == container) {
284     *ppobj = NULL;
285     return E_OUTOFMEMORY;
286   }
287   container->IDxDiagContainer_iface.lpVtbl = &DxDiagContainer_Vtbl;
288   container->ref = 0; /* will be inited with QueryInterface */
289   container->cont = cont;
290   container->pProv = pProv;
291   IDxDiagProvider_AddRef(pProv);
292   return IDxDiagContainerImpl_QueryInterface(&container->IDxDiagContainer_iface, riid, ppobj);
293 }
294