1b39c5158Smillertpackage OS2::DLL; 2b39c5158Smillert 3*9f11ffb7Safresh1our $VERSION = '1.07'; 4b39c5158Smillert 5b39c5158Smillertuse Carp; 6b39c5158Smillertuse XSLoader; 7b39c5158Smillert 8b39c5158Smillert@libs = split(/;/, $ENV{'PERL5REXX'} || $ENV{'PERLREXX'} || $ENV{'LIBPATH'} || $ENV{'PATH'}); 9b39c5158Smillert%dlls = (); 10b39c5158Smillert 11b39c5158Smillert# Preloaded methods go here. Autoload methods go after __END__, and are 12b39c5158Smillert# processed by the autosplit program. 13b39c5158Smillert 14b39c5158Smillert# Cannot be autoload, the autoloader is used for the REXX functions. 15b39c5158Smillert 16b39c5158Smillertmy $load_with_dirs = sub { 17b39c5158Smillert my ($class, $file, @where) = (@_); 18b39c5158Smillert return $dlls{$file} if $dlls{$file}; 19b39c5158Smillert my $handle; 20b39c5158Smillert foreach (@where) { 21b39c5158Smillert $handle = DynaLoader::dl_load_file("$_/$file.dll"); 22b39c5158Smillert last if $handle; 23b39c5158Smillert } 24b39c5158Smillert $handle = DynaLoader::dl_load_file($file) unless $handle; 25b39c5158Smillert return undef unless $handle; 26b39c5158Smillert my @packs = $INC{'OS2/REXX.pm'} ? qw(OS2::DLL::dll OS2::REXX) : 'OS2::DLL::dll'; 27b39c5158Smillert my $p = "OS2::DLL::dll::$file"; 28b39c5158Smillert @{"$p\::ISA"} = @packs; 29b39c5158Smillert *{"$p\::AUTOLOAD"} = \&OS2::DLL::dll::AUTOLOAD; 30b39c5158Smillert return $dlls{$file} = 31b39c5158Smillert bless {Handle => $handle, File => $file, Queue => 'SESSION' }, $p; 32b39c5158Smillert}; 33b39c5158Smillert 34b39c5158Smillertmy $new_dll = sub { 35b39c5158Smillert my ($dirs, $class, $file) = (shift, shift, shift); 36b39c5158Smillert my $handle; 37b39c5158Smillert push @_, @libs if $dirs; 38b39c5158Smillert $handle = $load_with_dirs->($class, $file, @_) 39b39c5158Smillert and return $handle; 40b39c5158Smillert my $path = @_ ? " from '@_'" : ''; 41b39c5158Smillert my $err = DynaLoader::dl_error(); 42b39c5158Smillert $err =~ s/\s+at\s+\S+\s+line\s+\S+\s*\z//; 43b39c5158Smillert croak "Can't load '$file'$path: $err"; 44b39c5158Smillert}; 45b39c5158Smillert 46b39c5158Smillertsub new { 47b39c5158Smillert confess 'Usage: OS2::DLL->new( <file> [<dirs>] )' unless @_ >= 2; 48b39c5158Smillert $new_dll->(1, @_); 49b39c5158Smillert} 50b39c5158Smillert 51b39c5158Smillertsub module { 52b39c5158Smillert confess 'Usage: OS2::DLL->module( <file> [<dirs>] )' unless @_ >= 2; 53b39c5158Smillert $new_dll->(0, @_); 54b39c5158Smillert} 55b39c5158Smillert 56b39c5158Smillertsub load { 57b39c5158Smillert confess 'Usage: load OS2::DLL <file> [<dirs>]' unless $#_ >= 1; 58b39c5158Smillert $load_with_dirs->(@_, @libs); 59b39c5158Smillert} 60b39c5158Smillert 61b39c5158Smillertsub libPath_find { 62b39c5158Smillert my ($name, $flags, @path) = (shift, shift); 63b39c5158Smillert $flags = 0x7 unless defined $flags; 64b39c5158Smillert push @path, split /;/, OS2::extLibpath if $flags & 0x1; # BEGIN 65b39c5158Smillert push @path, split /;/, OS2::libPath if $flags & 0x2; 66b39c5158Smillert push @path, split /;/, OS2::extLibpath(1) if $flags & 0x4; # END 67b39c5158Smillert s,(?![/\\])$,/, for @path; 68b39c5158Smillert s,\\,/,g for @path; 69b39c5158Smillert $name .= ".dll" unless $name =~ /\.[^\\\/]*$/; 70b39c5158Smillert $_ .= $name for @path; 71b39c5158Smillert return grep -f $_, @path if $flags & 0x8; 72b39c5158Smillert -f $_ and return $_ for @path; 73b39c5158Smillert return; 74b39c5158Smillert} 75b39c5158Smillert 76b39c5158Smillertpackage OS2::DLL::dll; 77b39c5158Smillertuse Carp; 78b39c5158Smillert@ISA = 'OS2::DLL'; 79b39c5158Smillert 80b39c5158Smillertsub AUTOLOAD { 81b39c5158Smillert $AUTOLOAD =~ /^OS2::DLL::dll::.+::(.+)$/ 82b39c5158Smillert or confess("Undefined subroutine &$AUTOLOAD called"); 83b39c5158Smillert return undef if $1 eq "DESTROY"; 84b39c5158Smillert die "AUTOLOAD loop" if $1 eq "AUTOLOAD"; 85b39c5158Smillert $_[0]->find($1) or confess($@); 86b39c5158Smillert goto &$AUTOLOAD; 87b39c5158Smillert} 88b39c5158Smillert 89b39c5158Smillertsub wrapper_REXX { 90b39c5158Smillert confess 'Usage: $dllhandle->wrapper_REXX($func_name)' unless @_ == 2; 91b39c5158Smillert my $self = shift; 92b39c5158Smillert my $file = $self->{File}; 93b39c5158Smillert my $handle = $self->{Handle}; 94b39c5158Smillert my $prefix = exists($self->{Prefix}) ? $self->{Prefix} : ""; 95b39c5158Smillert my $queue = $self->{Queue}; 96b39c5158Smillert my $name = shift; 97b39c5158Smillert $prefix = '' if $name =~ /^#\d+/; # loading by ordinal 98b39c5158Smillert my $addr = (DynaLoader::dl_find_symbol($handle, uc $prefix.$name) 99b39c5158Smillert || DynaLoader::dl_find_symbol($handle, $prefix.$name)); 100b39c5158Smillert return sub { 101b39c5158Smillert OS2::DLL::_call($name, $addr, $queue, @_); 102b39c5158Smillert } if $addr; 103b39c5158Smillert my $err = DynaLoader::dl_error(); 104b39c5158Smillert $err =~ s/\s+at\s+\S+\s+line\s+\S+\s*\z//; 105b39c5158Smillert croak "Can't find symbol `$name' in DLL `$file': $err"; 106b39c5158Smillert} 107b39c5158Smillert 108b39c5158Smillertsub find 109b39c5158Smillert{ 110b39c5158Smillert my $self = shift; 111b39c5158Smillert my $file = $self->{File}; 112b39c5158Smillert my $p = ref $self; 113b39c5158Smillert foreach (@_) { 114b39c5158Smillert my $f = eval {$self->wrapper_REXX($_)} or return 0; 115b39c5158Smillert ${"${p}::"}{$_} = sub { shift; $f->(@_) }; 116b39c5158Smillert } 117b39c5158Smillert return 1; 118b39c5158Smillert} 119b39c5158Smillert 120b39c5158Smillertsub handle { shift->{Handle} } 121b39c5158Smillertsub fullname { OS2::DLLname(0x202, shift->handle) } 122b39c5158Smillert#sub modname { OS2::DLLname(0x201, shift->handle) } 123b39c5158Smillert 124b39c5158Smillertsub has_f32 { 125b39c5158Smillert my $handle = shift->handle; 126b39c5158Smillert my $name = shift; 127b39c5158Smillert DynaLoader::dl_find_symbol($handle, $name); 128b39c5158Smillert} 129b39c5158Smillert 130b39c5158SmillertXSLoader::load 'OS2::DLL'; 131b39c5158Smillert 132b39c5158Smillert1; 133b39c5158Smillert__END__ 134b39c5158Smillert 135b39c5158Smillert=head1 NAME 136b39c5158Smillert 137b39c5158SmillertOS2::DLL - access to DLLs with REXX calling convention. 138b39c5158Smillert 139b39c5158Smillert=head2 NOTE 140b39c5158Smillert 141b39c5158SmillertWhen you use this module, the REXX variable pool is not available. 142b39c5158Smillert 143b39c5158SmillertSee documentation of L<OS2::REXX> module if you need the variable pool. 144b39c5158Smillert 145b39c5158Smillert=head1 SYNOPSIS 146b39c5158Smillert 147b39c5158Smillert use OS2::DLL; 148b39c5158Smillert $emx_dll = OS2::DLL->module('emx'); 149b39c5158Smillert $emx_version = $emx_dll->emx_revision(); 150b39c5158Smillert $func_emx_version = $emx_dll->wrapper_REXX('#128'); # emx_revision 151b39c5158Smillert $emx_version = $func_emx_version->(); 152b39c5158Smillert 153b39c5158Smillert=head1 DESCRIPTION 154b39c5158Smillert 15591f110e0Safresh1=head2 Create a DLL handle 156b39c5158Smillert 157b39c5158Smillert $dll = OS2::DLL->module( NAME [, WHERE] ); 158b39c5158Smillert 159b39c5158SmillertLoads an OS/2 module NAME, looking in directories WHERE (adding the 160b39c5158Smillertextension F<.dll>), if the DLL is not found there, loads in the usual OS/2 way 161b39c5158Smillert(via LIBPATH and other settings). Croaks with a verbose report on failure. 162b39c5158Smillert 163b39c5158SmillertThe DLL is not unloaded when the return value is destroyed. 164b39c5158Smillert 165b39c5158Smillert=head2 Create a DLL handle (looking in some strange locations) 166b39c5158Smillert 167b39c5158Smillert $dll = OS2::DLL->new( NAME [, WHERE] ); 168b39c5158Smillert 169b39c5158SmillertSame as C<module>|L<Create a DLL handle>, but in addition to WHERE, looks 170b39c5158Smillertin environment paths PERL5REXX, PERLREXX, PATH (provided for backward 171b39c5158Smillertcompatibility). 172b39c5158Smillert 173b39c5158Smillert=head2 Loads DLL by name 174b39c5158Smillert 175b39c5158Smillert $dll = load OS2::DLL NAME [, WHERE]; 176b39c5158Smillert 177b39c5158SmillertSame as C<new>|L<Create a DLL handle (looking in some strange locations)>, 178b39c5158Smillertbut returns DLL object reference, or undef on failure (in this case one can 179b39c5158Smillertget the reason via C<DynaLoader::dl_error()>) (provided for backward 180b39c5158Smillertcompatibility). 181b39c5158Smillert 182b39c5158Smillert=head2 Check for functions (optional): 183b39c5158Smillert 184b39c5158Smillert BOOL = $dll->find(NAME [, NAME [, ...]]); 185b39c5158Smillert 186b39c5158SmillertReturns true if all functions are available. As a side effect, creates 187b39c5158Smillerta REXX wrapper with the specified name in the package constructed by the name 188b39c5158Smillertof the DLL so that the next call to C<< $dll->NAME() >> will pick up the cached 189b39c5158Smillertmethod. 190b39c5158Smillert 191b39c5158Smillert=head2 Create a Perl wrapper (optional): 192b39c5158Smillert 193b39c5158Smillert $func = $dll->wrapper_REXX(NAME); 194b39c5158Smillert 195b39c5158SmillertReturns a reference to a Perl function wrapper for the entry point NAME 196b39c5158Smillertin the DLL. Similar to the OS/2 API, the NAME may be C<"#123"> - in this case 197b39c5158Smillertthe ordinal is loaded. Croaks with a meaningful error message if NAME does 198b39c5158Smillertnot exists (although the message for the case when the name is an ordinal may 199b39c5158Smillertbe confusing). 200b39c5158Smillert 201b39c5158Smillert=head2 Call external function with REXX calling convention: 202b39c5158Smillert 203b39c5158Smillert $ret_string = $dll->function_name(arguments); 204b39c5158Smillert 205b39c5158SmillertReturns the return string if the REXX return code is 0, else undef. 206b39c5158SmillertDies with error message if the function is not available. On the first call 207b39c5158Smillertresolves the name in the DLL and caches the Perl wrapper; future calls go 208b39c5158Smillertthrough the wrapper. 209b39c5158Smillert 210b39c5158SmillertUnless used inside REXX environment (see L<OS2::REXX>), the REXX runtime 211b39c5158Smillertenvironment (variable pool, queue etc.) is not available to the called 212b39c5158Smillertfunction. 213b39c5158Smillert 214b39c5158Smillert=head1 Inspecting the module 215b39c5158Smillert 216b39c5158Smillert=over 217b39c5158Smillert 218b39c5158Smillert=item $module->handle 219b39c5158Smillert 220b39c5158Smillert=item $module->fullname 221b39c5158Smillert 222b39c5158SmillertReturn the (integer) handle and full path name of a loaded DLL. 223b39c5158Smillert 224b39c5158SmillertTODO: the module name (whatever is specified in the C<LIBRARY> statement 225b39c5158Smillertof F<.def> file when linking) via OS2::Proc. 226b39c5158Smillert 227b39c5158Smillert=item $module->has_f32($name) 228b39c5158Smillert 229b39c5158SmillertReturns the address of a 32-bit entry point with name $name, or 0 if none 230b39c5158Smillertfound. (Keep in mind that some entry points may be 16-bit, and some may have 231b39c5158Smillertcapitalized names comparing to callable-from-C counterparts.) Name of the 232b39c5158Smillertform C<#197> will find entry point with ordinal 197. 233b39c5158Smillert 234b39c5158Smillert=item libPath_find($name [, $flags]) 235b39c5158Smillert 236b39c5158SmillertLooks for the DLL $name on C<BEGINLIBPATH>, C<LIBPATH>, C<ENDLIBPATH> if 237b39c5158Smillertbits 0x1, 0x2, 0x4 of $flags are set correspondingly. If called with no 238b39c5158Smillertarguments, looks on all 3 locations. Returns the full name of the found 239b39c5158Smillertfile. B<DLL is not loaded.> 240b39c5158Smillert 241b39c5158Smillert$name has F<.dll> appended unless it already has an extension. 242b39c5158Smillert 243b39c5158Smillert=back 244b39c5158Smillert 245b39c5158Smillert=head1 Low-level API 246b39c5158Smillert 247b39c5158Smillert=over 248b39c5158Smillert 249b39c5158Smillert=item Call a _System linkage function via a pointer 250b39c5158Smillert 251b39c5158SmillertIf a function takes up to 20 ULONGs and returns ULONG: 252b39c5158Smillert 253b39c5158Smillert $res = call20( $pointer, $arg0, $arg1, ...); 254b39c5158Smillert 255b39c5158Smillert=item Same for packed arguments: 256b39c5158Smillert 257b39c5158Smillert $res = call20_p( $pointer, pack 'L20', $arg0, $arg1, ...); 258b39c5158Smillert 259b39c5158Smillert=item Same for C<regparm(3)> function: 260b39c5158Smillert 261b39c5158Smillert $res = call20_rp3( $pointer, $arg0, $arg1, ...); 262b39c5158Smillert 263b39c5158Smillert=item Same for packed arguments and C<regparm(3)> function 264b39c5158Smillert 265b39c5158Smillert $res = call20_rp3_p( $pointer, pack 'L20', $arg0, $arg1, ...); 266b39c5158Smillert 267b39c5158Smillert=item Same for a function which returns non-0 and sets system-error on error 268b39c5158Smillert 269b8851fccSafresh1 call20_Dos( $msg, $pointer, $arg0, $arg1, ...); # die("$msg: $^E") 270b8851fccSafresh1 if error 271b39c5158Smillert 272b39c5158Smillert[Good for C<Dos*> API - and rare C<Win*> calls.] 273b39c5158Smillert 274b39c5158Smillert=item Same for a function which returns 0 and sets WinLastError() on error 275b39c5158Smillert 276b39c5158Smillert $res = call20_Win( $msg, $pointer, $arg0, $arg1, ...); 277b39c5158Smillert # would die("$msg: $^E") if error 278b39c5158Smillert 279b39c5158Smillert[Good for most of C<Win*> API.] 280b39c5158Smillert 281b39c5158Smillert=item Same for a function which returns 0 and sets WinLastError() on error but 282b39c5158Smillert0 is also a valid return 283b39c5158Smillert 284b39c5158Smillert $res = call20_Win_0OK( $msg, $pointer, $arg0, $arg1, ...); 285b39c5158Smillert # would die("$msg: $^E") if error 286b39c5158Smillert 287b39c5158Smillert[Good for some of C<Win*> API.] 288b39c5158Smillert 289b39c5158Smillert=item As previous, but without die() 290b39c5158Smillert 291b39c5158Smillert $res = call20_Win_0OK_survive( $pointer, $arg0, $arg1, ...); 292b39c5158Smillert if ($res == 0 and $^E) { # Do error processing here 293b39c5158Smillert } 294b39c5158Smillert 295b39c5158Smillert[Good for some of C<Win*> API.] 296b39c5158Smillert 297b39c5158Smillert=back 298b39c5158Smillert 299b39c5158Smillert=head1 ENVIRONMENT 300b39c5158Smillert 301b39c5158SmillertIf C<PERL_REXX_DEBUG> is set, emits debugging output. Looks for DLLs 302b39c5158Smillertin C<PERL5REXX>, C<PERLREXX>, C<PATH>. 303b39c5158Smillert 304b39c5158Smillert=head1 AUTHOR 305b39c5158Smillert 306b39c5158SmillertExtracted by Ilya Zakharevich perl-module-OS2-DLL@ilyaz.org from L<OS2::REXX> 307b39c5158Smillertwritten by Andreas Kaiser ak@ananke.s.bawue.de. 308b39c5158Smillert 309b39c5158Smillert=cut 310