How do I ShellExecute a file, but with a specific program instead of the default program?


The usual way to launch a file is to use Shell­Execute, which opens the file in the default program registered to handle that type of file. But what if you want to override the default?

We saw some time ago that if you know the ProgId of the program you want to run, you can specify it in the lpClass of the SHELL­EXECUTE­INFO to force the file to be treated as if it were a specific kind of file.

Okay, but what if you aren't sure that the program you want to run has registered a ProgId at all? Or if you don't know what that ProgId is? For example, maybe you searched the hard drive for executable files and put them all in a list, and let the user pick one, and then you want to run that program to open the file.

In that case, you are in a bit of a pickle because you don't know how an arbitrary program expects its command line to be formatted in order to open a file. Fortunately, most programs which can open files will accept the file name on the command line with no other options, so you will have a high chance of success if you simply enclose the name of the file you want to open in quotation marks (in case it contains spaces), and then pass that as the command line. When calling Shell­Execute, you pass lpFile equal to the program you want to run, and lpParameters equal to the file you want to open, enclosed in quotation marks if necessary.

Exercise: Does the path to the program need to be fully-qualified?

Exercise: Why do you have to quote the file you want to open, but not the program itself?

One reason you may want to use Shell­Execute instead of just going straight to Create­Process is if you need elevation. You can pass lpOperation equal to runas to get Shell­Execute to do the work of prompting the user for elevation.

Comments (13)
  1. Kenn says:

    Another reason to use ShellExecute rather than CreateProcess is that CreateProcess doesn’t modify the PATH environment variable to add per-application path directories (as configured at SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\exe-name.EXE). You need ShellExecute to do that.

  2. skSdnW says:

    A) No, it will search the normal places and the App Paths key. If you know the full path then you should use it, it is faster and will not cause problems if there are naming collisions, multiple versions installed, or a broken registry entry.

    B) The parameters argument can contain multiple switches and paths and space is the separator. You therefore need the path+name item to be quoted so it is treated as a single item. The file argument is always a single path/name and should never be quoted.

    1. Ivan K says:

      Off topic, but won’t there be an issue if two different applications happen to use the same “app paths” subkey name? I guess this isn’t an issue in the real world though since most people would pick a unique name or just overwrite an existing key on install.

      1. skSdnW says:

        In the real world it can be a issue because most installers do not delete the key, they just add the values they need without clearing the key first. If two apps with the same .exe name are installed on the same machine the app installed last “wins” but other values like “UseUrl” and “DropTarget” might still be there even if they are not supported by the second app.

  3. mikeb says:

    If searching takes place on a lpFile member that is not fully qualified, then the docs for SHELLEXECUTEINFO should be updated. They currently say this about lpFile: ” If the path is not included with the name, the current directory is assumed.”

    Of course, if you have a full path to the executable you should specify it. If searching takes place then you might not get the program you wanted executed.

      1. mikeb says:

        I’m not surprised that searching takes place or that it’s documented somewhere. I think that it would be appropriate to at least mention it in the docs for SHELLEXECUTEINFO, especially since what is mentioned there is incorrect for this scenario.

  4. Remy Lebeau says:

    Why doesn’t Microsoft expose new CreateProcess/ShellExecute APIs for launching elevated processes without having to use hacks? It has been possible for 10 years now using 3rd party functions (see https://www.codeproject.com/Articles/19165/Vista-UAC-The-Definitive-Guide), so why not make official APIs for it?

    1. Joshua says:

      I don’t think you’re gonna get an answer.

  5. Kevin says:

    If the filename or path contains quotation marks, you have to escape those, right? Is there a standard function for doing so?

    1. skSdnW says:

      Double quote is a reserved character not allowed in filenames.

    2. Joshua says:

      I’ve complained about no inverse of CommandLineToArgvW before.

    3. poizan42 says:

      Unfortunately no. And the escaping rules are complex and everybody gets them wrong. You must escape quotes with a backslash. But backslashes themselves are not escaped *unless they precede a quote*. So a run of backslashes preceding a quote must be doubled up. See this blogpost for a correct implementation: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/

Comments are closed.

Skip to main content