| Filename | C:/tmp64ng/perl/vendor/lib/Win32/API.pm | 
| Statements | Executed 139 statements in 0s | 
| Calls | P | F | Exclusive Time  | 
        Inclusive Time  | 
        Subroutine | 
|---|---|---|---|---|---|
| 1 | 1 | 1 | 15.6ms | 15.6ms | Win32::API::BEGIN@62 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@17 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@18 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@19 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@20 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@26 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@30 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@36 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@537 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@63 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@64 | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::BEGIN@79 | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::CLONE | 
| 3 | 2 | 1 | 0s | 0s | Win32::API::CORE:match (opcode) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::CORE:pack (opcode) | 
| 2 | 2 | 1 | 0s | 0s | Win32::API::CORE:subst (opcode) | 
| 7 | 7 | 1 | 0s | 0s | Win32::API::DEBUG | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::DESTROY | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::GetMagicSV (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::GetProcAddress (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::ISCYG (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::Import | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::LoadLibrary (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::More::BEGIN@397 | 
| 0 | 0 | 0 | 0s | 0s | Win32::API::More::type_to_num | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::SetMagicSV (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::_Align (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::_ImportXS (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::bootstrap (xsub) | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::calltype_to_num | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::new | 
| 1 | 1 | 1 | 0s | 0s | Win32::API::parse_prototype | 
| 2 | 2 | 1 | 0s | 0s | Win32::API::type_to_num | 
| Line | State ments  | 
      Time on line  | 
      Calls | Time in subs  | 
      Code | 
|---|---|---|---|---|---|
| 1 | # See the bottom of this file for the POD documentation. Search for the | ||||
| 2 | # string '=head'. | ||||
| 3 | |||||
| 4 | ####################################################################### | ||||
| 5 | # | ||||
| 6 | # Win32::API - Perl Win32 API Import Facility | ||||
| 7 | # | ||||
| 8 | # Author: Aldo Calpini <dada@perl.it> | ||||
| 9 | # Maintainer: Cosimo Streppone <cosimo@cpan.org> | ||||
| 10 | # | ||||
| 11 | # Changes for gcc/cygwin: Daniel Risacher <magnus@alum.mit.edu> | ||||
| 12 | # ported from 0.41 based on Daniel's patch by Reini Urban <rurban@x-ray.at> | ||||
| 13 | # | ||||
| 14 | ####################################################################### | ||||
| 15 | |||||
| 16 | package Win32::API; | ||||
| 17 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@17 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 17     # spent     0s making 1 call to Win32::API::BEGIN@17
    # spent     0s making 1 call to strict::import  | 
| 18 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@18 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 18     # spent     0s making 1 call to Win32::API::BEGIN@18
    # spent     0s making 1 call to warnings::import  | 
| 19 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@19 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 19     # spent     0s making 1 call to Config::import
    # spent     0s making 1 call to Win32::API::BEGIN@19  | 
| 20 | # spent 0s within Win32::API::BEGIN@20 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 51  | ||||
| 21 | 1 | 0s | require Exporter; # to export the constants to the main:: space | ||
| 22 | 1 | 0s | require DynaLoader; # to dynuhlode the module. | ||
| 23 | |||||
| 24 | sub ISCYG (); | ||||
| 25 | 1 | 0s | eval "sub ISCYG () { ".($^O eq 'cygwin' ? 1 : 0)."}"; | ||
| 26 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@26 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 26     # spent     0s making 1 call to Win32::API::BEGIN@26
    # spent     0s making 1 call to warnings::unimport  | 
| 27 | 1 | 0s | 1 | 0s |     die "Win32::API on Cygwin requires the cygpath tool on PATH"     # spent     0s making 1 call to Win32::API::ISCYG  | 
| 28 | if ISCYG && index(`cygpath --help`,'Usage: cygpath') == -1; | ||||
| 29 | |||||
| 30 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@30 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 30     # spent     0s making 1 call to Win32::API::BEGIN@30
    # spent     0s making 1 call to vars::import  | 
| 31 | |||||
| 32 | 1 | 0s | @ISA = qw( Exporter DynaLoader ); | ||
| 33 | 1 | 0s | @EXPORT_OK = qw( ReadMemory IsBadReadPtr MoveMemory | ||
| 34 | WriteMemory SafeReadWideCString ); # symbols to export on request | ||||
| 35 | |||||
| 36 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@36 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 36     # spent     0s making 1 call to Exporter::import
    # spent     0s making 1 call to Win32::API::BEGIN@36  | 
| 37 | |||||
| 38 | 1 | 0s | $DEBUG = 0; | ||
| 39 | |||||
| 40 | sub ERROR_NOACCESS () { 998 } | ||||
| 41 | sub ERROR_NOT_ENOUGH_MEMORY () { 8 } | ||||
| 42 | sub ERROR_INVALID_PARAMETER () { 87 } | ||||
| 43 | sub APICONTROL_CC_STD () { 0 } | ||||
| 44 | sub APICONTROL_CC_C () { 1 } | ||||
| 45 | sub APICONTROL_CC_mask () { 0x7 } | ||||
| 46 | sub APICONTROL_UseMI64 () { 0x8 } | ||||
| 47 | sub APICONTROL_is_more () { 0x10 } | ||||
| 48 | sub APICONTROL_has_proto() { 0x20 } | ||||
| 49 | 1 | 0s | 1 | 0s |     eval " *Win32::API::Type::PTRSIZE = *Win32::API::More::PTRSIZE = *PTRSIZE = sub  () { ".$Config{ptrsize}." }";     # spent     0s making 1 call to Config::FETCH     # spent     0s executing statements in string eval  | 
| 50 | 1 | 0s | 1 | 0s |     eval " *Win32::API::Type::IVSIZE = *Win32::API::More::IVSIZE = *IVSIZE = sub  () { ".$Config{ivsize}." }";     # spent     0s making 1 call to Config::FETCH     # spent     0s executing statements in string eval  | 
| 51 | 1 | 0s | 1 | 0s | } # spent     0s making 1 call to Win32::API::BEGIN@20  | 
| 52 | |||||
| 53 | # spent 0s within Win32::API::DEBUG which was called 7 times, avg 0s/call:
#    once (0s+0s) by Win32::API::parse_prototype at line 526
#    once (0s+0s) by Win32::API::parse_prototype at line 570
#    once (0s+0s) by Win32::API::new at line 192
#    once (0s+0s) by Win32::API::new at line 114
#    once (0s+0s) by Win32::API::parse_prototype at line 525
#    once (0s+0s) by Win32::API::parse_prototype at line 583
#    once (0s+0s) by Win32::API::new at line 259  | ||||
| 54 | 7 | 0s | if ($Win32::API::DEBUG) { | ||
| 55 | printf @_ if @_ or return 1; | ||||
| 56 | } | ||||
| 57 | else { | ||||
| 58 | 7 | 0s | return 0; | ||
| 59 | } | ||||
| 60 | } | ||||
| 61 | |||||
| 62 | 2 | 0s | 2 | 15.6ms | # spent 15.6ms within Win32::API::BEGIN@62 which was called:
#    once (15.6ms+0s) by ExtUtils::MakeMaker::Locale::_init at line 62 # spent  15.6ms making 1 call to Win32::API::BEGIN@62
# spent     0s making 1 call to Exporter::import  | 
| 63 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@63 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 63 # spent     0s making 1 call to Exporter::import
# spent     0s making 1 call to Win32::API::BEGIN@63  | 
| 64 | 2 | 0s | 1 | 0s | # spent 0s within Win32::API::BEGIN@64 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 64 # spent     0s making 1 call to Win32::API::BEGIN@64  | 
| 65 | |||||
| 66 | ####################################################################### | ||||
| 67 | # STATIC OBJECT PROPERTIES | ||||
| 68 | # | ||||
| 69 | #### some package-global hash to | ||||
| 70 | #### keep track of the imported | ||||
| 71 | #### libraries and procedures | ||||
| 72 | 1 | 0s | my %Libraries = (); | ||
| 73 | 1 | 0s | my %Procedures = (); | ||
| 74 | |||||
| 75 | |||||
| 76 | ####################################################################### | ||||
| 77 | # dynamically load in the API extension module. | ||||
| 78 | # BEGIN required for constant subs in BOOT: | ||||
| 79 | # spent 0s within Win32::API::BEGIN@79 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 82  | ||||
| 80 | 1 | 0s | $VERSION = '0.79'; | ||
| 81 | 1 | 0s | 1 | 0s |     bootstrap Win32::API;     # spent     0s making 1 call to DynaLoader::bootstrap  | 
| 82 | 1 | 0s | 1 | 0s | } # spent     0s making 1 call to Win32::API::BEGIN@79  | 
| 83 | |||||
| 84 | ####################################################################### | ||||
| 85 | # PUBLIC METHODS | ||||
| 86 | # | ||||
| 87 | # spent 0s within Win32::API::new which was called:
#    once (0s+0s) by Win32::API::Import at line 267  | ||||
| 88 | 1 | 0s | die "Win32::API/More::new/Import is a class method that takes 2 to 6 parameters, see POD" | ||
| 89 | if @_ < 3 || @_ > 7; | ||||
| 90 | 1 | 0s | my ($class, $dll, $hproc, $ccnum, $outnum) = (shift, shift); | ||
| 91 | 1 | 0s | if(! defined $dll){ | ||
| 92 | $hproc = shift; | ||||
| 93 | } | ||||
| 94 | 1 | 0s | my ($proc, $in, $out, $callconvention) = @_; | ||
| 95 | 1 | 0s | my ($hdll, $freedll, $proto, $stackunwind) = (0, 0, 0, 0); | ||
| 96 | 1 | 0s | my $self = {}; | ||
| 97 | 1 | 0s | if(! defined $hproc){ | ||
| 98 | if (ISCYG() and $dll ne File::Basename::basename($dll)) { | ||||
| 99 | |||||
| 100 | # need to convert $dll to win32 path | ||||
| 101 | # isn't there an API for this? | ||||
| 102 | my $newdll = `cygpath -w "$dll"`; | ||||
| 103 | chomp $newdll; | ||||
| 104 | DEBUG "(PM)new: converted '$dll' to\n '$newdll'\n"; | ||||
| 105 | $dll = $newdll; | ||||
| 106 | } | ||||
| 107 | |||||
| 108 | #### avoid loading a library more than once | ||||
| 109 | 1 | 0s | if (exists($Libraries{$dll})) { | ||
| 110 | DEBUG "Win32::API::new: Library '$dll' already loaded, handle=$Libraries{$dll}\n"; | ||||
| 111 | $hdll = $Libraries{$dll}; | ||||
| 112 | } | ||||
| 113 | else { | ||||
| 114 | 1 | 0s | 1 | 0s |             DEBUG "Win32::API::new: Loading library '$dll'\n";             # spent     0s making 1 call to Win32::API::DEBUG  | 
| 115 | 1 | 0s | 1 | 0s |             $hdll = Win32::API::LoadLibrary($dll);             # spent     0s making 1 call to Win32::API::LoadLibrary  | 
| 116 | 1 | 0s | $freedll = 1; | ||
| 117 | # $Libraries{$dll} = $hdll; | ||||
| 118 | } | ||||
| 119 | |||||
| 120 | #### if the dll can't be loaded, set $! to Win32's GetLastError() | ||||
| 121 | 1 | 0s | if (!$hdll) { | ||
| 122 | $! = Win32::GetLastError(); | ||||
| 123 | DEBUG "FAILED Loading library '$dll': $^E\n"; | ||||
| 124 | return undef; | ||||
| 125 | } | ||||
| 126 | } | ||||
| 127 | else{ | ||||
| 128 | if(!looks_like_number($hproc) || IsBadReadPtr($hproc, 4)){ | ||||
| 129 | Win32::SetLastError(ERROR_NOACCESS); | ||||
| 130 | DEBUG "FAILED Function pointer '$hproc' is not a valid memory location\n"; | ||||
| 131 | return undef; | ||||
| 132 | } | ||||
| 133 | } | ||||
| 134 | #### determine if we have a prototype or not, outtype is for future use in XS | ||||
| 135 | 1 | 0s | if ((not defined $in) and (not defined $out)) { | ||
| 136 | 1 | 0s | 1 | 0s |         ($proc, $self->{in}, $self->{intypes}, $outnum, $self->{outtype},         # spent     0s making 1 call to Win32::API::parse_prototype  | 
| 137 | $ccnum) = parse_prototype($class, $proc); | ||||
| 138 | 1 | 0s | if( ! $proc ){ | ||
| 139 | Win32::API::FreeLibrary($hdll) if $freedll; | ||||
| 140 | Win32::SetLastError(ERROR_INVALID_PARAMETER); | ||||
| 141 | return undef; | ||||
| 142 | } | ||||
| 143 | 1 | 0s | $proto = 1; | ||
| 144 | } | ||||
| 145 | else { | ||||
| 146 | $self->{in} = []; | ||||
| 147 | my $self_in = $self->{in}; #avoid hash derefing | ||||
| 148 | if (ref($in) eq 'ARRAY') { | ||||
| 149 | foreach (@$in) { | ||||
| 150 | push(@{$self_in}, $class->type_to_num($_)); | ||||
| 151 | } | ||||
| 152 | } | ||||
| 153 | else { | ||||
| 154 | my @in = split '', $in; | ||||
| 155 | foreach (@in) { | ||||
| 156 | push(@{$self_in}, $class->type_to_num($_)); | ||||
| 157 | } | ||||
| 158 | }#'V' must be one and ONLY letter for "in" | ||||
| 159 | foreach(@{$self_in}){ | ||||
| 160 | if($_ == 0){ | ||||
| 161 | if(@{$self_in} != 1){ | ||||
| 162 | Win32::API::FreeLibrary($hdll) if $freedll; | ||||
| 163 | die "Win32::API 'V' for in prototype must be the only parameter"; | ||||
| 164 | } else {undef(@{$self_in});} #empty arr, as if in param was "" | ||||
| 165 | } | ||||
| 166 | } | ||||
| 167 | $outnum = $class->type_to_num($out, 1); | ||||
| 168 | $ccnum = calltype_to_num($callconvention); | ||||
| 169 | } | ||||
| 170 | |||||
| 171 | 1 | 0s | if(!$hproc){ #if not non DLL func | ||
| 172 | #### first try to import the function of given name... | ||||
| 173 | 1 | 0s | 1 | 0s |         $hproc = Win32::API::GetProcAddress($hdll, $proc);         # spent     0s making 1 call to Win32::API::GetProcAddress  | 
| 174 | |||||
| 175 | #### ...then try appending either A or W (for ASCII or Unicode) | ||||
| 176 | 1 | 0s | if (!$hproc) { | ||
| 177 | my $tproc = $proc; | ||||
| 178 | $tproc .= (IsUnicode() ? "W" : "A"); | ||||
| 179 | |||||
| 180 | # print "Win32::API::new: procedure not found, trying '$tproc'...\n"; | ||||
| 181 | $hproc = Win32::API::GetProcAddress($hdll, $tproc); | ||||
| 182 | } | ||||
| 183 | |||||
| 184 | #### ...if all that fails, give up, $! setting is back compat, $! is deprecated | ||||
| 185 | 1 | 0s | if (!$hproc) { | ||
| 186 | my $err = $! = Win32::GetLastError(); | ||||
| 187 | DEBUG "FAILED GetProcAddress for Proc '$proc': $^E\n"; | ||||
| 188 | Win32::API::FreeLibrary($hdll) if $freedll; | ||||
| 189 | Win32::SetLastError($err); | ||||
| 190 | return undef; | ||||
| 191 | } | ||||
| 192 | 1 | 0s | 1 | 0s |         DEBUG "GetProcAddress('$proc') = '$hproc'\n";         # spent     0s making 1 call to Win32::API::DEBUG  | 
| 193 | } | ||||
| 194 | else { | ||||
| 195 | DEBUG "Using non-DLL function pointer '$hproc' for '$proc'\n"; | ||||
| 196 | } | ||||
| 197 | if(PTRSIZE == 4 && $ccnum == APICONTROL_CC_C) {#fold out on WIN64 | ||||
| 198 | #calculate add to ESP amount, in units of 4, will be *4ed later | ||||
| 199 | $stackunwind += $_ == T_QUAD || $_ == T_DOUBLE ? 2 : 1 for(@{$self->{in}}); | ||||
| 200 | if($stackunwind > 0xFFFF) { | ||||
| 201 | goto too_many_in_params; | ||||
| 202 | } | ||||
| 203 | } | ||||
| 204 | # if a prototype has 8 byte types on 32bit, $stackunwind will be higher than | ||||
| 205 | # length of {in} letter array, so 2 different checks need to be done | ||||
| 206 | 1 | 0s | if($#{$self->{in}} > 0xFFFF) { | ||
| 207 | too_many_in_params: | ||||
| 208 | DEBUG "FAILED This function has too many parameters (> ~65535) \n"; | ||||
| 209 | Win32::API::FreeLibrary($hdll) if $freedll; | ||||
| 210 | Win32::SetLastError(ERROR_NOT_ENOUGH_MEMORY); | ||||
| 211 | return undef; | ||||
| 212 | } | ||||
| 213 | #### ok, let's stuff the object | ||||
| 214 | 1 | 0s | $self->{procname} = $proc; | ||
| 215 | 1 | 0s | $self->{dll} = $hdll; | ||
| 216 | 1 | 0s | $self->{dllname} = $dll; | ||
| 217 | |||||
| 218 | 1 | 0s | $outnum &= ~T_FLAG_NUMERIC; | ||
| 219 | 1 | 0s | my $control; | ||
| 220 | 1 | 0s | $self->{weakapi} = \$control; | ||
| 221 | 1 | 0s | 1 | 0s |     weaken($self->{weakapi});     # spent     0s making 1 call to Scalar::Util::weaken  | 
| 222 | $control = pack( 'L' | ||||
| 223 | .'L' | ||||
| 224 | .(PTRSIZE == 8 ? 'Q' : 'L') | ||||
| 225 | .(PTRSIZE == 8 ? 'Q' : 'L') | ||||
| 226 | .(PTRSIZE == 8 ? 'Q' : 'L') | ||||
| 227 | .(PTRSIZE == 8 ? '' : 'L') | ||||
| 228 | ,($class eq "Win32::API::More" ? APICONTROL_is_more : 0) | ||||
| 229 | | ($proto ? APICONTROL_has_proto : 0) | ||||
| 230 | | $ccnum | ||||
| 231 | | (PTRSIZE == 8 ? 0 : $stackunwind << 8) | ||||
| 232 | | $outnum << 24 | ||||
| 233 | 1 | 0s | 1 | 0s |                         , scalar(@{$self->{in}}) * PTRSIZE #in param count, in SV * units                         # spent     0s making 1 call to Win32::API::CORE:pack  | 
| 234 | , $hproc | ||||
| 235 | , \($self->{weakapi})+0 #weak api obj ref | ||||
| 236 | , (exists $self->{intypes} ? ($self->{intypes})+0 : 0) | ||||
| 237 | , 0); #padding to align to 8 bytes on 32 bit only | ||||
| 238 | #align to 16 bytes | ||||
| 239 | 1 | 0s | $control .= "\x00" x ((((length($control)+ 15) >> 4) << 4)-length($control)); | ||
| 240 | #make a APIPARAM template array | ||||
| 241 | 1 | 0s | my ($i, $arr_end) = (0, scalar(@{$self->{in}})); | ||
| 242 | 1 | 0s | for(; $i< $arr_end; $i++) { | ||
| 243 | my $tin = $self->{in}[$i]; | ||||
| 244 | #unsigned meaningless no sign vs zero extends are done bc uv/iv is | ||||
| 245 | #the biggest native integer on the cpu, big to small is truncation | ||||
| 246 | #numeric is implemented as T_NUMCHAR for in, keeps asm jumptable clean | ||||
| 247 | $tin &= ~(T_FLAG_UNSIGNED|T_FLAG_NUMERIC); | ||||
| 248 | $tin--; #T_VOID doesn't exist as in param in XS | ||||
| 249 | #put index of param array slice in unused space for croaks, why not? | ||||
| 250 | $control .= "\x00" x 8 . pack('CCSSS', $tin, 0, 0, $i, $i+1); | ||||
| 251 | } | ||||
| 252 | 1 | 0s | 1 | 0s |     _Align($control, 16); #align the whole PVX to 16 bytes for SSE moves     # spent     0s making 1 call to Win32::API::_Align  | 
| 253 | |||||
| 254 | #### keep track of the imported function | ||||
| 255 | 1 | 0s | if(defined $dll){ | ||
| 256 | 1 | 0s | $Libraries{$dll} = $hdll; | ||
| 257 | 1 | 0s | $Procedures{$dll}++; | ||
| 258 | } | ||||
| 259 | 1 | 0s | 1 | 0s |     DEBUG "Object blessed!\n";     # spent     0s making 1 call to Win32::API::DEBUG  | 
| 260 | |||||
| 261 | 1 | 0s | my $ref = bless(\$control, $class); | ||
| 262 | 1 | 0s | 1 | 0s |     SetMagicSV($ref, $self);     # spent     0s making 1 call to Win32::API::SetMagicSV  | 
| 263 | 1 | 0s | return $ref; | ||
| 264 | } | ||||
| 265 | |||||
| 266 | # spent 0s within Win32::API::Import which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 30 of ExtUtils/MakeMaker/Locale.pm  | ||||
| 267 | 1 | 0s | 1 | 0s |     my $closure = shift->new(@_)     # spent     0s making 1 call to Win32::API::new  | 
| 268 | or return undef; | ||||
| 269 | 1 | 0s | 1 | 0s |     my $procname = ${Win32::API::GetMagicSV($closure)}{procname};     # spent     0s making 1 call to Win32::API::GetMagicSV  | 
| 270 | #dont allow "sub main:: {0;}" | ||||
| 271 | 1 | 0s | Win32::SetLastError(ERROR_INVALID_PARAMETER), return undef if $procname eq ''; | ||
| 272 | 1 | 0s | 1 | 0s |     _ImportXS($closure, (caller)[0].'::'.$procname);     # spent     0s making 1 call to Win32::API::_ImportXS  | 
| 273 | 1 | 0s | return $closure; | ||
| 274 | } | ||||
| 275 | |||||
| 276 | ####################################################################### | ||||
| 277 | # PRIVATE METHODS | ||||
| 278 | # | ||||
| 279 | sub DESTROY { | ||||
| 280 | my ($self) = GetMagicSV($_[0]); | ||||
| 281 | |||||
| 282 | return if ! defined $self->{dllname}; | ||||
| 283 | #### decrease this library's procedures reference count | ||||
| 284 | $Procedures{$self->{dllname}}--; | ||||
| 285 | |||||
| 286 | #### once it reaches 0, free it | ||||
| 287 | if ($Procedures{$self->{dllname}} == 0) { | ||||
| 288 | DEBUG "Win32::API::DESTROY: Freeing library '$self->{dllname}'\n"; | ||||
| 289 | Win32::API::FreeLibrary($Libraries{$self->{dllname}}); | ||||
| 290 | delete($Libraries{$self->{dllname}}); | ||||
| 291 | } | ||||
| 292 | } | ||||
| 293 | |||||
| 294 | # Convert calling convention string (_cdecl|__stdcall) | ||||
| 295 | # to a C const. Unknown counts as __stdcall | ||||
| 296 | # | ||||
| 297 | # spent 0s within Win32::API::calltype_to_num which was called:
#    once (0s+0s) by Win32::API::parse_prototype at line 588  | ||||
| 298 | 1 | 0s | my $type = shift; | ||
| 299 | |||||
| 300 | 1 | 0s | if (!$type || $type eq "__stdcall" || $type eq "WINAPI" || $type eq "NTAPI" | ||
| 301 | || $type eq "CALLBACK" ) { | ||||
| 302 | return APICONTROL_CC_STD; | ||||
| 303 | } | ||||
| 304 | elsif ($type eq "_cdecl" || $type eq "__cdecl" || $type eq "WINAPIV") { | ||||
| 305 | return APICONTROL_CC_C; | ||||
| 306 | } | ||||
| 307 | else { | ||||
| 308 | warn "unknown calling convention: '$type'"; | ||||
| 309 | return APICONTROL_CC_STD; | ||||
| 310 | } | ||||
| 311 | } | ||||
| 312 | |||||
| 313 | |||||
| 314 | sub type_to_num { | ||||
| 315 | 2 | 0s | die "wrong class" if shift ne "Win32::API"; | ||
| 316 | 2 | 0s | my $type = shift; | ||
| 317 | 2 | 0s | my $out = shift; | ||
| 318 | 2 | 0s | my ($num, $numeric); | ||
| 319 | 2 | 0s | if(index($type, 'num', 0) == 0){ | ||
| 320 | substr($type, 0, length('num'), ''); | ||||
| 321 | $numeric = 1; | ||||
| 322 | } | ||||
| 323 | else{ | ||||
| 324 | 2 | 0s | $numeric = 0; | ||
| 325 | } | ||||
| 326 | |||||
| 327 | 2 | 0s | if ( $type eq 'N' | ||
| 328 | or $type eq 'n' | ||||
| 329 | or $type eq 'l' | ||||
| 330 | or $type eq 'L' | ||||
| 331 | or ( PTRSIZE == 8 and $type eq 'Q' || $type eq 'q')) | ||||
| 332 | { | ||||
| 333 | $num = T_NUMBER; | ||||
| 334 | } | ||||
| 335 | elsif ($type eq 'P' | ||||
| 336 | or $type eq 'p') | ||||
| 337 | { | ||||
| 338 | $num = T_POINTER; | ||||
| 339 | } | ||||
| 340 | elsif ($type eq 'I' | ||||
| 341 | or $type eq 'i') | ||||
| 342 | { | ||||
| 343 | $num = T_INTEGER; | ||||
| 344 | } | ||||
| 345 | elsif ($type eq 'f' | ||||
| 346 | or $type eq 'F') | ||||
| 347 | { | ||||
| 348 | $num = T_FLOAT; | ||||
| 349 | } | ||||
| 350 | elsif ($type eq 'D' | ||||
| 351 | or $type eq 'd') | ||||
| 352 | { | ||||
| 353 | $num = T_DOUBLE; | ||||
| 354 | } | ||||
| 355 | elsif ($type eq 'c' | ||||
| 356 | or $type eq 'C') | ||||
| 357 | { | ||||
| 358 | $num = $numeric ? T_NUMCHAR : T_CHAR; | ||||
| 359 | } | ||||
| 360 | elsif (PTRSIZE == 4 and $type eq 'q' || $type eq 'Q') | ||||
| 361 | { | ||||
| 362 | $num = T_QUAD; | ||||
| 363 | } | ||||
| 364 | elsif($type eq '>'){ | ||||
| 365 | die "Win32::API does not support pass by copy structs as function arguments"; | ||||
| 366 | } | ||||
| 367 | else { | ||||
| 368 | $num = T_VOID; #'V' takes this branch, which is T_VOID in C | ||||
| 369 | }#not valid return types of the C func | ||||
| 370 | 2 | 0s | if(defined $out) {#b/B remains private/undocumented | ||
| 371 | 2 | 0s | 2 | 0s |         die "Win32::API invalid return type, structs and ".         # spent     0s making 2 calls to Win32::API::CORE:match, avg 0s/call  | 
| 372 | "callbacks as return types not supported" | ||||
| 373 | if($type =~ m/^s|S|t|T|b|B|k|K$/); | ||||
| 374 | } | ||||
| 375 | else {#in type | ||||
| 376 | if ($type eq 's' or $type eq 'S' or $type eq 't' or $type eq 'T') | ||||
| 377 | { | ||||
| 378 | $num = T_STRUCTURE; | ||||
| 379 | } | ||||
| 380 | elsif ($type eq 'b' | ||||
| 381 | or $type eq 'B') | ||||
| 382 | { | ||||
| 383 | $num = T_POINTERPOINTER; | ||||
| 384 | } | ||||
| 385 | elsif ($type eq 'k' | ||||
| 386 | or $type eq 'K') | ||||
| 387 | { | ||||
| 388 | $num = T_CODE; | ||||
| 389 | } | ||||
| 390 | } | ||||
| 391 | 2 | 0s | $num |= T_FLAG_NUMERIC if $numeric; | ||
| 392 | 2 | 0s | return $num; | ||
| 393 | } | ||||
| 394 | |||||
| 395 | package Win32::API::More; | ||||
| 396 | |||||
| 397 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::More::BEGIN@397 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 397 # spent     0s making 1 call to Win32::API::More::BEGIN@397
# spent     0s making 1 call to vars::import  | 
| 398 | 1 | 0s | @ISA = qw ( Win32::API ); | ||
| 399 | sub type_to_num { | ||||
| 400 | die "wrong class" if shift ne "Win32::API::More"; | ||||
| 401 | my $type = shift; | ||||
| 402 | my $out = shift; | ||||
| 403 | my ($num, $numeric); | ||||
| 404 | if(index($type, 'num', 0) == 0){ | ||||
| 405 | substr($type, 0, length('num'), ''); | ||||
| 406 | $numeric = 1; | ||||
| 407 | } | ||||
| 408 | else{ | ||||
| 409 | $numeric = 0; | ||||
| 410 | } | ||||
| 411 | |||||
| 412 | if ( $type eq 'N' | ||||
| 413 | or $type eq 'n' | ||||
| 414 | or $type eq 'l' | ||||
| 415 | or $type eq 'L' | ||||
| 416 | or ( PTRSIZE == 8 and $type eq 'Q' || $type eq 'q') | ||||
| 417 | or (! $out and # in XS short 'in's are interger/numbers code | ||||
| 418 | $type eq 'S' | ||||
| 419 | || $type eq 's')) | ||||
| 420 | { | ||||
| 421 | $num = Win32::API::T_NUMBER; | ||||
| 422 | if(defined $out && ($type eq 'N' || $type eq 'L' | ||||
| 423 | || $type eq 'S' || $type eq 'Q')){ | ||||
| 424 | $num |= Win32::API::T_FLAG_UNSIGNED; | ||||
| 425 | } | ||||
| 426 | } | ||||
| 427 | elsif ($type eq 'P' | ||||
| 428 | or $type eq 'p') | ||||
| 429 | { | ||||
| 430 | $num = Win32::API::T_POINTER; | ||||
| 431 | } | ||||
| 432 | elsif ($type eq 'I' | ||||
| 433 | or $type eq 'i') | ||||
| 434 | { | ||||
| 435 | $num = Win32::API::T_INTEGER; | ||||
| 436 | if(defined $out && $type eq 'I'){ | ||||
| 437 | $num |= Win32::API::T_FLAG_UNSIGNED; | ||||
| 438 | } | ||||
| 439 | } | ||||
| 440 | elsif ($type eq 'f' | ||||
| 441 | or $type eq 'F') | ||||
| 442 | { | ||||
| 443 | $num = Win32::API::T_FLOAT; | ||||
| 444 | } | ||||
| 445 | elsif ($type eq 'D' | ||||
| 446 | or $type eq 'd') | ||||
| 447 | { | ||||
| 448 | $num = Win32::API::T_DOUBLE; | ||||
| 449 | } | ||||
| 450 | elsif ($type eq 'c' | ||||
| 451 | or $type eq 'C') | ||||
| 452 | { | ||||
| 453 | $num = $numeric ? Win32::API::T_NUMCHAR : Win32::API::T_CHAR; | ||||
| 454 | if(defined $out && $type eq 'C'){ | ||||
| 455 | $num |= Win32::API::T_FLAG_UNSIGNED; | ||||
| 456 | } | ||||
| 457 | } | ||||
| 458 | elsif (PTRSIZE == 4 and $type eq 'q' || $type eq 'Q') | ||||
| 459 | { | ||||
| 460 | $num = Win32::API::T_QUAD; | ||||
| 461 | if(defined $out && $type eq 'Q'){ | ||||
| 462 | $num |= Win32::API::T_FLAG_UNSIGNED; | ||||
| 463 | } | ||||
| 464 | } | ||||
| 465 | elsif ($type eq 's') #4 is only used for out params | ||||
| 466 | { | ||||
| 467 | $num = Win32::API::T_SHORT; | ||||
| 468 | } | ||||
| 469 | elsif ($type eq 'S') | ||||
| 470 | { | ||||
| 471 | $num = Win32::API::T_SHORT | Win32::API::T_FLAG_UNSIGNED; | ||||
| 472 | } | ||||
| 473 | elsif($type eq '>'){ | ||||
| 474 | die "Win32::API does not support pass by copy structs as function arguments"; | ||||
| 475 | } | ||||
| 476 | else { | ||||
| 477 | $num = Win32::API::T_VOID; #'V' takes this branch, which is T_VOID in C | ||||
| 478 | } #not valid return types of the C func | ||||
| 479 | if(defined $out) {#b/B remains private/undocumented | ||||
| 480 | die "Win32::API invalid return type, structs and ". | ||||
| 481 | "callbacks as return types not supported" | ||||
| 482 | if($type =~ m/^t|T|b|B|k|K$/); | ||||
| 483 | } | ||||
| 484 | else {#in type | ||||
| 485 | if ( $type eq 't' | ||||
| 486 | or $type eq 'T') | ||||
| 487 | { | ||||
| 488 | $num = Win32::API::T_STRUCTURE; | ||||
| 489 | } | ||||
| 490 | elsif ($type eq 'b' | ||||
| 491 | or $type eq 'B') | ||||
| 492 | { | ||||
| 493 | $num = Win32::API::T_POINTERPOINTER; | ||||
| 494 | } | ||||
| 495 | elsif ($type eq 'k' | ||||
| 496 | or $type eq 'K') | ||||
| 497 | { | ||||
| 498 | $num = Win32::API::T_CODE; | ||||
| 499 | } | ||||
| 500 | } | ||||
| 501 | $num |= Win32::API::T_FLAG_NUMERIC if $numeric; | ||||
| 502 | return $num; | ||||
| 503 | } | ||||
| 504 | package Win32::API; | ||||
| 505 | |||||
| 506 | # spent 0s within Win32::API::parse_prototype which was called:
#    once (0s+0s) by Win32::API::new at line 136  | ||||
| 507 | 1 | 0s | my ($class, $proto) = @_; | ||
| 508 | |||||
| 509 | 1 | 0s | my @in_params = (); | ||
| 510 | 1 | 0s | my @in_types = (); #one day create a BNF-ish formal grammer parser here | ||
| 511 | 1 | 0s | 1 | 0s |     if ($proto =~ /^\s*((?:(?:un|)signed\s+|) #optional signedness     # spent     0s making 1 call to Win32::API::CORE:match  | 
| 512 | \S+)(?:\s*(\*)\s*|\s+) #type and maybe a * | ||||
| 513 | (?:(\w+)\s+)? # maybe a calling convention | ||||
| 514 | (\S+)\s* #func name | ||||
| 515 | \(([^\)]*)\) #param list | ||||
| 516 | /x) { | ||||
| 517 | 1 | 0s | my $ret = $1.(defined($2)?$2:''); | ||
| 518 | 1 | 0s | my $callconvention = $3; | ||
| 519 | 1 | 0s | my $proc = $4; | ||
| 520 | 1 | 0s | my $params = $5; | ||
| 521 | |||||
| 522 | 1 | 0s | 1 | 0s |         $params =~ s/^\s+//;         # spent     0s making 1 call to Win32::API::CORE:subst  | 
| 523 | 1 | 0s | 1 | 0s |         $params =~ s/\s+$//;         # spent     0s making 1 call to Win32::API::CORE:subst  | 
| 524 | |||||
| 525 | 1 | 0s | 1 | 0s |         DEBUG "(PM)parse_prototype: got PROC '%s'\n",   $proc;         # spent     0s making 1 call to Win32::API::DEBUG  | 
| 526 | 1 | 0s | 1 | 0s |         DEBUG "(PM)parse_prototype: got PARAMS '%s'\n", $params;         # spent     0s making 1 call to Win32::API::DEBUG  | 
| 527 | |||||
| 528 | 1 | 0s | foreach my $param (split(/\s*,\s*/, $params)) { | ||
| 529 | my ($type, $name); | ||||
| 530 | #match "in_t* _var" "in_t * _var" "in_t *_var" "in_t _var" "in_t*_var" supported | ||||
| 531 | #unsigned or signed or nothing as prefix supported | ||||
| 532 | # "in_t ** _var" and "const in_t* var" not supported | ||||
| 533 | if ($param =~ /((?:(?:un|)signed\s+|)\w+)(?:\s*(\*)\s*|\s+)(\w+)/) { | ||||
| 534 | ($type, $name) = ($1.(defined($2)? $2:''), $3); | ||||
| 535 | } | ||||
| 536 | { | ||||
| 537 | 2 | 0s | 2 | 0s | # spent 0s within Win32::API::BEGIN@537 which was called:
#    once (0s+0s) by ExtUtils::MakeMaker::Locale::_init at line 537                 # spent     0s making 1 call to Win32::API::BEGIN@537
                # spent     0s making 1 call to warnings::unimport  | 
| 538 | if($type eq '') {goto BADPROTO;} #something very wrong, bail out | ||||
| 539 | } | ||||
| 540 | my $packing = Win32::API::Type::packing($type); | ||||
| 541 | if (defined $packing && $packing ne '>') { | ||||
| 542 | if (Win32::API::Type::is_pointer($type)) { | ||||
| 543 | DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n", | ||||
| 544 | $type, | ||||
| 545 | $packing, | ||||
| 546 | $class->type_to_num('P'); | ||||
| 547 | push(@in_params, $class->type_to_num('P')); | ||||
| 548 | } | ||||
| 549 | else { | ||||
| 550 | DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n", | ||||
| 551 | $type, | ||||
| 552 | $packing, | ||||
| 553 | $class->type_to_num(Win32::API::Type->packing($type, undef, 1)); | ||||
| 554 | push(@in_params, $class->type_to_num(Win32::API::Type->packing($type, undef, 1))); | ||||
| 555 | } | ||||
| 556 | } | ||||
| 557 | elsif (Win32::API::Struct::is_known($type)) { | ||||
| 558 | DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n", | ||||
| 559 | $type, 'T', Win32::API::More->type_to_num('T'); | ||||
| 560 | push(@in_params, Win32::API::More->type_to_num('T')); | ||||
| 561 | } | ||||
| 562 | else { | ||||
| 563 | warn | ||||
| 564 | "Win32::API::parse_prototype: WARNING unknown parameter type '$type'"; | ||||
| 565 | push(@in_params, $class->type_to_num('I')); | ||||
| 566 | } | ||||
| 567 | push(@in_types, $type); | ||||
| 568 | |||||
| 569 | } | ||||
| 570 | 1 | 0s | 1 | 0s |         DEBUG "parse_prototype: IN=[ @in_params ]\n";         # spent     0s making 1 call to Win32::API::DEBUG  | 
| 571 | |||||
| 572 | |||||
| 573 | 1 | 0s | 1 | 0s |         if (Win32::API::Type::is_known($ret)) {         # spent     0s making 1 call to Win32::API::Type::is_known  | 
| 574 | 1 | 0s | 1 | 0s |             if (Win32::API::Type::is_pointer($ret)) {             # spent     0s making 1 call to Win32::API::Type::is_pointer  | 
| 575 | DEBUG "parse_prototype: OUT='%s' PACKING='%s' API_TYPE=%d\n", | ||||
| 576 | $ret, | ||||
| 577 | Win32::API::Type->packing($ret), | ||||
| 578 | $class->type_to_num('P'); | ||||
| 579 | return ($proc, \@in_params, \@in_types, $class->type_to_num('P', 1), | ||||
| 580 | $ret, calltype_to_num($callconvention)); | ||||
| 581 | } | ||||
| 582 | else { | ||||
| 583 | 1 | 0s | 4 | 0s |                 DEBUG "parse_prototype: OUT='%s' PACKING='%s' API_TYPE=%d\n",                 # spent     0s making 1 call to Win32::API::DEBUG
                # spent     0s making 2 calls to Win32::API::Type::packing, avg 0s/call
                # spent     0s making 1 call to Win32::API::type_to_num  | 
| 584 | $ret, | ||||
| 585 | Win32::API::Type->packing($ret), | ||||
| 586 | $class->type_to_num(Win32::API::Type->packing($ret, undef, 1), 1); | ||||
| 587 | return ( | ||||
| 588 | 1 | 0s | 3 | 0s |                     $proc, \@in_params, \@in_types,                     # spent     0s making 1 call to Win32::API::Type::packing
                    # spent     0s making 1 call to Win32::API::calltype_to_num
                    # spent     0s making 1 call to Win32::API::type_to_num  | 
| 589 | $class->type_to_num(Win32::API::Type->packing($ret, undef, 1), 1), | ||||
| 590 | $ret, calltype_to_num($callconvention) | ||||
| 591 | ); | ||||
| 592 | } | ||||
| 593 | } | ||||
| 594 | else { | ||||
| 595 | warn | ||||
| 596 | "Win32::API::parse_prototype: WARNING unknown output parameter type '$ret'"; | ||||
| 597 | return ($proc, \@in_params, \@in_types, $class->type_to_num('I', 1), | ||||
| 598 | $ret, calltype_to_num($callconvention)); | ||||
| 599 | } | ||||
| 600 | |||||
| 601 | } | ||||
| 602 | else { | ||||
| 603 | BADPROTO: | ||||
| 604 | warn "Win32::API::parse_prototype: bad prototype '$proto'"; | ||||
| 605 | return undef; | ||||
| 606 | } | ||||
| 607 | } | ||||
| 608 | |||||
| 609 | # | ||||
| 610 | # XXX hack, see the proper implementation in TODO | ||||
| 611 | # The point here is don't let fork children free the parent's DLLs. | ||||
| 612 | # CLONE runs on ::API and ::More, that's bad and causes a DLL leak, make sure | ||||
| 613 | # CLONE dups the DLL handles only once per CLONE | ||||
| 614 | # GetModuleHandleEx was not used since that is a WinXP and newer function, not Win2K. | ||||
| 615 | # GetModuleFileName was used to get full DLL pathname incase SxS/multiple DLLs | ||||
| 616 | # with same file name exist in the process. Even if the dll was loaded as a | ||||
| 617 | # relative path initially, later SxS can load a DLL with a different full path | ||||
| 618 | # yet same file name, and then LoadLibrary'ing the original relative path | ||||
| 619 | # might increase the refcount on the wrong DLL or return a different HMODULE | ||||
| 620 | sub CLONE { | ||||
| 621 | return if $_[0] ne "Win32::API"; | ||||
| 622 | |||||
| 623 | _my_cxt_clone(); | ||||
| 624 | foreach( keys %Libraries){ | ||||
| 625 | if($Libraries{$_} != Win32::API::LoadLibrary(Win32::API::GetModuleFileName($Libraries{$_}))){ | ||||
| 626 | die "Win32::API::CLONE unable to clone DLL \"$Libraries{$_}\" Unicode Problem??"; | ||||
| 627 | } | ||||
| 628 | } | ||||
| 629 | } | ||||
| 630 | |||||
| 631 | 1 | 0s | 1; | ||
| 632 | |||||
| 633 | __END__ | ||||
sub Win32::API::CORE:match; # opcode  | |||||
# spent 0s within Win32::API::CORE:pack which was called:
#    once (0s+0s) by Win32::API::new at line 233  | |||||
sub Win32::API::CORE:subst; # opcode  | |||||
# spent 0s within Win32::API::GetMagicSV which was called:
#    once (0s+0s) by Win32::API::Import at line 269  | |||||
# spent 0s within Win32::API::GetProcAddress which was called:
#    once (0s+0s) by Win32::API::new at line 173  | |||||
# spent 0s within Win32::API::ISCYG which was called:
#    once (0s+0s) by Win32::API::BEGIN@20 at line 27  | |||||
# spent 0s within Win32::API::LoadLibrary which was called:
#    once (0s+0s) by Win32::API::new at line 115  | |||||
# spent 0s within Win32::API::SetMagicSV which was called:
#    once (0s+0s) by Win32::API::new at line 262  | |||||
# spent 0s within Win32::API::_Align which was called:
#    once (0s+0s) by Win32::API::new at line 252  | |||||
# spent 0s within Win32::API::_ImportXS which was called:
#    once (0s+0s) by Win32::API::Import at line 272  | |||||
# spent 0s within Win32::API::bootstrap which was called:
#    once (0s+0s) by DynaLoader::bootstrap at line 216 of DynaLoader.pm  |