provider.c 28.6 KB
Newer Older
1 2 3
/* 
 * IDxDiagProvider Implementation
 * 
4
 * Copyright 2004-2005 Raphael Junqueira
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 23
 *
 */

#include "config.h"
#include "wine/debug.h"
24 25 26

#define COBJMACROS
#include "dxdiag_private.h"
27
#include "wine/unicode.h"
28 29 30 31 32 33
#include "winver.h"
#include "objidl.h"
#include "dshow.h"
#include "strmif.h"
#include "vfw.h"
#include "mmddk.h"
34 35 36 37

WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);

/* IDxDiagProvider IUnknown parts follow: */
38
static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(PDXDIAGPROVIDER iface, REFIID riid, LPVOID *ppobj)
39
{
40
    IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
41 42 43

    if (IsEqualGUID(riid, &IID_IUnknown)
        || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
44
        IUnknown_AddRef(iface);
45 46 47 48 49 50 51 52
        *ppobj = This;
        return S_OK;
    }

    WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
    return E_NOINTERFACE;
}

53
static ULONG WINAPI IDxDiagProviderImpl_AddRef(PDXDIAGPROVIDER iface) {
54
    IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
55 56 57 58
    ULONG refCount = InterlockedIncrement(&This->ref);

    TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);

59 60
    DXDIAGN_LockModule();

61
    return refCount;
62 63
}

64
static ULONG WINAPI IDxDiagProviderImpl_Release(PDXDIAGPROVIDER iface) {
65
    IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
66 67 68 69 70
    ULONG refCount = InterlockedDecrement(&This->ref);

    TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);

    if (!refCount) {
71 72
        HeapFree(GetProcessHeap(), 0, This);
    }
73 74 75

    DXDIAGN_UnlockModule();
    
76
    return refCount;
77 78 79
}

/* IDxDiagProvider Interface follow: */
80
static HRESULT WINAPI IDxDiagProviderImpl_Initialize(PDXDIAGPROVIDER iface, DXDIAG_INIT_PARAMS* pParams) {
81
    IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
82 83 84 85 86 87 88 89 90 91 92 93
    TRACE("(%p,%p)\n", iface, pParams);

    if (NULL == pParams) {
      return E_POINTER;
    }
    if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS)) {
      return E_INVALIDARG;
    }

    This->init = TRUE;
    memcpy(&This->params, pParams, pParams->dwSize);
    return S_OK;
94 95
}

96
static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(PDXDIAGPROVIDER iface, IDxDiagContainer** ppInstance) {
97
  HRESULT hr = S_OK;
98
  IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
99 100 101 102 103 104 105 106 107 108 109 110 111
  TRACE("(%p,%p)\n", iface, ppInstance);

  if (NULL == ppInstance) {
    return E_INVALIDARG;
  }
  if (FALSE == This->init) {
    return E_INVALIDARG; /* should be E_CO_UNINITIALIZED */
  }
  if (NULL == This->pRootContainer) {
    hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &This->pRootContainer);
    if (FAILED(hr)) {
      return hr;
    }
112
    hr = DXDiag_InitRootDXDiagContainer((PDXDIAGCONTAINER)This->pRootContainer);
113 114
  }
  return IDxDiagContainerImpl_QueryInterface((PDXDIAGCONTAINER)This->pRootContainer, &IID_IDxDiagContainer, (void**) ppInstance);
115 116
}

117
static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
{
    IDxDiagProviderImpl_QueryInterface,
    IDxDiagProviderImpl_AddRef,
    IDxDiagProviderImpl_Release,
    IDxDiagProviderImpl_Initialize,
    IDxDiagProviderImpl_GetRootContainer
};

HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
  IDxDiagProviderImpl* provider;

  TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
  
  provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
  if (NULL == provider) {
    *ppobj = NULL;
    return E_OUTOFMEMORY;
  }
  provider->lpVtbl = &DxDiagProvider_Vtbl;
  provider->ref = 0; /* will be inited with QueryInterface */
  return IDxDiagProviderImpl_QueryInterface ((PDXDIAGPROVIDER)provider, riid, ppobj);
139
} 
140

141 142 143 144
/**
 * @param szFilePath: usually GetSystemDirectoryW
 * @param szFileName: name of the dll without path
 */
