• Advertisement
Sign in to follow this  

Redirecting console output

This topic is 3229 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
A DLL is loaded at most once per process, regardless of what links to it. Where the problems can arise is the mixing of versions. Using the CRT (C RunTime) as an example:

With static linking, the version of code and data is exclusive to the module (exe/dll). Each module that statically links to the CRT gets it's own copy of things like printf etc. Using stdout (which is really a #define for a function call) calls a different copy of the function in each module and returns a different value.

With dynamic linking, the version of code and data is shareable. Every different module that dynamically links to the CRT uses the same unique copy of the code and data. Using stdout calls the exact same function and returns the same value. The DLL initializes the first time it's referenced, and that's that.

Applying this to your question:

If C is a dll then it gets loaded once irregardless of what A and B are.

If C is a static lib and either A or B are dll's, they'll be two copies of C. The dll's version and the exe's version referenced from the non-dll's static lib. If A and B are both dlls, each will get it's own version of C

If A, B, and C are all static libs then they'll be one copy of each in the executable as that is the only module.

That's probably not the clearest explanation of a topic you've ever read so if you're still having trouble getting your head round it, I'm sure somebody will be able to point you to a more eloquent explanation or point out where I've goofed.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement