如何使用命令行界面创建图形工具?

时间:2011-02-25 12:41:41

标签: c++ visual-studio user-interface command-line-interface

我正在构建一个既可以是图形工具也可以纯粹使用命令行界面的工具。 用户可以通过命令行选项" - command_line_only"来决定。我的IDE是Visual Studio 2008.

我似乎找不到合适的项目属性来确保

  1. 使用命令行界面模式时显示标准输出打印
  2. 在图形模式下使用该工具时,不会打开命令行框
  3. 有办法吗? Visual Studio的devenv似乎表现得像这样,所以我很确定它可以做到!

3 个答案:

答案 0 :(得分:1)

编辑:我似乎已经回答了你的标题,但在重新阅读你的问题时,我不确定这是你在问什么。我在这里留下答案,因为它可能对搜索你的标题的人有用

是的,你可以做到这一点,但一般来说,视觉研究并不能很容易地将代码与gui分开(特别是来自非常受约束的hello world示例)。如果你想混合输入,那么你真的想确保从一开始就做得很好。

我的建议是从命令行选项开始。如果您被允许使用提升(出于理由),请使用boost::program_options

然后,一旦你有了这个,你可以在顶部添加gui。另外,我建议使用像gtk ++这样的gui库,因为它是跨平台的。

答案 1 :(得分:1)

将应用程序构建为Win32应用程序(不是控制台应用程序),并检查参数以决定是否使用控制台窗口。

以下代码为based on this

使用控制台;创建一个名为CConsoleAttacher的类。使用它如下,基本上如果有参数然后打开一个控制台,如果你从那里开始将连接到CMD窗口。显然,当您启动主窗口时,Win32应用程序会从控制台中分离,因此需要在创建应用程序窗口之前尽早处理(这也是您想要做的事情......)

    CConsoleAttacher ca;
    if (ca.hasArguments())
    {
        ca.ConnectToConsole();
    }
    printf ("Test output \n");

创建一个名为CConsoleAttacher的类。

CConsoleAttacher.cpp

#include "StdAfx.h"

#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>
#include "ConsoleAttacher.h"

#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
static const WORD MAX_CONSOLE_LINES = 500;

CConsoleAttacher::CConsoleAttacher(void)
{
    argv = CommandLineToArgvW(GetCommandLineW(), &argc);

}


CConsoleAttacher::~CConsoleAttacher(void)
{
    LocalFree(argv);
}


int CConsoleAttacher::getArgumentCount(void)
{
    return argc;
}


CString CConsoleAttacher::getArgument(int id)
{
    CString arg ;
    if (id < argc)
    {
        arg = argv[id];
    }
    return arg;
}

bool CConsoleAttacher::hasArguments(void)
{
    return argc > 1;
}

void CConsoleAttacher::ConnectToConsole(void)
{
    int hConHandle;
    HANDLE lStdHandle;
    CONSOLE_SCREEN_BUFFER_INFO coninfo;
    FILE *fp;

    // allocate a console for this app
    if (!AttachConsole(ATTACH_PARENT_PROCESS))
    {
        if (!AllocConsole())
            return;
    }

    // set the screen buffer to be big enough to let us scroll text
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&coninfo);
    coninfo.dwSize.Y = MAX_CONSOLE_LINES;

    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize);

    // redirect unbuffered STDOUT to the console
    lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );

    *stdout = *fp;
    setvbuf( stdout, NULL, _IONBF, 0 );

    // redirect unbuffered STDIN to the console
    lStdHandle = GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "r" );

    *stdin = *fp;
    setvbuf( stdin, NULL, _IONBF, 0 );

    // redirect unbuffered STDERR to the console
    lStdHandle = GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );

    *stderr = *fp;
    setvbuf( stderr, NULL, _IONBF, 0 );

    // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
    // point to console as well
    ios::sync_with_stdio();
}

CConsoleAttacher.h

#pragma once
class CConsoleAttacher
{
private:
    int argc;
    wchar_t** argv;

public:
    CConsoleAttacher(void);
    ~CConsoleAttacher(void);
    int getArgumentCount(void);
    CString CConsoleAttacher::getArgument(int id);
    void ConnectToConsole(void);
    bool hasArguments(void);
};

答案 2 :(得分:1)

