Nayana Adassuriya
Nayana Adassuriya

Reputation: 24766

Print string resources(string table) in C++ console application

Background: I'm developing a C++ MFC application that can run both GUI and Console modes. But at both time user need to run application using command prompt with some argument. When Init the application it checks the use input arguments on command prompt and decide to run in console mode or GUI mode. This application need to work with multiple language. So I'm using string table to store display texts.

So here I use this function to attached existing command prompt to application to show status when the application run as console mode.

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;
}

And then prints the status to console like this.

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

In GUI mode I use this method to show text in a label.

lblError.SetWindowTextW(CMsg(IDS_STRING_ERROR_MESSAGE));

Question: Both method compile and run fine. But GUI mode shows correct string and Console prints some meaning less code like this. 00C2D210 for same string. Any idea?

Upvotes: 2

Views: 1067

Answers (2)

Nayana Adassuriya
Nayana Adassuriya

Reputation: 24766

Here I'm answering my question by doing some testing few days. This is for windows environment.

#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));
}

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409176

It's because the strings are wide-character strings (guessing from the trailing W in SetWindowTextW, and the output of a wide-character string when using narrow-character std::cout is often a cryptic hexademinal number). Use wcout to output wide-character strings to the console.

std::wcout << CMsg(IDS_STRING_ERROR_MESSAGE);

It might be that the standard output stream might not be able to print CString directly, in which case you will probably have to add an output operator overload for it:

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

    return os;
}

Upvotes: 1

Related Questions