开发者

Redirect stdout to an edit control (Win32). Mark II

I've seen a question exactly like this already exists: Redirect stdout to an edit control (Win32)

However, the solution given requires the programmer to implement a my_printf function that does a {printf; read from pipe to edit control}. I cannot do that because my printf's are in a external library.

Ideally, I'm thinking of:

  1. redirect app's stdout to edit control
  2. run app and voila

But if edit control's API only allows you to write a string to it, I开发者_如何学Go would think of something like:

1 - dup'ing stdout to a pipe out descriptor

3 - read from pipe in descriptor into a buffer

4 - write from buffer to edit control

However, there is a missing step 2 there:

2 - getting a signal of when a write to that pipe out descriptor is done.

How could I automate that part. Could I use something like a socket select here?

[EDIT]

So, according to David Heffernan's comments, I would have something like:

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

Where AppendLog writes a string to the edit control.

[EDIT]

This code works properly now. With the little inconvenience that, when I redirect stdout traces from libcurl, libcurl stops working :) But that's another story...


Windows supports asynchronous I/O. That makes it easy:

  1. dup'ing stdout to a pipe out descriptor
  2. Issue async read from pipe in descriptor into a buffer
  3. Wait for message or event (MsgWaitForMultipleObjects).
    • If the wait ends with one or more messages, call PeekMessage(PM_REMOVE) to remove them.
    • If the pipe event is signalled, copy text from buffer to edit control.


As far as I'm aware you can't get 'notifications' with a pipe. If you do want to do that maybe you should use WM_COPYDATA instead which would also provide a simpler solution. You will get a message when text is posted to your window which you can then append to the edit control.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