Redirect stdout to a buffer

E

Ecir Hana

Hello,

I'm trying to write a simple Win32 app, which may run some Python
scripts. Since it is a Windows GUI app, I would like to redirect all
output (Python print, C printf, fprinf stderr, ...) to a text area
inside the app. In other words, I'm trying to log all the output from
the app (C, Python) to a window. So far, this works for C printf():

int fds[2];
_pipe(fds, 1024, O_TEXT);
_dup2(fds[1], 1);
....
and then I read from pipe's read-end and append the text to the text
area.

But when I try to run:
Py_Initialize();
PyRun_SimpleString("print 'abc'");
Py_Finalize();

I get an error:
IOError: [Errno 9] Bad file descriptor

What am I doing wrong? How to redirect standard IO, both for C and for
Python?
PS: Maybe I'm doind something wrong, but SetStdHandle() does not work
at all....
 
E

Ecir Hana

Hello,

I'm trying to write a simple Win32 app, which may run some Python
scripts. Since it is a Windows GUI app, I would like to redirect all
output (Python print, C printf, fprinf stderr, ...) to a text area
inside the app. In other words, I'm trying to log all the output from
the app (C, Python) to a window. So far, this works for C printf():

int fds[2];
_pipe(fds, 1024, O_TEXT);
_dup2(fds[1], 1);
...
and then I read from pipe's read-end and append the text to the text
area.

But when I try to run:
Py_Initialize();
PyRun_SimpleString("print 'abc'");
Py_Finalize();

I get an error:
IOError: [Errno 9] Bad file descriptor

What am I doing wrong? How to redirect standard IO, both for C and for
Python?
PS: Maybe I'm doind something wrong, but SetStdHandle() does not work
at all....

Also, maybe this matters: it's on WinXP, Python 2.6 and MinGW GCC.
 
G

Gabriel Genellina

I'm trying to write a simple Win32 app, which may run some Python
scripts. Since it is a Windows GUI app, I would like to redirect all
output (Python print, C printf, fprinf stderr, ...) to a text area
inside the app. In other words, I'm trying to log all the output from
the app (C, Python) to a window. So far, this works for C printf():
[...]
PS: Maybe I'm doind something wrong, but SetStdHandle() does not work
at all....

This worked for me:

#include <windows.h>
#include "Python.h"

int main()
{
HANDLE hReadPipe, hWritePipe;
DWORD nr, nw;
char buffer[100];

CreatePipe(
&hReadPipe,
&hWritePipe,
NULL,
1024);
SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe);

Py_Initialize();
PyRun_SimpleString("print 'from Python'");
Py_Finalize();

puts("from C\n");

CloseHandle(hWritePipe);
ReadFile(hReadPipe, buffer, 19, &nr, NULL);
CloseHandle(hReadPipe);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), buffer, nr, &nw, NULL);
}
Also, maybe this matters: it's on WinXP, Python 2.6 and MinGW GCC.

I'm using Visual Studio 2008 Express Edition.
 
E

Ecir Hana

I'm trying to write a simple Win32 app, which may run some Python
scripts. Since it is a Windows GUI app, I would like to redirect all
output (Python print, C printf, fprinf stderr, ...) to a text area
inside the app. In other words, I'm trying to log all the output from
the app (C, Python) to a window. So far, this works for C printf():
[...]
PS: Maybe I'm doind something wrong, but SetStdHandle() does not work
at all....

This worked for me:

#include <windows.h>
#include "Python.h"

int main()
{
   HANDLE hReadPipe, hWritePipe;
   DWORD nr, nw;
   char buffer[100];

   CreatePipe(
     &hReadPipe,
     &hWritePipe,
     NULL,
     1024);
   SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe);

   Py_Initialize();
   PyRun_SimpleString("print 'from Python'");
   Py_Finalize();

   puts("from C\n");

   CloseHandle(hWritePipe);
   ReadFile(hReadPipe, buffer, 19, &nr, NULL);
   CloseHandle(hReadPipe);
   WriteFile(GetStdHandle(STD_ERROR_HANDLE), buffer, nr, &nw, NULL);

}
Also, maybe this matters: it's on WinXP, Python 2.6 and MinGW GCC.

I'm using Visual Studio 2008 Express Edition.

Hi,

thanks for the reply!

However, please, could you tell me how many bytes it read here:

ReadFile(hReadPipe, buffer, 19, &nr, NULL);

