DirectX Installation for Fixed Media

From NSIS Wiki

The following is for NSIS installations where the source is a media such as a DVD, CD-ROM, or otherwise can store the 100mb+ DirectX installation. As the installer will be on fixed media, we can save installation time and user's hard drive space by running directly from the source media, rather than coping install files.

For web-based installers, please use the DirectX Installation with Web Installer instructions.

Prerequisites

Obtaining the DirectX Runtime Install

Obtain the Latest DirectX End-User Runtimes from Microsoft. You can use any release, but it's best to get the latest runtime, even if your title doesn't explicitly require it.

When you get the file, you will need to extract the contents, rather than installing the runtimes. To do this, you will need to run the file in a command line as follows, defining the export location in the /T parameter:

directx_redist.exe /T:<path to export> /C

Placing the DirectX install

You will need include the full DirectX installation files on your final media and outside of the NSIS installer itself. This allows the DirectX setup to run and install without copying DirectX Setup files to the user system.

While the contents can be named and places anywhere in relative to the final installer executable, this document will assume the following layout:

  • ~/setup.exe (Your final NSIS installer file.)
  • ~/DirectX/
    • dxsetup.exe
    • dsetup.dll
    • dsetup32.dll
    • All the other DirectX setup files.

If you lay out files in this structure, you can define the location of the DirectX installer files as:

$EXEPATH/DirectX/

Installing DirectX

There are two ways to go about the install. The easy way or use DirectSetup to interface with the DirectX install program directly.

The Easy Way

If you simply want to run the installer with only a fail/success status, this is the way to go. This script will do the following:

  1. Launch the DirectX Installer on the source media.
  2. NSIS waits till the DirectX installer finishes.
  3. Close and continue with the install script.

First, you will need to define a variable at the very beginning of your script:

Var DirectXSetupError

To make things easier on yourself, create a new Section for DirectX. NSIS will run the section while installing. The placement of the section could go anywhere, but it's highly recommended that DirectX be the last install section after everything else is complete. This is incase DirectX fails, your software will be installed.

If you use component install UI, DirectX will show up as an entry. You can force on with "SectionIn RO", or leave out if you wish the user to have the option to run the DirectX install.

Section "DirectX Install" SEC_DIRECTX
 
 SectionIn RO
 
 DetailPrint "Running DirectX Setup..."
 ExecWait '"$EXEDIR\DirectX\DXSETUP.exe" /silent' $DirectXSetupError
 DetailPrint "Finished DirectX Setup"
 
SectionEnd

Note: Change the ExecWait line to point to the path of DXSETUP.exe. In this example, $EXEDIR is used to point to the directory the NSIS installer is located, then a subfolder of "DirectX".

The variable $DirectXSetupError is used to force NSIS to pause while the DirectX setup is running. You can use the error code to further script error handling, but a variable is required to be there in order for NSIS to wait.

I've also included DetailPrint lines to display the DirectX status in the install logs. These strings can be localized to your liking.

Using DirectSetup

DirectSetup is the direct interface to the DirectX setup application. For this you will still need to have all of the DirectX setup files on a fixed location in relation to the NSIS installer you create. This script will also require the use of the System plug-in, which is included in NSIS.

First, you'll need the following NSH. The best way is to save the code as "DirectSetup.nsh".

#
#		DirectSetup.nsh
#		
#		For installing DirectX using the System Plug-in.
#
#
 
# NSIS Macro Includes
!define DirectX_Version '!insertmacro DirectX_Version'
!define DirectX_Install '!insertmacro DirectX_Install'
 
# NSIS Includes
!include LogicLib.nsh
 
# Macro Variables
Var DX_SETUP_TYPE
Var DX_SETUP_OUTPATH
 
