How to detect DX > v9.0c?

BlitzMax Forums/BlitzMax Programming/How to detect DX > v9.0c?

Grey Alien(Posted 2012) [#1]
Hi there, I have this old code and it only works up to DX 9.0c because that's the highest value stored in the registry key for DX. So how do you detect DX10/11? Any ideas? Thx

SuperStrict

?win32
Const HKEY_LOCAL_MACHINE% = -2147483646

Extern "win32"
	Function RegOpenKey%(hKeyParent%,SubKey$z,phkResult:Byte Ptr)="RegOpenKeyA@12"
	Function RegCloseKey%(hKey%)="RegCloseKey@4"
	Function RegQueryValueEx%(hKey%,ValueName$z,Reserved%,nType:Byte Ptr,ValueBytes:Byte Ptr,ValueSize:Byte Ptr)="RegQueryValueExA@24"
End Extern
?

Print ccGetDirectXVersion()

Function ccGetDirectXVersion$()
	Local strVersion:String = ""

	?win32
	Local hbank:TBank = CreateBank(4)
	RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\Microsoft\DirectX",BankBuf(hbank))
	Local hKey% = PeekInt(hbank,0)
	
	Local value_bank:TBank = CreateBank(100)
	Local value_bank_size:TBank = CreateBank(4)
	Local type_bank:TBank = CreateBank(4)
	
	PokeInt(type_bank,0,0)
	PokeInt(value_bank_size,0,100)
	   
	RegQueryValueEx(hKey,"Version",0,BankBuf(type_bank),BankBuf(value_bank),BankBuf(value_bank_size))
	
	Local dx_version:String = ""
	For Local char%=0 To PeekInt(value_bank_size,0)-1
		If PeekByte(value_bank,char)=0 Then Exit
		dx_version = dx_version + Chr(PeekByte(value_bank,char))
	Next
	
	RegCloseKey(hKey)
	
	Select dx_version
	    Case "4.02.0095"
	        strVersion = "1.0"
	    Case "4.03.00.1096"
	        strVersion = "2.0a"
	    Case "4.04.00.0068"
	        strVersion = "3.0"
	    Case "4.04.00.0069"
	        strVersion = "3.0"
	    Case "4.04.00.0070"
	        strVersion = "3.0a"
	    Case "4.05.00.0155"
	        strVersion = "5.0"
	    Case "4.05.01.1600"
	        strVersion = "5.0"
	    Case "4.05.01.1998"
	        strVersion = "5.2"
	    Case "4.06.02.0436"
	        strVersion = "6.1"
	    Case "4.06.03.0518"
	        strVersion = "6.1a"
	    Case "4.07.00.0700"
	        strVersion = "7.0"
	    Case "4.07.00.0716"
	        strVersion = "7.0a"
	    Case "4.07.01.3000"
	        strVersion = "7.1"
	    Case "4.08.00.0400"
	        strVersion = "8.0"
	    Case "4.08.01.0810"
	        strVersion = "8.1"
	    Case "4.08.01.0881"
	        strVersion = "8.1"
	    Case "4.08.01.0901"
	        strVersion = "8.1a"
	    Case "4.08.02.0134"
	        strVersion = "8.2"
	    Case "4.09.0000.0900"
	        strVersion = "9.0"
	    Case "4.09.00.0900"
	        strVersion = "9.0"
	    Case "4.09.0000.0901"
	        strVersion = "9.0a"
	    Case "4.09.00.0901"
	        strVersion = "9.0a"
	    Case "4.09.0000.0902"
	        strVersion = "9.0b"
	    Case "4.09.00.0902"
	        strVersion = "9.0b"
	    Case "4.09.00.0903"
	        strVersion = "9.0c"
	    Case "4.09.0000.0903"
	        strVersion = "9.0c"
	    Case "4.09.00.0904"
	        strVersion = "9.0c"
	    Case "4.09.0000.0904"
	        strVersion = "9.0c"
	End Select
	?
	
	Return strVersion

End Function



BlitzSupport(Posted 2012) [#2]
The only way you can properly do this as far as I am aware is to try and access features/interfaces unique to each version and test for their existence... a bit too low-level for me!

(The above code will return 9.0c even if 10+ is installed because you can have 9.x and 10+ installed at the same time -- normal on Vista upwards I believe.)

Simple hack way:



You'd use your posted code for versions up to 9.0c, then this for further (integer) versions. I don't believe there's an official way, so if you want sub-versions you'll probably have to implement the interface-detection stuff. Can't imagine there's much practical need for it, though, for all the difference it'll make in terms of what you can do with that information.

This technically just opens the DLLs if they're present, so in theory someone could have just copied them in without having DX installed, but I think it'd be pretty safe.


BlitzSupport(Posted 2012) [#3]
Interesting results for 7 to 12 using the above, actually, and much as I'd expect:

DirectX version 7 is NOT installed
DirectX version 8 library exists but contains no D3D8CreateDevice function
DirectX version 9 library exists but contains no D3D9CreateDevice function
DirectX version 10 is installed
DirectX version 11 is installed
DirectX version 12 is NOT installed


(Again, you'd use the Registry code for versions 8 and 9.)


Grey Alien(Posted 2012) [#4]
Wow nice one thanks James! That's a pretty good solution. Mind if I nab it for my public domain source file?


BlitzSupport(Posted 2012) [#5]
No probs! You'll have to revisit if/when a new DX comes out, of course, to see if it still holds up.


Grey Alien(Posted 2012) [#6]
Thanks, appreciated.


col(Posted 2012) [#7]
Hiya guys,


DirectX version 8 library exists but contains no D3D8CreateDevice function
DirectX version 9 library exists but contains no D3D9CreateDevice function



The function names changed slightly on the newer versions. And Dx7 has a completely different approach to initializing.

Direct3DCreate8
Direct3DCreate9
D3D10CreateDevice
D3D11CreateDevice

EDIT:- Forgot to update James method which is without a doubt the easiest way to detect the version. MS own functions are.. well.. could be better :-)


Last edited 2012


therevills(Posted 2012) [#8]
What about using a c++ call to directxsetupgetversion?

http://doc.51windows.net/Directx9_SDK/?url=/directx9_sdk/setup/reference/functions/directxsetupgetversion.htm


Grey Alien(Posted 2012) [#9]
@Dave Thanks for the clarification.

@James should we close the kernel32 lib as well? e.g.

If CloseLibrary then CloseLibrary lib


I tried that and it didn't crash but I'm not sure I should be doing it...

Last edited 2012


col(Posted 2012) [#10]
@therevills DirectXSetupGetVersion() only works up to version 9.c for some wacky reason hence "MS own functions are.. well.. could be better"

@Jake The system maintains a reference count for all LoadLibrary and CloseLibrary calls, so it's OK to leave it in. It's even ok to leave it out as the system will clean up when the app exits.

Last edited 2012


Grey Alien(Posted 2012) [#11]
@Dave: Thanks for the reassurance, though I wonder if it's better to free up the memory when done. Done know how much kernel32 will consume.


col(Posted 2012) [#12]
It doesn't consume much at all but I know what you mean.
If you're really worried about it then technically speaking, the Kernel32 library is loaded with your app. This means you don't really need to load it in again.

To use it in James example with the minimum of fuss - swap out the
Local CloseLibrary:Int (library:Int)
Local lib:Int = LoadLibraryA ("kernel32.dll")
CloseLibrary = GetProcAddress (lib, "FreeLibrary")


for

Extern"Win32"
	Function CloseLibrary(hLib) = "FreeLibrary@4"
EndExtern


to use the existing instance already linked in to your exe.

Last edited 2012


Grey Alien(Posted 2012) [#13]
Nice one Dave, I'll give that a whirl. You are certainly a very useful Windows expert to have around!


Grey Alien(Posted 2012) [#14]
Also it made my debug mode access violation go away, weird but yay!

http://www.blitzbasic.com/Community/posts.php?topic=98996


BlitzSupport(Posted 2012) [#15]
Yeah, I just put the library closure stuff in for completeness. It just frees the handle from LoadLibraryA so not too important since it'll close at the end anyway like Dave says. (Was just protecting against sticking this all in a function that might then in theory be called 100s of times, however unlikely!)

Also, good point on FreeLibrary!


SLotman(Posted 2012) [#16]
I actually still use the registry stuff - just got the keys from a system with DX10 and DX11 ^_^

Anyway, I now default my games to dx9, and just test if it's win95/98/2000 or XP with less then 24bpp desktop, then I switch to dx7 or opengl. No need at all to poke at dlls =D


Grey Alien(Posted 2012) [#17]
To be honest I'm not using the detection to make any decisions, just to display some debug info.