Redirecting console output

Started by
9 comments, last by adeyblue 15 years ago
Hello, As the title says I'm trying to redirect console output under Windows. I've embedded Lua in my application and now I want to redirect output from the lua script to a TextBox. I couldn't find much on the internet except someone mentioning creating a pipe and then using SetStdHandle to redirect output to this pipe and then using ReadFile on this pipe to get the output but that doesn't seem to work. The text still gets sent to the console and causing ReadFile to block my application:
HANDLE rd,wr;
if (!CreatePipe(&rd,&wr,NULL,0))
	cout << "Error creating pipe.\n";
HANDLE old=GetStdHandle(STD_OUTPUT_HANDLE);
if (!SetStdHandle(STD_OUTPUT_HANDLE,wr))
	cout << "Error setting std handle.\n";
std::cout << "yo!";	
char buf[100];
while (true)
{
	DWORD readBytes=0;
	if (!ReadFile(rd,buf,1,&readBytes,0))
		break;
	if (readBytes>0)
	{			
		string str;
		for (DWORD i=0;i<readBytes;i++)
			str+=buf;
		MessageBoxA(0,str.c_str(),"",0);
	}
	else
		break;
}
SetStdHandle(STD_OUTPUT_HANDLE,old);

Any suggestions/snippets of code/links are welcomed.
Advertisement
Here are a few links, maybe you'll find something in them that helps.

google:gamedev.net:freopen

How to spawn console processes with redirected standard handles
Redirecting an arbitrary Console's Input/Output
Capturing Console Output
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Thanks but these examples use the same code of spawning a new process(from another executable) and capturing its IO by setting the new handlers in its creation parameters. What I'm trying to do is redirect the console IO for the current process. I've found some code and was able to get it working but when I switched to a non console application it stopped working. I hope what I'm trying to achieve here is possible cause I haven't seen any solution to this yet.
I modified this thread's solution for generating a console in a Win32 application.

#include <windows.h>#include <stdio.h>#include <iostream>#include <string>#include <io.h>#include <fcntl.h>void RedirectConsole(HANDLE hPipe){	int hConHandle = 0;	HANDLE lStdHandle = 0;	FILE *fp = 0 ;	// redirect unbuffered STDOUT to the Pipe	lStdHandle = hPipe;	hConHandle = _open_osfhandle(PtrToUlong(lStdHandle), _O_TEXT);	fp = _fdopen(hConHandle, "w");	*stdout = *fp;	setvbuf(stdout, NULL, _IONBF, 0);}int main(int argc, char * argv[]){	HANDLE rd,wr;	if (!CreatePipe(&rd,&wr,NULL,0))		std::cout << "Error creating pipe.\n";	RedirectConsole(wr);	std::cout << "cout\n";	printf("printf\n");	char buf[100];	while (true)	{		DWORD readBytes=0;		if (!ReadFile(rd, buf, 99, &readBytes, 0))			break;		buf[99] = 0;		if (readBytes>0)		{						std::string str;			for (DWORD i=0;i<readBytes;i++)				str+=buf;			MessageBoxA(0,str.c_str(),"",0);		}		else			break;	}}


For the sake of not making you click through a dozen MessageBox's either, I changed the read to the max buffer size rather than one at a time [wink]
Thanks it works. Using cout and printf works like a charm but still I can't capture output from a Lua script. If I replace the printf to be luaL_dostring(luaState,"print(\"test\")") there is no messagebox. Also I've tested running my application from the command prompt with > 1.txt and the text file is filled with the correct output so the print command in lua outputs to stdout.

[Edited by - CableGuy on April 18, 2009 4:05:34 PM]
Quote:Original post by CableGuy
Thanks it works. Using cout and printf works like a charm but still I can't capture output from a Lua script. If I replace the printf to be luaL_dostring(luaState,"print(\"test\")") there is no messagebox.


I think you have a problem in your code. I made a simple Lua test and it works fine for me.

#include <windows.h>#include <io.h>#include <fcntl.h>#include <string>#include <iostream>extern "C"{	#include "lua/lua.h"	#include "lua/lualib.h"	#include "lua/lauxlib.h"}void RedirectConsole(HANDLE hPipe){	int hConHandle = 0;	HANDLE lStdHandle = 0;	FILE *fp = 0 ;	// redirect unbuffered STDOUT to the console	lStdHandle = hPipe;	hConHandle = _open_osfhandle(PtrToUlong(lStdHandle), _O_TEXT);	fp = _fdopen(hConHandle, "w");	*stdout = *fp;	setvbuf(stdout, NULL, _IONBF, 0);}int main(int argc, char** argv){	lua_State * L = lua_open();	luaL_openlibs(L);	HANDLE rd,wr;	if (!CreatePipe(&rd,&wr,NULL,0))		std::cout << "Error creating pipe.\n";	RedirectConsole(wr);		luaL_dostring(L, "print(\"test\")");	char buf[100];	while (true)	{		DWORD readBytes=0;		if (!ReadFile(rd, buf, 99, &readBytes, 0))			break;		buf[99] = 0;		if (readBytes>0)		{						std::string str;			for (DWORD i=0;i<readBytes;i++)				str+=buf;			MessageBoxA(0,str.c_str(),"",0);			break;		}		else			break;	}	lua_close(L);	return EXIT_SUCCESS;}


Does your Lua state have I/O functions enabled for it? That's the only thing off the top of my head right now.
Weird your code doesn't work for me...

EDIT: For some weird reason if I use Lua as a DLL it doesn't work but if I use it as a static lib it works...

[Edited by - CableGuy on April 18, 2009 5:29:03 PM]
Quote:Original post by CableGuy
Weird your code doesn't work for me...

EDIT: For some weird reason if I use Lua as a DLL it doesn't work but if I use it as a static lib it works...


Really weird. I'm using Lua via a static Library, not a DLL. I've got version: lua5_1_4_Win32_vc8_lib.

Attached is a complete project with my Lua version for you to try. Although if you have set Visual Studio settings to pull from specific folders via Tools menu, you will want to change that first so it does not use your .lib files and instead uses mine.

Download: CableGuy
Quote:Original post by CableGuy
Weird your code doesn't work for me...

EDIT: For some weird reason if I use Lua as a DLL it doesn't work but if I use it as a static lib it works...


If you app and the lua dll aren't linked to the same dll version of the CRT (Project Properties->C/C++->Code Generation->Runtime Library->Multi-Threaded (Debug) DLL) then they'll each have a different stdout "file". Any changes you make to it in your code, like using the RedirectConsole function, will only affect your copy.

Oh and
Quote:
void RedirectConsole(HANDLE hPipe)
{
..
// redirect unbuffered STDOUT to the Pipe
lStdHandle = hPipe;
// PtrToUlong chops the handle in half on 64-bit windows
hConHandle = _open_osfhandle(reinterpret_cast<intptr_t>(lStdHandle), _O_TEXT);
}


The stdout assignment also leaks everything to do with the original, but I'm not sure if doing fclose(stdout); before the assignment is kosher.
Thank you both got it working now, using a static lib.
@adeyblue: A bit off topic: So lets say I have three dlls : A,B,C. A and B are both linked against C. When I have an executable that links against A,B only one instance of C is mapped to it?

This topic is closed to new replies.

Advertisement