Win32 GUI приложение, которое записывает текст об использовании в стандартный вывод при вызове "app.exe --help"
Как мне создать приложение для Windows, которое делает следующее:
- это обычное приложение с графическим интерфейсом при вызове без аргументов командной строки
- указание необязательного аргумента командной строки "--help" приводит к тому, что приложение записывает текст использования в стандартный вывод, а затем завершается
- это должен быть один исполняемый файл. Никакого обмана, когда консольное приложение исполняет второй исполняемый файл.
- предположим, что основной код приложения написан на C/C++
- бонусные баллы, если окно GUI не создано при указании "--help". (т.е. без мерцания из недолговечного окна)
По моему опыту стандартный шаблон Visual Studio для консольного приложения не имеет возможности графического интерфейса, а обычный шаблон win32 не отправляет свой стандартный вывод в родительскую оболочку cmd.
3 ответа
Microsoft разработала консольные и графические приложения, чтобы быть взаимоисключающими. Этот бит близорукости означает, что не существует идеального решения. Самый популярный подход - иметь два исполняемых файла (например, cscript / wscript, java / javaw, devenv.com / devenv.exe и т. Д.), Однако вы указали, что считаете это "изменой".
У вас есть два варианта - сделать "исполняемый файл консоли" или "исполняемый файл GUI", а затем использовать код, чтобы попытаться обеспечить другое поведение.
- Исполняемый файл GUI:
cmd.exe
будет предполагать, что ваша программа не выполняет консольный ввод-вывод, поэтому не будет ждать ее завершения, прежде чем продолжить, что в интерактивном режиме (т.е. не в пакетном режиме) означает отображение следующего ("C:\>
") и чтение с клавиатуры. Поэтому даже если вы используете AttachConsole, ваш вывод будет смешан с cmd
вывод, и ситуация ухудшается, если вы попытаетесь сделать ввод. Это в основном не стартер.
- Исполняемый файл консоли:
Вопреки распространенному мнению, ничто не мешает отображению графического интерфейса консольного исполняемого файла, но есть две проблемы.
Во-первых, если вы запустите его из командной строки без аргументов (вам нужен графический интерфейс),cmd
все еще будет ждать его завершения, прежде чем продолжить, так что конкретная консоль будет недоступна на время. Этого можно избежать, запустив второй процесс с тем же исполняемым файлом (вы считаете это мошенничеством?), Передав флаг DETACHED_PROCESS в CreateProcess() и немедленно выйдя из него. Новый процесс может обнаружить, что у него нет консоли, и отобразить графический интерфейс.
Вот код C, чтобы проиллюстрировать этот подход:
#include <stdio.h>
#include <windows.h>
int main(int argc, char *argv[])
{
if (GetStdHandle(STD_OUTPUT_HANDLE) == 0) // no console, we must be the child process
{
MessageBox(0, "Hello GUI world!", "", 0);
}
else if (argc > 1) // we have command line args
{
printf("Hello console world!\n");
}
else // no command line args but a console - launch child process
{
DWORD dwCreationFlags = CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS;
STARTUPINFO startinfo;
PROCESS_INFORMATION procinfo;
ZeroMemory(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
if (!CreateProcess(NULL, argv[0], NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &startinfo, &procinfo))
MessageBox(0, "CreateProcess() failed :(", "", 0);
}
exit(0);
}
Я скомпилировал его с помощью gg cygwin - YMMV с MSVC.
Вторая проблема заключается в том, что при запуске из Проводника ваша программа на долю секунды отображает окно консоли. Нет никакого программного способа обойти это, потому что консоль создается Windows при запуске приложения до его запуска. Единственное, что вы можете сделать, это в вашем установщике сделать ярлык для вашей программы с помощью "команды show" SW_HIDE (т. Е. 0). Это повлияет только на консоль, если вы намеренно не соблюдаете поле wShowWindow STARTUPINFO в своей программе, так что не делайте этого.
Я проверил это, взломав cygwin "mkshortcut.exe". Как вы этого добьетесь в своей программе установки, зависит от вас.
Пользователь по-прежнему может, конечно, запустить вашу программу, найдя исполняемый файл в Проводнике и дважды щелкнув по нему, минуя скрывающий консоль ярлык и увидев короткую черную вспышку в окне консоли. Вы ничего не можете с этим поделать.
Ты можешь использовать AllocConsole()
Функция WinApi для выделения консоли для приложения с графическим интерфейсом. Вы также можете попробовать подключиться к консоли родительского процесса с помощью AttachConsole()
, это имеет смысл, если он уже есть. Полный код с перенаправлением stdout
а также stderr
к этой консоли будет так:
if(AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
Я нашел этот подход в источниках Pidgin (см. WinMain()
в pidgin/win32/winpidgin.c)
Я знаю, что мой ответ приходит поздно, но я думаю, что предпочтительным методом для ситуации здесь является метод ".com" и ".exe".
Это может считаться "обманом" по вашему определению двух исполняемых файлов, но это требует очень незначительных изменений со стороны программистов и может быть сделано одно и забыто. Также это решение не имеет недостатков решения Хью, где у вас есть окна консоли, отображаемые в течение доли секунды.
В окнах командной строки, если вы запускаете программу и не указываете расширение, порядок расположения исполняемого файла предпочтительнее, чем.com, а не.exe.
Затем вы можете использовать хитрости, чтобы этот ".com" был прокси для stdin / stdout / stderr и запустить файл с тем же именем.exe. Это дает поведение, позволяющее программе выполнять преформу в режиме командной строки при вызове из консоли (возможно, только при обнаружении определенных аргументов командной строки), при этом все еще имея возможность запускаться как приложение с графическим интерфейсом без консоли.
Существуют различные статьи, описывающие это, например, "Как сделать приложение как графическим, так и консольным приложением?" (см. ссылки в ссылке ниже).
Я разместил проект под названием dualsubsystem в коде Google, который обновляет старое решение Codeguru для этой техники и предоставляет исходные коды и рабочие примеры двоичных файлов.
Я надеюсь, что это полезно!