XNA2.0 Dependency checking

After a lot of trial and error using Process Monitor and Virtual PC, I have finally sussed out exactly what XNA2.0 games on Windows need to run. The requirements are slightly different to XNA 1 games.

Direct X runtimes

There are four files that need to be installed in the system32 folder for XNA to initialise properly. They are:

  • xinput1_3.dll
  • x3daudio1_3.dll
  • d3dx9_31.dll, and
  • xactengine2_9.dll

The first three can be placed alongside the application exe and then load fine, but xactengine2_9.dll does not load this way for some reason, and has to be present in the system directory. Distributing these files alongside the application breaks the DirectX EULA, so they have to be installed using dxsetup.exe.

To check the presence in your XNA game, just put this code in Program.cs before game.Run() is called:

<pre class="code"><span style="color: rgb(0,0,255)">bool HasAllPrereqs = <span style="color: rgb(0,0,255)">true;
<pre class="code"><span style="color: rgb(0,128,0)">// check all the required files, if any missing, return false
<span style="color: rgb(0,0,255)">if (!System.IO.<span style="color: rgb(43,145,175)">File.Exists(System.<span style="color: rgb(43,145,175)">Environment.SystemDirectory 
    + <span style="color: rgb(163,21,21)">"\\xactengine2_9.dll")) HasAllPrereqs = <span style="color: rgb(0,0,255)">false;
<span style="color: rgb(0,0,255)">if (!System.IO.<span style="color: rgb(43,145,175)">File.Exists(System.<span style="color: rgb(43,145,175)">Environment.SystemDirectory 
    + <span style="color: rgb(163,21,21)">"\\d3dx9_31.dll")) HasAllPrereqs = <span style="color: rgb(0,0,255)">false;
<span style="color: rgb(0,0,255)">if (!System.IO.<span style="color: rgb(43,145,175)">File.Exists(System.<span style="color: rgb(43,145,175)">Environment.SystemDirectory 
    + <span style="color: rgb(163,21,21)">"\\x3daudio1_2.dll")) HasAllPrereqs = <span style="color: rgb(0,0,255)">false;
<span style="color: rgb(0,0,255)">if (!System.IO.<span style="color: rgb(43,145,175)">File.Exists(System.<span style="color: rgb(43,145,175)">Environment.SystemDirectory 
    + <span style="color: rgb(163,21,21)">"\\xinput1_3.dll")) HasAllPrereqs = <span style="color: rgb(0,0,255)">false;

If HasAllPrereqs is false after those lines, exit the application before it crashes horribly when XNA tries to initialise.

Visual C++ 2005 SP1 runtimes

Even a fresh Vista install doesn’t have these. They are provided when updating Visual Studio 2005 to SP1, or installing SP1 of the .Net Framework 2.0. However, Vista comes with SP0 of .Net 2.0, meaning 99% of machines you come across will be lacking what XNA 2.0 needs. There is a 2.5MB standalone installer on the MS download site here which installs what you need even on .Net 2.0 SP0 machines. .Net 3.5 installs Net 2.0 SP1.

So if any of the following are installed, we safely have the right Visual C++ 2005 runtimes:

  • .NET Framework 2.0 SP1
  • .NET Framework 3.5
  • Visual C++ 2005 SP1 Redistributable

By looking up the product codes in the registry, we can also check at runtime if we have the runtimes (again, before game.Run()):

<pre class="code">[<span style="color: rgb(43,145,175)">DllImport(<span style="color: rgb(163,21,21)">"msi.dll")]
<span style="color: rgb(0,0,255)">public <span style="color: rgb(0,0,255)">static <span style="color: rgb(0,0,255)">extern <span style="color: rgb(43,145,175)">Int32 MsiQueryProductState(<span style="color: rgb(0,0,255)">string szProduct);

…goes before the main application entry point, and

<pre class="code"><span style="color: rgb(0,0,255)">bool vccOK = <span style="color: rgb(0,0,255)">false;
<span style="color: rgb(0,128,0)">// check for VC++ 2005 SP1 redist (very rare in the wild)
<span style="color: rgb(0,0,255)">if (MsiQueryProductState(
<span style="color: rgb(163,21,21)">"{7299052b-02a4-4627-81f2-1818da5d550d}") == 5) vccOK = <span style="color: rgb(0,0,255)">true;
<span style="color: rgb(0,128,0)">// check for .NET Framework 2.0 SP1
<span style="color: rgb(0,0,255)">if (MsiQueryProductState(
<span style="color: rgb(163,21,21)">"{2FC099BD-AC9B-33EB-809C-D332E1B27C40}") == 5) vccOK = <span style="color: rgb(0,0,255)">true;
<span style="color: rgb(0,128,0)">// check for .NET Framework 3.5 (includes 2.0 SP1)
<span style="color: rgb(0,0,255)">if (MsiQueryProductState(
<span style="color: rgb(163,21,21)">"{B508B3F1-A24A-32C0-B310-85786919EF28}") == 5) vccOK = <span style="color: rgb(0,0,255)">true;

If vccOK is still false, exit the application before you call game.Run().