📜 ⬆️ ⬇️

IPC :: Open3. Solving STDERR problem

When we write a graphical application, it happens that it is necessary to call external programs and read from STDOUT / STDERR.
The IPC :: Open3 module does an excellent job with this.

However, you wrote the program, everything works, but you do not want the user (or you) to see an unnecessary terminal window.

There are several options to hide it:

1. Run the script through wperl.exe, and not through perl.exe
2. ???
')
Consider the program
 use strict;

 use Tkx;
 use IPC :: Open3;

 my $ mw = Tkx :: widget-> new ('.');
 my $ tw = $ mw-> new_text ();

 my $ bt = $ mw-> new_ttk__button (
     -text => 'dir',
     -command => sub {
         my ($ rdr, $ pid);
         $ pid = open3 (undef, $ rdr, undef, 'dir');
         $ tw-> insert ('end', do {local $ /; <$ rdr>});
     },
 );

 Tkx :: pack ($ tw);
 Tkx :: pack ($ bt);

 Tkx :: MainLoop;


image

The dir command is called, and its result is displayed. (do not pay attention to the encoding).

Everything works, but if you run the script through wperl.exe, then when you call open3, you will get an error:
 open3: Can't call method "close" on an undefined value at C: /perl5.8/lib/IPC/Open3.pm line 368.

 open3: Can't call method "close" on an undefined value at C: /perl5.8/lib/IPC/Open3.pm line 368.


The problem is that wperl does not create standard streams (STDIN, STDOUT, STDERR).

I have long puzzled how to make the program work. I tried to call WINAPI inside the body of the program, run it through the bat file (it works, but not with all programs), but the solution turned out to be simple.

You need to use the ShellExecute function from shell32.dll with the SW_HIDE attribute.

Below is the loader code on C.
 #include <stdio.h>
 #include <windows.h>

 static char * ldr_file = "app.pl";
 static char * ldr_path = "";

 int main (int argc, char * argv [])
 {
   int code;
   LoadLibrary ("shell32.dll");
  
   code = (int) ShellExecute (NULL, "open", ldr_file, ldr_path, NULL, SW_HIDE);
   if (code <= 32)
   {
	 char buf [200];
	 sprintf (buf, "Cannot run application. Code:% d", code);
	 MessageBox (
		 Null
		 buf,
		 "Dynld Error",
		 MB_ICONERROR |  MB_OK
	 );
   }

   return code;
 }


Compile gcc from MinGW.
gcc -mwindows loader.c -o loader.exe

Source: https://habr.com/ru/post/67712/


All Articles