What is the lpClass member of SHELLEXECUTEINFO used for?

A customer reported problems launching the default Web browser with the Shell­Execute­Ex function:

int _tmain(int argc, _TCHAR* argv[])
  sei.cbSize = sizeof(sei);
  sei.nShow = SW_SHOWNORMAL;
  sei.lpFile = TEXT("www.microsoft.com");
  sei.lpVerb = TEXT("opennew");
  sei.lpClass = TEXT("htmlfile");


  return 0;

This fails with sei.hInstApp = SE_ERR_FNF.

If you don't pass the SEE_MASK_CLASSNAME flag and leave lpClass = NULL, then the Shell­Execute­Ex function will try to figure out what your lpFile refers to, looking at the file extension, looking for the file on the PATH, and if all else fails, trying some autocorrection. In this case, the customer was relying on the autocorrection, since they left the http:// prefix off their URL. One of the default autocorrection rules is that if the item that couldn't be launched begins with www, then try again with http:// in front.

On the other hand, if you pass an explicit lpClass, then no name resolution is performed on the lpFile. You're saying "Don't do any sniffing and poking and autocorrection. I have already determined that this item should be executed according to the rules specified for HKEY_CLASSES_ROOT\htmlfile, so just follow the rules and don't question me."

No second-guessing means that the Shell­Execute­Ex function shrugged its shoulders and said, "Well, I don't see a file called www.microsoft.com in the current directory, so I will fail with a file-not-found error."

If you pass an explicit class, then Shell­Execute­Ex will treat your lpFile as if it were a file of that type. If you have something and you want all the standard detection logic to kick in, then don't specify a class.

Bonus reading: The above program is simplified to illustrate the topic. A real-life version of this program needs some other scaffolding.

Comments (14)
  1. WndSks says:

    And as a final issue, htmlfile might not be the class for .html files, you would have to check HKCR.html first

  2. RichB says:

    You only ever talk about poorly designed Win32 APIs here. How about showing us a well designed API?

    …or is that not possible ;-)….

    [What would be the point? "Hey, here's help on using a function that nobody is having trouble with!" -Raymond]
  3. I see the problem.  They forgot to call SetCurrentDirectory(_T("http://")) first.

  4. Dan says:

    Wouldn't the class type for http:// urls be "http" anyway?  Granted I don't really understand how protocol classes work in this respect.  Would the flawed example work with "www.example.com" and a "http" class, or would it still need http:// prefixing the url?

  5. santosh says:

    I don't understand how customer can report problems but can't read full documentation of an API.

  6. Would the flawed example work with "www.example.com" and a "http" class

    IIRC, the shell would do whatever HKEY_CLASSES_ROOThttpshellopencommand says to do.  On one of my machines this is:

    "C:Program Files (x86)Internet ExplorerIEXPLORE.exe" -nohome

    And on the other it is:

    "C:Program FilesMinefieldfirefox.exe" -requestPending -osint -url "%1"

    The launched process would then have to decide what to do with the http://-less URL.

  7. No, that can't be right, or the "htmlfile"/"opennew" would have worked too.

  8. Paul says:


      In my mind, one of the characteristics of a well designed API (vs a poorly designed one) is that it can be used without documentation because the expected functions exist and work as expected.  

    …Relying, of course, on some sort of code auto-completion feature in your IDE

  9. Kyle says:


    In only the most basic of circumstances will that ever hold true.  When dealing with simple operations like mathematics (add, subtract, etc.), that can certainly hold true.  Difficult procedures (like invoking new processes, etc.) require lots of options because of the general purpose nature of Windows.  Perhaps ShellExecuteEx() could be improved, but could it really be improved to the point that documentation would be unnecessary?  How so?  And how do you improve functions while maintaining backward compatibility?

    The issues seen with the Windows API are the result of years of organic growth.  It's not to say that things should never be improved or superseded, but it's practically impossible to have a constantly developed API meet this mythical notion of being "well-designed" in all facets.  It only happens in APIs that progress very, very slowly and APIs that provide very little flexibility.

  10. Alexandre Grigoriev says:


    Is "IsBadReadPtr" well designed API? After all, its name practically tells what it's doing.

  11. Kyle says:

    Ummm…so what makes the ShellExecuteEx() a poorly designed API, RichB?  Because a developer can't use it without reading documentation?  Oh wait…that's the case with *all* APIs.

  12. GregM says:

    "I don't understand how customer can report problems but can't read full documentation of an API."

    Santosh, you obviously haven't seen these 2 Connect bug reports from the last 2 months: "3 * 0.1 is not 0.3" and "I get an access violation when I pass RegQueryValue a 100 byte buffer but say that it's 500 bytes long".

  13. Gabe says:

    Kyle: GregM has demonstrated that even simple mathematical functions (how come 3 * 0.1 != 0.3?) can't be used without documentation. I doubt Paul can create an API that can be used with no documentation, yet won't cause somebody to report a bug against it.

  14. Kyle says:


    It's amazing such people become developers.  :)

Comments are closed.