2

背景: 我正在开发一个可以同时运行 GUI 和控制台模式的 C++ MFC 应用程序。但在这两种情况下,用户都需要使用带有一些参数的命令提示符运行应用程序。当初始化应用程序时,它会检查命令提示符上的使用输入参数,并决定在控制台模式或 GUI 模式下运行。此应用程序需要使用多种语言。所以我使用字符串表来存储显示文本。

因此,在这里我使用此功能将现有命令提示符附加到应用程序,以在应用程序以控制台模式运行时显示状态。

BOOL CMyclass::EnableConsolePrinting(){
    BOOL GotConsoleAttach = FALSE;    
    if (AttachConsole(ATTACH_PARENT_PROCESS))
    {   
        int osfh = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), 8);
        if ((HANDLE)osfh != INVALID_HANDLE_VALUE)
        {
            *stdout = *_tfdopen(osfh, _T("a"));
            GotConsoleAttach = TRUE;
        }
    }
    return GotConsoleAttach;
}

然后像这样将状态打印到控制台。

this->EnableConsolePrinting();  
cout << CMsg(IDS_STRING_ERROR_MESSAGE); 

在 GUI 模式下,我使用此方法在标签中显示文本。

lblError.SetWindowTextW(CMsg(IDS_STRING_ERROR_MESSAGE));

问题:两种方法都编译并运行良好。但是 GUI 模式会显示正确的字符串,并且控制台会打印一些有意义的代码,比如这样。00C2D210对于相同的字符串。任何的想法?

4

2 回答 2

1

这是因为字符串是宽字符串(从尾随猜测,W使用SetWindowTextW窄字符时宽字符串的输出std::cout通常是一个神秘的十六进制数字)。用于wcout将宽字符串输出到控制台。

std::wcout << CMsg(IDS_STRING_ERROR_MESSAGE);

可能是标准输出流可能无法CString直接打印,在这种情况下,您可能必须为其添加输出运算符重载:

std::ostream& operator<<(std::ostream& os, const CString& str)
{
    auto length = str.GetLength();
    os << str.GetBuffer(length + 1);
    str.ReleaseBuffer();

    return os;
}
于 2013-02-08T08:50:45.637 回答
0

在这里,我通过几天的测试来回答我的问题。这是针对windows环境的。

#define GetCMsg(x) CString(MAKEINTRESOURCE(x))


void myClass::redirectIOToConsole()
{
    #define MAX_CONSOLE_LINES  500

    int hConHandle;
    long lStdHandle;

    CONSOLE_SCREEN_BUFFER_INFO coninfo;
    FILE *fp;

    // If you need to allocate a new console for this app
    //AllocConsole();

    //Attach existing console for this application
    AttachConsole(ATTACH_PARENT_PROCESS);

    // 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 = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );
    *stdout = *fp;
    setvbuf( stdout, NULL, _IONBF, 0 );

    // redirect unbuffered STDIN to the console
    lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "r" );
    *stdin = *fp;
    setvbuf( stdin, NULL, _IONBF, 0 );

    // redirect unbuffered STDERR to the console
    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle(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();
}


void myClass::writeToConsole(wstring result){   
    const HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD numWritten = 0;
    WriteConsoleW(stdOut, result.c_str(), result.size(), &numWritten, NULL);    
    cout.flush();
}

void myClass::myFoo(){
//attache current console to application
 this->redirectIOToConsole();
//write Unicode strings to current console 
 this->writeToConsole(GetCMsg(IDS_STRING_ERROR_MESSAGE));
}
于 2013-02-27T05:41:54.640 回答