Andreas
Andreas

Reputation: 10037

How to emulate ShellExecute() with CreateProcess()

I'm trying to open a *.jpg file with CreateProcess() and I want CreateProcess() to behave exactly the same as when opening the *.jpg with ShellExecute().

So I first use FindExecutable() to get the viewer application for the *.jpg file, then I concatenate the viewer application's path and the path to the *.jpg file, adding quotes to make sure it works with paths that have spaces in them.

However, the result is not the same: On my system *.jpg files are associated with an application that has a lightweight viewer mode and a more sophisticated editor mode. When I use ShellExecute() to open the file (or double-click on it in Explorer), the viewer application opens in the lightweight viewer mode. When I use CreateProcess() as described above, however, the viewer application shows the *.jpg file as well but it opens in editor mode.

So ShellExecute() must be doing something else that causes the viewer application to behave like it does but I don't know what. Any ideas what might be missing to make CreateProcess() behave exactly like ShellExecute()?

This is what the code looks like currently:

PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;

memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
memset(&siStartInfo, 0, sizeof(STARTUPINFO));

siStartInfo.cb = sizeof(STARTUPINFO); 

CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);

Upvotes: 0

Views: 832

Answers (1)

Anders
Anders

Reputation: 101569

ShellExecute uses CreateProcess internally but before it gets there it does many other things.

This blog post by Raymond Chen provides a hint:

The Find­Executable function comes from 16-bit Windows, and back in those days, there were no context menu shell extensions or custom drop targets. (There was DDE, but that’s okay, because programs still have to register an executable to be used in the fallback case when nobody responds to the DDE message.)

...

Newer applications shouldn’t be using Find­Executable anyway, seeing as the handler for a file type may not even be an executable.

A IContextMenu based shell extension could be the default and if it is, it can do anything and ShellExecute just tells the extension to invoke the command. This is not done if SEE_MASK_INVOKEIDLIST is not specified?

A classic static verb in the registry can have IExecuteCommand and/or drop target handlers that also perform the actual execution.

If neither of the above are true, ShellExecute will look for DDE registration and if found it will try to use DDE.

If all else fails, ShellExecute will use CreateProcess to invoke the command string after substituting the %1 values.

Even if you emulate all of this (including all the undocumented details and compatibility workarounds) you still have to call ShellExecute if the command resolves to a executable that requires UAC elevation.

Just figuring out which verb is the true default is hard enough, I suggest that you just use ShellExecute and let the shell handle the rest.

If you are just curious, you can look at the resulting command line in Task Manager or Process Explorer to see if a custom handler simply adds a special parameter.

Upvotes: 3

Related Questions