【问题标题】:Redirect stdout to an edit control (Win32). Mark II将标准输出重定向到编辑控件 (Win32)。马克二世
【发布时间】:2011-06-30 08:30:03
【问题描述】:

我已经看到一个与此完全相同的问题:Redirect stdout to an edit control (Win32)

但是,给出的解决方案需要程序员实现一个 my_printf 函数来执行 {printf;从管道读取以编辑控件}。我不能这样做,因为我的 printf 在外部库中。

理想情况下,我正在考虑:

  1. 将应用的标准输出重定向到编辑控件
  2. 运行应用,瞧

但如果编辑控件的 API 只允许您向其写入字符串,我会想到类似:

1 - 将标准输出复制到管道输出描述符
3 - 从描述符中的管道读取到缓冲区中
4 - 从缓冲区写入编辑控件

但是,这里缺少第 2 步:

2 - 获得对该管道输出描述符的写入何时完成的信号。

我怎样才能使那部分自动化。我可以在这里使用类似套接字select 的东西吗?

[编辑]

所以,根据 David Heffernan 的 cmets,我会有类似的东西:

  #define MYPRINT      1
  #define WM_MYMESSAGE (WM_USER+1)

  INT_PTR CALLBACK Foo::DialogProc(
    ...
    case WM_COPYDATA:
      {
        PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT) lParam;
        LPCSTR szString = (LPCSTR)(pMyCDS->lpData);
        AppendLog(szString);
      }
      break;
    ...
  }

  /* static */
  void Foo::MainThread()
  {
    // Create worker thread
    DWORD dwThreadId = 0;
    m_hRedirectStdoutThread = CreateThread(
      // default security
      NULL,
      // default stack size
      0,
      // routine to execute
      (LPTHREAD_START_ROUTINE) &CTracesConsole::RedirectStdoutThreadRun,
      // thread parameter
      NULL,
      // immediately run the thread
      0,
      // thread Id
      &dwThreadId);
    if (NULL == m_hRedirectStdoutThread)
    {
      printf("Error creating stdin thread\n");
      return;
    }

    // Loop forever
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  /* static */
  void Foo::RedirectStdoutThreadRun()
  {
    // Redirect stdout to pipe
    int fds[2];
    _pipe(fds, 1024, O_TEXT);
    _dup2(fds[1], 1); // 1 is stdout

    char buffer[1024];
    for (;;)
    {
      // Need to flush the pipe
      _flushall();
      // Read stdout from pipe
      DWORD dwNumberOfBytesRead = 0;
      dwNumberOfBytesRead = _read(fds[0], buffer, 1024 - 1);
      buffer[dwNumberOfBytesRead] = 0;

      // Send data as a message
      COPYDATASTRUCT myCDS;
      myCDS.dwData = MYPRINT;
      myCDS.cbData = dwNumberOfBytesRead + 1;
      myCDS.lpData = buffer;
      PostMessage(g_hWindow,
                  WM_MYMESSAGE,
                  0,
                  (LPARAM)(LPVOID) &myCDS);
    }
  }

其中 AppendLog 将字符串写入编辑控件。

[编辑]

此代码现在可以正常工作。有点不便的是,当我从 libcurl 重定向 stdout 跟踪时,libcurl 停止工作:) 但那是另一个故事......

【问题讨论】:

  • 管道stdout 到您的应用程序。阅读stdin 并将其发送到编辑控件中。工作完成。
  • @David Heffernan - 我的问题的重点是我应该在哪里阅读stdin。我的应用程序确实直接写入文本控件。与这些写入交错,我将从外部库中获得另一个写入stdout。您如何看待让工作线程不断读取stdin 并写入编辑控件?
  • 我会在工作线程中读取标准输入,并在管道为空时让它阻塞。然后,您需要使用 windows 消息将文本发送到主线程中的窗口,以便您遵守 windows 的线程关联。
  • @David Heffernan - 对于块,我可以在描述符中的管道上使用 WaitForSingleObject 吗? windows消息你指的是GetMessage、DispatchMessage等Win API?
  • ReadFile 阻塞,直到有数据要读取。 GetMessage/DispatchMessage 已经存在于您的应用程序中,因为您有一个编辑控件。使用SendMessage 发送消息。

标签: c++ winapi redirect


【解决方案1】:

Windows 支持异步 I/O。这很容易:

  1. 将标准输出复制到管道输出描述符
  2. 将描述符中的管道异步读取到缓冲区中
  3. 等待消息或事件 (MsgWaitForMultipleObjects)。
    • 如果等待以一条或多条消息结束,请致电PeekMessage(PM_REMOVE) 将其删除。
    • 如果管道事件发出信号,则将文本从缓冲区复制到编辑控件。

【讨论】:

  • 我选择了 Mike 的选项,这就是为什么我接受了他的回答。谢谢。
【解决方案2】:

据我所知,您无法通过管道获取“通知”。如果您确实想这样做,也许您应该使用 WM_COPYDATA 代替,这也将提供更简单的解决方案。当文本发布到您的窗口时,您会收到一条消息,然后您可以将其附加到编辑控件。

【讨论】:

  • 是的,我假设他所指的“信号”是 Windows 消息。如果您要使用管道并想要一个 WM,您需要自己生成它
  • 我想 ReadFile 会返回一个错误代码,表明管道已关闭,这将是足够的信号。如果您使用管道,那么我认为不需要 Windows 消息。
  • 我想他也想在他的 WndProc 中处理它,因为最终他需要向 WndProc 发送消息以与编辑控件交互。否则他只会到处传递 HWND
  • 我只追求一个功能,stdout ---> 编辑控件。我考虑过使用管道,我想知道是否可以在写入管道时收到通知。我没有想到其他可能性,因为有一个单独的线程不断地从那个管道中读取。
  • @Mike - 接受这个答案,因为它最接近我正在使用的最终代码。谢谢。
猜你喜欢
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
相关资源
最近更新 更多