145
static HRESULT DXDiag_AddFileDescContainer(IDxDiagContainer* pSubCont, const WCHAR* szFilePath, const WCHAR* szFileName) {
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  HRESULT hr = S_OK;
  /**/
  static const WCHAR szSlashSep[] = {'\\',0};
  static const WCHAR szPath[] = {'s','z','P','a','t','h',0};
  static const WCHAR szName[] = {'s','z','N','a','m','e',0};
  static const WCHAR szVersion[] = {'s','z','V','e','r','s','i','o','n',0};
  static const WCHAR szAttributes[] = {'s','z','A','t','t','r','i','b','u','t','e','s',0};
  static const WCHAR szLanguageEnglish[] = {'s','z','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
  static const WCHAR dwFileTimeHigh[] = {'d','w','F','i','l','e','T','i','m','e','H','i','g','h',0};
  static const WCHAR dwFileTimeLow[] = {'d','w','F','i','l','e','T','i','m','e','L','o','w',0};
  static const WCHAR bBeta[] = {'b','B','e','t','a',0};
  static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
  static const WCHAR bExists[] = {'b','E','x','i','s','t','s',0};
  /** values */
  static const WCHAR szFinal_Retail_v[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
  static const WCHAR szEnglish_v[] = {'E','n','g','l','i','s','h',0};
  static const WCHAR szVersionFormat[] = {'%','u','.','%','0','2','u','.','%','0','4','u','.','%','0','4','u',0};
  VARIANT v;

  WCHAR szFile[512];
  WCHAR szVersion_v[1024];
  DWORD retval, hdl;
  LPVOID pVersionInfo;
  BOOL boolret;
  UINT uiLength;
  VS_FIXEDFILEINFO* pFileInfo;

  FIXME("(%p,%s)\n", pSubCont, debugstr_w(szFileName));
  
  lstrcpyW(szFile, szFilePath);
  lstrcatW(szFile, szSlashSep);
  lstrcatW(szFile, szFileName);

  retval = GetFileVersionInfoSizeW(szFile, &hdl);
  pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
  hr = GetFileVersionInfoW(szFile, 0, retval, pVersionInfo); 
  boolret = VerQueryValueW(pVersionInfo, (LPWSTR) szSlashSep, (LPVOID) &pFileInfo, &uiLength);

  V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szFile);
  hr = IDxDiagContainerImpl_AddProp(pSubCont, szPath, &v);
186
  VariantClear(&v);
187 188
  V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szFileName);
  hr = IDxDiagContainerImpl_AddProp(pSubCont, szName, &v);
189
  VariantClear(&v);
190 191
  V_VT(&v) = VT_BOOL; V_BOOL(&v) = boolret;
  hr = IDxDiagContainerImpl_AddProp(pSubCont, bExists, &v);  
192
  VariantClear(&v);
193 194 195 196 197 198 199 200 201 202 203 204 205

  if (boolret) {
    snprintfW(szVersion_v, sizeof(szVersion_v), 
	      szVersionFormat,
	      HIWORD(pFileInfo->dwFileVersionMS), 
	      LOWORD(pFileInfo->dwFileVersionMS),
	      HIWORD(pFileInfo->dwFileVersionLS),
	      LOWORD(pFileInfo->dwFileVersionLS));

    TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));

    V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szVersion_v);
    hr = IDxDiagContainerImpl_AddProp(pSubCont, szVersion, &v);
206
    VariantClear(&v);
207 208
    V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szFinal_Retail_v);
    hr = IDxDiagContainerImpl_AddProp(pSubCont, szAttributes, &v);
209
    VariantClear(&v);
210 211
    V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szEnglish_v);
    hr = IDxDiagContainerImpl_AddProp(pSubCont, szLanguageEnglish, &v);
212
    VariantClear(&v);
213 214
    V_VT(&v) = VT_UI4; V_UI4(&v) = pFileInfo->dwFileDateMS;
    hr = IDxDiagContainerImpl_AddProp(pSubCont, dwFileTimeHigh, &v);
215
    VariantClear(&v);
216 217
    V_VT(&v) = VT_UI4; V_UI4(&v) = pFileInfo->dwFileDateLS;
    hr = IDxDiagContainerImpl_AddProp(pSubCont, dwFileTimeLow, &v);
