Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

RegRead associated program for a file extension


  • Please log in to reply
17 replies to this topic
mp3
  • Guests
  • Last active:
  • Joined: --
I need to get full path of program that is associated with .mp3 files.
Please help. I don't understand registry structure...

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
This code retrieves the command line executed when you double-click an MP3 file:

RegRead, sDefaultApp, HKCR, .mp3
RegRead, sDefaultAct, HKCR, %sDefaultApp%\shell
RegRead, sDefaultCommand, HKCR, %sDefaultApp%\shell\%sDefaultAct%\command

MsgBox %sDefaultCommand%


mp3
  • Guests
  • Last active:
  • Joined: --
Thanks.
I played with your code and tried other extensions like .bmp or .jpg but MsgBox is blank.

Has anybody written function where user enters extension, and function returns full path of program associated whit that file type?
Something like
AssociatedProgram(extension)
{
	; ....
	Return FullPath
}


TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
Here's a more reliable way:

MsgBox % AssocQueryApp("mp3")
MsgBox % AssocQueryApp("jpg")
MsgBox % AssocQueryApp("avi")

AssocQueryApp(sExt) { 
    sExt =.%sExt%                                              ;ASSOCSTR_EXECUTABLE
    DllCall("shlwapi.dll\AssocQueryStringA", "uint", 0, "uint", 2, "uint", &sExt, "uint", 0, "uint", 0, "uint*", iLength)
    VarSetCapacity(sApp, iLength, 0)
    DllCall("shlwapi.dll\AssocQueryStringA", "uint", 0, "uint", 2, "uint", &sExt, "uint", 0, "str", sApp, "uint*", iLength)
    Return sApp
}


jaco0646
  • Moderators
  • 3165 posts
  • Last active: Apr 01 2014 01:46 AM
  • Joined: 07 Oct 2006
I believe the RegRead method will work by adding one simple check: if an action is not set, it defaults to open.
MsgBox % AssocQueryApp("mp3")
MsgBox % AssocQueryApp("jpg")
MsgBox % AssocQueryApp("avi")

AssocQueryApp(ext) {
 RegRead, type, HKCR, .%ext%
 RegRead, act , HKCR, %type%\shell
 If ErrorLevel
  act = open
 RegRead, cmd , HKCR, %type%\shell\%act%\command
 Return, cmd
}
...or in a GUI
Gui, Add, Edit, vExt gLabel
Gui, Add, Edit, vCmd w500

Gui, Show
return
GuiClose:
 ExitApp

Label:
 Gui, Submit, NoHide

 RegRead, type, HKCR, .%Ext%
 RegRead, act , HKCR, %type%\shell
 If ErrorLevel
  act = open
 RegRead, cmd , HKCR, %type%\shell\%act%\command

 GuiControl,,Cmd, %cmd%
return


TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I believe the RegRead method will work by adding one simple check: if an action is not set, it defaults to open.

That's what I thought as well, but apparently it is not foolproof. The registry settings pulled that way are those registered by applications. A user may choose to override this (i.e. if he goes to Open With > Always open with this program), and it won't be updated in the registry.

Edit: Case in point, your example says that WMP opens my AVI files, which is not true (it's MPC-HC). AssocQueryString returns the right one.

jaco0646
  • Moderators
  • 3165 posts
  • Last active: Apr 01 2014 01:46 AM
  • Joined: 07 Oct 2006
You're right. HKCR holds the local, or default, settings. The current user's preferences in HKCU override these. I switched my mp3 files to MPC-HC as you suggested and was able to retrieve the correct command with yet another check.
Gui, Add, Edit, vExt gLabel

Gui, Add, Edit, vCmd w500



Gui, Show

return

GuiClose:

 ExitApp



Label:

 Gui, Submit, NoHide



 RegRead, type, HKCU, Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.%Ext%, Application



 If !ErrorLevel { ;Current user has overridden default setting

  RegRead, act, HKCU, Software\Classes\Applications\%type%\shell

  If ErrorLevel

   act = open

  RegRead, cmd, HKCU, Software\Classes\Applications\%type%\shell\%act%\command

 }

 Else {           ;Default setting

  RegRead, type, HKCR, .%Ext%

  RegRead, act , HKCR, %type%\shell

  If ErrorLevel

   act = open

  RegRead, cmd , HKCR, %type%\shell\%act%\command

 }

 GuiControl,,Cmd, %cmd%

return
Since all the file association data is stored in the registry, the DLLCall() can't be doing anything but looking there; however, with data in multiple keys and an order of precedence to contend with, the RegRead method becomes less appealing. I noticed even this additional check cannot find the associated command for icons (.ico). :?

mp3
  • Guests
  • Last active:
  • Joined: --
TheGood, this does not work for me - WinXP SP3
MsgBox % AssocQueryApp("mp3")
MsgBox % AssocQueryApp("jpg")
MsgBox % AssocQueryApp("avi")

AssocQueryApp(sExt) {
    sExt =.%sExt%                                              ;ASSOCSTR_EXECUTABLE
    DllCall("shlwapi.dll\AssocQueryStringA", "uint", 0, "uint", 2, "uint", &sExt, "uint", 0, "uint", 0, "uint*", iLength)
    VarSetCapacity(sApp, iLength, 0)
    DllCall("shlwapi.dll\AssocQueryStringA", "uint", 0, "uint", 2, "uint", &sExt, "uint", 0, "str", sApp, "uint*", iLength)
    Return sApp
}

jaco0646 code from your last post works perfectly :) I made a function from it. Looks fine to me, but check out is everything OK.
Gui, Add, Edit, vExt gLabel
Gui, Add, Edit, vCmd w500

Gui, Show
return
GuiClose:
ExitApp

Label:
Gui, Submit, NoHide
AssocApp := AssocQueryApp(Ext)
GuiControl,,Cmd, %AssocApp%
return

AssocQueryApp(Ext)
{
	RegRead, type, HKCU, Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.%Ext%, Application
	If !ErrorLevel { ;Current user has overridden default setting
		RegRead, act, HKCU, Software\Classes\Applications\%type%\shell
		If ErrorLevel
			act = open
		RegRead, cmd, HKCU, Software\Classes\Applications\%type%\shell\%act%\command
		}
	Else {           ;Default setting
		RegRead, type, HKCR, .%Ext%
		RegRead, act , HKCR, %type%\shell
		If ErrorLevel
			act = open
	RegRead, cmd , HKCR, %type%\shell\%act%\command
	}
	return cmd
}

Thanks very much both of you.

SOLVED

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

TheGood, this does not work for me - WinXP SP3

I made some research, and apparently the ANSI version of AssocQueryString is known to be broken in Windows XP only. The Unicode version however works for all Windows versions (W2K+):

MsgBox % AssocQueryApp("mp3")
MsgBox % AssocQueryApp("jpg")
MsgBox % AssocQueryApp("avi")

AssocQueryApp(sExt) {            
    sExt := "." sExt, ANSItoWide(&sExt, sExtW)                      ;ASSOCSTR_EXECUTABLE
    DllCall("shlwapi.dll\AssocQueryStringW", "uint", 0, "uint", 2, "uint", &sExtW, "uint", 0, "uint", 0, "uint*", iLength)
    VarSetCapacity(sAppW, iLength * 2, 0)
    DllCall("shlwapi.dll\AssocQueryStringW", "uint", 0, "uint", 2, "uint", &sExtW, "uint", 0, "uint", &sAppW, "uint*", iLength)
    WidetoANSI(&sAppW, sApp)
    Return sApp
}

ANSItoWide(ptrANSI, ByRef sWide) {
    n := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", ptrANSI, "int", -1, "uint", 0, "int", 0)
    VarSetCapacity(sWide, n * 2)
    DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", ptrANSI, "int", -1, "uint", &sWide, "int", n * 2)
}

WidetoANSI(ptrWide, ByRef sANSI) {
    n := DllCall("WideCharToMultiByte", "int", 0, "int", 0, "uint", ptrWide, "int", -1, "int", 0, "int", 0, "int", 0, "int", 0)
    VarSetCapacity(sANSI, n)
    DllCall("WideCharToMultiByte", "int", 0, "int", 0, "uint", ptrWide, "int", -1, "str", sANSI, "int", n, "int", 0, "int", 0)
}

