James Couball wrote:
> Everyone, thank you for the replies.
> 
> Here is what I ended up with for a getppid that works platforms that
> support getppid() and Windows (comments welcome):

Just for comparison, here's a script that compares your OLE version to a
Win32::API version - the API version is a bit longer, but should be much
faster.  I couldn't get either method to fail if parent has exited (or at
least attempted to exit using script at end and uncommenting BEGIN line
below) :

#!perl --

use strict;
use warnings;
use Win32::API;

# make sure we're detached from parent for this test and log ppid to foo
# this next line is attempting to have parent exit before this runs
# BEGIN { open STDOUT, ">>$ENV{TMP}/foo"; binmode STDOUT; $| = 1; sleep 5; }

our ($pt0, $timeit);
BEGIN { $timeit = 1; }  # time the script
BEGIN { if ($timeit) { print scalar (localtime), "\n";
  $pt0 = Win32::GetTickCount (); } }
END { if ($timeit) { print scalar (localtime); my $ticks = Win32::GetTickCount;
  printf " - %.6f sec (%u ticks)\n", ($ticks - $pt0) / 1000, $ticks - $pt0; } }

our %A;                                 # get commandline switches into %A
for (my $ii = 0; $ii < @ARGV; ) {
  if ($ARGV[$ii] =~ /^--$/) { splice @ARGV, $ii, 1; last; }
  if ($ARGV[$ii] !~ /^-{1,2}(.*)$/) { $ii++; next; }
  my $arg = $1; splice @ARGV, $ii, 1;
  if ($arg =~ /^([\w]+)=(.*)$/) { exists ($A{$1}) ? ($A{$1} .= "|$2") :
  ($A{$1} = $2); } else { $A{$1}++; }
}

my $ole = $A{o} || 0;                   # get switches to vars
my $api = $A{a} || 0; $api = 1 if not $ole;

(my $prog = $0) =~ s/^.*[\\\/]//;       # usage printout
my $usage = <<EOD;

Usage: $prog [-a] [-o]
        -a      use Win32::API (default)
        -o      use OLE instead of API

EOD
die $usage if $A{h} or $A{help};

my $CreateToolhelp32Snapshot;           # define API calls
my $Process32First;
my $Process32Next;
my $CloseHandle;

my $ppid;
if ($^O =~ /^MSWin/) {
        if ($ole) {
                $ppid = getppido ();    # use OLE to get it
        } elsif ($api) {
                $ppid = getppida ();    # use Win32::API to get it
        }
} else {
        $ppid = getppid ();
}
printf "OLE=%u, API=%u, pid='%d', ppid='%d'\n", $ole, $api, $$, defined
   $ppid ? $ppid : '<unknown>';
exit;

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

sub getppido {          # OLE version
        require Win32::OLE;
        require Win32::OLE::Variant;

my $machine = "\\\\.";
# WMI Win32_Process class
my $class = "winmgmts:{impersonationLevel=impersonate}$machine\\Root\\cimv2";

my $ppid;
if (my $wmi = Win32::OLE->GetObject($class)) {
        my $pid = $$;
        if (my $proc=$wmi->Get(qq{Win32_Process.Handle="$pid"})) {
                $ppid = $proc->{ParentProcessId} if
                  ($proc->{ParentProcessId}!=0);
        }
}
return $ppid;

}

#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

sub getppida {          # Win32::API version

if (not defined $CreateToolhelp32Snapshot) {
        $CreateToolhelp32Snapshot = new Win32::API ('kernel32',
          'CreateToolhelp32Snapshot', 'II', 'N') or
          die "import CreateToolhelp32Snapshot: $!($^E)";
        $Process32First = new Win32::API ('kernel32', 'Process32First',
          'IP', 'N') or die "import Process32First: $!($^E)";
        $Process32Next = new Win32::API ('kernel32', 'Process32Next', 'IP',
          'N') or die "import Process32Next: $!($^E)";
        $CloseHandle = new Win32::API ('kernel32', 'CloseHandle', 'I', 'N')
          or die "import CloseHandle: $!($^E)";
}

use constant TH32CS_SNAPPROCESS => 0x00000002;
use constant INVALID_HANDLE_VALUE => -1;
use constant MAX_PATH => 260;

# Take a snapshot of all processes in the system.

my $hProcessSnap = $CreateToolhelp32Snapshot->Call(TH32CS_SNAPPROCESS, 0);
die "CreateToolhelp32Snapshot: $!($^E)" if $hProcessSnap ==
   INVALID_HANDLE_VALUE;

#       Struct PROCESSENTRY32:
#       DWORD dwSize;                   #  0 for 4
#       DWORD cntUsage;                 #  4 for 4
#       DWORD th32ProcessID;            #  8 for 4
#       DWORD th32DefaultHeapID;        # 12 for 4
#       DWORD th32ModuleID;             # 16 for 4
#       DWORD cntThreads;               # 20 for 4
#       DWORD th32ParentProcessID;      # 24 for 4
#       LONG  pcPriClassBase;           # 28 for 4
#       DWORD dwFlags;                  # 32 for 4
#       char szExeFile[MAX_PATH];       # 36 for 260

# Set the size of the structure before using it.

my $dwSize = MAX_PATH + 36;
my $pe32 = pack 'I9C260', $dwSize, 0 x 8, '0' x MAX_PATH;
my $lppe32 = pack 'P', $pe32;

# Retrieve information about the first process, and exit if unsuccessful

my $ret = $Process32First->Call($hProcessSnap, $pe32);
do {
        if (not $ret) {
                $CloseHandle->Call($hProcessSnap);
                warn "Process32First: ret=$ret, $!($^E)";
                return undef;
        }

        # return ppid if pid == my pid

        my $th32ProcessID = unpack 'I', substr $pe32, 8, 4;
        return unpack ('I', substr $pe32, 24, 4) if $$ == $th32ProcessID;

} while ($Process32Next->Call($hProcessSnap, $pe32));

$CloseHandle->Call($hProcessSnap);
return undef;

}

__END__


Detached script starter - I start like this from tcsh :

perl detach.pl 'f:/perl/bin/perl.exe' 'getppid.pl -o'
perl detach.pl 'f:/perl/bin/perl.exe' 'getppid.pl -a'

#!perl --

use strict;
use warnings;
use Win32::Process;

print qq{pid=$$, Win32::Process::Create(\$pObj, "$ARGV[0]", "@ARGV", 0, },
   DETACHED_PROCESS, qq{, '.'\n};

my $pObj;
Win32::Process::Create($pObj, $ARGV[0], "@ARGV", 0, DETACHED_PROCESS, ".") or
   die "Win32::Process::Create: $!($^E)";

my $cpid = $pObj->GetProcessID();
print "child pid=$cpid started - $$ exiting\n";

exit;           # don't wait for child
_______________________________________________
ActivePerl mailing list
ActivePerl@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to