Click here to Skip to main content
11,647,828 members (68,043 online)
Click here to Skip to main content

Open With (.NET)

, 17 Jun 2014 CPOL 7.2K 370 24
Rate this:
Please Sign up or sign in to vote.
Application selection for a File to open it with

Introduction

This is about a DLL for opening a file with an application that the user can select from a collection of applications that supports the files extension.

This DLL has a UserControlwhich demonstrates how it works, a WindowsFormFormular that you call with a staticfunction and can give you the Diagnostics.Process back from the opened application like Process.Start does.

Background

I need an Open With function for a software I am currently working on, like the Windows function from the Contextmenuof a file and if the user selects an application to open with, I need the Diagnostics.Process for it to see when the application is closed to save the file back in my software. The problem was .NET does not provide as a function.

Using the Code

The base class structure looks like the following diagram:

Class Filelink

Filelocationwhich is the Filepathwith the execute name from an application.

Paramswhich are the optional Params(Verbs).

PreParamsare used for like DLL where rundll32.exe must be executed.

The ToStringmethod will return a stringwith Filelocation, Paramsand PreParamsfor the FilelinkObject.

Class cApplicationData

This class contains relevant data for an application like the Iconand Productname.

Class OpenWith

This class has a Dictionary<String, cApplication> in which you can find all applications for the extension for which you created OpenWith, Keyof the Dictionaryis the Productname. UserChoiceApplicationis the cApplicationData for the default selection.

How We Get the Applications

You create a new Instance from the OpenWith class with a Fileextension, this class will check the Registry for the current Fileextensionand create the Collectionof cApplicationData.

First of all, it will check in the Registrykey"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts".

There can be found the "UserChoice" Subkeyfor the default application, next check is in the Subkey"OpenWithList" for the applications for this extension.

