Managed DirectX / SharpDX / SlimDX working without installer?

3.9k views Asked by At

I'm trying to write a C# application that should:

  • run on .NET Framework (4.0 ideally)
  • run on DirectX 9 on as much computers as possible (everyone that have DirectX 9 installed)
  • be a single EXE file (without DLLs)
  • do not force the end user to install anything (especially to download)

I have tried Managed DirectX, SharpDX and I didn't succeed. (I don't care if they are obsolete, I don't need much from DirectX, only the basics, it's relatively simple app). For hiding the DLLs I'm embedding them into resources and loading them by AppDomain.AssemblyResolve event.

Here are my problems:

Managed DirectX. Generally works, on most BUT NOT ALL computers. There was a case that it wasn't working despite of that there were even 3D games installed (which install and run on DirectX, at least 9). The MS Managed DirectX was just NOT INSTALLED with the DirectX. Anyone knows why? Why some people have it and some don't? When I added the DLLs I needed into the folder with the app it was working fine, but when I've embedded them as resources, they couldn't load (even when I've extracted them to temp folder and tried to load from there). I've got an idea of how to resolve that, which may work, but my quesion is: will my Managed DirectX DLLs work on every CPU? (32/64 bit?). I had problems of this type before.

SharpDX. Doesn't work on most computers, even the modern ones. It requires a specific version of DirectX Runtime (June 2010) to be installed! If it's not, it's throwing exception about missing d3dx9_43.dll. Everyone have d3dx9.dll, but almost noone d3dx9_43.dll. Installing the specific version is their official solution for this problem... I don't know what were they thinking, but it's just not usable. Also there was a problem to load them from resources but I've managed to resolve that. When I've embedded the d3dx9_43.dll from my 32 bit system it was throwing a BadImageFormatException on 64 bit system, so I can't even put that file next to the app, not to mention embedding it or installing to SYSTEM32 directory where it should be (which would require Full Trust). There is another problem. Even if I would want to attach the DirectX June 2010 End-User Runtime, it's taking 95MB, which is MUCH too much (not to mention asking the user to download it...). Oh, and I also can't reset the device in SharpDX to go fullscreen (the same code worked just fine on Managed DirectX!) but I assume it CAN be fixed somehow...

SlimDX. Didn't even try this because on its official homepage it is said that it requires a "SlimDX Runtime" to be installed on end-user computer. As i said at the beginning, the app should JUST WORK and not force the user to install anything (except the DirectX itself, which is already installed on most, even old computers).

Any suggestions? Please don't give me the tumbleweed award again... :] I'm open to everything except going into unmanaged code and writing my own wrapper.

2

There are 2 answers

7
Dr. Andrew Burnett-Thompson On

I actually have a solution for this. Or rather, I am closing in on one.

If you use SharpDX.Direct3D9 or SharpDX.Direct3D10 it's likely you need D3DX9_43.dll and D3DX10_43.dll respectively.

You are right that these DLLs are located in the C:\Windows\System32 and C:\Windows\SysWow64 directories after installing the DirectX10 June 2010 Runtime.

However, your users don't want a 100MByte download (too right)...

EDIT: Update. I now have this working

  1. Include the libraries you need as dependencies as embedded resources in your Managed DLL.

    • Make sure you include the x86 and x64 versions of the library in separate folders.
    • e.g. D3DX9_43.dll from C:\Windows\System32 is the 64bit version on x64 machines, should be included as an embedded resource in \Resources\Dependencies\x64
    • D3DX9_43.dll from C:\Windows\SysWow64 is the 32bit version (go figure!) on x64 machines and should be included as an embedded resource in \Resources\Dependencies\x86
  2. Now create a DLL loader using this technique to selectively write out the correct (x86 or x64) DLLs to file, using the UAC save AppData\Local\YourApp\Dependencies\x64 or \x86 folders as targets

  3. Finally, call the Kernel32 LoadLibrary function via P/Invoke on the dependencies. IMPORTANT! Only ever load x86 unmanaged DLLs when the Environment.Is64BitProcess flag is false. Vice versa for x64 unmanaged DLLs

Finally, sip margarita and watch your SharpDX application in all its glory on a machine with no DirectX Runtime installed!

EDIT 2: The above breaks the licensing agreement for the DirectX Runtime

As Xoof points out in the comments, the above breaks the licensing agreement for the DirectX Runtime. Good he let us know really as I was about to package these DLLs into commercial software.

Instead, we're going to go down the route of pre-packaging a subset of the *cab files found under C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Redist\ with our installer. We will use this to create our own mini DirectX Runtime (about 4.7MBytes) with just the files we need.

enter image description here

Hopefully the above info is useful to anyone who wants to know how to dynamically load platform-specific unmanaged DLLs with a managed application, and how to pre-package a subset of DirectX DLLs with your application!

0
Chuck Walbourn On

Note that the DirectX SDK REDIST EULA doesn't allow you to redistribute the files any way other than to use DXSETUP or DXWSETUP. You can only redistribute the CABs and then invoke DXSETUP for any version of D3DX. You do not, however, need to include all 150+ CAB files. You can include only those you actually use, but you still admin rights to launch DXSETUP. See MSDN.

Be sure to read Not So DirectSetup.

BTW, with the Windows 8.x SDK, you are allowed to redistribute the D3DCompiler_46.DLL, D3DCompiler_47.DLL, D3DCSX11_46.DLL, and/or D3DCSX11_47.DLL by just copying the file around. This is called 'application local deployment'.