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:
- redirect app's stdout to edit control
- 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 controlHowever, 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:
- dup'ing stdout to a pipe out descriptor
- Issue async read from pipe in descriptor into a buffer
- 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.
- If the wait ends with one or more messages, call
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.
精彩评论