В целом, запускатель невероятно переусложнен.
Основной challenge - определить, надо ли ожидать завершения запускаемой команды.
Сейчас ради этого переизобретается половина системного запускателя и сворачиваются горы - анализируются ассоциации в реестре, ищутся и исследуются файлы на диске, по очереди подставляя path/pathext и гордо предполагая, что мы постигли логику ОС и запустится именно то, что мы нашли. Что, внезапно, далеко не всегда так.
Есть, однако, и другой способ - просто тупо передать ОС то, что ввел пользователь, как есть, и посмотреть на результат.
Если что-то запустилось, то посмотреть на процесс и ждать только в том случае, если процесс консольный.
Это, наверное, позволило бы выкинуть процентов 90 кода и получать более адекватные результаты, но есть нюанс: тип процесса нам надо знать еще до запуска, т.к. если он консольный, то надо подготовить почву, убрав с экрана панели и т.п., а если нет, то все это бессмысленно и приводит только к мерцанию панелей.
Это, в принципе, тоже решаемо, несколькими путями:
- Машина времени. Идеально, но увы, we are limited by the technology of our time, but one day...
- Подготавливать почву всегда и смириться с тем, что панели будут мерцать при запуске notepad и paint.
- Запускать без подготовки, быстро анализировать запущенный процесс и, если да, быстро вытирать все, надеясь, что успеем до того, как процесс решит что-то вывести в консоль. Наверное, будет работать, т.к. на инициализацию процесса требуется какое-то время.
- Аналогично предыдущему пункту, но запускать процесс как paused, анализировать, опционально подготавливать экран и снимать с паузы. Увы, не работает с ShellExecuteEx, только с CreateProcess.