ActiveState Community

PerlApp, Windows 7, and Piped Filehandles

Posted by phantomsea2005 on 2009-08-28 15:15
OS: Windows

I'm having an issue that I'm almost certain is a problem with PerlApp.

I have a Tk GUI application compiled with PerlApp (with the option to hide the console enabled). I have another application that is text-based and compiled with PerlApp (also with the option to hide the console enabled). The two applications work together ... The Tk GUI app starts the text-based app and uses a pipe on the filehandle to redirect the text-based app's output to the GUI app.

Example:

open(APP, 'C:\Apps\Text-Based.exe |');
while(my $line_data = )
{
do_something($line_data);
}

Under Windows 2000, XP, and Vista, this behaves just as expected ... the GUI starts the text app, and the text app's output is directed to the GUI app via the filehandle ('APP' in the above example).

Under Windows 7, this does NOT work. The GUI starts the text-based app, and no output from the text app is sent to the GUI. HOWEVER, if I compile the GUI app without enabling the "hide console" option, it does work. The down-side to that is I get an unwanted console window in addition to the GUI window.

So, since the problem can SORT OF be solved by using different settings in the PerlApp compiler, I'm figuring this is a PerlApp problem that only shows up under Windows 7. Any advice? Thank you!

If I've not explained anything above clearly enough, or if you need more info to help me out, just let me know and I'll elaborate.

phantomsea2005 | Sun, 2009-08-30 13:17

After quite a bit of searching, I found an article on PerlMonks that explains how to disable the console window using Win32::API (and WITHOUT using PerlApp's "hide console" feature). It works!!! OK, so the console does show up for a second before it disappears, but that's liveable.

Article is here: http://www.perlmonks.org/?node_id=536265

And here's the code to make it happen:

use Win32::API 0.20;

# just for completeness...
use constant SW_HIDE => 0;
use constant SW_SHOWNORMAL => 1;

# the API we need
my $GetConsoleTitle = new Win32::API('kernel32', 'GetConsoleTitle', 'PN', 'N');
my $SetConsoleTitle = new Win32::API('kernel32', 'SetConsoleTitle', 'P', 'N');
my $FindWindow = new Win32::API('user32', 'FindWindow', 'PP', 'N');
my $ShowWindow = new Win32::API('user32', 'ShowWindow', 'NN', 'N');

# save the current console title
my $old_title = " " x 1024;
$GetConsoleTitle->Call( $old_title, 1024 );

# build up a new (fake) title
my $title = "PERL-$$-".Win32::GetTickCount();

# sets our string as the console title
$SetConsoleTitle->Call( $title );

# sleep 40 milliseconds to let Windows rename the window
Win32::Sleep(40);

# find the window by title
$hw = $FindWindow->Call( 0, $title );

# restore the old title
$SetConsoleTitle->Call( $old_title );

# hide the console!
$ShowWindow->Call( $hw, SW_HIDE );

santeri.isv | Sun, 2009-08-30 13:00

hey man. For this purposes i use an loader written on c

#include 
#include 

static char *ldr_file = "buildedapp.exe";
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;
}

phantomsea2005 | Sun, 2009-08-30 13:44

Okay, my C is a little rusty, but I see what you are doing.

So you compile the loader alone as an EXE and use it to invoke the PerlApp app? That's an interesting solution, but that means another file has to be included, right?

Thanks for the feedback!

In the meantime, I took the Win32::API code, stuck it in a module (Win32::HideConsole), and sumbitted it to CPAN. You can find it here: http://search.cpan.org/~phatwares/Win32-HideConsole-1.00/lib/Win32/HideC...