Create new console from console app? C++

2020-07-31 04:41发布

问题:

I am stuck on create new console window for my console application, for logger. That code works fine for GUI apps, but not work for console, and they require: CreateProcess function with the DETACHED_PROCESS flag.

Logger Log;    
DWORD PiD;

void __stdcall LoggerCore(PVOID pVoid)
{             
    AllocConsole();
    while(true)
    {
        SetConsoleTitleA(Log.LoggerTittle()); 
        Sleep(5000);
    }
    _endthread();
}            

char* Logger::LoggerTittle()
{
    static char Tittle[55]; 
    sprintf(Tittle, "Debug Logger");  
    return Tittle;
} 

void Logger::LoggerInit()
{   
  CreateThread( 0 , 0 , (LPTHREAD_START_ROUTINE) LoggerCore , 0 , 0 , &PiD );
}

And that code, create a new console when app is GUI, and display "Log.ConsoleOutPut(1, c_Green,t_Default,"Debug Logger: SomeInfo");" in new console window. But all of that, not work for console application. So, how i can make a second console window in console application by using CreateProcess? Thanks for advice!

So, i am try to re-write it, but nothing... that is not works for me.

#include logger.h
char Message[1024];

Logger Log;    

DWORD PiD;
/*

void __stdcall LoggerCore(PVOID pVoid)
{             
    AllocConsole();
    while(true)
    {
        SetConsoleTitleA(Log.LoggerTittle()); 
        Sleep(5000);
    }
    _endthread();
}            

char* Logger::LoggerTittle()
{
    static char Tittle[55]; 
    sprintf(Tittle, "Debug Logger");  
    return Tittle;
} 
*/
void Logger::LoggerInit()
{   
    SECURITY_ATTRIBUTES sa;
    sa.nLength=sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle=1;
    sa.lpSecurityDescriptor=0;
    SetHandleInformation(this->near_end,HANDLE_FLAG_INHERIT,0);
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    ZeroMemory(&pi,sizeof(pi));
    ZeroMemory(&si,sizeof(si));
    si.cb=sizeof(STARTUPINFO);
    si.dwFlags|=STARTF_USESTDHANDLES;
    TCHAR program[]=TEXT("???");//need type something here.
    TCHAR arguments[100];

    if (!CreateProcess(program,arguments,0,0,1,CREATE_NEW_CONSOLE,0,0,&si,&pi))
     printf( "CreateProcess failed (%d).\n", GetLastError() );
     return;

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    this->process=pi.hProcess;
    CloseHandle(pi.hThread);

 // CreateThread( 0 , 0 , (LPTHREAD_START_ROUTINE) LoggerCore , 0 , 0 , &PiD );
}


void Logger::CheckProcent(char* message)
{
    for (UINT i = 0; i <= strlen(message); i++)
    {                                                  
        if(message[i] == '%')         
        {
            for(UINT j = strlen(message); j >= i; j--)        
                message[j+1] = message[j];
            i++;
        }
    }
}

