Check which version of DirectX is installed

断了今生、忘了曾经 提交于 2020-01-21 05:16:28

问题


As per the title, how can I check which version of DirectX a user has installed? Checking the FeatureLevel isn't enough, as my application can run on feature level 10.0, but requires that DirectX 11.1 be installed.

Why this is not a duplicate:

  • How to code to get direct X version on my machine in C#?
    • The first answer in this question says "If Windows 7, DirectX = 11, if Windows Vista, DirectX = 10". This is wrong, as Vista supports both DirectX 10 and 11 and Windows 7 supports DirectX 11 and 11.1.
    • The second answer references a registry key which only applies to DirectX 9 and lower. Even on a Windows 7 system with DirectX 11.1 installed, this registry key will never indicate an installed version greater than 9.0c
  • .NET How to detect if DirectX 10 is supported?
    • The answer to this question yet again references the same registry key for DirectX 9 and lower ONLY.

I need an answer that applies to DirectX 10 installs and up. That means determining if their version is 10, 10.1, 11 or 11.1.


回答1:


EDIT: Removed registry check method because it works only for Dx <=9 (thx @Telanor)

This method is very, very slow, but only one I figured out that is 100% accurate

private static int checkdxversion_dxdiag()
{
    Process.Start("dxdiag", "/x dxv.xml");
    while (!File.Exists("dxv.xml"))
        Thread.Sleep(1000);
    XmlDocument doc = new XmlDocument();
    doc.Load("dxv.xml");
    XmlNode dxd = doc.SelectSingleNode("//DxDiag");
    XmlNode dxv = dxd.SelectSingleNode("//DirectXVersion");

    return Convert.ToInt32(dxv.InnerText.Split(' ')[1]);
}



回答2:


Another possibility is using the IDxDiagProvider COM object directly and browse through the IDxDiagContainer hierarchy it yields - this is what dxdiag.exe does internally. It requires a moment to complete too, so it's not a fast solution either, but at least you don't need to create or parse a raw file.

Apparently, this functionality was previously wrapped in the managed DirectX assemblies in Microsoft.DirectX.Diagnostics, as they have a very similar interface to what the COM objects provide, but these assemblies are outdated and not working in .NET Core, so let's wrap those COM objects ourselves! For documentation of the methods, you can still refer to the documentation linked above.

First, you need the IDxDiagProvider interface and the DxDiagProvider coclass together with the DXDIAG_INIT_PARAMS passed to the provider:

[ComImport]
[Guid("A65B8071-3BFE-4213-9A5B-491DA4461CA7")]
public class DxDiagProvider { }

[Guid("9C6B4CB0-23F8-49CC-A3ED-45A55000A6D2")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDxDiagProvider
{
    void Initialize(ref DXDIAG_INIT_PARAMS pParams);
    void GetRootContainer(out IDxDiagContainer ppInstance);
}

[StructLayout(LayoutKind.Sequential)]
public struct DXDIAG_INIT_PARAMS
{
    public int dwSize;
    public uint dwDxDiagHeaderVersion;
    public bool bAllowWHQLChecks;
    public IntPtr pReserved;
};

You also need to wrap the IDxDiagContainer class:

[Guid("7D0F462F-4064-4862-BC7F-933E5058C10F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDxDiagContainer
{
    void EnumChildContainerNames(uint dwIndex, string pwszContainer, uint cchContainer);
    void EnumPropNames(uint dwIndex, string pwszPropName, uint cchPropName);
    void GetChildContainer(string pwszContainer, out IDxDiagContainer ppInstance);
    void GetNumberOfChildContainers(out uint pdwCount);
    void GetNumberOfProps(out uint pdwCount);
    void GetProp(string pwszPropName, out object pvarProp);
}

Now we get to use our wrappers and have to do the following to retrieve the version info:

  • Instantiate the provider by creating the coclass and casting it to the interface.
  • Initialize the provider with the initialization parameters.
  • Get the root container.
  • Get the DxDiag_SystemInfo child container.
  • Read the DirectX version properties.

Code which properly cleans up the COM resources can look like this:

IDxDiagProvider provider = null;
IDxDiagContainer rootContainer = null;
IDxDiagContainer systemInfoContainer = null;
try
{
    // Instantiate and initialize the provider.
    provider = (IDxDiagProvider)new DxDiagProvider();
    DXDIAG_INIT_PARAMS initParams = new DXDIAG_INIT_PARAMS
    {
        dwSize = Marshal.SizeOf<DXDIAG_INIT_PARAMS>(),
        dwDxDiagHeaderVersion = 111
    };
    provider.Initialize(ref initParams);

    // Get the Root\SystemInfo container.
    provider.GetRootContainer(out rootContainer);
    rootContainer.GetChildContainer("DxDiag_SystemInfo", out systemInfoContainer);

    // Read the DirectX version info.
    int versionMajor = GetProperty<int>(container, "dwDirectXVersionMajor");
    int versionMinor = GetProperty<int>(container, "dwDirectXVersionMinor");
    string versionLetter = GetProperty<string>(container, "szDirectXVersionLetter");
    bool isDebug = GetProperty<bool>(container, "bDebug");
}
finally
{
    if (provider != null)
        Marshal.ReleaseComObject(provider);
    if (rootContainer != null)
        Marshal.ReleaseComObject(rootContainer);
    if (systemInfoContainer != null)
        Marshal.ReleaseComObject(systemInfoContainer);
}

As you can see there's a small utility GetProperty method I created to retrieve a correctly typed property from the VARIANT values the COM interface returns:

private static T GetProperty<T>(IDxDiagContainer container, string propName)
{
    container.GetProp(propName, out object variant);
    return (T)Convert.ChangeType(variant, typeof(T));
}


来源:https://stackoverflow.com/questions/17130764/check-which-version-of-directx-is-installed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!