----- Original Message ----- 
From: "Rod Butcher"

> Also, perl itself always crashes after exactly 13 calls to Process32Next
> (probably on the 14th call). Plenty of RAM available, it has not
> returned code 18 to indicate no more processes (anyway, there are +- 50
> running).

Be aware that it's not Process32Next() that will return 18, but
GetLastError() -  or $^E, which is essentially the same as GetLastError().

The MS docs say that GetLastError/$^E will return 18 if "no processes exist
or the snapshot does not contain process information". In that case I would
think that Process32Next() would have returned FALSE.

You may already know it , and it may have no bearing on your problem anyway,
but I thought I should clear it up just in case ... :-)

I'm also a little puzzled as to why we're doing:

$PE32 = pack 'LLLLLLLLLZ', $hProcessSnap, 0, 0, 0, 0, 0, 0, 0, 0, ' ' x 259
. "\0";

I gather that packs the PROCESSENTRY32 struct, but the first parameter
should be sizeof(PROCESSENTRY32), not $hProcessSnap.
Since sizeof(PROCESSENTRY32) == 296, shouldn't that line of code be replaced
by:

$PE32 = pack 'LLLLLLLLLZ', 296, 0, 0, 0, 0, 0, 0, 0, 0, ' ' x 259 . "\0";

I second Bill's suggestion that you provide a complete script so that we can
all be "on the same page".

Below my sig is a sample C script that I found in my MSDN docs. Not sure if
it helps.
It passes TH32CS_SNAPPROCESS (== 2) as the first argument to
CreateToolhelp32Snapshot(). So I tried the same in a perl script - which
seems to avoid the segfault you reported (which I also got with
TH32CS_SNAPTHREAD), but it only prints out the first letter of the
executable's name - ie 'p' for 'perl.exe', 'n' for 'notepad.exe', etc. A bit
more work needed on the packing/unpacking, methinks.

For the record, here's the perl script I was running - using Win32::API and
passing TH32CS_SNAPPROCESS :

####################################
use Win32::API;
use warnings;
use Data::Dumper;


Win32::API->Import('kernel32',
  'HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)')
  or die "import CreateToolhelp32Snapshot: $!($^E)";

use constant TH32CS_SNAPPROCESS => 0x2;
my $hProcessSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
die "CreateToolhelp32Snapshot: $!($^E)" if $hProcessSnap == -1;
print Data::Dumper->Dump([$hProcessSnap], [qw($hProcessSnap)]);

$PE32 = pack 'LLLLLLLLLZ', 296, 0, 0, 0, 0, 0, 0, 0, 0, ' ' x 259 . "\0";
Win32::API->Import('kernel32', 'Process32First', 'IP', 'I') or
  die "import Process32First: $!($^E)";

Win32::API->Import('kernel32', 'Process32Next', 'IP', 'I') or
  die "import Process32Next: $!($^E)";

my $ret = Process32First ($hProcessSnap, $PE32) or
  die "Process32First: $! $(^E)";

my @PE32 = unpack 'LLLLLLLLLZ', $PE32;
print Data::Dumper->Dump([EMAIL PROTECTED], [qw([EMAIL PROTECTED])]);

my $i = 0;

while($ret) {
     $PE32 = pack 'LLLLLLLLLZ', 296, 0, 0, 0, 0, 0, 0, 0, 0, ' ' x 259 .
"\0";
     $ret = Process32Next ($hProcessSnap, $PE32) or
       die "Process32Next: $! $(^E)";

     my @PE32 = unpack 'LLLLLLLLLZ', $PE32;
     print Data::Dumper->Dump([EMAIL PROTECTED], [qw([EMAIL PROTECTED])]);
}
__END__
####################################

I've also written a perl script using Inline::C.(It seems to get the
"szExeFile" part correct - and, for the rest, produces essentially the same
as the above Win32::API script.) For the record, here it is:

####################################
use warnings;

use constant INVALID_HANDLE_VALUE => 4294967295;
use constant TH32CS_INHERIT => 2147483648;
use constant TH32CS_SNAPALL => 15;
use constant TH32CS_SNAPHEAPLIST => 1;
use constant TH32CS_SNAPMODULE => 8;
use constant TH32CS_SNAPPROCESS => 2;
use constant TH32CS_SNAPTHREAD => 4;
use constant ERROR_NO_MORE_FILES => 18;