void Logger::ConsoleOutPut(int WOL, sColor Color, sLogType Type, const char* Format, ...)
{                   
    SYSTEMTIME t;
    GetLocalTime(&t);
    DWORD dwBytesWritten;
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    HANDLE hStdin;
    hStdin = GetStdHandle(STD_INPUT_HANDLE);

    if (hStdin == INVALID_HANDLE_VALUE)
        ExitProcess(1);

    va_list pArguments;
    va_start(pArguments, Format);
    sprintf(Message,Format, pArguments);
    CheckProcent(Message); // "%" Bug Fix 
    va_end(pArguments);

    char currdate[11] = {0};
    char outputmsg[2048];
    if(WOL == 1)
    {
        sprintf(currdate, "(%02d:%02d:%02d)", t.wHour, t.wMinute, t.wSecond);
        sprintf(outputmsg,"%s %s\n", currdate,Message);
    }
    else
        sprintf(outputmsg,"%s\n", Message); 

    switch(Color)
    {
    case c_BoldGreen: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_INTENSITY);
        break;
    case c_BoldRed: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED );
        break;
    case c_Red: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_RED | FOREGROUND_INTENSITY);
        break;
    case c_Green: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_GREEN | FOREGROUND_INTENSITY);
        break;
    case c_Blue: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_BLUE | FOREGROUND_INTENSITY);
        break;
    case c_Cyan: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
        break;
    case c_Yellow: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
        break;
    case c_Magenta: 
        SetConsoleTextAttribute(this->Handle(FALSE),FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY);
        break;
    case c_Grey:
        SetConsoleTextAttribute(this->Handle(FALSE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
        break;
    } 

    CreateLog(Type,outputmsg); 
    WriteFile(this->Handle(FALSE), outputmsg, strlen(outputmsg), &dwBytesWritten, NULL);
    SetConsoleTextAttribute(this->Handle(FALSE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    return;
}

HANDLE Logger::Handle(BOOL Input)
{
    if(Input==TRUE)
        return GetStdHandle(STD_INPUT_HANDLE);
    else
        return GetStdHandle(STD_OUTPUT_HANDLE);
}

void Logger::CreateLog(sLogType Type,const char* Format, ...)
{
    SYSTEMTIME now;
    GetLocalTime(&now);  

    char ConsoleLog[55];
    char CommandsLog[55]; 
    char ErrorLog[55];
    char Date[55];
    char SqlLog[55];
    char TestLog[55];
    sprintf(Date, ".\\Logger\\%02d-%02d-%02d\\", now.wDay, now.wMonth, now.wYear); 
    CreateDirectory(Date,NULL);

    sprintf(CommandsLog, ".\\Logger\\%02d-%02d-%02d\\Commands.log", now.wDay, now.wMonth, now.wYear); 
    sprintf(ConsoleLog, ".\\Logger\\%02d-%02d-%02d\\CONSOLE.log", now.wDay, now.wMonth, now.wYear);     
    sprintf(ErrorLog, ".\\Logger\\%02d-%02d-%02d\\Error.log", now.wDay, now.wMonth, now.wYear);
    sprintf(SqlLog, ".\\Logger\\%02d-%02d-%02d\\Sql.log", now.wDay, now.wMonth, now.wYear);
    sprintf(TestLog, ".\\Logger\\%02d-%02d-%02d\\Test.log", now.wDay, now.wMonth, now.wYear);

    va_list pArguments1;
    va_start(pArguments1, Format);
    sprintf(Message,Format, pArguments1);
    va_end(pArguments1);

    switch (Type)
    {
        case t_NULL:
        break;

        case t_Error:
        {
            SaveFile(ErrorLog, Message);
        }
        break;
        case t_Default: 
        {
            SaveFile(ConsoleLog,Message);
        }
        break;  
        case t_COMMANDS:
        {                                   
            SaveFile(ConsoleLog,Message);
            SaveFile(CommandsLog,Message);
        }
        break;
        case t_SQL: 
        {                                      
            SaveFile(ConsoleLog,Message);
            SaveFile(SqlLog,Message);
        }
        break;
        case t_TEST:
        {
            SaveFile(TestLog,Message);
        }
        break;
    }
}

void Logger::SaveFile(char *logString,char *Message)
{
    FILE *stream;  
    stream=fopen(logString, "a+" );
    fprintf(stream, "%s", Message);
    fclose(stream);
}

So, now my problem is - CreateProcess failed <2>, and when i am set TCHAR program[]=TEXT("application.exe"); - they launch many copies of that program, when i am set param in NULL - they return me <87> error... And they send logs to primary console window (app window).

回答1:

You can't. According to the documentation for AllocConsole:

A process can be associated with only one console, so the AllocConsole function fails if the calling process already has a console.

More info

You can't use CREATE_NEW_PROCESS and DETACHED_PROCESS together. See Process Creation Flags. I think you misunderstand what DETACHED_PROCESS is. From the documentation:

DETACHED_PROCESS

For console processes, the new process does not inherit its parent's console (the default). The new process can call the AllocConsole function at a later time to create a console. For more information, see Creation of a Console.

This value cannot be used with CREATE_NEW_CONSOLE.

A detached process is a process without a console. You can't create a new console for a process that doesn't have a console.

Remove the DETACHED_PROCESS flag from your call, and it should work.