Bob A, has asked for the wisdom of the Perl Monks concerning the following question:

I want to call a Windows API from Perl. We are running under Windows 2000 and NT. In particular, I want to retrieve the used and free space on a drive using the GetDiskFreeSpaceEx call.

Replies are listed 'Best First'.
Re: API Calls from Perl
by Coyote (Deacon) on Apr 09, 2001 at 19:39 UTC
    Check out the Win32::API module. It's not included with ActiveState's perl distribution, but you can install it using ActiveState's PPM tool. From the documentation:

    use Win32::API; $function = new Win32::API($library, $functionname, \@argumenttypes, $returntype); $return = $function->Call(@arguments);

    Update:

    To effectively use this method you will also need the API documentation. Here's the prototype for the GetDiskFreeEx function:

    BOOL GetDiskFreeSpaceEx( LPCTSTR lpDirectoryName, // pointer to the directory name PULARGE_INTEGER lpFreeBytesAvailableToCaller, // receives the number + of bytes on // disk available to t +he caller PULARGE_INTEGER lpTotalNumberOfBytes, // receives the number of b +ytes on disk PULARGE_INTEGER lpTotalNumberOfFreeBytes // receives the free bytes +on disk );

    This function lives in KERNEL32.DLL.

    ----
    Coyote

Re: API Calls from Perl
by Asim (Hermit) on Apr 09, 2001 at 20:23 UTC
    If you want to make the direct API call, use Win32::API (but look below for an easier method). You can get it from CPAN, or via PPM if you're using ActivePerl from ActiveState, or from the author's site at http://dada.perl.it/ Here's some (tested locally) code that uses the API calls. I retrived the base for this code from a posting to the ActiveState Perl Mailing list by Bill Luebkert:
    use strict; use Win32::API; my $v = 0; # set to 1 for verbose sub DRIVE_UNKNOWN { 0; } # The drive type cannot be determined. sub DRIVE_NO_ROOT_DIR { 1; } # The root directory does not exist. sub DRIVE_REMOVABLE { 2; } # The drive can be removed from the driv +e. sub DRIVE_FIXED { 3; } # The disk cannot be removed from the dr +ive. sub DRIVE_REMOTE { 4; } # The drive is a remote (network) drive +. sub DRIVE_CDROM { 5; } # The drive is a CD-ROM drive. sub DRIVE_RAMDISK { 6; } # The drive is a RAM disk. my $GetDriveType = new Win32::API("kernel32", "GetDriveType", ['P'], ' +N') or die Win32::FormatMessage(Win32::GetLastError()); my $GetDiskFreeSpace = new Win32::API("kernel32", "GetDiskFreeSpace", +['P','P','P','P','P'], 'N') or die Win32::FormatMessage(Win32::GetLas +tError()); open (BADLIST, "chk_servers") or die; while (<BADLIST>) { chomp; #my ($server,$nos,$domain,$share1,$share2)=split(/,/); #my (undef, $server, $share) = split /\\+/; #print "Share $share on $server\n"; my $Drive = $_; print "$Drive: "; my $ret = $GetDriveType->Call($Drive) or die Win32::FormatMessage( +Win32::GetLastError()); if ($ret == DRIVE_CDROM) { print "$_: CD-ROM\n"; next; } next if ($ret == DRIVE_UNKNOWN); #next if ($ret == DRIVE_NO_ROOT_DIR); if ($ret == DRIVE_REMOVABLE) { print "$_: Removeable\n"; next; +} #if ($ret == DRIVE_REMOTE) { print "$_: Network\n"; next; } $Drive = "$_\0"; #my $Drive = "\\\\$server\\$share1\$\\\0"; my $SecsPerCluster = pack ("I", 0); my $BytesPerSec = pack ("I", 0); my $FreeClusters = pack ("I", 0); my $TotClusters = pack ("I", 0); $ret = $GetDiskFreeSpace->Call($Drive, $SecsPerCluster, $BytesPerS +ec, $FreeClusters, $TotClusters) or print Win32::FormatMessage(Win32: +:GetLastError()); my $SPC = unpack ("I", $SecsPerCluster); my $BPS = unpack ("I", $BytesPerSec); my $FC = unpack ("I", $FreeClusters); my $TC = unpack ("I", $TotClusters); if ($ret) { printf "%-2.2s %9.3f\n\tSecsPerCluster=%u\n\tBytesPerSec=%u\n" +, $Drive, $SPC * $BPS * $FC / (1024 * 1024), $SPC, $BPS if $v; printf "\tFreeClusters=%u\n\tTotClusters=%u\n", $FC, $TC if $v +; printf "%9.0f Bytes\n", $SPC * $BPS * $FC ; } }
    BUT -- all this is a mistake in my opinion (although very educational about making these calls). Use either Win32::AdminMisc from Dave Roth or Win32::DriveInfo, so that all the above gets culled to a line like:         if (my (undef, undef, undef, undef, undef, $totalbytes, $freebytes) = Win32::DriveInfo::DriveSpace($UNC)) Both are in PPM and CPAN.
    ----Asim, known to some as Woodrow.
Re: API Calls from Perl
by Beatnik (Parson) on Apr 09, 2001 at 19:41 UTC
    Have you checked Win32::DriveInfo ?

    Beatnik
    ... Quidquid perl dictum sit, altum viditur.
(jptxs) Re: API Calls from Perl
by jptxs (Curate) on Apr 09, 2001 at 19:40 UTC
    try two things right from the start:
    • look at this Win32::API
    • goto CPAN and search for windows, WIN32, etc.
    I think you will find both enlightening. I'd slap in some code, but I've never done winPerl =)
    "A man's maturity -- consists in having found again the seriousness one had as a child, at play." --Nietzsche
Re: API Calls from Perl
by rchiav (Deacon) on Apr 09, 2001 at 19:47 UTC
    Look at Win32::API. That's a review of the Module.. and you can get it (if it's not already on your system) from either CPAN or if you're using ActiveState's distribution, you can use ppm.

    Hope this helps,
    Rich
    bash: undo: command not found