218
    VariantClear(&v);
219 220
    V_VT(&v) = VT_BOOL; V_BOOL(&v) = (0 != ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE));
    hr = IDxDiagContainerImpl_AddProp(pSubCont, bBeta, &v);  
221
    VariantClear(&v);
222 223
    V_VT(&v) = VT_BOOL; V_BOOL(&v) = (0 != ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG));
    hr = IDxDiagContainerImpl_AddProp(pSubCont, bDebug, &v);  
224
    VariantClear(&v);
225 226 227 228 229 230 231
  }

  HeapFree(GetProcessHeap(), 0, pVersionInfo);

  return hr;
}

232
static HRESULT DXDiag_InitDXDiagSystemInfoContainer(IDxDiagContainer* pSubCont) {
233
  HRESULT hr = S_OK;
234 235 236 237
  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};
  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};
  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};
  static const WCHAR szDirectXVersionLetter_v[] = {'c',0};
238 239 240 241 242 243 244 245 246 247 248 249
  static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
  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};
  static const WCHAR szDirectXVersionEnglish_v[] = {'4','.','0','9','.','0','0','0','0','.','0','9','0','4',0};
  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};
  static const WCHAR szDirectXVersionLongEnglish_v[] = {'=',' ','"','D','i','r','e','c','t','X',' ','9','.','0','c',' ','(','4','.','0','9','.','0','0','0','0','.','0','9','0','4',')',0};
  /*static const WCHAR szDxDiagVersion[] = {'s','z','D','x','D','i','a','g','V','e','r','s','i','o','n',0};*/
  /*szWindowsDir*/
  /*szWindowsDir*/
  /*"dwOSMajorVersion"*/
  /*"dwOSMinorVersion"*/
  /*"dwOSBuildNumber"*/
  /*"dwOSPlatformID"*/
250 251 252 253
  VARIANT v;

  V_VT(&v) = VT_UI4; V_UI4(&v) = 9;
  hr = IDxDiagContainerImpl_AddProp(pSubCont, dwDirectXVersionMajor, &v);
254
  VariantClear(&v);
255 256
  V_VT(&v) = VT_UI4; V_UI4(&v) = 0;
  hr = IDxDiagContainerImpl_AddProp(pSubCont, dwDirectXVersionMinor, &v);
257
  VariantClear(&v);
258 259
  V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szDirectXVersionLetter_v);
  hr = IDxDiagContainerImpl_AddProp(pSubCont, szDirectXVersionLetter, &v);
260
  VariantClear(&v);
261 262
  V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szDirectXVersionEnglish_v);
  hr = IDxDiagContainerImpl_AddProp(pSubCont, szDirectXVersionEnglish, &v);
263
  VariantClear(&v);
264 265
  V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(szDirectXVersionLongEnglish_v);
  hr = IDxDiagContainerImpl_AddProp(pSubCont, szDirectXVersionLongEnglish, &v);
266
  VariantClear(&v);
267 268
  V_VT(&v) = VT_BOOL; V_BOOL(&v) = FALSE;
  hr = IDxDiagContainerImpl_AddProp(pSubCont, bDebug, &v);
269
  VariantClear(&v);
270 271 272 273

  return hr;
}

274
static HRESULT DXDiag_InitDXDiagSystemDevicesContainer(IDxDiagContainer* pSubCont) {
275 276 277 278
  HRESULT hr = S_OK;
  /*
  static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
  static const WCHAR szDeviceID[] = {'s','z','D','e','v','i','c','e','I','D',0};
279 280 281

  static const WCHAR szDrivers[] = {'s','z','D','r','i','v','e','r','s',0};

282 283
  VARIANT v;
  IDxDiagContainer* pDeviceSubCont = NULL;
284 285
  IDxDiagContainer* pDriversCont = NULL;

286 287
  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pDeviceSubCont);
  if (FAILED(hr)) { return hr; }
288
  V_VT(pvarProp) = VT_BSTR; V_BSTR(pvarProp) = SysAllocString(property->psz);
289
  hr = IDxDiagContainerImpl_AddProp(pDeviceSubCont, szDescription, &v);
290 291
  VariantClear(&v);
  V_VT(pvarProp) = VT_BSTR; V_BSTR(pvarProp) = SysAllocString(property->psz);
292
  hr = IDxDiagContainerImpl_AddProp(pDeviceSubCont, szDeviceID, &v);
293
  VariantClear(&v);
294 295

  hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, "", pDeviceSubCont);
296 297 298 299 300 301 302 303 304 305
  */

  /*
   * Drivers Cont contains Files Desc Containers
   */
  /*
  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pDriversCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pDeviceSubCont, szDrivers, pDriversCont);

306 307 308 309
  */
  return hr;
}