# DirectSetup Return Values
!define DSETUPERR_SUCCESS_RESTART 1
!define DSETUPERR_SUCCESS 0
!define DSETUPERR_BADWINDOWSVERSION -1
!define DSETUPERR_SOURCEFILENOTFOUND -2
!define DSETUPERR_BADSOURCESIZE -3
!define DSETUPERR_BADSOURCETIME -4
!define DSETUPERR_NOCOPY -5
!define DSETUPERR_OUTOFDISKSPACE -6
!define DSETUPERR_CANTFINDINF -7
!define DSETUPERR_CANTFINDDIR -8
!define DSETUPERR_INTERNAL -9
!define DSETUPERR_NTWITHNO3D -10
!define DSETUPERR_UNKNOWNOS -11
!define DSETUPERR_USERHITCANCEL -12
!define DSETUPERR_NOTPREINSTALLEDONNT -13
!define DSETUPERR_NOTADMIN -15
!define DSETUPERR_UNSUPPORTEDPROCESSOR -16
!define DSETUPERR_CABDOWNLOADFAIL -19
!define DSETUPERR_DXCOMPONENTFILEINUSE -20
!define DSETUPERR_UNTRUSTEDCABINETFILE -21
 
# DirectSetup Flags
!define DSETUP_DDRAWDRV			0x00000008
!define DSETUP_DSOUNDDRV			0x00000010
!define DSETUP_DXCORE				0x00010000
!define DSETUP_DIRECTX				0x00010018
!define DSETUP_MANAGEDDX			0x00004000
!define DSETUP_TESTINSTALL			0x00020000
 
# DirectXSetupCallbackFunction Reason Codes
!define DSETUP_CB_MSG_NOMESSAGE                     0
!define DSETUP_CB_MSG_INTERNAL_ERROR                10
!define DSETUP_CB_MSG_BEGIN_INSTALL                 13
!define DSETUP_CB_MSG_BEGIN_INSTALL_RUNTIME         14
!define DSETUP_CB_MSG_PROGRESS                      18
!define DSETUP_CB_MSG_WARNING_DISABLED_COMPONENT    19
 
/*
	DirectX_Version
 
		Retrieves the version number of the DirectX core runtime components that are currently installed.
 
		INPUT:
			DirectX_SRC = Location of the extracted DirectX runtime components.
 
		OUTPUT:
			$2 = Returns the version number as an int which was converted from a hex value.
			$3 = Returns the revision number as an int which was converted from a hex value.
 
*/
!macro DirectX_Version DirectX_SRC
 
	StrCpy $DX_SETUP_OUTPATH $OUTDIR
 
	SetOutPath "${DirectX_SRC}"
	System::Alloc 4
	Pop $0
	System::Alloc 4
	Pop $1
	System::Call "dsetup::DirectXSetupGetVersion(i, i) i (r0, r1) .r2"
 
	System::Call "*$0(&i4 .r2)"
	System::Call "*$1(&i4 .r3)"
 
	SetOutPath $DX_SETUP_OUTPATH
 
!macroend
 
