in reply to Win32::API: deciphering a returned pointer to a struct

The DomainControllerInfo arg is described as:

Pointer to a PDOMAIN_CONTROLLER_INFO value that receives a pointer to a DOMAIN_CONTROLLER_INFO structure that contains data about the domain controller selected. This structure is allocated by DsGetDcName. The caller must free the structure using the NetApiBufferFree function when it is no longer required.

And if you look at the function declaration,

PDOMAIN_CONTROLLER_INFO *DomainControllerInfo

It's suppose to be a pointer to a pointer that it will populate, not a pointer to a struct that it will populate.

Completely untested (and you need to fill a couple of question marks):

use strict; use warnings; use Carp qw( croak ); use Win32::API qw( ); use Win32::API::Struct qw( ); use constant DS_IS_DNS_NAME => 0x00020000; typedef Win32::API::Struct GUID => qw { DWORD Data1; WORD Data2; WORD Data3; BYTE Data4[8]; }; sub _link { my $o = Win32::API->new( @_ ); die "Can't link to DsGetDcName in dll Netapi32: $^E\n" if !$o; return $o; } { my $DsGetDcName = _link( 'Netapi32', 'DsGetDcName', 'PPSPNP', 'N' ); my $NetApiBufferFree = _link( 'Netapi32', 'NetApiBufferFree', 'N', 'N' ); my $GUID_FORMAT = 'L S S a8'; my $SIZE_OF_GUID = 4+2+2+ 8; my $DCI_FORMAT = "p p L a$SIZE_OF_GUID p p L p p"; my $SIZE_OF_DCI = 4+4+4+ $SIZE_OF_GUID+4+4+4+4+4; sub DsGetDcName { my $pk_ptr_to_pk_dci = pack('L', 0); if (!(my $rv = $DsGetDcName->Call( @_, $pk_ptr_to_pk_dci ))) { # It uses the same codes as GetLastError $^E = $rv; croak("$^E"); } my $ptr_to_pk_dci = unpack('L', $pk_ptr_to_pk_dci); my $pk_dci = unpack("P$SIZE_OF_DCI", $pk_ptr_to_pk_dci); # If only Win32::API::Struct provided a public # interface that takes a packed struct. my ($dcn, $dca, $dcat, $pk_guid, $dn, $dfn, $flags, $sn, $csn) = unpack($DCI_FORMAT, $pk_dci); my @guid = unpack($GUID_FORMAT, $pk_guid); my $guid = Win32::API::Struct->new('GUID'); @{$guid}{qw( Data1 Data2 Data3 Data4 )} = @guid; if (!(my $rv = $NetApiBufferFree->Call( $ptr_to_pk_dci ))) { # It uses the same codes as GetLastError $^E = $rv; # Don't use carp since it's likely a bug in this sub. warn("Warning: Error from NetApiBufferFree: $^E"); } return { DomainControllerName => $dcn, DomainControllerAddress => $dca, DomainControllerAddressType => $dcat, DomainGuid => \@guid, DomainName => $dn, DnsForestName => $dfn, Flags => $flags, DcSiteName => $sn, ClientSiteName => $csn, }; } } my $domainguid = Win32::API::Struct->new('GUID'); my $dci = DsGetDcName( 'mymachine', 'mydomain', $domainguid, 'myADsite', DS_IS_DNS_NAME, ); use Data::Dumper qw( Dumper ); print Dumper $dci;