1 /*
2  * Unit tests for IDxDiagContainer
3  *
4  * Copyright 2010 Andrew Nguyen
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 #define COBJMACROS
22 
23 #include <stdio.h>
24 #include "wine/dxdiag.h"
25 #include "oleauto.h"
26 #include "wine/test.h"
27 
28 struct property_test
29 {
30     const WCHAR *prop;
31     VARTYPE vt;
32 };
33 
34 static IDxDiagProvider *pddp;
35 static IDxDiagContainer *pddc;
36 
37 static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
38 static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
39 static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d','.',
40                                             'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
41 static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d','.',
42                                                    'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e',
43                                                    'D','e','v','i','c','e','s',0};
44 
45 /* Based on debugstr_variant in dlls/jscript/jsutils.c. */
46 static const char *debugstr_variant(const VARIANT *var)
47 {
48     static char buf[400];
49 
50     if (!var)
51         return "(null)";
52 
53     switch (V_VT(var))
54     {
55     case VT_EMPTY:
56         return "{VT_EMPTY}";
57     case VT_BSTR:
58         sprintf(buf, "{VT_BSTR: %s}", wine_dbgstr_w(V_BSTR(var)));
59         break;
60     case VT_BOOL:
61         sprintf(buf, "{VT_BOOL: %x}", V_BOOL(var));
62         break;
63     case VT_UI4:
64         sprintf(buf, "{VT_UI4: %u}", V_UI4(var));
65         break;
66     default:
67         sprintf(buf, "{vt %d}", V_VT(var));
68         break;
69     }
70 
71     return buf;
72 }
73 
74 static BOOL create_root_IDxDiagContainer(void)
75 {
76     HRESULT hr;
77     DXDIAG_INIT_PARAMS params;
78 
79     hr = CoCreateInstance(&CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER,
80                           &IID_IDxDiagProvider, (LPVOID*)&pddp);
81     if (SUCCEEDED(hr))
82     {
83         params.dwSize = sizeof(params);
84         params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
85         params.bAllowWHQLChecks = FALSE;
86         params.pReserved = NULL;
87         hr = IDxDiagProvider_Initialize(pddp, &params);
88         if (SUCCEEDED(hr))
89         {
90             hr = IDxDiagProvider_GetRootContainer(pddp, &pddc);
91             if (SUCCEEDED(hr))
92                 return TRUE;
93         }
94         IDxDiagProvider_Release(pddp);
95     }
96     return FALSE;
97 }
98 
99 static void test_GetNumberOfChildContainers(void)
100 {
101     HRESULT hr;
102     DWORD count;
103 
104     if (!create_root_IDxDiagContainer())
105     {
106         skip("Unable to create the root IDxDiagContainer\n");
107         return;
108     }
109 
110     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, NULL);
111     ok(hr == E_INVALIDARG,
112        "Expected IDxDiagContainer::GetNumberOfChildContainers to return E_INVALIDARG, got 0x%08x\n", hr);
113 
114     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
115     ok(hr == S_OK,
116        "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
117     if (hr == S_OK)
118         ok(count != 0, "Expected the number of child containers for the root container to be non-zero\n");
119 
120     IDxDiagContainer_Release(pddc);
121     IDxDiagProvider_Release(pddp);
122 }
123 
124 static void test_GetNumberOfProps(void)
125 {
126     HRESULT hr;
127     DWORD count;
128 
129     if (!create_root_IDxDiagContainer())
130     {
131         skip("Unable to create the root IDxDiagContainer\n");
132         return;
133     }
134 
135     hr = IDxDiagContainer_GetNumberOfProps(pddc, NULL);
136     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetNumberOfProps to return E_INVALIDARG, got 0x%08x\n", hr);
137 
138     hr = IDxDiagContainer_GetNumberOfProps(pddc, &count);
139     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
140     if (hr == S_OK)
141         ok(count == 0, "Expected the number of properties for the root container to be zero\n");
142 
143     IDxDiagContainer_Release(pddc);
144     IDxDiagProvider_Release(pddp);
145 }
146 
147 static void test_EnumChildContainerNames(void)
148 {
149     HRESULT hr;
150     WCHAR container[256];
151     DWORD maxcount, index;
152     static const WCHAR testW[] = {'t','e','s','t',0};
153     static const WCHAR zerotestW[] = {0,'e','s','t',0};
154 
155     if (!create_root_IDxDiagContainer())
156     {
157         skip("Unable to create the root IDxDiagContainer\n");
158         return;
159     }
160 
161     /* Test various combinations of invalid parameters. */
162     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, NULL, 0);
163     ok(hr == E_INVALIDARG,
164        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
165 
166     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, NULL, sizeof(container)/sizeof(WCHAR));
167     ok(hr == E_INVALIDARG,
168        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
169 
170     /* Test the conditions in which the output buffer can be modified. */
171     memcpy(container, testW, sizeof(testW));
172     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, container, 0);
173     ok(hr == E_INVALIDARG,
174        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
175     ok(!memcmp(container, testW, sizeof(testW)),
176        "Expected the container buffer to be untouched, got %s\n", wine_dbgstr_w(container));
177 
178     memcpy(container, testW, sizeof(testW));
179     hr = IDxDiagContainer_EnumChildContainerNames(pddc, ~0, container, 0);
180     ok(hr == E_INVALIDARG,
181        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
182     ok(!memcmp(container, testW, sizeof(testW)),
183        "Expected the container buffer to be untouched, got %s\n", wine_dbgstr_w(container));
184 
185     memcpy(container, testW, sizeof(testW));
186     hr = IDxDiagContainer_EnumChildContainerNames(pddc, ~0, container, sizeof(container)/sizeof(WCHAR));
187     ok(hr == E_INVALIDARG,
188        "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG, got 0x%08x\n", hr);
189     ok(!memcmp(container, zerotestW, sizeof(zerotestW)),
190        "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
191 
192     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &maxcount);
193     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
194     if (FAILED(hr))
195     {
196         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
197         goto cleanup;
198     }
199 
200     trace("Starting child container enumeration of the root container:\n");
201 
202     /* We should be able to enumerate as many child containers as the value
203      * that IDxDiagContainer::GetNumberOfChildContainers returns. */
204     for (index = 0; index <= maxcount; index++)
205     {
206         /* A buffer size of 1 is unlikely to be valid, as only a null terminator
207          * could be stored, and it is unlikely that a container name could be empty. */
208         DWORD buffersize = 1;
209         memcpy(container, testW, sizeof(testW));
210         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, buffersize);
211         if (hr == E_INVALIDARG)
212         {
213             /* We should get here when index is one more than the maximum index value. */
214             ok(maxcount == index,
215                "Expected IDxDiagContainer::EnumChildContainerNames to return E_INVALIDARG "
216                "on the last index %d, got 0x%08x\n", index, hr);
217             ok(container[0] == '\0',
218                "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
219             break;
220         }
221         else if (hr == DXDIAG_E_INSUFFICIENT_BUFFER)
222         {
223             WCHAR temp[256];
224 
225             ok(container[0] == '\0',
226                "Expected the container buffer string to be empty, got %s\n", wine_dbgstr_w(container));
227 
228             /* Get the container name to compare against. */
229             hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, temp, sizeof(temp)/sizeof(WCHAR));
230             ok(hr == S_OK,
231                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
232 
233             /* Show that the DirectX SDK's stipulation that the buffer be at
234              * least 256 characters long is a mere suggestion, and smaller sizes
235              * can be acceptable also. IDxDiagContainer::EnumChildContainerNames
236              * doesn't provide a way of getting the exact size required, so the
237              * buffersize value will be iterated to at most 256 characters. */
238             for (buffersize = 2; buffersize <= 256; buffersize++)
239             {
240                 memcpy(container, testW, sizeof(testW));
241                 hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, buffersize);
242                 if (hr != DXDIAG_E_INSUFFICIENT_BUFFER)
243                     break;
244 
245                 ok(!memcmp(temp, container, sizeof(WCHAR)*(buffersize - 1)),
246                    "Expected truncated container name string, got %s\n", wine_dbgstr_w(container));
247             }
248 
249             ok(hr == S_OK,
250                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, "
251                "got hr = 0x%08x, buffersize = %d\n", hr, buffersize);
252             if (hr == S_OK)
253                 trace("pddc[%d] = %s, length = %d\n", index, wine_dbgstr_w(container), buffersize);
254         }
255         else
256         {
257             ok(0, "IDxDiagContainer::EnumChildContainerNames unexpectedly returned 0x%08x\n", hr);
258             break;
259         }
260     }
261 
262 cleanup:
263     IDxDiagContainer_Release(pddc);
264     IDxDiagProvider_Release(pddp);
265 }
266 
267 static void test_GetChildContainer(void)
268 {
269     HRESULT hr;
270     WCHAR container[256] = {0};
271     IDxDiagContainer *child;
272 
273     if (!create_root_IDxDiagContainer())
274     {
275         skip("Unable to create the root IDxDiagContainer\n");
276         return;
277     }
278 
279     /* Test various combinations of invalid parameters. */
280     hr = IDxDiagContainer_GetChildContainer(pddc, NULL, NULL);
281     ok(hr == E_INVALIDARG,
282        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
283 
284     child = (void*)0xdeadbeef;
285     hr = IDxDiagContainer_GetChildContainer(pddc, NULL, &child);
286     ok(hr == E_INVALIDARG,
287        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
288     ok(child == (void*)0xdeadbeef, "Expected output pointer to be unchanged, got %p\n", child);
289 
290     hr = IDxDiagContainer_GetChildContainer(pddc, container, NULL);
291     ok(hr == E_INVALIDARG,
292        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
293 
294     child = (void*)0xdeadbeef;
295     hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
296     ok(hr == E_INVALIDARG,
297        "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
298     ok(child == NULL, "Expected output pointer to be NULL, got %p\n", child);
299 
300     /* Get the name of a suitable child container. */
301     hr = IDxDiagContainer_EnumChildContainerNames(pddc, 0, container, sizeof(container)/sizeof(WCHAR));
302     ok(hr == S_OK,
303        "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
304     if (FAILED(hr))
305     {
306         skip("IDxDiagContainer::EnumChildContainerNames failed\n");
307         goto cleanup;
308     }
309 
310     child = (void*)0xdeadbeef;
311     hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
312     ok(hr == S_OK,
313        "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
314     ok(child != NULL && child != (void*)0xdeadbeef, "Expected a valid output pointer, got %p\n", child);
315 
316     if (SUCCEEDED(hr))
317     {
318         IDxDiagContainer *ptr;
319 
320         /* Show that IDxDiagContainer::GetChildContainer returns a different pointer
321          * for multiple calls for the same container name. */
322         hr = IDxDiagContainer_GetChildContainer(pddc, container, &ptr);
323         ok(hr == S_OK,
324            "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
325         if (SUCCEEDED(hr))
326             ok(ptr != child, "Expected the two pointers (%p vs. %p) to be unequal\n", child, ptr);
327 
328         IDxDiagContainer_Release(ptr);
329         IDxDiagContainer_Release(child);
330     }
331 
332 cleanup:
333     IDxDiagContainer_Release(pddc);
334     IDxDiagProvider_Release(pddp);
335 }
336 
337 static void test_dot_parsing(void)
338 {
339     HRESULT hr;
340     WCHAR containerbufW[256] = {0}, childbufW[256] = {0};
341     DWORD count, index;
342     size_t i;
343     static const struct
344     {
345         const char *format;
346         const HRESULT expect;
347     } test_strings[] = {
348         { "%s.%s",   S_OK },
349         { "%s.%s.",  S_OK },
350         { ".%s.%s",  E_INVALIDARG },
351         { "%s.%s..", E_INVALIDARG },
352         { ".%s.%s.", E_INVALIDARG },
353         { "..%s.%s", E_INVALIDARG },
354     };
355 
356     if (!create_root_IDxDiagContainer())
357     {
358         skip("Unable to create the root IDxDiagContainer\n");
359         return;
360     }
361 
362     /* Find a container with a child container of its own. */
363     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
364     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
365     if (FAILED(hr))
366     {
367         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
368         goto cleanup;
369     }
370 
371     for (index = 0; index < count; index++)
372     {
373         IDxDiagContainer *child;
374 
375         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, containerbufW, sizeof(containerbufW)/sizeof(WCHAR));
376         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
377         if (FAILED(hr))
378         {
379             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
380             goto cleanup;
381         }
382 
383         hr = IDxDiagContainer_GetChildContainer(pddc, containerbufW, &child);
384         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
385 
386         if (SUCCEEDED(hr))
387         {
388             hr = IDxDiagContainer_EnumChildContainerNames(child, 0, childbufW, sizeof(childbufW)/sizeof(WCHAR));
389             ok(hr == S_OK || hr == E_INVALIDARG,
390                "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK or E_INVALIDARG, got 0x%08x\n", hr);
391             IDxDiagContainer_Release(child);
392 
393             if (SUCCEEDED(hr))
394                 break;
395         }
396     }
397 
398     if (!*containerbufW || !*childbufW)
399     {
400         skip("Unable to find a suitable container\n");
401         goto cleanup;
402     }
403 
404     trace("Testing IDxDiagContainer::GetChildContainer dot parsing with container %s and child container %s.\n",
405           wine_dbgstr_w(containerbufW), wine_dbgstr_w(childbufW));
406 
407     for (i = 0; i < sizeof(test_strings)/sizeof(test_strings[0]); i++)
408     {
409         IDxDiagContainer *child;
410         char containerbufA[256];
411         char childbufA[256];
412         char dotbufferA[255 + 255 + 3 + 1];
413         WCHAR dotbufferW[255 + 255 + 3 + 1]; /* containerbuf + childbuf + dots + null terminator */
414 
415         WideCharToMultiByte(CP_ACP, 0, containerbufW, -1, containerbufA, sizeof(containerbufA), NULL, NULL);
416         WideCharToMultiByte(CP_ACP, 0, childbufW, -1, childbufA, sizeof(childbufA), NULL, NULL);
417         sprintf(dotbufferA, test_strings[i].format, containerbufA, childbufA);
418         MultiByteToWideChar(CP_ACP, 0, dotbufferA, -1, dotbufferW, sizeof(dotbufferW)/sizeof(WCHAR));
419 
420         trace("Trying container name %s\n", wine_dbgstr_w(dotbufferW));
421         hr = IDxDiagContainer_GetChildContainer(pddc, dotbufferW, &child);
422         ok(hr == test_strings[i].expect,
423            "Expected IDxDiagContainer::GetChildContainer to return 0x%08x for %s, got 0x%08x\n",
424            test_strings[i].expect, wine_dbgstr_w(dotbufferW), hr);
425         if (SUCCEEDED(hr))
426             IDxDiagContainer_Release(child);
427     }
428 
429 cleanup:
430     IDxDiagContainer_Release(pddc);
431     IDxDiagProvider_Release(pddp);
432 }
433 
434 static void test_EnumPropNames(void)
435 {
436     HRESULT hr;
437     WCHAR container[256], property[256];
438     IDxDiagContainer *child = NULL;
439     DWORD count, index, propcount;
440     static const WCHAR testW[] = {'t','e','s','t',0};
441 
442     if (!create_root_IDxDiagContainer())
443     {
444         skip("Unable to create the root IDxDiagContainer\n");
445         return;
446     }
447 
448     /* Find a container with a non-zero number of properties. */
449     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
450     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
451     if (FAILED(hr))
452     {
453         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
454         goto cleanup;
455     }
456 
457     for (index = 0; index < count; index++)
458     {
459         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
460         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
461         if (FAILED(hr))
462         {
463             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
464             goto cleanup;
465         }
466 
467         hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
468         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
469 
470         if (SUCCEEDED(hr))
471         {
472             hr = IDxDiagContainer_GetNumberOfProps(child, &propcount);
473             ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
474 
475             if (!propcount)
476             {
477                 IDxDiagContainer_Release(child);
478                 child = NULL;
479             }
480             else
481                 break;
482         }
483     }
484 
485     if (!child)
486     {
487         skip("Unable to find a container with non-zero property count\n");
488         goto cleanup;
489     }
490 
491     hr = IDxDiagContainer_EnumPropNames(child, ~0, NULL, 0);
492     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
493 
494     memcpy(property, testW, sizeof(testW));
495     hr = IDxDiagContainer_EnumPropNames(child, ~0, property, 0);
496     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
497     ok(!memcmp(property, testW, sizeof(testW)),
498        "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
499 
500     memcpy(property, testW, sizeof(testW));
501     hr = IDxDiagContainer_EnumPropNames(child, ~0, property, sizeof(property)/sizeof(WCHAR));
502     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG, got 0x%08x\n", hr);
503     ok(!memcmp(property, testW, sizeof(testW)),
504        "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
505 
506     trace("Starting property enumeration of the %s container:\n", wine_dbgstr_w(container));
507 
508     /* We should be able to enumerate as many properties as the value that
509      * IDxDiagContainer::GetNumberOfProps returns. */
510     for (index = 0; index <= propcount; index++)
511     {
512         /* A buffer size of 1 is unlikely to be valid, as only a null terminator
513          * could be stored, and it is unlikely that a property name could be empty. */
514         DWORD buffersize = 1;
515 
516         memcpy(property, testW, sizeof(testW));
517         hr = IDxDiagContainer_EnumPropNames(child, index, property, buffersize);
518         if (hr == E_INVALIDARG)
519         {
520             /* We should get here when index is one more than the maximum index value. */
521             ok(propcount == index,
522                "Expected IDxDiagContainer::EnumPropNames to return E_INVALIDARG "
523                "on the last index %d, got 0x%08x\n", index, hr);
524             ok(!memcmp(property, testW, sizeof(testW)),
525                "Expected the property buffer to be unchanged, got %s\n", wine_dbgstr_w(property));
526             break;
527         }
528         else if (hr == DXDIAG_E_INSUFFICIENT_BUFFER)
529         {
530             WCHAR temp[256];
531 
532             ok(property[0] == '\0',
533                "Expected the property buffer string to be empty, got %s\n", wine_dbgstr_w(property));
534             hr = IDxDiagContainer_EnumPropNames(child, index, temp, sizeof(temp)/sizeof(WCHAR));
535             ok(hr == S_OK,
536                "Expected IDxDiagContainer::EnumPropNames to return S_OK, got 0x%08x\n", hr);
537 
538             /* Show that the DirectX SDK's stipulation that the buffer be at
539              * least 256 characters long is a mere suggestion, and smaller sizes
540              * can be acceptable also. IDxDiagContainer::EnumPropNames doesn't
541              * provide a way of getting the exact size required, so the buffersize
542              * value will be iterated to at most 256 characters. */
543             for (buffersize = 2; buffersize <= 256; buffersize++)
544             {
545                 memcpy(property, testW, sizeof(testW));
546                 hr = IDxDiagContainer_EnumPropNames(child, index, property, buffersize);
547                 if (hr != DXDIAG_E_INSUFFICIENT_BUFFER)
548                     break;
549 
550                 ok(!memcmp(temp, property, sizeof(WCHAR)*(buffersize - 1)),
551                    "Expected truncated property name string, got %s\n", wine_dbgstr_w(property));
552             }
553 
554             ok(hr == S_OK,
555                "Expected IDxDiagContainer::EnumPropNames to return S_OK, "
556                "got hr = 0x%08x, buffersize = %d\n", hr, buffersize);
557             if (hr == S_OK)
558                 trace("child[%d] = %s, length = %d\n", index, wine_dbgstr_w(property), buffersize);
559         }
560         else
561         {
562             ok(0, "IDxDiagContainer::EnumPropNames unexpectedly returned 0x%08x\n", hr);
563             break;
564         }
565     }
566 
567     IDxDiagContainer_Release(child);
568 
569 cleanup:
570     IDxDiagContainer_Release(pddc);
571     IDxDiagProvider_Release(pddp);
572 }
573 
574 static void test_GetProp(void)
575 {
576     HRESULT hr;
577     WCHAR container[256], property[256];
578     IDxDiagContainer *child = NULL;
579     DWORD count, index;
580     VARIANT var;
581     SAFEARRAY *sa;
582     SAFEARRAYBOUND bound;
583     ULONG ref;
584     static const WCHAR emptyW[] = {0};
585     static const WCHAR testW[] = {'t','e','s','t',0};
586 
587     if (!create_root_IDxDiagContainer())
588     {
589         skip("Unable to create the root IDxDiagContainer\n");
590         return;
591     }
592 
593     /* Find a container with a property. */
594     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
595     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
596     if (FAILED(hr))
597     {
598         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
599         goto cleanup;
600     }
601 
602     for (index = 0; index < count; index++)
603     {
604         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
605         ok(hr == S_OK, "Expected IDxDiagContainer_EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
606         if (FAILED(hr))
607         {
608             skip("IDxDiagContainer::EnumChildContainerNames failed\n");
609             goto cleanup;
610         }
611 
612         hr = IDxDiagContainer_GetChildContainer(pddc, container, &child);
613         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
614 
615         if (SUCCEEDED(hr))
616         {
617             hr = IDxDiagContainer_EnumPropNames(child, 0, property, sizeof(property)/sizeof(WCHAR));
618             ok(hr == S_OK || hr == E_INVALIDARG,
619                "Expected IDxDiagContainer::EnumPropNames to return S_OK or E_INVALIDARG, got 0x%08x\n", hr);
620 
621             if (SUCCEEDED(hr))
622                 break;
623             else
624             {
625                 IDxDiagContainer_Release(child);
626                 child = NULL;
627             }
628         }
629     }
630 
631     if (!child)
632     {
633         skip("Unable to find a suitable container\n");
634         goto cleanup;
635     }
636 
637     hr = IDxDiagContainer_GetProp(child, NULL, NULL);
638     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
639 
640     V_VT(&var) = 0xdead;
641     hr = IDxDiagContainer_GetProp(child, NULL, &var);
642     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
643     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
644 
645     hr = IDxDiagContainer_GetProp(child, emptyW, NULL);
646     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
647 
648     V_VT(&var) = 0xdead;
649     hr = IDxDiagContainer_GetProp(child, emptyW, &var);
650     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
651     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
652 
653     hr = IDxDiagContainer_GetProp(child, testW, NULL);
654     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
655 
656     V_VT(&var) = 0xdead;
657     hr = IDxDiagContainer_GetProp(child, testW, &var);
658     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetProp to return E_INVALIDARG, got 0x%08x\n", hr);
659     ok(V_VT(&var) == 0xdead, "Expected the variant to be untouched, got %u\n", V_VT(&var));
660 
661     VariantInit(&var);
662     hr = IDxDiagContainer_GetProp(child, property, &var);
663     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
664     ok(V_VT(&var) != VT_EMPTY, "Expected the variant to be modified, got %d\n", V_VT(&var));
665 
666     /* Since the documentation for IDxDiagContainer::GetProp claims that the
667      * function reports return values from VariantCopy, try to exercise failure
668      * paths in handling the destination variant. */
669 
670     /* Try an invalid variant type. */
671     V_VT(&var) = 0xdead;
672     hr = IDxDiagContainer_GetProp(child, property, &var);
673     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
674     ok(V_VT(&var) != 0xdead, "Expected the variant to be modified, got %d\n", V_VT(&var));
675 
676     /* Try passing a variant with a locked SAFEARRAY. */
677     bound.cElements = 1;
678     bound.lLbound = 0;
679     sa = SafeArrayCreate(VT_UI1, 1, &bound);
680     ok(sa != NULL, "Expected SafeArrayCreate to return a valid pointer\n");
681 
682     V_VT(&var) = (VT_ARRAY | VT_UI1);
683     V_ARRAY(&var) = sa;
684 
685     hr = SafeArrayLock(sa);
686     ok(hr == S_OK, "Expected SafeArrayLock to return S_OK, got 0x%08x\n", hr);
687 
688     hr = IDxDiagContainer_GetProp(child, property, &var);
689     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
690     ok(V_VT(&var) != (VT_ARRAY | VT_UI1), "Expected the variant to be modified\n");
691 
692     hr = SafeArrayUnlock(sa);
693     ok(hr == S_OK, "Expected SafeArrayUnlock to return S_OK, got 0x%08x\n", hr);
694     hr = SafeArrayDestroy(sa);
695     ok(hr == S_OK, "Expected SafeArrayDestroy to return S_OK, got 0x%08x\n", hr);
696 
697     /* Determine whether GetProp calls VariantClear on the passed variant. */
698     V_VT(&var) = VT_UNKNOWN;
699     V_UNKNOWN(&var) = (IUnknown *)child;
700     IDxDiagContainer_AddRef(child);
701 
702     hr = IDxDiagContainer_GetProp(child, property, &var);
703     ok(hr == S_OK, "Expected IDxDiagContainer::GetProp to return S_OK, got 0x%08x\n", hr);
704     ok(V_VT(&var) != VT_UNKNOWN, "Expected the variant to be modified\n");
705 
706     IDxDiagContainer_AddRef(child);
707     ref = IDxDiagContainer_Release(child);
708     ok(ref == 2, "Expected reference count to be 2, got %u\n", ref);
709     IDxDiagContainer_Release(child);
710 
711     IDxDiagContainer_Release(child);
712 cleanup:
713     IDxDiagContainer_Release(pddc);
714     IDxDiagProvider_Release(pddp);
715 }
716 
717 static void test_root_children(void)
718 {
719     static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
720     static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
721     static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
722     static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
723     static const WCHAR DxDiag_SystemDevices[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','D','e','v','i','c','e','s',0};
724     static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
725     static const WCHAR DxDiag_DirectShowFilters[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','h','o','w','F','i','l','t','e','r','s',0};
726     static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
727 
728     HRESULT hr;
729     DWORD count, index;
730 
731     static const WCHAR *root_children[] = {
732         DxDiag_SystemInfo, DxDiag_DisplayDevices, DxDiag_DirectSound,
733         DxDiag_DirectMusic, DxDiag_DirectInput, DxDiag_DirectPlay,
734         DxDiag_SystemDevices, DxDiag_DirectXFiles, DxDiag_DirectShowFilters,
735         DxDiag_LogicalDisks
736     };
737 
738     if (!create_root_IDxDiagContainer())
739     {
740         skip("Unable to create the root IDxDiagContainer\n");
741         return;
742     }
743 
744     /* Verify the identity and ordering of the root container's children. */
745     hr = IDxDiagContainer_GetNumberOfChildContainers(pddc, &count);
746     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
747     if (FAILED(hr))
748     {
749         skip("IDxDiagContainer::GetNumberOfChildContainers failed\n");
750         goto cleanup;
751     }
752 
753     ok(count == sizeof(root_children)/sizeof(root_children[0]),
754        "Got unexpected count %u for the number of child containers\n", count);
755 
756     if (count != sizeof(root_children)/sizeof(root_children[0]))
757     {
758         skip("Received unexpected number of child containers\n");
759         goto cleanup;
760     }
761 
762     for (index = 0; index <= count; index++)
763     {
764         WCHAR container[256];
765 
766         hr = IDxDiagContainer_EnumChildContainerNames(pddc, index, container, sizeof(container)/sizeof(WCHAR));
767         if (hr == E_INVALIDARG)
768         {
769             ok(index == count,
770                "Expected IDxDiagContainer::EnumChildContainerNames to return "
771                "E_INVALIDARG on the last index %u\n", count);
772             break;
773         }
774         else if (hr == S_OK)
775         {
776             ok(!lstrcmpW(container, root_children[index]),
777                "Expected container %s for index %u, got %s\n",
778                wine_dbgstr_w(root_children[index]), index, wine_dbgstr_w(container));
779         }
780         else
781         {
782             ok(0, "IDxDiagContainer::EnumChildContainerNames unexpectedly returned 0x%08x\n", hr);
783             break;
784         }
785     }
786 
787 cleanup:
788     IDxDiagContainer_Release(pddc);
789     IDxDiagProvider_Release(pddp);
790 }
791 
792 static void test_container_properties(IDxDiagContainer *container, const struct property_test *property_tests, size_t len)
793 {
794     HRESULT hr;
795 
796     /* Check that the container has no properties if there are no properties to examine. */
797     if (len == 0)
798     {
799         DWORD prop_count;
800 
801         hr = IDxDiagContainer_GetNumberOfProps(container, &prop_count);
802         ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
803         if (hr == S_OK)
804             ok(prop_count == 0, "Expected container property count to be zero, got %u\n", prop_count);
805     }
806     else
807     {
808         VARIANT var;
809         int i;
810 
811         VariantInit(&var);
812 
813         /* Examine the variant types of obtained property values. */
814         for (i = 0; i < len; i++)
815         {
816             hr = IDxDiagContainer_GetProp(container, property_tests[i].prop, &var);
817             ok(hr == S_OK, "[%d] Expected IDxDiagContainer::GetProp to return S_OK for %s, got 0x%08x\n",
818                i, wine_dbgstr_w(property_tests[i].prop), hr);
819 
820             if (hr == S_OK)
821             {
822                 ok(V_VT(&var) == property_tests[i].vt,
823                    "[%d] Expected variant type %d, got %d\n", i, property_tests[i].vt, V_VT(&var));
824                 trace("%s = %s\n", wine_dbgstr_w(property_tests[i].prop), debugstr_variant(&var));
825                 VariantClear(&var);
826             }
827         }
828     }
829 }
830 
831 static void test_DxDiag_SystemInfo(void)
832 {
833     static const WCHAR dwOSMajorVersion[] = {'d','w','O','S','M','a','j','o','r','V','e','r','s','i','o','n',0};
834     static const WCHAR dwOSMinorVersion[] = {'d','w','O','S','M','i','n','o','r','V','e','r','s','i','o','n',0};
835     static const WCHAR dwOSBuildNumber[] = {'d','w','O','S','B','u','i','l','d','N','u','m','b','e','r',0};
836     static const WCHAR dwOSPlatformID[] = {'d','w','O','S','P','l','a','t','f','o','r','m','I','D',0};
837     static const WCHAR dwDirectXVersionMajor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','a','j','o','r',0};
838     static const WCHAR dwDirectXVersionMinor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','i','n','o','r',0};
839     static const WCHAR szDirectXVersionLetter[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','e','t','t','e','r',0};
840     static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
841     static const WCHAR bNECPC98[] = {'b','N','E','C','P','C','9','8',0};
842     static const WCHAR ullPhysicalMemory[] = {'u','l','l','P','h','y','s','i','c','a','l','M','e','m','o','r','y',0};
843     static const WCHAR ullUsedPageFile[] = {'u','l','l','U','s','e','d','P','a','g','e','F','i','l','e',0};
844     static const WCHAR ullAvailPageFile[] = {'u','l','l','A','v','a','i','l','P','a','g','e','F','i','l','e',0};
845     static const WCHAR szWindowsDir[] = {'s','z','W','i','n','d','o','w','s','D','i','r',0};
846     static const WCHAR szCSDVersion[] = {'s','z','C','S','D','V','e','r','s','i','o','n',0};
847     static const WCHAR szDirectXVersionEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','E','n','g','l','i','s','h',0};
848     static const WCHAR szDirectXVersionLongEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','o','n','g','E','n','g','l','i','s','h',0};
849     static const WCHAR bNetMeetingRunning[] = {'b','N','e','t','M','e','e','t','i','n','g','R','u','n','n','i','n','g',0};
850     static const WCHAR szMachineNameLocalized[] = {'s','z','M','a','c','h','i','n','e','N','a','m','e','L','o','c','a','l','i','z','e','d',0};
851     static const WCHAR szMachineNameEnglish[] = {'s','z','M','a','c','h','i','n','e','N','a','m','e','E','n','g','l','i','s','h',0};
852     static const WCHAR szLanguagesLocalized[] = {'s','z','L','a','n','g','u','a','g','e','s','L','o','c','a','l','i','z','e','d',0};
853     static const WCHAR szLanguagesEnglish[] = {'s','z','L','a','n','g','u','a','g','e','s','E','n','g','l','i','s','h',0};
854     static const WCHAR szTimeLocalized[] = {'s','z','T','i','m','e','L','o','c','a','l','i','z','e','d',0};
855     static const WCHAR szTimeEnglish[] = {'s','z','T','i','m','e','E','n','g','l','i','s','h',0};
856     static const WCHAR szPhysicalMemoryEnglish[] = {'s','z','P','h','y','s','i','c','a','l','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
857     static const WCHAR szPageFileLocalized[] = {'s','z','P','a','g','e','F','i','l','e','L','o','c','a','l','i','z','e','d',0};
858     static const WCHAR szPageFileEnglish[] = {'s','z','P','a','g','e','F','i','l','e','E','n','g','l','i','s','h',0};
859     static const WCHAR szOSLocalized[] = {'s','z','O','S','L','o','c','a','l','i','z','e','d',0};
860     static const WCHAR szOSExLocalized[] = {'s','z','O','S','E','x','L','o','c','a','l','i','z','e','d',0};
861     static const WCHAR szOSExLongLocalized[] = {'s','z','O','S','E','x','L','o','n','g','L','o','c','a','l','i','z','e','d',0};
862     static const WCHAR szOSEnglish[] = {'s','z','O','S','E','n','g','l','i','s','h',0};
863     static const WCHAR szOSExEnglish[] = {'s','z','O','S','E','x','E','n','g','l','i','s','h',0};
864     static const WCHAR szOSExLongEnglish[] = {'s','z','O','S','E','x','L','o','n','g','E','n','g','l','i','s','h',0};
865     static const WCHAR szProcessorEnglish[] = {'s','z','P','r','o','c','e','s','s','o','r','E','n','g','l','i','s','h',0};
866 
867     static const struct property_test property_tests[] =
868     {
869         {dwOSMajorVersion, VT_UI4},
870         {dwOSMinorVersion, VT_UI4},
871         {dwOSBuildNumber, VT_UI4},
872         {dwOSPlatformID, VT_UI4},
873         {dwDirectXVersionMajor, VT_UI4},
874         {dwDirectXVersionMinor, VT_UI4},
875         {szDirectXVersionLetter, VT_BSTR},
876         {bDebug, VT_BOOL},
877         {bNECPC98, VT_BOOL},
878         {ullPhysicalMemory, VT_BSTR},
879         {ullUsedPageFile, VT_BSTR},
880         {ullAvailPageFile, VT_BSTR},
881         {szWindowsDir, VT_BSTR},
882         {szCSDVersion, VT_BSTR},
883         {szDirectXVersionEnglish, VT_BSTR},
884         {szDirectXVersionLongEnglish, VT_BSTR},
885         {bNetMeetingRunning, VT_BOOL},
886         {szMachineNameLocalized, VT_BSTR},
887         {szMachineNameEnglish, VT_BSTR},
888         {szLanguagesLocalized, VT_BSTR},
889         {szLanguagesEnglish, VT_BSTR},
890         {szTimeLocalized, VT_BSTR},
891         {szTimeEnglish, VT_BSTR},
892         {szPhysicalMemoryEnglish, VT_BSTR},
893         {szPageFileLocalized, VT_BSTR},
894         {szPageFileEnglish, VT_BSTR},
895         {szOSLocalized, VT_BSTR},
896         {szOSExLocalized, VT_BSTR},
897         {szOSExLongLocalized, VT_BSTR},
898         {szOSEnglish, VT_BSTR},
899         {szOSExEnglish, VT_BSTR},
900         {szOSExLongEnglish, VT_BSTR},
901         {szProcessorEnglish, VT_BSTR},
902     };
903 
904     IDxDiagContainer *container, *container2;
905     static const WCHAR empty[] = {0};
906     HRESULT hr;
907 
908     if (!create_root_IDxDiagContainer())
909     {
910         skip("Unable to create the root IDxDiagContainer\n");
911         return;
912     }
913 
914     hr = IDxDiagContainer_GetChildContainer(pddc, empty, &container2);
915     ok(hr == E_INVALIDARG, "Expected IDxDiagContainer::GetChildContainer to return E_INVALIDARG, got 0x%08x\n", hr);
916 
917     hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_SystemInfo, &container);
918     ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
919 
920     if (hr == S_OK)
921     {
922         trace("Testing container DxDiag_SystemInfo\n");
923         test_container_properties(container, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
924 
925         container2 = NULL;
926         hr = IDxDiagContainer_GetChildContainer(container, empty, &container2);
927         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
928         ok(container2 != NULL, "Expected container2 != NULL\n");
929         ok(container2 != container, "Expected container != container2\n");
930         if (hr == S_OK) IDxDiagContainer_Release(container2);
931 
932         IDxDiagContainer_Release(container);
933     }
934 
935     IDxDiagContainer_Release(pddc);
936     IDxDiagProvider_Release(pddp);
937 }
938 
939 static void test_DxDiag_DisplayDevices(void)
940 {
941     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
942     static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
943     static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
944     static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
945     static const WCHAR szVendorId[] = {'s','z','V','e','n','d','o','r','I','d',0};
946     static const WCHAR szDeviceId[] = {'s','z','D','e','v','i','c','e','I','d',0};
947     static const WCHAR szDeviceIdentifier[] = {'s','z','D','e','v','i','c','e','I','d','e','n','t','i','f','i','e','r',0};
948     static const WCHAR dwWidth[] = {'d','w','W','i','d','t','h',0};
949     static const WCHAR dwHeight[] = {'d','w','H','e','i','g','h','t',0};
950     static const WCHAR dwBpp[] = {'d','w','B','p','p',0};
951     static const WCHAR szDisplayMemoryLocalized[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','L','o','c','a','l','i','z','e','d',0};
952     static const WCHAR szDisplayMemoryEnglish[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
953     static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
954     static const WCHAR szDriverVersion[] = {'s','z','D','r','i','v','e','r','V','e','r','s','i','o','n',0};
955     static const WCHAR szSubSysId[] = {'s','z','S','u','b','S','y','s','I','d',0};
956     static const WCHAR szRevisionId[] = {'s','z','R','e','v','i','s','i','o','n','I','d',0};
957     static const WCHAR dwRefreshRate[] = {'d','w','R','e','f','r','e','s','h','R','a','t','e',0};
958     static const WCHAR szManufacturer[] = {'s','z','M','a','n','u','f','a','c','t','u','r','e','r',0};
959     static const WCHAR b3DAccelerationExists[] = {'b','3','D','A','c','c','e','l','e','r','a','t','i','o','n','E','x','i','s','t','s',0};
960     static const WCHAR b3DAccelerationEnabled[] = {'b','3','D','A','c','c','e','l','e','r','a','t','i','o','n','E','n','a','b','l','e','d',0};
961     static const WCHAR bDDAccelerationEnabled[] = {'b','D','D','A','c','c','e','l','e','r','a','t','i','o','n','E','n','a','b','l','e','d',0};
962     static const WCHAR iAdapter[] = {'i','A','d','a','p','t','e','r',0};
963 
964     static const struct property_test property_tests[] =
965     {
966         {szDescription, VT_BSTR},
967         {szDeviceName, VT_BSTR},
968         {szKeyDeviceID, VT_BSTR},
969         {szKeyDeviceKey, VT_BSTR},
970         {szVendorId, VT_BSTR},
971         {szDeviceId, VT_BSTR},
972         {szDeviceIdentifier, VT_BSTR},
973         {dwWidth, VT_UI4},
974         {dwHeight, VT_UI4},
975         {dwBpp, VT_UI4},
976         {szDisplayMemoryLocalized, VT_BSTR},
977         {szDisplayMemoryEnglish, VT_BSTR},
978         {szDriverName, VT_BSTR},
979         {szDriverVersion, VT_BSTR},
980         {szSubSysId, VT_BSTR},
981         {szRevisionId, VT_BSTR},
982         {dwRefreshRate, VT_UI4},
983         {szManufacturer, VT_BSTR},
984         {b3DAccelerationExists, VT_BOOL},
985         {b3DAccelerationEnabled, VT_BOOL},
986         {bDDAccelerationEnabled, VT_BOOL},
987         {iAdapter, VT_UI4},
988     };
989 
990     IDxDiagContainer *display_cont = NULL;
991     DWORD count, i;
992     HRESULT hr;
993 
994     if (!create_root_IDxDiagContainer())
995     {
996         skip("Unable to create the root IDxDiagContainer\n");
997         return;
998     }
999 
1000     hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_DisplayDevices, &display_cont);
1001     ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1002 
1003     if (hr != S_OK)
1004         goto cleanup;
1005 
1006     hr = IDxDiagContainer_GetNumberOfProps(display_cont, &count);
1007     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
1008     if (hr == S_OK)
1009         ok(count == 0, "Expected count to be 0, got %u\n", count);
1010 
1011     hr = IDxDiagContainer_GetNumberOfChildContainers(display_cont, &count);
1012     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
1013 
1014     if (hr != S_OK)
1015         goto cleanup;
1016 
1017     for (i = 0; i < count; i++)
1018     {
1019         WCHAR child_container[256];
1020         IDxDiagContainer *child;
1021 
1022         hr = IDxDiagContainer_EnumChildContainerNames(display_cont, i, child_container, sizeof(child_container)/sizeof(WCHAR));
1023         ok(hr == S_OK, "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
1024 
1025         hr = IDxDiagContainer_GetChildContainer(display_cont, child_container, &child);
1026         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1027 
1028         if (hr == S_OK)
1029         {
1030             trace("Testing container %s\n", wine_dbgstr_w(child_container));
1031             test_container_properties(child, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
1032         }
1033         IDxDiagContainer_Release(child);
1034     }
1035 
1036 cleanup:
1037     if (display_cont) IDxDiagContainer_Release(display_cont);
1038     IDxDiagContainer_Release(pddc);
1039     IDxDiagProvider_Release(pddp);
1040 }
1041 
1042 static void test_DxDiag_SoundDevices(void)
1043 {
1044     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
1045     static const WCHAR szGuidDeviceID[] = {'s','z','G','u','i','d','D','e','v','i','c','e','I','D',0};
1046     static const WCHAR szDriverPath[] = {'s','z','D','r','i','v','e','r','P','a','t','h',0};
1047     static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
1048     static const WCHAR empty[] = {0};
1049 
1050     static const struct property_test property_tests[] =
1051     {
1052         {szDescription, VT_BSTR},
1053         {szGuidDeviceID, VT_BSTR},
1054         {szDriverName, VT_BSTR},
1055         {szDriverPath, VT_BSTR},
1056     };
1057 
1058     IDxDiagContainer *sound_cont = NULL;
1059     DWORD count, i;
1060     HRESULT hr;
1061 
1062     if (!create_root_IDxDiagContainer())
1063     {
1064         skip("Unable to create the root IDxDiagContainer\n");
1065         return;
1066     }
1067 
1068     hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_SoundDevices, &sound_cont);
1069     ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1070 
1071     if (hr != S_OK)
1072         goto cleanup;
1073 
1074     hr = IDxDiagContainer_GetNumberOfProps(sound_cont, &count);
1075     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
1076     if (hr == S_OK)
1077         ok(count == 0, "Expected count to be 0, got %u\n", count);
1078 
1079     hr = IDxDiagContainer_GetNumberOfChildContainers(sound_cont, &count);
1080     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
1081 
1082     if (hr != S_OK)
1083         goto cleanup;
1084 
1085     for (i = 0; i < count; i++)
1086     {
1087         WCHAR child_container[256];
1088         IDxDiagContainer *child, *child2;
1089 
1090         hr = IDxDiagContainer_EnumChildContainerNames(sound_cont, i, child_container, sizeof(child_container)/sizeof(WCHAR));
1091         ok(hr == S_OK, "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
1092 
1093         hr = IDxDiagContainer_GetChildContainer(sound_cont, child_container, &child);
1094         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1095 
1096         if (hr == S_OK)
1097         {
1098             trace("Testing container %s\n", wine_dbgstr_w(child_container));
1099             test_container_properties(child, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
1100         }
1101 
1102         child2 = NULL;
1103         hr = IDxDiagContainer_GetChildContainer(child, empty, &child2);
1104         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1105         ok(child2 != NULL, "Expected child2 != NULL\n");
1106         ok(child2 != child, "Expected child != child2\n");
1107         if (hr == S_OK) IDxDiagContainer_Release(child2);
1108 
1109         IDxDiagContainer_Release(child);
1110     }
1111 
1112 cleanup:
1113     if (sound_cont) IDxDiagContainer_Release(sound_cont);
1114     IDxDiagContainer_Release(pddc);
1115     IDxDiagProvider_Release(pddp);
1116 }
1117 
1118 static void test_DxDiag_SoundCaptureDevices(void)
1119 {
1120     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
1121     static const WCHAR szGuidDeviceID[] = {'s','z','G','u','i','d','D','e','v','i','c','e','I','D',0};
1122     static const WCHAR szDriverPath[] = {'s','z','D','r','i','v','e','r','P','a','t','h',0};
1123     static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
1124 
1125     static const struct property_test property_tests[] =
1126     {
1127         {szDescription, VT_BSTR},
1128         {szGuidDeviceID, VT_BSTR},
1129         {szDriverName, VT_BSTR},
1130         {szDriverPath, VT_BSTR},
1131     };
1132 
1133     IDxDiagContainer *sound_cont = NULL;
1134     DWORD count, i;
1135     HRESULT hr;
1136 
1137     if (!create_root_IDxDiagContainer())
1138     {
1139         skip("Unable to create the root IDxDiagContainer\n");
1140         return;
1141     }
1142 
1143     hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_SoundCaptureDevices, &sound_cont);
1144     ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1145 
1146     if (hr != S_OK)
1147         goto cleanup;
1148 
1149     hr = IDxDiagContainer_GetNumberOfProps(sound_cont, &count);
1150     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
1151     if (hr == S_OK)
1152         ok(count == 0, "Expected count to be 0, got %u\n", count);
1153 
1154     hr = IDxDiagContainer_GetNumberOfChildContainers(sound_cont, &count);
1155     ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
1156 
1157     if (hr != S_OK)
1158         goto cleanup;
1159 
1160     for (i = 0; i < count; i++)
1161     {
1162         WCHAR child_container[256];
1163         IDxDiagContainer *child;
1164 
1165         hr = IDxDiagContainer_EnumChildContainerNames(sound_cont, i, child_container, sizeof(child_container)/sizeof(WCHAR));
1166         ok(hr == S_OK, "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
1167 
1168         hr = IDxDiagContainer_GetChildContainer(sound_cont, child_container, &child);
1169         ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
1170 
1171         if (hr == S_OK)
1172         {
1173             trace("Testing container %s\n", wine_dbgstr_w(child_container));
1174             test_container_properties(child, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
1175         }
1176         IDxDiagContainer_Release(child);
1177     }
1178 
1179 cleanup:
1180     if (sound_cont) IDxDiagContainer_Release(sound_cont);
1181     IDxDiagContainer_Release(pddc);
1182     IDxDiagProvider_Release(pddp);
1183 }
1184 
1185 START_TEST(container)
1186 {
1187     CoInitialize(NULL);
1188     test_GetNumberOfChildContainers();
1189     test_GetNumberOfProps();
1190     test_EnumChildContainerNames();
1191     test_GetChildContainer();
1192     test_dot_parsing();
1193     test_EnumPropNames();
1194     test_GetProp();
1195 
1196     test_root_children();
1197     test_DxDiag_SystemInfo();
1198     test_DxDiag_DisplayDevices();
1199     test_DxDiag_SoundDevices();
1200     test_DxDiag_SoundCaptureDevices();
1201     CoUninitialize();
1202 }
1203