Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked


by Yary (Pilgrim)
on Nov 28, 2012 at 22:39 UTC ( #1006121=perlquestion: print w/replies, xml ) Need Help??
Yary has asked for the wisdom of the Perl Monks concerning the following question:

Howdy peeps, this was originally going to be a private email to module author tye, but alas the address in my copy of Win32API::File is outdated. And perhaps the wider Perl community can help/learn from this.

I have used Win32API::File to get out of a few tight spots in the last couple years. Alas I have now gotten into a spot that it should help me with, but I am coming up short. I'm unable to set the HANDLE_FLAG_PROTECT_FROM_CLOSE flag and I'm not sure if it is a problem with the module, or with my environment.

Here's sample code:

#!perl -w use strict; use Win32API::File qw(:Func :HANDLE_FLAG_); open my $fh,">&2"; my $os_handle=GetOsFHandle($fh) or die "Can't GetOSFHandle: $^E,\nstop +ped"; GetHandleInformation($os_handle, my $flags); print "flags was=$flags\n"; print "HANDLE_FLAG_PROTECT_FROM_CLOSE=",HANDLE_FLAG_PROTECT_FROM_CLOSE +,"\n"; $flags |= HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE; print "Trying for flags=$flags\n"; SetHandleInformation($os_handle, $flags, $flags) or die "Can't SetHandleInformation: $^E,\nstopped"; GetHandleInformation($os_handle, my $newflags); print "flags now=$newflags\n";
That prints
flags was=1
Trying for flags=3
flags now=1
It's the last line "flags now=1" that indicates to me that SetHandleInformation isn't actually setting "HANDLE_FLAG_PROTECT_FROM_CLOSE"
perl -v
This is perl 5, version 14, subversion 2 (v5.14.2) built for
(with 1 registered patch, see perl -V for more detail)
Any ideas?

Replies are listed 'Best First'.
Re: Win32API::File not setting HANDLE_FLAG_PROTECT_FROM_CLOSE (sources)
by tye (Sage) on Nov 29, 2012 at 04:10 UTC
    Howdy peeps, this was originally going to be a private email to module author tye

    I would've just replied to tell you to post it someplace like here. I hate the relative waste of my time in answering a question in a way that it can only ever benefit a single person. And it is ludicrous to assume that I am the only person on Earth capable and willing to (partially) answer a question about a module that I had a hand in writing. (:

    As to your question, your original code reacts like this for me:

    flags was=1 HANDLE_FLAG_PROTECT_FROM_CLOSE=2 Trying for flags=3 Can't SetHandleInformation: The parameter is incorrect, stopped at line 14.

    With minor changes, I can get it to act like it did for you (no complaint but doesn't change anything) or to act like one would expect.

    For me, saying that I want to "change" the HANDLE_FLAG_INHERIT value from 1 to 1 (along with changing _PROTECT_FROM_CLOSE from 0 to 1) for one of the STD* handles or a dup(1) of one of them causes the "The parameter is incorrect" error. (This is what your original code does.) Kind of a silly response, sure. But I'd bet money that this is just an undocumented (as near as I can tell) and "varies between versions" behavior of the underlying Windows SetHandleInformation() call.

    If I don't specify that I want to "change" the HANDLE_FLAG_INHERIT value (pass in a second argument of 2, not 3) but still use one of the STD* handles (or a dup), then I get the "no complaint but no change" behavior.

    If I add an __END__ line and pass in \*DATA to GetOsFHandle() so that I get back a handle to the Perl script (which is an ordinary file), then the flags get updated as desired.

    You'll have to find somebody with more knowledge of obscure particulars of the Windows SetHandleInformation() call if you want more than somewhat wild guesses as to why.

    I can certainly see it being unsupported to turn off the INHERIT flag on a STD* handle. It seems reasonable to imagine an unfortunate implementation choice that made it illegal to even just try to "keep it on".

    I don't have a good guess as to why one isn't permitted to make a STD* handle immune from being closed nor why that prohibition should be silent. It seems even harder to justify such for a dup(1) of a STD* handle. Perhaps this particular impotence applies to all "console" handles? Not that I can think of any guesses as to why that would be.

    But maybe somebody here knows more about Windows or can make better guesses or can find better documentation. Or you might have to shop your question to a different audience.

    I'm even curious to know why a flag like _PROTECT_FROM_CLOSE was created in the first place. :)

    - tye        

      I'm even curious to know why a flag like _PROTECT_FROM_CLOSE was created in the first place. :)
      Sometimes two processes need to communicate via file descriptors and std* is not enough- Unix example I know of is UCSPI (ooks-pie) UNIX Client-Server Program Interface which qmail uses. In a case like that, you need to keep non-STD* filehandles from closing when you exec a new process, otherwise the child tries using FD 3 (or FDs 6 and 7, etc) and finds it is closed.

      Unix has no problem with this, it uses fcntl($fh, F_SETFD, ~FD_CLOEXEC) and all is well. But those POSIX macros are not implemented in Win32-land, at least not in ActiveState's Perl. Hence my desire to try _PROTECT_FROM_CLOSE on FD 3.

      I was all over the web looking for insight, tried other tricks like setting $^F=3 (never even glanced at that perlvar before) but no luck. The best I found was a terse comment that said "Can't be done. OS limitation." which gave me the courage to give up!

      Thanks for looking into it, and confirming that I'm not alone.

      Here is my original goal, which seems to be elusive to many on the web: have a program write to stdout, stderr, and some 3rd stream. In Unix it would be invoked like "MyProg >stdout.log 2>stderr.log 3>extra_data.log". Windows cmd.exe shell allows FD's 3-9 in redirects but it doesn't pass them to any programs it spawns, they seem to be just for dup'ing 0,1,2 on the command line.

      My idea was to write a wrapper in perl that would allow communicating with a sub-program using those higher-number, user-defined file descriptors in Win32.

        Ah, thanks. _PROTECT_FROM_CLOSE does a lot more than that ("If this flag is set, calling the CloseHandle function will not close the object handle"). But if 'exec' doesn't have its own flag for "don't close upon exec", I could see implementing it this way (and can see some problems that such a choice presents).

        I was conflating the "don't close when creating a subprocess" with the "don't close when exec()ing cases". But then, Windows doesn't have fork() nor exec() so there really is only the "don't close when creating a subprocess", which is what _INHERIT is for. (Perl's exec on (non-Cygwin) Windows actually creates a subprocess and then has the parent process exit.)

        Perhaps you should be setting _INHERIT instead?

        Also, your code doesn't appear useful for the use-case you proposed. You don't want some "Console" handle for talking over some protocol, surely. So write some code that creates a pipe or uses a socket and then try to give that file descriptor to the child (probably using _INHERIT not _PROTECT_FROM_CLOSE, I would bet) and see how that works.

        Indeed, the point of including SetHandleInformation() in Win32API::File was exactly for the purpose of letting other programs use handles that your Perl script opened. I think how I've done that successfully in the past was via _INHERIT, but, to be honest, I'm not completely sure at the moment.

        Please let us know how it works out.

        - tye        

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1006121]
Approved by Gangabass
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (8)
As of 2018-06-20 21:14 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (117 votes). Check out past polls.