From: thierry wilmot Date: 2003-09-12T04:33:44+09:00 Subject: Re: stdout in embedded ruby in win32 First , thanks all for your answers, ruby community is great ! Simon Strandgaard : I try to redicrect $defout, $deferr, it no works better and Ruby interpetor tell me these variables will now be obslete. Zane Dodson : Ok, I think I have here a beginning of answer. I compile my app in debug mode and link it with msvcrt-ruby18.dll compiled in release mode. Dependency walker show me that my app mount msvcrtd.dll and msvcrt.dll for ruby's dll. I try to compile ruby in debug mode, and all seems to work fine. (I not find an easy way to compile ruby dll in debug, so I hack makefile.sub) Nobu Nakada : Yes, when using Ruby static lib you can call all core ruby functions in a more easiest way than in dll mode, but if you wanna use extensions like webrick or drd, you must first found dll/so used by there extensions and link them to your app. That a never ending story ! Sean O'Dell wrote: > nobu.nokada@softhome.net wrote: > >> Hi, >> >> At Thu, 11 Sep 2003 06:09:58 +0900, >> thierry wilmot wrote: >> >>> I have just finished to convert my ruby embedded app from static ruby >>> lib (msvcrt-ruby18-static.lib) to dll, and have some problems with >>> standard stream stdin,stdout,stderr redirection in dll mode. My .exe >>> is not compile in console mode, but in windows mode. >> >> >> >> Link with msvcrt.dll. >> >> >>> a well works code in static lib : >>> >>> freopen("stdout.txt","w+",stdout); >>> >>> Does not work in dll mode, cause some unobvious Windows reasons a dll >>> have it own std streams, and if your freopen() streams in .exe, they >>> will not be redirected in the msvcrt-ruby18.dll >> >> >> >> Due to the specification of Windows DLL. And if you want to >> use extension libraries, you have to use ruby DLL or recompile >> all libraries to import symbols from your .exe. > > > Not sure if this solves your problem Thierry, but here's what I did in > my Windows application to "capture" stdio streams used by the Ruby DLL: > > > > First, in the Ruby .dll, I hacked in these functions: > > > > int rb_w32_redirect_stdin(HANDLE pipe) > { > return dup2(_open_osfhandle((long)pipe, _O_TEXT), 0); > } > > int rb_w32_redirect_stdout(HANDLE pipe) > { > return dup2(_open_osfhandle((long)pipe, _O_TEXT), 1); > } > > int rb_w32_redirect_stderr(HANDLE pipe) > { > return dup2(_open_osfhandle((long)pipe, _O_TEXT), 2); > } > > > > ... and exported them. Then in my application, I call: > > > > // thread that continually grabs Ruby's stdout output > unsigned long __stdcall stdioReadThread(void* parameter) > { > DWORD dwRead; > char chBuf[READ_THREAD_BUFFER_SIZE]; > > for( ;; ) > { > if(!ReadFile(stdioReadHandle, chBuf, READ_THREAD_BUFFER_SIZE - 1, > &dwRead, NULL) || dwRead == 0) > break; > chBuf[dwRead / sizeof(char)] = '\0'; > // DO SOMETHING WITH THE BUFFER HERE > } > > return 0; > } > > > > // create pipe that replaces Ruby's stdout > if(CreatePipe(&stdioReadHandle, &stdioWriteHandle, NULL, 0)) > { > dup2(_open_osfhandle((long)stdioWriteHandle, _O_TEXT), 1); > dup2(_open_osfhandle((long)stdioWriteHandle, _O_TEXT), 2); > > stdioReadThreadHandle = CreateThread(NULL, 0, stdioReadThread, > outputTextBox, 0, &stdioReadThreadID); > } > > > > // then call init, and re-assign Ruby's stdout handle > ruby_init(); > rb_w32_redirect_stdout(GetStdHandle(STD_OUTPUT_HANDLE)); > > > > The read thread will basically "sleep" on the pipe until Ruby sends > output to the stdout handle. When it wakes up, it starts pulling from > the pipe. The example above basically does nothing, but in my > application, I sent the output to a textbox to simulate an output > console. You could modify the read thread to do whatever you want with > the output. > > Hope that helps ... someone ... > > Sean O'Dell >