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