Using node in a Win32 GUI Application fails (stdin/stderr/stdout)

73 views
Skip to first unread message

Trevor Linton

unread,
Nov 29, 2014, 5:10:56 PM11/29/14
to nod...@googlegroups.com
Hello,

I'm using (and have tried both) node 0.10.3x and 0.11.x (and the node bleeding edge) and have an issue i'm hoping someone can shed some light on.  

I'm embedding node into a Win32 GUI app (that is to say /Subsystem:Windows and wWinMain, rather than the default /subsystem:console).  Windows applications do not setup a proper stderr, stdin, stdout handles.  When node::Load() attempts to run, the application exits with either code 1 (for node 0.11) or code 8 (for node 0.10).

I've traced the problem down. 
  • It starts with libuv win/handle.c in the function uv_guess_handle (line 56) that returns a FILE_TYPE_UNKNOWN for the file descriptor 1 or 2 (stdout, or stderr) if the subsystem is compiled as "Windows". 
  • This is called when node::Load runs, specifically in, src/node.js the function createWritableStdioStream (line 483)
  • The createWritableStdioStream causes an error to be thrown thats caught by node.cc (line 2182) 
  • The FatalException exits the application, since we're in a windows GUI application, we don't see this, as its printed to stderr.. which doesn't exist (making it incredibly difficult to track down).
  • Other related files that are used in the stack trace, but does not seem relevant: tty_wrap (line 89) 
I've tried a few solutions but to no success.

  1. Create a Windows console buffer when acting like a GUI app, this allows you to capture stdin/stdout for application running as a GUI. Unfortunately since lib win/handle.c (line 56) uses the low-level file descriptor and not the stdin/stdout stream, this has no effect as the console buffer simply replaced the stdin/stdout global streams, not the 0 & 1 FD descriptors.
  2. Tried redirecting stdin, stdout, stderr using named pipes with CreateNamedPipe.  This also had no effect for the same reason as #1.
  3. Tried reopening the stream to re-assign them, this, no effect, see above. 
  4. Looked into hiding the console window and just compiling with /subsystem:console, however this causes a "flicker" when the app loads, but does successfully fix the issue.
  5. Tried using AttachConsole to a "faked" child processes' console, the child process is a dummy process that is created with CreateProcess with the console attribute hidden. This "sort of" worked, but caused halting problems as the stdout/stdin are themselves unable to create a stream buffer for some reason.
  6. Tried simply closing or opening the low-level fd stdout/stderr; however this had no effect and threw assertion errors from Windows.

About to give up, I thought that SOMEONE, SOMEWHERE must have fixed this issue.  I looked at applications that use node in a GUI app, and found two solutions:

  1. Node-webkit modifies node.js to create dummy handles for stdio if its on win32.  This isn't optimal, as i'd like to be able to only force the dummy handles for stdin/stdout/stderr if there really isn't a console available.
  2. Atom and others seem to take the approach of second process launches, which creates a second process (of themselves) the first launched with a subsystem:windows, then relaunched with STARTUPINFO on CreateProcess set to hide the console (but launched as a console application).  This isn't an optimal solution either, as I stated in #5 above, there are corner cases where the system cannot create a std stream but can deliver a valid file descriptor for the stream (it causes assertion errors in windows __open_oshandle, unsure why)  Although it does seem to work for 95% of the use cases i've seen. 
For obvious reason (e.g., when running as a GUI) I do not have any use for standard in/outs, the optimal fix would be to create dummy stream handles on node::Load() for these instances (similar to node-webkit) but allow it to be a configurable option and not-by-default.  

TL;DR: Node fails with no workaround if it can't find stdin/stdout, like in a GUI app. 

My first question: Does anyone know of another alternate way of getting this to work that I haven't tried? I'd rather not submit a patch nor modify the node code as its upstream?
My second question: If I submit a patch for node to help alleviate these issues, would creating dummy stdin/stdout/stderr be the best solution, is there alternate approaches recommended if I need to modify node?

Thanks,
Trevor Linton
Reply all
Reply to author
Forward
0 new messages