GETDXVER.CPP

/************************************************************************** 

GetDXVer.cpp

Demonstrates how applications can detect what version of DirectX
is installed.

**************************************************************************/
/**************************************************************************

(C) Copyright 1995-1997 Microsoft Corp. All rights reserved.

You have a royalty-free right to use, modify, reproduce and
distribute the Sample Files (and/or any modified version) in
any way you find useful, provided that you agree that
Microsoft has no warranty obligations or liability for any
Sample Application Files which are modified.

**************************************************************************/

#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <dinput.h>

/****************************************************************************
*
* GetDXVersion
*
* This function returns two arguments:
*dwDXVersion:
* 0 No DirectX installed
* 0x100 DirectX version 1 installed
* 0x200 DirectX 2 installed
* 0x300 DirectX 3 installed
* 0x500 At least DirectX 5 installed.
* 0x501 At least DirectX 5a installed.
*dwDXPlatform:
* 0 Unknown (This is a failure case. Should never happen)
* VER_PLATFORM_WIN32_WINDOWS Windows 9X platform
* VER_PLATFORM_WIN32_NT Windows NT platform
*
****************************************************************************/

typedef HRESULT (WINAPI *DIRECTDRAWCREATE)(GUID *, LPDIRECTDRAW *, IUnknown *);
typedef HRESULT (WINAPI *DIRECTINPUTCREATE)(HINSTANCE, DWORD, LPDIRECTINPUT *, IUnknown *);

void GetDXVersion (LPDWORD pdwDXVersion, LPDWORD pdwDXPlatform)
{
HRESULT hr;
HINSTANCE DDHinst = 0;
HINSTANCE DIHinst = 0;
LPDIRECTDRAW pDDraw = 0;
LPDIRECTDRAW2 pDDraw2 = 0;
DIRECTDRAWCREATE DirectDrawCreate = 0;
DIRECTINPUTCREATE DirectInputCreate = 0;
OSVERSIONINFO osVer;
LPDIRECTDRAWSURFACE pSurf = 0;
LPDIRECTDRAWSURFACE3 pSurf3 = 0;

/*
* First get the windows platform
*/
osVer.dwOSVersionInfoSize = sizeof(osVer);
if (!GetVersionEx(&osVer))
{
*pdwDXVersion = 0;
*pdwDXPlatform = 0;
return;
}

if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
*pdwDXPlatform = VER_PLATFORM_WIN32_NT;
/*
* NT is easy... NT 4.0 is DX2, 4.0 SP3 is DX3, 5.0 is DX5
* and no DX on earlier versions.
*/
if (osVer.dwMajorVersion < 4)
{
*pdwDXPlatform = 0;//No DX on NT3.51 or earlier
return;
}
if (osVer.dwMajorVersion == 4)
{
/*
* NT4 up to SP2 is DX2, and SP3 onwards is DX3, so we are at least DX2
*/
*pdwDXVersion = 0x200;

/*
* We're not supposed to be able to tell which SP we're on, so check for dinput
*/
DIHinst = LoadLibrary("DINPUT.DLL");
if (DIHinst == 0)
{
/*
* No DInput... must be DX2 on NT 4 pre-SP3
*/
OutputDebugString("Couldn't LoadLibrary DInput\r\n");
return;
}

DirectInputCreate = (DIRECTINPUTCREATE)
GetProcAddress(DIHinst, "DirectInputCreateA");
FreeLibrary(DIHinst);

if (DirectInputCreate == 0)
{
/*
* No DInput... must be pre-SP3 DX2
*/
OutputDebugString("Couldn't GetProcAddress DInputCreate\r\n");
return;
}

/*
* It must be NT4, DX2
*/
*pdwDXVersion = 0x300; //DX3 on NT4 SP3 or higher
return;
}
/*
* Else it's NT5 or higher, and it's DX5a or higher:
*/
*pdwDXVersion = 0x501; //DX5a on NT5
return;
}

/*
* Not NT... must be Win9x
*/
*pdwDXPlatform = VER_PLATFORM_WIN32_WINDOWS;

/*
* If we are on Memphis or higher, then we are at least DX5a
*/
if ( (osVer.dwBuildNumber & 0xffff) > 1353) //Check for higher than developer release
{
*pdwDXVersion = 0x501; //DX5a on Memphis or higher
return;
}

