| Filename | C:/tmp64ng/perl/vendor/lib/Win32/API/Struct.pm | 
| Statements | Executed 20 statements in 0s | 
| Calls | P | F | Exclusive Time  | 
        Inclusive Time  | 
        Subroutine | 
|---|---|---|---|---|---|
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@10 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@11 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@14 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@15 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@16 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@313 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Struct::BEGIN@9 | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::DEBUG | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::Dump | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::EXISTS | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::FETCH | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::FIRSTKEY | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::FromMemory | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::NEXTKEY | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::Pack | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::STORE | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::TIEHASH | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::Unpack | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::align | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::ck_type | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::getPack | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::getUnpack | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::is_known | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::members | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::new | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::recognize | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::sizeof | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::to_base_struct | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::Struct::typedef | 
| Line | State ments  | 
      Time on line  | 
      Calls | Time in subs  | 
      Code | 
|---|---|---|---|---|---|
| 1 | # | ||||
| 2 | # Win32::API::Struct - Perl Win32 API struct Facility | ||||
| 3 | # | ||||
| 4 | # Author: Aldo Calpini <dada@perl.it> | ||||
| 5 | # Maintainer: Cosimo Streppone <cosimo@cpan.org> | ||||
| 6 | # | ||||
| 7 | |||||
| 8 | package Win32::API::Struct; | ||||
| 9 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@9 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 9 # spent     0s making 1 call to Win32::API::Struct::BEGIN@9
# spent     0s making 1 call to strict::import  | 
| 10 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@10 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 10 # spent     0s making 1 call to Win32::API::Struct::BEGIN@10
# spent     0s making 1 call to warnings::import  | 
| 11 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@11 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 11 # spent     0s making 1 call to Win32::API::Struct::BEGIN@11
# spent     0s making 1 call to vars::import  | 
| 12 | 1 | 0s | $VERSION = '0.65'; | ||
| 13 | |||||
| 14 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@14 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 14 # spent     0s making 1 call to Exporter::import
# spent     0s making 1 call to Win32::API::Struct::BEGIN@14  | 
| 15 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@15 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 15 # spent     0s making 1 call to Exporter::import
# spent     0s making 1 call to Win32::API::Struct::BEGIN@15  | 
| 16 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@16 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 16 # spent     0s making 1 call to Config::import
# spent     0s making 1 call to Win32::API::Struct::BEGIN@16  | 
| 17 | |||||
| 18 | 1 | 0s | require Exporter; | ||
| 19 | 1 | 0s | require DynaLoader; | ||
| 20 | 1 | 0s | @ISA = qw(Exporter DynaLoader); | ||
| 21 | |||||
| 22 | 1 | 0s | my %Known = (); | ||
| 23 | |||||
| 24 | sub DEBUG { | ||||
| 25 | if ($Win32::API::DEBUG) { | ||||
| 26 | printf @_ if @_ or return 1; | ||||
| 27 | } | ||||
| 28 | else { | ||||
| 29 | return 0; | ||||
| 30 | } | ||||
| 31 | } | ||||
| 32 | |||||
| 33 | sub typedef { | ||||
| 34 | my $class = shift; | ||||
| 35 | my $struct = shift; | ||||
| 36 | my ($type, $name, @recog_arr); | ||||
| 37 | my $self = { | ||||
| 38 | align => undef, | ||||
| 39 | typedef => [], | ||||
| 40 | }; | ||||
| 41 | while (defined($type = shift)) { | ||||
| 42 | $name = shift; | ||||
| 43 | $name =~ s/;$//; | ||||
| 44 | @recog_arr = recognize($type, $name); | ||||
| 45 | #http://perlmonks.org/?node_id=978468, not catching the type not found here, | ||||
| 46 | #will lead to a div 0 later | ||||
| 47 | if(@recog_arr != 3){ | ||||
| 48 | carp "Win32::API::Struct::typedef: unknown member type=\"$type\", name=\"$name\""; | ||||
| 49 | return undef; | ||||
| 50 | } | ||||
| 51 | push(@{$self->{typedef}}, [@recog_arr]); | ||||
| 52 | } | ||||
| 53 | |||||
| 54 | $Known{$struct} = $self; | ||||
| 55 | $Win32::API::Type::Known{$struct} = '>'; | ||||
| 56 | return 1; | ||||
| 57 | } | ||||
| 58 | |||||
| 59 | |||||
| 60 | #void ck_type($param, $proto, $param_num) | ||||
| 61 | sub ck_type { | ||||
| 62 | my ($param, $proto) = @_; | ||||
| 63 | #legacy LP prefix check | ||||
| 64 | return if substr($proto, 0, 2) eq 'LP' && substr($proto, 2) eq $param; | ||||
| 65 | #check if proto can be converted to base struct name | ||||
| 66 | return if exists $Win32::API::Struct::Pointer{$proto} && | ||||
| 67 | $param eq $Win32::API::Struct::Pointer{$proto}; | ||||
| 68 | #check if proto can have * chopped off to convert to base struct name | ||||
| 69 | $proto =~ s/\s*\*$//; | ||||
| 70 | return if $proto eq $param; | ||||
| 71 | croak("Win32::API::Call: supplied type (LP)\"". | ||||
| 72 | $param."\"( *) doesn't match type \"". | ||||
| 73 | $_[1]."\" for parameter ". | ||||
| 74 | $_[2]." "); | ||||
| 75 | } | ||||
| 76 | |||||
| 77 | #$basename = to_base_struct($pointername) | ||||
| 78 | sub to_base_struct { | ||||
| 79 | return $Win32::API::Struct::Pointer{$_[0]} | ||||
| 80 | if exists $Win32::API::Struct::Pointer{$_[0]}; | ||||
| 81 | die "Win32::API::Struct::Unpack unknown type"; | ||||
| 82 | } | ||||
| 83 | |||||
| 84 | sub recognize { | ||||
| 85 | my ($type, $name) = @_; | ||||
| 86 | my ($size, $packing); | ||||
| 87 | |||||
| 88 | if (exists $Known{$type}) { | ||||
| 89 | $packing = '>'; | ||||
| 90 | return ($name, $packing, $type); | ||||
| 91 | } | ||||
| 92 | else { | ||||
| 93 | $packing = Win32::API::Type::packing($type); | ||||
| 94 | return undef unless defined $packing; | ||||
| 95 | if ($name =~ s/\[(.*)\]$//) { | ||||
| 96 | $size = $1; | ||||
| 97 | $packing = $packing . '*' . $size; | ||||
| 98 | } | ||||
| 99 | DEBUG "(PM)Struct::recognize got '$name', '$type' -> '$packing'\n"; | ||||
| 100 | return ($name, $packing, $type); | ||||
| 101 | } | ||||
| 102 | } | ||||
| 103 | |||||
| 104 | sub new { | ||||
| 105 | my $class = shift; | ||||
| 106 | my ($type, $name, $packing); | ||||
| 107 | my $self = {typedef => [],}; | ||||
| 108 | if ($#_ == 0) { | ||||
| 109 | if (is_known($_[0])) { | ||||
| 110 | DEBUG "(PM)Struct::new: got '$_[0]'\n"; | ||||
| 111 | if( ! defined ($self->{typedef} = $Known{$_[0]}->{typedef})){ | ||||
| 112 | carp 'Win32::API::Struct::new: unknown type="'.$_[0].'"'; | ||||
| 113 | return undef; | ||||
| 114 | } | ||||
| 115 | foreach my $member (@{$self->{typedef}}) { | ||||
| 116 | ($name, $packing, $type) = @$member; | ||||
| 117 | next unless defined $name; | ||||
| 118 | if ($packing eq '>') { | ||||
| 119 | $self->{$name} = Win32::API::Struct->new($type); | ||||
| 120 | } | ||||
| 121 | } | ||||
| 122 | $self->{__typedef__} = $_[0]; | ||||
| 123 | } | ||||
| 124 | else { | ||||
| 125 | carp "Unknown Win32::API::Struct '$_[0]'"; | ||||
| 126 | return undef; | ||||
| 127 | } | ||||
| 128 | } | ||||
| 129 | else { | ||||
| 130 | while (defined($type = shift)) { | ||||
| 131 | $name = shift; | ||||
| 132 | |||||
| 133 | # print "new: found member $name ($type)\n"; | ||||
| 134 | if (not exists $Win32::API::Type::Known{$type}) { | ||||
| 135 | carp "Unknown Win32::API::Struct type '$type'"; | ||||
| 136 | return undef; | ||||
| 137 | } | ||||
| 138 | else { | ||||
| 139 | push(@{$self->{typedef}}, | ||||
| 140 | [$name, $Win32::API::Type::Known{$type}, $type]); | ||||
| 141 | } | ||||
| 142 | } | ||||
| 143 | } | ||||
| 144 | return bless $self; | ||||
| 145 | } | ||||
| 146 | |||||
| 147 | sub members { | ||||
| 148 | my $self = shift; | ||||
| 149 | return map { $_->[0] } @{$self->{typedef}}; | ||||
| 150 | } | ||||
| 151 | |||||
| 152 | sub sizeof { | ||||
| 153 | my $self = shift; | ||||
| 154 | my $size = 0; | ||||
| 155 | my $align = 0; | ||||
| 156 | my $first = ''; | ||||
| 157 | |||||
| 158 | for my $member (@{$self->{typedef}}) { | ||||
| 159 | my ($name, $packing, $type) = @{$member}; | ||||
| 160 | next unless defined $name; | ||||
| 161 | if (ref $self->{$name} eq q{Win32::API::Struct}) { | ||||
| 162 | |||||
| 163 | # If member is a struct, recursively calculate its size | ||||
| 164 | # FIXME for subclasses | ||||
| 165 | $size += $self->{$name}->sizeof(); | ||||
| 166 | } | ||||
| 167 | else { | ||||
| 168 | |||||
| 169 | # Member is a simple type (LONG, DWORD, etc...) | ||||
| 170 | if ($packing =~ /\w\*(\d+)/) { # Arrays (ex: 'c*260') | ||||
| 171 | $size += Win32::API::Type::sizeof($type) * $1; | ||||
| 172 | $first = Win32::API::Type::sizeof($type) * $1 unless defined $first; | ||||
| 173 | DEBUG "(PM)Struct::sizeof: sizeof with member($name) now = " . $size | ||||
| 174 | . "\n"; | ||||
| 175 | } | ||||
| 176 | else { # Simple types | ||||
| 177 | my $type_size = Win32::API::Type::sizeof($type); | ||||
| 178 | $align = $type_size if $type_size > $align; | ||||
| 179 | my $type_align = (($size + $type_size) % $type_size); | ||||
| 180 | $size += $type_size + $type_align; | ||||
| 181 | $first = Win32::API::Type::sizeof($type) unless defined $first; | ||||
| 182 | } | ||||
| 183 | } | ||||
| 184 | } | ||||
| 185 | |||||
| 186 | my $struct_size = $size; | ||||
| 187 | if (defined $align && $align > 0) { | ||||
| 188 | $struct_size += ($size % $align); | ||||
| 189 | } | ||||
| 190 | DEBUG "(PM)Struct::sizeof first=$first totalsize=$struct_size\n"; | ||||
| 191 | return $struct_size; | ||||
| 192 | } | ||||
| 193 | |||||
| 194 | sub align { | ||||
| 195 | my $self = shift; | ||||
| 196 | my $align = shift; | ||||
| 197 | |||||
| 198 | if (not defined $align) { | ||||
| 199 | |||||
| 200 | if (!(defined $self->{align} && $self->{align} eq 'auto')) { | ||||
| 201 | return $self->{align}; | ||||
| 202 | } | ||||
| 203 | |||||
| 204 | $align = 0; | ||||
| 205 | |||||
| 206 | foreach my $member (@{$self->{typedef}}) { | ||||
| 207 | my ($name, $packing, $type) = @$member; | ||||
| 208 | |||||
| 209 | if (ref($self->{$name}) eq "Win32::API::Struct") { | ||||
| 210 | #### ???? | ||||
| 211 | } | ||||
| 212 | else { | ||||
| 213 | if ($packing =~ /\w\*(\d+)/) { | ||||
| 214 | #### ???? | ||||
| 215 | } | ||||
| 216 | else { | ||||
| 217 | $align = Win32::API::Type::sizeof($type) | ||||
| 218 | if Win32::API::Type::sizeof($type) > $align; | ||||
| 219 | } | ||||
| 220 | } | ||||
| 221 | } | ||||
| 222 | return $align; | ||||
| 223 | } | ||||
| 224 | else { | ||||
| 225 | $self->{align} = $align; | ||||
| 226 | |||||
| 227 | } | ||||
| 228 | } | ||||
| 229 | |||||
| 230 | sub getPack { | ||||
| 231 | my $self = shift; | ||||
| 232 | my $packing = ""; | ||||
| 233 | my $packed_size = 0; | ||||
| 234 | my ($type, $name, $type_size, $type_align); | ||||
| 235 | my @items = (); | ||||
| 236 | my @recipients = (); | ||||
| 237 | my @buffer_ptrs = (); #this contains the struct_ptrs that were placed in the | ||||
| 238 | #the struct, its part of "C func changes the struct ptr to a private allocated | ||||
| 239 | #struct" code, it is push/poped only for struct ptrs, it is NOT a 1 to | ||||
| 240 | #1 mapping between all struct members, so don't access it with indexes | ||||
| 241 | |||||
| 242 | my $align = $self->align(); | ||||
| 243 | |||||
| 244 | foreach my $member (@{$self->{typedef}}) { | ||||
| 245 | my ($name, $type, $orig) = @$member; | ||||
| 246 | if ($type eq '>') { | ||||
| 247 | my ($subpacking, $subitems, $subrecipients, $subpacksize, $subbuffersptrs) = | ||||
| 248 | $self->{$name}->getPack(); | ||||
| 249 | DEBUG "(PM)Struct::getPack($self->{__typedef__}) ++ $subpacking\n"; | ||||
| 250 | push(@items, @$subitems); | ||||
| 251 | push(@recipients, @$subrecipients); | ||||
| 252 | push(@buffer_ptrs, @$subbuffersptrs); | ||||
| 253 | $packing .= $subpacking; | ||||
| 254 | $packed_size += $subpacksize; | ||||
| 255 | } | ||||
| 256 | else { | ||||
| 257 | my $repeat = 1; | ||||
| 258 | if ($type =~ /\w\*(\d+)/) { | ||||
| 259 | $repeat = $1; | ||||
| 260 | $type = "a$repeat"; | ||||
| 261 | } | ||||
| 262 | |||||
| 263 | DEBUG "(PM)Struct::getPack($self->{__typedef__}) ++ $type\n"; | ||||
| 264 | |||||
| 265 | if ($type eq 'p') { | ||||
| 266 | $type = Win32::API::Type::pointer_pack_type(); | ||||
| 267 | push(@items, Win32::API::PointerTo($self->{$name})); | ||||
| 268 | } | ||||
| 269 | elsif ($type eq 'T') { | ||||
| 270 | $type = Win32::API::Type::pointer_pack_type(); | ||||
| 271 | my $structptr; | ||||
| 272 | if(ref($self->{$name})){ | ||||
| 273 | $self->{$name}->Pack(); | ||||
| 274 | $structptr = Win32::API::PointerTo($self->{$name}->{buffer}); | ||||
| 275 | } | ||||
| 276 | else{ | ||||
| 277 | $structptr = 0; | ||||
| 278 | } | ||||
| 279 | push(@items, $structptr); | ||||
| 280 | push(@buffer_ptrs, $structptr); | ||||
| 281 | } | ||||
| 282 | else { | ||||
| 283 | push(@items, $self->{$name}); | ||||
| 284 | } | ||||
| 285 | push(@recipients, $self); | ||||
| 286 | $type_size = Win32::API::Type::sizeof($orig); | ||||
| 287 | $type_align = (($packed_size + $type_size) % $type_size); | ||||
| 288 | $packing .= "x" x $type_align . $type; | ||||
| 289 | $packed_size += ( $type_size * $repeat ) + $type_align; | ||||
| 290 | } | ||||
| 291 | } | ||||
| 292 | |||||
| 293 | DEBUG | ||||
| 294 | "(PM)Struct::getPack: $self->{__typedef__}(buffer) = pack($packing, $packed_size)\n"; | ||||
| 295 | |||||
| 296 | return ($packing, [@items], [@recipients], $packed_size, \@buffer_ptrs); | ||||
| 297 | } | ||||
| 298 | |||||
| 299 | # void $struct->Pack([$priv_warnings_flag]); | ||||
| 300 | sub Pack { | ||||
| 301 | my $self = shift; | ||||
| 302 | my ($packing, $items); | ||||
| 303 | ($packing, $items, $self->{buffer_recipients}, | ||||
| 304 | undef, $self->{buffer_ptrs}) = $self->getPack(); | ||||
| 305 | |||||
| 306 | if(DEBUG){ | ||||
| 307 | DEBUG "(PM)Struct::Pack: $self->{__typedef__}(buffer) = pack($packing, @$items)\n"; | ||||
| 308 | } | ||||
| 309 | |||||
| 310 | if($_[0]){ #Pack() on a new struct, without slice set, will cause lots of uninit | ||||
| 311 | #warnings, sometimes its intentional to set up buffer recipients for a | ||||
| 312 | #future UnPack() | ||||
| 313 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::Struct::BEGIN@313 which was called:
#    once (0s+0s) by Win32::API::BEGIN@63 at line 313         # spent     0s making 1 call to Win32::API::Struct::BEGIN@313
        # spent     0s making 1 call to warnings::unimport  | 
| 314 | $self->{buffer} = pack($packing, @$items); | ||||
| 315 | } | ||||
| 316 | else{ | ||||
| 317 | $self->{buffer} = pack($packing, @$items); | ||||
| 318 | } | ||||
| 319 | if (DEBUG) { | ||||
| 320 | for my $i (0 .. $self->sizeof - 1) { | ||||
| 321 | printf "#pack# %3d: 0x%02x\n", $i, ord(substr($self->{buffer}, $i, 1)); | ||||
| 322 | } | ||||
| 323 | } | ||||
| 324 | } | ||||
| 325 | |||||
| 326 | sub getUnpack { | ||||
| 327 | my $self = shift; | ||||
| 328 | my $packing = ""; | ||||
| 329 | my $packed_size = 0; | ||||
| 330 | my ($type, $name, $type_size, $type_align, $orig_type); | ||||
| 331 | my (@items, @types, @type_names); | ||||
| 332 | my $align = $self->align(); | ||||
| 333 | foreach my $member (@{$self->{typedef}}) { | ||||
| 334 | my ($name, $type, $orig) = @$member; | ||||
| 335 | if ($type eq '>') { | ||||
| 336 | my ($subpacking, $subpacksize, $subitems, $subtypes, $subtype_names) = $self->{$name}->getUnpack(); | ||||
| 337 | DEBUG "(PM)Struct::getUnpack($self->{__typedef__}) ++ $subpacking\n"; | ||||
| 338 | $packing .= $subpacking; | ||||
| 339 | $packed_size += $subpacksize; | ||||
| 340 | push(@items, @$subitems); | ||||
| 341 | push(@types, @$subtypes); | ||||
| 342 | push(@type_names, @$subtype_names); | ||||
| 343 | } | ||||
| 344 | else { | ||||
| 345 | if($type eq 'T') { | ||||
| 346 | $orig_type = $type; | ||||
| 347 | $type = Win32::API::Type::pointer_pack_type(); | ||||
| 348 | } | ||||
| 349 | my $repeat = 1; | ||||
| 350 | if ($type =~ /\w\*(\d+)/) { | ||||
| 351 | $repeat = $1; | ||||
| 352 | $type = "Z$repeat"; | ||||
| 353 | } | ||||
| 354 | DEBUG "(PM)Struct::getUnpack($self->{__typedef__}) ++ $type\n"; | ||||
| 355 | $type_size = Win32::API::Type::sizeof($orig); | ||||
| 356 | $type_align = (($packed_size + $type_size) % $type_size); | ||||
| 357 | $packing .= "x" x $type_align . $type; | ||||
| 358 | $packed_size += ( $type_size * $repeat ) + $type_align; | ||||
| 359 | push(@items, $name); | ||||
| 360 | if($orig_type){ | ||||
| 361 | push(@types, $orig_type); | ||||
| 362 | undef($orig_type); | ||||
| 363 | } | ||||
| 364 | else{ | ||||
| 365 | push(@types, $type); | ||||
| 366 | } | ||||
| 367 | push(@type_names, $orig); | ||||
| 368 | } | ||||
| 369 | } | ||||
| 370 | DEBUG "(PM)Struct::getUnpack($self->{__typedef__}): unpack($packing, @items)\n"; | ||||
| 371 | return ($packing, $packed_size, \@items, \@types, \@type_names); | ||||
| 372 | } | ||||
| 373 | |||||
| 374 | sub Unpack { | ||||
| 375 | my $self = shift; | ||||
| 376 | my ($packing, undef, $items, $types, $type_names) = $self->getUnpack(); | ||||
| 377 | my @itemvalue = unpack($packing, $self->{buffer}); | ||||
| 378 | DEBUG "(PM)Struct::Unpack: unpack($packing, buffer) = @itemvalue\n"; | ||||
| 379 | foreach my $i (0 .. $#$items) { | ||||
| 380 | my $recipient = $self->{buffer_recipients}->[$i]; | ||||
| 381 | my $item = $$items[$i]; | ||||
| 382 | DEBUG "(PM)Struct::Unpack: %s(%s) = '%s' (0x%08x)\n", | ||||
| 383 | $recipient->{__typedef__}, | ||||
| 384 | $item, | ||||
| 385 | $itemvalue[$i], | ||||
| 386 | $itemvalue[$i], | ||||
| 387 | ; | ||||
| 388 | if($$types[$i] eq 'T'){ | ||||
| 389 | my $oldstructptr = pop(@{$self->{buffer_ptrs}}); | ||||
| 390 | my $newstructptr = $itemvalue[$i]; | ||||
| 391 | my $SVMemberRef = \$recipient->{$item}; | ||||
| 392 | |||||
| 393 | if(!$newstructptr){ #new ptr is null | ||||
| 394 | if($oldstructptr != $newstructptr){ #old ptr was true | ||||
| 395 | carp "Win32::API::Struct::Unpack struct pointer". | ||||
| 396 | " member \"".$item."\" was changed by C function,". | ||||
| 397 | " possible resource leak"; | ||||
| 398 | } | ||||
| 399 | $$SVMemberRef = undef; | ||||
| 400 | } | ||||
| 401 | else{ #new ptr is true | ||||
| 402 | if($oldstructptr != $newstructptr){#old ptr was true, or null, but has changed, leak warning | ||||
| 403 | carp "Win32::API::Struct::Unpack struct pointer". | ||||
| 404 | " member \"".$item."\" was changed by C function,". | ||||
| 405 | " possible resource leak"; | ||||
| 406 | }#create a ::Struct if the slice is undef, user had the slice set to undef | ||||
| 407 | |||||
| 408 | if (!ref($$SVMemberRef)){ | ||||
| 409 | $$SVMemberRef = Win32::API::Struct->new(to_base_struct($type_names->[$i])); | ||||
| 410 | $$SVMemberRef->Pack(1); #buffer_recipients must be generated, no uninit warnings | ||||
| 411 | } | ||||
| 412 | #must fix {buffer} with contents of the new struct, $structptr might be | ||||
| 413 | #null or might be a SVPV from a ::Struct that was ignored, in any case, | ||||
| 414 | #a foreign memory allocator is at work here | ||||
| 415 | $$SVMemberRef->{buffer} = Win32::API::ReadMemory($newstructptr, $$SVMemberRef->sizeof) | ||||
| 416 | if($oldstructptr != $newstructptr); | ||||
| 417 | #always must be called, if new ptr is not null, at this point, C func, did | ||||
| 418 | #one of 2 things, filled the old ::Struct's {buffer} PV, or gave a new struct * | ||||
| 419 | #from its own allocator, there is no way to tell if the struct contents changed | ||||
| 420 | #so Unpack() must be called | ||||
| 421 | $$SVMemberRef->Unpack(); | ||||
| 422 | } | ||||
| 423 | } | ||||
| 424 | else{ #not a struct ptr | ||||
| 425 | $recipient->{$item} = $itemvalue[$i]; | ||||
| 426 | |||||
| 427 | # DEBUG "(PM)Struct::Unpack: self.items[$i] = $self->{$$items[$i]}\n"; | ||||
| 428 | } | ||||
| 429 | } | ||||
| 430 | } | ||||
| 431 | |||||
| 432 | sub FromMemory { | ||||
| 433 | my ($self, $addr) = @_; | ||||
| 434 | DEBUG "(PM)Struct::FromMemory: doing Pack\n"; | ||||
| 435 | $self->Pack(); | ||||
| 436 | DEBUG "(PM)Struct::FromMemory: doing GetMemory( 0x%08x, %d )\n", $addr, $self->sizeof; | ||||
| 437 | $self->{buffer} = Win32::API::ReadMemory($addr, $self->sizeof); | ||||
| 438 | $self->Unpack(); | ||||
| 439 | DEBUG "(PM)Struct::FromMemory: doing Unpack\n"; | ||||
| 440 | DEBUG "(PM)Struct::FromMemory: structure is now:\n"; | ||||
| 441 | $self->Dump() if DEBUG; | ||||
| 442 | DEBUG "\n"; | ||||
| 443 | } | ||||
| 444 | |||||
| 445 | sub Dump { | ||||
| 446 | my $self = shift; | ||||
| 447 | my $prefix = shift; | ||||
| 448 | foreach my $member (@{$self->{typedef}}) { | ||||
| 449 | my ($name, $packing, $type) = @$member; | ||||
| 450 | if (ref($self->{$name})) { | ||||
| 451 | $self->{$name}->Dump($name); | ||||
| 452 | } | ||||
| 453 | else { | ||||
| 454 | printf "%-20s %-20s %-20s\n", $prefix, $name, $self->{$name}; | ||||
| 455 | } | ||||
| 456 | } | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | #the LP logic should be moved to parse_prototype, since only | ||||
| 460 | #::API::Call() ever understood the implied LP prefix, Struct::new never did | ||||
| 461 | #is_known then can be inlined away and sub deleted, it is not public API | ||||
| 462 | sub is_known { | ||||
| 463 | my $name = shift; | ||||
| 464 | if (exists $Known{$name}) { | ||||
| 465 | return 1; | ||||
| 466 | } | ||||
| 467 | else { | ||||
| 468 | my $nametest = $name; | ||||
| 469 | if ($nametest =~ s/^LP//) { | ||||
| 470 | return exists $Known{$nametest}; | ||||
| 471 | } | ||||
| 472 | $nametest = $name; | ||||
| 473 | if($nametest =~ s/\*$//){ | ||||
| 474 | return exists $Known{$nametest}; | ||||
| 475 | } | ||||
| 476 | return 0; | ||||
| 477 | } | ||||
| 478 | } | ||||
| 479 | |||||
| 480 | sub TIEHASH { | ||||
| 481 | return Win32::API::Struct::new(@_); | ||||
| 482 | } | ||||
| 483 | |||||
| 484 | sub EXISTS { | ||||
| 485 | |||||
| 486 | } | ||||
| 487 | |||||
| 488 | sub FETCH { | ||||
| 489 | my $self = shift; | ||||
| 490 | my $key = shift; | ||||
| 491 | |||||
| 492 | if ($key eq 'sizeof') { | ||||
| 493 | return $self->sizeof; | ||||
| 494 | } | ||||
| 495 | my @members = map { $_->[0] } @{$self->{typedef}}; | ||||
| 496 | if (grep(/^\Q$key\E$/, @members)) { | ||||
| 497 | return $self->{$key}; | ||||
| 498 | } | ||||
| 499 | else { | ||||
| 500 | warn "'$key' is not a member of Win32::API::Struct $self->{__typedef__}"; | ||||
| 501 | } | ||||
| 502 | } | ||||
| 503 | |||||
| 504 | sub STORE { | ||||
| 505 | my $self = shift; | ||||
| 506 | my ($key, $val) = @_; | ||||
| 507 | my @members = map { $_->[0] } @{$self->{typedef}}; | ||||
| 508 | if (grep(/^\Q$key\E$/, @members)) { | ||||
| 509 | $self->{$key} = $val; | ||||
| 510 | } | ||||
| 511 | else { | ||||
| 512 | warn "'$key' is not a member of Win32::API::Struct $self->{__typedef__}"; | ||||
| 513 | } | ||||
| 514 | } | ||||
| 515 | |||||
| 516 | sub FIRSTKEY { | ||||
| 517 | my $self = shift; | ||||
| 518 | my @members = map { $_->[0] } @{$self->{typedef}}; | ||||
| 519 | return $members[0]; | ||||
| 520 | } | ||||
| 521 | |||||
| 522 | sub NEXTKEY { | ||||
| 523 | my $self = shift; | ||||
| 524 | my $key = shift; | ||||
| 525 | my @members = map { $_->[0] } @{$self->{typedef}}; | ||||
| 526 | for my $i (0 .. $#members - 1) { | ||||
| 527 | return $members[$i + 1] if $members[$i] eq $key; | ||||
| 528 | } | ||||
| 529 | return undef; | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | 1 | 0s | 1; | ||
| 533 | |||||
| 534 | ####################################################################### | ||||
| 535 | # DOCUMENTATION | ||||
| 536 | # | ||||
| 537 | |||||
| 538 | =head1 NAME | ||||
| 539 | |||||
| 540 | Win32::API::Struct - C struct support package for Win32::API | ||||
| 541 | |||||
| 542 | =head1 SYNOPSIS | ||||
| 543 | |||||
| 544 | use Win32::API; | ||||
| 545 | |||||
| 546 | Win32::API::Struct->typedef( 'POINT', qw( | ||||
| 547 | LONG x; | ||||
| 548 | LONG y; | ||||
| 549 | )); | ||||
| 550 | |||||
| 551 | my $Point = Win32::API::Struct->new( 'POINT' ); | ||||
| 552 | $Point->{x} = 1024; | ||||
| 553 | $Point->{y} = 768; | ||||
| 554 | |||||
| 555 | #### alternatively | ||||
| 556 | |||||
| 557 | tie %Point, 'Win32::API::Struct', 'POINT'; | ||||
| 558 | $Point{x} = 1024; | ||||
| 559 | $Point{y} = 768; | ||||
| 560 | |||||
| 561 | |||||
| 562 | =head1 ABSTRACT | ||||
| 563 | |||||
| 564 | This module enables you to define C structs for use with | ||||
| 565 | Win32::API. | ||||
| 566 | |||||
| 567 | See L<Win32::API/USING STRUCTURES> for more info about its usage. | ||||
| 568 | |||||
| 569 | =head1 DESCRIPTION | ||||
| 570 | |||||
| 571 | This module is automatically imported by Win32::API, so you don't | ||||
| 572 | need to 'use' it explicitly. The main methods are C<typedef> and | ||||
| 573 | C<new>, which are documented below. | ||||
| 574 | |||||
| 575 | =over 4 | ||||
| 576 | |||||
| 577 | =item C<typedef NAME, TYPE, MEMBER, TYPE, MEMBER, ...> | ||||
| 578 | |||||
| 579 | This method defines a structure named C<NAME>. The definition consists | ||||
| 580 | of types and member names, just like in C. In fact, most of the | ||||
| 581 | times you can cut the C definition for a structure and paste it | ||||
| 582 | verbatim to your script, enclosing it in a C<qw()> block. The | ||||
| 583 | function takes care of removing the semicolon after the member | ||||
| 584 | name. Win32::API::Struct does B<NOT> support Enums, Unions, or Bitfields. | ||||
| 585 | C<NAME> must not end in C<*>, typedef creates structs, not struct pointers. | ||||
| 586 | See L<Win32::API::Type/"typedef"> | ||||
| 587 | on how to create a struct pointer type. Returns true on success, and undef on error. | ||||
| 588 | On error it L<warns|perlfunc/warn> with the specific reason. | ||||
| 589 | |||||
| 590 | The synopsis example could be written like this: | ||||
| 591 | |||||
| 592 | Win32::API::Struct->typedef('POINT', 'LONG', 'x', 'LONG', 'y'); | ||||
| 593 | |||||
| 594 | But it could also be written like this (note the indirect object | ||||
| 595 | syntax), which is pretty cool: | ||||
| 596 | |||||
| 597 | typedef Win32::API::Struct POINT => qw{ | ||||
| 598 | LONG x; | ||||
| 599 | LONG y; | ||||
| 600 | }; | ||||
| 601 | |||||
| 602 | L<Win32::API/Call> automatically knows that an 'LPNAME' type, refers | ||||
| 603 | to a 'NAME' type struct. Also see L<Win32::API::Type/"typedef"> on how to declare | ||||
| 604 | pointers to struct types. | ||||
| 605 | |||||
| 606 | Unlike in Win32::API, a single non-array char or CHAR struct member in a | ||||
| 607 | struct is numeric, NOT the first character of a string. UTF16 strings pointers | ||||
| 608 | will be garbage on read back (passing in works, returning doesn't) since | ||||
| 609 | the NULL character will often be the 2nd byte of the UTF16 string. | ||||
| 610 | |||||
| 611 | =item C<new NAME> | ||||
| 612 | |||||
| 613 | This creates a structure (a Win32::API::Struct object) of the | ||||
| 614 | type C<NAME> (it must have been defined with C<typedef>). In Perl, | ||||
| 615 | when you create a structure, all the members are undefined. But | ||||
| 616 | when you use that structure in C (eg. a Win32::API call), you | ||||
| 617 | can safely assume that they will be treated as zero (or NULL). | ||||
| 618 | |||||
| 619 | =item C<sizeof> | ||||
| 620 | |||||
| 621 | This returns the size, in bytes, of the structure. Acts just like | ||||
| 622 | the C function of the same name. It is particularly useful for | ||||
| 623 | structures that need a member to be initialized to the structure's | ||||
| 624 | own size. | ||||
| 625 | |||||
| 626 | =item C<align [SIZE]> | ||||
| 627 | |||||
| 628 | Sets or returns the structure alignment (eg. how the structure is | ||||
| 629 | stored in memory). This is a very advanced option, and you normally | ||||
| 630 | don't need to mess with it. | ||||
| 631 | All structures in the Win32 Platform SDK should work without it. | ||||
| 632 | But if you define your own structure, you may need to give it an | ||||
| 633 | explicit alignment. In most cases, passing a C<SIZE> of 'auto' | ||||
| 634 | should keep the world happy. | ||||
| 635 | |||||
| 636 | =back | ||||
| 637 | |||||
| 638 | =head2 THE C<tie> INTERFACE | ||||
| 639 | |||||
| 640 | Instead of creating an object with the C<new> method, you can | ||||
| 641 | tie a hash, which will hold the desired structure, using the | ||||
| 642 | C<tie> builtin function: | ||||
| 643 | |||||
| 644 | tie %structure, Win32::API::Struct => 'NAME'; | ||||
| 645 | |||||
| 646 | The differences between the tied and non-tied approaches are: | ||||
| 647 | |||||
| 648 | =over 4 | ||||
| 649 | |||||
| 650 | =item * | ||||
| 651 | with tied structures, you can access members directly as | ||||
| 652 | hash lookups, eg. | ||||
| 653 | |||||
| 654 | # tied # non-tied | ||||
| 655 | $Point{x} vs. $Point->{x} | ||||
| 656 | |||||
| 657 | =item * | ||||
| 658 | with tied structures, when you try to fetch or store a | ||||
| 659 | member that is not part of the structure, it will result | ||||
| 660 | in a warning, eg. | ||||
| 661 | |||||
| 662 | print $Point{z}; | ||||
| 663 | # this will warn: 'z' is not a member of Win32::API::Struct POINT | ||||
| 664 | |||||
| 665 | =item * | ||||
| 666 | when you pass a tied structure as a Win32::API parameter, | ||||
| 667 | remember to backslash it, eg. | ||||
| 668 | |||||
| 669 | # tied # non-tied | ||||
| 670 | GetCursorPos( \%Point ) vs. GetCursorPos( $Point ) | ||||
| 671 | |||||
| 672 | =back | ||||
| 673 | |||||
| 674 | =head2 FOREIGN MEMORY ALLOCATORS | ||||
| 675 | |||||
| 676 | Using Win32::API::Struct is not recommended in situations where a C function | ||||
| 677 | will return results to you by putting a pointer to a string or a pointer to | ||||
| 678 | another struct into your supplied struct. Win32::API::Struct will do its best | ||||
| 679 | to detect that a new pointer appeared and to read it contents into Perl, but | ||||
| 680 | that pointer will be tossed away after being read. If this pointer is | ||||
| 681 | something you must explicitly free, you have leaked it by using | ||||
| 682 | Win32::API::Struct to decode it. If this pointer is something you must pass back to | ||||
| 683 | the C API you are using, you lost/leaked it. If you pass NULL, or a ::Struct | ||||
| 684 | pointer in a ::Struct to C API, after the C API call, ::Struct will detect the | ||||
| 685 | pointer changed, it will read the new struct from the new pointer into | ||||
| 686 | Perl, and a new child ::Struct will appear in the hash slice | ||||
| 687 | of the parent ::Struct, if you pass this new child ::Struct into the C API | ||||
| 688 | it will be a B<COPY> of the struct the C API from Perl's allocation placed | ||||
| 689 | in the parent ::Struct. For C++-like APIs, this will be unacceptable and lead to | ||||
| 690 | crashes as the C Functions tries to free a memory block that didn't come from the | ||||
| 691 | allocator of the C Function. Windows has many memory allocators, each CRT | ||||
| 692 | (VS 2, 3, 4, 5, NT/6, 7.0, 7.1, 8, 9, 10) malloc, LocalAlloc, GlobalAlloc, | ||||
| 693 | HeapAlloc, (each version of C++ Runtime Library) "new", CoGetMalloc, CoTaskMemAlloc, | ||||
| 694 | NetApiBufferAllocate, VirtualAlloc, CryptMemAlloc, AllocADsMem, SHAlloc, | ||||
| 695 | SnmpUtilMemAlloc. None of these allocators' pointers are compatible with Perl's | ||||
| 696 | allocator. Some C APIs give you static global buffers which never are freed or freed | ||||
| 697 | automatically in the next call to a function from to that DLL. | ||||
| 698 | |||||
| 699 | With foreign allocators, its best to treat to write a pointer class, bless the | ||||
| 700 | ref to scalar integer (holding the pointer) into that class to ensure that the | ||||
| 701 | DESTROY method will free the pointer and you never leak it, and your write | ||||
| 702 | method accessors using L<perlfunc/pack>, L<Win32::API/ReadMemory> and | ||||
| 703 | L<Win32::API/WriteMemory> around the pointer. | ||||
| 704 | |||||
| 705 | |||||
| 706 | =head1 AUTHOR | ||||
| 707 | |||||
| 708 | Aldo Calpini ( I<dada@perl.it> ). | ||||
| 709 | |||||
| 710 | =head1 MAINTAINER | ||||
| 711 | |||||
| 712 | Cosimo Streppone ( I<cosimo@cpan.org> ). | ||||
| 713 | |||||
| 714 | =cut |