because for me, it has read 0. When I run your code, it prints from
both C and Python, but it prints straight to the console, not to the
buffer. Could you also please try to add:

WriteFile(GetStdHandle(STD_ERROR_HANDLE), "----\n", 5, &nw, NULL);

before:

WriteFile(GetStdHandle(STD_ERROR_HANDLE), buffer, nr, &nw, NULL);

Does it print "----" before "from Python" and "from C" for you?
Because for me it comes afterwards (as nr is 0)...
 
G

Gabriel Genellina

I'm trying to write a simple Win32 app, which may run some Python
scripts. Since it is a Windows GUI app, I would like to redirect all
output (Python print, C printf, fprinf stderr, ...) to a text area
inside the app. In other words, I'm trying to log all the output from
the app (C, Python) to a window. So far, this works for C printf():
[...]

thanks for the reply!

Sorry, my earlier code was not working as I expected; I wrongly assumed
the output was being redirected but that was not the case.
The version below ("set paranoid mode on") does redirect printf(),
fwrite(stdout,...), write(1,...), WriteFile(consolehandle,...), all those
calls in C, but fails in Python with IOError: [Errno 9] Bad file
descriptor.
I'm unable to figure out *where* it fails just by reading the Python
source; one should set a breakpoint in python26.dll to see what actually
happens.
However, please, could you tell me how many bytes it read here:

ReadFile(hReadPipe, buffer, 19, &nr, NULL);

The code below now reads from the pipe everything that has been written --
except from Python :(

<code>
#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include "Python.h"

int error(char* lpszText)
{
LPVOID lpMsgBuf;
DWORD lasterror = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lasterror,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
fprintf(stderr,
"%s: error %d: %s",
lpszText, lasterror, lpMsgBuf);
LocalFree(lpMsgBuf);
return 1;
}

int main()
{
HANDLE hReadPipe, hWritePipe;
DWORD nr, nw;
char buffer[100];
int fd, i;
BOOL bResult;

if (!CreatePipe(
&hReadPipe,
&hWritePipe,
NULL,
0))
return error("cannot create pipe");
if (!SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe))
return error("SetStdHandle");

// this was missing in previous version
fd = _open_osfhandle((intptr_t)hWritePipe, _O_TEXT);
if (fd==-1) return error("_open_osfhandle");
if (_dup2(fd, 1)!=0) return error("dup2");

if (!WriteFile(hWritePipe, "WriteFile(pipe)\n", 16, &nr, NULL)) return
error("WriteFile(pipe)");
if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "WriteFile(stdout)\n",
18, &nr, NULL)) return error("WriteFile(stdout)");
fputs("fputs from C\n", stdout);
if (fwrite("fwrite from C\n", 1, 14, stdout)!=14) return
error("fwrite!=14");
if (write(1, "write from C\n", 13)<0) return error("write");
fflush(stdout);

fprintf(stderr, "before Python\n");
Py_Initialize();
PyRun_SimpleString("import sys;sys.stdout.write('from Python\\n')\n");
Py_Finalize();

fprintf(stderr, "before flush 2\n");
fflush(stdout);

fprintf(stderr, "before close pipe w\n");
if (!CloseHandle(hWritePipe)) return error("CloseHandle(hWritePipe)");
fprintf(stderr, "before close STDOUT Handle\n");
if (!CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE))) return
error("CloseHandle(STDOUT)");
fprintf(stderr, "before read pipe\n");
// read one char at a time...
for (i = 0; i<sizeof(buffer); i++) {
bResult = ReadFile(hReadPipe, &buffer, 1, &nr, NULL);
if ((!bResult) || (nr==0))
break;
}
buffer='\0';
fprintf(stderr, "before close pipe r\n");
if (!CloseHandle(hReadPipe)) return error("CloseHandle(hReadPipe)");
fprintf(stderr, "==========\nnread=%d\n%s\n", i, buffer);
return 0;
}
</code>
 
E

Ecir Hana

The code below now reads from the pipe everything that has been written --  
except from Python :(

Thanks a lot for the fine code! So far I don't know why it fails to
print from Python - I'll post here any news I get...
 
E

Ecir Hana

I tried to replace official Python dll with the one built with MinGW
and it works. The problem is, that port is very old and so far it
seems that official support for building Python under MinGW is nowhere
near.

I really don't want to use MSVC, so if there's any other way around
this, please, let me know.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top