use Inline C => Config =>
    BUILD_NOISY => 1, # So we see any compiler warnings
    LIBS => '-lkernel32';

use Inline C => <<'EOC';

#include <windows.h>
#include <tlhelp32.h>

void print_constants() {
     printf("%u\n%u\n%u\n%u\n%u\n%u\n%u\n%u\n",
            INVALID_HANDLE_VALUE, TH32CS_INHERIT,
            TH32CS_SNAPALL, TH32CS_SNAPHEAPLIST,
            TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS,
            TH32CS_SNAPTHREAD, ERROR_NO_MORE_FILES);
}

void print_sizeof_struct() {
     printf("%u\n", sizeof(PROCESSENTRY32));
}

SV * wrap_CreateToolhelp32Snapshot(SV * flags, SV * pid) {
     HANDLE WINAPI hnd;
     hnd = CreateToolhelp32Snapshot((unsigned long) SvUV(flags), (unsigned
long)SvUV(pid));
     if(hnd == INVALID_HANDLE_VALUE)
       croak("CreateToolhelp32Snapshot() returned an INVALID_HANDLE_VALUE");
     return newSVuv((unsigned long)hnd);
}

SV * wrap_Process32Next(SV * handle) {
     PROCESSENTRY32 x;
     BOOL WINAPI ret;

     x.dwSize = sizeof(PROCESSENTRY32);

     ret = Process32Next((HANDLE)SvUV(handle), &x);

     if(ret) {
       printf("%u\n%u\n%u\n%u\n%u\n%u\n%u\n%u\n%u\n%s\n",
       x.dwSize, x.cntUsage, x.th32ProcessID, x.th32DefaultHeapID,
       x.th32ModuleID, x.cntThreads, x.th32ParentProcessID,
       x.pcPriClassBase, x.dwFlags, x.szExeFile);
       }
     return newSVuv((unsigned long) ret);
}

void wrap_CloseHandle(SV * handle) {
     CloseHandle((HANDLE) SvUV(handle));
}


EOC

#print_constants(); # prints out the values of the various constants.

#print_sizeof_struct(); # prints out sizeof(PROCESSENTRY32)

$hnd = wrap_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

print $hnd, "\n";

while (1){
      if(!wrap_Process32Next($hnd)) {
        wrap_CloseHandle($hnd);
        last;
        }
      };

__END__
####################################

I'm a friggen idiot when it comes to Windows .... please make allowances for
that.

Cheers,
Rob

The C script from the MSDN docs:

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

BOOL GetProcessList ()
{
    HANDLE         hProcessSnap = NULL;
    BOOL           bRet      = FALSE;
    PROCESSENTRY32 pe32      = {0};

    //  Take a snapshot of all processes in the system.

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hProcessSnap == INVALID_HANDLE_VALUE)
        return (FALSE);

    //  Fill in the size of the structure before using it.

    pe32.dwSize = sizeof(PROCESSENTRY32);

    //  Walk the snapshot of the processes, and for each process,
    //  display information.

    if (Process32First(hProcessSnap, &pe32))
    {
        DWORD         dwPriorityClass;
        BOOL          bGotModule = FALSE;
        MODULEENTRY32 me32       = {0};

        do
        {
            bGotModule = GetProcessModule(pe32.th32ProcessID,
                pe32.th32ModuleID, &me32, sizeof(MODULEENTRY32));

            if (bGotModule)
            {
                HANDLE hProcess;

                // Get the actual priority class.
                hProcess = OpenProcess (PROCESS_ALL_ACCESS,
                    FALSE, pe32.th32ProcessID);
                dwPriorityClass = GetPriorityClass (hProcess);
                CloseHandle (hProcess);

                // Print the process's information.
                printf( "\nPriority Class Base\t%d\n",
                    pe32.pcPriClassBase);
                printf( "PID\t\t\t%d\n", pe32.th32ProcessID);
                printf( "Thread Count\t\t%d\n", pe32.cntThreads);
                printf( "Module Name\t\t%s\n", me32.szModule);
                printf( "Full Path\t\t%s\n\n", me32.szExePath);
            }
        }
        while (Process32Next(hProcessSnap, &pe32));
        bRet = TRUE;
    }
    else
        bRet = FALSE;    // could not walk the list of processes

    // Do not forget to clean up the snapshot object.

    CloseHandle (hProcessSnap);
    return (bRet);
}

_______________________________________________
Perl-Win32-Users mailing list
Perl-Win32-Users@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to