ShellExecute() is just what it says... a Shell. It is a shell around the OS and defaults to the OS to run programs, which gives it a lot more flexibility than CreateProcess(), which engages the program directly, which is why you can't run, say, HTML files, or PDF files, etc., with CreateProcess(), but which can be run with ShellExecute().
1. Determining the type of file by searching the Windows Registry.
2. Enumerating the allowed shell commands (verbs).
3. Retrieving the command line for the specified verb.
4. Constructing the command-line switches.
5. Calling CreateProcess() to start the process pointed to by the retrieved command line.
In my opinion, your coding of CreateProcess() has a bug that makes it fail, because as you can see from the above, ShellExecute() ends up calling CreateProcess().