Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

STDOUT and a PAR --gui executable

by crabbdean (Pilgrim)
on Apr 12, 2004 at 14:40 UTC ( #344393=perlquestion: print w/ replies, xml ) Need Help??
crabbdean has asked for the wisdom of the Perl Monks concerning the following question:

I've created a program that accepts commandline paramaters at runtime. One of these is to create a log file, another is to set verbose mode so that output is put to STDOUT instead of the logfile. Another flag "--help" outputs help to the STDOUT. 'print' statements are to the filehandle LOGFILE that I duplicate to STDOUT if the verbose flag is set. (see code below).

As a perl .pl this all works fine.

I then compile this script into a PAR archive executable using the --gui option so that there is no console when running the executable (I need it like this because I don't want a console). Now I know that with the --gui option it doesn't create a console, but I thought when running it from a command line you'd still get the output to STDOUT (and I do need this STDOUT functionality)

So I'm guessing two possible causes:
1. PAR --gui suppresses STDOUT completely.
2. OR, I've opened the duplicate filehandle to STDOUT incorrectly (although it does work as a .pl and when simply PAR'ed (without --gui) but not when compiled as PAR --gui

If No. 1 is true, then I need to find out how to suppress the console from a perl EXE and still get STDOUT if run from a command line. Anybody know how to do this or what's going on?
if ($createlog || $logfile) { $verbose = 1; ## if createlog specified but no logfile name given then ## create default logfile name if (!$logfile) { $logfile = "./logs/ZIPsync_$day.log"; ## Make Logs folder eval { mkpath("./logs") }; if (-e $logfile && (time - (stat $logfile)->mtime) > 86400) { + unlink $logfile; open (LOGFILE, ">$logfile") or dying($!); } else { open (LOGFILE, ">>$logfile") or dying($!); } } else { open (LOGFILE, ">$logfile") or dying($!); } } ## output to STDOUT if $verbose mode seleted but no output log if ($verbose && !$createlog && !$logfile) { open (LOGFILE, ">&1") or dying($!); }

Dean
The Funkster of Mirth
Programming these days takes more than a lone avenger with a compiler. - sam
RFC1149: A Standard for the Transmission of IP Datagrams on Avian Carriers

Comment on STDOUT and a PAR --gui executable
Download Code
Re: STDOUT and a PAR --gui executable
by waswas-fng (Curate) on Apr 12, 2004 at 14:44 UTC
    I do not understand, by compiling with par with the -gui flag, you are stating that you don't want a console nor the bind to stdout or stdin or stderr. If you need console output don't compile with -gui. If you don't want the console (and the default in/out/err binds) and need to dump to some log open a log filehandle and do so in your source.


    -Waswas
      I haven't used PAR, but I wonder why it would skip any stdin, stdout, stderr handling when you request a GUI. Having written console and gui apps in C for Windows, I know there's no technical reason a gui can't also use the standard file descriptors.

      --
      [ e d @ h a l l e y . c c ]

        PAR does not magically make your perl app console-less. It does so by doing quite a few things behind the scenes like, close STDIN/STDOUT/STDERR, tells the OS not run the program in console-less mode, and a few other things. PAR is a hack that allows you to virtually "compile" your interpreted script -- it does not do this by actually compiling it, it wraps your script inside a perl interpreter executable.

        For instance if you look at the actual code that accomplishes this below (from PAR), you will see that it goes into the executable and sets bytes to make the application a windows no console exe. This inherently closes off parl's (the exe that is used as the interpreter wrapper) STDIN/STDOUT/STDERR.
        sub _strip_console { my $file = shift; my $preoff = shift || 0; my ($record, $magic, $signature, $offset, $size); open my $exe, "+< $file" or die "Cannot open $file: $!\n"; binmode $exe; seek $exe, $preoff, 0; # read IMAGE_DOS_HEADER structure read $exe, $record, 64; ($magic, $offset) = unpack "Sx58L", $record; die "$file is not an MSDOS executable file.\n" unless $magic == 0x5a4d; # "MZ" # read signature, IMAGE_FILE_HEADER and first WORD of IMAGE_OPTION +AL_HEADER seek $exe, $preoff + $offset, 0; read $exe, $record, 4+20+2; ($signature,$size,$magic) = unpack "Lx16Sx2S", $record; die "PE header not found" unless $signature == 0x4550; # "PE\0\0" die "Optional header is neither in NT32 nor in NT64 format" unless ($size == 224 && $magic == 0x10b) || # IMAGE_NT_OPTIONA +L_HDR32_MAGIC ($size == 240 && $magic == 0x20b); # IMAGE_NT_OPTIONA +L_HDR64_MAGIC # Offset 68 in the IMAGE_OPTIONAL_HEADER(32|64) is the 16 bit subs +ystem code seek $exe, $preoff + $offset+4+20+68, 0; print $exe pack "S", 2; # IMAGE_WINDOWS close $exe; }


        -Waswas
        Really? I just created a simple test application in MS VC++ 6 here, and the fprintf(stderr, ...) statements I put inside WinMain don't seem to do anything at all. (same with stdout)

        In fact, I'm not sure that what the poster is asking about can be done at all, really - when you start a win32 gui application from the command prompt, the command prompt returns to you as soon as the executeable is loaded. I don't think it's possible to have a win32 gui application that interacts with the command window from which it was launched, by windows' design.

        It is of course possible to have a win32 console application that hides its own console window immediately after launching, and to write a console application that detaches from its console window, but both of those will flash a console window onscreen before continuing.

        I'll go check the Microsoft documentation to see if what the poster desires is even possible with windows.


        Update: There's a function that's new in windows XP that'll let you re-attach to the parent console (AttachConsole) however, this still has problems, because your output will be all messed up with the returned command line prompt, and you can't really read from the console in that case.

        But the cause is not helpless! Googling on AttachConsole gave this article which contains a workaround, which I'll post separately.

Re: STDOUT and a PAR --gui executable
by bbfu (Curate) on Apr 12, 2004 at 14:54 UTC

    Easiest way is to leave off the --gui option and manually hide the console window yourself when desired, using Win32::GUI (or similar). Only down side is that the console window will momentarily flash on when the verbose option is not selected.

    ## output to STDOUT if $verbose mode seleted but no output log if ($verbose && !$createlog && !$logfile) { open (LOGFILE, ">&1") or dying($!); } else { use Win32::GUI; my ($DOS) = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); }

    bbfu
    Black flowers blossom
    Fearless on my breath

Re: STDOUT and a PAR --gui executable
by fizbin (Chaplain) on Apr 12, 2004 at 16:26 UTC
    If No. 1 is true, then I need to find out how to suppress the console from a perl EXE and still get STDOUT if run from a command line. Anybody know how to do this or what's going on?

    In general, what you're asking for is not possible with windows, whether in a perl EXE or not. If a windows executeable is marked as a gui executeable, it is given no access to the console when launched from the command line; if it is not marked as a gui application, it is always given a console, creating one if necessary. You can close it right away, but it'll still flash briefly on the screen.

    That being said, there is a function new in Windows XP (and Windows Server 2003) that lets you re-attach to the parent console. But you don't really want to do that, because your output will get messed up with the command prompt, and you still can't do something like pipe your output through more, etc.

    So instead, use the workaround suggested in this article (in the answer to the second question). That is, create two executeables, one as a gui application and one as a console application, and name the console version the same thing as the gui but with the name ending in .com, not .exe. Put the pretty icon on the .exe version. Then, when run from the command line, the .com version will get run (since windows searches for .com before .exe), but when people click things they'll click on the .exe.

    Filling in the rough edges here is left as an exercise for the reader, such as launching the pure-GUI version (or detaching from the console in some other manner) when they don't specify -verbose on the command line, etc. (the article touches on some of that)

    This ugly workaround is what Microsoft does with .Net (mentioned in the article).

Re: STDOUT and a PAR --gui executable
by crabbdean (Pilgrim) on Apr 12, 2004 at 21:12 UTC
    Thanks Nuns and Monks for your help, it lead me down an interesting path ... and to finally a solution! :-)

    The program discussed is a directory synchorniser which will be used for our laptop SOE at work to synchronise thier documents onto the server. I created two versions, one that synchronises directories to a TAR file and another to a ZIP file. Hence my reason for wanting to run it in silent mode, I didn't want the user knowing it was running. In reality I could have lived with a flash of the console to the screen as bbfu suggested in thier solution, but being a perfectionist of sorts I wanted an answer. fizbin's posted article was also very interesting. After testing and pondering the problem for about 2 hours here is what I did.

    I compiled two versions of the program using the commands below. Note the difference in extensions I used on the programs.
    pp --gui -o ZIPsync.exe ZIPsync.pl pp -o ZIPsync.com ZIPsync.pl
    If you then run it at the command line *without* an extension like ZIPsync -v passing it my verbose paramater it outputs STDOUT to the commandline (because it picks up and runs with the ".com" version. Because I ran it from a commandline I already have a console so no problem, and the STDOUT is output. YAY!

    If I go into the directory and double click the "exe" version it runs in --gui mode and hence no console at all. Beautiful!

    But what about calling my EXE with *other* paramaters ? Well I created a shortcut to the EXE and put my paramaters into there. That also ran nicely! Additionally if you try to use the "verbose" paramater it just gets ignored because there is no STDOUT. A user in this case would be forced to specify the "log" paramater to gather output to a file.

    There is one additional thing I came across which I'll try later when I get time. There is a module called Win32::Die which is only about ten lines of code. The description says "Win32::Die detects if your program was double-clicked, or run from a command line, and alters %SIG{__DIE__} appropriately." It would seem to me that its also possible to include similar code into my program and if it detects the program was double clicked to the automatically change the "verbose" paramater to set the "create a logfile" paramater, thereby defaulting my double-clicked EXE to create logs if verbose mode is requested. I'll try that one again later.

    Thanks to all. So it seems its not impossible. There is always more than one way to skin an Operating System! :-)

    Dean
    The Funkster of Mirth
    Programming these days takes more than a lone avenger with a compiler. - sam
    RFC1149: A Standard for the Transmission of IP Datagrams on Avian Carriers

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://344393]
Approved by arden
Front-paged by bart
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (11)
As of 2014-11-24 22:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (147 votes), past polls