using (RegistryKey rkReg = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\" + strFileExtension))
            {
                if (rkReg != null)
                {
                    //Check subkey for User choice Programm
                    using (RegistryKey rkUserChoice = rkReg.OpenSubKey("UserChoice"))
                    {
                        if (rkUserChoice != null)
                        {
                            mHaveUserChoice = true;
                            string tempUserChoiceName = (string)rkUserChoice.GetValue("ProgId");
                            tempUserChoiceName = tempUserChoiceName.Replace("Applications\\", "");

                            mProgUserChoice = new cApplicationData(tempUserChoiceName);
                            if (mProgUserChoice == null)
                            {
                                mHaveUserChoice = false;
                            }
                            rkUserChoice.Close();
                        }
                        else
                        {
                            mHaveUserChoice = false;
                        }
                    }

                    if (mProgrammList != null)
                    {
                        mProgrammList.Clear();
                    }
                    else
                    {
                        mProgrammList = new Dictionary<string, cApplicationData>();
                    }

                    //Check subkey for OpenWithList
                    using (RegistryKey rkOpenWithList = rkReg.OpenSubKey("OpenWithList"))
                    {
                        if (rkOpenWithList != null)
                        {
                            string[] strKeyArray = rkOpenWithList.GetValueNames();

                            foreach (string strKeyName in strKeyArray)
                            {
                                string tempValue = (string)rkOpenWithList.GetValue(strKeyName);
                                if (tempValue.Contains("."))
                                {
                                    cApplicationData appData = new cApplicationData(tempValue);

                                    if (appData != null && appData.Havefilelinks && !string.IsNullOrEmpty(appData.Productname))
                                    {
                                        Log.Livelog.Log(string.Format("Add New Key to Programmlist Applicationkey:'{0}'  Productname:'{1}'", tempValue, appData.Productname));
                                        mProgrammList.Add(appData.Productname, appData);
                                    }
                                }
                            }
                            rkOpenWithList.Close();
                        }
                    }

After this, we are looking in the Registrykey"HKEY_CLASSES_ROOT" which have Subkeys with Fileextensions. There we check the Subkeyfor the current extension "OpenWithProgids" which contains another list of applications for the extension.

//Check extension in HKEY_CLASSES_ROOT
                    using (RegistryKey rkExtensionClassRoot = Registry.ClassesRoot.OpenSubKey(strFileExtension + "\\OpenWithProgids"))
                    {
                        if (rkExtensionClassRoot != null)
                        {
                            string[] strKeyArray = rkExtensionClassRoot.GetValueNames();

                            foreach (string strKeyName in strKeyArray)
                            {
                                cApplicationData appData = new cApplicationData(strKeyName);

                                if (appData != null && appData.Havefilelinks && !string.IsNullOrEmpty(appData.Productname) && !mProgrammList.ContainsKey(appData.Productname))
                                {
                                    Log.Livelog.Log(string.Format("Add New Key to Programmlist Applicationkey:'{0}' Productname:'{1}'", strKeyName, appData.Productname));
                                    mProgrammList.Add(appData.Productname, appData);
                                }
                            }
                            rkExtensionClassRoot.Close();
                        }
                    }

And the last Registry, we are looking for applications if an application supports this Fileextensionand is not in our Collection. This Registryentries can be found in "HKEY_CLASSES_ROOT\Applications", each Subkeyis an Applicationand can have the Subkey"SupportedTypes" where the Values Names are Fileextensionsnames.

//Check Application Support File Extension
RegistryKey rkApplic = Registry.ClassesRoot.OpenSubKey("Applications");
if (rkApplic != null)
{
    string[] strSubKeys = rkApplic.GetSubKeyNames();
    if (strSubKeys != null)
    {
        //for each Application 
        foreach (string mApp in strSubKeys)
        {
            
                //Check for Subkey SupportedTypes
                RegistryKey rkSup = rkApplic.OpenSubKey(mApp + "\\SupportedTypes");
                if (rkSup != null)
                {
                    string[] strNames = rkSup.GetValueNames();
                    if (strNames.Contains<string>(strFileExtension))
                    {
                        //File Extension is Supported by this Application
                        cApplicationData appData = new cApplicationData(mApp);
                        
                        if (appData != null && appData.Havefilelinks && 
                        !string.IsNullOrEmpty(appData.Productname) && 
                        !mProgrammList.ContainsKey(appData.Productname))
                        {
                                Log.Livelog.Log(string.Format("Add New Key to 
                                Programmlist Applicationkey:'{0}' Productname:'{1}'", mApp, appData.Productname));
                                mProgrammList.Add(appData.Productname, appData);
                        }
                    }
                }
        }
    }
}

Create cApplicationData

Create a new Instance for cApplicationData with the Registrynameof an application.

First of all, it will try to find the application in "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\".

//get app path from CurrentVersion
            using (RegistryKey rkAppPaths = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + mAppRegName))
            {
                if (rkAppPaths != null)
                {
                    string[] strKeyName = rkAppPaths.GetValueNames();
                    if (strKeyName != null)
                    {
                        foreach (string mkey in strKeyName)
                        {
                            if (string.IsNullOrEmpty(mkey))
                            {
                                string strFilelink = (string)rkAppPaths.GetValue(mkey);

                                Filelink fl = NormalizeToFilelink(strFilelink);

                                if (fl != null)
                                {
                                    mOpenFileLink = fl;
                                    mHaveFilelinks = true;

                                    GetApplicationFileInfo(fl.Filelocation);
                                    fl = null;
                                }
                                else
                                {
                                    Log.Livelog.Log(string.Format("No Filelink Class for '{0}'", strFilelink));
                                }
                            }
                        }
                    }
                }

If the application can't find it there, it checks the Subkey"HKEY_CLASSES_ROOT\Applications" and if the application also can't find it there, it checks if it is a Subkeyfor "HKEY_CLASSES_ROOT".

string strSubkeyRoot = "Applications\\";

                    //If not in CurrentVersion then Check there
                    RegistryKey rkAppShell = Registry.ClassesRoot.OpenSubKey(strSubkeyRoot + mAppRegName + "\\shell");
                    if (rkAppShell == null)
                    {
                        //try without Subkey
                        if (!string.IsNullOrEmpty(strSubkeyRoot))
                        {
                            rkAppShell = Registry.ClassesRoot.OpenSubKey(mAppRegName + "\\shell");
                        }
                    }

Under the Subkey"shell\command", there can be Multiple Value Names like "open", "edit", "play", "print" and "preview", for each of this names are FileLink classes where you can access the Filepathand its params. After getting a Filelink, it will try to get the IO.FileInfo and Diagnostics.FileVersionInfo if they are null. The next step is to get the Iconfrom the FileLinkfor the application.

System.Drawing.Icon ico = System.Drawing.Icon.ExtractAssociatedIcon(mAppFilelink);
if (ico != null)
{
    mAppIcon = ico;
}

Controls

ucOpenWith

This control should be loaded with the Filename that you would open with an application. ApplicationProcessis a readonly property for the Diagnostics.Process of the selected application, FormatGridcan be overridden if necessary. In the InitOpenWithmethod, the ProcessStart.OpenWith is called with the extension from the File to get all applications. If an application is selected, the control starts the application with the file as parameter and fires the ApplicationProcessStart Event. If the Property ShowGridToolTipis set to true, the Name Cell in the Grid can have a Tooltipwith the Companyname.

frmOpenWithDialog

This Windows Form has the property ApplicationProcesswhich is a readonly Diagnostics.Processfor the selected application. The Formshould be loaded with the Filename.

ProcessOpen

With the ProcessOpenclass, you can call a staticmethod to show frmOpenWithDialogas Dialog, it has one overload where you can get the Diagnostics.Processfor the selected application.

Overloads for ShowDialog

/// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename)
        {
            return ShowDialog(strFullFilename, "");
        }

        /// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <param name="strFormularTitle">Formular Text</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename, string strFormularTitle)
        {
            return ShowDialog(strFullFilename, strFormularTitle, false);
        }

        /// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <param name="strFormularTitle">Formular Text</param>
        /// <param name="bShowgridToolTip">Shows the Application Companyname as Grid Tooltip (default=False)</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename, string strFormularTitle, bool bShowgridToolTip)
        {
            if (!string.IsNullOrEmpty(strFullFilename))
            {
                DialogResult dlgReturn = DialogResult.No;

                using (frmOpenWithDialog frm = new frmOpenWithDialog())
                {
                    frm.Load(strFullFilename);

                    if (!string.IsNullOrEmpty(strFormularTitle))
                    {
                        frm.Text = strFormularTitle;
                    }
                    if (bShowgridToolTip)
                    {
                        frm.ShowGridToolTip = bShowgridToolTip;
                    }

                    dlgReturn = frm.ShowDialog();
                }

                return dlgReturn;
            }
            else
            {
                throw new ArgumentNullException("strFullFilename");
            }
        }

        /// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <param name="prc">Diagnositcs.Process for the Applcation</param>
        /// <param name="strFormularTitle">Formular Text</param>
        /// <param name="bShowgridToolTip">Shows the Application Companyname as Grid Tooltip (default=False)</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename, out System.Diagnostics.Process prc, string strFormularTitle, bool bShowgridToolTip)
        {
            if (!string.IsNullOrEmpty(strFullFilename))
            {
                DialogResult dlgReturn = DialogResult.No;

                using (frmOpenWithDialog frm = new frmOpenWithDialog())
                {
                    frm.Load(strFullFilename);

                    if (!string.IsNullOrEmpty(strFormularTitle))
                    {
                        frm.Text = strFormularTitle;
                    }
                    if (bShowgridToolTip)
                    {
                        frm.ShowGridToolTip = bShowgridToolTip;
                    }

                    dlgReturn = frm.ShowDialog();

                    prc = frm.ApplicationProcess;
                }

                return dlgReturn;
            }
            else
            {
                throw new ArgumentNullException("strFullFilename");
            }
        }

        /// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <param name="prc">Diagnositcs.Process for the Applcation</param>
        /// <param name="strFormularTitle">Formular Text</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename, out System.Diagnostics.Process prc, string strFormularTitle)
        {
            return ShowDialog(strFullFilename, out prc, strFullFilename, false);
        }

        /// <summary>
        /// Shows OpenWith Dialog for the File
        /// </summary>
        /// <param name="strFullFilename">Fullfilename (Path and Filename)</param>
        /// <param name="prc">Diagnositcs.Process for the Applcation</param>
        /// <returns>DialogResult.OK if Application selected</returns>
        public static DialogResult ShowDialog(string strFullFilename, out System.Diagnostics.Process prc)
        {
            return ShowDialog(strFullFilename,out prc, "");
        }

Overloads for static calls Start

/// <summary>
        /// Start an Application from Filelink with File 
        /// </summary>
        /// <param name="fl">Filelink for the Application</param>
        /// <param name="File">File to open</param>
        /// <returns>the Diagnostics.Process for the Application</returns>
        public static Process Start(ProcessStart.Filelink fl, string File)
        {
            if (fl != null)
            {
                return ProcessOpen.Start(fl.PreParams, fl.Filelocation, fl.Params, File);
            } else
            {
                throw new ArgumentNullException("fl", "ProcessStart.Filelink can't be Null when starting a Process");
            }
        }

        /// <summary>
        /// Start an Application from the Parameter with a File
        /// </summary>
        /// <param name="PreParam">Preparams for the Application (rundll32)</param>
        /// <param name="Path">Application Path</param>
        /// <param name="Params">Application parameter</param>
        /// <param name="File">File to open</param>
        /// <returns>the Diagnostics.Process for the Application</returns>
        public static Process Start(string PreParam, string Path, string Params, string File)
        {
            string strCommandPromt = "";
            bool bHavePreParams = false;

            //needed for .dll (rundll32)
            if (!string.IsNullOrEmpty(PreParam))
            {
                strCommandPromt =  PreParam ;
                bHavePreParams = true;
            } else
            {
                strCommandPromt = Path;
            }

            if (!string.IsNullOrEmpty(Params))
            {
                if (Params.Contains("%1"))
                {
                    if (bHavePreParams)
                    {
                        //problem with dll with qoute by the target file path
                        Params = "  \"" + Path + "\"  " + " " + Params.Replace("%1", " " + File + " ");
                    }
                    else
                    {
                        Params = Params.Replace("%1", "  \"" + File + "\"  ");
                    }
                }
                //Ignore other Verbs at this moment
                if (Params.Contains("%"))
                {
                    //Replace % and Wildcard with Empty
                    Params = System.Text.RegularExpressions.Regex.Replace(Params, @"%\d+", "");
                }
            } else
            {
                //add the file to the command
                Params = "  \"" + File + "\"";
            }

            ProcessStartInfo psi = new ProcessStartInfo(strCommandPromt);
            psi.Arguments = Params;

            return Process.Start(psi);
        }

OpenWithDialogopened with a .txt file:

OpenWithDialogopened with a .jpg file:

Points of Interest

TODO

  • Applications which have DLL as filename are currently not supported
  • Applications with DelegateExecuteare not implemented
  • Implement automatic test

At this time, this has only been tested under Windows 8.1 and Windows 7.

History

  • Version 1.0 released 17.06.2014
  • New Version 1.1 released 19.06.2014, DLL Application support, Code changing, new overloads in ProgressOpen

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

You can find my Blog @ dlution.at

You may also be interested in...

Comments and Discussions

 
QuestionBuilt-in Windows Explorer Shell Functionality Pin
newton.saber15-Jul-14 8:24
membernewton.saber15-Jul-14 8:24 
BugI like it. Pin
MR-DIBBLER18-Jun-14 10:56
memberMR-DIBBLER18-Jun-14 10:56 
AnswerRe: I like it. Pin
Taucher Christoph18-Jun-14 11:52
memberTaucher Christoph18-Jun-14 11:52 
SuggestionNice work Pin
Daniele Rota Nodari17-Jun-14 23:40
memberDaniele Rota Nodari17-Jun-14 23:40 
AnswerRe: Nice work Pin
Taucher Christoph17-Jun-14 23:55
memberTaucher Christoph17-Jun-14 23:55 
QuestionVery useful! Pin
leiyangge17-Jun-14 15:22
memberleiyangge17-Jun-14 15:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150804.4 | Last Updated 17 Jun 2014
Article Copyright 2014 by Taucher Christoph
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid