Friday, September 19, 2008

Get default application in Windows XP or Vista with VB.NET

When you double click a file, Windows Explorer opens it with associated default application. Windows Explorer determines current default application with file's extension and with information that is stored in the Windows registry. Obtaining the default application with VB.NET is not a difficult task. Default application can be found in both Windows XP and Windows Vista with the same VB.NET code.

Windows stores known file extensions in HKEY_CLASSES_ROOT registry hive. So, the first thing is to check if file extension exists in the registry. If the file extension exists, it has a so called ProgID associated with it. For example, file extension ".txt" has a ProgID "txtfile". Next step is to locate this ProgID registry key and check if it has a sub key "\shell\open\command". This sub key contains finally the path and the name of the default application. In the case of "txtfile" registry key, the default application could be "%SystemRoot%\system32\NOTEPAD.EXE %1".

The VB.NET function below returns the name of the default application, if it exists. Additionally it returns a ready-to-execute string which can be used with VB.NET's Shell command. First parameter in the function is a parameter string for default application. Second parameter is the actual file extension we are searching for.

''' <summary>
''' Return registered application by file's extension
''' </summary>
''' <param name="ParamFileName">Parameter for ShellAppName</param>
''' <param name="FileExtension">File extension</param>
''' <param name="AppName">Returns application name if any</param>
''' <param name="ShellAppName">Returns a string with application name and file name as its parameter</param>
''' <returns>True if the default application for this file type was found</returns>
''' <remarks>This function is Windows XP and Vista compatible</remarks>
Public Function GetRegisteredApplication(ByVal ParamFileName As String, ByVal FileExtension As String, _
 ByRef AppName As String, ByRef ShellAppName As String) As Boolean
 '
 ' Return registered application by file's extension
 '
 Dim StrExt As String
 Dim StrProgID As String
 Dim StrExe As String
 Dim oHKCR As RegistryKey ' HKEY_CLASSES_ROOT
 Dim oProgID As RegistryKey
 Dim oOpenCmd As RegistryKey
 Dim TempPos As Integer

 Try
   ' Add starting dot to extension
   StrExt = "." & FileExtension
   ' Get Programmatic Identifier for this extension
   Try
     oHKCR = Registry.ClassesRoot
     oProgID = oHKCR.OpenSubKey(StrExt)
     StrProgID = oProgID.GetValue(Nothing).ToString
     oProgID.Close()
   Catch
     ' No ProgID, return false
     Return False
   End Try
   ' Get associated application
   Try
     oOpenCmd = oHKCR.OpenSubKey(StrProgID & "\shell\open\command")
     StrExe = oOpenCmd.GetValue(Nothing).ToString
     oOpenCmd.Close()
   Catch
     ' Missing default application
     Return False
   End Try
   TempPos = StrExe.IndexOf(" %1")
   If TempPos > 0 Then
     ' Replace %1 placeholder with ParamFileName
     StrExe = StrExe.Substring(0, TempPos)
     AppName = StrExe
     StrExe = StrExe & " " & Convert.ToChar(34) & ParamFileName & Convert.ToChar(34)
     ShellAppName = StrExe
   Else
     ' No %1 placeholder found, append ParamFileName
     AppName = StrExe
     ShellAppName = StrExe & " " & Convert.ToChar(34) & ParamFileName & Convert.ToChar(34)
   End If
   Return True
 Catch ex As Exception
   Return False
 End Try

End Function

The function returns value True if the default application was found. If the function returns False, there was some error or some issue with registry permissions. In the latter case see System.Security.AccessControl namespace. That namespace provides methods to handle permission issues and how to set registry permissions.

To test this function, here's a code snippet for testing purpose. First create a new text file to C-drives root and name it "test.txt". When you run this snippet, it opens "test.txt" file with Notepad and displays message box:

Default application for text files

Default application for text files

This is, if you have Notepad as your default text editor.

Dim ApplicationName As String
Dim ShellApplicationName As String
Dim FileExtension As String
Dim ParamFileName As String

ApplicationName = ""
ShellApplicationName = ""
FileExtension = "txt"
ParamFileName = "C:\test.txt"
If GetRegisteredApplication(ParamFileName, FileExtension, ApplicationName, ShellApplicationName) Then
 Shell(ShellApplicationName)
 MessageBox.Show("Default application for the files of type '" & FileExtension & "'" & _
   " is '" & ApplicationName & "'", _
   "Default Application", _
   MessageBoxButtons.OK, _
   MessageBoxIcon.Exclamation)
Else
 MessageBox.Show("No default application found for the files of type '" & FileExtension & "'", _
   "Default Application", _
  MessageBoxButtons.OK, _
  MessageBoxIcon.Exclamation)
End If

Final words of warning. Always be careful when handling registry with your application. I have tested and used this code, and it does only read from the registry. But I will not give any kind of warranty if your registry gets messed up. So backup your registry first or otherwise make sure that you can restore your system if something goes wrong. You use this code totally at your own risk!

6 comments:

Amrish Shalikram Jaiswal said...

Thanks a lot! Your idea has really helped me. But, i am facing one problem. This strategy does not work in the scenario where user changed the default application using "folder option" and now i want to open it in tha application.

Can you help me please!!

Thanking you,
Amrish

Teme64 said...

File type associations made with Folder Options are stored in registry key
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\extension

If there exists sub key "Application", Explorer uses this value to open file.

Here's the code you can use in that case

''' summary
''' Return with Explorer registered application by file's extension
''' /summary
''' param name="ParamFileName" Parameter for ShellAppName /param
''' param name="FileExtension">File extension /param
''' param name="AppName" Returns application name if any /param
''' param name="ShellAppName">Returns a string with application name and file name as its parameter /param
''' returns True if the default application for this file type was found /returns
''' remarks This function is tested with Windows XP only /remarks
Public Function GetExplorerRegisteredApplication(ByVal ParamFileName As String, ByVal FileExtension As String, _
ByRef AppName As String, ByRef ShellAppName As String) As Boolean
'
' Return with Explorer registered application by file's extension
'
Dim StrExt As String
Dim StrExe As String
Dim oHKCU As RegistryKey ' HKEY_CURRENT_USER
Dim oApplication As RegistryKey
Dim TempPos As Integer

