stdout in embedded ruby in win32

T

thierry wilmot

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.

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

redisrected $stdout, $stderr in ruby code is not enough. I need to catch
all backtrace when exceptions occurs.

any ideas ?
 
S

Simon Strandgaard

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.

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

redisrected $stdout, $stderr in ruby code is not enough. I need to catch
all backtrace when exceptions occurs.

any ideas ?

I once attempted to redirect *all* output from Ruby, but it was on unix.
Things works different on windows. Later $defout and $deferr got added.

Reading your post, it seem like you already have managed to redirect
$stdout and $stderr ? Is this correct ?
If so then you just have to redirect $defout and $deferr, and that should
be it (I guess).
 
Z

Zane Dodson

|
| 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

Hello Thierry,

In my experience, the results you describe above occur when you mix
different C/C++ runtime libraries (which is far too easy to do
accidently IMO).

Take a look at
http://msdn.microsoft.com/library/d...us/sdkintro/sdkintro/mixing_library_types.asp

Best regards,
 
N

nobu.nokada

Hi,

At Thu, 11 Sep 2003 06:09:58 +0900,
thierry said:
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.
 
S

Sean O'Dell

Hi,

At Thu, 11 Sep 2003 06:09:58 +0900,



Link with msvcrt.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
 
T

thierry wilmot

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 !


Hi,

At Thu, 11 Sep 2003 06:09:58 +0900,




Link with msvcrt.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
 
Z

Zane Dodson

On Fri, Sep 12, 2003 at 04:33:44AM +0900, thierry wilmot wrote:
| First , thanks all for your answers, ruby community is great !
|
|<snip>
|
| 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)
|
| <snip>

What you state above is consistent with my experience. You need
everything linked with the same runtime DLL. This means the
executable and all dependent DLLs. As I understand it, Microsoft
has provided 3 different libraries, each in 2 varieties (debug and
non-debug), providing 6 different ways to link the C runtime with an
executable or DLL. If an executable or any of its dependent DLLs is
linked with more than one of these runtime libraries, disaster is
generally the result.

Here is another link you might find helpful on this very confusing
topic.
http://support.microsoft.com/default.aspx?scid=kb;en-us;94248

Best regards,
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top