http://qs1969.pair.com?node_id=558186

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

Hi,

i'm working on a a new module right now (Win32::Security::EFS).
internally i use two functions to talk to Win32::API and Win32::API::Struct.
sub import_api_ex { my ( $lib, $sig ) = @_; my $key = join "_", map { uc } ( $lib, $sig ); $api{$key} = Win32::API->new( $lib, $sig ) unless exists $api{$key}; return $api{$key}; } sub define_struct { my ( $name, @params ) = @_; Win32::API::Struct->typedef( $name, @params ); }
Now, i want to implement the following function from advapi32.dll
DWORD QueryUsersOnEncryptedFile( LPCWSTR lpFileName, // file name PENCRYPTION_CERTIFICATE_HASH_LIST *pUsers // hash list );
as you can see, the 2nd parameter is a pointer to pointer of a structure. anyways, i defined all needed structers.
BEGIN { define_struct( 'EFS_HASH_BLOB', qw/ DWORD cbData; LPBYTE pbData; / ); define_struct( 'ENCRYPTION_CERTIFICATE_HASH', qw/ DWORD cbTotalLength; void* pUserSid; LPEFS_HASH_BLOB pHash; LPWSTR lpDisplayInformation; / ); define_struct( 'ENCRYPTION_CERTIFICATE_HASH_LIST', qw/ DWORD nCert_Hash; LPENCRYPTION_CERTIFICATE_HASH* pUsers; / ); }
Then, i tried to import the function
sub query_users { my ( $self, $filename ) = @_; my $func = import_api_ex( 'advapi32', 'DWORD QueryUsersOnEncrypted +File(LPCWSTR lpFileName, LPENCRYPTION_CERTIFICATE_HASH_LIST* pUsers)' ); die "Could not import API QueryUsersOnEncryptedFile: $!" unless defined $func; }
nothing special yet, but when i try to call the function, i get a WARNING:
Win32::API::parse_prototype: WARNING unknown parameter type 'LPENCRYPT +ION_CERTIFICATE_HASH_LIST*' at C:/Perl/site/lib/Wi n32/API.pm line 248, <DATA> line 164.
How do i fix this problem? Any hints appreciated!

Replies are listed 'Best First'.
Re: Win32::API::Struct: Pointers of Pointers
by BrowserUk (Patriarch) on Jun 29, 2006 at 00:12 UTC

    Since you are not going to benefit from compile time pointer checking, dodge the issue and change the prototype to one that avoids the unknown type

    my $func = import_api_ex( 'advapi32', 'DWORD QueryUsersOnEncryptedFile(LPCWSTR lpFileName, LPVOID* +pUsers)' );

    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.
      Would be an idea. but where do i go from there? Meaning, how do i access pUsers for example?

        Just as you would normally using W::API::Struct. Create the struct per your example and the pass the variable as the parameter when your call the API. The only thing that is checked is the your are passing in a pointer. Once the call returns, you should be able to access the elements of the struct in the usual way.


        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.
      well,

      it is not working. here is would i did.
      my $func = import_api_ex( 'advapi32', 'DWORD QueryUsersOnEncryptedFile(LPCWSTR lpFileName, LPVOID pUsers +)' ) ; # LPVOID* is not known die "Could not import API QueryUsersOnEncryptedFile: $!" unless define +d $func; my $encCertHashList = Win32::API::Struct->new('ENCRYPTION_CERTIFICATE_HASH_LIST'); $func->Call( make_unicode( File::Spec->canonpath($filename) ), $encCertHashList ); print $encCertHashList-> {nCert_Hash}; # i get: Can't use string ("ÈÖƒ?") as a HASH ref while + "strict refs" in use $encCertHashList = Win32::API::Struct->new('ENCRYPTION_CERTIFICATE_HAS +H_LIST'); $func->Call( make_unicode( File::Spec->canonpath($filename) ), \$encCertHashList ); print $encCertHashList-> {nCert_Hash}; # i get: Use of uninitialized value in print
      i tried both variants without the make_unicode call <- made no differences!

        I wonder what return code you're getting?


        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.
Re: Win32::API::Struct: Pointers of Pointers
by runrig (Abbot) on Jun 29, 2006 at 00:02 UTC
    The API docs say it's a pointer to a structure, so try removing the "*" from the Win32::API->new() call. I did that and I get no errors even when doing the actual $func->Call(...) though I'm not sure if I'm getting meaningful results either.
      No, the structure is ENCRYPTION_CERTIFICATE_HASH_LIST and PENCRYPTION_CERTIFICATE_HASH_LIST is already a pointer. So, PENCRYPTION_CERTIFICATE_HASH_LIST* is a mointer of pointer.

      Knowing a lot about C and C++ programming (mainly under Windows), your suggestion can not work correctly.
        Knowing a lot about C and C++ programming (mainly under Windows), your suggestion can not work correctly.

        I'm just going by the principle that the documentation is not always right, and it doesn't hurt to try something else. The argument description says that it is a pointer to a structure. The "*" in the function syntax suggests it's a pointer to a pointer to a structure. One of those is wrong. If you've implemented this in C or C++ and you know for sure, then nevermind.