/*
* Now we know we are in Windows 9x (or maybe 3.1), so anything's possible.
* First see if DDRAW.DLL even exists.
*/
DDHinst = LoadLibrary("DDRAW.DLL");
if (DDHinst == 0)
{
*pdwDXVersion = 0;
*pdwDXPlatform = 0;
FreeLibrary(DDHinst);
return;
}

/*
* See if we can create the DirectDraw object.
*/
DirectDrawCreate = (DIRECTDRAWCREATE)
GetProcAddress(DDHinst, "DirectDrawCreate");
if (DirectDrawCreate == 0)
{
*pdwDXVersion = 0;
*pdwDXPlatform = 0;
FreeLibrary(DDHinst);
OutputDebugString("Couldn't LoadLibrary DDraw\r\n");
return;
}

hr = DirectDrawCreate(NULL, &pDDraw, NULL);
if (FAILED(hr))
{
*pdwDXVersion = 0;
*pdwDXPlatform = 0;
FreeLibrary(DDHinst);
OutputDebugString("Couldn't create DDraw\r\n");
return;
}

/*
* So DirectDraw exists. We are at least DX1.
*/
*pdwDXVersion = 0x100;

/*
* Let's see if IID_IDirectDraw2 exists.
*/
hr = pDDraw->QueryInterface(IID_IDirectDraw2, (LPVOID *)&pDDraw2);
if (FAILED(hr))
{
/*
* No IDirectDraw2 exists... must be DX1
*/
pDDraw->Release();
FreeLibrary(DDHinst);
OutputDebugString("Couldn't QI DDraw2\r\n");
return;
}
/*
* IDirectDraw2 exists. We must be at least DX2
*/
pDDraw2->Release();
*pdwDXVersion = 0x200;

/*
* See if we can create the DirectInput object.
*/
DIHinst = LoadLibrary("DINPUT.DLL");
if (DIHinst == 0)
{
/*
* No DInput... must be DX2
*/
OutputDebugString("Couldn't LoadLibrary DInput\r\n");
pDDraw->Release();
FreeLibrary(DDHinst);
return;
}

DirectInputCreate = (DIRECTINPUTCREATE)
GetProcAddress(DIHinst, "DirectInputCreateA");
FreeLibrary(DIHinst);

if (DirectInputCreate == 0)
{
/*
* No DInput... must be DX2
*/
FreeLibrary(DDHinst);
pDDraw->Release();
OutputDebugString("Couldn't GetProcAddress DInputCreate\r\n");
return;
}

/*
* DirectInputCreate exists. That's enough to tell us that we are at least DX3
*/
*pdwDXVersion = 0x300;

/*
* Checks for 3a vs 3b?
*/

/*
* We can tell if DX5 is present by checking for the existence of IDirectDrawSurface3.
* First we need a surface to QI off of.
*/
DDSURFACEDESC desc;

ZeroMemory(&desc, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

hr = pDDraw->SetCooperativeLevel(NULL,DDSCL_NORMAL);
if (FAILED(hr))
{
/*
* Failure. This means DDraw isn't properly installed.
*/
pDDraw->Release();
FreeLibrary(DDHinst);
*pdwDXVersion = 0;
OutputDebugString("Couldn't Set coop level\r\n");
return;
}

hr = pDDraw->CreateSurface(&desc, &pSurf, NULL);
if (FAILED(hr))
{
/*
* Failure. This means DDraw isn't properly installed.
*/
pDDraw->Release();
FreeLibrary(DDHinst);
*pdwDXVersion = 0;
OutputDebugString("Couldn't CreateSurface\r\n");
return;
}

/*
* Try for the IDirectDrawSurface3 interface. If it works, we're on DX5 at least
*/
if ( FAILED(pSurf->QueryInterface(IID_IDirectDrawSurface3,(LPVOID*)&pSurf3)) )
{
pDDraw->Release();
FreeLibrary(DDHinst);

return;
}

/*
* QI for IDirectDrawSurface3 succeeded. We must be at least DX5
*/
*pdwDXVersion = 0x500;

pSurf->Release();
pDDraw->Release();
FreeLibrary(DDHinst);

return;
}