Try
' Add starting dot to extension
StrExt = "." & FileExtension
' Check if Application key exists
Try
oHKCU = Registry.CurrentUser
' Append reg key
StrExt = "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & StrExt
oApplication = oHKCU.OpenSubKey(StrExt)
StrExe = oApplication.GetValue("Application").ToString
oApplication.Close()
Catch
' No application, return false
Return False
End Try
TempPos = StrExe.IndexOf(" %1")
If TempPos > 0 Then
' Replace %1 placeholder with ParamFileName
StrExe = StrExe.Substring(0, TempPos)
AppName = StrExe
StrExe = StrExe & " " & Convert.ToChar(34) & ParamFileName & Convert.ToChar(34)
ShellAppName = StrExe
Else
' No %1 placeholder found, append ParamFileName
AppName = StrExe
ShellAppName = StrExe & " " & Convert.ToChar(34) & ParamFileName & Convert.ToChar(34)
End If
Return True
Catch ex As Exception
Return False
End Try

End Function

If the function above returns False, user hasn't changed file associations with Folder Options, and you can use the original GetRegisteredApplication function.

Anonymous said...

You can use the FindExecutable method as described in this post: http://it.toolbox.com/blogs/paytonbyrd/how-to-use-findexecutable-from-c-3324 or AssocQueryString (http://www.pinvoke.net/default.aspx/shlwapi/AssocQueryString.html)

Peter

Teme64 said...

Original post gets information from the registry. FindExecutable uses WinAPI and pInvoke. Both approaches does the job but both require a certain precautions.

Roy said...

Convert to C-Sharp for those who want it.

string AppName;
string ShellAppName;

public bool GetRegisteredApplication(string ParamFileName, string FileExtension)
{
AppName = null;
ShellAppName = null;

//Return registered application by file's extension

string StrProgID;
string StrExe;
RegistryKey oHKCR; //HKEY_CLASSES_ROOT
RegistryKey oProgID;
RegistryKey oOpenCmd;
int TempPos;

try
{
//Get Programmatic Identifier for this extension
try
{
oHKCR = Registry.ClassesRoot;
oProgID = oHKCR.OpenSubKey(FileExtension);
StrProgID = oProgID.GetValue(null).ToString();
oProgID.Close();
}
catch
{ //No ProgID, return false
return false;
}
//Get associated application
try
{
oOpenCmd = oHKCR.OpenSubKey(StrProgID + "\\shell\\open\\command");
StrExe = oOpenCmd.GetValue(null).ToString();
oOpenCmd.Close();
}
catch
{
//Missing default application
return false;
}
TempPos = StrExe.IndexOf(" %1");
if (TempPos > 0)
{
//Replace %1 placeholder with ParamFileName
StrExe = StrExe.Substring(0, TempPos);
AppName = StrExe.ToLower();
ShellAppName = StrExe + " " + Convert.ToChar(34) + ParamFileName + Convert.ToChar(34);
}
else
{
//No %1 placeholder found, append ParamFileName
AppName = StrExe.ToLower();
ShellAppName = StrExe + " " + Convert.ToChar(34) + ParamFileName + Convert.ToChar(34);
}
return true;
}
catch
{
return false;
}
}

Roy said...

Converted to C#:

string AppName;
string ShellAppName;

public bool GetRegisteredApplication(string ParamFileName, string FileExtension)
{
AppName = null;
ShellAppName = null;

//Return registered application by file's extension

string StrProgID;
string StrExe;
RegistryKey oHKCR; //HKEY_CLASSES_ROOT
RegistryKey oProgID;
RegistryKey oOpenCmd;
int TempPos;

try
{
//Get Programmatic Identifier for this extension
try
{
oHKCR = Registry.ClassesRoot;
oProgID = oHKCR.OpenSubKey(FileExtension);
StrProgID = oProgID.GetValue(null).ToString();
oProgID.Close();
}
catch
{ //No ProgID, return false
return false;
}
//Get associated application
try
{
oOpenCmd = oHKCR.OpenSubKey(StrProgID + "\\shell\\open\\command");
StrExe = oOpenCmd.GetValue(null).ToString();
oOpenCmd.Close();
}
catch
{
//Missing default application
return false;
}
TempPos = StrExe.IndexOf(" %1");
if (TempPos > 0)
{
//Replace %1 placeholder with ParamFileName
StrExe = StrExe.Substring(0, TempPos);
AppName = StrExe.ToLower();
ShellAppName = StrExe + " " + Convert.ToChar(34) + ParamFileName + Convert.ToChar(34);
}
else
{
//No %1 placeholder found, append ParamFileName
AppName = StrExe.ToLower();
ShellAppName = StrExe + " " + Convert.ToChar(34) + ParamFileName + Convert.ToChar(34);
}
return true;
}
catch
{
return false;
}
}