310
static HRESULT DXDiag_InitDXDiagLogicalDisksContainer(IDxDiagContainer* pSubCont) {
311 312 313 314 315 316 317 318 319
  HRESULT hr = S_OK;
  /*
  static const WCHAR szDriveLetter[] = {'s','z','D','r','i','v','e','L','e','t','t','e','r',0};
  static const WCHAR szFreeSpace[] = {'s','z','F','r','e','e','S','p','a','c','e',0};
  static const WCHAR szMaxSpace[] = {'s','z','M','a','x','S','p','a','c','e',0};
  static const WCHAR szFileSystem[] = {'s','z','F','i','l','e','S','y','s','t','e','m',0};
  static const WCHAR szModel[] = {'s','z','M','o','d','e','l',0};
  static const WCHAR szPNPDeviceID[] = {'s','z','P','N','P','D','e','v','i','c','e','I','D',0};
  static const WCHAR dwHardDriveIndex[] = {'d','w','H','a','r','d','D','r','i','v','e','I','n','d','e','x',0};
320 321 322

  static const WCHAR szDrivers[] = {'s','z','D','r','i','v','e','r','s',0};
 
323 324
  VARIANT v;
  IDxDiagContainer* pDiskSubCont = NULL;
325
  IDxDiagContainer* pDriversCont = NULL;
326 327 328 329 330

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pDiskSubCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, "" , pDiskSubCont);
  */
331 332 333 334 335 336 337 338 339
  
  /*
   * Drivers Cont contains Files Desc Containers
   */
  /*
  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pDriversCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pDeviceSubCont, szDrivers, pDriversCont);
  */
340 341
  return hr;
}
342
static HRESULT DXDiag_InitDXDiagDirectXFilesContainer(IDxDiagContainer* pSubCont) {
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
  HRESULT hr = S_OK;
  /**/
  static const WCHAR ddraw_dll[] = {'d','d','r','a','w','.','d','l','l',0};
  static const WCHAR dplayx_dll[] = {'d','p','l','a','y','x','.','d','l','l',0};
  static const WCHAR dpnet_dll[] = {'d','p','n','e','t','.','d','l','l',0};
  static const WCHAR dinput_dll[] = {'d','i','n','p','u','t','.','d','l','l',0};
  static const WCHAR dinput8_dll[] = {'d','i','n','p','u','t','8','.','d','l','l',0};
  static const WCHAR dsound_dll[] = {'d','s','o','u','n','d','.','d','l','l',0};
  static const WCHAR dswave_dll[] = {'d','s','w','a','v','e','.','d','l','l',0};
  static const WCHAR d3d8_dll[] = {'d','3','d','8','.','d','l','l',0};
  static const WCHAR d3d9_dll[] = {'d','3','d','9','.','d','l','l',0};
  static const WCHAR dmband_dll[] = {'d','m','b','a','n','d','.','d','l','l',0};
  static const WCHAR dmcompos_dll[] = {'d','m','c','o','m','p','o','s','.','d','l','l',0};
  static const WCHAR dmime_dll[] =  {'d','m','i','m','e','.','d','l','l',0};
  static const WCHAR dmloader_dll[] = {'d','m','l','o','a','d','e','r','.','d','l','l',0};
  static const WCHAR dmscript_dll[] = {'d','m','s','c','r','i','p','t','.','d','l','l',0};
  static const WCHAR dmstyle_dll[] = {'d','m','s','t','y','l','e','.','d','l','l',0};
  static const WCHAR dmsynth_dll[] = {'d','m','s','y','n','t','h','.','d','l','l',0};
  static const WCHAR dmusic_dll[] = {'d','m','u','s','i','c','.','d','l','l',0};
362 363
  static const WCHAR devenum_dll[] = {'d','e','v','e','n','u','m','.','d','l','l',0};
  static const WCHAR quartz_dll[] = {'q','u','a','r','t','z','.','d','l','l',0};
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
  WCHAR szFilePath[512];

  hr = GetSystemDirectoryW(szFilePath, MAX_PATH);
  if (FAILED(hr)) { return hr; }  
  szFilePath[MAX_PATH-1]=0;     

  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, ddraw_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dplayx_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dpnet_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dinput_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dinput8_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dsound_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dswave_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, d3d8_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, d3d9_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmband_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmcompos_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmime_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmloader_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmscript_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmstyle_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmsynth_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, dmusic_dll);
