msvcrt: NULL terminate program arguments list in __getmainargs.
[wine] / dlls / dxdiagn / container.c
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   cur = strchrW(tmp, '.');
166   while (NULL != cur) {
167     *cur = '\0'; /* cut tmp string to '.' */
168     if (!*(cur + 1)) break; /* Account for a lone terminating period, as in "cont1.cont2.". */
169     TRACE("Trying to get parent container %s\n", debugstr_w(tmp));
170     hr = IDxDiagContainerImpl_GetChildContainerInternal(pContainer, tmp, &pContainer);
171     if (FAILED(hr))
172       goto on_error;
173     cur++; /* go after '.' (just replaced by \0) */
174     tmp = cur;
175     cur = strchrW(tmp, '.');
176   }
177
178   TRACE("Trying to get container %s\n", debugstr_w(tmp));
179   hr = IDxDiagContainerImpl_GetChildContainerInternal(pContainer, tmp, &pContainer);
180   if (SUCCEEDED(hr)) {
181     hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pContainer, This->pProv, (void **)ppInstance);
182     if (SUCCEEDED(hr))
183         TRACE("Succeeded in getting the container instance\n");
184   }
185
186 on_error:
187   HeapFree(GetProcessHeap(), 0, orig_tmp);
188   return hr;
189 }
190
191 static HRESULT WINAPI IDxDiagContainerImpl_GetNumberOfProps(IDxDiagContainer *iface,
192         DWORD *pdwCount)
193 {
194   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
195
196   TRACE("(%p)\n", iface);
197   if (NULL == pdwCount) {
198     return E_INVALIDARG;
199   }
200   *pdwCount = This->cont->nProperties;
201   return S_OK;
202 }
203
204 static HRESULT WINAPI IDxDiagContainerImpl_EnumPropNames(IDxDiagContainer *iface, DWORD dwIndex,
205         LPWSTR pwszPropName, DWORD cchPropName)
206 {
207   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
208   IDxDiagContainerImpl_Property *p;
209   DWORD i = 0;
210
211   TRACE("(%p, %u, %p, %u)\n", iface, dwIndex, pwszPropName, cchPropName);
212
213   if (NULL == pwszPropName || 0 == cchPropName) {
214     return E_INVALIDARG;
215   }
216
217   LIST_FOR_EACH_ENTRY(p, &This->cont->properties, IDxDiagContainerImpl_Property, entry)
218   {
219     if (dwIndex == i) {
220       TRACE("Found property name %s, copying string\n", debugstr_w(p->propName));
221       lstrcpynW(pwszPropName, p->propName, cchPropName);
222       return (cchPropName <= strlenW(p->propName)) ?
223               DXDIAG_E_INSUFFICIENT_BUFFER : S_OK;
224     }
225     ++i;
226   }
227
228   TRACE("Failed to find property name at specified index\n");
229   return E_INVALIDARG;
230 }
231
232 static HRESULT WINAPI IDxDiagContainerImpl_GetProp(IDxDiagContainer *iface, LPCWSTR pwszPropName,
233         VARIANT *pvarProp)
234 {
235   IDxDiagContainerImpl *This = impl_from_IDxDiagContainer(iface);
236   IDxDiagContainerImpl_Property *p;
237
238   TRACE("(%p, %s, %p)\n", iface, debugstr_w(pwszPropName), pvarProp);
239
240   if (NULL == pvarProp || NULL == pwszPropName) {
241     return E_INVALIDARG;
242   }
243
244   LIST_FOR_EACH_ENTRY(p, &This->cont->properties, IDxDiagContainerImpl_Property, entry)
245   {
246     if (0 == lstrcmpW(p->propName, pwszPropName)) {
247       VariantInit(pvarProp);
248       return VariantCopy(pvarProp, &p->vProp);
249     }
250   }
251
252   return E_INVALIDARG;
253 }
254
255 static const IDxDiagContainerVtbl DxDiagContainer_Vtbl =
256 {
257     IDxDiagContainerImpl_QueryInterface,
258     IDxDiagContainerImpl_AddRef,
259     IDxDiagContainerImpl_Release,
260     IDxDiagContainerImpl_GetNumberOfChildContainers,
261     IDxDiagContainerImpl_EnumChildContainerNames,
262     IDxDiagContainerImpl_GetChildContainer,
263     IDxDiagContainerImpl_GetNumberOfProps,
264     IDxDiagContainerImpl_EnumPropNames,
265     IDxDiagContainerImpl_GetProp
266 };
267
268
269 HRESULT DXDiag_CreateDXDiagContainer(REFIID riid, IDxDiagContainerImpl_Container *cont, IDxDiagProvider *pProv, LPVOID *ppobj) {
270   IDxDiagContainerImpl* container;
271
272   TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj);
273
274   container = HeapAlloc(GetProcessHeap(), 0, sizeof(IDxDiagContainerImpl));
275   if (NULL == container) {
276     *ppobj = NULL;
277     return E_OUTOFMEMORY;
278   }
279   container->IDxDiagContainer_iface.lpVtbl = &DxDiagContainer_Vtbl;
280   container->ref = 0; /* will be inited with QueryInterface */
281   container->cont = cont;
282   container->pProv = pProv;
283   IDxDiagProvider_AddRef(pProv);
284   return IDxDiagContainerImpl_QueryInterface(&container->IDxDiagContainer_iface, riid, ppobj);
285 }