你怎么写第二个控制台?

时间:2014-11-24 18:31:39

标签: c++ winapi

我想在我的程序中使用第二个控制台来记录编程活动。我在msdn上查看了相关的函数/示例,并尝试将一个简单的程序组合在一起:

//function in parent that communicates with child
void writeToChild()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

HANDLE inWrite, inRead,
       outWrite, outRead;
SECURITY_ATTRIBUTES saAttr;

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&inRead, &inWrite, &saAttr, 0))
{
    exit(0xbad);
}
if ( ! SetHandleInformation(inRead, HANDLE_FLAG_INHERIT, 0) )
{
    exit(0xbad);
}
if (!CreatePipe(&outRead, &outWrite, &saAttr, 0))
{
    exit(0xbad);
}
if ( ! SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0) )
{
    exit(0xbad);
}

ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.lpTitle = "Log";
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = outWrite;
si.hStdError = outWrite;
si.hStdInput = inRead;
ZeroMemory( &pi, sizeof(pi) );

// Start the child process.
if( !CreateProcess( NULL,   
    "Logger",          
    NULL,        
    NULL,       
    TRUE,       
    CREATE_NEW_CONSOLE,             
    NULL,           
    NULL,           
    &si,            
    &pi )          
)
{
    printf( "CreateProcess failed (%d).\n", GetLastError() );
    exit(0xbad);
}
unsigned long numWritten = 0;
WriteFile(inWrite, "Test", 4, &numWritten, NULL);
cout<<"wrote "<<numWritten<<" characters"<<endl;

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

// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}

//Logger
#include <windows.h>

#define BUFSIZE 4096

int main()
{
HANDLE stdin, stdout;
stdin = GetStdHandle(STD_INPUT_HANDLE);
stdout = GetStdHandle(STD_OUTPUT_HANDLE);

char buffer[BUFSIZE];
unsigned long numRead;
while (true)
{
    ReadFile(stdin, buffer, BUFSIZE, &numRead, NULL);
    if (numRead > 0)
        WriteFile(stdout, buffer, numRead, NULL, NULL);
}
return 0;
}

问题是,当父级显示写入4个字符时,子控制台上不会显示任何内容。我不确定如何调试这个因为我没有使用Windows编程的经验。

2 个答案:

答案 0 :(得分:2)

我不太确定您在代码段中使用单独的流程的位置。但是,在Windows中不能有多个与单个进程关联的控制台,尽管您可以将多个屏幕缓冲区与单个控制台关联并在它们之间切换(请参阅SetConsoleActiveScreenBuffer并从那里开始),但是您必须为切换实现用户界面;它不是内置的东西。

如果屏幕缓冲区不适合你,你可以通过管道或环回套接字或其他一些IPC方法进行第二个记录器进程,例如:

  • 您可以使用syslog,这是各种应用程序和硬件使用的常用日志记录工具。

  • 您还可以写入日志文件并使用程序观看文件,例如Windows equivalent of tail -f。这样做的好处是可以将记录的数据存储在一个文件中,以便日后查看。

  • 您可以让您的应用程序充当TCP服务器,telnet到它,并通过telnet转储日志消息。

请注意,对于上述任何选项,为方便用户,您可以让应用程序单独启动第二个日志监视过程(只需简单调用ShellExecute,不要过火)

其他选项包括:

  • 您可以使用Windows事件日志,虽然它可能有点麻烦。

  • 您可以创建一个单独的GUI窗口,其中包含一个文本字段或显示日志消息的列表。

  • 如果您的程序是拥有自己的控制台的GUI应用程序(从您的描述中看似乎不是这种情况,只是为了完整性)您可以创建AllocConsole和朋友的控制台(但请注意,在关闭控制台时仍会关闭该控制台也会终止您的应用程序。)

这里有很多选择。但是你不能为同一个过程安装两个控制台。

答案 1 :(得分:0)

以下是我如何设法做到的总结:

//parent process
YourString pipeName = format(L"\\\\.\\pipe\\%s", pName);

HANDLE hPipe = CreateNamedPipe(pipeName, /*dwOpenMode*/PIPE_ACCESS_OUTBOUND, 
    /*dwPipeMode*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
    /*nMaxInstances*/PIPE_UNLIMITED_INSTANCES,
    /*nOutBufferSize*/10000, /*nInBufferSize*/10000, /*nDefaultTimeOut*/50, 
    /*lpSecurityAttributes*/NULL);
//[check return value]

PROCESS_INFORMATION pi = {};
STARTUPINFOW si = {};

YourString commandLine = format(L"\"%s\" \"%s\"", childProcessExeFileName, pipeName);

HANDLE hProcess = CreateProcess(
        /*lpApplicationName*/NULL, /*lpCommandLine*/commandLine,
        /*lpProcessAttributes*/NULL, /*lpThreadAttributes*/NULL,
        /*bInheritHandles*/TRUE, /*dwCreationFlags*/CREATE_NEW_CONSOLE,
        /*lpEnvironment*/NULL, /*lpCurrentDirectory*/NULL,
        &si, &pi);
//[check return value]

lpBuffer = ...
nNumberOfBytesToWrite = len(lpBuffer);

WriteFile(hPipe, lpBuffer, nNumberOfBytesToWrite, /*lpNumberOfBytesWritten*/NULL, /*lpOverlapped*/NULL);




//child process
int main(int argc, char ** argv) {

    HANDLE hPipe = CreateFile(argv[1], GENERIC_READ, 0, 
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    //[check return value]

    ULONG PID;
    BOOL ok = GetNamedPipeServerProcessId(hPipe, &PID); 
    //[check return value]

    HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, PID);
    //[check return value]

    char buffer[1000];
    DWORD nByteRead;

    while (WaitForSingleObject(hProcess, 0) == WAIT_TIMEOUT) {

        if (hPipe) {

            ok = ReadFile(hPipe, buffer,
                sizeof(buffer) - 1, &nByteRead, NULL);

            buffer[nByteRead] = 0;

            if (!ok) {
                if (GetLastError() != ERROR_BROKEN_PIPE) ERROR();
                hPipe = NULL;
            }
            else printf("%s", buffer);
        }
        else Sleep(1000);
    }

    return 1;
}

如果您有兴趣,我可以使用简单的语法向您发送一个使用它的类:

WinConsole secondConsole;
secondConsole.Printf("Hello %s\n", "World");

这可以让你拥有任意数量的游戏机。