387 388
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, devenum_dll);
  hr = DXDiag_AddFileDescContainer(pSubCont, szFilePath, quartz_dll);
389 390 391
  return hr;
}

392
static HRESULT DXDiag_InitDXDiagDisplayContainer(IDxDiagContainer* pSubCont) {
393 394
  HRESULT hr = S_OK;
  /*
395 396 397 398 399
  static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
  static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
  static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
  static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
  WCHAR szAdapterName[512];
400
  VARIANT v;
401 402 403 404
  IDxDiagContainer* pDisplayAdapterSubCont = NULL;
  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pDisplayAdapterSubCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, szAdapterName, pDisplayAdapterSubCont);  
405 406 407 408
  */
  return hr;
}

409
static HRESULT DXDiag_InitDXDiagDirectSoundContainer(IDxDiagContainer* pSubCont) {
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
  HRESULT hr = S_OK;
  static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
  static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e','D','e','v','i','c','e','s',0};
  IDxDiagContainer* pSubSubCont = NULL;

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubSubCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, DxDiag_SoundDevices, pSubSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubSubCont);
  if (FAILED(hr)) { return hr; }
  hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, DxDiag_SoundCaptureDevices, pSubSubCont);

  return hr;
}
425

426
static HRESULT DXDiag_InitDXDiagDirectMusicContainer(IDxDiagContainer* pSubCont) {
427 428 429
  HRESULT hr = S_OK;
  return hr;
}
430 431

static HRESULT DXDiag_InitDXDiagDirectInputContainer(IDxDiagContainer* pSubCont) {
432 433 434
  HRESULT hr = S_OK;
  return hr;
}
435 436

static HRESULT DXDiag_InitDXDiagDirectPlayContainer(IDxDiagContainer* pSubCont) {
437 438 439
  HRESULT hr = S_OK;
  return hr;
}
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462

struct REG_RF {
  DWORD dwVersion;
  DWORD dwMerit;
  DWORD dwPins;
  DWORD dwUnused;
};
struct REG_RFP {
  BYTE signature[4]; /* e.g. "0pi3" */
  DWORD dwFlags;
  DWORD dwInstances;
  DWORD dwMediaTypes;
  DWORD dwMediums;
  DWORD bCategory; /* is there a category clsid? */
  /* optional: dwOffsetCategoryClsid */
};
struct REG_TYPE {
  BYTE signature[4]; /* e.g. "0ty3" */
  DWORD dwUnused;
  DWORD dwOffsetMajor;
  DWORD dwOffsetMinor;
};

