如何写入第二个控制台
How do you write to a second console?
我的想法是在我的程序中使用第二个控制台来记录编程活动。我在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 编程经验。
我不太确定您将在代码片段中的单独进程上走向何方。但是,您不能将多个控制台与 Windows 中的单个进程关联,尽管您可以将多个屏幕缓冲区与单个控制台关联并在它们之间切换(请参阅SetConsoleActiveScreenBuffer
并从那里开始),但您必须实现该切换的用户界面;这不是内置的东西。
如果屏幕缓冲区对您不起作用,您可以有第二个记录器进程,您可以通过管道或环回套接字或其他一些 IPC 方法与之通信,例如:
-
您可以使用 syslog,这是各种应用程序和硬件使用的常见日志记录工具。
-
您还可以写入日志文件并使用程序来监视该文件,例如 Windows 相当于
tail -f
。这样做的好处是将记录的数据存储在文件中,以便以后查看。 -
您可以让您的应用程序充当 TCP 服务器,远程登录到它,并通过 telnet 转储日志消息。
请注意,对于上述任何选项,为了方便用户,您可以让应用程序单独启动第二个日志监视进程(只需对ShellExecute
进行简单的调用,不要过分)。
其他选项包括:
-
您可以使用 Windows 事件日志,尽管它可能有点麻烦。
-
您可以创建一个单独的 GUI 窗口,其中包含显示日志消息的文本字段或列表。
-
如果您的程序是一个没有自己的控制台的 GUI 应用程序(从您的描述来看,情况似乎并非如此,但只是为了完整起见),您可以为它创建一个带有
AllocConsole
和朋友的控制台(但请注意,在控制台仍处于连接状态时关闭该控制台也会终止您的应用程序)。
这里有很多选择。但是,您不能为同一进程使用两个控制台。
以下是我如何做到这一点的摘要:
//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 %sn", "World");
这使您可以拥有任意数量的控制台。
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- 等待整个 omp 块完成,然后再调用第二个函数
- 我想在C++中读取一些多个字符,但它永远不会读取第二个字符
- 如何在创建自定义迭代器时获得 std::p air 的第一个和第二个?
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 将第二个 GATT 服务添加到 Movesense 容器
- 如何在 c++ 中根据第二个元素按降序对列表进行排序
- 对的排序向量 (std::vector<pair<int, int>>) 按对的第一个元素搜索并更新第二个元素值
- 比较 2 个向量并从第二个向量中删除在第一个 - c++ 中找不到的元素
- 为什么这个程序没有打印返回的迭代器的正确第二个元素?
- 使第二个类的构造函数成为第一个类中的友元函数
- 为什么第二个代码给出了预期的结果,而第一个代码却没有?
- 为什么第一个代码块产生垃圾值,而第二个代码块将类成员的值相加?
- 打印无序映射的第二个元素,即集合
- 我有一个类,它创建了另一个类的实例.如何将变量通过第一个类传递到第二个类的实例化中?
- 需要使用模板查找数组的第二个最小和最小值
- c++:交换向量中所有元组的第一个和第二个元素
- 如果条件,当我想第二个参数时
- 将内容从第一个文件("constituencies")移动到第二个文件("temp")并在之后重命名时,我的文件被删除
- 如何写入第二个控制台