Win32 GUI приложение, которое записывает текст об использовании в стандартный вывод при вызове «app.exe --help» - PullRequest
20 голосов
/ 10 сентября 2008

Как создать приложение для Windows, которое выполняет следующие действия:

  • это обычное приложение с графическим интерфейсом, когда оно вызывается без аргументов командной строки
  • указание необязательного аргумента командной строки "--help" приводит к тому, что приложение записывает текст использования в стандартный вывод, а затем завершается
  • это должен быть один исполняемый файл. Никакого обмана, когда консольное приложение исполняет второй исполняемый файл.
  • предположим, что основной код приложения написан на C / C ++
  • бонусных баллов, если окно GUI не создано, если указано «--help». (т.е. без мерцания из недолговечного окна)

По моему опыту, стандартный шаблон Visual Studio для консольного приложения не имеет возможности графического интерфейса, а обычный шаблон win32 не отправляет свой стандартный вывод в родительскую оболочку cmd.

Ответы [ 3 ]

22 голосов
/ 22 сентября 2008

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 при запуске приложения до его запуска. Единственное, что вы можете do в вашей программе установки создайте ярлык для вашей программы с помощью команды "show command" SW_HIDE (т.е. 0). Это повлияет только на консоль, если вы сознательно не соблюдаете поле wShowWindow в STARTUPINFO в вашей программе, так что не делайте этого.

Я проверил это, взломав cygwin "mkshortcut.exe". Как вы делаете это в вашей программе установки по вашему выбору.

Пользователь по-прежнему может, конечно, запустить вашу программу, найдя исполняемый файл в Проводнике и дважды щелкнув по нему, минуя скрывающий консоль ярлык и увидев короткую черную вспышку окна консоли. С этим ничего не поделаешь.

13 голосов
/ 28 сентября 2014

Вы можете использовать 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)

4 голосов
/ 08 июля 2009

Я знаю, что мой ответ поступит поздно, но я думаю, что предпочтительным методом для ситуации здесь является метод ".com" и ".exe".

Это может считаться "обманом" по вашему определению двух исполняемых файлов, но это требует очень небольших изменений со стороны программистов и может быть сделано один и забыто. Также у этого решения нет недостатков решения Хью, где у вас есть окна консоли, отображаемые в течение доли секунды.

В окнах из командной строки, если вы запускаете программу и не указываете расширение, порядок расположения исполняемого файла предпочтительнее .com, чем .exe.

Затем вы можете использовать хитрости, чтобы этот ".com" был прокси для stdin / stdout / stderr и запустить файл с тем же именем .exe. Это дает поведение, позволяющее программе выполнять преформу в режиме командной строки при вызове из консоли (возможно, только при обнаружении определенных аргументов командной строки), при этом все еще имея возможность запускаться как приложение с графическим интерфейсом без консоли.

Существуют различные статьи, описывающие это, например, «Как сделать приложение как графическим, так и консольным приложением?» (см. ссылки в ссылке ниже).

Я разместил проект под названием dualsubsystem в коде Google , который обновляет старое решение Codeguru для этой техники и предоставляет исходный код и исполняемые файлы с примерами.

Надеюсь, это полезно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...