463
static HRESULT DXDiag_InitDXDiagDirectShowFiltersContainer(IDxDiagContainer* pSubCont) {
464
  HRESULT hr = S_OK;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
  static const WCHAR szName[] = {'s','z','N','a','m','e',0};
  static const WCHAR szCatName[] = {'s','z','C','a','t','N','a','m','e',0};
  static const WCHAR szClsidCat[] = {'s','z','C','l','s','i','d','C','a','t',0};
  static const WCHAR szClsidFilter[] = {'s','z','C','l','s','i','d','F','i','l','t','e','r',0};
  static const WCHAR dwInputs[] = {'d','w','I','n','p','u','t','s',0};
  static const WCHAR dwOutputs[] = {'d','w','O','u','t','p','u','t','s',0};
  static const WCHAR dwMerit[] = {'d','w','M','e','r','i','t',0};
  /*
  static const WCHAR szFileName[] = {'s','z','F','i','l','e','N','a','m','e',0};
  static const WCHAR szFileVersion[] = {'s','z','F','i','l','e','V','e','r','s','i','o','n',0};
  */
  VARIANT v;

  static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
  static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};  
  static const WCHAR wszFilterDataName[] = {'F','i','l','t','e','r','D','a','t','a',0};
  /*static const WCHAR wszMeritName[] = {'M','e','r','i','t',0};*/

  ICreateDevEnum* pCreateDevEnum = NULL;
  IEnumMoniker* pEmCat = NULL;
  IMoniker* pMCat = NULL;
  /** */
  hr = CoCreateInstance(&CLSID_SystemDeviceEnum, 
			NULL, 
			CLSCTX_INPROC_SERVER,
			&IID_ICreateDevEnum, 
			(void**) &pCreateDevEnum);
  if (FAILED(hr)) return hr; 
  
  hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
  if (FAILED(hr)) goto out_show_filters; 

  VariantInit(&v);

  while (S_OK == IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL)) {
    IPropertyBag* pPropBag = NULL;
    CLSID clsidCat; 
    hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void**) &pPropBag);
    if (SUCCEEDED(hr)) {
      WCHAR* wszCatName = NULL;
      WCHAR* wszCatClsid = NULL;

      hr = IPropertyBag_Read(pPropBag, wszFriendlyName, &v, 0);
      wszCatName = SysAllocString(V_BSTR(&v));
      VariantClear(&v);

      hr = IPropertyBag_Read(pPropBag, wszClsidName, &v, 0);
      wszCatClsid = SysAllocString(V_BSTR(&v));
      hr = CLSIDFromString(V_UNION(&v, bstrVal), &clsidCat);
      VariantClear(&v);

      /*
      hr = IPropertyBag_Read(pPropBag, wszMeritName, &v, 0);
      hr = IDxDiagContainerImpl_AddProp(pSubCont, dwMerit, &v);
      VariantClear(&v);
      */

      if (SUCCEEDED(hr)) {
	IEnumMoniker* pEnum = NULL;
	IMoniker* pMoniker = NULL;
        hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);        
526
        FIXME("\tClassEnumerator for clsid(%s) pEnum(%p)\n", debugstr_guid(&clsidCat), pEnum);
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
        if (FAILED(hr) || pEnum == NULL) {
          goto class_enum_failed;
        }
        while (NULL != pEnum && S_OK == IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL)) {          
	  IPropertyBag* pPropFilterBag = NULL;
          FIXME("\tIEnumMoniker_Next(%p, 1, %p)\n", pEnum, pMoniker);
	  hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void**) &pPropFilterBag);
	  if (SUCCEEDED(hr)) {
	    LPBYTE pData = NULL;
	    LPBYTE pCurrent = NULL;
	    struct REG_RF* prrf = NULL;
	    VARIANT v_data;
	    DWORD it;
	    DWORD dwNOutputs = 0;
	    DWORD dwNInputs = 0;
	    	    
	    V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(wszCatName);
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, szCatName, &v);
	    VariantClear(&v);

	    V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(wszCatClsid);
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, szClsidCat, &v);
	    VariantClear(&v);

	    hr = IPropertyBag_Read(pPropFilterBag, wszFriendlyName, &v, 0);
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, szName, &v);
	    FIXME("\tName:%s\n", debugstr_w(V_BSTR(&v)));
	    VariantClear(&v);

	    hr = IPropertyBag_Read(pPropFilterBag, wszClsidName, &v, 0);
	    FIXME("\tClsid:%s\n", debugstr_w(V_BSTR(&v)));
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, szClsidFilter, &v);
	    VariantClear(&v);

	    hr = IPropertyBag_Read(pPropFilterBag, wszFilterDataName, &v, NULL);
	    hr = SafeArrayAccessData(V_UNION(&v, parray), (LPVOID*) &pData);	    
	    prrf = (struct REG_RF*) pData;
	    pCurrent = pData;
 
	    VariantInit(&v_data);
	    V_VT(&v_data) = VT_UI4; V_UI4(&v_data) = prrf->dwVersion;
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, szName, &v_data);
	    VariantClear(&v_data);
	    V_VT(&v_data) = VT_UI4; V_UI4(&v_data) = prrf->dwMerit;
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, dwMerit, &v_data);
	    VariantClear(&v_data);

	    pCurrent += sizeof(struct REG_RF);
	    for (it = 0; it < prrf->dwPins; ++it) {
	      struct REG_RFP* prrfp = (struct REG_RFP*) pCurrent;
	      UINT j;

	      if (prrfp->dwFlags & REG_PINFLAG_B_OUTPUT) ++dwNOutputs;
	      else ++dwNInputs;

	      pCurrent += sizeof(struct REG_RFP);
	      if (prrfp->bCategory) {
		pCurrent += sizeof(DWORD);
	      }
	      for (j = 0; j < prrfp->dwMediaTypes; ++j) {
                struct REG_TYPE* prt = (struct REG_TYPE *)pCurrent;
                pCurrent += sizeof(*prt);
	      }
	      for (j = 0; j < prrfp->dwMediums; ++j) {
		DWORD dwOffset = *(DWORD*) pCurrent;
		pCurrent += sizeof(dwOffset);
	      }
	    }

	    V_VT(&v_data) = VT_UI4; V_UI4(&v_data) = dwNInputs;
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, dwInputs, &v_data);
	    VariantClear(&v_data);
	    V_VT(&v_data) = VT_UI4; V_UI4(&v_data) = dwNOutputs;
	    hr = IDxDiagContainerImpl_AddProp(pSubCont, dwOutputs, &v_data);
	    VariantClear(&v_data);

	    SafeArrayUnaccessData(V_UNION(&v, parray));
	    VariantClear(&v);
	  }
	  IPropertyBag_Release(pPropFilterBag); pPropFilterBag = NULL;
	}
	IEnumMoniker_Release(pEnum); pEnum = NULL;
      }