If you'd prefer it all in one big function (unicode conversions inline):

MsgBox % AssocQueryApp("mp3")
MsgBox % AssocQueryApp("jpg")
MsgBox % AssocQueryApp("avi")

AssocQueryApp(sExt) {           
    sExt =.%sExt%
    n := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sExt, "int", -1, "uint", 0, "int", 0)
    VarSetCapacity(sExtW, n * 2)
    DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sExt, "int", -1, "uint", &sExtW, "int", n * 2)
    DllCall("shlwapi.dll\AssocQueryStringW", "uint", 0, "uint", 2, "uint", &sExtW, "uint", 0, "uint", 0, "uint*", iLength)
    VarSetCapacity(sAppW, iLength * 2, 0)                      ;ASSOCSTR_EXECUTABLE
    DllCall("shlwapi.dll\AssocQueryStringW", "uint", 0, "uint", 2, "uint", &sExtW, "uint", 0, "uint", &sAppW, "uint*", iLength)
    n := DllCall("WideCharToMultiByte", "int", 0, "int", 0, "uint", &sAppW, "int", -1, "int", 0, "int", 0, "int", 0, "int", 0)
    VarSetCapacity(sApp, n)
    DllCall("WideCharToMultiByte", "int", 0, "int", 0, "uint", &sAppW, "int", -1, "str", sApp, "int", n, "int", 0, "int", 0)
    Return sApp
}


emmanuel d
  • Members
  • 519 posts
  • Last active: Jul 15 2017 12:04 PM
  • Joined: 29 Jan 2009

You're right. HKCR holds the local, or default, settings. The current user's preferences in HKCU override these.

this is a lie, HKCR is a merge of HKLM and HKCU, first HKLM is read and then overriden by HKCU, so HKCR ALWAYS contains the true value.

you might want to check the folowing keys that contain keys and values that override your filetypes
HKCU,Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\
HKLM,Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\

you also need to check: PerceivedType like (example for text based files)
HKCR,.hta,PerceivedType,Text
and then look at:
HKCR,Software\Classes\SystemFileAssociations\text\shell\open\command
this might override your open command

Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license

http://www.ahkscript.org/ the new forum


TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
...or you could just use an API call that takes care of all that for you. :)

jaco0646
  • Moderators
  • 3165 posts
  • Last active: Apr 01 2014 01:46 AM
  • Joined: 07 Oct 2006

this is a lie

That's a bold accusation, especially without linking to any supporting documentation.

HKLM is read and then overriden by HKCU

That's what I said.

HKCR ALWAYS contains the true value.

That may be, if HKCR stores the HKLM values in one key and the overriding HKCU values in another then we are both right. As TheGood first pointed out and I confirmed, HKCR does hold the LM values. If it also holds the CU values, then certainly that root could be checked rather than the other. It doesn't make my code any less effective, nor my statements any less true.

mp3
  • Guests
  • Last active:
  • Joined: --
TheGood, I tried your latest code. Works perfectly on Windows XP. Thx. :)

emmanuel d
  • Members
  • 519 posts
  • Last active: Jul 15 2017 12:04 PM
  • Joined: 29 Jan 2009

then we are both right.

That might be, at this point.

HKCR does hold the LM values. If it also holds the CU values

that is not true entirely, if only one of them exist, yes else not, simply it contains the merged values.

then certainly that root could be checked rather than the other.

this is the truth and nothing but the truth. i totaly agree here.

don't take offence of anything i say, im not native inglish so... sorry if i did

one hint to all, dont write to HKCR or HKLM for filetype, write to HKCU

Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license

http://www.ahkscript.org/ the new forum


Mystiq
  • Members
  • 83 posts
  • Last active: Nov 06 2011 07:07 PM
  • Joined: 08 Jan 2007
I'm using TheGood's code and noticed that for unknown file extensions it returns path to "shell32.dll" in Windows directory. Is this normal/expected?

I have Windows 7 in case it matters.

Thanks!