这不是一件容易的事,IIRC。问题是在Windows上,可执行文件本身具有一个标志,无论它是GUI应用程序还是控制台应用程序,例如执行其中一个时,cmd.exe的行为会有所不同。我建议您将应用程序的核心功能拆分为库,并构建单独的CLI和GUI前端。

编辑:如果你真的坚持,这对目标大有帮助。 goto出于历史原因,现在可以用if代替:

static
bool
usable_handle (HANDLE h)
{
    return h && h != INVALID_HANDLE_VALUE;
}


static
bool
try_reopen_std_handle (int dest_handle, DWORD os_handle_num, HANDLE os_handle,
    int flags)
{
    if (! usable_handle (os_handle))
        return false;

    int ret = SetStdHandle (os_handle_num, os_handle);
    assert (ret);
    if (! ret)
        return false;

    int base_flags = 0;
#if defined (UNICODE)
    //base_flags = _O_WTEXT;
#endif

    int opened_handle = _open_osfhandle (reinterpret_cast<intptr_t>(os_handle),
        flags | base_flags);
    assert (opened_handle != -1 && "_open_osfhandle");
    if (opened_handle == -1)
        return false;

    int dupd_handle = _dup2 (opened_handle, dest_handle);
    assert (dupd_handle != -1 && "_dup2");

    return dupd_handle == 0;
}


static
bool
try_fdopen (FILE * f, int handle, char const * mode)
{
    FILE * tmp = _fdopen (handle, mode);
    if (tmp && f)
        *f = *tmp;
    return !! tmp;
}


static
HANDLE
try_dup_os_handle (HANDLE src)
{
    if (! usable_handle (src))
        return INVALID_HANDLE_VALUE;

    HANDLE dest = INVALID_HANDLE_VALUE;
    HANDLE const process = GetCurrentProcess ();
    if (DuplicateHandle (process, src, process, &dest, 0, TRUE,
        DUPLICATE_SAME_ACCESS))
        return dest;
    else
        return INVALID_HANDLE_VALUE;
}


static
void
init_std_io ()
{
    // Retrieve inherited standard handles. AttachConsole() will close
    // the existing standard handles, so we duplicate them here first
    // to keep them alive.

    HANDLE os_stdin = try_dup_os_handle (GetStdHandle (STD_INPUT_HANDLE));
    HANDLE os_stdout = try_dup_os_handle (GetStdHandle (STD_OUTPUT_HANDLE));
    HANDLE os_stderr = try_dup_os_handle (GetStdHandle (STD_ERROR_HANDLE));

    // Attach existing console or allocate a new one.

    int ret = AttachConsole (ATTACH_PARENT_PROCESS);
    if (ret)
        OutputDebugString (_T("Attached existing console.\n"));
    else
    {
        ret = AllocConsole ();
        if (ret)
            OutputDebugString (_T("Allocated new console.\n"));
        else
            OutputDebugString (_T("Failed to allocate new console.\n"));
        assert (ret);
    }

    // Open a "POSIX" handle for each OS handle and then fdopen() a C stream
    // for each such "POSIX" handle.
    //
    // Only use the standard handle provided by AttachConsole() if the standard
    // handle from before AttachConsole() is not usable.
    //
    // Finally, re-open standard C stream.

    if (! usable_handle (os_stdin))
        os_stdin = GetStdHandle (STD_INPUT_HANDLE);
    ret = try_reopen_std_handle (0, STD_INPUT_HANDLE, os_stdin, _O_RDONLY);
    if (! ret)
        goto do_stdout;
    try_fdopen (stdin, 0, "r");

do_stdout:
    if (! usable_handle (os_stdout))
        os_stdout = GetStdHandle (STD_OUTPUT_HANDLE);
    ret = try_reopen_std_handle (1, STD_OUTPUT_HANDLE, os_stdout, _O_WRONLY);
    if (! ret)
        goto do_stderr;
    try_fdopen (stdout, 1, "w");

do_stderr:
    if (! usable_handle (os_stderr))
        os_stderr = GetStdHandle (STD_ERROR_HANDLE);
    ret = try_reopen_std_handle (2, STD_ERROR_HANDLE, os_stderr, _O_WRONLY);
    if (! ret)
        goto done_stderr;
    try_fdopen (stderr, 2, "w");

done_stderr:;
}