class_enum_failed:      
      SysFreeString(wszCatName);
      SysFreeString(wszCatClsid);
      IPropertyBag_Release(pPropBag); pPropBag = NULL;
    }
    IEnumMoniker_Release(pMCat); pMCat = NULL;
  }

out_show_filters:
  if (NULL != pEmCat) { IEnumMoniker_Release(pEmCat); pEmCat = NULL; }
  if (NULL != pCreateDevEnum) { ICreateDevEnum_Release(pCreateDevEnum); pCreateDevEnum = NULL; }
621 622 623
  return hr;
}

624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
HRESULT DXDiag_InitRootDXDiagContainer(IDxDiagContainer* pRootCont) {
  HRESULT hr = S_OK;
  static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
  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};
  static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
  static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
  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};
  static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
  static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
  static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
  static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
  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};
  IDxDiagContainer* pSubCont = NULL;
  
  TRACE("(%p)\n", pRootCont);
639

640 641 642
  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
  hr = DXDiag_InitDXDiagSystemInfoContainer(pSubCont);
643
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_SystemInfo, pSubCont);
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
  hr = DXDiag_InitDXDiagSystemDevicesContainer(pSubCont);
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_SystemDevices, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
  hr = DXDiag_InitDXDiagLogicalDisksContainer(pSubCont);
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_LogicalDisks, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
  hr = DXDiag_InitDXDiagDirectXFilesContainer(pSubCont);
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectXFiles, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
662
  hr = DXDiag_InitDXDiagDisplayContainer(pSubCont);
663 664 665 666 667 668 669 670 671
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DisplayDevices, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
  hr = DXDiag_InitDXDiagDirectSoundContainer(pSubCont);
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectSound, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
672
  hr = DXDiag_InitDXDiagDirectMusicContainer(pSubCont);
673 674 675 676
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectMusic, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
677
  hr = DXDiag_InitDXDiagDirectInputContainer(pSubCont);
678 679 680 681
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectInput, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
682
  hr = DXDiag_InitDXDiagDirectPlayContainer(pSubCont);
683 684 685 686
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectPlay, pSubCont);

  hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (void**) &pSubCont);
  if (FAILED(hr)) { return hr; }
687
  hr = DXDiag_InitDXDiagDirectShowFiltersContainer(pSubCont);
688 689
  hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, DxDiag_DirectShowFilters, pSubCont);

690 691
  return hr;
}