/*
	DirectX_Install
 
		Retrieves the version number of the DirectX core runtime components that are currently installed.
 
		INPUT:
			DirectX_SRC = Location of the extracted DirectX runtime components.
 
		OUTPUT:
			$9 = The return vaule recieved by the DirectX Setup program.
 
		Todo:
			Incorperate DirectXSetupCallbackFunction() to allow progress status when
				DirectSetup is running.
 
*/
!macro DirectX_Install DirectX_SRC
 
	StrCpy $DX_SETUP_TYPE ${DSETUP_DIRECTX}
 
	# Uncomment this line when testing. It test a DirectX install, but won't actually do the install.
		;StrCpy $DX_SETUP_TYPE ${DSETUP_TESTINSTALL}
 
	# Save the current $OUTDIR.
	StrCpy $DX_SETUP_OUTPATH $OUTDIR
	SetOutPath "${DirectX_SRC}"
 
	# The Actual DirectX Setup call
	DetailPrint "Updating DirectX. Please wait."
	System::Call 'DSetup::DirectXSetupA(i, t, i) i \
    ($HWNDPARENT, "${DirectX_SRC}", $DX_SETUP_TYPE) .r9'
 
	# Reset $OUTDIR
		SetOutPath $DX_SETUP_OUTPATH
 
	# When DirectX Installs in some way:
 
		${If} $9 == ${DSETUPERR_SUCCESS}
			DetailPrint "DirectX Setup Success! No restart needed!"
			Goto DX_INSTALL_SUCCESS
		${ElseIf} $9 == ${DSETUPERR_SUCCESS_RESTART}
			SetRebootFlag true
			DetailPrint "DirectX Setup Success! A restart will be required."
			Goto DX_INSTALL_SUCCESS
 
	# When DirectX Fails in some way:
 
		# User's system is incapable
		${ElseIf} $9 == ${DSETUPERR_BADWINDOWSVERSION}
			DetailPrint "DirectX Setup Failed: Microsoft DirectX does not support the version of Microsoft Windows on the computer."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_OUTOFDISKSPACE}
			DetailPrint "DirectX Setup Failed: The setup program ran out of disk space during installation."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_UNKNOWNOS}
			DetailPrint "DirectX Setup Failed: The operating system is unknown."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_NOTADMIN}
			DetailPrint "DirectX Setup Failed: The current user does not have administrative privileges."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_UNSUPPORTEDPROCESSOR}
			DetailPrint "DirectX Setup Failed: The processor type is unsupported. DirectX supports only Intel Pentium, AMD K6, and compatible processors with equivalent or higher performance."
			Goto DX_INSTALL_FAIL
 
		# DirectX Files broken
		${ElseIf} $9 == ${DSETUPERR_SOURCEFILENOTFOUND}
			DetailPrint "DirectX Setup Failed: One of the required source files could not be found."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_NOCOPY}
			DetailPrint "DirectX Setup Failed: A file's version could not be verified or was incorrect."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_CANTFINDINF}
			DetailPrint "DirectX Setup Failed: A required information (.inf) file could not be found."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_CANTFINDDIR}
			DetailPrint "DirectX Setup Failed: The setup program could not find the working directory."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_CABDOWNLOADFAIL}
			DetailPrint "DirectX Setup Failed: The cabinet (.cab) file failed to load."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_DXCOMPONENTFILEINUSE}
			DetailPrint "DirectX Setup Failed: The cabinet (.cab) file was in use."
			Goto DX_INSTALL_FAIL
		${ElseIf} $9 == ${DSETUPERR_UNTRUSTEDCABINETFILE}
			DetailPrint "DirectX Setup Failed: The cabinet (.cab) file is not signed."
			Goto DX_INSTALL_FAIL
 
		# Unknown or other errors
		${Else} # Also doubles for ${DSETUPERR_INTERNAL}
			DetailPrint "DirectX Setup Failed: An internal error occurred."
			Goto DX_INSTALL_FAIL
		${EndIf}
 
	DX_INSTALL_FAIL:
		# Instructions when failed.
 
	DX_INSTALL_SUCCESS:
		# Instructions when passed.
 
!macroend

Then you will need to put in the following include line in your main NSIS script:

!include "DirectSetup.nsh"

From here, you will need to invoke the macro during the install process.

DirectX_Version

While not required to use, you can use this code to return the user's currently installed DirectX version. Keep in mind that since DirectX9, Microsoft hasn't changed the reporting of DirectX versions.

The following will output the main version number to $2 and the revision number to $3 as an integer converted from a Hex value. You will need to replace ${DirectX_SRC} with the location of the extracted DirectX Setup files.

${DirectX_Version} "${DirectX_SRC}"
MessageBox MB_OK "DirectX$\nVersion: $2$\nRevision: $3"

DirectX_Install

This function will run the DirectX install. The command will wait here until the install process is complete, returning errors and writing DetailPrint statements. You will need to replace ${DirectX_SRC} with the location of the extracted DirectX Setup files.

${DirectX_Install} "${DirectX_SRC}"

When completed, you will get the return value of the Setup in $9. Refer to the NSI file to what the return codes are and what they mean.

Note: There is a return code for DirectSetup which requires the computer to reboot. The macro will set the SetRebootFlag to true in this case.

To Do

There's a way to have the DirectSetup run callbacks which update the current status of the DirectX install. However, I can't seem to get my head around running callbacks with the System Plug-in. Any assistance in this is greatly appreciated!

See Also

Personal tools
donate