jschollen has asked for the wisdom of the Perl Monks concerning the following question:

Hi everyone,

I'm having a problem rebuilding the windows device tree.
The problem occures allready with the first function call, being SetupDiGetClassImageList (from setupapi.dll).
The return value I get is 0 (should be 1) and the Data::Dumper gives me the reponse: $VAR1 = 0;

Does anyone know what I'm doing wrong?

(I'm a newbe at Win32::API, but hope to conquer it someday).

The code I've got so far is:
#!/usr/local/perl -w # Packages use strict; use Data::Dumper; use Sys::Hostname; use Win32::API; # Headers my $CR_SUCCESS = 0; my $CR_DEFAULT = 1; my $CR_OUT_OF_MEMORY = 2; my $CR_INVALID_POINTER = 3; my $CR_INVALID_FLAG = 4; my $CR_INVALID_DEVNODE = 5; my $CR_INVALID_DEVINST = $CR_INVALID_DEVNODE; my $CR_INVALID_RES_DES = 6; my $CR_INVALID_LOG_CONF = 7; my $CR_INVALID_ARBITRATOR = 8; my $CR_INVALID_NODELIST = 9; my $CR_DEVNODE_HAS_REQS = 10; my $CR_DEVINST_HAS_REQS = $CR_DEVNODE_HAS_REQS; my $CR_INVALID_RESOURCEID = 11; my $CR_DLVXD_NOT_FOUND = 12; # WIN 95 ONLY my $CR_NO_SUCH_DEVNODE = 13; my $CR_NO_SUCH_DEVINST = $CR_NO_SUCH_DEVNODE; my $CR_NO_MORE_LOG_CONF = 14; my $CR_NO_MORE_RES_DES = 15; my $CR_ALREADY_SUCH_DEVNODE = 16; my $CR_ALREADY_SUCH_DEVINST = $CR_ALREADY_SUCH_DEVNODE; my $CR_INVALID_RANGE_LIST = 17; my $CR_INVALID_RANGE = 18; my $CR_FAILURE = 19; my $CR_NO_SUCH_LOGICAL_DEV = 20; my $CR_CREATE_BLOCKED = 21; my $CR_NOT_SYSTEM_VM = 22; # WIN 95 ONLY my $CR_REMOVE_VETOED = 23; my $CR_APM_VETOED = 24; my $CR_INVALID_LOAD_TYPE = 25; my $CR_BUFFER_SMALL = 26; my $CR_NO_ARBITRATOR = 27; my $CR_NO_REGISTRY_HANDLE = 28; my $CR_REGISTRY_ERROR = 29; my $CR_INVALID_DEVICE_ID = 30; my $CR_INVALID_DATA = 31; my $CR_INVALID_API = 32; my $CR_DEVLOADER_NOT_READY = 33; my $CR_NEED_RESTART = 34; my $CR_NO_MORE_HW_PROFILES = 35; my $CR_DEVICE_NOT_THERE = 36; my $CR_NO_SUCH_VALUE = 37; my $CR_WRONG_TYPE = 38; my $CR_INVALID_PRIORITY = 39; my $CR_NOT_DISABLEABLE = 40; my $CR_FREE_RESOURCES = 41; my $CR_QUERY_VETOED = 42; my $CR_CANT_SHARE_IRQ = 43; my $CR_NO_DEPENDENT = 44; my $CR_SAME_RESOURCES = 45; my $CR_NO_SUCH_REGISTRY_KEY = 46; my $CR_INVALID_MACHINENAME = 47; # NT ONLY my $CR_REMOTE_COMM_FAILURE = 48; # NT ONLY my $CR_MACHINE_UNAVAILABLE = 49; # NT ONLY my $CR_NO_CM_SERVICES = 50; # NT ONLY my $CR_ACCESS_DENIED = 51; # NT ONLY my $CR_CALL_NOT_IMPLEMENTED = 52; my $CR_INVALID_PROPERTY = 53; my $CR_DEVICE_INTERFACE_ACTIVE = 54; my $CR_NO_SUCH_DEVICE_INTERFACE = 55; my $CR_INVALID_REFERENCE_STRING = 56; my $CR_INVALID_CONFLICT_LIST = 57; my $CR_INVALID_INDEX = 58; my $CR_INVALID_STRUCTURE_SIZE = 59; my $NUM_CR_RESULTS = 60; # Variables my $answer = ""; my $stepOk = 1; my $errorMsg = ""; my $ClassImageListData; my $ClassImageData; my $classImList = new Win32::API('setupapi','SetupDiGetClassImageList' +,'P','N') or ($errorMsg = $!); if($errorMsg ne "") { $stepOk = 0; $errorMsg = "Unable to load classImList: ".$errorMsg; print STDOUT $errorMsg."\n"; } else { Win32::API::Struct->typedef(ULONG_PTR => qw{ ULONG *Reserved; }); Win32::API::Struct->typedef(_IMAGELIST => qw{ }); Win32::API::Struct->typedef(HIMAGELIST => qw{ _IMAGELIST *value }); Win32::API::Struct->typedef(SP_CLASSIMAGE_DATA => qw{ DWORD cbSize; HIMAGELIST ImageList; DWORD Reserved; }); Win32::API::Struct->typedef(SP_CLASSIMAGELIST_DATA => qw{ DWORD cbSize; HIMAGELIST ImageList; ULONG_PTR Reserved; }); $ClassImageData = Win32::API::Struct->new('SP_CLASSIMAGE_DATA') or ( +$errorMsg = $!); if($errorMsg ne "") { $stepOk = 0; $errorMsg = "Unable to load structure SP_CLASSIMAGE_DATA: ".$error +Msg; print STDOUT $errorMsg."\n"; } else { print STDOUT "The SP_CLASSIMAGE_DATA structure is: $ClassImageData +\n"; $ClassImageListData = Win32::API::Struct->new('SP_CLASSIMAGELIST_D +ATA') or ($errorMsg = $!); if($errorMsg ne "") { $stepOk = 0; $errorMsg = "Unable to load structure SP_CLASSIMAGELIST_DATA: ". +$errorMsg; print STDOUT $errorMsg."\n"; } else { print STDOUT "The SP_CLASSIMAGELIST_DATA structure is: $ClassIma +geListData\n"; $ClassImageListData->{cbSize} = length($ClassImageListData); print STDOUT "The length of the ClassImageListData is: ".length( +$ClassImageListData)."\n"; print STDOUT "Or: ".$ClassImageListData->{cbSize}."\n"; $ClassImageData->{cbSize} = length($ClassImageData); print STDOUT "The length of the ClassImageData is: ".length($Cla +ssImageData)."\n"; print STDOUT "Or: ".$ClassImageData->{cbSize}."\n"; } } if($stepOk) { print STDOUT "The ClassImageData is: $ClassImageData\n"; print STDOUT "The ClassImageListData is: $ClassImageListData\n"; $answer = $classImList->Call($ClassImageListData); print STDOUT "The return value of the SetupDiGetClassImageList is: + $answer\n"; if($answer) { print STDOUT "The value of the SetupDiGetClassImageList is: $Cla +ssImageData\n"; } else { $stepOk = 0; $errorMsg = "Error reading classImList: $answer"; print STDOUT $errorMsg."\n"; print STDOUT "***********\n"; print Dumper($answer); print STDOUT "***********\n"; } } }

Replies are listed 'Best First'.
Re: Windows Device Tree
by BrowserUk (Patriarch) on Aug 28, 2006 at 16:19 UTC

    If an API call is failing, then you should print the value returned by GetLastError(), this will usually give you an error code that will sometimes help you identify why the API is failing.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      $^E is easier to use than Win32::GetLastError().

      - tye        

        I've never been 100% sure whether referencing $^E, (which I always use myself), is effectively a synchronous call to GetLastError(), or whether it ($^E) only get's set if the XS code arranges to do so? Hence my reluctance to recommend $^E to others directly.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      Great idea.
      When I use Win32::GetLastError I receive error value 1784 which means ERROR_INVALID_USER_BUFFER: The supplied user buffer is not valid for the requested operation

      I guess that means that I did not define my structures correctly.

      Can someone guide me? (all help is much appreciated).

      The structures I found on MSDN are: The once I found in CommCtrl.h are:

      Update:
      I think I found the sollution to my problem.
      The structures should be defined as:

      And the sizes of the of the structures should not be defined with length() but with sizeof():

      I do get some warnings about uninitialized values, but that can be sorted out.