diff options
author | Reinhard Kotucha <reinhard.kotucha@web.de> | 2008-01-05 21:23:03 +0000 |
---|---|---|
committer | Reinhard Kotucha <reinhard.kotucha@web.de> | 2008-01-05 21:23:03 +0000 |
commit | 61700e8be90ff6f495c0b1a9835fe07e9848de8d (patch) | |
tree | ba85dbc1413d5f834a501a8828e3b67678ba8524 /Master/tlpkg/tlperl/lib/Win32 | |
parent | 270728c6f3efcac6728d2c335c79824c356f428d (diff) |
tlperl: Perl for scripts provided by TeX Live.
git-svn-id: svn://tug.org/texlive/trunk@6046 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Win32')
28 files changed, 17485 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/Win32/ChangeNotify.pm b/Master/tlpkg/tlperl/lib/Win32/ChangeNotify.pm new file mode 100644 index 00000000000..a86682da376 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/ChangeNotify.pm @@ -0,0 +1,198 @@ +#--------------------------------------------------------------------- +package Win32::ChangeNotify; +# +# Copyright 1998 Christopher J. Madsen +# +# Created: 3 Feb 1998 from the ActiveWare version +# (c) 1995 Microsoft Corporation. All rights reserved. +# Developed by ActiveWare Internet Corp., http://www.ActiveWare.com +# +# Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com> +# +# Author: Christopher J. Madsen <cjm@pobox.com> +# Version: 1.02 (13-Jun-1999) +# +# This program is free software; you can redistribute it and/or modify +# it under the same terms as Perl itself. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the +# GNU General Public License or the Artistic License for more details. +# +# Monitor directory for changes +#--------------------------------------------------------------------- +# 1.04 -Minor changes by Yves Orton to fix the trueness of $subtree (Dec 2002) + +$VERSION = '1.05'; + +use Carp; +use Win32::IPC 1.00 '/./'; # Import everything +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader Win32::IPC); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + FILE_NOTIFY_CHANGE_ATTRIBUTES + FILE_NOTIFY_CHANGE_DIR_NAME + FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_LAST_WRITE + FILE_NOTIFY_CHANGE_SECURITY + FILE_NOTIFY_CHANGE_SIZE + INFINITE +); +@EXPORT_OK = qw( + wait_all wait_any +); + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. + + my $constname; + ($constname = $AUTOLOAD) =~ s/.*:://; + if ($constname =~ /^(?:FILE_NOTIFY_CHANGE_|INFINITE)/) { + local $! = 0; + my $val = constant($constname); + croak("$constname is not defined by Win32::ChangeNotify") if $! != 0; + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; + } +} # end AUTOLOAD + +bootstrap Win32::ChangeNotify; + +sub new { + my ($class,$path,$subtree,$filter) = @_; + + if ($filter =~ /\A[\s|A-Z_]+\Z/i) { + $filter = 0; + foreach (split(/[\s|]+/, $_[3])) { + $filter |= constant("FILE_NOTIFY_CHANGE_" . uc $_); + carp "Invalid filter $_" if $!; + } + } + _new($class,$path,$subtree,$filter); +} # end new + +sub Close { &close } + +sub FindFirst { $_[0] = Win32::ChangeNotify->_new(@_[1..3]); } + +sub FindNext { &reset } + +1; +__END__ + +=head1 NAME + +Win32::ChangeNotify - Monitor events related to files and directories + +=head1 SYNOPSIS + + require Win32::ChangeNotify; + + $notify = Win32::ChangeNotify->new($Path,$WatchSubTree,$Events); + $notify->wait or warn "Something failed: $!\n"; + # There has been a change. + +=head1 DESCRIPTION + +This module allows the user to use a Win32 change notification event +object from Perl. This allows the Perl program to monitor events +relating to files and directory trees. + +Unfortunately, the Win32 API which implements this feature does not +provide any indication of I<what> triggered the notification (as far +as I know). If you're monitoring a directory for file changes, and +you need to know I<which> file changed, you'll have to find some other +way of determining that. Depending on exactly what you're trying to +do, you may be able to check file timestamps to find recently changed +files. Or, you may need to cache the directory contents somewhere and +compare the current contents to your cached copy when you receive a +change notification. + +The C<wait> method and C<wait_all> & C<wait_any> functions are +inherited from the L<"Win32::IPC"> module. + +=head2 Methods + +=over 4 + +=item $notify = Win32::ChangeNotify->new($path, $subtree, $filter) + +Constructor for a new ChangeNotification object. C<$path> is the +directory to monitor. If C<$subtree> is true, then all directories +under C<$path> will be monitored. C<$filter> indicates what events +should trigger a notification. It should be a string containing any +of the following flags (separated by whitespace and/or C<|>). + + ATTRIBUTES Any attribute change + DIR_NAME Any directory name change + FILE_NAME Any file name change (creating/deleting/renaming) + LAST_WRITE Any change to a file's last write time + SECURITY Any security descriptor change + SIZE Any change in a file's size + +(C<$filter> can also be an integer composed from the +C<FILE_NOTIFY_CHANGE_*> constants.) + +=item $notify->close + +Shut down monitoring. You could just C<undef $notify> instead (but +C<close> works even if there are other copies of the object). This +happens automatically when your program exits. + +=item $notify->reset + +Resets the ChangeNotification object after a change has been detected. +The object will become signalled again after the next change. (It is +OK to call this immediately after C<new>, but it is not required.) + +=item $notify->wait + +See L<"Win32::IPC">. Remember to call C<reset> afterwards if you want +to continue monitoring. + +=back + +=head2 Deprecated Functions and Methods + +B<Win32::ChangeNotify> still supports the ActiveWare syntax, but its +use is deprecated. + +=over 4 + +=item FindFirst($Obj,$PathName,$WatchSubTree,$Filter) + +Use + + $Obj = Win32::ChangeNotify->new($PathName,$WatchSubTree,$Filter) + +instead. + +=item $obj->FindNext() + +Use C<$obj-E<gt>reset> instead. + +=item $obj->Close() + +Use C<$obj-E<gt>close> instead. + +=back + +=head1 AUTHOR + +Christopher J. Madsen E<lt>F<cjm@pobox.com>E<gt> + +Loosely based on the original module by ActiveWare Internet Corp., +F<http://www.ActiveWare.com> + +=cut + +# Local Variables: +# tmtrack-file-task: "Win32::ChangeNotify" +# End: diff --git a/Master/tlpkg/tlperl/lib/Win32/Client.pl b/Master/tlpkg/tlperl/lib/Win32/Client.pl new file mode 100644 index 00000000000..6ae585b7c91 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Client.pl @@ -0,0 +1,63 @@ +use strict; +use Win32::Pipe; + +#### +# You may notice that named pipe names are case INsensitive! +#### + +my $PipeName = "\\\\.\\pipe\\TEST this LoNG Named Pipe!"; + +print "I am falling asleep for few seconds, so that we give time\nFor the server to get up and running.\n"; +sleep(4); +print "\nOpening a pipe ...\n"; + +if (my $Pipe = Win32::Pipe->new($PipeName)) { + print "\n\nPipe has been opened, writing data to it...\n"; + print "-------------------------------------------\n"; + $Pipe->Write("\n" . Win32::Pipe::Credit() . "\n\n"); + while () { + print "\nCommands:\n"; + print " FILE:xxxxx Dumps the file xxxxx.\n"; + print " Credit Dumps the credit screen.\n"; + print " Quit Quits this client (server remains running).\n"; + print " Exit Exits both client and server.\n"; + print " -----------------------------------------\n"; + + my $In = <STDIN>; + chop($In); + + if ((my $File = $In) =~ s/^file:(.*)/$1/i){ + if (-s $File) { + if (open(FILE, "< $File")) { + while ($File = <FILE>) { + $In .= $File; + }; + close(FILE); + } + } + } + + if ($In =~ /^credit$/i){ + $In = "\n" . Win32::Pipe::Credit() . "\n\n"; + } + + unless ($Pipe->Write($In)) { + print "Writing to pipe failed.\n"; + last; + } + + if ($In =~ /^(exit|quit)$/i) { + print "\nATTENTION: Closing due to user request.\n"; + last; + } + } + print "Closing...\n"; + $Pipe->Close(); +} +else { + my($Error, $ErrorText) = Win32::Pipe::Error(); + print "Error:$Error \"$ErrorText\"\n"; + sleep(4); +} + +print "Done...\n"; diff --git a/Master/tlpkg/tlperl/lib/Win32/Clipboard.pm b/Master/tlpkg/tlperl/lib/Win32/Clipboard.pm new file mode 100644 index 00000000000..ba4038a5ade --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Clipboard.pm @@ -0,0 +1,369 @@ +package Win32::Clipboard; +####################################################################### +# +# Win32::Clipboard - Interaction with the Windows clipboard +# +# Version: 0.52 +# Author: Aldo Calpini <dada@perl.it> +# +# Modified by: Hideyo Imazu <himazu@gmail.com> +# +####################################################################### + +require Exporter; # to export the constants to the main:: space +require DynaLoader; # to dynuhlode the module. + +@ISA = qw( Exporter DynaLoader ); +@EXPORT = qw( + CF_TEXT + CF_BITMAP + CF_METAFILEPICT + CF_SYLK + CF_DIF + CF_TIFF + CF_OEMTEXT + CF_DIB + CF_PALETTE + CF_PENDATA + CF_RIFF + CF_WAVE + CF_UNICODETEXT + CF_ENHMETAFILE + CF_HDROP + CF_LOCALE +); + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. +# + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } else { + my ($pack, $file, $line) = caller; + die "Win32::Clipboard::$constname is not defined, used at $file line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +####################################################################### +# STATIC OBJECT PROPERTIES +# +$VERSION = "0.5201"; + +####################################################################### +# FUNCTIONS +# + +sub new { + my($class, $value) = @_; + my $self = "I'm the Clipboard!"; + Set($value) if defined($value); + return bless(\$self); +} + +sub Version { + return $VERSION; +} + +sub Get { + if( IsBitmap() ) { return GetBitmap(); } + elsif( IsFiles() ) { return GetFiles(); } + else { return GetText(); } +} + +sub TIESCALAR { + my $class = shift; + my $value = shift; + Set($value) if defined $value; + my $self = "I'm the Clipboard!"; + return bless \$self, $class; +} + +sub FETCH { Get() } +sub STORE { shift; Set(@_) } + +sub DESTROY { + my($self) = @_; + undef $self; + StopClipboardViewer(); +} + +END { + StopClipboardViewer(); +} + +####################################################################### +# dynamically load in the Clipboard.pll module. +# + +bootstrap Win32::Clipboard; + +####################################################################### +# a little hack to use the module itself as a class. +# + +sub main::Win32::Clipboard { + my($value) = @_; + my $self={}; + my $result = Win32::Clipboard::Set($value) if defined($value); + return bless($self, "Win32::Clipboard"); +} + +1; + +__END__ + +=head1 NAME + +Win32::Clipboard - Interaction with the Windows clipboard + +=head1 SYNOPSIS + + use Win32::Clipboard; + + $CLIP = Win32::Clipboard(); + + print "Clipboard contains: ", $CLIP->Get(), "\n"; + + $CLIP->Set("some text to copy into the clipboard"); + + $CLIP->Empty(); + + $CLIP->WaitForChange(); + print "Clipboard has changed!\n"; + + +=head1 DESCRIPTION + +This module lets you interact with the Windows clipboard: you can get its content, +set it, empty it, or let your script sleep until it changes. +This version supports 3 formats for clipboard data: + +=over 4 + +=item * +text (C<CF_TEXT>) + +The clipboard contains some text; this is the B<only> format you can use to set +clipboard data; you get it as a single string. + +Example: + + $text = Win32::Clipboard::GetText(); + print $text; + +=item * +bitmap (C<CF_DIB>) + +The clipboard contains an image, either a bitmap or a picture copied in the +clipboard from a graphic application. The data you get is a binary buffer +ready to be written to a bitmap (BMP format) file. + +Example: + + $image = Win32::Clipboard::GetBitmap(); + open BITMAP, ">some.bmp"; + binmode BITMAP; + print BITMAP $image; + close BITMAP; + +=item * +list of files (C<CF_HDROP>) + +The clipboard contains files copied or cutted from an Explorer-like +application; you get a list of filenames. + +Example: + + @files = Win32::Clipboard::GetFiles(); + print join("\n", @files); + +=back + +=head2 REFERENCE + +All the functions can be used either with their full name (eg. B<Win32::Clipboard::Get>) +or as methods of a C<Win32::Clipboard> object. +For the syntax, refer to L</SYNOPSIS> above. Note also that you can create a clipboard +object and set its content at the same time with: + + $CLIP = Win32::Clipboard("blah blah blah"); + +or with the more common form: + + $CLIP = new Win32::Clipboard("blah blah blah"); + +If you prefer, you can even tie the Clipboard to a variable like this: + + tie $CLIP, 'Win32::Clipboard'; + + print "Clipboard content: $CLIP\n"; + + $CLIP = "some text to copy to the clipboard..."; + +In this case, you can still access other methods using the tied() function: + + tied($CLIP)->Empty; + print "got the picture" if tied($CLIP)->IsBitmap; + +=over 4 + +=item Empty() + +Empty the clipboard. + +=for html <P> + +=item EnumFormats() + +Returns an array of identifiers describing the format for the data currently in the +clipboard. Formats can be standard ones (described in the L</CONSTANTS> section) or +application-defined custom ones. See also IsFormatAvailable(). + +=for html <P> + +=item Get() + +Returns the clipboard content; note that the result depends on the nature of +clipboard data; to ensure that you get only the desired format, you should use +GetText(), GetBitmap() or GetFiles() instead. Get() is in fact implemented as: + + if( IsBitmap() ) { return GetBitmap(); } + elsif( IsFiles() ) { return GetFiles(); } + else { return GetText(); } + +See also IsBitmap(), IsFiles(), IsText(), EnumFormats() and IsFormatAvailable() +to check the clipboard format before getting data. + +=for html <P> + +=item GetAs(FORMAT) + +Returns the clipboard content in the desired FORMAT (can be one of the constants +defined in the L</CONSTANTS> section or a custom format). Note that the only +meaningful identifiers are C<CF_TEXT>, C<CF_DIB> and C<CF_HDROP>; any other +format is treated as a string. + +=for html <P> + +=item GetBitmap() + +Returns the clipboard content as an image, or C<undef> on errors. + +=for html <P> + +=item GetFiles() + +Returns the clipboard content as a list of filenames, or C<undef> on errors. + +=for html <P> + +=item GetFormatName(FORMAT) + +Returns the name of the specified custom clipboard format, or C<undef> on errors; +note that you cannot get the name of the standard formats (described in the +L</CONSTANTS> section). + +=for html <P> + +=item GetText() + +Returns the clipboard content as a string, or C<undef> on errors. + +=for html <P> + +=item IsBitmap() + +Returns a boolean value indicating if the clipboard contains an image. +See also GetBitmap(). + +=for html <P> + +=item IsFiles() + +Returns a boolean value indicating if the clipboard contains a list of +files. See also GetFiles(). + +=for html <P> + +=item IsFormatAvailable(FORMAT) + +Checks if the clipboard data matches the specified FORMAT (one of the constants +described in the L</CONSTANTS> section); returns zero if the data does not match, +a nonzero value if it matches. + +=for html <P> + +=item IsText() + +Returns a boolean value indicating if the clipboard contains text. +See also GetText(). + +=for html <P> + +=item Set(VALUE) + +Set the clipboard content to the specified string. + +=for html <P> + +=item WaitForChange([TIMEOUT]) + +This function halts the script until the clipboard content changes. If you specify +a C<TIMEOUT> value (in milliseconds), the function will return when this timeout +expires, even if the clipboard hasn't changed. If no value is given, it will wait +indefinitely. Returns 1 if the clipboard has changed, C<undef> on errors. + +=back + +=head2 CONSTANTS + +These constants are the standard clipboard formats recognized by Win32::Clipboard: + + CF_TEXT 1 + CF_DIB 8 + CF_HDROP 15 + +The following formats are B<not recognized> by Win32::Clipboard; they are, +however, exported constants and can eventually be used with the EnumFormats(), +IsFormatAvailable() and GetAs() functions: + + CF_BITMAP 2 + CF_METAFILEPICT 3 + CF_SYLK 4 + CF_DIF 5 + CF_TIFF 6 + CF_OEMTEXT 7 + CF_PALETTE 9 + CF_PENDATA 10 + CF_RIFF 11 + CF_WAVE 12 + CF_UNICODETEXT 13 + CF_ENHMETAFILE 14 + CF_LOCALE 16 + +=head1 AUTHOR + +This version was released by Hideyo Imazu <F<himazu@gmail.com>>. + +Aldo Calpini <F<dada@perl.it>> was the former maintainer. + +Original XS porting by Gurusamy Sarathy <F<gsar@activestate.com>>. + +=cut + + diff --git a/Master/tlpkg/tlperl/lib/Win32/Console.pm b/Master/tlpkg/tlperl/lib/Win32/Console.pm new file mode 100644 index 00000000000..1e3876a6a33 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Console.pm @@ -0,0 +1,1463 @@ +####################################################################### +# +# Win32::Console - Win32 Console and Character Mode Functions +# +####################################################################### + +package Win32::Console; + +require Exporter; +require DynaLoader; + +$VERSION = "0.07"; + +@ISA= qw( Exporter DynaLoader ); +@EXPORT = qw( + BACKGROUND_BLUE + BACKGROUND_GREEN + BACKGROUND_INTENSITY + BACKGROUND_RED + CAPSLOCK_ON + CONSOLE_TEXTMODE_BUFFER + CTRL_BREAK_EVENT + CTRL_C_EVENT + ENABLE_ECHO_INPUT + ENABLE_LINE_INPUT + ENABLE_MOUSE_INPUT + ENABLE_PROCESSED_INPUT + ENABLE_PROCESSED_OUTPUT + ENABLE_WINDOW_INPUT + ENABLE_WRAP_AT_EOL_OUTPUT + ENHANCED_KEY + FILE_SHARE_READ + FILE_SHARE_WRITE + FOREGROUND_BLUE + FOREGROUND_GREEN + FOREGROUND_INTENSITY + FOREGROUND_RED + LEFT_ALT_PRESSED + LEFT_CTRL_PRESSED + NUMLOCK_ON + GENERIC_READ + GENERIC_WRITE + RIGHT_ALT_PRESSED + RIGHT_CTRL_PRESSED + SCROLLLOCK_ON + SHIFT_PRESSED + STD_INPUT_HANDLE + STD_OUTPUT_HANDLE + STD_ERROR_HANDLE + $FG_BLACK + $FG_GRAY + $FG_BLUE + $FG_LIGHTBLUE + $FG_RED + $FG_LIGHTRED + $FG_GREEN + $FG_LIGHTGREEN + $FG_MAGENTA + $FG_LIGHTMAGENTA + $FG_CYAN + $FG_LIGHTCYAN + $FG_BROWN + $FG_YELLOW + $FG_LIGHTGRAY + $FG_WHITE + $BG_BLACK + $BG_GRAY + $BG_BLUE + $BG_LIGHTBLUE + $BG_RED + $BG_LIGHTRED + $BG_GREEN + $BG_LIGHTGREEN + $BG_MAGENTA + $BG_LIGHTMAGENTA + $BG_CYAN + $BG_LIGHTCYAN + $BG_BROWN + $BG_YELLOW + $BG_LIGHTGRAY + $BG_WHITE + $ATTR_NORMAL + $ATTR_INVERSE + @CONSOLE_COLORS +); + + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. +# + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { +# if ($! =~ /Invalid/) { +# $AutoLoader::AUTOLOAD = $AUTOLOAD; +# goto &AutoLoader::AUTOLOAD; +# } else { + ($pack, $file, $line) = caller; undef $pack; + die "Symbol Win32::Console::$constname not defined, used at $file line $line."; +# } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +####################################################################### +# STATIC OBJECT PROPERTIES +# + +# %HandlerRoutineStack = (); +# $HandlerRoutineRegistered = 0; + +####################################################################### +# PUBLIC METHODS +# + +#======== +sub new { +#======== + my($class, $param1, $param2) = @_; + + my $self = {}; + + if (defined($param1) + and ($param1 == constant("STD_INPUT_HANDLE", 0) + or $param1 == constant("STD_OUTPUT_HANDLE", 0) + or $param1 == constant("STD_ERROR_HANDLE", 0))) + { + $self->{'handle'} = _GetStdHandle($param1); + } + else { + $param1 = constant("GENERIC_READ", 0) | constant("GENERIC_WRITE", 0) unless $param1; + $param2 = constant("FILE_SHARE_READ", 0) | constant("FILE_SHARE_WRITE", 0) unless $param2; + $self->{'handle'} = _CreateConsoleScreenBuffer($param1, $param2, + constant("CONSOLE_TEXTMODE_BUFFER", 0)); + } + bless $self, $class; + return $self; +} + +#============ +sub Display { +#============ + my($self) = @_; + return undef unless ref($self); + return _SetConsoleActiveScreenBuffer($self->{'handle'}); +} + +#=========== +sub Select { +#=========== + my($self, $type) = @_; + return undef unless ref($self); + return _SetStdHandle($type, $self->{'handle'}); +} + +#=========== +sub SetIcon { +#=========== + my($self, $icon) = @_; + $icon = $self unless ref($self); + return _SetConsoleIcon($icon); +} + +#========== +sub Title { +#========== + my($self, $title) = @_; + $title = $self unless ref($self); + + if (defined($title)) { + return _SetConsoleTitle($title); + } + else { + return _GetConsoleTitle(); + } +} + +#============== +sub WriteChar { +#============== + my($self, $text, $col, $row) = @_; + return undef unless ref($self); + return _WriteConsoleOutputCharacter($self->{'handle'},$text,$col,$row); +} + +#============= +sub ReadChar { +#============= + my($self, $size, $col, $row) = @_; + return undef unless ref($self); + + my $buffer = (" " x $size); + if (_ReadConsoleOutputCharacter($self->{'handle'}, $buffer, $size, $col, $row)) { + return $buffer; + } + else { + return undef; + } +} + +#============== +sub WriteAttr { +#============== + my($self, $attr, $col, $row) = @_; + return undef unless ref($self); + return _WriteConsoleOutputAttribute($self->{'handle'}, $attr, $col, $row); +} + +#============= +sub ReadAttr { +#============= + my($self, $size, $col, $row) = @_; + return undef unless ref($self); + return _ReadConsoleOutputAttribute($self->{'handle'}, $size, $col, $row); +} + +#========== +sub Write { +#========== + my($self,$string) = @_; + return undef unless ref($self); + return _WriteConsole($self->{'handle'}, $string); +} + +#============= +sub ReadRect { +#============= + my($self, $left, $top, $right, $bottom) = @_; + return undef unless ref($self); + + my $col = $right - $left + 1; + my $row = $bottom - $top + 1; + + my $buffer = (" " x ($col*$row*4)); + if (_ReadConsoleOutput($self->{'handle'}, $buffer, + $col, $row, 0, 0, + $left, $top, $right, $bottom)) + { + return $buffer; + } + else { + return undef; + } +} + +#============== +sub WriteRect { +#============== + my($self, $buffer, $left, $top, $right, $bottom) = @_; + return undef unless ref($self); + + my $col = $right - $left + 1; + my $row = $bottom - $top + 1; + + return _WriteConsoleOutput($self->{'handle'}, $buffer, + $col, $row, 0, 0, + $left, $top, $right, $bottom); +} + +#=========== +sub Scroll { +#=========== + my($self, $left1, $top1, $right1, $bottom1, + $col, $row, $char, $attr, + $left2, $top2, $right2, $bottom2) = @_; + return undef unless ref($self); + + return _ScrollConsoleScreenBuffer($self->{'handle'}, + $left1, $top1, $right1, $bottom1, + $col, $row, $char, $attr, + $left2, $top2, $right2, $bottom2); +} + +#============== +sub MaxWindow { +#============== + my($self, $flag) = @_; + return undef unless ref($self); + + if (not defined($flag)) { + my @info = _GetConsoleScreenBufferInfo($self->{'handle'}); + return $info[9], $info[10]; + } + else { + return _GetLargestConsoleWindowSize($self->{'handle'}); + } +} + +#========= +sub Info { +#========= + my($self) = @_; + return undef unless ref($self); + return _GetConsoleScreenBufferInfo($self->{'handle'}); +} + +#=========== +sub Window { +#=========== + my($self, $flag, $left, $top, $right, $bottom) = @_; + return undef unless ref($self); + + if (not defined($flag)) { + my @info = _GetConsoleScreenBufferInfo($self->{'handle'}); + return $info[5], $info[6], $info[7], $info[8]; + } + else { + return _SetConsoleWindowInfo($self->{'handle'}, $flag, $left, $top, $right, $bottom); + } +} + +#============== +sub GetEvents { +#============== + my($self) = @_; + return undef unless ref($self); + return _GetNumberOfConsoleInputEvents($self->{'handle'}); +} + +#========== +sub Flush { +#========== + my($self) = @_; + return undef unless ref($self); + return _FlushConsoleInputBuffer($self->{'handle'}); +} + +#============== +sub InputChar { +#============== + my($self, $number) = @_; + return undef unless ref($self); + + $number = 1 unless defined($number); + + my $buffer = (" " x $number); + if (_ReadConsole($self->{'handle'}, $buffer, $number) == $number) { + return $buffer; + } + else { + return undef; + } +} + +#========== +sub Input { +#========== + my($self) = @_; + return undef unless ref($self); + return _ReadConsoleInput($self->{'handle'}); +} + +#============== +sub PeekInput { +#============== + my($self) = @_; + return undef unless ref($self); + return _PeekConsoleInput($self->{'handle'}); +} + +#=============== +sub WriteInput { +#=============== + my($self) = shift; + return undef unless ref($self); + return _WriteConsoleInput($self->{'handle'}, @_); +} + +#========= +sub Mode { +#========= + my($self, $mode) = @_; + return undef unless ref($self); + if (defined($mode)) { + return _SetConsoleMode($self->{'handle'}, $mode); + } + else { + return _GetConsoleMode($self->{'handle'}); + } +} + +#======== +sub Cls { +#======== + my($self, $attr) = @_; + return undef unless ref($self); + + $attr = $ATTR_NORMAL unless defined($attr); + + my ($x, $y) = $self->Size(); + my($left, $top, $right ,$bottom) = $self->Window(); + my $vx = $right - $left; + my $vy = $bottom - $top; + $self->FillChar(" ", $x*$y, 0, 0); + $self->FillAttr($attr, $x*$y, 0, 0); + $self->Cursor(0, 0); + $self->Window(1, 0, 0, $vx, $vy); +} + +#========= +sub Attr { +#========= + my($self, $attr) = @_; + return undef unless ref($self); + + if (not defined($attr)) { + return (_GetConsoleScreenBufferInfo($self->{'handle'}))[4]; + } + else { + return _SetConsoleTextAttribute($self->{'handle'}, $attr); + } +} + +#=========== +sub Cursor { +#=========== + my($self, $col, $row, $size, $visi) = @_; + return undef unless ref($self); + + my $curr_row = 0; + my $curr_col = 0; + my $curr_size = 0; + my $curr_visi = 0; + my $return = 0; + my $discard = 0; + + + if (defined($col)) { + $row = -1 if not defined($row); + if ($col == -1 or $row == -1) { + ($discard, $discard, $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + $col=$curr_col if $col==-1; + $row=$curr_row if $row==-1; + } + $return += _SetConsoleCursorPosition($self->{'handle'}, $col, $row); + if (defined($size) and defined($visi)) { + if ($size == -1 or $visi == -1) { + ($curr_size, $curr_visi) = _GetConsoleCursorInfo($self->{'handle'}); + $size = $curr_size if $size == -1; + $visi = $curr_visi if $visi == -1; + } + $size = 1 if $size < 1; + $size = 99 if $size > 99; + $return += _SetConsoleCursorInfo($self->{'handle'}, $size, $visi); + } + return $return; + } + else { + ($discard, $discard, $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + ($curr_size, $curr_visi) = _GetConsoleCursorInfo($self->{'handle'}); + return ($curr_col, $curr_row, $curr_size, $curr_visi); + } +} + +#========= +sub Size { +#========= + my($self, $col, $row) = @_; + return undef unless ref($self); + + if (not defined($col)) { + ($col, $row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + return ($col, $row); + } + else { + $row = -1 if not defined($row); + if ($col == -1 or $row == -1) { + ($curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + $col=$curr_col if $col==-1; + $row=$curr_row if $row==-1; + } + return _SetConsoleScreenBufferSize($self->{'handle'}, $col, $row); + } +} + +#============= +sub FillAttr { +#============= + my($self, $attr, $number, $col, $row) = @_; + return undef unless ref($self); + + $number = 1 unless $number; + + if (!defined($col) or !defined($row) or $col == -1 or $row == -1) { + ($discard, $discard, + $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + $col = $curr_col if !defined($col) or $col == -1; + $row = $curr_row if !defined($row) or $row == -1; + } + return _FillConsoleOutputAttribute($self->{'handle'}, $attr, $number, $col, $row); +} + +#============= +sub FillChar { +#============= + my($self, $char, $number, $col, $row) = @_; + return undef unless ref($self); + + if (!defined($col) or !defined($row) or $col == -1 or $row == -1) { + ($discard, $discard, + $curr_col, $curr_row) = _GetConsoleScreenBufferInfo($self->{'handle'}); + $col = $curr_col if !defined($col) or $col == -1; + $row = $curr_row if !defined($row) or $row == -1; + } + return _FillConsoleOutputCharacter($self->{'handle'}, $char, $number, $col, $row); +} + +#============ +sub InputCP { +#============ + my($self, $codepage) = @_; + $codepage = $self if (defined($self) and ref($self) ne "Win32::Console"); + if (defined($codepage)) { + return _SetConsoleCP($codepage); + } + else { + return _GetConsoleCP(); + } +} + +#============= +sub OutputCP { +#============= + my($self, $codepage) = @_; + $codepage = $self if (defined($self) and ref($self) ne "Win32::Console"); + if (defined($codepage)) { + return _SetConsoleOutputCP($codepage); + } + else { + return _GetConsoleOutputCP(); + } +} + +#====================== +sub GenerateCtrlEvent { +#====================== + my($self, $type, $pid) = @_; + $type = constant("CTRL_C_EVENT", 0) unless defined($type); + $pid = 0 unless defined($pid); + return _GenerateConsoleCtrlEvent($type, $pid); +} + +#=================== +#sub SetCtrlHandler { +#=================== +# my($name, $add) = @_; +# $add = 1 unless defined($add); +# my @nor = keys(%HandlerRoutineStack); +# if ($add == 0) { +# foreach $key (@nor) { +# delete $HandlerRoutineStack{$key}, last if $HandlerRoutineStack{$key}==$name; +# } +# $HandlerRoutineRegistered--; +# } else { +# if ($#nor == -1) { +# my $r = _SetConsoleCtrlHandler(); +# if (!$r) { +# print "WARNING: SetConsoleCtrlHandler failed...\n"; +# } +# } +# $HandlerRoutineRegistered++; +# $HandlerRoutineStack{$HandlerRoutineRegistered} = $name; +# } +#} + +#=================== +sub get_Win32_IPC_HANDLE { # So Win32::IPC can wait on a console handle +#=================== + $_[0]->{'handle'}; +} + +######################################################################## +# PRIVATE METHODS +# + +#================ +#sub CtrlHandler { +#================ +# my($ctrltype) = @_; +# my $routine; +# my $result = 0; +# CALLEM: foreach $routine (sort { $b <=> $a } keys %HandlerRoutineStack) { +# #print "CtrlHandler: calling $HandlerRoutineStack{$routine}($ctrltype)\n"; +# $result = &{"main::".$HandlerRoutineStack{$routine}}($ctrltype); +# last CALLEM if $result; +# } +# return $result; +#} + +#============ +sub DESTROY { +#============ + my($self) = @_; + _CloseHandle($self->{'handle'}); +} + +####################################################################### +# dynamically load in the Console.pll module. +# + +bootstrap Win32::Console; + +####################################################################### +# ADDITIONAL CONSTANTS EXPORTED IN THE MAIN NAMESPACE +# + +$FG_BLACK = 0; +$FG_GRAY = constant("FOREGROUND_INTENSITY",0); +$FG_BLUE = constant("FOREGROUND_BLUE",0); +$FG_LIGHTBLUE = constant("FOREGROUND_BLUE",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_RED = constant("FOREGROUND_RED",0); +$FG_LIGHTRED = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_GREEN = constant("FOREGROUND_GREEN",0); +$FG_LIGHTGREEN = constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_MAGENTA = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_BLUE",0); +$FG_LIGHTMAGENTA = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_BLUE",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_CYAN = constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_BLUE",0); +$FG_LIGHTCYAN = constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_BLUE",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_BROWN = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_GREEN",0); +$FG_YELLOW = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_INTENSITY",0); +$FG_LIGHTGRAY = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_BLUE",0); +$FG_WHITE = constant("FOREGROUND_RED",0)| + constant("FOREGROUND_GREEN",0)| + constant("FOREGROUND_BLUE",0)| + constant("FOREGROUND_INTENSITY",0); + +$BG_BLACK = 0; +$BG_GRAY = constant("BACKGROUND_INTENSITY",0); +$BG_BLUE = constant("BACKGROUND_BLUE",0); +$BG_LIGHTBLUE = constant("BACKGROUND_BLUE",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_RED = constant("BACKGROUND_RED",0); +$BG_LIGHTRED = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_GREEN = constant("BACKGROUND_GREEN",0); +$BG_LIGHTGREEN = constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_MAGENTA = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_BLUE",0); +$BG_LIGHTMAGENTA = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_BLUE",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_CYAN = constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_BLUE",0); +$BG_LIGHTCYAN = constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_BLUE",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_BROWN = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_GREEN",0); +$BG_YELLOW = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_INTENSITY",0); +$BG_LIGHTGRAY = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_BLUE",0); +$BG_WHITE = constant("BACKGROUND_RED",0)| + constant("BACKGROUND_GREEN",0)| + constant("BACKGROUND_BLUE",0)| + constant("BACKGROUND_INTENSITY",0); + +$ATTR_NORMAL = $FG_LIGHTGRAY|$BG_BLACK; +$ATTR_INVERSE = $FG_BLACK|$BG_LIGHTGRAY; + +for my $fg ($FG_BLACK, $FG_GRAY, $FG_BLUE, $FG_GREEN, + $FG_CYAN, $FG_RED, $FG_MAGENTA, $FG_BROWN, + $FG_LIGHTBLUE, $FG_LIGHTGREEN, $FG_LIGHTCYAN, + $FG_LIGHTRED, $FG_LIGHTMAGENTA, $FG_YELLOW, + $FG_LIGHTGRAY, $FG_WHITE) +{ + for my $bg ($BG_BLACK, $BG_GRAY, $BG_BLUE, $BG_GREEN, + $BG_CYAN, $BG_RED, $BG_MAGENTA, $BG_BROWN, + $BG_LIGHTBLUE, $BG_LIGHTGREEN, $BG_LIGHTCYAN, + $BG_LIGHTRED, $BG_LIGHTMAGENTA, $BG_YELLOW, + $BG_LIGHTGRAY, $BG_WHITE) + { + push(@CONSOLE_COLORS, $fg|$bg); + } +} + +# Preloaded methods go here. + +#Currently Autoloading is not implemented in Perl for win32 +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; + +__END__ + +=head1 NAME + +Win32::Console - Win32 Console and Character Mode Functions + + +=head1 DESCRIPTION + +This module implements the Win32 console and character mode +functions. They give you full control on the console input and output, +including: support of off-screen console buffers (eg. multiple screen +pages) + +=over + +=item * + +reading and writing of characters, attributes and whole portions of +the screen + +=item * + +complete processing of keyboard and mouse events + +=item * + +some very funny additional features :) + +=back + +Those functions should also make possible a port of the Unix's curses +library; if there is anyone interested (and/or willing to contribute) +to this project, e-mail me. Thank you. + + +=head1 REFERENCE + + +=head2 Methods + +=over + +=item Alloc + +Allocates a new console for the process. Returns C<undef> on errors, a +nonzero value on success. A process cannot be associated with more +than one console, so this method will fail if there is already an +allocated console. Use Free to detach the process from the console, +and then call Alloc to create a new console. See also: C<Free> + +Example: + + $CONSOLE->Alloc(); + +=item Attr [attr] + +Gets or sets the current console attribute. This attribute is used by +the Write method. + +Example: + + $attr = $CONSOLE->Attr(); + $CONSOLE->Attr($FG_YELLOW | $BG_BLUE); + +=item Close + +Closes a shortcut object. Note that it is not "strictly" required to +close the objects you created, since the Win32::Shortcut objects are +automatically closed when the program ends (or when you elsehow +destroy such an object). + +Example: + + $LINK->Close(); + +=item Cls [attr] + +Clear the console, with the specified I<attr> if given, or using +ATTR_NORMAL otherwise. + +Example: + + $CONSOLE->Cls(); + $CONSOLE->Cls($FG_WHITE | $BG_GREEN); + +=item Cursor [x, y, size, visible] + +Gets or sets cursor position and appearance. Returns C<undef> on +errors, or a 4-element list containing: I<x>, I<y>, I<size>, +I<visible>. I<x> and I<y> are the current cursor position; ... + +Example: + + ($x, $y, $size, $visible) = $CONSOLE->Cursor(); + + # Get position only + ($x, $y) = $CONSOLE->Cursor(); + + $CONSOLE->Cursor(40, 13, 50, 1); + + # Set position only + $CONSOLE->Cursor(40, 13); + + # Set size and visibility without affecting position + $CONSOLE->Cursor(-1, -1, 50, 1); + +=item Display + +Displays the specified console on the screen. Returns C<undef> on errors, +a nonzero value on success. + +Example: + + $CONSOLE->Display(); + +=item FillAttr [attribute, number, col, row] + +Fills the specified number of consecutive attributes, beginning at +I<col>, I<row>, with the value specified in I<attribute>. Returns the +number of attributes filled, or C<undef> on errors. See also: +C<FillChar>. + +Example: + + $CONSOLE->FillAttr($FG_BLACK | $BG_BLACK, 80*25, 0, 0); + +=item FillChar char, number, col, row + +Fills the specified number of consecutive characters, beginning at +I<col>, I<row>, with the character specified in I<char>. Returns the +number of characters filled, or C<undef> on errors. See also: +C<FillAttr>. + +Example: + + $CONSOLE->FillChar("X", 80*25, 0, 0); + +=item Flush + +Flushes the console input buffer. All the events in the buffer are +discarded. Returns C<undef> on errors, a nonzero value on success. + +Example: + + $CONSOLE->Flush(); + +=item Free + +Detaches the process from the console. Returns C<undef> on errors, a +nonzero value on success. See also: C<Alloc>. + +Example: + + $CONSOLE->Free(); + +=item GenerateCtrlEvent [type, processgroup] + +Sends a break signal of the specified I<type> to the specified +I<processgroup>. I<type> can be one of the following constants: + + CTRL_BREAK_EVENT + CTRL_C_EVENT + +they signal, respectively, the pressing of Control + Break and of +Control + C; if not specified, it defaults to CTRL_C_EVENT. +I<processgroup> is the pid of a process sharing the same console. If +omitted, it defaults to 0 (the current process), which is also the +only meaningful value that you can pass to this function. Returns +C<undef> on errors, a nonzero value on success. + +Example: + + # break this script now + $CONSOLE->GenerateCtrlEvent(); + +=item GetEvents + +Returns the number of unread input events in the console's input +buffer, or C<undef> on errors. See also: C<Input>, C<InputChar>, +C<PeekInput>, C<WriteInput>. + +Example: + + $events = $CONSOLE->GetEvents(); + +=item Info + +Returns an array of informations about the console (or C<undef> on +errors), which contains: + +=over + +=item * + +columns (X size) of the console buffer. + +=item * + +rows (Y size) of the console buffer. + +=item * + +current column (X position) of the cursor. + +=item * + +current row (Y position) of the cursor. + +=item * + +current attribute used for C<Write>. + +=item * + +left column (X of the starting point) of the current console window. + +=item * + +top row (Y of the starting point) of the current console window. + +=item * + +right column (X of the final point) of the current console window. + +=item * + +bottom row (Y of the final point) of the current console window. + +=item * + +maximum number of columns for the console window, given the current +buffer size, font and the screen size. + +=item * + +maximum number of rows for the console window, given the current +buffer size, font and the screen size. + +=back + +See also: C<Attr>, C<Cursor>, C<Size>, C<Window>, C<MaxWindow>. + +Example: + + @info = $CONSOLE->Info(); + print "Cursor at $info[3], $info[4].\n"; + +=item Input + +Reads an event from the input buffer. Returns a list of values, which +depending on the event's nature are: + +=over + +=item keyboard event + +The list will contain: + +=over + +=item * + +event type: 1 for keyboard + +=item * + +key down: TRUE if the key is being pressed, FALSE if the key is being released + +=item * + +repeat count: the number of times the key is being held down + +=item * + +virtual keycode: the virtual key code of the key + +=item * + +virtual scancode: the virtual scan code of the key + +=item * + +char: the ASCII code of the character (if the key is a character key, 0 otherwise) + +=item * + +control key state: the state of the control keys (SHIFTs, CTRLs, ALTs, etc.) + +=back + +=item mouse event + +The list will contain: + +=over + +=item * + +event type: 2 for mouse + +=item * + +mouse pos. X: X coordinate (column) of the mouse location + +=item * + +mouse pos. Y: Y coordinate (row) of the mouse location + +=item * + +button state: the mouse button(s) which are pressed + +=item * + +control key state: the state of the control keys (SHIFTs, CTRLs, ALTs, etc.) + +=item * + +event flags: the type of the mouse event + +=back + +=back + +This method will return C<undef> on errors. Note that the events +returned are depending on the input C<Mode> of the console; for example, +mouse events are not intercepted unless ENABLE_MOUSE_INPUT is +specified. See also: C<GetEvents>, C<InputChar>, C<Mode>, +C<PeekInput>, C<WriteInput>. + +Example: + + @event = $CONSOLE->Input(); + +=item InputChar number + +Reads and returns I<number> characters from the console input buffer, +or C<undef> on errors. See also: C<Input>, C<Mode>. + +Example: + + $key = $CONSOLE->InputChar(1); + +=item InputCP [codepage] + +Gets or sets the input code page used by the console. Note that this +doesn't apply to a console object, but to the standard input +console. This attribute is used by the Write method. See also: +C<OutputCP>. + +Example: + + $codepage = $CONSOLE->InputCP(); + $CONSOLE->InputCP(437); + + # you may want to use the non-instanciated form to avoid confuzion :) + $codepage = Win32::Console::InputCP(); + Win32::Console::InputCP(437); + +=item MaxWindow + +Returns the size of the largest possible console window, based on the +current font and the size of the display. The result is C<undef> on +errors, otherwise a 2-element list containing col, row. + +Example: + + ($maxCol, $maxRow) = $CONSOLE->MaxWindow(); + +=item Mode [flags] + +Gets or sets the input or output mode of a console. I<flags> can be a +combination of the following constants: + + ENABLE_LINE_INPUT + ENABLE_ECHO_INPUT + ENABLE_PROCESSED_INPUT + ENABLE_WINDOW_INPUT + ENABLE_MOUSE_INPUT + ENABLE_PROCESSED_OUTPUT + ENABLE_WRAP_AT_EOL_OUTPUT + +For more informations on the meaning of those flags, please refer to +the L<"Microsoft's Documentation">. + +Example: + + $mode = $CONSOLE->Mode(); + $CONSOLE->Mode(ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); + +=item MouseButtons + +Returns the number of the buttons on your mouse, or C<undef> on errors. + +Example: + + print "Your mouse has ", $CONSOLE->MouseButtons(), " buttons.\n"; + +=item new Win32::Console standard_handle + +=item new Win32::Console [accessmode, sharemode] + +Creates a new console object. The first form creates a handle to a +standard channel, I<standard_handle> can be one of the following: + + STD_OUTPUT_HANDLE + STD_ERROR_HANDLE + STD_INPUT_HANDLE + +The second form, instead, creates a console screen buffer in memory, +which you can access for reading and writing as a normal console, and +then redirect on the standard output (the screen) with C<Display>. In +this case, you can specify one or both of the following values for +I<accessmode>: + + GENERIC_READ + GENERIC_WRITE + +which are the permissions you will have on the created buffer, and one +or both of the following values for I<sharemode>: + + FILE_SHARE_READ + FILE_SHARE_WRITE + +which affect the way the console can be shared. If you don't specify +any of those parameters, all 4 flags will be used. + +Example: + + $STDOUT = new Win32::Console(STD_OUTPUT_HANDLE); + $STDERR = new Win32::Console(STD_ERROR_HANDLE); + $STDIN = new Win32::Console(STD_INPUT_HANDLE); + + $BUFFER = new Win32::Console(); + $BUFFER = new Win32::Console(GENERIC_READ | GENERIC_WRITE); + +=item OutputCP [codepage] + +Gets or sets the output code page used by the console. Note that this +doesn't apply to a console object, but to the standard output console. +See also: C<InputCP>. + +Example: + + $codepage = $CONSOLE->OutputCP(); + $CONSOLE->OutputCP(437); + + # you may want to use the non-instanciated form to avoid confuzion :) + $codepage = Win32::Console::OutputCP(); + Win32::Console::OutputCP(437); + +=item PeekInput + +Does exactly the same as C<Input>, except that the event read is not +removed from the input buffer. See also: C<GetEvents>, C<Input>, +C<InputChar>, C<Mode>, C<WriteInput>. + +Example: + + @event = $CONSOLE->PeekInput(); + +=item ReadAttr [number, col, row] + +Reads the specified I<number> of consecutive attributes, beginning at +I<col>, I<row>, from the console. Returns the attributes read (a +variable containing one character for each attribute), or C<undef> on +errors. You can then pass the returned variable to C<WriteAttr> to +restore the saved attributes on screen. See also: C<ReadChar>, +C<ReadRect>. + +Example: + + $colors = $CONSOLE->ReadAttr(80*25, 0, 0); + +=item ReadChar [number, col, row] + +Reads the specified I<number> of consecutive characters, beginning at +I<col>, I<row>, from the console. Returns a string containing the +characters read, or C<undef> on errors. You can then pass the +returned variable to C<WriteChar> to restore the saved characters on +screen. See also: C<ReadAttr>, C<ReadRect>. + +Example: + + $chars = $CONSOLE->ReadChar(80*25, 0, 0); + +=item ReadRect left, top, right, bottom + +Reads the content (characters and attributes) of the rectangle +specified by I<left>, I<top>, I<right>, I<bottom> from the console. +Returns a string containing the rectangle read, or C<undef> on errors. +You can then pass the returned variable to C<WriteRect> to restore the +saved rectangle on screen (or on another console). See also: +C<ReadAttr>, C<ReadChar>. + +Example: + + $rect = $CONSOLE->ReadRect(0, 0, 80, 25); + +=item Scroll left, top, right, bottom, col, row, char, attr, + [cleft, ctop, cright, cbottom] + +Moves a block of data in a console buffer; the block is identified by +I<left>, I<top>, I<right>, I<bottom>, while I<row>, I<col> identify +the new location of the block. The cells left empty as a result of +the move are filled with the character I<char> and attribute I<attr>. +Optionally you can specify a clipping region with I<cleft>, I<ctop>, +I<cright>, I<cbottom>, so that the content of the console outside this +rectangle are unchanged. Returns C<undef> on errors, a nonzero value +on success. + +Example: + + # scrolls the screen 10 lines down, filling with black spaces + $CONSOLE->Scroll(0, 0, 80, 25, 0, 10, " ", $FG_BLACK | $BG_BLACK); + +=item Select standard_handle + +Redirects a standard handle to the specified console. +I<standard_handle> can have one of the following values: + + STD_INPUT_HANDLE + STD_OUTPUT_HANDLE + STD_ERROR_HANDLE + +Returns C<undef> on errors, a nonzero value on success. + +Example: + + $CONSOLE->Select(STD_OUTPUT_HANDLE); + +=item SetIcon icon_file + +Sets the icon in the title bar of the current console window. + +Example: + + $CONSOLE->SetIcon("C:/My/Path/To/Custom.ico"); + +=item Size [col, row] + +Gets or sets the console buffer size. + +Example: + + ($x, $y) = $CONSOLE->Size(); + $CONSOLE->Size(80, 25); + +=item Title [title] + +Gets or sets the title of the current console window. + +Example: + + $title = $CONSOLE->Title(); + $CONSOLE->Title("This is a title"); + +=item Window [flag, left, top, right, bottom] + +Gets or sets the current console window size. If called without +arguments, returns a 4-element list containing the current window +coordinates in the form of I<left>, I<top>, I<right>, I<bottom>. To +set the window size, you have to specify an additional I<flag> +parameter: if it is 0 (zero), coordinates are considered relative to +the current coordinates; if it is non-zero, coordinates are absolute. + +Example: + + ($left, $top, $right, $bottom) = $CONSOLE->Window(); + $CONSOLE->Window(1, 0, 0, 80, 50); + +=item Write string + +Writes I<string> on the console, using the current attribute, that you +can set with C<Attr>, and advancing the cursor as needed. This isn't +so different from Perl's "print" statement. Returns the number of +characters written or C<undef> on errors. See also: C<WriteAttr>, +C<WriteChar>, C<WriteRect>. + +Example: + + $CONSOLE->Write("Hello, world!"); + +=item WriteAttr attrs, col, row + +Writes the attributes in the string I<attrs>, beginning at I<col>, +I<row>, without affecting the characters that are on screen. The +string attrs can be the result of a C<ReadAttr> function, or you can +build your own attribute string; in this case, keep in mind that every +attribute is treated as a character, not a number (see example). +Returns the number of attributes written or C<undef> on errors. See +also: C<Write>, C<WriteChar>, C<WriteRect>. + +Example: + + $CONSOLE->WriteAttr($attrs, 0, 0); + + # note the use of chr()... + $attrs = chr($FG_BLACK | $BG_WHITE) x 80; + $CONSOLE->WriteAttr($attrs, 0, 0); + +=item WriteChar chars, col, row + +Writes the characters in the string I<attr>, beginning at I<col>, I<row>, +without affecting the attributes that are on screen. The string I<chars> +can be the result of a C<ReadChar> function, or a normal string. Returns +the number of characters written or C<undef> on errors. See also: +C<Write>, C<WriteAttr>, C<WriteRect>. + +Example: + + $CONSOLE->WriteChar("Hello, worlds!", 0, 0); + +=item WriteInput (event) + +Pushes data in the console input buffer. I<(event)> is a list of values, +for more information see C<Input>. The string chars can be the result of +a C<ReadChar> function, or a normal string. Returns the number of +characters written or C<undef> on errors. See also: C<Write>, +C<WriteAttr>, C<WriteRect>. + +Example: + + $CONSOLE->WriteInput(@event); + +=item WriteRect rect, left, top, right, bottom + +Writes a rectangle of characters and attributes (contained in I<rect>) +on the console at the coordinates specified by I<left>, I<top>, +I<right>, I<bottom>. I<rect> can be the result of a C<ReadRect> +function. Returns C<undef> on errors, otherwise a 4-element list +containing the coordinates of the affected rectangle, in the format +I<left>, I<top>, I<right>, I<bottom>. See also: C<Write>, +C<WriteAttr>, C<WriteChar>. + +Example: + + $CONSOLE->WriteRect($rect, 0, 0, 80, 25); + +=back + + +=head2 Constants + +The following constants are exported in the main namespace of your +script using Win32::Console: + + BACKGROUND_BLUE + BACKGROUND_GREEN + BACKGROUND_INTENSITY + BACKGROUND_RED + CAPSLOCK_ON + CONSOLE_TEXTMODE_BUFFER + ENABLE_ECHO_INPUT + ENABLE_LINE_INPUT + ENABLE_MOUSE_INPUT + ENABLE_PROCESSED_INPUT + ENABLE_PROCESSED_OUTPUT + ENABLE_WINDOW_INPUT + ENABLE_WRAP_AT_EOL_OUTPUT + ENHANCED_KEY + FILE_SHARE_READ + FILE_SHARE_WRITE + FOREGROUND_BLUE + FOREGROUND_GREEN + FOREGROUND_INTENSITY + FOREGROUND_RED + LEFT_ALT_PRESSED + LEFT_CTRL_PRESSED + NUMLOCK_ON + GENERIC_READ + GENERIC_WRITE + RIGHT_ALT_PRESSED + RIGHT_CTRL_PRESSED + SCROLLLOCK_ON + SHIFT_PRESSED + STD_INPUT_HANDLE + STD_OUTPUT_HANDLE + STD_ERROR_HANDLE + +Additionally, the following variables can be used: + + $FG_BLACK + $FG_GRAY + $FG_BLUE + $FG_LIGHTBLUE + $FG_RED + $FG_LIGHTRED + $FG_GREEN + $FG_LIGHTGREEN + $FG_MAGENTA + $FG_LIGHTMAGENTA + $FG_CYAN + $FG_LIGHTCYAN + $FG_BROWN + $FG_YELLOW + $FG_LIGHTGRAY + $FG_WHITE + + $BG_BLACK + $BG_GRAY + $BG_BLUE + $BG_LIGHTBLUE + $BG_RED + $BG_LIGHTRED + $BG_GREEN + $BG_LIGHTGREEN + $BG_MAGENTA + $BG_LIGHTMAGENTA + $BG_CYAN + $BG_LIGHTCYAN + $BG_BROWN + $BG_YELLOW + $BG_LIGHTGRAY + $BG_WHITE + + $ATTR_NORMAL + $ATTR_INVERSE + +ATTR_NORMAL is set to gray foreground on black background (DOS's +standard colors). + + +=head2 Microsoft's Documentation + +Documentation for the Win32 Console and Character mode Functions can +be found on Microsoft's site at this URL: + +http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/sys/src/conchar.htm + +A reference of the available functions is at: + +http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/sys/src/conchar_34.htm + + +=head1 AUTHOR + +Aldo Calpini <a.calpini@romagiubileo.it> + +=head1 CREDITS + +Thanks to: Jesse Dougherty, Dave Roth, ActiveWare, and the +Perl-Win32-Users community. + +=head1 DISCLAIMER + +This program is FREE; you can redistribute, modify, disassemble, or +even reverse engineer this software at your will. Keep in mind, +however, that NOTHING IS GUARANTEED to work and everything you do is +AT YOUR OWN RISK - I will not take responsibility for any damage, loss +of money and/or health that may arise from the use of this program! + +This is distributed under the terms of Larry Wall's Artistic License. diff --git a/Master/tlpkg/tlperl/lib/Win32/Event.pm b/Master/tlpkg/tlperl/lib/Win32/Event.pm new file mode 100644 index 00000000000..5faddf5a76e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Event.pm @@ -0,0 +1,104 @@ +#--------------------------------------------------------------------- +package Win32::Event; +# +# Copyright 1998 Christopher J. Madsen +# +# Author: Christopher J. Madsen <cjm@pobox.com> +# Created: 3 Feb 1998 from the ActiveWare version +# Version: 1.00 (6-Feb-1998) +# +# This program is free software; you can redistribute it and/or modify +# it under the same terms as Perl itself. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the +# GNU General Public License or the Artistic License for more details. +# +# Use Win32 event objects for synchronization +#--------------------------------------------------------------------- + +$VERSION = '1.01'; + +use Win32::IPC 1.00 '/./'; # Import everything +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader Win32::IPC); +@EXPORT_OK = qw( + wait_all wait_any INFINITE +); + +bootstrap Win32::Event; + +1; +__END__ + +=head1 NAME + +Win32::Event - Use Win32 event objects from Perl + +=head1 SYNOPSIS + + use Win32::Event; + + $event = Win32::Event->new($manual,$initial,$name); + $event->wait(); + +=head1 DESCRIPTION + +This module allows access to the Win32 event objects. The C<wait> +method and C<wait_all> & C<wait_any> functions are inherited from the +L<"Win32::IPC"> module. + +=head2 Methods + +=over 4 + +=item $event = Win32::Event->new([$manual, [$initial, [$name]]]) + +Constructor for a new event object. If C<$manual> is true, you must +manually reset the event after it is signalled (the default is false). +If C<$initial> is true, the initial state of the object is signalled +(default false). If C<$name> is omitted, creates an unnamed event +object. + +If C<$name> signifies an existing event object, then C<$manual> and +C<$initial> are ignored and the object is opened. If this happens, +C<$^E> will be set to 183 (ERROR_ALREADY_EXISTS). + +=item $event = Win32::Event->open($name) + +Constructor for opening an existing event object. + +=item $event->pulse + +Signal the C<$event> and then immediately reset it. If C<$event> is a +manual-reset event, releases all threads currently blocking on it. If +it's an auto-reset event, releases just one thread. + +If no threads are waiting, just resets the event. + +=item $event->reset + +Reset the C<$event> to nonsignalled. + +=item $event->set + +Set the C<$event> to signalled. + +=item $event->wait([$timeout]) + +Wait for C<$event> to be signalled. See L<"Win32::IPC">. + +=back + +=head1 AUTHOR + +Christopher J. Madsen E<lt>F<cjm@pobox.com>E<gt> + +=cut + +# Local Variables: +# tmtrack-file-task: "Win32::Event" +# End: diff --git a/Master/tlpkg/tlperl/lib/Win32/EventLog.pm b/Master/tlpkg/tlperl/lib/Win32/EventLog.pm new file mode 100644 index 00000000000..141821556e7 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/EventLog.pm @@ -0,0 +1,471 @@ +# +# EventLog.pm +# +# Creates an object oriented interface to the Windows NT Evenlog +# Written by Jesse Dougherty +# + +package Win32::EventLog; + +use strict; +use vars qw($VERSION $AUTOLOAD @ISA @EXPORT $GetMessageText); +$VERSION = '0.074'; + +require Exporter; +require DynaLoader; + +die "The Win32::Eventlog module works only on Windows NT" + unless Win32::IsWinNT(); + +@ISA= qw(Exporter DynaLoader); +@EXPORT = qw( + EVENTLOG_AUDIT_FAILURE + EVENTLOG_AUDIT_SUCCESS + EVENTLOG_BACKWARDS_READ + EVENTLOG_END_ALL_PAIRED_EVENTS + EVENTLOG_END_PAIRED_EVENT + EVENTLOG_ERROR_TYPE + EVENTLOG_FORWARDS_READ + EVENTLOG_INFORMATION_TYPE + EVENTLOG_PAIRED_EVENT_ACTIVE + EVENTLOG_PAIRED_EVENT_INACTIVE + EVENTLOG_SEEK_READ + EVENTLOG_SEQUENTIAL_READ + EVENTLOG_START_PAIRED_EVENT + EVENTLOG_SUCCESS + EVENTLOG_WARNING_TYPE +); + +$GetMessageText=0; + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + # reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($!) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + my ($pack,$file,$line) = caller; + die "Unknown Win32::EventLog macro $constname, at $file line $line.\n"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +# +# new() +# +# Win32::EventLog->new("source name", "ServerName"); +# +sub new { + die "usage: PACKAGE->new(SOURCENAME[, SERVERNAME])\n" unless @_ > 1; + my ($class,$source,$server) = @_; + my $handle; + + # Create new handle + if ($source !~ /\\/) { + OpenEventLog($handle, $server, $source); + } + else { + OpenBackupEventLog($handle, $server, $source); + } + return bless {handle => $handle, + Source => $source, + Computer => $server} => $class; +} + +sub DESTROY {shift->Close} + +# +# Open (the rather braindead old way) +# A variable initialized to empty must be supplied as the first +# arg, followed by whatever new() takes +# +sub Open { + $_[0] = Win32::EventLog->new($_[1],$_[2]); +} + +sub OpenBackup { + my ($class,$source,$server) = @_; + OpenBackupEventLog(my $handle, $server, $source); + return bless {handle => $handle, + Source => $source, + Computer => $server} => $class; +} + +sub Backup { + die " usage: OBJECT->Backup(FILENAME)\n" unless @_ == 2; + my ($self,$file) = @_; + return BackupEventLog($self->{handle}, $file); +} + +sub Close { + my $self = shift; + CloseEventLog($self->{handle}); + $self->{handle} = 0; +} + +# Read +# Note: the EventInfo arguement requires a hash reference. +sub Read { + my $self = shift; + + die "usage: OBJECT->Read(FLAGS, RECORDOFFSET, HASHREF)\n" unless @_ == 3; + + my ($readflags,$recordoffset) = @_; + # The following is stolen shamelessly from Wyt's tests for the registry. + my $result = ReadEventLog($self->{handle}, $readflags, $recordoffset, + my $header, my $source, my $computer, my $sid, + my $data, my $strings); + my ($length, + $reserved, + $recordnumber, + $timegenerated, + $timewritten, + $eventid, + $eventtype, + $numstrings, + $eventcategory, + $reservedflags, + $closingrecordnumber, + $stringoffset, + $usersidlength, + $usersidoffset, + $datalength, + $dataoffset) = unpack('l6s4l6', $header); + + # make a hash out of the values returned from ReadEventLog. + my %h = ( Source => $source, + Computer => $computer, + Length => $datalength, + Category => $eventcategory, + RecordNumber => $recordnumber, + TimeGenerated => $timegenerated, + Timewritten => $timewritten, + EventID => $eventid, + EventType => $eventtype, + ClosingRecordNumber => $closingrecordnumber, + User => $sid, + Strings => $strings, + Data => $data, + ); + + # get the text message here + if ($result and $GetMessageText) { + GetEventLogText($source, $eventid, $strings, $numstrings, my $message); + $h{Message} = $message; + } + + if (ref($_[2]) eq 'HASH') { + %{$_[2]} = %h; # this needed for Read(...,\%foo) case + } + else { + $_[2] = \%h; + } + return $result; +} + +sub GetMessageText { + my $self = shift; + local $^W; + GetEventLogText($self->{Source}, + $self->{EventID}, + $self->{Strings}, + $self->{Strings} =~ tr/\0/\0/, + my $message); + + $self->{Message} = $message; + return $message; +} + +sub Report { + die "usage: OBJECT->Report( HASHREF )\n" unless @_ == 2; + my ($self,$EventInfo) = @_; + + die "Win32::EventLog::Report requires a hash reference as arg 2\n" + unless ref($EventInfo) eq "HASH"; + + my $computer = $EventInfo->{Computer} ? $EventInfo->{Computer} + : $self->{Computer}; + my $source = exists($EventInfo->{Source}) ? $EventInfo->{Source} + : $self->{Source}; + + return WriteEventLog($computer, $source, $EventInfo->{EventType}, + $EventInfo->{Category}, $EventInfo->{EventID}, 0, + $EventInfo->{Data}, split(/\0/, $EventInfo->{Strings})); + +} + +sub GetOldest { + my $self = shift; + die "usage: OBJECT->GetOldest( SCALAREF )\n" unless @_ == 1; + return GetOldestEventLogRecord($self->{handle},$_[0]); +} + +sub GetNumber { + my $self = shift; + die "usage: OBJECT->GetNumber( SCALARREF )\n" unless @_ == 1; + return GetNumberOfEventLogRecords($self->{handle}, $_[0]); +} + +sub Clear { + my ($self,$file) = @_; + die "usage: OBJECT->Clear( FILENAME )\n" unless @_ == 2; + return ClearEventLog($self->{handle}, $file); +} + +bootstrap Win32::EventLog; + +1; +__END__ + +=head1 NAME + +Win32::EventLog - Process Win32 Event Logs from Perl + +=head1 SYNOPSIS + + use Win32::EventLog + $handle=Win32::EventLog->new("Application"); + +=head1 DESCRIPTION + +This module implements most of the functionality available from the +Win32 API for accessing and manipulating Win32 Event Logs. The access +to the EventLog routines is divided into those that relate to an +EventLog object and its associated methods and those that relate other +EventLog tasks (like adding an EventLog record). + +=head1 The EventLog Object and its Methods + +The following methods are available to open, read, close and backup +EventLogs. + +=over 4 + +=item Win32::EventLog->new(SOURCENAME [,SERVERNAME]); + +The new() method creates a new EventLog object and returns a handle +to it. This hande is then used to call the methods below. + +The method is overloaded in that if the supplied SOURCENAME +argument contains one or more literal '\' characters (an illegal +character in a SOURCENAME), it assumes that you are trying to open +a backup eventlog and uses SOURCENAME as the backup eventlog to +open. Note that when opening a backup eventlog, the SERVERNAME +argument is ignored (as it is in the underlying Win32 API). For +EventLogs on remote machines, the SOURCENAME parameter must +therefore be specified as a UNC path. + +=item $handle->Backup(FILENAME); + +The Backup() method backs up the EventLog represented by $handle. It +takes a single arguemt, FILENAME. When $handle represents an +EventLog on a remote machine, FILENAME is filename on the remote +machine and cannot be a UNC path (i.e you must use F<C:\TEMP\App.EVT>). +The method will fail if the log file already exists. + +=item $handle->Read(FLAGS, OFFSET, HASHREF); + +The Read() method read an EventLog entry from the EventLog represented +by $handle. + +=item $handle->Close(); + +The Close() method closes the EventLog represented by $handle. After +Close() has been called, any further attempt to use the EventLog +represented by $handle will fail. + +=item $handle->GetOldest(SCALARREF); + +The GetOldest() method number of the the oldest EventLog record in +the EventLog represented by $handle. This is required to correctly +compute the OFFSET required by the Read() method. + +=item $handle->GetNumber(SCALARREF); + +The GetNumber() method returns the number of EventLog records in +the EventLog represented by $handle. The number of the most recent +record in the EventLog is therefore computed by + + $handle->GetOldest($oldest); + $handle->GetNumber($lastRec); + $lastRecOffset=$oldest+$lastRec; + +=item $handle->Clear(FILENAME); + +The Clear() method clears the EventLog represented by $handle. If +you provide a non-null FILENAME, the EventLog will be backed up +into FILENAME before the EventLog is cleared. The method will fail +if FILENAME is specified and the file refered to exists. Note also +that FILENAME specifies a file local to the machine on which the +EventLog resides and cannot be specified as a UNC name. + +=item $handle->Report(HASHREF); + +The Report() method generates an EventLog entry. The HASHREF should +contain the following keys: + +=over 4 + +=item C<Computer> + +The C<Computer> field specfies which computer you want the EventLog +entry recorded. If this key doesn't exist, the server name used to +create the $handle is used. + +=item C<Source> + +The C<Source> field specifies the source that generated the EventLog +entry. If this key doesn't exist, the source name used to create the +$handle is used. + +=item C<EventType> + +The C<EventType> field should be one of the constants + +=over 4 + +=item C<EVENTLOG_ERROR_TYPE> + +An Error event is being logged. + +=item C<EVENTLOG_WARNING_TYPE> + +A Warning event is being logged. + +=item C<EVENTLOG_INFORMATION_TYPE> + +An Information event is being logged. + +=item C<EVENTLOG_AUDIT_SUCCESS> + +A Success Audit event is being logged (typically in the Security +EventLog). + +=item C<EVENTLOG_AUDIT_FAILURE> + +A Failure Audit event is being logged (typically in the Security +EventLog). + +=back + +These constants are exported into the main namespace by default. + +=item C<Category> + +The C<Category> field can have any value you want. It is specific to +the particular Source. + +=item C<EventID> + +The C<EventID> field should contain the ID of the message that this +event pertains too. This assumes that you have an associated message +file (indirectly referenced by the field C<Source>). + +=item C<Data> + +The C<Data> field contains raw data associated with this event. + +=item C<Strings> + +The C<Strings> field contains the single string that itself contains +NUL terminated sub-strings. This are used with the EventID to generate +the message as seen from (for example) the Event Viewer application. + +=back + +=back + +=head1 Other Win32::EventLog functions. + +The following functions are part of the Win32::EventLog package but +are not callable from an EventLog object. + +=over 4 + +=item GetMessageText(HASHREF); + +The GetMessageText() function assumes that HASHREF was obtained by +a call to C<$handle-E<gt>Read()>. It returns the formatted string that +represents the fully resolved text of the EventLog message (such as +would be seen in the Windows NT Event Viewer). For convenience, the +key 'Message' in the supplied HASHREF is also set to the return value +of this function. + +If you set the variable $Win32::EventLog::GetMessageText to 1 then +each call to C<$handle-E<gt>Read()> will call this function automatically. + +=back + +=head1 Example 1 + +The following example illustrates the way in which the EventLog module +can be used. It opens the System EventLog and reads through it from +oldest to newest records. For each record from the B<Source> EventLog +it extracts the full text of the Entry and prints the EventLog message +text out. + + use Win32::EventLog; + + $handle=Win32::EventLog->new("System", $ENV{ComputerName}) + or die "Can't open Application EventLog\n"; + $handle->GetNumber($recs) + or die "Can't get number of EventLog records\n"; + $handle->GetOldest($base) + or die "Can't get number of oldest EventLog record\n"; + + while ($x < $recs) { + $handle->Read(EVENTLOG_FORWARDS_READ|EVENTLOG_SEEK_READ, + $base+$x, + $hashRef) + or die "Can't read EventLog entry #$x\n"; + if ($hashRef->{Source} eq "EventLog") { + Win32::EventLog::GetMessageText($hashRef); + print "Entry $x: $hashRef->{Message}\n"; + } + $x++; + } + +=head1 Example 2 + +To backup and clear the EventLogs on a remote machine, do the following :- + + use Win32::EventLog; + + $myServer="\\\\my-server"; # your servername here. + my($date)=join("-", ((split(/\s+/, scalar(localtime)))[0,1,2,4])); + my($dest); + + for my $eventLog ("Application", "System", "Security") { + $handle=Win32::EventLog->new($eventLog, $myServer) + or die "Can't open Application EventLog on $myServer\n"; + + $dest="C:\\BackupEventLogs\\$eventLog\\$date.evt"; + $handle->Backup($dest) + or warn "Could not backup and clear the $eventLog EventLog on $myServer ($^E)\n"; + + $handle->Close; + } + +Note that only the Clear method is required. Note also that if the +file $dest exists, the function will fail. + +=head1 BUGS + +None currently known. + +The test script for 'make test' should be re-written to use the +EventLog object. + +=head1 AUTHOR + +Original code by Jesse Dougherty for HiP Communications. Additional +fixes and updates attributed to Martin Pauley +<martin.pauley@ulsterbank.ltd.uk>) and Bret Giddings (bret@essex.ac.uk). diff --git a/Master/tlpkg/tlperl/lib/Win32/File.pm b/Master/tlpkg/tlperl/lib/Win32/File.pm new file mode 100644 index 00000000000..d67a25448c8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/File.pm @@ -0,0 +1,118 @@ +package Win32::File; + +# +# File.pm +# Written by Douglas_Lankshear@ActiveWare.com +# +# subsequent hacks: +# Gurusamy Sarathy +# + +$VERSION = '0.05'; + +require Exporter; +require DynaLoader; + +@ISA= qw( Exporter DynaLoader ); +@EXPORT = qw( + ARCHIVE + COMPRESSED + DIRECTORY + HIDDEN + NORMAL + OFFLINE + READONLY + SYSTEM + TEMPORARY + ); +@EXPORT_OK = qw(GetAttributes SetAttributes); + +=head1 NAME + +Win32::File - manage file attributes in perl + +=head1 SYNOPSIS + + use Win32::File; + +=head1 DESCRIPTION + +This module offers the retrieval and setting of file attributes. + +=head1 Functions + +=head2 NOTE + +All of the functions return FALSE (0) if they fail, unless otherwise noted. +The function names are exported into the caller's namespace by request. + +=over 10 + +=item GetAttributes(filename, returnedAttributes) + +Gets the attributes of a file or directory. returnedAttributes will be set +to the OR-ed combination of the filename attributes. + +=item SetAttributes(filename, newAttributes) + +Sets the attributes of a file or directory. newAttributes must be an OR-ed +combination of the attributes. + +=back + +=head1 Constants + +The following constants are exported by default. + +=over 10 + +=item ARCHIVE + +=item COMPRESSED + +=item DIRECTORY + +=item HIDDEN + +=item NORMAL + +=item OFFLINE + +=item READONLY + +=item SYSTEM + +=item TEMPORARY + +=back + +=cut + +sub AUTOLOAD +{ + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname); + if($! != 0) + { + if($! =~ /Invalid/) + { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else + { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::File macro $constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::File; + +1; +__END__ diff --git a/Master/tlpkg/tlperl/lib/Win32/FileSecurity.pm b/Master/tlpkg/tlperl/lib/Win32/FileSecurity.pm new file mode 100644 index 00000000000..6c6e5865336 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/FileSecurity.pm @@ -0,0 +1,308 @@ +package Win32::FileSecurity; + +# +# FileSecurity.pm +# By Monte Mitzelfelt, monte@conchas.nm.org +# Larry Wall's Artistic License applies to all related Perl +# and C code for this module +# Thanks to the guys at ActiveWare! +# ver 0.67 ALPHA 1997.07.07 +# + +require Exporter; +require DynaLoader; +use Carp ; + +$VERSION = '1.04'; + +require Win32 unless defined &Win32::IsWinNT; +croak "The Win32::FileSecurity module works only on Windows NT" unless Win32::IsWinNT(); + +@ISA= qw( Exporter DynaLoader ); + +require Exporter ; +require DynaLoader ; + +@ISA = qw(Exporter DynaLoader) ; +@EXPORT_OK = qw( + Get + Set + EnumerateRights + MakeMask + DELETE + READ_CONTROL + WRITE_DAC + WRITE_OWNER + SYNCHRONIZE + STANDARD_RIGHTS_REQUIRED + STANDARD_RIGHTS_READ + STANDARD_RIGHTS_WRITE + STANDARD_RIGHTS_EXECUTE + STANDARD_RIGHTS_ALL + SPECIFIC_RIGHTS_ALL + ACCESS_SYSTEM_SECURITY + MAXIMUM_ALLOWED + GENERIC_READ + GENERIC_WRITE + GENERIC_EXECUTE + GENERIC_ALL + F + FULL + R + READ + C + CHANGE + A + ADD + ) ; + +sub AUTOLOAD { + local($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + $val = constant($constname); + if($! != 0) { + if($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::FileSecurity macro " + ."$constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::FileSecurity; + +1; + +__END__ + +=head1 NAME + +Win32::FileSecurity - manage FileSecurity Discretionary Access Control Lists in perl + +=head1 SYNOPSIS + + use Win32::FileSecurity; + +=head1 DESCRIPTION + +This module offers control over the administration of system FileSecurity DACLs. +You may want to use Get and EnumerateRights to get an idea of what mask values +correspond to what rights as viewed from File Manager. + +=head1 CONSTANTS + + DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, + SYNCHRONIZE, STANDARD_RIGHTS_REQUIRED, + STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL, + SPECIFIC_RIGHTS_ALL, ACCESS_SYSTEM_SECURITY, + MAXIMUM_ALLOWED, GENERIC_READ, GENERIC_WRITE, + GENERIC_EXECUTE, GENERIC_ALL, F, FULL, R, READ, + C, CHANGE + +=head1 FUNCTIONS + +=head2 NOTE: + +All of the functions return false if they fail, unless otherwise noted. +Errors returned via $! containing both Win32 GetLastError() and a text message +indicating Win32 function that failed. + +=over 10 + +=item constant( $name, $set ) + +Stores the value of named constant $name into $set. +Same as C<$set = Win32::FileSecurity::NAME_OF_CONSTANT();>. + +=item Get( $filename, \%permisshash ) + +Gets the DACLs of a file or directory. + +=item Set( $filename, \%permisshash ) + +Sets the DACL for a file or directory. + +=item EnumerateRights( $mask, \@rightslist ) + +Turns the bitmask in $mask into a list of strings in @rightslist. + +=item MakeMask( qw( DELETE READ_CONTROL ) ) + +Takes a list of strings representing constants and returns a bitmasked +integer value. + +=back + +=head2 %permisshash + +Entries take the form $permisshash{USERNAME} = $mask ; + +=head1 EXAMPLE1 + + # Gets the rights for all files listed on the command line. + use Win32::FileSecurity qw(Get EnumerateRights); + + foreach( @ARGV ) { + next unless -e $_ ; + if ( Get( $_, \%hash ) ) { + while( ($name, $mask) = each %hash ) { + print "$name:\n\t"; + EnumerateRights( $mask, \@happy ) ; + print join( "\n\t", @happy ), "\n"; + } + } + else { + print( "Error #", int( $! ), ": $!" ) ; + } + } + +=head1 EXAMPLE2 + + # Gets existing DACL and modifies Administrator rights + use Win32::FileSecurity qw(MakeMask Get Set); + + # These masks show up as Full Control in File Manager + $file = MakeMask( qw( FULL ) ); + + $dir = MakeMask( qw( + FULL + GENERIC_ALL + ) ); + + foreach( @ARGV ) { + s/\\$//; + next unless -e; + Get( $_, \%hash ) ; + $hash{Administrator} = ( -d ) ? $dir : $file ; + Set( $_, \%hash ) ; + } + +=head1 COMMON MASKS FROM CACLS AND WINFILE + +=head2 READ + + MakeMask( qw( FULL ) ); # for files + MakeMask( qw( READ GENERIC_READ GENERIC_EXECUTE ) ); # for directories + +=head2 CHANGE + + MakeMask( qw( CHANGE ) ); # for files + MakeMask( qw( CHANGE GENERIC_WRITE GENERIC_READ GENERIC_EXECUTE ) ); # for directories + +=head2 ADD & READ + + MakeMask( qw( ADD GENERIC_READ GENERIC_EXECUTE ) ); # for directories only! + +=head2 FULL + + MakeMask( qw( FULL ) ); # for files + MakeMask( qw( FULL GENERIC_ALL ) ); # for directories + +=head1 RESOURCES + +From Microsoft: check_sd + http://premium.microsoft.com/download/msdn/samples/2760.exe + +(thanks to Guert Schimmel at Sybase for turning me on to this one) + +=head1 VERSION + +1.03 ALPHA 97-12-14 + +=head1 REVISION NOTES + +=over 10 + +=item 1.03 ALPHA 1998.01.11 + +Imported diffs from 0.67 (parent) version + +=item 1.02 ALPHA 1997.12.14 + +Pod fixes, @EXPORT list additions <gsar@activestate.com> + +Fix unitialized vars on unknown ACLs <jmk@exc.bybyte.de> + +=item 1.01 ALPHA 1997.04.25 + +CORE Win32 version imported from 0.66 <gsar@activestate.com> + +=item 0.67 ALPHA 1997.07.07 + +Kludged bug in mapping bits to separate ACE's. Notably, this screwed +up CHANGE access by leaving out a delete bit in the +C<INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE> Access Control Entry. + +May need to rethink... + +=item 0.66 ALPHA 1997.03.13 + +Fixed bug in memory allocation check + +=item 0.65 ALPHA 1997.02.25 + +Tested with 5.003 build 303 + +Added ISA exporter, and @EXPORT_OK + +Added F, FULL, R, READ, C, CHANGE as composite pre-built mask names. + +Added server\ to keys returned in hash from Get + +Made constants and MakeMask case insensitive (I don't know why I did that) + +Fixed mask comparison in ListDacl and Enumerate Rights from simple & mask +to exact bit match ! ( ( x & y ) ^ x ) makes sure all bits in x +are set in y + +Fixed some "wild" pointers + +=item 0.60 ALPHA 1996.07.31 + +Now suitable for file and directory permissions + +Included ListDacl.exe in bundle for debugging + +Added "intuitive" inheritance for directories, basically functions like FM +triggered by presence of GENERIC_ rights this may need to change + +see EXAMPLE2 + +Changed from AddAccessAllowedAce to AddAce for control over inheritance + +=item 0.51 ALPHA 1996.07.20 + +Fixed memory allocation bug + +=item 0.50 ALPHA 1996.07.29 + +Base functionality + +Using AddAccessAllowedAce + +Suitable for file permissions + +=back + +=head1 KNOWN ISSUES / BUGS + +=over 10 + +=item 1 + +May not work on remote drives. + +=item 2 + +Errors croak, don't return via $! as documented. + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/IPC.pm b/Master/tlpkg/tlperl/lib/Win32/IPC.pm new file mode 100644 index 00000000000..c97279b24c5 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/IPC.pm @@ -0,0 +1,195 @@ +#--------------------------------------------------------------------- +package Win32::IPC; +# +# Copyright 1998 Christopher J. Madsen +# +# Created: 3 Feb 1998 from the ActiveWare version +# (c) 1995 Microsoft Corporation. All rights reserved. +# Developed by ActiveWare Internet Corp., http://www.ActiveWare.com +# +# Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com> +# +# Author: Christopher J. Madsen <cjm@pobox.com> +# Version: 1.03 (11-Jul-2003) +# +# This program is free software; you can redistribute it and/or modify +# it under the same terms as Perl itself. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the +# GNU General Public License or the Artistic License for more details. +# +# Base class for Win32 synchronization objects +#--------------------------------------------------------------------- + +$VERSION = '1.03'; + +require Exporter; +require DynaLoader; +use strict; +use vars qw($AUTOLOAD $VERSION @ISA @EXPORT @EXPORT_OK); + +@ISA = qw(Exporter DynaLoader); +@EXPORT = qw( + INFINITE + WaitForMultipleObjects +); +@EXPORT_OK = qw( + wait_any wait_all +); + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + local $! = 0; + my $val = constant($constname); + if ($! != 0) { + my ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::IPC macro $constname, used at $file line $line."; + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} # end AUTOLOAD + +bootstrap Win32::IPC; + +# How's this for cryptic? Use wait_any or wait_all! +sub WaitForMultipleObjects +{ + my $result = (($_[1] ? wait_all($_[0], $_[2]) + : wait_any($_[0], $_[2])) + ? 1 + : 0); + @{$_[0]} = (); # Bug for bug compatibility! Use wait_any or wait_all! + $result; +} # end WaitForMultipleObjects + +1; +__END__ + +=head1 NAME + +Win32::IPC - Base class for Win32 synchronization objects + +=head1 SYNOPSIS + + use Win32::Event 1.00 qw(wait_any); + #Create objects. + + wait_any(@ListOfObjects,$timeout); + +=head1 DESCRIPTION + +This module is loaded by the other Win32 synchronization modules. You +shouldn't need to load it yourself. It supplies the wait functions to +those modules. + +The synchronization modules are L<"Win32::ChangeNotify">, +L<"Win32::Event">, L<"Win32::Mutex">, & L<"Win32::Semaphore">. + +In addition, you can use C<wait_any> and C<wait_all> with +L<"Win32::Console"> and L<"Win32::Process"> objects. (However, those +modules do not export the wait functions; you must load one of the +synchronization modules (or just Win32::IPC)). + +=head2 Methods + +B<Win32::IPC> supplies one method to all synchronization objects. + +=over 4 + +=item $obj->wait([$timeout]) + +Waits for C<$obj> to become signalled. C<$timeout> is the maximum time +to wait (in milliseconds). If C<$timeout> is omitted, waits forever. +If C<$timeout> is 0, returns immediately. + +Returns: + + +1 The object is signalled + -1 The object is an abandoned mutex + 0 Timed out + undef An error occurred + +=back + +=head2 Functions + +=over 4 + +=item wait_any(@objects, [$timeout]) + +Waits for at least one of the C<@objects> to become signalled. +C<$timeout> is the maximum time to wait (in milliseconds). If +C<$timeout> is omitted, waits forever. If C<$timeout> is 0, returns +immediately. + +The return value indicates which object ended the wait: + + +N $object[N-1] is signalled + -N $object[N-1] is an abandoned mutex + 0 Timed out + undef An error occurred + +If more than one object became signalled, the one with the lowest +index is used. + +=item wait_all(@objects, [$timeout]) + +This is the same as C<wait_any>, but it waits for all the C<@objects> +to become signalled. The return value indicates the last object to +become signalled, and is negative if at least one of the C<@objects> +is an abandoned mutex. + +=back + +=head2 Deprecated Functions and Methods + +B<Win32::IPC> still supports the ActiveWare syntax, but its use is +deprecated. + +=over 4 + +=item INFINITE + +Constant value for an infinite timeout. Omit the C<$timeout> argument +instead. + +=item WaitForMultipleObjects(\@objects, $wait_all, $timeout) + +Warning: C<WaitForMultipleObjects> erases C<@objects>! +Use C<wait_all> or C<wait_any> instead. + +=item $obj->Wait($timeout) + +Similar to C<not $obj-E<gt>wait($timeout)>. + +=back + +=head1 INTERNALS + +The C<wait_any> and C<wait_all> functions support two kinds of +objects. Objects derived from C<Win32::IPC> are expected to consist +of a reference to a scalar containing the Win32 HANDLE as an IV. + +Other objects (for which C<UNIVERSAL::isa($object, "Win32::IPC")> is +false), are expected to implement a C<get_Win32_IPC_HANDLE> method. +When called in scalar context with no arguments, this method should +return a Win32 HANDLE (as an IV) suitable for passing to the Win32 +WaitForMultipleObjects API function. + +=head1 AUTHOR + +Christopher J. Madsen E<lt>F<cjm@pobox.com>E<gt> + +Loosely based on the original module by ActiveWare Internet Corp., +F<http://www.ActiveWare.com> + +=cut + +# Local Variables: +# tmtrack-file-task: "Win32::IPC" +# End: diff --git a/Master/tlpkg/tlperl/lib/Win32/Internet.pm b/Master/tlpkg/tlperl/lib/Win32/Internet.pm new file mode 100644 index 00000000000..f6dac3130af --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Internet.pm @@ -0,0 +1,3009 @@ +####################################################################### +# +# Win32::Internet - Perl Module for Internet Extensions +# ^^^^^^^^^^^^^^^ +# This module creates an object oriented interface to the Win32 +# Internet Functions (WININET.DLL). +# +# Version: 0.08 (14 Feb 1997) +# Version: 0.081 (25 Sep 1999) +# Version: 0.082 (04 Sep 2001) +# +####################################################################### + +# changes: +# - fixed 2 bugs in Option(s) related subs +# - works with build 30x also + +package Win32::Internet; + +require Exporter; # to export the constants to the main:: space +require DynaLoader; # to dynuhlode the module. + +# use Win32::WinError; # for windows constants. + +@ISA= qw( Exporter DynaLoader ); +@EXPORT = qw( + HTTP_ADDREQ_FLAG_ADD + HTTP_ADDREQ_FLAG_REPLACE + HTTP_QUERY_ALLOW + HTTP_QUERY_CONTENT_DESCRIPTION + HTTP_QUERY_CONTENT_ID + HTTP_QUERY_CONTENT_LENGTH + HTTP_QUERY_CONTENT_TRANSFER_ENCODING + HTTP_QUERY_CONTENT_TYPE + HTTP_QUERY_COST + HTTP_QUERY_CUSTOM + HTTP_QUERY_DATE + HTTP_QUERY_DERIVED_FROM + HTTP_QUERY_EXPIRES + HTTP_QUERY_FLAG_REQUEST_HEADERS + HTTP_QUERY_FLAG_SYSTEMTIME + HTTP_QUERY_LANGUAGE + HTTP_QUERY_LAST_MODIFIED + HTTP_QUERY_MESSAGE_ID + HTTP_QUERY_MIME_VERSION + HTTP_QUERY_PRAGMA + HTTP_QUERY_PUBLIC + HTTP_QUERY_RAW_HEADERS + HTTP_QUERY_RAW_HEADERS_CRLF + HTTP_QUERY_REQUEST_METHOD + HTTP_QUERY_SERVER + HTTP_QUERY_STATUS_CODE + HTTP_QUERY_STATUS_TEXT + HTTP_QUERY_URI + HTTP_QUERY_USER_AGENT + HTTP_QUERY_VERSION + HTTP_QUERY_WWW_LINK + ICU_BROWSER_MODE + ICU_DECODE + ICU_ENCODE_SPACES_ONLY + ICU_ESCAPE + ICU_NO_ENCODE + ICU_NO_META + ICU_USERNAME + INTERNET_FLAG_PASSIVE + INTERNET_FLAG_ASYNC + INTERNET_HYPERLINK + INTERNET_FLAG_KEEP_CONNECTION + INTERNET_FLAG_MAKE_PERSISTENT + INTERNET_FLAG_NO_AUTH + INTERNET_FLAG_NO_AUTO_REDIRECT + INTERNET_FLAG_NO_CACHE_WRITE + INTERNET_FLAG_NO_COOKIES + INTERNET_FLAG_READ_PREFETCH + INTERNET_FLAG_RELOAD + INTERNET_FLAG_RESYNCHRONIZE + INTERNET_FLAG_TRANSFER_ASCII + INTERNET_FLAG_TRANSFER_BINARY + INTERNET_INVALID_PORT_NUMBER + INTERNET_INVALID_STATUS_CALLBACK + INTERNET_OPEN_TYPE_DIRECT + INTERNET_OPEN_TYPE_PROXY + INTERNET_OPEN_TYPE_PROXY_PRECONFIG + INTERNET_OPTION_CONNECT_BACKOFF + INTERNET_OPTION_CONNECT_RETRIES + INTERNET_OPTION_CONNECT_TIMEOUT + INTERNET_OPTION_CONTROL_SEND_TIMEOUT + INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT + INTERNET_OPTION_DATA_SEND_TIMEOUT + INTERNET_OPTION_DATA_RECEIVE_TIMEOUT + INTERNET_OPTION_HANDLE_SIZE + INTERNET_OPTION_LISTEN_TIMEOUT + INTERNET_OPTION_PASSWORD + INTERNET_OPTION_READ_BUFFER_SIZE + INTERNET_OPTION_USER_AGENT + INTERNET_OPTION_USERNAME + INTERNET_OPTION_VERSION + INTERNET_OPTION_WRITE_BUFFER_SIZE + INTERNET_SERVICE_FTP + INTERNET_SERVICE_GOPHER + INTERNET_SERVICE_HTTP + INTERNET_STATUS_CLOSING_CONNECTION + INTERNET_STATUS_CONNECTED_TO_SERVER + INTERNET_STATUS_CONNECTING_TO_SERVER + INTERNET_STATUS_CONNECTION_CLOSED + INTERNET_STATUS_HANDLE_CLOSING + INTERNET_STATUS_HANDLE_CREATED + INTERNET_STATUS_NAME_RESOLVED + INTERNET_STATUS_RECEIVING_RESPONSE + INTERNET_STATUS_REDIRECT + INTERNET_STATUS_REQUEST_COMPLETE + INTERNET_STATUS_REQUEST_SENT + INTERNET_STATUS_RESOLVING_NAME + INTERNET_STATUS_RESPONSE_RECEIVED + INTERNET_STATUS_SENDING_REQUEST +); + + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. +# + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + + # [dada] This results in an ugly Autoloader error + #if ($! =~ /Invalid/) { + # $AutoLoader::AUTOLOAD = $AUTOLOAD; + # goto &AutoLoader::AUTOLOAD; + #} else { + + # [dada] ... I prefer this one :) + + ($pack,$file,$line) = caller; undef $pack; + die "Win32::Internet::$constname is not defined, used at $file line $line."; + + #} + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +####################################################################### +# STATIC OBJECT PROPERTIES +# +$VERSION = "0.082"; + +%callback_code = (); +%callback_info = (); + + +####################################################################### +# PUBLIC METHODS +# + +#======== ### CLASS CONSTRUCTOR +sub new { +#======== + my($class, $useragent, $opentype, $proxy, $proxybypass, $flags) = @_; + my $self = {}; + + if(ref($useragent) and ref($useragent) eq "HASH") { + $opentype = $useragent->{'opentype'}; + $proxy = $useragent->{'proxy'}; + $proxybypass = $useragent->{'proxybypass'}; + $flags = $useragent->{'flags'}; + my $myuseragent = $useragent->{'useragent'}; + undef $useragent; + $useragent = $myuseragent; + } + + $useragent = "Perl-Win32::Internet/".$VERSION unless defined($useragent); + $opentype = constant("INTERNET_OPEN_TYPE_DIRECT",0) unless defined($opentype); + $proxy = "" unless defined($proxy); + $proxybypass = "" unless defined($proxybypass); + $flags = 0 unless defined($flags); + + + my $handle = InternetOpen($useragent, $opentype, $proxy, $proxybypass, $flags); + if ($handle) { + $self->{'connections'} = 0; + $self->{'pasv'} = 0; + $self->{'handle'} = $handle; + $self->{'useragent'} = $useragent; + $self->{'proxy'} = $proxy; + $self->{'proxybypass'} = $proxybypass; + $self->{'flags'} = $flags; + $self->{'Type'} = "Internet"; + + # [dada] I think it's better to call SetStatusCallback explicitly... + #if($flags & constant("INTERNET_FLAG_ASYNC",0)) { + # my $callbackresult=InternetSetStatusCallback($handle); + # if($callbackresult==&constant("INTERNET_INVALID_STATUS_CALLBACK",0)) { + # $self->{'Error'} = -2; + # } + #} + + bless $self; + } else { + $self->{'handle'} = undef; + bless $self; + } + $self; +} + + +#============ +sub OpenURL { +#============ + my($self,$new,$URL) = @_; + return undef unless ref($self); + + my $newhandle=InternetOpenUrl($self->{'handle'},$URL,"",0,0,0); + if(!$newhandle) { + $self->{'Error'} = "Cannot open URL."; + return undef; + } else { + $self->{'connections'}++; + $_[1] = _new($newhandle); + $_[1]->{'Type'} = "URL"; + $_[1]->{'URL'} = $URL; + return $newhandle; + } +} + + +#================ +sub TimeConvert { +#================ + my($self, $sec, $min, $hour, $day, $mon, $year, $wday, $rfc) = @_; + return undef unless ref($self); + + if(!defined($rfc)) { + return InternetTimeToSystemTime($sec); + } else { + return InternetTimeFromSystemTime($sec, $min, $hour, + $day, $mon, $year, + $wday, $rfc); + } +} + + +#======================= +sub QueryDataAvailable { +#======================= + my($self) = @_; + return undef unless ref($self); + + return InternetQueryDataAvailable($self->{'handle'}); +} + + +#============= +sub ReadFile { +#============= + my($self, $buffersize) = @_; + return undef unless ref($self); + + my $howmuch = InternetQueryDataAvailable($self->{'handle'}); + $buffersize = $howmuch unless defined($buffersize); + return InternetReadFile($self->{'handle'}, ($howmuch<$buffersize) ? $howmuch + : $buffersize); +} + + +#=================== +sub ReadEntireFile { +#=================== + my($handle) = @_; + my $content = ""; + my $buffersize = 16000; + my $howmuch = 0; + my $buffer = ""; + + $handle = $handle->{'handle'} if defined($handle) and ref($handle); + + $howmuch = InternetQueryDataAvailable($handle); + # print "\nReadEntireFile: $howmuch bytes to read...\n"; + + while($howmuch>0) { + $buffer = InternetReadFile($handle, ($howmuch<$buffersize) ? $howmuch + : $buffersize); + # print "\nReadEntireFile: ", length($buffer), " bytes read...\n"; + + if(!defined($buffer)) { + return undef; + } else { + $content .= $buffer; + } + $howmuch = InternetQueryDataAvailable($handle); + # print "\nReadEntireFile: still $howmuch bytes to read...\n"; + + } + return $content; +} + + +#============= +sub FetchURL { +#============= + # (OpenURL+Read+Close)... + my($self, $URL) = @_; + return undef unless ref($self); + + my $newhandle = InternetOpenUrl($self->{'handle'}, $URL, "", 0, 0, 0); + if(!$newhandle) { + $self->{'Error'} = "Cannot open URL."; + return undef; + } else { + my $content = ReadEntireFile($newhandle); + InternetCloseHandle($newhandle); + return $content; + } +} + + +#================ +sub Connections { +#================ + my($self) = @_; + return undef unless ref($self); + + return $self->{'connections'} if $self->{'Type'} eq "Internet"; + return undef; +} + + +#================ +sub GetResponse { +#================ + my($num, $text) = InternetGetLastResponseInfo(); + return $text; +} + +#=========== +sub Option { +#=========== + my($self, $option, $value) = @_; + return undef unless ref($self); + + my $retval = 0; + + $option = constant("INTERNET_OPTION_USER_AGENT", 0) unless defined($option); + + if(!defined($value)) { + $retval = InternetQueryOption($self->{'handle'}, $option); + } else { + $retval = InternetSetOption($self->{'handle'}, $option, $value); + } + return $retval; +} + + +#============== +sub UserAgent { +#============== + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_USER_AGENT", 0), $value); +} + + +#============= +sub Username { +#============= + my($self, $value) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP" and $self->{'Type'} ne "FTP") { + $self->{'Error'} = "Username() only on FTP or HTTP sessions."; + return undef; + } + + return Option($self, constant("INTERNET_OPTION_USERNAME", 0), $value); +} + + +#============= +sub Password { +#============= + my($self, $value)=@_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP" and $self->{'Type'} ne "FTP") { + $self->{'Error'} = "Password() only on FTP or HTTP sessions."; + return undef; + } + + return Option($self, constant("INTERNET_OPTION_PASSWORD", 0), $value); +} + + +#=================== +sub ConnectTimeout { +#=================== + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_CONNECT_TIMEOUT", 0), $value); +} + + +#=================== +sub ConnectRetries { +#=================== + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_CONNECT_RETRIES", 0), $value); +} + + +#=================== +sub ConnectBackoff { +#=================== + my($self,$value)=@_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_CONNECT_BACKOFF", 0), $value); +} + + +#==================== +sub DataSendTimeout { +#==================== + my($self,$value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_DATA_SEND_TIMEOUT", 0), $value); +} + + +#======================= +sub DataReceiveTimeout { +#======================= + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_DATA_RECEIVE_TIMEOUT", 0), $value); +} + + +#========================== +sub ControlReceiveTimeout { +#========================== + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT", 0), $value); +} + + +#======================= +sub ControlSendTimeout { +#======================= + my($self, $value) = @_; + return undef unless ref($self); + + return Option($self, constant("INTERNET_OPTION_CONTROL_SEND_TIMEOUT", 0), $value); +} + + +#================ +sub QueryOption { +#================ + my($self, $option) = @_; + return undef unless ref($self); + + return InternetQueryOption($self->{'handle'}, $option); +} + + +#============== +sub SetOption { +#============== + my($self, $option, $value) = @_; + return undef unless ref($self); + + return InternetSetOption($self->{'handle'}, $option, $value); +} + + +#============= +sub CrackURL { +#============= + my($self, $URL, $flags) = @_; + return undef unless ref($self); + + $flags = constant("ICU_ESCAPE", 0) unless defined($flags); + + my @newurl = InternetCrackUrl($URL, $flags); + + if(!defined($newurl[0])) { + $self->{'Error'} = "Cannot crack URL."; + return undef; + } else { + return @newurl; + } +} + + +#============== +sub CreateURL { +#============== + my($self, $scheme, $hostname, $port, + $username, $password, + $path, $extrainfo, $flags) = @_; + return undef unless ref($self); + + if(ref($scheme) and ref($scheme) eq "HASH") { + $flags = $hostname; + $hostname = $scheme->{'hostname'}; + $port = $scheme->{'port'}; + $username = $scheme->{'username'}; + $password = $scheme->{'password'}; + $path = $scheme->{'path'}; + $extrainfo = $scheme->{'extrainfo'}; + my $myscheme = $scheme->{'scheme'}; + undef $scheme; + $scheme = $myscheme; + } + + $hostname = "" unless defined($hostname); + $port = 0 unless defined($port); + $username = "" unless defined($username); + $password = "" unless defined($password); + $path = "" unless defined($path); + $extrainfo = "" unless defined($extrainfo); + $flags = constant("ICU_ESCAPE", 0) unless defined($flags); + + my $newurl = InternetCreateUrl($scheme, $hostname, $port, + $username, $password, + $path, $extrainfo, $flags); + if(!defined($newurl)) { + $self->{'Error'} = "Cannot create URL."; + return undef; + } else { + return $newurl; + } +} + + +#==================== +sub CanonicalizeURL { +#==================== + my($self, $URL, $flags) = @_; + return undef unless ref($self); + + my $newurl = InternetCanonicalizeUrl($URL, $flags); + if(!defined($newurl)) { + $self->{'Error'} = "Cannot canonicalize URL."; + return undef; + } else { + return $newurl; + } +} + + +#=============== +sub CombineURL { +#=============== + my($self, $baseURL, $relativeURL, $flags) = @_; + return undef unless ref($self); + + my $newurl = InternetCombineUrl($baseURL, $relativeURL, $flags); + if(!defined($newurl)) { + $self->{'Error'} = "Cannot combine URL(s)."; + return undef; + } else { + return $newurl; + } +} + + +#====================== +sub SetStatusCallback { +#====================== + my($self) = @_; + return undef unless ref($self); + + my $callback = InternetSetStatusCallback($self->{'handle'}); + print "callback=$callback, constant=",constant("INTERNET_INVALID_STATUS_CALLBACK", 0), "\n"; + if($callback == constant("INTERNET_INVALID_STATUS_CALLBACK", 0)) { + return undef; + } else { + return $callback; + } +} + + +#====================== +sub GetStatusCallback { +#====================== + my($self, $context) = @_; + $context = $self if not defined $context; + return($callback_code{$context}, $callback_info{$context}); +} + + +#========== +sub Error { +#========== + my($self) = @_; + return undef unless ref($self); + + require Win32 unless defined &Win32::GetLastError; + my $errtext = ""; + my $tmp = ""; + my $errnum = Win32::GetLastError(); + + if($errnum < 12000) { + $errtext = Win32::FormatMessage($errnum); + $errtext =~ s/[\r\n]//g; + } elsif($errnum == 12003) { + ($tmp, $errtext) = InternetGetLastResponseInfo(); + chomp $errtext; + 1 while($errtext =~ s/(.*)\n//); # the last line should be significative... + # otherwise call GetResponse() to get it whole + } elsif($errnum >= 12000) { + $errtext = FormatMessage($errnum); + $errtext =~ s/[\r\n]//g; + } else { + $errtext="Error"; + } + if($errnum == 0 and defined($self->{'Error'})) { + if($self->{'Error'} == -2) { + $errnum = -2; + $errtext = "Asynchronous operations not available."; + } else { + $errnum = -1; + $errtext = $self->{'Error'}; + } + } + return (wantarray)? ($errnum, $errtext) : "\[".$errnum."\] ".$errtext; +} + + +#============ +sub Version { +#============ + my $dll = InternetDllVersion(); + $dll =~ s/\0//g; + return (wantarray)? ($Win32::Internet::VERSION, $dll) + : $Win32::Internet::VERSION."/".$dll; +} + + +#========== +sub Close { +#========== + my($self, $handle) = @_; + if(!defined($handle)) { + return undef unless ref($self); + $handle = $self->{'handle'}; + } + InternetCloseHandle($handle); +} + + + +####################################################################### +# FTP CLASS METHODS +# + +#======== ### FTP CONSTRUCTOR +sub FTP { +#======== + my($self, $new, $server, $username, $password, $port, $pasv, $context) = @_; + return undef unless ref($self); + + if(ref($server) and ref($server) eq "HASH") { + $port = $server->{'port'}; + $username = $server->{'username'}; + $password = $password->{'host'}; + my $myserver = $server->{'server'}; + $pasv = $server->{'pasv'}; + $context = $server->{'context'}; + undef $server; + $server = $myserver; + } + + $server = "" unless defined($server); + $username = "anonymous" unless defined($username); + $password = "" unless defined($password); + $port = 21 unless defined($port); + $context = 0 unless defined($context); + + $pasv = $self->{'pasv'} unless defined $pasv; + $pasv = $pasv ? constant("INTERNET_FLAG_PASSIVE",0) : 0; + + my $newhandle = InternetConnect($self->{'handle'}, $server, $port, + $username, $password, + constant("INTERNET_SERVICE_FTP", 0), + $pasv, $context); + if($newhandle) { + $self->{'connections'}++; + $_[1] = _new($newhandle); + $_[1]->{'Type'} = "FTP"; + $_[1]->{'Mode'} = "bin"; + $_[1]->{'pasv'} = $pasv; + $_[1]->{'username'} = $username; + $_[1]->{'password'} = $password; + $_[1]->{'server'} = $server; + return $newhandle; + } else { + return undef; + } +} + +#======== +sub Pwd { +#======== + my($self) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) { + $self->{'Error'} = "Pwd() only on FTP sessions."; + return undef; + } + + return FtpGetCurrentDirectory($self->{'handle'}); +} + + +#======= +sub Cd { +#======= + my($self, $path) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP" || !defined($self->{'handle'})) { + $self->{'Error'} = "Cd() only on FTP sessions."; + return undef; + } + + my $retval = FtpSetCurrentDirectory($self->{'handle'}, $path); + if(!defined($retval)) { + return undef; + } else { + return $path; + } +} +#==================== +sub Cwd { Cd(@_); } +sub Chdir { Cd(@_); } +#==================== + + +#========== +sub Mkdir { +#========== + my($self, $path) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) { + $self->{'Error'} = "Mkdir() only on FTP sessions."; + return undef; + } + + my $retval = FtpCreateDirectory($self->{'handle'}, $path); + $self->{'Error'} = "Can't create directory." unless defined($retval); + return $retval; +} +#==================== +sub Md { Mkdir(@_); } +#==================== + + +#========= +sub Mode { +#========= + my($self, $value) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) { + $self->{'Error'} = "Mode() only on FTP sessions."; + return undef; + } + + if(!defined($value)) { + return $self->{'Mode'}; + } else { + my $modesub = ($value =~ /^a/i) ? "Ascii" : "Binary"; + $self->$modesub($_[0]); + } + return $self->{'Mode'}; +} + + +#========== +sub Rmdir { +#========== + my($self, $path) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP" or !defined($self->{'handle'})) { + $self->{'Error'} = "Rmdir() only on FTP sessions."; + return undef; + } + my $retval = FtpRemoveDirectory($self->{'handle'}, $path); + $self->{'Error'} = "Can't remove directory." unless defined($retval); + return $retval; +} +#==================== +sub Rd { Rmdir(@_); } +#==================== + + +#========= +sub Pasv { +#========= + my($self, $value) = @_; + return undef unless ref($self); + + if(defined($value) and $self->{'Type'} eq "Internet") { + if($value == 0) { + $self->{'pasv'} = 0; + } else { + $self->{'pasv'} = 1; + } + } + return $self->{'pasv'}; +} + +#========= +sub List { +#========= + my($self, $pattern, $retmode) = @_; + return undef unless ref($self); + + my $retval = ""; + my $size = ""; + my $attr = ""; + my $ctime = ""; + my $atime = ""; + my $mtime = ""; + my $csec = 0; my $cmin = 0; my $chou = 0; my $cday = 0; my $cmon = 0; my $cyea = 0; + my $asec = 0; my $amin = 0; my $ahou = 0; my $aday = 0; my $amon = 0; my $ayea = 0; + my $msec = 0; my $mmin = 0; my $mhou = 0; my $mday = 0; my $mmon = 0; my $myea = 0; + my $newhandle = 0; + my $nextfile = 1; + my @results = (); + my ($filename, $altname, $file); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "List() only on FTP sessions."; + return undef; + } + + $pattern = "" unless defined($pattern); + $retmode = 1 unless defined($retmode); + + if($retmode == 2) { + + ( $newhandle,$filename, $altname, $size, $attr, + $csec, $cmin, $chou, $cday, $cmon, $cyea, + $asec, $amin, $ahou, $aday, $amon, $ayea, + $msec, $mmin, $mhou, $mday, $mmon, $myea + ) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0); + + if(!$newhandle) { + $self->{'Error'} = "Can't read FTP directory."; + return undef; + } else { + + while($nextfile) { + $ctime = join(",", ($csec, $cmin, $chou, $cday, $cmon, $cyea)); + $atime = join(",", ($asec, $amin, $ahou, $aday, $amon, $ayea)); + $mtime = join(",", ($msec, $mmin, $mhou, $mday, $mmon, $myea)); + push(@results, $filename, $altname, $size, $attr, $ctime, $atime, $mtime); + + ( $nextfile, $filename, $altname, $size, $attr, + $csec, $cmin, $chou, $cday, $cmon, $cyea, + $asec, $amin, $ahou, $aday, $amon, $ayea, + $msec, $mmin, $mhou, $mday, $mmon, $myea + ) = InternetFindNextFile($newhandle); + + } + InternetCloseHandle($newhandle); + return @results; + + } + + } elsif($retmode == 3) { + + ( $newhandle,$filename, $altname, $size, $attr, + $csec, $cmin, $chou, $cday, $cmon, $cyea, + $asec, $amin, $ahou, $aday, $amon, $ayea, + $msec, $mmin, $mhou, $mday, $mmon, $myea + ) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0); + + if(!$newhandle) { + $self->{'Error'} = "Can't read FTP directory."; + return undef; + + } else { + + while($nextfile) { + $ctime = join(",", ($csec, $cmin, $chou, $cday, $cmon, $cyea)); + $atime = join(",", ($asec, $amin, $ahou, $aday, $amon, $ayea)); + $mtime = join(",", ($msec, $mmin, $mhou, $mday, $mmon, $myea)); + $file = { "name" => $filename, + "altname" => $altname, + "size" => $size, + "attr" => $attr, + "ctime" => $ctime, + "atime" => $atime, + "mtime" => $mtime, + }; + push(@results, $file); + + ( $nextfile, $filename, $altname, $size, $attr, + $csec, $cmin, $chou, $cday, $cmon, $cyea, + $asec, $amin, $ahou, $aday, $amon, $ayea, + $msec, $mmin, $mhou, $mday, $mmon, $myea + ) = InternetFindNextFile($newhandle); + + } + InternetCloseHandle($newhandle); + return @results; + } + + } else { + + ($newhandle, $filename) = FtpFindFirstFile($self->{'handle'}, $pattern, 0, 0); + + if(!$newhandle) { + $self->{'Error'} = "Can't read FTP directory."; + return undef; + + } else { + + while($nextfile) { + push(@results, $filename); + + ($nextfile, $filename) = InternetFindNextFile($newhandle); + # print "List.no more files\n" if !$nextfile; + + } + InternetCloseHandle($newhandle); + return @results; + } + } +} +#==================== +sub Ls { List(@_); } +sub Dir { List(@_); } +#==================== + + +#================= +sub FileAttrInfo { +#================= + my($self,$attr) = @_; + my @attrinfo = (); + push(@attrinfo, "READONLY") if $attr & 1; + push(@attrinfo, "HIDDEN") if $attr & 2; + push(@attrinfo, "SYSTEM") if $attr & 4; + push(@attrinfo, "DIRECTORY") if $attr & 16; + push(@attrinfo, "ARCHIVE") if $attr & 32; + push(@attrinfo, "NORMAL") if $attr & 128; + push(@attrinfo, "TEMPORARY") if $attr & 256; + push(@attrinfo, "COMPRESSED") if $attr & 2048; + return (wantarray)? @attrinfo : join(" ", @attrinfo); +} + + +#=========== +sub Binary { +#=========== + my($self) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Binary() only on FTP sessions."; + return undef; + } + $self->{'Mode'} = "bin"; + return undef; +} +#====================== +sub Bin { Binary(@_); } +#====================== + + +#========== +sub Ascii { +#========== + my($self) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Ascii() only on FTP sessions."; + return undef; + } + $self->{'Mode'} = "asc"; + return undef; +} +#===================== +sub Asc { Ascii(@_); } +#===================== + + +#======== +sub Get { +#======== + my($self, $remote, $local, $overwrite, $flags, $context) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Get() only on FTP sessions."; + return undef; + } + my $mode = ($self->{'Mode'} eq "asc" ? 1 : 2); + + $remote = "" unless defined($remote); + $local = $remote unless defined($local); + $overwrite = 0 unless defined($overwrite); + $flags = 0 unless defined($flags); + $context = 0 unless defined($context); + + my $retval = FtpGetFile($self->{'handle'}, + $remote, + $local, + $overwrite, + $flags, + $mode, + $context); + $self->{'Error'} = "Can't get file." unless defined($retval); + return $retval; +} + + +#=========== +sub Rename { +#=========== + my($self, $oldname, $newname) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Rename() only on FTP sessions."; + return undef; + } + + my $retval = FtpRenameFile($self->{'handle'}, $oldname, $newname); + $self->{'Error'} = "Can't rename file." unless defined($retval); + return $retval; +} +#====================== +sub Ren { Rename(@_); } +#====================== + + +#=========== +sub Delete { +#=========== + my($self, $filename) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Delete() only on FTP sessions."; + return undef; + } + my $retval = FtpDeleteFile($self->{'handle'}, $filename); + $self->{'Error'} = "Can't delete file." unless defined($retval); + return $retval; +} +#====================== +sub Del { Delete(@_); } +#====================== + + +#======== +sub Put { +#======== + my($self, $local, $remote, $context) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "FTP") { + $self->{'Error'} = "Put() only on FTP sessions."; + return undef; + } + my $mode = ($self->{'Mode'} eq "asc" ? 1 : 2); + + $context = 0 unless defined($context); + + my $retval = FtpPutFile($self->{'handle'}, $local, $remote, $mode, $context); + $self->{'Error'} = "Can't put file." unless defined($retval); + return $retval; +} + + +####################################################################### +# HTTP CLASS METHODS +# + +#========= ### HTTP CONSTRUCTOR +sub HTTP { +#========= + my($self, $new, $server, $username, $password, $port, $flags, $context) = @_; + return undef unless ref($self); + + if(ref($server) and ref($server) eq "HASH") { + my $myserver = $server->{'server'}; + $username = $server->{'username'}; + $password = $password->{'host'}; + $port = $server->{'port'}; + $flags = $server->{'flags'}; + $context = $server->{'context'}; + undef $server; + $server = $myserver; + } + + $server = "" unless defined($server); + $username = "anonymous" unless defined($username); + $password = "" unless defined($password); + $port = 80 unless defined($port); + $flags = 0 unless defined($flags); + $context = 0 unless defined($context); + + my $newhandle = InternetConnect($self->{'handle'}, $server, $port, + $username, $password, + constant("INTERNET_SERVICE_HTTP", 0), + $flags, $context); + if($newhandle) { + $self->{'connections'}++; + $_[1] = _new($newhandle); + $_[1]->{'Type'} = "HTTP"; + $_[1]->{'username'} = $username; + $_[1]->{'password'} = $password; + $_[1]->{'server'} = $server; + $_[1]->{'accept'} = "text/*\0image/gif\0image/jpeg\0\0"; + return $newhandle; + } else { + return undef; + } +} + + +#================ +sub OpenRequest { +#================ + # alternatively to Request: + # it creates a new HTTP_Request object + # you can act upon it with AddHeader, SendRequest, ReadFile, QueryInfo, Close, ... + + my($self, $new, $path, $method, $version, $referer, $accept, $flags, $context) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP") { + $self->{'Error'} = "OpenRequest() only on HTTP sessions."; + return undef; + } + + if(ref($path) and ref($path) eq "HASH") { + $method = $path->{'method'}; + $version = $path->{'version'}; + $referer = $path->{'referer'}; + $accept = $path->{'accept'}; + $flags = $path->{'flags'}; + $context = $path->{'context'}; + my $mypath = $path->{'path'}; + undef $path; + $path = $mypath; + } + + $method = "GET" unless defined($method); + $path = "/" unless defined($path); + $version = "HTTP/1.0" unless defined($version); + $referer = "" unless defined($referer); + $accept = $self->{'accept'} unless defined($accept); + $flags = 0 unless defined($flags); + $context = 0 unless defined($context); + + $path = "/".$path if substr($path,0,1) ne "/"; + # accept string list needs to be terminated by double-NULL + $accept .= "\0\0" unless $accept =~ /\0\0\z/; + + my $newhandle = HttpOpenRequest($self->{'handle'}, + $method, + $path, + $version, + $referer, + $accept, + $flags, + $context); + if($newhandle) { + $_[1] = _new($newhandle); + $_[1]->{'Type'} = "HTTP_Request"; + $_[1]->{'method'} = $method; + $_[1]->{'request'} = $path; + $_[1]->{'accept'} = $accept; + return $newhandle; + } else { + return undef; + } +} + +#================ +sub SendRequest { +#================ + my($self, $postdata) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP_Request") { + $self->{'Error'} = "SendRequest() only on HTTP requests."; + return undef; + } + + $postdata = "" unless defined($postdata); + + return HttpSendRequest($self->{'handle'}, "", $postdata); +} + + +#============== +sub AddHeader { +#============== + my($self, $header, $flags) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP_Request") { + $self->{'Error'} = "AddHeader() only on HTTP requests."; + return undef; + } + + $flags = constant("HTTP_ADDREQ_FLAG_ADD", 0) if (!defined($flags) or $flags == 0); + + return HttpAddRequestHeaders($self->{'handle'}, $header, $flags); +} + + +#============== +sub QueryInfo { +#============== + my($self, $header, $flags) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP_Request") { + $self->{'Error'}="QueryInfo() only on HTTP requests."; + return undef; + } + + $flags = constant("HTTP_QUERY_CUSTOM", 0) if (!defined($flags) and defined($header)); + my @queryresult = HttpQueryInfo($self->{'handle'}, $flags, $header); + return (wantarray)? @queryresult : join(" ", @queryresult); +} + + +#============ +sub Request { +#============ + # HttpOpenRequest+HttpAddHeaders+HttpSendRequest+InternetReadFile+HttpQueryInfo + my($self, $path, $method, $version, $referer, $accept, $flags, $postdata) = @_; + return undef unless ref($self); + + if($self->{'Type'} ne "HTTP") { + $self->{'Error'} = "Request() only on HTTP sessions."; + return undef; + } + + if(ref($path) and ref($path) eq "HASH") { + $method = $path->{'method'}; + $version = $path->{'version'}; + $referer = $path->{'referer'}; + $accept = $path->{'accept'}; + $flags = $path->{'flags'}; + $postdata = $path->{'postdata'}; + my $mypath = $path->{'path'}; + undef $path; + $path = $mypath; + } + + my $content = ""; + my $result = ""; + my @queryresult = (); + my $statuscode = ""; + my $headers = ""; + + $path = "/" unless defined($path); + $method = "GET" unless defined($method); + $version = "HTTP/1.0" unless defined($version); + $referer = "" unless defined($referer); + $accept = $self->{'accept'} unless defined($accept); + $flags = 0 unless defined($flags); + $postdata = "" unless defined($postdata); + + $path = "/".$path if substr($path,0,1) ne "/"; + # accept string list needs to be terminated by double-NULL + $accept .= "\0\0" unless $accept =~ /\0\0\z/; + + my $newhandle = HttpOpenRequest($self->{'handle'}, + $method, + $path, + $version, + $referer, + $accept, + $flags, + 0); + + if($newhandle) { + + $result = HttpSendRequest($newhandle, "", $postdata); + + if(defined($result)) { + $statuscode = HttpQueryInfo($newhandle, + constant("HTTP_QUERY_STATUS_CODE", 0), ""); + $headers = HttpQueryInfo($newhandle, + constant("HTTP_QUERY_RAW_HEADERS_CRLF", 0), ""); + $content = ReadEntireFile($newhandle); + + InternetCloseHandle($newhandle); + + return($statuscode, $headers, $content); + } else { + return undef; + } + } else { + return undef; + } +} + + +####################################################################### +# END OF THE PUBLIC METHODS +# + + +#========= ### SUB-CLASSES CONSTRUCTOR +sub _new { +#========= + my $self = {}; + if ($_[0]) { + $self->{'handle'} = $_[0]; + bless $self; + } else { + undef($self); + } + $self; +} + + +#============ ### CLASS DESTRUCTOR +sub DESTROY { +#============ + my($self) = @_; + # print "Closing handle $self->{'handle'}...\n"; + InternetCloseHandle($self->{'handle'}); + # [dada] rest in peace +} + + +#============= +sub callback { +#============= + my($name, $status, $info) = @_; + $callback_code{$name} = $status; + $callback_info{$name} = $info; +} + +####################################################################### +# dynamically load in the Internet.pll module. +# + +bootstrap Win32::Internet; + +# Preloaded methods go here. + +#Currently Autoloading is not implemented in Perl for win32 +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +Win32::Internet - Access to WININET.DLL functions + +=head1 INTRODUCTION + +This extension to Perl implements the Win32 Internet APIs (found in +F<WININET.DLL>). They give a complete support for HTTP, FTP and GOPHER +connections. + +See the L<"Version History"> and the L<"Functions Table"> for a list +of the currently supported features. You should also get a copy of the +L<"Microsoft Win32 Internet Functions"> documentation. + +=head1 REFERENCE + +To use this module, first add the following line at the beginning of +your script: + + use Win32::Internet; + +Then you have to open an Internet connection with this command: + + $Connection = new Win32::Internet(); + +This is required to use any of the function of this module. It will +create an Internet object in Perl on which you can act upon with the +L<"General Internet Functions"> explained later. + +The objects available are: + +=over + +=item * + +Internet connections (the main object, see C<new>) + +=item * + +URLs (see C<OpenURL>) + +=item * + +FTP sessions (see C<FTP>) + +=item * + +HTTP sessions (see C<HTTP>) + +=item * + +HTTP requests (see C<OpenRequest>) + +=back + +As in the good Perl tradition, there are in this extension different +ways to do the same thing; there are, in fact, different levels of +implementation of the Win32 Internet Functions. Some routines use +several Win32 API functions to perform a complex task in a single +call; they are simpler to use, but of course less powerful. + +There are then other functions that implement nothing more and nothing +less than the corresponding API function, so you can use all of their +power, but with some additional programming steps. + +To make an example, there is a function called C<FetchURL> that you +can use to fetch the content of any HTTP, FTP or GOPHER URL with this +simple commands: + + $INET = new Win32::Internet(); + $file = $INET->FetchURL("http://www.yahoo.com"); + +You can have the same result (and this is actually what is done by +C<FetchURL>) this way: + + $INET = new Win32::Internet(); + $URL = $INET->OpenURL("http://www.yahoo.com"); + $file = $URL->ReadFile(); + $URL->Close(); + +Or, you can open a complete HTTP session: + + $INET = new Win32::Internet(); + $HTTP = $INET->HTTP("www.yahoo.com", "anonymous", "dada@divinf.it"); + ($statuscode, $headers, $file) = $HTTP->Request("/"); + $HTTP->Close(); + +Finally, you can choose to manage even the HTTP request: + + $INET = new Win32::Internet(); + $HTTP = $INET->HTTP("www.yahoo.com", "anonymous", "dada@divinf.it"); + $HTTP->OpenRequest($REQ, "/"); + $REQ->AddHeader("If-Modified-Since: Saturday, 16-Nov-96 15:58:50 GMT"); + $REQ->SendRequest(); + $statuscode = $REQ->QueryInfo("",HTTP_QUERY_STATUS_CODE); + $lastmodified = $REQ->QueryInfo("Last-Modified"); + $file = $REQ->ReadEntireFile(); + $REQ->Close(); + $HTTP->Close(); + +To open and control a complete FTP session, type: + + $Connection->FTP($Session, "ftp://ftp.activeware.com", "anonymous", "dada\@divinf.it"); + +This will create an FTP object in Perl to which you can apply the L<"FTP +functions"> provided by the package: + + $Session->Cd("/ntperl/perl5.001m/CurrentBuild"); + $Session->Ascii(); + $Session->Get("110-i86.zip"); + $Session->Close(); + +For a more complete example, see the TEST.PL file that comes with the +package. + +=head2 General Internet Functions + +B<General Note> + +All methods assume that you have the line: + + use Win32::Internet; + +somewhere before the method calls, and that you have an Internet +object called $INET which was created using this call: + + $INET = new Win32::Internet(); + +See C<new> for more information. + +B<Methods> + +=over + +=item CanonicalizeURL URL, [flags] + +Converts a URL to a canonical format, which includes converting unsafe +characters to escape sequences. Returns the canonicalized URL or +C<undef> on errors. For the possible values of I<flags>, refer to the +L<"Microsoft Win32 Internet Functions"> document. See also +C<CombineURL> and C<OpenURL>. + +Example: + + $cURL = $INET->CanonicalizeURL($URL); + $URL = $INET->CanonicalizeURL($cURL, ICU_DECODE); + +=item Close + +=item Close object + +Closes an Internet connection. This can be applied to any +Win32::Internet object (Internet connections, URLs, FTP sessions, +etc.). Note that it is not "strictly" required to close the +connections you create, since the Win32::Internet objects are +automatically closed when the program ends (or when you elsehow +destroy such an object). + +Example: + + $INET->Close(); + $FTP->Close(); + $INET->Close($FTP); # same as above... + +=item CombineURL baseURL, relativeURL, [flags] + +Combines a base and relative URL into a single URL. Returns the +(canonicalized) combined URL or C<undef> on errors. For the possible +values of I<flags>, refer to the L<"Microsoft Win32 Internet +Functions"> document. See also C<CombineURL> and C<OpenURL>. + +Example: + + $URL = $INET->CombineURL("http://www.divinf.it/dada/perl/internet", ".."); + +=item ConnectBackoff [value] + +Reads or sets the delay value, in milliseconds, to wait between +connection retries. If no I<value> parameter is specified, the +current value is returned; otherwise, the delay between retries is set +to I<value>. See also C<ConnectTimeout>, C<ConnectRetries>, +C<QueryOption> and C<SetOption>. + +Example: + + $HTTP->ConnectBackoff(2000); + $backoff = $HTTP->ConnectBackoff(); + +=item ConnectRetries [value] + +Reads or sets the number of times a connection is retried before +considering it failed. If no I<value> parameter is specified, the +current value is returned; otherwise, the number of retries is set to +I<value>. The default value for C<ConnectRetries> is 5. See also +C<ConnectBackoff>, C<ConnectTimeout>, C<QueryOption> and C<SetOption>. + +Example: + + $HTTP->ConnectRetries(20); + $retries = $HTTP->ConnectRetries(); + +=item ConnectTimeout [value] + +Reads or sets the timeout value (in milliseconds) before a connection +is considered failed. If no I<value> parameter is specified, the +current value is returned; otherwise, the timeout is set to I<value>. +The default value for C<ConnectTimeout> is infinite. See also +C<ConnectBackoff>, C<ConnectRetries>, C<QueryOption> and C<SetOption>. + +Example: + + $HTTP->ConnectTimeout(10000); + $timeout = $HTTP->ConnectTimeout(); + +=item ControlReceiveTimeout [value] + +Reads or sets the timeout value (in milliseconds) to use for non-data +(control) receive requests before they are canceled. Currently, this +value has meaning only for C<FTP> sessions. If no I<value> parameter +is specified, the current value is returned; otherwise, the timeout is +set to I<value>. The default value for C<ControlReceiveTimeout> is +infinite. See also C<ControlSendTimeout>, C<QueryOption> and +C<SetOption>. + +Example: + + $HTTP->ControlReceiveTimeout(10000); + $timeout = $HTTP->ControlReceiveTimeout(); + +=item ControlSendTimeout [value] + +Reads or sets the timeout value (in milliseconds) to use for non-data +(control) send requests before they are canceled. Currently, this +value has meaning only for C<FTP> sessions. If no I<value> parameter +is specified, the current value is returned; otherwise, the timeout is +set to I<value>. The default value for C<ControlSendTimeout> is +infinite. See also C<ControlReceiveTimeout>, C<QueryOption> and +C<SetOption>. + +Example: + + $HTTP->ControlSendTimeout(10000); + $timeout = $HTTP->ControlSendTimeout(); + +=item CrackURL URL, [flags] + +Splits an URL into its component parts and returns them in an array. +Returns C<undef> on errors, otherwise the array will contain the +following values: I<scheme, host, port, username, password, path, +extrainfo>. + +For example, the URL "http://www.divinf.it/index.html#top" can be +splitted in: + + http, www.divinf.it, 80, anonymous, dada@divinf.it, /index.html, #top + +If you don't specify a I<flags> parameter, ICU_ESCAPE will be used by +default; for the possible values of I<flags> refer to the L<"Microsoft +Win32 Internet Functions"> documentation. See also C<CreateURL>. + +Example: + + @parts=$INET->CrackURL("http://www.activeware.com"); + ($scheme, $host, $port, $user, $pass, $path, $extra) = + $INET->CrackURL("http://www.divinf.it:80/perl-win32/index.sht#feedback"); + +=item CreateURL scheme, hostname, port, username, password, path, extrainfo, [flags] + +=item CreateURL hashref, [flags] + +Creates a URL from its component parts. Returns C<undef> on errors, +otherwise the created URL. + +If you pass I<hashref> (a reference to an hash array), the following +values are taken from the array: + + %hash=( + "scheme" => "scheme", + "hostname" => "hostname", + "port" => port, + "username" => "username", + "password" => "password", + "path" => "path", + "extrainfo" => "extrainfo", + ); + +If you don't specify a I<flags> parameter, ICU_ESCAPE will be used by +default; for the other possible values of I<flags> refer to the +L<"Microsoft Win32 Internet Functions"> documentation. See also +C<CrackURL>. + +Example: + + $URL=$I->CreateURL("http", "www.divinf.it", 80, "", "", "/perl-win32/index.sht", "#feedback"); + $URL=$I->CreateURL(\%params); + +=item DataReceiveTimeout [value] + +Reads or sets the timeout value (in milliseconds) to use for data +receive requests before they are canceled. If no I<value> parameter +is specified, the current value is returned; otherwise, the timeout is +set to I<value>. The default value for DataReceiveTimeout is +infinite. See also C<DataSendTimeout>, C<QueryOption> and +C<SetOption>. + +Example: + + $HTTP->DataReceiveTimeout(10000); + $timeout = $HTTP->DataReceiveTimeout(); + +=item DataSendTimeout [value] + +Reads or sets the timeout value (in milliseconds) to use for data send +requests before they are canceled. If no I<value> parameter is +specified, the current value is returned; otherwise, the timeout is +set to I<value>. The default value for DataSendTimeout is infinite. +See also C<DataReceiveTimeout>, C<QueryOption> and C<SetOption>. + +Example: + + $HTTP->DataSendTimeout(10000); + $timeout = $HTTP->DataSendTimeout(); + +=item Error + +Returns the last recorded error in the form of an array or string +(depending upon the context) containing the error number and an error +description. Can be applied on any Win32::Internet object (FTP +sessions, etc.). There are 3 types of error you can encounter; they +are recognizable by the error number returned: + +=over + +=item * -1 + +A "trivial" error has occurred in the package. For example, you tried +to use a method on the wrong type of object. + +=item * 1 .. 11999 + +A generic error has occurred and the Win32::GetLastError error message +is returned. + +=item * 12000 and higher + +An Internet error has occurred; the extended Win32 Internet API error +message is returned. + +=back + +See also C<GetResponse>. + +Example: + + die $INET->Error(), qq(\n); + ($ErrNum, $ErrText) = $INET->Error(); + +=item FetchURL URL + +Fetch the content of an HTTP, FTP or GOPHER URL. Returns the content +of the file read (or C<undef> if there was an error and nothing was +read). See also C<OpenURL> and C<ReadFile>. + +Example: + + $file = $INET->FetchURL("http://www.yahoo.com/"); + $file = $INET->FetchURL("ftp://www.activeware.com/contrib/internet.zip"); + +=item FTP ftpobject, server, username, password, [port, pasv, context] + +=item FTP ftpobject, hashref + +Opens an FTP connection to server logging in with the given +I<username> and I<password>. + +The parameters and their values are: + +=over + +=item * server + +The server to connect to. Default: I<none>. + +=item * username + +The username used to login to the server. Default: anonymous. + +=item * password + +The password used to login to the server. Default: I<none>. + +=item * port + +The port of the FTP service on the server. Default: 21. + +=item * pasv + +If it is a value other than 0, use passive transfer mode. Default is +taken from the parent Internet connection object; you can set this +value with the C<Pasv> method. + +=item * context + +A number to identify this operation if it is asynchronous. See +C<SetStatusCallback> and C<GetStatusCallback> for more info on +asynchronous operations. Default: I<none>. + +=back + +If you pass I<hashref> (a reference to an hash array), the following +values are taken from the array: + + %hash=( + "server" => "server", + "username" => "username", + "password" => "password", + "port" => port, + "pasv" => pasv, + "context" => context, + ); + +This method returns C<undef> if the connection failed, a number +otherwise. You can then call any of the L<"FTP functions"> as methods +of the newly created I<ftpobject>. + +Example: + + $result = $INET->FTP($FTP, "ftp.activeware.com", "anonymous", "dada\@divinf.it"); + # and then for example... + $FTP->Cd("/ntperl/perl5.001m/CurrentBuild"); + + $params{"server"} = "ftp.activeware.com"; + $params{"password"} = "dada\@divinf.it"; + $params{"pasv"} = 0; + $result = $INET->FTP($FTP,\%params); + +=item GetResponse + +Returns the text sent by a remote server in response to the last +function executed. It applies on any Win32::Internet object, +particularly of course on L<FTP sessions|"FTP functions">. See also +the C<Error> function. + +Example: + + print $INET->GetResponse(); + $INET->FTP($FTP, "ftp.activeware.com", "anonymous", "dada\@divinf.it"); + print $FTP->GetResponse(); + +=item GetStatusCallback context + +Returns information about the progress of the asynchronous operation +identified by I<context>; those informations consist of two values: a +status code (one of the INTERNET_STATUS_* L<"Constants">) and an +additional value depending on the status code; for example, if the +status code returned is INTERNET_STATUS_HANDLE_CREATED, the second +value will hold the handle just created. For more informations on +those values, please refer to the L<"Microsoft Win32 Internet +Functions"> documentation. See also C<SetStatusCallback>. + +Example: + + ($status, $info) = $INET->GetStatusCallback(1); + +=item HTTP httpobject, server, username, password, [port, flags, context] + +=item HTTP httpobject, hashref + +Opens an HTTP connection to I<server> logging in with the given +I<username> and I<password>. + +The parameters and their values are: + +=over + +=item * server + +The server to connect to. Default: I<none>. + +=item * username + +The username used to login to the server. Default: anonymous. + +=item * password + +The password used to login to the server. Default: I<none>. + +=item * port + +The port of the HTTP service on the server. Default: 80. + +=item * flags + +Additional flags affecting the behavior of the function. Default: +I<none>. + +=item * context + +A number to identify this operation if it is asynchronous. See +C<SetStatusCallback> and C<GetStatusCallback> for more info on +asynchronous operations. Default: I<none>. + +=back + +Refer to the L<"Microsoft Win32 Internet Functions"> documentation for +more details on those parameters. + +If you pass I<hashref> (a reference to an hash array), the following +values are taken from the array: + + %hash=( + "server" => "server", + "username" => "username", + "password" => "password", + "port" => port, + "flags" => flags, + "context" => context, + ); + +This method returns C<undef> if the connection failed, a number +otherwise. You can then call any of the L<"HTTP functions"> as +methods of the newly created I<httpobject>. + +Example: + + $result = $INET->HTTP($HTTP,"www.activeware.com","anonymous","dada\@divinf.it"); + # and then for example... + ($statuscode, $headers, $file) = $HTTP->Request("/gifs/camel.gif"); + + $params{"server"} = "www.activeware.com"; + $params{"password"} = "dada\@divinf.it"; + $params{"flags"} = INTERNET_FLAG_RELOAD; + $result = $INET->HTTP($HTTP,\%params); + +=item new Win32::Internet [useragent, opentype, proxy, proxybypass, flags] + +=item new Win32::Internet [hashref] + +Creates a new Internet object and initializes the use of the Internet +functions; this is required before any of the functions of this +package can be used. Returns C<undef> if the connection fails, a number +otherwise. The parameters and their values are: + +=over + +=item * useragent + +The user agent passed to HTTP requests. See C<OpenRequest>. Default: +Perl-Win32::Internet/I<version>. + +=item * opentype + +How to access to the Internet (eg. directly or using a proxy). +Default: INTERNET_OPEN_TYPE_DIRECT. + +=item * proxy + +Name of the proxy server (or servers) to use. Default: I<none>. + +=item * proxybypass + +Optional list of host names or IP addresses, or both, that are known +locally. Default: I<none>. + +=item * flags + +Additional flags affecting the behavior of the function. Default: +I<none>. + +=back + +Refer to the L<"Microsoft Win32 Internet Functions"> documentation for +more details on those parameters. If you pass I<hashref> (a reference to +an hash array), the following values are taken from the array: + + %hash=( + "useragent" => "useragent", + "opentype" => "opentype", + "proxy" => "proxy", + "proxybypass" => "proxybypass", + "flags" => flags, + ); + +Example: + + $INET = new Win32::Internet(); + die qq(Cannot connect to Internet...\n) if ! $INET; + + $INET = new Win32::Internet("Mozilla/3.0", INTERNET_OPEN_TYPE_PROXY, "www.microsoft.com", ""); + + $params{"flags"} = INTERNET_FLAG_ASYNC; + $INET = new Win32::Internet(\%params); + +=item OpenURL urlobject, URL + +Opens a connection to an HTTP, FTP or GOPHER Uniform Resource Location +(URL). Returns C<undef> on errors or a number if the connection was +succesful. You can then retrieve the URL content by applying the +methods C<QueryDataAvailable> and C<ReadFile> on the newly created +I<urlobject>. See also C<FetchURL>. + +Example: + + $INET->OpenURL($URL, "http://www.yahoo.com/"); + $bytes = $URL->QueryDataAvailable(); + $file = $URL->ReadEntireFile(); + $URL->Close(); + +=item Password [password] + +Reads or sets the password used for an C<FTP> or C<HTTP> connection. +If no I<password> parameter is specified, the current value is +returned; otherwise, the password is set to I<password>. See also +C<Username>, C<QueryOption> and C<SetOption>. + +Example: + + $HTTP->Password("splurfgnagbxam"); + $password = $HTTP->Password(); + +=item QueryDataAvailable + +Returns the number of bytes of data that are available to be read +immediately by a subsequent call to C<ReadFile> (or C<undef> on +errors). Can be applied to URL or HTTP request objects. See +C<OpenURL> or C<OpenRequest>. + +Example: + + $INET->OpenURL($URL, "http://www.yahoo.com/"); + $bytes = $URL->QueryDataAvailable(); + +=item QueryOption option + +Queries an Internet option. For the possible values of I<option>, +refer to the L<"Microsoft Win32 Internet Functions"> document. See +also C<SetOption>. + +Example: + + $value = $INET->QueryOption(INTERNET_OPTION_CONNECT_TIMEOUT); + $value = $HTTP->QueryOption(INTERNET_OPTION_USERNAME); + +=item ReadEntireFile + +Reads all the data available from an opened URL or HTTP request +object. Returns what have been read or C<undef> on errors. See also +C<OpenURL>, C<OpenRequest> and C<ReadFile>. + +Example: + + $INET->OpenURL($URL, "http://www.yahoo.com/"); + $file = $URL->ReadEntireFile(); + +=item ReadFile bytes + +Reads I<bytes> bytes of data from an opened URL or HTTP request +object. Returns what have been read or C<undef> on errors. See also +C<OpenURL>, C<OpenRequest>, C<QueryDataAvailable> and +C<ReadEntireFile>. + +B<Note:> be careful to keep I<bytes> to an acceptable value (eg. don't +tell him to swallow megabytes at once...). C<ReadEntireFile> in fact +uses C<QueryDataAvailable> and C<ReadFile> in a loop to read no more +than 16k at a time. + +Example: + + $INET->OpenURL($URL, "http://www.yahoo.com/"); + $chunk = $URL->ReadFile(16000); + +=item SetOption option, value + +Sets an Internet option. For the possible values of I<option>, refer to +the L<"Microsoft Win32 Internet Functions"> document. See also +C<QueryOption>. + +Example: + + $INET->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,10000); + $HTTP->SetOption(INTERNET_OPTION_USERNAME,"dada"); + +=item SetStatusCallback + +Initializes the callback routine used to return data about the +progress of an asynchronous operation. + +Example: + + $INET->SetStatusCallback(); + +This is one of the step required to perform asynchronous operations; +the complete procedure is: + + # use the INTERNET_FLAG_ASYNC when initializing + $params{'flags'}=INTERNET_FLAG_ASYNC; + $INET = new Win32::Internet(\%params); + + # initialize the callback routine + $INET->SetStatusCallback(); + + # specify the context parameter (the last 1 in this case) + $INET->HTTP($HTTP, "www.yahoo.com", "anonymous", "dada\@divinf.it", 80, 0, 1); + +At this point, control returns immediately to Perl and $INET->Error() +will return 997, which means an asynchronous I/O operation is +pending. Now, you can call + + $HTTP->GetStatusCallback(1); + +in a loop to verify what's happening; see also C<GetStatusCallback>. + +=item TimeConvert time + +=item TimeConvert seconds, minute, hours, day, month, year, + day_of_week, RFC + +The first form takes a HTTP date/time string and returns the date/time +converted in the following array: I<seconds, minute, hours, day, +month, year, day_of_week>. + +The second form does the opposite (or at least it should, because +actually seems to be malfunctioning): it takes the values and returns +an HTTP date/time string, in the RFC format specified by the I<RFC> +parameter (OK, I didn't find yet any accepted value in the range +0..2000, let me know if you have more luck with it). + +Example: + + ($sec, $min, $hour, $day, $mday, $year, $wday) = + $INET->TimeConvert("Sun, 26 Jan 1997 20:01:52 GMT"); + + # the opposite DOESN'T WORK! which value should $RFC have??? + $time = $INET->TimeConvert(52, 1, 20, 26, 1, 1997, 0, $RFC); + +=item UserAgent [name] + +Reads or sets the user agent used for HTTP requests. If no I<name> +parameter is specified, the current value is returned; otherwise, the +user agent is set to I<name>. See also C<QueryOption> and +C<SetOption>. + +Example: + + $INET->UserAgent("Mozilla/3.0"); + $useragent = $INET->UserAgent(); + +=item Username [name] + +Reads or sets the username used for an C<FTP> or C<HTTP> connection. +If no I<name> parameter is specified, the current value is returned; +otherwise, the username is set to I<name>. See also C<Password>, +C<QueryOption> and SetOption. + +Example: + + $HTTP->Username("dada"); + $username = $HTTP->Username(); + +=item Version + +Returns the version numbers for the Win32::Internet package and the +WININET.DLL version, as an array or string, depending on the context. +The string returned will contain "package_version/DLL_version", while +the array will contain: "package_version", "DLL_version". + +Example: + + $version = $INET->Version(); # should return "0.06/4.70.1215" + @version = $INET->Version(); # should return ("0.06", "4.70.1215") + +=back + + +=head2 FTP Functions + +B<General Note> + +All methods assume that you have the following lines: + + use Win32::Internet; + $INET = new Win32::Internet(); + $INET->FTP($FTP, "hostname", "username", "password"); + +somewhere before the method calls; in other words, we assume that you +have an Internet object called $INET and an open FTP session called +$FTP. + +See C<new> and C<FTP> for more information. + + +B<Methods> + +=over + +=item Ascii + +=item Asc + +Sets the ASCII transfer mode for this FTP session. It will be applied +to the subsequent C<Get> functions. See also the C<Binary> and +C<Mode> function. + +Example: + + $FTP->Ascii(); + +=item Binary + +=item Bin + +Sets the binary transfer mode for this FTP session. It will be +applied to the subsequent C<Get> functions. See also the C<Ascii> and +C<Mode> function. + +Example: + + $FTP->Binary(); + +=item Cd path + +=item Cwd path + +=item Chdir path + +Changes the current directory on the FTP remote host. Returns I<path> +or C<undef> on error. + +Example: + + $FTP->Cd("/pub"); + +=item Delete file + +=item Del file + +Deletes a file on the FTP remote host. Returns C<undef> on error. + +Example: + + $FTP->Delete("110-i86.zip"); + +=item Get remote, [local, overwrite, flags, context] + +Gets the I<remote> FTP file and saves it locally in I<local>. If +I<local> is not specified, it will be the same name as I<remote>. +Returns C<undef> on error. The parameters and their values are: + +=over + +=item * remote + +The name of the remote file on the FTP server. Default: I<none>. + +=item * local + +The name of the local file to create. Default: remote. + +=item * overwrite + +If 0, overwrites I<local> if it exists; with any other value, the +function fails if the I<local> file already exists. Default: 0. + +=item * flags + +Additional flags affecting the behavior of the function. Default: +I<none>. + +=item * context + +A number to identify this operation if it is asynchronous. See +C<SetStatusCallback> and C<GetStatusCallback> for more info on +asynchronous operations. Default: I<none>. + +=back + +Refer to the L<"Microsoft Win32 Internet Functions"> documentation for +more details on those parameters. + +Example: + + $FTP->Get("110-i86.zip"); + $FTP->Get("/pub/perl/languages/CPAN/00index.html", "CPAN_index.html"); + +=item List [pattern, listmode] + +=item Ls [pattern, listmode] + +=item Dir [pattern, listmode] + +Returns a list containing the files found in this directory, +eventually matching the given I<pattern> (which, if omitted, is +considered "*.*"). The content of the returned list depends on the +I<listmode> parameter, which can have the following values: + +=over + +=item * listmode=1 (or omitted) + +the list contains the names of the files found. Example: + + @files = $FTP->List(); + @textfiles = $FTP->List("*.txt"); + foreach $file (@textfiles) { + print "Name: ", $file, "\n"; + } + +=item * listmode=2 + +the list contains 7 values for each file, which respectively are: + +=over + +=item * the file name + +=item * the DOS short file name, aka 8.3 + +=item * the size + +=item * the attributes + +=item * the creation time + +=item * the last access time + +=item * the last modified time + +=back + +Example: + + @files = $FTP->List("*.*", 2); + for($i=0; $i<=$#files; $i+=7) { + print "Name: ", @files[$i], "\n"; + print "Size: ", @files[$i+2], "\n"; + print "Attr: ", @files[$i+3], "\n"; + } + +=item * listmode=3 + +the list contains a reference to an hash array for each found file; +each hash contains: + +=over + +=item * name => the file name + +=item * altname => the DOS short file name, aka 8.3 + +=item * size => the size + +=item * attr => the attributes + +=item * ctime => the creation time + +=item * atime => the last access time + +=item * mtime => the last modified time + +=back + +Example: + + @files = $FTP->List("*.*", 3); + foreach $file (@files) { + print $file->{'name'}, " ", $file->{'size'}, " ", $file->{'attr'}, "\n"; + } + +B<Note:> all times are reported as strings of the following format: +I<second, hour, minute, day, month, year>. + +Example: + + $file->{'mtime'} == "0,10,58,9,12,1996" stands for 09 Dec 1996 at 10:58:00 + +=back + +=item Mkdir name + +=item Md name + +Creates a directory on the FTP remote host. Returns C<undef> on error. + +Example: + + $FTP->Mkdir("NextBuild"); + +=item Mode [mode] + +If called with no arguments, returns the current transfer mode for +this FTP session ("asc" for ASCII or "bin" for binary). The I<mode> +argument can be "asc" or "bin", in which case the appropriate transfer +mode is selected. See also the Ascii and Binary functions. Returns +C<undef> on errors. + +Example: + + print "Current mode is: ", $FTP->Mode(); + $FTP->Mode("asc"); # ... same as $FTP->Ascii(); + +=item Pasv [mode] + +If called with no arguments, returns 1 if the current FTP session has +passive transfer mode enabled, 0 if not. + +You can call it with a I<mode> parameter (0/1) only as a method of a +Internet object (see C<new>), in which case it will set the default +value for the next C<FTP> objects you create (read: set it before, +because you can't change this value once you opened the FTP session). + +Example: + + print "Pasv is: ", $FTP->Pasv(); + + $INET->Pasv(1); + $INET->FTP($FTP,"ftp.activeware.com", "anonymous", "dada\@divinf.it"); + $FTP->Pasv(0); # this will be ignored... + +=item Put local, [remote, context] + +Upload the I<local> file to the FTP server saving it under the name +I<remote>, which if if omitted is the same name as I<local>. Returns +C<undef> on error. + +I<context> is a number to identify this operation if it is asynchronous. +See C<SetStatusCallback> and C<GetStatusCallback> for more info on +asynchronous operations. + +Example: + + $FTP->Put("internet.zip"); + $FTP->Put("d:/users/dada/temp.zip", "/temp/dada.zip"); + +=item Pwd + +Returns the current directory on the FTP server or C<undef> on errors. + +Example: + + $path = $FTP->Pwd(); + +=item Rename oldfile, newfile + +=item Ren oldfile, newfile + +Renames a file on the FTP remote host. Returns C<undef> on error. + +Example: + + $FTP->Rename("110-i86.zip", "68i-011.zip"); + +=item Rmdir name + +=item Rd name + +Removes a directory on the FTP remote host. Returns C<undef> on error. + +Example: + + $FTP->Rmdir("CurrentBuild"); + +=back + +=head2 HTTP Functions + +B<General Note> + +All methods assume that you have the following lines: + + use Win32::Internet; + $INET = new Win32::Internet(); + $INET->HTTP($HTTP, "hostname", "username", "password"); + +somewhere before the method calls; in other words, we assume that you +have an Internet object called $INET and an open HTTP session called +$HTTP. + +See C<new> and C<HTTP> for more information. + + +B<Methods> + +=over + +=item AddHeader header, [flags] + +Adds HTTP request headers to an HTTP request object created with +C<OpenRequest>. For the possible values of I<flags> refer to the +L<"Microsoft Win32 Internet Functions"> document. + +Example: + + $HTTP->OpenRequest($REQUEST,"/index.html"); + $REQUEST->AddHeader("If-Modified-Since: Sunday, 17-Nov-96 11:40:03 GMT"); + $REQUEST->AddHeader("Accept: text/html\r\n", HTTP_ADDREQ_FLAG_REPLACE); + +=item OpenRequest requestobject, [path, method, version, referer, accept, flags, context] + +=item OpenRequest requestobject, hashref + +Opens an HTTP request. Returns C<undef> on errors or a number if the +connection was succesful. You can then use one of the C<AddHeader>, +C<SendRequest>, C<QueryInfo>, C<QueryDataAvailable> and C<ReadFile> +methods on the newly created I<requestobject>. The parameters and +their values are: + +=over + +=item * path + +The object to request. This is generally a file name, an executable +module, etc. Default: / + +=item * method + +The method to use; can actually be GET, POST, HEAD or PUT. Default: +GET + +=item * version + +The HTTP version. Default: HTTP/1.0 + +=item * referer + +The URL of the document from which the URL in the request was +obtained. Default: I<none> + +=item * accept + +A single string with "\0" (ASCII zero) delimited list of content +types accepted. The string must be terminated by "\0\0". +Default: "text/*\0image/gif\0image/jpeg\0\0" + +=item * flags + +Additional flags affecting the behavior of the function. Default: +I<none> + +=item * context + +A number to identify this operation if it is asynchronous. See +C<SetStatusCallback> and C<GetStatusCallback> for more info on +asynchronous operations. Default: I<none> + +=back + +Refer to the L<"Microsoft Win32 Internet Functions"> documentation for +more details on those parameters. If you pass I<hashref> (a reference to +an hash array), the following values are taken from the array: + + %hash=( + "path" => "path", + "method" => "method", + "version" => "version", + "referer" => "referer", + "accept" => "accept", + "flags" => flags, + "context" => context, + ); + +See also C<Request>. + +Example: + + $HTTP->OpenRequest($REQUEST, "/index.html"); + $HTTP->OpenRequest($REQUEST, "/index.html", "GET", "HTTP/0.9"); + + $params{"path"} = "/index.html"; + $params{"flags"} = " + $HTTP->OpenRequest($REQUEST, \%params); + +=item QueryInfo header, [flags] + +Queries information about an HTTP request object created with +C<OpenRequest>. You can specify an I<header> (for example, +"Content-type") and/or one or more I<flags>. If you don't specify +I<flags>, HTTP_QUERY_CUSTOM will be used by default; this means that +I<header> should contain a valid HTTP header name. For the possible +values of I<flags> refer to the L<"Microsoft Win32 Internet +Functions"> document. + +Example: + + $HTTP->OpenRequest($REQUEST,"/index.html"); + $statuscode = $REQUEST->QueryInfo("", HTTP_QUERY_STATUS_CODE); + $headers = $REQUEST->QueryInfo("", HTTP_QUERY_RAW_HEADERS_CRLF); # will get all the headers + $length = $REQUEST->QueryInfo("Content-length"); + +=item Request [path, method, version, referer, accept, flags] + +=item Request hashref + +Performs an HTTP request and returns an array containing the status +code, the headers and the content of the file. It is a one-step +procedure that makes an C<OpenRequest>, a C<SendRequest>, some +C<QueryInfo>, C<ReadFile> and finally C<Close>. For a description of +the parameters, see C<OpenRequest>. + +Example: + + ($statuscode, $headers, $file) = $HTTP->Request("/index.html"); + ($s, $h, $f) = $HTTP->Request("/index.html", "GET", "HTTP/1.0"); + +=item SendRequest [postdata] + +Send an HTTP request to the destination server. I<postdata> are any +optional data to send immediately after the request header; this is +generally used for POST or PUT requests. See also C<OpenRequest>. + +Example: + + $HTTP->OpenRequest($REQUEST, "/index.html"); + $REQUEST->SendRequest(); + + # A POST request... + $HTTP->OpenRequest($REQUEST, "/cgi-bin/somescript.pl", "POST"); + + #This line is a must -> (thanks Philip :) + $REQUEST->AddHeader("Content-Type: application/x-www-form-urlencoded"); + + $REQUEST->SendRequest("key1=value1&key2=value2&key3=value3"); + +=back + + +=head1 APPENDIX + + +=head2 Microsoft Win32 Internet Functions + +Complete documentation for the Microsoft Win32 Internet Functions can +be found, in both HTML and zipped Word format, at this address: + + http://www.microsoft.com/intdev/sdk/docs/wininet/ + +=head2 Functions Table + +This table reports the correspondence between the functions offered by +WININET.DLL and their implementation in the Win32::Internet +extension. Functions showing a "---" are not currently +implemented. Functions enclosed in parens ( ) aren't implemented +straightforwardly, but in a higher-level routine, eg. together with +other functions. + + WININET.DLL Win32::Internet + + InternetOpen new Win32::Internet + InternetConnect FTP / HTTP + InternetCloseHandle Close + InternetQueryOption QueryOption + InternetSetOption SetOption + InternetSetOptionEx --- + InternetSetStatusCallback SetStatusCallback + InternetStatusCallback GetStatusCallback + InternetConfirmZoneCrossing --- + InternetTimeFromSystemTime TimeConvert + InternetTimeToSystemTime TimeConvert + InternetAttemptConnect --- + InternetReadFile ReadFile + InternetSetFilePointer --- + InternetFindNextFile (List) + InternetQueryDataAvailable QueryDataAvailable + InternetGetLastResponseInfo GetResponse + InternetWriteFile --- + InternetCrackUrl CrackURL + InternetCreateUrl CreateURL + InternetCanonicalizeUrl CanonicalizeURL + InternetCombineUrl CombineURL + InternetOpenUrl OpenURL + FtpFindFirstFile (List) + FtpGetFile Get + FtpPutFile Put + FtpDeleteFile Delete + FtpRenameFile Rename + FtpOpenFile --- + FtpCreateDirectory Mkdir + FtpRemoveDirectory Rmdir + FtpSetCurrentDirectory Cd + FtpGetCurrentDirectory Pwd + HttpOpenRequest OpenRequest + HttpAddRequestHeaders AddHeader + HttpSendRequest SendRequest + HttpQueryInfo QueryInfo + InternetErrorDlg --- + + +Actually, I don't plan to add support for Gopher, Cookie and Cache +functions. I will if there will be consistent requests to do so. + +There are a number of higher-level functions in the Win32::Internet +that simplify some usual procedures, calling more that one WININET API +function. This table reports those functions and the relative WININET +functions they use. + + Win32::Internet WININET.DLL + + FetchURL InternetOpenUrl + InternetQueryDataAvailable + InternetReadFile + InternetCloseHandle + + ReadEntireFile InternetQueryDataAvailable + InternetReadFile + + Request HttpOpenRequest + HttpSendRequest + HttpQueryInfo + InternetQueryDataAvailable + InternetReadFile + InternetCloseHandle + + List FtpFindFirstFile + InternetFindNextFile + + +=head2 Constants + +Those are the constants exported by the package in the main namespace +(eg. you can use them in your scripts); for their meaning and proper +use, refer to the Microsoft Win32 Internet Functions document. + + HTTP_ADDREQ_FLAG_ADD + HTTP_ADDREQ_FLAG_REPLACE + HTTP_QUERY_ALLOW + HTTP_QUERY_CONTENT_DESCRIPTION + HTTP_QUERY_CONTENT_ID + HTTP_QUERY_CONTENT_LENGTH + HTTP_QUERY_CONTENT_TRANSFER_ENCODING + HTTP_QUERY_CONTENT_TYPE + HTTP_QUERY_COST + HTTP_QUERY_CUSTOM + HTTP_QUERY_DATE + HTTP_QUERY_DERIVED_FROM + HTTP_QUERY_EXPIRES + HTTP_QUERY_FLAG_REQUEST_HEADERS + HTTP_QUERY_FLAG_SYSTEMTIME + HTTP_QUERY_LANGUAGE + HTTP_QUERY_LAST_MODIFIED + HTTP_QUERY_MESSAGE_ID + HTTP_QUERY_MIME_VERSION + HTTP_QUERY_PRAGMA + HTTP_QUERY_PUBLIC + HTTP_QUERY_RAW_HEADERS + HTTP_QUERY_RAW_HEADERS_CRLF + HTTP_QUERY_REQUEST_METHOD + HTTP_QUERY_SERVER + HTTP_QUERY_STATUS_CODE + HTTP_QUERY_STATUS_TEXT + HTTP_QUERY_URI + HTTP_QUERY_USER_AGENT + HTTP_QUERY_VERSION + HTTP_QUERY_WWW_LINK + ICU_BROWSER_MODE + ICU_DECODE + ICU_ENCODE_SPACES_ONLY + ICU_ESCAPE + ICU_NO_ENCODE + ICU_NO_META + ICU_USERNAME + INTERNET_FLAG_PASSIVE + INTERNET_FLAG_ASYNC + INTERNET_FLAG_HYPERLINK + INTERNET_FLAG_KEEP_CONNECTION + INTERNET_FLAG_MAKE_PERSISTENT + INTERNET_FLAG_NO_AUTH + INTERNET_FLAG_NO_AUTO_REDIRECT + INTERNET_FLAG_NO_CACHE_WRITE + INTERNET_FLAG_NO_COOKIES + INTERNET_FLAG_READ_PREFETCH + INTERNET_FLAG_RELOAD + INTERNET_FLAG_RESYNCHRONIZE + INTERNET_FLAG_TRANSFER_ASCII + INTERNET_FLAG_TRANSFER_BINARY + INTERNET_INVALID_PORT_NUMBER + INTERNET_INVALID_STATUS_CALLBACK + INTERNET_OPEN_TYPE_DIRECT + INTERNET_OPEN_TYPE_PROXY + INTERNET_OPEN_TYPE_PROXY_PRECONFIG + INTERNET_OPTION_CONNECT_BACKOFF + INTERNET_OPTION_CONNECT_RETRIES + INTERNET_OPTION_CONNECT_TIMEOUT + INTERNET_OPTION_CONTROL_SEND_TIMEOUT + INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT + INTERNET_OPTION_DATA_SEND_TIMEOUT + INTERNET_OPTION_DATA_RECEIVE_TIMEOUT + INTERNET_OPTION_HANDLE_TYPE + INTERNET_OPTION_LISTEN_TIMEOUT + INTERNET_OPTION_PASSWORD + INTERNET_OPTION_READ_BUFFER_SIZE + INTERNET_OPTION_USER_AGENT + INTERNET_OPTION_USERNAME + INTERNET_OPTION_VERSION + INTERNET_OPTION_WRITE_BUFFER_SIZE + INTERNET_SERVICE_FTP + INTERNET_SERVICE_GOPHER + INTERNET_SERVICE_HTTP + INTERNET_STATUS_CLOSING_CONNECTION + INTERNET_STATUS_CONNECTED_TO_SERVER + INTERNET_STATUS_CONNECTING_TO_SERVER + INTERNET_STATUS_CONNECTION_CLOSED + INTERNET_STATUS_HANDLE_CLOSING + INTERNET_STATUS_HANDLE_CREATED + INTERNET_STATUS_NAME_RESOLVED + INTERNET_STATUS_RECEIVING_RESPONSE + INTERNET_STATUS_REDIRECT + INTERNET_STATUS_REQUEST_COMPLETE + INTERNET_STATUS_REQUEST_SENT + INTERNET_STATUS_RESOLVING_NAME + INTERNET_STATUS_RESPONSE_RECEIVED + INTERNET_STATUS_SENDING_REQUEST + + +=head1 VERSION HISTORY + +=over + +=item * 0.082 (4 Sep 2001) + +=over + +=item * + +Fix passive FTP mode. INTERNET_FLAG_PASSIVE was misspelled in earlier +versions (as INTERNET_CONNECT_FLAG_PASSIVE) and wouldn't work. Found +by Steve Raynesford <stever@evolvecomm.com>. + +=back + +=item * 0.081 (25 Sep 1999) + +=over + +=item * + +Documentation converted to pod format by Jan Dubois <JanD@ActiveState.com>. + +=item * + +Minor changes from Perl 5.005xx compatibility. + +=back + +=item * 0.08 (14 Feb 1997) + +=over + +=item * + +fixed 2 more bugs in Option(s) related subs (thanks to Brian +Helterline!). + +=item * + +Error() now gets error messages directly from WININET.DLL. + +=item * + +The PLL file now comes in 2 versions, one for Perl version 5.001 +(build 100) and one for Perl version 5.003 (build 300 and +higher). Everybody should be happy now :) + +=item * + +added an installation program. + +=back + +=item * 0.07 (10 Feb 1997) + +=over + +=item * + +fixed a bug in Version() introduced with 0.06... + +=item * + +completely reworked PM file, fixed *lots* of minor bugs, and removed +almost all the warnings with "perl -w". + +=back + +=item * 0.06 (26 Jan 1997) + +=over + +=item * + +fixed another hideous bug in "new" (the 'class' parameter was still +missing). + +=item * + +added support for asynchronous operations (work still in embryo). + +=item * + +removed the ending \0 (ASCII zero) from the DLL version returned by +"Version". + +=item * + +added a lot of constants. + +=item * + +added safefree() after every safemalloc() in C... wonder why I didn't +it before :) + +=item * + +added TimeConvert, which actually works one way only. + +=back + +=item * 0.05f (29 Nov 1996) + +=over + +=item * + +fixed a bug in "new" (parameters passed were simply ignored). + +=item * + +fixed another bug: "Chdir" and "Cwd" were aliases of RMDIR instead of +CD.. + +=back + +=item * 0.05 (29 Nov 1996) + +=over + +=item * + +added "CrackURL" and "CreateURL". + +=item * + +corrected an error in TEST.PL (there was a GetUserAgent instead of +UserAgent). + +=back + +=item * 0.04 (25 Nov 1996) + +=over + +=item * + +added "Version" to retrieve package and DLL versions. + +=item * + +added proxies and other options to "new". + +=item * + +changed "OpenRequest" and "Request" to read parameters from a hash. + +=item * + +added "SetOption/QueryOption" and a lot of relative functions +(connect, username, password, useragent, etc.). + +=item * + +added "CanonicalizeURL" and "CombineURL". + +=item * + +"Error" covers a wider spectrum of errors. + +=back + +=item * 0.02 (18 Nov 1996) + +=over + +=item * + +added support for HTTP sessions and requests. + +=back + +=item * 0.01 (11 Nov 1996) + +=over + +=item * + +fetching of HTTP, FTP and GOPHER URLs. + +=item * + +complete set of commands to manage an FTP session. + +=back + +=back + +=head1 AUTHOR + +Version 0.08 (14 Feb 1997) by Aldo Calpini <a.calpini@romagiubileo.it> + + +=head1 CREDITS + +Win32::Internet is based on the Win32::Registry code written by Jesse +Dougherty. + +Additional thanks to: Carl Tichler for his help in the initial +development; Tore Haraldsen, Brian Helterline for the bugfixes; Dave +Roth for his great source code examples. + + +=head1 DISCLAIMER + +This program is FREE; you can redistribute, modify, disassemble, or +even reverse engineer this software at your will. Keep in mind, +however, that NOTHING IS GUARANTEED to work and everything you do is +AT YOUR OWN RISK - I will not take responsability for any damage, loss +of money and/or health that may arise from the use of this program! + +This is distributed under the terms of Larry Wall's Artistic License. diff --git a/Master/tlpkg/tlperl/lib/Win32/Job.pm b/Master/tlpkg/tlperl/lib/Win32/Job.pm new file mode 100644 index 00000000000..3350f76400d --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Job.pm @@ -0,0 +1,370 @@ +package Win32::Job; + +use strict; +use base qw(DynaLoader); +use vars qw($VERSION); + +$VERSION = '0.01'; + +use constant WIN32s => 0; +use constant WIN9X => 1; +use constant WINNT => 2; + +require Win32 unless defined &Win32::GetOSVersion; +my @ver = Win32::GetOSVersion; +die "Win32::Job is not supported on $ver[0]" unless ( + $ver[4] == WINNT and ( + $ver[1] > 5 or + ($ver[1] == 5 and $ver[2] > 0) or + ($ver[1] == 5 and $ver[2] == 0 and $ver[3] >= 0) + ) +); + +Win32::Job->bootstrap($VERSION); + +1; + +__END__ + +=head1 NAME + +Win32::Job - Run sub-processes in a "job" environment + +=head1 SYNOPSIS + + use Win32::Job; + + my $job = Win32::Job->new; + + # Run 'perl Makefile.PL' for 10 seconds + $job->spawn($Config{perlpath}, "perl Makefile.PL"); + $job->run(10); + +=head1 PLATFORMS + +Win32::Job requires Windows 2000 or later. Windows 95, 98, NT, and Me are not +supported. + +=head1 DESCRIPTION + +Windows 2000 introduced the concept of a "job": a collection of processes +which can be controlled as a single unit. For example, you can reliably kill a +process and all of its children by launching the process in a job, then +telling Windows to kill all processes in the job. Win32::Job makes this +feature available to Perl. + +For example, imagine you want to allow 2 minutes for a process to complete. +If you have control over the child process, you can probably just run it in +the background, then poll every second to see if it has finished. + +That's fine as long as the child process doesn't spawn any child processes. +What if it does? If you wrote the child process yourself and made an effort to +clean up your child processes before terminating, you don't have to worry. +If not, you will leave hanging processes (called "zombie" processes in Unix). + +With Win32::Job, just create a new Job, then use the job to spawn the child +process. All I<its> children will also be created in the new Job. When you +time out, just call the job's kill() method and the entire process tree will +be terminated. + +=head1 Using Win32::Job + +The following methods are available: + +=over 4 + +=item 1 + +new() + + new(); + +Creates a new Job object using the Win32 API call CreateJobObject(). The job +is created with a default security context, and is unnamed. + +Note: this method returns C<undef> if CreateJobObject() fails. Look at C<$^E> +for more detailed error information. + +=item 2 + +spawn() + + spawn($exe, $args, \%opts); + +Creates a new process and associates it with the Job. The process is initially +suspended, and can be resumed with one of the other methods. Uses the Win32 +API call CreateProcess(). Returns the PID of the newly created process. + +Note: this method returns C<undef> if CreateProcess() fails. See C<$^E> for +more detailed error information. One reason this will fail is if the calling +process is itself part of a job, and the job's security context does not allow +child processes to be created in a different job context than the parent. + +The arguments are described here: + +=over 4 + +=item 1 + +$exe + +The executable program to run. This may be C<undef>, in which case the first +argument in $args is the program to run. + +If this has path information in it, it is used "as is" and passed to +CreateProcess(), which interprets it as either an absolute path, or a +path relative to the current drive and directory. If you did not specify an +extension, ".exe" is assumed. + +If there are no path separators (either backslashes or forward slashes), +then Win32::Job will search the current directory and your PATH, looking +for the file. In addition, if you did not specify an extension, then +Win32::Job checks ".exe", ".com", and ".bat" in order. If it finds a ".bat" +file, Win32::Job will actually call F<cmd.exe> and prepend "cmd.exe" to the +$args. + +For example, assuming a fairly normal PATH: + + spawn(q{c:\winnt\system\cmd.exe}, q{cmd /C "echo %PATH%"}) + exefile: c:\winnt\system\cmd.exe + cmdline: cmd /C "echo %PATH%" + + spawn("cmd.exe", q{cmd /C "echo %PATH%"}) + exefile: c:\winnt\system\cmd.exe + cmdline: cmd /C "echo %PATH%" + +=item 2 + +$args + +The commandline to pass to the executable program. The first word will be +C<argv[0]> to an EXE file, so you should repeat the command name in $args. + +For example: + + $job->spawn($Config{perlpath}, "perl foo.pl"); + +In this case, the "perl" is ignored, since perl.exe doesn't use it. + +=item 3 + +%opts + +A hash reference for advanced options. This parameter is optional. +the following keys are recognized: + +=over 4 + +=item cwd + +A string specifying the current directory of the new process. + +By default, the process shares the parent's current directory, C<.>. + +=item new_console + +A boolean; if true, the process is started in a new console window. + +By default, the process shares the parent's console. This has no effect on GUI +programs which do not interact with the console. + +=item window_attr + +Either C<minimized>, which displays the new window minimized; C<maximimzed>, +which shows the new window maximized; or C<hidden>, which does not display the +new window. + +By default, the window is displayed using its application's defaults. + +=item new_group + +A boolean; if true, the process is the root of a new process group. This +process group includes all descendents of the child. + +By default, the process is in the parent's process group (but in a new job). + +=item no_window + +A boolean; if true, the process is run without a console window. This flag is +only valid when starting a console application, otherwise it is ignored. If you +are launching a GUI application, use the C<window_attr> tag instead. + +By default, the process shares its parent's console. + +=item stdin + +An open input filehandle, or the name of an existing file. The resulting +filehandle will be used for the child's standard input handle. + +By default, the child process shares the parent's standard input. + +=item stdout + +An open output filehandle or filename (will be opened for append). The +resulting filehandle will be used for the child's standard output handle. + +By default, the child process shares the parent's standard output. + +=item stderr + +An open output filehandle or filename (will be opened for append). The +resulting filehandle will be used for the child's standard error handle. + +By default, the child process shares the parent's standard error. + +=back + +Unrecognized keys are ignored. + +=back + +=item 3 + +run() + + run($timeout, $which); + +Provides a simple way to run the programs with a time limit. The +$timeout is in seconds with millisecond accuracy. This call blocks for +up to $timeout seconds, or until the processes finish. + +The $which parameter specifies whether to wait for I<all> processes to +complete within the $timeout, or whether to wait for I<any> process to +complete. You should set this to a boolean, where a true value means to +wait for I<all> the processes to complete, and a false value to wait +for I<any>. If you do not specify $which, it defaults to true (C<all>). + +Returns a boolean indicating whether the processes exited by themselves, +or whether the time expired. A true return value means the processes +exited normally; a false value means one or more processes was killed +will $timeout. + +You can get extended information on process exit codes using the +status() method. + +For example, this is how to build two perl modules at the same time, +with a 5 minute timeout: + + use Win32::Job; + $job = Win32::Job->new; + $job->spawn("cmd", q{cmd /C "cd Mod1 && nmake"}); + $job->spawn("cmd", q{cmd /C "cd Mod2 && nmake"}); + $ok = $job->run(5 * 60); + print "Mod1 and Mod2 built ok!\n" if $ok; + +=item 4 + +watch() + + watch(\&handler, $interval, $which); + + handler($job); + +Provides more fine-grained control over how to stop the programs. You specify +a callback and an interval in seconds, and Win32::Job will call the "watchdog" +function at this interval, either until the processes finish or your watchdog +tells Win32::Job to stop. You must return a value indicating whether to stop: a +true value means to terminate the processes immediately. + +The $which parameter has the same meaning as run()'s. + +Returns a boolean with the same meaning as run()'s. + +The handler may do anything it wants. One useful application of the watch() +method is to check the filesize of the output file, and terminate the Job if +the file becomes larger than a certain limit: + + use Win32::Job; + $job = Win32::Job->new; + $job->spawn("cmd", q{cmd /C "cd Mod1 && nmake"}, { + stdin => 'NUL', # the NUL device + stdout => 'stdout.log', + stderr => 'stdout.log', + }); + $ok = $job->watch(sub { + return 1 if -s "stdout.log" > 1_000_000; + }, 1); + print "Mod1 built ok!\n" if $ok; + +=item 5 + +status() + + status() + +Returns a hash containing information about the processes in the job. +Only returns valid information I<after> calling either run() or watch(); +returns an empty hash if you have not yet called them. May be called from a +watch() callback, in which case the C<exitcode> field should be ignored. + +The keys of the hash are the process IDs; the values are a subhash +containing the following keys: + +=over 4 + +=item exitcode + +The exit code returned by the process. If the process was killed because +of a timeout, the value is 293. + +=item time + +The time accumulated by the process. This is yet another subhash containing +the subkeys (i) C<user>, the amount of time the process spent in user +space; (ii) C<kernel>, the amount of time the process spent in kernel space; +and (iii) C<elapsed>, the total time the process was running. + +=back + +=item 6 + +kill() + + kill(); + +Kills all processes and subprocesses in the Job. Has no return value. +Sets the exit code to all processes killed to 293, which you can check +for in the status() return value. + +=back + +=head1 SEE ALSO + +For more information about jobs, see Microsoft's online help at + + http://msdn.microsoft.com/ + +For other modules which do similar things (but not as well), see: + +=over 4 + +=item 1 + +Win32::Process + +Low-level access to creating processes in Win32. See L<Win32::Process>. + +=item 2 + +Win32::Console + +Low-level access to consoles in Win32. See L<Win32::Console>. + +=item 3 + +Win32::ProcFarm + +Manage pools of threads to perform CPU-intensive tasks on Windows. See +L<Win32::ProcFarm>. + +=back + +=head1 AUTHOR + +ActiveState (support@ActiveState.com) + +=head1 COPYRIGHT + +Copyright (c) 2002, ActiveState Corporation. All Rights Reserved. + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/Mutex.pm b/Master/tlpkg/tlperl/lib/Win32/Mutex.pm new file mode 100644 index 00000000000..801c2d35cda --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Mutex.pm @@ -0,0 +1,125 @@ +#--------------------------------------------------------------------- +package Win32::Mutex; +# +# Copyright 1998 Christopher J. Madsen +# +# Created: 3 Feb 1998 from the ActiveWare version +# (c) 1995 Microsoft Corporation. All rights reserved. +# Developed by ActiveWare Internet Corp., http://www.ActiveWare.com +# +# Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com> +# +# Author: Christopher J. Madsen <cjm@pobox.com> +# Version: 1.00 (6-Feb-1998) +# +# This program is free software; you can redistribute it and/or modify +# it under the same terms as Perl itself. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the +# GNU General Public License or the Artistic License for more details. +# +# Use Win32 mutex objects for synchronization +#--------------------------------------------------------------------- + +$VERSION = '1.02'; + +use Win32::IPC 1.00 '/./'; # Import everything +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader Win32::IPC); +@EXPORT_OK = qw( + wait_all wait_any +); + +bootstrap Win32::Mutex; + +sub Create { $_[0] = Win32::Mutex->new(@_[1..2]) } +sub Open { $_[0] = Win32::Mutex->open($_[1]) } +sub Release { &release } + +1; +__END__ + +=head1 NAME + +Win32::Mutex - Use Win32 mutex objects from Perl + +=head1 SYNOPSIS + + require Win32::Mutex; + + $mutex = Win32::Mutex->new($initial,$name); + $mutex->wait; + +=head1 DESCRIPTION + +This module allows access to the Win32 mutex objects. The C<wait> +method and C<wait_all> & C<wait_any> functions are inherited from the +L<"Win32::IPC"> module. + +=head2 Methods + +=over 4 + +=item $mutex = Win32::Mutex->new([$initial, [$name]]) + +Constructor for a new mutex object. If C<$initial> is true, requests +immediate ownership of the mutex (default false). If C<$name> is +omitted, creates an unnamed mutex object. + +If C<$name> signifies an existing mutex object, then C<$initial> is +ignored and the object is opened. If this happens, C<$^E> will be set +to 183 (ERROR_ALREADY_EXISTS). + +=item $mutex = Win32::Mutex->open($name) + +Constructor for opening an existing mutex object. + +=item $mutex->release + +Release ownership of a C<$mutex>. You should have obtained ownership +of the mutex through C<new> or one of the wait functions. Returns +true if successful. + +=item $mutex->wait([$timeout]) + +Wait for ownership of C<$mutex>. See L<"Win32::IPC">. + +=back + +=head2 Deprecated Functions and Methods + +B<Win32::Mutex> still supports the ActiveWare syntax, but its use is +deprecated. + +=over 4 + +=item Create($MutObj,$Initial,$Name) + +Use C<$MutObj = Win32::Mutex-E<gt>new($Initial,$Name)> instead. + +=item Open($MutObj,$Name) + +Use C<$MutObj = Win32::Mutex-E<gt>open($Name)> instead. + +=item $MutObj->Release() + +Use C<$MutObj-E<gt>release> instead. + +=back + +=head1 AUTHOR + +Christopher J. Madsen E<lt>F<cjm@pobox.com>E<gt> + +Loosely based on the original module by ActiveWare Internet Corp., +F<http://www.ActiveWare.com> + +=cut + +# Local Variables: +# tmtrack-file-task: "Win32::Mutex" +# End: diff --git a/Master/tlpkg/tlperl/lib/Win32/NetAdmin.pm b/Master/tlpkg/tlperl/lib/Win32/NetAdmin.pm new file mode 100644 index 00000000000..ace31a619e4 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/NetAdmin.pm @@ -0,0 +1,419 @@ +package Win32::NetAdmin; + +# +#NetAdmin.pm +#Written by Douglas_Lankshear@ActiveWare.com +# + +$VERSION = '0.08'; + +require Exporter; +require DynaLoader; + +require Win32 unless defined &Win32::IsWinNT; +die "The Win32::NetAdmin module works only on Windows NT" unless Win32::IsWinNT(); + +@ISA= qw( Exporter DynaLoader ); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + DOMAIN_ALIAS_RID_ACCOUNT_OPS + DOMAIN_ALIAS_RID_ADMINS + DOMAIN_ALIAS_RID_BACKUP_OPS + DOMAIN_ALIAS_RID_GUESTS + DOMAIN_ALIAS_RID_POWER_USERS + DOMAIN_ALIAS_RID_PRINT_OPS + DOMAIN_ALIAS_RID_REPLICATOR + DOMAIN_ALIAS_RID_SYSTEM_OPS + DOMAIN_ALIAS_RID_USERS + DOMAIN_GROUP_RID_ADMINS + DOMAIN_GROUP_RID_GUESTS + DOMAIN_GROUP_RID_USERS + DOMAIN_USER_RID_ADMIN + DOMAIN_USER_RID_GUEST + FILTER_TEMP_DUPLICATE_ACCOUNT + FILTER_NORMAL_ACCOUNT + FILTER_INTERDOMAIN_TRUST_ACCOUNT + FILTER_WORKSTATION_TRUST_ACCOUNT + FILTER_SERVER_TRUST_ACCOUNT + SV_TYPE_WORKSTATION + SV_TYPE_SERVER + SV_TYPE_SQLSERVER + SV_TYPE_DOMAIN_CTRL + SV_TYPE_DOMAIN_BAKCTRL + SV_TYPE_TIMESOURCE + SV_TYPE_AFP + SV_TYPE_NOVELL + SV_TYPE_DOMAIN_MEMBER + SV_TYPE_PRINT + SV_TYPE_PRINTQ_SERVER + SV_TYPE_DIALIN + SV_TYPE_DIALIN_SERVER + SV_TYPE_XENIX_SERVER + SV_TYPE_NT + SV_TYPE_WFW + SV_TYPE_POTENTIAL_BROWSER + SV_TYPE_BACKUP_BROWSER + SV_TYPE_MASTER_BROWSER + SV_TYPE_DOMAIN_MASTER + SV_TYPE_DOMAIN_ENUM + SV_TYPE_SERVER_UNIX + SV_TYPE_SERVER_MFPN + SV_TYPE_SERVER_NT + SV_TYPE_SERVER_OSF + SV_TYPE_SERVER_VMS + SV_TYPE_WINDOWS + SV_TYPE_DFS + SV_TYPE_ALTERNATE_XPORT + SV_TYPE_LOCAL_LIST_ONLY + SV_TYPE_ALL + UF_TEMP_DUPLICATE_ACCOUNT + UF_NORMAL_ACCOUNT + UF_INTERDOMAIN_TRUST_ACCOUNT + UF_WORKSTATION_TRUST_ACCOUNT + UF_SERVER_TRUST_ACCOUNT + UF_MACHINE_ACCOUNT_MASK + UF_ACCOUNT_TYPE_MASK + UF_DONT_EXPIRE_PASSWD + UF_SETTABLE_BITS + UF_SCRIPT + UF_ACCOUNTDISABLE + UF_HOMEDIR_REQUIRED + UF_LOCKOUT + UF_PASSWD_NOTREQD + UF_PASSWD_CANT_CHANGE + USE_FORCE + USE_LOTS_OF_FORCE + USE_NOFORCE + USER_PRIV_MASK + USER_PRIV_GUEST + USER_PRIV_USER + USER_PRIV_ADMIN +); + +@EXPORT_OK = qw( + GetError + GetDomainController + GetAnyDomainController + UserCreate + UserDelete + UserGetAttributes + UserSetAttributes + UserChangePassword + UsersExist + GetUsers + GroupCreate + GroupDelete + GroupGetAttributes + GroupSetAttributes + GroupAddUsers + GroupDeleteUsers + GroupIsMember + GroupGetMembers + LocalGroupCreate + LocalGroupDelete + LocalGroupGetAttributes + LocalGroupSetAttributes + LocalGroupIsMember + LocalGroupGetMembers + LocalGroupGetMembersWithDomain + LocalGroupAddUsers + LocalGroupDeleteUsers + GetServers + GetTransports + LoggedOnUsers + GetAliasFromRID + GetUserGroupFromRID + GetServerDisks +); +$EXPORT_TAGS{ALL}= \@EXPORT_OK; + +=head1 NAME + +Win32::NetAdmin - manage network groups and users in perl + +=head1 SYNOPSIS + + use Win32::NetAdmin; + +=head1 DESCRIPTION + +This module offers control over the administration of groups and users over a +network. + +=head1 FUNCTIONS + +=head2 NOTE + +All of the functions return false if they fail, unless otherwise noted. +When a function fails call Win32::NetAdmin::GetError() rather than +GetLastError() or $^E to retrieve the error code. + +C<server> is optional for all the calls below. If not given the local machine is +assumed. + +=over 10 + +=item GetError() + +Returns the error code of the last call to this module. + +=item GetDomainController(server, domain, returnedName) + +Returns the name of the domain controller for server. + +=item GetAnyDomainController(server, domain, returnedName) + +Returns the name of any domain controller for a domain that is directly trusted +by the server. + +=item UserCreate(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath) + +Creates a user on server with password, passwordAge, privilege, homeDir, comment, +flags, and scriptPath. + +=item UserDelete(server, user) + +Deletes a user from server. + +=item UserGetAttributes(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath) + +Gets password, passwordAge, privilege, homeDir, comment, flags, and scriptPath +for user. + +=item UserSetAttributes(server, userName, password, passwordAge, privilege, homeDir, comment, flags, scriptPath) + +Sets password, passwordAge, privilege, homeDir, comment, flags, and scriptPath +for user. + +=item UserChangePassword(domainname, username, oldpassword, newpassword) + +Changes a users password. Can be run under any account. + +=item UsersExist(server, userName) + +Checks if a user exists. + +=item GetUsers(server, filter, userRef) + +Fills userRef with user names if it is an array reference and with the user +names and the full names if it is a hash reference. + +=item GroupCreate(server, group, comment) + +Creates a group. + +=item GroupDelete(server, group) + +Deletes a group. + +=item GroupGetAttributes(server, groupName, comment) + +Gets the comment. + +=item GroupSetAttributes(server, groupName, comment) + +Sets the comment. + +=item GroupAddUsers(server, groupName, users) + +Adds a user to a group. + +=item GroupDeleteUsers(server, groupName, users) + +Deletes a users from a group. + +=item GroupIsMember(server, groupName, user) + +Returns TRUE if user is a member of groupName. + +=item GroupGetMembers(server, groupName, userArrayRef) + +Fills userArrayRef with the members of groupName. + +=item LocalGroupCreate(server, group, comment) + +Creates a local group. + +=item LocalGroupDelete(server, group) + +Deletes a local group. + +=item LocalGroupGetAttributes(server, groupName, comment) + +Gets the comment. + +=item LocalGroupSetAttributes(server, groupName, comment) + +Sets the comment. + +=item LocalGroupIsMember(server, groupName, user) + +Returns TRUE if user is a member of groupName. + +=item LocalGroupGetMembers(server, groupName, userArrayRef) + +Fills userArrayRef with the members of groupName. + +=item LocalGroupGetMembersWithDomain(server, groupName, userRef) + +This function is similar LocalGroupGetMembers but accepts an array or +a hash reference. Unlike LocalGroupGetMembers it returns each user name +as C<DOMAIN\USERNAME>. If a hash reference is given, the function +returns to each user or group name the type (group, user, alias etc.). +The possible types are as follows: + + $SidTypeUser = 1; + $SidTypeGroup = 2; + $SidTypeDomain = 3; + $SidTypeAlias = 4; + $SidTypeWellKnownGroup = 5; + $SidTypeDeletedAccount = 6; + $SidTypeInvalid = 7; + $SidTypeUnknown = 8; + +=item LocalGroupAddUsers(server, groupName, users) + +Adds a user to a group. + +=item LocalGroupDeleteUsers(server, groupName, users) + +Deletes a users from a group. + +=item GetServers(server, domain, flags, serverRef) + +Gets an array of server names or an hash with the server names and the +comments as seen in the Network Neighborhood or the server manager. +For flags, see SV_TYPE_* constants. + +=item GetTransports(server, transportRef) + +Enumerates the network transports of a computer. If transportRef is an array +reference, it is filled with the transport names. If transportRef is a hash +reference then a hash of hashes is filled with the data for the transports. + +=item LoggedOnUsers(server, userRef) + +Gets an array or hash with the users logged on at the specified computer. If +userRef is a hash reference, the value is a semikolon separated string of +username, logon domain and logon server. + +=item GetAliasFromRID(server, RID, returnedName) + +=item GetUserGroupFromRID(server, RID, returnedName) + +Retrieves the name of an alias (i.e local group) or a user group for a RID +from the specified server. These functions can be used for example to get the +account name for the administrator account if it is renamed or localized. + +Possible values for C<RID>: + + DOMAIN_ALIAS_RID_ACCOUNT_OPS + DOMAIN_ALIAS_RID_ADMINS + DOMAIN_ALIAS_RID_BACKUP_OPS + DOMAIN_ALIAS_RID_GUESTS + DOMAIN_ALIAS_RID_POWER_USERS + DOMAIN_ALIAS_RID_PRINT_OPS + DOMAIN_ALIAS_RID_REPLICATOR + DOMAIN_ALIAS_RID_SYSTEM_OPS + DOMAIN_ALIAS_RID_USERS + DOMAIN_GROUP_RID_ADMINS + DOMAIN_GROUP_RID_GUESTS + DOMAIN_GROUP_RID_USERS + DOMAIN_USER_RID_ADMIN + DOMAIN_USER_RID_GUEST + +=item GetServerDisks(server, arrayRef) + +Returns an array with the disk drives of the specified server. The array +contains two-character strings (drive letter followed by a colon). + +=back + +=head1 EXAMPLE + + # Simple script using Win32::NetAdmin to set the login script for + # all members of the NT group "Domain Users". Only works if you + # run it on the PDC. (From Robert Spier <rspier@seas.upenn.edu>) + # + # FILTER_TEMP_DUPLICATE_ACCOUNTS + # Enumerates local user account data on a domain controller. + # + # FILTER_NORMAL_ACCOUNT + # Enumerates global user account data on a computer. + # + # FILTER_INTERDOMAIN_TRUST_ACCOUNT + # Enumerates domain trust account data on a domain controller. + # + # FILTER_WORKSTATION_TRUST_ACCOUNT + # Enumerates workstation or member server account data on a domain + # controller. + # + # FILTER_SERVER_TRUST_ACCOUNT + # Enumerates domain controller account data on a domain controller. + + + use Win32::NetAdmin qw(GetUsers GroupIsMember + UserGetAttributes UserSetAttributes); + + my %hash; + GetUsers("", FILTER_NORMAL_ACCOUNT , \%hash) + or die "GetUsers() failed: $^E"; + + foreach (keys %hash) { + my ($password, $passwordAge, $privilege, + $homeDir, $comment, $flags, $scriptPath); + if (GroupIsMember("", "Domain Users", $_)) { + print "Updating $_ ($hash{$_})\n"; + UserGetAttributes("", $_, $password, $passwordAge, $privilege, + $homeDir, $comment, $flags, $scriptPath) + or die "UserGetAttributes() failed: $^E"; + $scriptPath = "dnx_login.bat"; # this is the new login script + UserSetAttributes("", $_, $password, $passwordAge, $privilege, + $homeDir, $comment, $flags, $scriptPath) + or die "UserSetAttributes() failed: $^E"; + } + } + +=cut + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::NetAdmin macro $constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +$SidTypeUser = 1; +$SidTypeGroup = 2; +$SidTypeDomain = 3; +$SidTypeAlias = 4; +$SidTypeWellKnownGroup = 5; +$SidTypeDeletedAccount = 6; +$SidTypeInvalid = 7; +$SidTypeUnknown = 8; + +sub GetError() { + our $__lastError; + $__lastError; +} + +bootstrap Win32::NetAdmin; + +1; +__END__ + diff --git a/Master/tlpkg/tlperl/lib/Win32/NetResource.pm b/Master/tlpkg/tlperl/lib/Win32/NetResource.pm new file mode 100644 index 00000000000..04ac87acabd --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/NetResource.pm @@ -0,0 +1,456 @@ +package Win32::NetResource; + +require Exporter; +require DynaLoader; +require AutoLoader; + +$VERSION = '0.053'; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + RESOURCEDISPLAYTYPE_DOMAIN + RESOURCEDISPLAYTYPE_FILE + RESOURCEDISPLAYTYPE_GENERIC + RESOURCEDISPLAYTYPE_GROUP + RESOURCEDISPLAYTYPE_SERVER + RESOURCEDISPLAYTYPE_SHARE + RESOURCEDISPLAYTYPE_TREE + RESOURCETYPE_ANY + RESOURCETYPE_DISK + RESOURCETYPE_PRINT + RESOURCETYPE_UNKNOWN + RESOURCEUSAGE_CONNECTABLE + RESOURCEUSAGE_CONTAINER + RESOURCEUSAGE_RESERVED + RESOURCE_CONNECTED + RESOURCE_GLOBALNET + RESOURCE_REMEMBERED + STYPE_DISKTREE + STYPE_PRINTQ + STYPE_DEVICE + STYPE_IPC + STYPE_SPECIAL + SHARE_NETNAME_PARMNUM + SHARE_TYPE_PARMNUM + SHARE_REMARK_PARMNUM + SHARE_PERMISSIONS_PARMNUM + SHARE_MAX_USES_PARMNUM + SHARE_CURRENT_USES_PARMNUM + SHARE_PATH_PARMNUM + SHARE_PASSWD_PARMNUM + SHARE_FILE_SD_PARMNUM +); + +@EXPORT_OK = qw( + GetSharedResources + AddConnection + CancelConnection + WNetGetLastError + GetError + GetUNCName + NetShareAdd + NetShareCheck + NetShareDel + NetShareGetInfo + NetShareSetInfo +); + +=head1 NAME + +Win32::NetResource - manage network resources in perl + +=head1 SYNOPSIS + + use Win32::NetResource; + + $ShareInfo = { + 'path' => "C:\\MyShareDir", + 'netname' => "MyShare", + 'remark' => "It is good to share", + 'passwd' => "", + 'current-users' =>0, + 'permissions' => 0, + 'maxusers' => -1, + 'type' => 0, + }; + + Win32::NetResource::NetShareAdd( $ShareInfo,$parm ) + or die "unable to add share"; + + +=head1 DESCRIPTION + +This module offers control over the network resources of Win32.Disks, +printers etc can be shared over a network. + +=head1 DATA TYPES + +There are two main data types required to control network resources. +In Perl these are represented by hash types. + +=over 4 + +=item %NETRESOURCE + + KEY VALUE + + 'Scope' => Scope of an Enumeration + RESOURCE_CONNECTED, + RESOURCE_GLOBALNET, + RESOURCE_REMEMBERED. + + 'Type' => The type of resource to Enum + RESOURCETYPE_ANY All resources + RESOURCETYPE_DISK Disk resources + RESOURCETYPE_PRINT Print resources + + 'DisplayType' => The way the resource should be displayed. + RESOURCEDISPLAYTYPE_DOMAIN + The object should be displayed as a domain. + RESOURCEDISPLAYTYPE_GENERIC + The method used to display the object does not matter. + RESOURCEDISPLAYTYPE_SERVER + The object should be displayed as a server. + RESOURCEDISPLAYTYPE_SHARE + The object should be displayed as a sharepoint. + + 'Usage' => Specifies the Resources usage: + RESOURCEUSAGE_CONNECTABLE + RESOURCEUSAGE_CONTAINER. + + 'LocalName' => Name of the local device the resource is + connected to. + + 'RemoteName' => The network name of the resource. + + 'Comment' => A string comment. + + 'Provider' => Name of the provider of the resource. + +=back + +=item %SHARE_INFO + +This hash represents the SHARE_INFO_502 struct. + +=over 4 + + KEY VALUE + 'netname' => Name of the share. + 'type' => type of share. + 'remark' => A string comment. + 'permissions' => Permissions value + 'maxusers' => the max # of users. + 'current-users' => the current # of users. + 'path' => The path of the share. + 'passwd' => A password if one is req'd + +=back + +=head1 FUNCTIONS + +=head2 NOTE + +All of the functions return false if they fail. + +=over 4 + +=item GetSharedResources(\@Resources,dwType,\%NetResource = NULL) + +Creates a list in @Resources of %NETRESOURCE hash references. + +The return value indicates whether there was an error in accessing +any of the shared resources. All the shared resources that were +encountered (until the point of an error, if any) are pushed into +@Resources as references to %NETRESOURCE hashes. See example +below. The \%NetResource argument is optional. If it is not supplied, +the root (that is, the topmost container) of the network is assumed, +and all network resources available from the toplevel container will +be enumerated. + +=item AddConnection(\%NETRESOURCE,$Password,$UserName,$Connection) + +Makes a connection to a network resource specified by %NETRESOURCE + +=item CancelConnection($Name,$Connection,$Force) + +Cancels a connection to a network resource connected to local device +$name.$Connection is either 1 - persistent connection or 0, non-persistent. + +=item WNetGetLastError($ErrorCode,$Description,$Name) + +Gets the Extended Network Error. + +=item GetError( $ErrorCode ) + +Gets the last Error for a Win32::NetResource call. + +=item GetUNCName( $UNCName, $LocalPath ); + +Returns the UNC name of the disk share connected to $LocalPath in $UNCName. +$LocalPath should be a drive based path. e.g. "C:\\share\\subdir" + +=back + +=head2 NOTE + +$servername is optional for all the calls below. (if not given the +local machine is assumed.) + +=over 4 + +=item NetShareAdd(\%SHARE,$parm_err,$servername = NULL ) + +Add a share for sharing. + +=item NetShareCheck($device,$type,$servername = NULL ) + +Check if a directory or a device is available for connection from the +network through a share. This includes all directories that are +reachable through a shared directory or device, meaning that if C:\foo +is shared, C:\foo\bar is also available for sharing. This means that +this function is pretty useless, given that by default every disk +volume has an administrative share such as "C$" associated with its +root directory. + +$device must be a drive name, directory, or a device. For example, +"C:", "C:\dir", "LPT1", "D$", "IPC$" are all valid as the $device +argument. $type is an output argument that will be set to one of +the following constants that describe the type of share: + + STYPE_DISKTREE Disk drive + STYPE_PRINTQ Print queue + STYPE_DEVICE Communication device + STYPE_IPC Interprocess communication (IPC) + STYPE_SPECIAL Special share reserved for interprocess + communication (IPC$) or remote administration + of the server (ADMIN$). Can also refer to + administrative shares such as C$, D$, etc. + +=item NetShareDel( $netname, $servername = NULL ) + +Remove a share from a machines list of shares. + +=item NetShareGetInfo( $netname, \%SHARE,$servername=NULL ) + +Get the %SHARE_INFO information about the share $netname on the +server $servername. + +=item NetShareSetInfo( $netname,\%SHARE,$parm_err,$servername=NULL) + +Set the information for share $netname. + +=back + +=head1 EXAMPLE + +=over 4 + +=item Enumerating all resources on the network + + # + # This example displays all the share points in the entire + # visible part of the network. + # + + use strict; + use Win32::NetResource qw(:DEFAULT GetSharedResources GetError); + my $resources = []; + unless(GetSharedResources($resources, RESOURCETYPE_ANY)) { + my $err; + GetError($err); + warn Win32::FormatMessage($err); + } + + foreach my $href (@$resources) { + next if ($$href{DisplayType} != RESOURCEDISPLAYTYPE_SHARE); + print "-----\n"; + foreach( keys %$href){ + print "$_: $href->{$_}\n"; + } + } + +=item Enumerating all resources on a particular host + + # + # This example displays all the share points exported by the local + # host. + # + + use strict; + use Win32::NetResource qw(:DEFAULT GetSharedResources GetError); + if (GetSharedResources(my $resources, RESOURCETYPE_ANY, + { RemoteName => "\\\\" . Win32::NodeName() })) + { + foreach my $href (@$resources) { + print "-----\n"; + foreach(keys %$href) { print "$_: $href->{$_}\n"; } + } + } + +=back + +=head1 AUTHOR + +Jesse Dougherty for Hip Communications. + +Additional general cleanups and bug fixes by Gurusamy Sarathy <gsar@activestate.com>. + +=cut + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::NetResource macro $constname, used at $file line $line. +"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +sub AddConnection +{ + my $h = $_[0]; + die "AddConnection: HASH reference required" unless ref($h) eq "HASH"; + + # + # The last four items *must* not be deallocated until the + # _AddConnection() completes (since the packed structure is + # pointing into these values. + # + my $netres = pack( 'i4 p4', $h->{Scope}, + $h->{Type}, + $h->{DisplayType}, + $h->{Usage}, + $h->{LocalName}, + $h->{RemoteName}, + $h->{Comment}, + $h->{Provider}); + _AddConnection($netres,$_[1],$_[2],$_[3]); +} + +#use Data::Dumper; + +sub GetSharedResources +{ + die "GetSharedResources: ARRAY reference required" + if defined $_[0] and ref($_[0]) ne "ARRAY"; + + my $aref = []; + + # Get the shared resources. + + my $ret; + + if (@_ > 2 and $_[2]) { + my $netres = pack('i4 p4', @{$_[2]}{qw(Scope + Type + DisplayType + Usage + LocalName + RemoteName + Comment + Provider)}); + $ret = _GetSharedResources( $aref , $_[1], $netres ); + } + else { + $ret = _GetSharedResources( $aref , $_[1] ); + } + + # build the array of hashes in $_[0] +# print Dumper($aref); + foreach ( @$aref ) { + my %hash; + @hash{'Scope', + 'Type', + 'DisplayType', + 'Usage', + 'LocalName', + 'RemoteName', + 'Comment', + 'Provider'} = split /\001/, $_; + push @{$_[0]}, \%hash; + } + + $ret; +} + +sub NetShareAdd +{ + my $shareinfo = _hash2SHARE( $_[0] ); + _NetShareAdd($shareinfo,$_[1], $_[2] || ""); +} + +sub NetShareGetInfo +{ + my ($netinfo,$val); + $val = _NetShareGetInfo( $_[0],$netinfo,$_[2] || ""); + %{$_[1]} = %{_SHARE2hash( $netinfo )}; + $val; +} + +sub NetShareSetInfo +{ + my $shareinfo = _hash2SHARE( $_[1] ); + _NetShareSetInfo( $_[0],$shareinfo,$_[2],$_[3] || ""); +} + + +# These are private functions to work with the ShareInfo structure. +# please note that the implementation of these calls requires the +# SHARE_INFO_502 level of information. + +sub _SHARE2hash +{ + my %hash = (); + @hash{'type', + 'permissions', + 'maxusers', + 'current-users', + 'remark', + 'netname', + 'path', + 'passwd'} = unpack('i4 A257 A81 A257 A257',$_[0]); + + return \%hash; +} + +sub _hash2SHARE +{ + my $h = $_[0]; + die "Argument must be a HASH reference" unless ref($h) eq "HASH"; + + return pack 'i4 a257 a81 a257 a257', + @$h{'type', + 'permissions', + 'maxusers', + 'current-users', + 'remark', + 'netname', + 'path', + 'passwd'}; +} + + +bootstrap Win32::NetResource; + +1; +__END__ diff --git a/Master/tlpkg/tlperl/lib/Win32/ODBC.pm b/Master/tlpkg/tlperl/lib/Win32/ODBC.pm new file mode 100644 index 00000000000..a51616388ea --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/ODBC.pm @@ -0,0 +1,1493 @@ +package Win32::ODBC; + +$VERSION = '0.032'; + +# Win32::ODBC.pm +# +==========================================================+ +# | | +# | ODBC.PM package | +# | --------------- | +# | | +# | Copyright (c) 1996, 1997 Dave Roth. All rights reserved. | +# | This program is free software; you can redistribute | +# | it and/or modify it under the same terms as Perl itself. | +# | | +# +==========================================================+ +# +# +# based on original code by Dan DeMaggio (dmag@umich.edu) +# +# Use under GNU General Public License or Larry Wall's "Artistic License" +# +# Check the README.TXT file that comes with this package for details about +# it's history. +# + +require Exporter; +require DynaLoader; + +$ODBCPackage = "Win32::ODBC"; +$ODBCPackage::Version = 970208; +$::ODBC = $ODBCPackage; +$CacheConnection = 0; + + # Reserve ODBC in the main namespace for US! +*ODBC::=\%Win32::ODBC::; + + +@ISA= qw( Exporter DynaLoader ); + # Items to export into callers namespace by default. Note: do not export + # names by default without a very good reason. Use EXPORT_OK instead. + # Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + ODBC_ADD_DSN + ODBC_REMOVE_DSN + ODBC_CONFIG_DSN + ODBC_ADD_SYS_DSN + ODBC_REMOVE_SYS_DSN + ODBC_CONFIG_SYS_DSN + + SQL_DONT_CLOSE + SQL_DROP + SQL_CLOSE + SQL_UNBIND + SQL_RESET_PARAMS + + SQL_FETCH_NEXT + SQL_FETCH_FIRST + SQL_FETCH_LAST + SQL_FETCH_PRIOR + SQL_FETCH_ABSOLUTE + SQL_FETCH_RELATIVE + SQL_FETCH_BOOKMARK + + SQL_COLUMN_COUNT + SQL_COLUMN_NAME + SQL_COLUMN_TYPE + SQL_COLUMN_LENGTH + SQL_COLUMN_PRECISION + SQL_COLUMN_SCALE + SQL_COLUMN_DISPLAY_SIZE + SQL_COLUMN_NULLABLE + SQL_COLUMN_UNSIGNED + SQL_COLUMN_MONEY + SQL_COLUMN_UPDATABLE + SQL_COLUMN_AUTO_INCREMENT + SQL_COLUMN_CASE_SENSITIVE + SQL_COLUMN_SEARCHABLE + SQL_COLUMN_TYPE_NAME + SQL_COLUMN_TABLE_NAME + SQL_COLUMN_OWNER_NAME + SQL_COLUMN_QUALIFIER_NAME + SQL_COLUMN_LABEL + SQL_COLATT_OPT_MAX + SQL_COLUMN_DRIVER_START + SQL_COLATT_OPT_MIN + SQL_ATTR_READONLY + SQL_ATTR_WRITE + SQL_ATTR_READWRITE_UNKNOWN + SQL_UNSEARCHABLE + SQL_LIKE_ONLY + SQL_ALL_EXCEPT_LIKE + SQL_SEARCHABLE + ); + #The above are included for backward compatibility + + +sub new +{ + my ($n, $self); + my ($type) = shift; + my ($DSN) = shift; + my (@Results) = @_; + + if (ref $DSN){ + @Results = ODBCClone($DSN->{'connection'}); + }else{ + @Results = ODBCConnect($DSN, @Results); + } + @Results = processError(-1, @Results); + if (! scalar(@Results)){ + return undef; + } + $self = bless {}; + $self->{'connection'} = $Results[0]; + $ErrConn = $Results[0]; + $ErrText = $Results[1]; + $ErrNum = 0; + $self->{'DSN'} = $DSN; + $self; +} + +#### +# Close this ODBC session (or all sessions) +#### +sub Close +{ + my ($self, $Result) = shift; + $Result = DESTROY($self); + $self->{'connection'} = -1; + return $Result; +} + +#### +# Auto-Kill an instance of this module +#### +sub DESTROY +{ + my ($self) = shift; + my (@Results) = (0); + if($self->{'connection'} > -1){ + @Results = ODBCDisconnect($self->{'connection'}); + @Results = processError($self, @Results); + if ($Results[0]){ + undef $self->{'DSN'}; + undef @{$self->{'fnames'}}; + undef %{$self->{'field'}}; + undef %{$self->{'connection'}}; + } + } + return $Results[0]; +} + + +sub sql{ + return (Sql(@_)); +} + +#### +# Submit an SQL Execute statement for processing +#### +sub Sql{ + my ($self, $Sql, @Results) = @_; + @Results = ODBCExecute($self->{'connection'}, $Sql); + return updateResults($self, @Results); +} + +#### +# Retrieve data from a particular field +#### +sub Data{ + + # Change by JOC 06-APR-96 + # Altered by Dave Roth <dave@roth.net> 96.05.07 + my($self) = shift; + my(@Fields) = @_; + my(@Results, $Results, $Field); + + if ($self->{'Dirty'}){ + GetData($self); + $self->{'Dirty'} = 0; + } + @Fields = @{$self->{'fnames'}} if (! scalar(@Fields)); + foreach $Field (@Fields) { + if (wantarray) { + push(@Results, data($self, $Field)); + } else { + $Results .= data($self, $Field); + } + } + return wantarray ? @Results : $Results; +} + +sub DataHash{ + my($self, @Results) = @_; + my(%Results, $Element); + + if ($self->{'Dirty'}){ + GetData($self); + $self->{'Dirty'} = 0; + } + @Results = @{$self->{'fnames'}} if (! scalar(@Results)); + foreach $Element (@Results) { + $Results{$Element} = data($self, $Element); + } + + return %Results; +} + +#### +# Retrieve data from the data buffer +#### +sub data +{ $_[0]->{'data'}->{$_[1]}; } + + +sub fetchrow{ + return (FetchRow(@_)); +} +#### +# Put a row from an ODBC data set into data buffer +#### +sub FetchRow{ + my ($self, @Results) = @_; + my ($item, $num, $sqlcode); + # Added by JOC 06-APR-96 + # $num = 0; + $num = 0; + undef $self->{'data'}; + + + @Results = ODBCFetch($self->{'connection'}, @Results); + if (! (@Results = processError($self, @Results))){ + #### + # There should be an innocuous error "No records remain" + # This indicates no more records in the dataset + #### + return undef; + } + # Set the Dirty bit so we will go and extract data via the + # ODBCGetData function. Otherwise use the cache. + $self->{'Dirty'} = 1; + + # Return the array of field Results. + return @Results; +} + +sub GetData{ + my($self) = @_; + my @Results; + my $num = 0; + + @Results = ODBCGetData($self->{'connection'}); + if (!(@Results = processError($self, @Results))){ + return undef; + } + #### + # This is a special case. Do not call processResults + #### + ClearError(); + foreach (@Results){ + s/ +$// if defined $_; # HACK + $self->{'data'}->{ ${$self->{'fnames'}}[$num] } = $_; + $num++; + } + # return is a hack to interface with a assoc array. + return wantarray? (1, 1): 1; +} + +#### +# See if any more ODBC Results Sets +# Added by Brian Dunfordshore <Brian_Dunfordshore@bridge.com> +# 96.07.10 +#### +sub MoreResults{ + my ($self) = @_; + + my(@Results) = ODBCMoreResults($self->{'connection'}); + return (processError($self, @Results))[0]; +} + +#### +# Retrieve the catalog from the current DSN +# NOTE: All Field names are uppercase!!! +#### +sub Catalog{ + my ($self) = shift; + my ($Qualifier, $Owner, $Name, $Type) = @_; + my (@Results) = ODBCTableList($self->{'connection'}, $Qualifier, $Owner, $Name, $Type); + + # If there was an error return 0 else 1 + return (updateResults($self, @Results) != 1); +} + +#### +# Return an array of names from the catalog for the current DSN +# TableList($Qualifier, $Owner, $Name, $Type) +# Return: (array of names of tables) +# NOTE: All Field names are uppercase!!! +#### +sub TableList{ + my ($self) = shift; + my (@Results) = @_; + if (! scalar(@Results)){ + @Results = ("", "", "%", "TABLE"); + } + + if (! Catalog($self, @Results)){ + return undef; + } + undef @Results; + while (FetchRow($self)){ + push(@Results, Data($self, "TABLE_NAME")); + } + return sort(@Results); +} + + +sub fieldnames{ + return (FieldNames(@_)); +} +#### +# Return an array of fieldnames extracted from the current dataset +#### +sub FieldNames { $self = shift; return @{$self->{'fnames'}}; } + + +#### +# Closes this connection. This is used mostly for testing. You should +# probably use Close(). +#### +sub ShutDown{ + my($self) = @_; + print "\nClosing connection $self->{'connection'}..."; + $self->Close(); + print "\nDone\n"; +} + +#### +# Return this connection number +#### +sub Connection{ + my($self) = @_; + return $self->{'connection'}; +} + +#### +# Returns the current connections that are in use. +#### +sub GetConnections{ + return ODBCGetConnections(); +} + +#### +# Set the Max Buffer Size for this connection. This determines just how much +# ram can be allocated when a fetch() is performed that requires a HUGE amount +# of memory. The default max is 10k and the absolute max is 100k. +# This will probably never be used but I put it in because I noticed a fetch() +# of a MEMO field in an Access table was something like 4Gig. Maybe I did +# something wrong, but after checking several times I decided to impliment +# this limit thingie. +#### +sub SetMaxBufSize{ + my($self, $Size) = @_; + my(@Results) = ODBCSetMaxBufSize($self->{'connection'}, $Size); + return (processError($self, @Results))[0]; +} + +#### +# Returns the Max Buffer Size for this connection. See SetMaxBufSize(). +#### +sub GetMaxBufSize{ + my($self) = @_; + my(@Results) = ODBCGetMaxBufSize($self->{'connection'}); + return (processError($self, @Results))[0]; +} + + +#### +# Returns the DSN for this connection as an associative array. +#### +sub GetDSN{ + my($self, $DSN) = @_; + if(! ref($self)){ + $DSN = $self; + $self = 0; + } + if (! $DSN){ + $self = $self->{'connection'}; + } + my(@Results) = ODBCGetDSN($self, $DSN); + return (processError($self, @Results)); +} + +#### +# Returns an associative array of $XXX{'DSN'}=Description +#### +sub DataSources{ + my($self, $DSN) = @_; + if(! ref $self){ + $DSN = $self; + $self = 0; + } + my(@Results) = ODBCDataSources($DSN); + return (processError($self, @Results)); +} + +#### +# Returns an associative array of $XXX{'Driver Name'}=Driver Attributes +#### +sub Drivers{ + my($self) = @_; + if(! ref $self){ + $self = 0; + } + my(@Results) = ODBCDrivers(); + return (processError($self, @Results)); +} + +#### +# Returns the number of Rows that were affected by the previous SQL command. +#### +sub RowCount{ + my($self, $Connection) = @_; + if (! ref($self)){ + $Connection = $self; + $self = 0; + } + if (! $Connection){$Connection = $self->{'connection'};} + my(@Results) = ODBCRowCount($Connection); + return (processError($self, @Results))[0]; +} + +#### +# Returns the Statement Close Type -- how does ODBC Close a statment. +# Types: +# SQL_DROP +# SQL_CLOSE +# SQL_UNBIND +# SQL_RESET_PARAMS +#### +sub GetStmtCloseType{ + my($self, $Connection) = @_; + if (! ref($self)){ + $Connection = $self; + $self = 0; + } + if (! $Connection){$Connection = $self->{'connection'};} + my(@Results) = ODBCGetStmtCloseType($Connection); + return (processError($self, @Results)); +} + +#### +# Sets the Statement Close Type -- how does ODBC Close a statment. +# Types: +# SQL_DROP +# SQL_CLOSE +# SQL_UNBIND +# SQL_RESET_PARAMS +# Returns the newly set value. +#### +sub SetStmtCloseType{ + my($self, $Type, $Connection) = @_; + if (! ref($self)){ + $Connection = $Type; + $Type = $self; + $self = 0; + } + if (! $Connection){$Connection = $self->{'connection'};} + my(@Results) = ODBCSetStmtCloseType($Connection, $Type); + return (processError($self, @Results))[0]; +} + +sub ColAttributes{ + my($self, $Type, @Field) = @_; + my(%Results, @Results, $Results, $Attrib, $Connection, $Temp); + if (! ref($self)){ + $Type = $Field; + $Field = $self; + $self = 0; + } + $Connection = $self->{'connection'}; + if (! scalar(@Field)){ @Field = $self->fieldnames;} + foreach $Temp (@Field){ + @Results = ODBCColAttributes($Connection, $Temp, $Type); + ($Attrib) = processError($self, @Results); + if (wantarray){ + $Results{$Temp} = $Attrib; + }else{ + $Results .= "$Temp"; + } + } + return wantarray? %Results:$Results; +} + +sub GetInfo{ + my($self, $Type) = @_; + my($Connection, @Results); + if(! ref $self){ + $Type = $self; + $self = 0; + $Connection = 0; + }else{ + $Connection = $self->{'connection'}; + } + @Results = ODBCGetInfo($Connection, $Type); + return (processError($self, @Results))[0]; +} + +sub GetConnectOption{ + my($self, $Type) = @_; + my(@Results); + if(! ref $self){ + $Type = $self; + $self = 0; + } + @Results = ODBCGetConnectOption($self->{'connection'}, $Type); + return (processError($self, @Results))[0]; +} + +sub SetConnectOption{ + my($self, $Type, $Value) = @_; + if(! ref $self){ + $Value = $Type; + $Type = $self; + $self = 0; + } + my(@Results) = ODBCSetConnectOption($self->{'connection'}, $Type, $Value); + return (processError($self, @Results))[0]; +} + + +sub Transact{ + my($self, $Type) = @_; + my(@Results); + if(! ref $self){ + $Type = $self; + $self = 0; + } + @Results = ODBCTransact($self->{'connection'}, $Type); + return (processError($self, @Results))[0]; +} + + +sub SetPos{ + my($self, @Results) = @_; + @Results = ODBCSetPos($self->{'connection'}, @Results); + $self->{'Dirty'} = 1; + return (processError($self, @Results))[0]; +} + +sub ConfigDSN{ + my($self) = shift @_; + my($Type, $Connection); + if(! ref $self){ + $Type = $self; + $Connection = 0; + $self = 0; + }else{ + $Type = shift @_; + $Connection = $self->{'connection'}; + } + my($Driver, @Attributes) = @_; + @Results = ODBCConfigDSN($Connection, $Type, $Driver, @Attributes); + return (processError($self, @Results))[0]; +} + + +sub Version{ + my($self, @Packages) = @_; + my($Temp, @Results); + if (! ref($self)){ + push(@Packages, $self); + } + my($ExtName, $ExtVersion) = Info(); + if (! scalar(@Packages)){ + @Packages = ("ODBC.PM", "ODBC.PLL"); + } + foreach $Temp (@Packages){ + if ($Temp =~ /pll/i){ + push(@Results, "ODBC.PM:$Win32::ODBC::Version"); + }elsif ($Temp =~ /pm/i){ + push(@Results, "ODBC.PLL:$ExtVersion"); + } + } + return @Results; +} + + +sub SetStmtOption{ + my($self, $Option, $Value) = @_; + if(! ref $self){ + $Value = $Option; + $Option = $self; + $self = 0; + } + my(@Results) = ODBCSetStmtOption($self->{'connection'}, $Option, $Value); + return (processError($self, @Results))[0]; +} + +sub GetStmtOption{ + my($self, $Type) = @_; + if(! ref $self){ + $Type = $self; + $self = 0; + } + my(@Results) = ODBCGetStmtOption($self->{'connection'}, $Type); + return (processError($self, @Results))[0]; +} + +sub GetFunctions{ + my($self, @Results)=@_; + @Results = ODBCGetFunctions($self->{'connection'}, @Results); + return (processError($self, @Results)); +} + +sub DropCursor{ + my($self) = @_; + my(@Results) = ODBCDropCursor($self->{'connection'}); + return (processError($self, @Results))[0]; +} + +sub SetCursorName{ + my($self, $Name) = @_; + my(@Results) = ODBCSetCursorName($self->{'connection'}, $Name); + return (processError($self, @Results))[0]; +} + +sub GetCursorName{ + my($self) = @_; + my(@Results) = ODBCGetCursorName($self->{'connection'}); + return (processError($self, @Results))[0]; +} + +sub GetSQLState{ + my($self) = @_; + my(@Results) = ODBCGetSQLState($self->{'connection'}); + return (processError($self, @Results))[0]; +} + + +# ----------- R e s u l t P r o c e s s i n g F u n c t i o n s ---------- +#### +# Generic processing of data into associative arrays +#### +sub updateResults{ + my ($self, $Error, @Results) = @_; + + undef %{$self->{'field'}}; + + ClearError($self); + if ($Error){ + SetError($self, $Results[0], $Results[1]); + return ($Error); + } + + @{$self->{'fnames'}} = @Results; + + foreach (0..$#{$self->{'fnames'}}){ + s/ +$//; + $self->{'field'}->{${$self->{'fnames'}}[$_]} = $_; + } + return undef; +} + +# ---------------------------------------------------------------------------- +# ----------------- D e b u g g i n g F u n c t i o n s -------------------- + +sub Debug{ + my($self, $iDebug, $File) = @_; + my(@Results); + if (! ref($self)){ + if (defined $self){ + $File = $iDebug; + $iDebug = $self; + } + $Connection = 0; + $self = 0; + }else{ + $Connection = $self->{'connection'}; + } + push(@Results, ($Connection, $iDebug)); + push(@Results, $File) if ($File ne ""); + @Results = ODBCDebug(@Results); + return (processError($self, @Results))[0]; +} + +#### +# Prints out the current dataset (used mostly for testing) +#### +sub DumpData { + my($self) = @_; my($f, $goo); + + # Changed by JOC 06-Apr-96 + # print "\nDumping Data for connection: $conn->{'connection'}\n"; + print "\nDumping Data for connection: $self->{'connection'}\n"; + print "Error: \""; + print $self->Error(); + print "\"\n"; + if (! $self->Error()){ + foreach $f ($self->FieldNames){ + print $f . " "; + $goo .= "-" x length($f); + $goo .= " "; + } + print "\n$goo\n"; + while ($self->FetchRow()){ + foreach $f ($self->FieldNames){ + print $self->Data($f) . " "; + } + print "\n"; + } + } +} + +sub DumpError{ + my($self) = @_; + my($ErrNum, $ErrText, $ErrConn); + my($Temp); + + print "\n---------- Error Report: ----------\n"; + if (ref $self){ + ($ErrNum, $ErrText, $ErrConn) = $self->Error(); + ($Temp = $self->GetDSN()) =~ s/.*DSN=(.*?);.*/$1/i; + print "Errors for \"$Temp\" on connection " . $self->{'connection'} . ":\n"; + }else{ + ($ErrNum, $ErrText, $ErrConn) = Error(); + print "Errors for the package:\n"; + } + + print "Connection Number: $ErrConn\nError number: $ErrNum\nError message: \"$ErrText\"\n"; + print "-----------------------------------\n"; + +} + +#### +# Submit an SQL statement and print data about it (used mostly for testing) +#### +sub Run{ + my($self, $Sql) = @_; + + print "\nExcecuting connection $self->{'connection'}\nsql statement: \"$Sql\"\n"; + $self->Sql($Sql); + print "Error: \""; + print $self->error; + print "\"\n"; + print "--------------------\n\n"; +} + +# ---------------------------------------------------------------------------- +# ----------- E r r o r P r o c e s s i n g F u n c t i o n s ------------ + +#### +# Process Errors returned from a call to ODBCxxxx(). +# It is assumed that the Win32::ODBC function returned the following structure: +# ($ErrorNumber, $ResultsText, ...) +# $ErrorNumber....0 = No Error +# >0 = Error Number +# $ResultsText.....if no error then this is the first Results element. +# if error then this is the error text. +#### +sub processError{ + my($self, $Error, @Results) = @_; + if ($Error){ + SetError($self, $Results[0], $Results[1]); + undef @Results; + } + return @Results; +} + +#### +# Return the last recorded error message +#### +sub error{ + return (Error(@_)); +} + +sub Error{ + my($self) = @_; + if(ref($self)){ + if($self->{'ErrNum'}){ + my($State) = ODBCGetSQLState($self->{'connection'}); + return (wantarray)? ($self->{'ErrNum'}, $self->{'ErrText'}, $self->{'connection'}, $State) :"[$self->{'ErrNum'}] [$self->{'connection'}] [$State] \"$self->{'ErrText'}\""; + } + }elsif ($ErrNum){ + return (wantarray)? ($ErrNum, $ErrText, $ErrConn):"[$ErrNum] [$ErrConn] \"$ErrText\""; + } + return undef +} + +#### +# SetError: +# Assume that if $self is not a reference then it is just a placeholder +# and should be ignored. +#### +sub SetError{ + my($self, $Num, $Text, $Conn) = @_; + if (ref $self){ + $self->{'ErrNum'} = $Num; + $self->{'ErrText'} = $Text; + $Conn = $self->{'connection'} if ! $Conn; + } + $ErrNum = $Num; + $ErrText = $Text; + + #### + # Test Section Begin + #### +# $! = ($Num, $Text); + #### + # Test Section End + #### + + $ErrConn = $Conn; +} + +sub ClearError{ + my($self, $Num, $Text) = @_; + if (ref $self){ + undef $self->{'ErrNum'}; + undef $self->{'ErrText'}; + }else{ + undef $ErrConn; + undef $ErrNum; + undef $ErrText; + } + ODBCCleanError(); + return 1; +} + + +sub GetError{ + my($self, $Connection) = @_; + my(@Results); + if (! ref($self)){ + $Connection = $self; + $self = 0; + }else{ + if (! defined($Connection)){ + $Connection = $self->{'connection'}; + } + } + + @Results = ODBCGetError($Connection); + return @Results; +} + + + + +# ---------------------------------------------------------------------------- +# ------------------ A U T O L O A D F U N C T I O N ----------------------- + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + $val = constant($constname); + + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + + # Added by JOC 06-APR-96 + # $pack = 0; + $pack = 0; + ($pack,$file,$line) = caller; + print "Your vendor has not defined Win32::ODBC macro $constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + + # -------------------------------------------------------------- + # + # + # Make sure that we shutdown ODBC and free memory even if we are + # using perlis.dll on Win32 platform! +END{ +# ODBCShutDown() unless $CacheConnection; +} + + +bootstrap Win32::ODBC; + +# Preloaded methods go here. + +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +Win32::ODBC - ODBC Extension for Win32 + +=head1 SYNOPSIS + +To use this module, include the following statement at the top of your +script: + + use Win32::ODBC; + +Next, create a data connection to your DSN: + + $Data = new Win32::ODBC("MyDSN"); + +B<NOTE>: I<MyDSN> can be either the I<DSN> as defined in the ODBC +Administrator, I<or> it can be an honest-to-God I<DSN Connect String>. + + Example: "DSN=My Database;UID=Brown Cow;PWD=Moo;" + +You should check to see if C<$Data> is indeed defined, otherwise there +has been an error. + +You can now send SQL queries and retrieve info to your heart's +content! See the description of the methods provided by this module +below and also the file F<TEST.PL> as referred to in L<INSTALLATION +NOTES> to see how it all works. + +Finally, B<MAKE SURE> that you close your connection when you are +finished: + + $Data->Close(); + +=head1 DESCRIPTION + +=head2 Background + +This is a hack of Dan DeMaggio's <dmag@umich.edu> F<NTXS.C> ODBC +implementation. I have recoded and restructured most of it including +most of the F<ODBC.PM> package, but its very core is still based on +Dan's code (thanks Dan!). + +The history of this extension is found in the file F<HISTORY.TXT> that +comes with the original archive (see L<INSTALLATION NOTES> below). + +=head2 Benefits + +And what are the benefits of this module? + +=over + +=item * + +The number of ODBC connections is limited by memory and ODBC itself +(have as many as you want!). + +=item * + +The working limit for the size of a field is 10,240 bytes, but you can +increase that limit (if needed) to a max of 2,147,483,647 bytes. (You +can always recompile to increase the max limit.) + +=item * + +You can open a connection by either specifing a DSN or a connection +string! + +=item * + +You can open and close the connections in any order! + +=item * + +Other things that I can not think of right now... :) + +=back + +=head1 CONSTANTS + +This package defines a number of constants. You may refer to each of +these constants using the notation C<ODBC::xxxxx>, where C<xxxxx> is +the constant. + +Example: + + print ODBC::SQL_SQL_COLUMN_NAME, "\n"; + +=head1 SPECIAL NOTATION + +For the method documentation that follows, an B<*> following the +method parameters indicates that that method is new or has been +modified for this version. + +=head1 CONSTRUCTOR + +=over + +=item new ( ODBC_OBJECT | DSN [, (OPTION1, VALUE1), (OPTION2, VALUE2) ...] ) +* + +Creates a new ODBC connection based on C<DSN>, or, if you specify an +already existing ODBC object, then a new ODBC object will be created +but using the ODBC Connection specified by C<ODBC_OBJECT>. (The new +object will be a new I<hstmt> using the I<hdbc> connection in +C<ODBC_OBJECT>.) + +C<DSN> is I<Data Source Name> or a proper C<ODBCDriverConnect> string. + +You can specify SQL Connect Options that are implemented before the +actual connection to the DSN takes place. These option/values are the +same as specified in C<GetConnectOption>/C<SetConnectOption> (see +below) and are defined in the ODBC API specs. + +Returns a handle to the database on success, or I<undef> on failure. + +=back + +=head1 METHODS + +=over + +=item Catalog ( QUALIFIER, OWNER, NAME, TYPE ) + +Tells ODBC to create a data set that contains table information about +the DSN. Use C<Fetch> and C<Data> or C<DataHash> to retrieve the data. +The returned format is: + + [Qualifier] [Owner] [Name] [Type] + +Returns I<true> on error. + +=item ColAttributes ( ATTRIBUTE [, FIELD_NAMES ] ) + +Returns the attribute C<ATTRIBUTE> on each of the fields in the list +C<FIELD_NAMES> in the current record set. If C<FIELD_NAMES> is empty, +then all fields are assumed. The attributes are returned as an +associative array. + +=item ConfigDSN ( OPTION, DRIVER, ATTRIBUTE1 [, ATTRIBUTE2, ATTRIBUTE3, ... +] ) + +Configures a DSN. C<OPTION> takes on one of the following values: + + ODBC_ADD_DSN.......Adds a new DSN. + ODBC_MODIFY_DSN....Modifies an existing DSN. + ODBC_REMOVE_DSN....Removes an existing DSN. + + ODBC_ADD_SYS_DSN.......Adds a new System DSN. + ODBC_MODIFY_SYS_DSN....Modifies an existing System DSN. + ODBC_REMOVE_SYS_DSN....Removes an existing System DSN. + +You must specify the driver C<DRIVER> (which can be retrieved by using +C<DataSources> or C<Drivers>). + +C<ATTRIBUTE1> B<should> be I<"DSN=xxx"> where I<xxx> is the name of +the DSN. Other attributes can be any DSN attribute such as: + + "UID=Cow" + "PWD=Moo" + "Description=My little bitty Data Source Name" + +Returns I<true> on success, I<false> on failure. + +B<NOTE 1>: If you use C<ODBC_ADD_DSN>, then you must include at least +I<"DSN=xxx"> and the location of the database. + +Example: For MS Access databases, you must specify the +I<DatabaseQualifier>: + + "DBQ=c:\\...\\MyDatabase.mdb" + +B<NOTE 2>: If you use C<ODBC_MODIFY_DSN>, then you need only specify +the I<"DNS=xxx"> attribute. Any other attribute you include will be +changed to what you specify. + +B<NOTE 3>: If you use C<ODBC_REMOVE_DSN>, then you need only specify +the I<"DSN=xxx"> attribute. + +=item Connection () + +Returns the connection number associated with the ODBC connection. + +=item Close () + +Closes the ODBC connection. No return value. + +=item Data ( [ FIELD_NAME ] ) + +Returns the contents of column name C<FIELD_NAME> or the current row +(if nothing is specified). + +=item DataHash ( [ FIELD1, FIELD2, ... ] ) + +Returns the contents for C<FIELD1, FIELD2, ...> or the entire row (if +nothing is specified) as an associative array consisting of: + + {Field Name} => Field Data + +=item DataSources () + +Returns an associative array of Data Sources and ODBC remarks about them. +They are returned in the form of: + + $ArrayName{'DSN'}=Driver + +where I<DSN> is the Data Source Name and ODBC Driver used. + +=item Debug ( [ 1 | 0 ] ) + +Sets the debug option to on or off. If nothing is specified, then +nothing is changed. + +Returns the debugging value (I<1> or I<0>). + +=item Drivers () + +Returns an associative array of ODBC Drivers and their attributes. +They are returned in the form of: + + $ArrayName{'DRIVER'}=Attrib1;Attrib2;Attrib3;... + +where I<DRIVER> is the ODBC Driver Name and I<AttribX> are the +driver-defined attributes. + +=item DropCursor ( [ CLOSE_TYPE ] ) + +Drops the cursor associated with the ODBC object. This forces the +cursor to be deallocated. This overrides C<SetStmtCloseType>, but the +ODBC object does not lose the C<StmtCloseType> setting. C<CLOSE_TYPE> +can be any valid C<SmtpCloseType> and will perform a close on the stmt +using the specified close type. + +Returns I<true> on success, I<false> on failure. + +=item DumpData () + +Dumps to the screen the fieldnames and all records of the current data +set. Used primarily for debugging. No return value. + +=item Error () + +Returns the last encountered error. The returned value is context +dependent: + +If called in a I<scalar> context, then a I<3-element array> is +returned: + + ( ERROR_NUMBER, ERROR_TEXT, CONNECTION_NUMBER ) + +If called in a I<string> context, then a I<string> is returned: + + "[ERROR_NUMBER] [CONNECTION_NUMBER] [ERROR_TEXT]" + +If debugging is on then two more variables are returned: + + ( ..., FUNCTION, LEVEL ) + +where C<FUNCTION> is the name of the function in which the error +occurred, and C<LEVEL> represents extra information about the error +(usually the location of the error). + +=item FetchRow ( [ ROW [, TYPE ] ] ) + +Retrieves the next record from the keyset. When C<ROW> and/or C<TYPE> +are specified, the call is made using C<SQLExtendedFetch> instead of +C<SQLFetch>. + +B<NOTE 1>: If you are unaware of C<SQLExtendedFetch> and its +implications, stay with just regular C<FetchRow> with no parameters. + +B<NOTE 2>: The ODBC API explicitly warns against mixing calls to +C<SQLFetch> and C<SQLExtendedFetch>; use one or the other but not +both. + +If I<ROW> is specified, it moves the keyset B<RELATIVE> C<ROW> number +of rows. + +If I<ROW> is specified and C<TYPE> is B<not>, then the type used is +B<RELATIVE>. + +Returns I<true> when another record is available to read, and I<false> +when there are no more records. + +=item FieldNames () + +Returns an array of fieldnames found in the current data set. There is +no guarantee on order. + +=item GetConnections () + +Returns an array of connection numbers showing what connections are +currently open. + +=item GetConnectOption ( OPTION ) + +Returns the value of the specified connect option C<OPTION>. Refer to +ODBC documentation for more information on the options and values. + +Returns a string or scalar depending upon the option specified. + +=item GetCursorName () + +Returns the name of the current cursor as a string or I<undef>. + +=item GetData () + +Retrieves the current row from the dataset. This is not generally +used by users; it is used internally. + +Returns an array of field data where the first element is either +I<false> (if successful) and I<true> (if B<not> successful). + +=item getDSN ( [ DSN ] ) + +Returns an associative array indicating the configuration for the +specified DSN. + +If no DSN is specified then the current connection is used. + +The returned associative array consists of: + + keys=DSN keyword; values=Keyword value. $Data{$Keyword}=Value + +=item GetFunctions ( [ FUNCTION1, FUNCTION2, ... ] ) + +Returns an associative array indicating the ability of the ODBC Driver +to support the specified functions. If no functions are specified, +then a 100 element associative array is returned containing all +possible functions and their values. + +C<FUNCTION> must be in the form of an ODBC API constant like +C<SQL_API_SQLTRANSACT>. + +The returned array will contain the results like: + + $Results{SQL_API_SQLTRANSACT}=Value + +Example: + + $Results = $O->GetFunctions( + $O->SQL_API_SQLTRANSACT, + SQL_API_SQLSETCONNECTOPTION + ); + $ConnectOption = $Results{SQL_API_SQLSETCONNECTOPTION}; + $Transact = $Results{SQL_API_SQLTRANSACT}; + +=item GetInfo ( OPTION ) + +Returns a string indicating the value of the particular +option specified. + +=item GetMaxBufSize () + +Returns the current allocated limit for I<MaxBufSize>. For more info, +see C<SetMaxBufSize>. + +=item GetSQLState () * + +Returns a string indicating the SQL state as reported by ODBC. The SQL +state is a code that the ODBC Manager or ODBC Driver returns after the +execution of a SQL function. This is helpful for debugging purposes. + +=item GetStmtCloseType ( [ CONNECTION ] ) + +Returns a string indicating the type of closure that will be used +everytime the I<hstmt> is freed. See C<SetStmtCloseType> for details. + +By default, the connection of the current object will be used. If +C<CONNECTION> is a valid connection number, then it will be used. + +=item GetStmtOption ( OPTION ) + +Returns the value of the specified statement option C<OPTION>. Refer +to ODBC documentation for more information on the options and values. + +Returns a string or scalar depending upon the option specified. + +=item MoreResults () + +This will report whether there is data yet to be retrieved from the +query. This can happen if the query was a multiple select. + +Example: + + "SELECT * FROM [foo] SELECT * FROM [bar]" + +B<NOTE>: Not all drivers support this. + +Returns I<1> if there is more data, I<undef> otherwise. + +=item RowCount ( CONNECTION ) + +For I<UPDATE>, I<INSERT> and I<DELETE> statements, the returned value +is the number of rows affected by the request or I<-1> if the number +of affected rows is not available. + +B<NOTE 1>: This function is not supported by all ODBC drivers! Some +drivers do support this but not for all statements (e.g., it is +supported for I<UPDATE>, I<INSERT> and I<DELETE> commands but not for +the I<SELECT> command). + +B<NOTE 2>: Many data sources cannot return the number of rows in a +result set before fetching them; for maximum interoperability, +applications should not rely on this behavior. + +Returns the number of affected rows, or I<-1> if not supported by the +driver in the current context. + +=item Run ( SQL ) + +Executes the SQL command B<SQL> and dumps to the screen info about +it. Used primarily for debugging. + +No return value. + +=item SetConnectOption ( OPTION ) * + +Sets the value of the specified connect option B<OPTION>. Refer to +ODBC documentation for more information on the options and values. + +Returns I<true> on success, I<false> otherwise. + +=item SetCursorName ( NAME ) * + +Sets the name of the current cursor. + +Returns I<true> on success, I<false> otherwise. + +=item SetPos ( ROW [, OPTION, LOCK ] ) * + +Moves the cursor to the row C<ROW> within the current keyset (B<not> +the current data/result set). + +Returns I<true> on success, I<false> otherwise. + +=item SetMaxBufSize ( SIZE ) + +This sets the I<MaxBufSize> for a particular connection. This will +most likely never be needed but... + +The amount of memory that is allocated to retrieve the field data of a +record is dynamic and changes when it need to be larger. I found that +a memo field in an MS Access database ended up requesting 4 Gig of +space. This was a bit much so there is an imposed limit (2,147,483,647 +bytes) that can be allocated for data retrieval. + +Since it is possible that someone has a database with field data +greater than 10,240, you can use this function to increase the limit +up to a ceiling of 2,147,483,647 (recompile if you need more). + +Returns the max number of bytes. + +=item SetStmtCloseType ( TYPE [, CONNECTION ] ) + +Sets a particular I<hstmt> close type for the connection. This is the +same as C<ODBCFreeStmt(hstmt, TYPE)>. By default, the connection of +the current object will be used. If C<CONNECTION> is a valid +connection number, then it will be used. + +C<TYPE> may be one of: + + SQL_CLOSE + SQL_DROP + SQL_UNBIND + SQL_RESET_PARAMS + +Returns a string indicating the newly set type. + +=item SetStmtOption ( OPTION ) * + +Sets the value of the specified statement option C<OPTION>. Refer to +ODBC documentation for more information on the options and values. + +Returns I<true> on success, I<false> otherwise. + +=item ShutDown () + +Closes the ODBC connection and dumps to the screen info about +it. Used primarily for debugging. + +No return value. + +=item Sql ( SQL_STRING ) + +Executes the SQL command C<SQL_STRING> on the current connection. + +Returns I<?> on success, or an error number on failure. + +=item TableList ( QUALIFIER, OWNER, NAME, TYPE ) + +Returns the catalog of tables that are available in the DSN. For an +unknown parameter, just specify the empty string I<"">. + +Returns an array of table names. + +=item Transact ( TYPE ) * + +Forces the ODBC connection to perform a I<rollback> or I<commit> +transaction. + +C<TYPE> may be one of: + + SQL_COMMIT + SQL_ROLLBACK + +B<NOTE>: This only works with ODBC drivers that support transactions. +Your driver supports it if I<true> is returned from: + + $O->GetFunctions($O->SQL_API_SQLTRANSACT)[1] + +(See C<GetFunctions> for more details.) + +Returns I<true> on success, I<false> otherwise. + +=item Version ( PACKAGES ) + +Returns an array of version numbers for the requested packages +(F<ODBC.pm> or F<ODBC.PLL>). If the list C<PACKAGES> is empty, then +all version numbers are returned. + +=back + +=head1 LIMITATIONS + +What known problems does this thing have? + +=over + +=item * + +If the account under which the process runs does not have write +permission on the default directory (for the process, not the ODBC +DSN), you will probably get a runtime error during a +C<SQLConnection>. I don't think that this is a problem with the code, +but more like a problem with ODBC. This happens because some ODBC +drivers need to write a temporary file. I noticed this using the MS +Jet Engine (Access Driver). + +=item * + +This module has been neither optimized for speed nor optimized for +memory consumption. + +=back + +=head1 INSTALLATION NOTES + +If you wish to use this module with a build of Perl other than +ActivePerl, you may wish to fetch the original source distribution for +this module at: + + ftp://ftp.roth.net:/pub/ntperl/ODBC/970208/Bin/Win32_ODBC_Build_CORE.zip + +or one of the other archives at that same location. See the included +README for hints on installing this module manually, what to do if you +get a I<parse exception>, and a pointer to a test script for this +module. + +=head1 OTHER DOCUMENTATION + +Find a FAQ for Win32::ODBC at: + + http://www.roth.net/odbc/odbcfaq.htm + +=head1 AUTHOR + +Dave Roth <rothd@roth.net> + +=head1 CREDITS + +Based on original code by Dan DeMaggio <dmag@umich.edu> + +=head1 DISCLAIMER + +I do not guarantee B<ANYTHING> with this package. If you use it you +are doing so B<AT YOUR OWN RISK>! I may or may not support this +depending on my time schedule. + +=head1 HISTORY + +Last Modified 1999.09.25. + +=head1 COPYRIGHT + +Copyright (c) 1996-1998 Dave Roth. All rights reserved. + +Courtesy of Roth Consulting: http://www.roth.net/consult/ + +Use under GNU General Public License. Details can be found at: +http://www.gnu.org/copyleft/gpl.html + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/PerfLib.pm b/Master/tlpkg/tlperl/lib/Win32/PerfLib.pm new file mode 100644 index 00000000000..2b773d68f4b --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/PerfLib.pm @@ -0,0 +1,538 @@ +package Win32::PerfLib; + +use strict; +use Carp; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD); + +require Exporter; +require DynaLoader; +require AutoLoader; + +@ISA = qw(Exporter DynaLoader); + +@EXPORT = qw( + PERF_100NSEC_MULTI_TIMER + PERF_100NSEC_MULTI_TIMER_INV + PERF_100NSEC_TIMER + PERF_100NSEC_TIMER_INV + PERF_AVERAGE_BASE + PERF_AVERAGE_BULK + PERF_AVERAGE_TIMER + PERF_COUNTER_BASE + PERF_COUNTER_BULK_COUNT + PERF_COUNTER_COUNTER + PERF_COUNTER_DELTA + PERF_COUNTER_ELAPSED + PERF_COUNTER_FRACTION + PERF_COUNTER_HISTOGRAM + PERF_COUNTER_HISTOGRAM_TYPE + PERF_COUNTER_LARGE_DELTA + PERF_COUNTER_LARGE_QUEUELEN_TYPE + PERF_COUNTER_LARGE_RAWCOUNT + PERF_COUNTER_LARGE_RAWCOUNT_HEX + PERF_COUNTER_MULTI_BASE + PERF_COUNTER_MULTI_TIMER + PERF_COUNTER_MULTI_TIMER_INV + PERF_COUNTER_NODATA + PERF_COUNTER_QUEUELEN + PERF_COUNTER_QUEUELEN_TYPE + PERF_COUNTER_RATE + PERF_COUNTER_RAWCOUNT + PERF_COUNTER_RAWCOUNT_HEX + PERF_COUNTER_TEXT + PERF_COUNTER_TIMER + PERF_COUNTER_TIMER_INV + PERF_COUNTER_VALUE + PERF_DATA_REVISION + PERF_DATA_VERSION + PERF_DELTA_BASE + PERF_DELTA_COUNTER + PERF_DETAIL_ADVANCED + PERF_DETAIL_EXPERT + PERF_DETAIL_NOVICE + PERF_DETAIL_WIZARD + PERF_DISPLAY_NOSHOW + PERF_DISPLAY_NO_SUFFIX + PERF_DISPLAY_PERCENT + PERF_DISPLAY_PER_SEC + PERF_DISPLAY_SECONDS + PERF_ELAPSED_TIME + PERF_INVERSE_COUNTER + PERF_MULTI_COUNTER + PERF_NO_INSTANCES + PERF_NO_UNIQUE_ID + PERF_NUMBER_DECIMAL + PERF_NUMBER_DEC_1000 + PERF_NUMBER_HEX + PERF_OBJECT_TIMER + PERF_RAW_BASE + PERF_RAW_FRACTION + PERF_SAMPLE_BASE + PERF_SAMPLE_COUNTER + PERF_SAMPLE_FRACTION + PERF_SIZE_DWORD + PERF_SIZE_LARGE + PERF_SIZE_VARIABLE_LEN + PERF_SIZE_ZERO + PERF_TEXT_ASCII + PERF_TEXT_UNICODE + PERF_TIMER_100NS + PERF_TIMER_TICK + PERF_TYPE_COUNTER + PERF_TYPE_NUMBER + PERF_TYPE_TEXT + PERF_TYPE_ZERO + ); + +$VERSION = '0.05'; + +sub AUTOLOAD { + + my $constname; + ($constname = $AUTOLOAD) =~ s/.*:://; + local $! = 0; + my $val = constant($constname); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + croak "Your vendor has not defined Win32::PerfLib macro $constname"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::PerfLib $VERSION; + +# Preloaded methods go here. + +sub new +{ + my $proto = shift; + my $class = ref($proto) || $proto; + my $comp = shift; + my $handle; + my $self = {}; + if(PerfLibOpen($comp,$handle)) + { + $self->{handle} = $handle; + bless $self, $class; + return $self; + } + else + { + return undef; + } + +} + +sub Close +{ + my $self = shift; + return PerfLibClose($self->{handle}); +} + +sub DESTROY +{ + my $self = shift; + if(!PerfLibClose($self->{handle})) + { + croak "Error closing handle!\n"; + } +} + +sub GetCounterNames +{ + my($machine,$href) = @_; + if(ref $href ne "HASH") + { + croak("usage: Win32::PerfLib::GetCounterNames(machine,hashRef)\n"); + } + my($data,@data,$num,$name); + my $retval = PerfLibGetNames($machine,$data); + if($retval) + { + @data = split(/\0/, $data); + while(@data) + { + $num = shift @data; + $name = shift @data; + $href->{$num} = $name; + } + } + $retval; +} + +sub GetCounterHelp +{ + my($machine,$href) = @_; + if(ref $href ne "HASH") + { + croak("usage: Win32::PerfLib::GetCounterHelp(machine,hashRef)\n"); + } + my($data,@data,$num,$name); + my $retval = PerfLibGetHelp($machine,$data); + if($retval) + { + @data = split(/\0/, $data); + while(@data) + { + $num = shift @data; + $name = shift @data; + $href->{$num} = $name; + } + } + $retval; +} + +sub GetObjectList +{ + my $self = shift; + my $object = shift; + my $data = shift; + if(ref $data ne "HASH") + { + croak("reference isn't a hash reference!\n"); + } + return PerfLibGetObjects($self->{handle}, $object, $data); +} + +sub GetCounterType +{ + my $type = shift; + my $retval; + if( &Win32::PerfLib::PERF_100NSEC_MULTI_TIMER == $type ) + { + $retval = "PERF_100NSEC_MULTI_TIMER"; + } + elsif( &Win32::PerfLib::PERF_100NSEC_MULTI_TIMER_INV == $type ) + { + $retval = "PERF_100NSEC_MULTI_TIMER_INV"; + } + elsif( &Win32::PerfLib::PERF_100NSEC_TIMER == $type ) + { + $retval = "PERF_100NSEC_TIMER"; + } + elsif( &Win32::PerfLib::PERF_100NSEC_TIMER_INV == $type ) + { + $retval = "PERF_100NSEC_TIMER_INV"; + } + elsif( &Win32::PerfLib::PERF_AVERAGE_BASE == $type ) + { + $retval = "PERF_AVERAGE_BASE"; + } + elsif( &Win32::PerfLib::PERF_AVERAGE_BULK == $type ) + { + $retval = "PERF_AVERAGE_BULK"; + } + elsif( &Win32::PerfLib::PERF_AVERAGE_TIMER == $type ) + { + $retval = "PERF_AVERAGE_TIMER"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_BULK_COUNT == $type ) + { + $retval = "PERF_COUNTER_BULK_COUNT"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_COUNTER == $type ) + { + $retval = "PERF_COUNTER_COUNTER"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_DELTA == $type ) + { + $retval = "PERF_COUNTER_DELTA"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_DELTA == $type ) + { + $retval = "PERF_COUNTER_LARGE_DELTA"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_QUEUELEN_TYPE == $type ) + { + $retval = "PERF_COUNTER_LARGE_QUEUELEN_TYPE"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_RAWCOUNT == $type ) + { + $retval = "PERF_COUNTER_LARGE_RAWCOUNT"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_LARGE_RAWCOUNT_HEX == $type ) + { + $retval = "PERF_COUNTER_LARGE_RAWCOUNT_HEX"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_BASE == $type ) + { + $retval = "PERF_COUNTER_MULTI_BASE"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_TIMER == $type ) + { + $retval = "PERF_COUNTER_MULTI_TIMER"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_MULTI_TIMER_INV == $type ) + { + $retval = "PERF_COUNTER_MULTI_TIMER_INV"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_NODATA == $type ) + { + $retval = "PERF_COUNTER_NODATA"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_QUEUELEN_TYPE == $type ) + { + $retval = "PERF_COUNTER_QUEUELEN_TYPE"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_RAWCOUNT == $type ) + { + $retval = "PERF_COUNTER_RAWCOUNT"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_RAWCOUNT_HEX == $type ) + { + $retval = "PERF_COUNTER_RAWCOUNT_HEX"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_TEXT == $type ) + { + $retval = "PERF_COUNTER_TEXT"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_TIMER == $type ) + { + $retval = "PERF_COUNTER_TIMER"; + } + elsif( &Win32::PerfLib::PERF_COUNTER_TIMER_INV == $type ) + { + $retval = "PERF_COUNTER_TIMER_INV"; + } + elsif( &Win32::PerfLib::PERF_ELAPSED_TIME == $type ) + { + $retval = "PERF_ELAPSED_TIME"; + } + elsif( &Win32::PerfLib::PERF_RAW_BASE == $type ) + { + $retval = "PERF_RAW_BASE"; + } + elsif( &Win32::PerfLib::PERF_RAW_FRACTION == $type ) + { + $retval = "PERF_RAW_FRACTION"; + } + elsif( &Win32::PerfLib::PERF_SAMPLE_BASE == $type ) + { + $retval = "PERF_SAMPLE_BASE"; + } + elsif( &Win32::PerfLib::PERF_SAMPLE_COUNTER == $type ) + { + $retval = "PERF_SAMPLE_COUNTER"; + } + elsif( &Win32::PerfLib::PERF_SAMPLE_FRACTION == $type ) + { + $retval = "PERF_SAMPLE_FRACTION"; + } + $retval; +} + + + +1; +__END__ + +=head1 NAME + +Win32::PerfLib - accessing the Windows NT Performance Counter + +=head1 SYNOPSIS + + use Win32::PerfLib; + my $server = ""; + Win32::PerfLib::GetCounterNames($server, \%counter); + %r_counter = map { $counter{$_} => $_ } keys %counter; + # retrieve the id for process object + $process_obj = $r_counter{Process}; + # retrieve the id for the process ID counter + $process_id = $r_counter{'ID Process'}; + + # create connection to $server + $perflib = new Win32::PerfLib($server); + $proc_ref = {}; + # get the performance data for the process object + $perflib->GetObjectList($process_obj, $proc_ref); + $perflib->Close(); + $instance_ref = $proc_ref->{Objects}->{$process_obj}->{Instances}; + foreach $p (sort keys %{$instance_ref}) + { + $counter_ref = $instance_ref->{$p}->{Counters}; + foreach $i (keys %{$counter_ref}) + { + if($counter_ref->{$i}->{CounterNameTitleIndex} == $process_id) + { + printf( "% 6d %s\n", $counter_ref->{$i}->{Counter}, + $instance_ref->{$p}->{Name} + ); + } + } + } + +=head1 DESCRIPTION + +This module allows to retrieve the performance counter of any computer +(running Windows NT) in the network. + +=head1 FUNCTIONS + +=head2 NOTE + +All of the functions return false if they fail, unless otherwise noted. +If the $server argument is undef the local machine is assumed. + +=over 10 + +=item Win32::PerfLib::GetCounterNames($server,$hashref) + +Retrieves the counter names and their indices from the registry and stores them +in the hash reference + +=item Win32::PerfLib::GetCounterHelp($server,$hashref) + +Retrieves the counter help strings and their indices from the registry and +stores them in the hash reference + +=item $perflib = Win32::PerfLib->new ($server) + +Creates a connection to the performance counters of the given server + +=item $perflib->GetObjectList($objectid,$hashref) + +retrieves the object and counter list of the given performance object. + +=item $perflib->Close($hashref) + +closes the connection to the performance counters + +=item Win32::PerfLib::GetCounterType(countertype) + +converts the counter type to readable string as referenced in L<calc.html> so +that it is easier to find the appropriate formula to calculate the raw counter +data. + +=back + +=head1 Datastructures + +The performance data is returned in the following data structure: + +=over 10 + +=item Level 1 + + $hashref = { + 'NumObjectTypes' => VALUE + 'Objects' => HASHREF + 'PerfFreq' => VALUE + 'PerfTime' => VALUE + 'PerfTime100nSec' => VALUE + 'SystemName' => STRING + 'SystemTime' => VALUE + } + +=item Level 2 + +The hash reference $hashref->{Objects} has the returned object ID(s) as keys and +a hash reference to the object counter data as value. Even there is only one +object requested in the call to GetObjectList there may be more than one object +in the result. + + $hashref->{Objects} = { + <object1> => HASHREF + <object2> => HASHREF + ... + } + +=item Level 3 + +Each returned object ID has object-specific performance information. If an +object has instances like the process object there is also a reference to +the instance information. + + $hashref->{Objects}->{<object1>} = { + 'DetailLevel' => VALUE + 'Instances' => HASHREF + 'Counters' => HASHREF + 'NumCounters' => VALUE + 'NumInstances' => VALUE + 'ObjectHelpTitleIndex' => VALUE + 'ObjectNameTitleIndex' => VALUE + 'PerfFreq' => VALUE + 'PerfTime' => VALUE + } + +=item Level 4 + +If there are instance information for the object available they are stored in +the 'Instances' hashref. If the object has no instances there is an 'Counters' +key instead. The instances or counters are numbered. + + $hashref->{Objects}->{<object1>}->{Instances} = { + <1> => HASHREF + <2> => HASHREF + ... + <n> => HASHREF + } + or + $hashref->{Objects}->{<object1>}->{Counters} = { + <1> => HASHREF + <2> => HASHREF + ... + <n> => HASHREF + } + +=item Level 5 + + $hashref->{Objects}->{<object1>}->{Instances}->{<1>} = { + Counters => HASHREF + Name => STRING + ParentObjectInstance => VALUE + ParentObjectTitleIndex => VALUE + } + or + $hashref->{Objects}->{<object1>}->{Counters}->{<1>} = { + Counter => VALUE + CounterHelpTitleIndex => VALUE + CounterNameTitleIndex => VALUE + CounterSize => VALUE + CounterType => VALUE + DefaultScale => VALUE + DetailLevel => VALUE + Display => STRING + } + +=item Level 6 + + $hashref->{Objects}->{<object1>}->{Instances}->{<1>}->{Counters} = { + <1> => HASHREF + <2> => HASHREF + ... + <n> => HASHREF + } + +=item Level 7 + + $hashref->{Objects}->{<object1>}->{Instances}->{<1>}->{Counters}->{<1>} = { + Counter => VALUE + CounterHelpTitleIndex => VALUE + CounterNameTitleIndex => VALUE + CounterSize => VALUE + CounterType => VALUE + DefaultScale => VALUE + DetailLevel => VALUE + Display => STRING + } + +Depending on the B<CounterType> there are calculations to do (see calc.html). + +=back + +=head1 AUTHOR + +Jutta M. Klebe, jmk@bybyte.de + +=head1 SEE ALSO + +perl(1). + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/Pipe.pm b/Master/tlpkg/tlperl/lib/Win32/Pipe.pm new file mode 100644 index 00000000000..a99d5a0da08 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Pipe.pm @@ -0,0 +1,414 @@ +package Win32::Pipe; + +$VERSION = '0.022'; + +# Win32::Pipe.pm +# +==========================================================+ +# | | +# | PIPE.PM package | +# | --------------- | +# | Release v96.05.11 | +# | | +# | Copyright (c) 1996 Dave Roth. All rights reserved. | +# | This program is free software; you can redistribute | +# | it and/or modify it under the same terms as Perl itself. | +# | | +# +==========================================================+ +# +# +# Use under GNU General Public License or Larry Wall's "Artistic License" +# +# Check the README.TXT file that comes with this package for details about +# it's history. +# + +require Exporter; +require DynaLoader; + +@ISA= qw( Exporter DynaLoader ); + # Items to export into callers namespace by default. Note: do not export + # names by default without a very good reason. Use EXPORT_OK instead. + # Do not simply export all your public functions/methods/constants. +@EXPORT = qw(); + +$ErrorNum = 0; +$ErrorText = ""; + +sub new +{ + my ($self, $Pipe); + my ($Type, $Name, $Time) = @_; + + if (! $Time){ + $Time = DEFAULT_WAIT_TIME(); + } + $Pipe = PipeCreate($Name, $Time); + if ($Pipe){ + $self = bless {}; + $self->{'Pipe'} = $Pipe; + }else{ + ($ErrorNum, $ErrorText) = PipeError(); + return undef; + } + $self; +} + +sub Write{ + my($self, $Data) = @_; + $Data = PipeWrite($self->{'Pipe'}, $Data); + return $Data; +} + +sub Read{ + my($self) = @_; + my($Data); + $Data = PipeRead($self->{'Pipe'}); + return $Data; +} + +sub Error{ + my($self) = @_; + my($MyError, $MyErrorText, $Temp); + if (! ref($self)){ + undef $Temp; + }else{ + $Temp = $self->{'Pipe'}; + } + ($MyError, $MyErrorText) = PipeError($Temp); + return wantarray? ($MyError, $MyErrorText):"[$MyError] \"$MyErrorText\""; +} + + +sub Close{ + my ($self) = shift; + PipeClose($self->{'Pipe'}); + $self->{'Pipe'} = 0; +} + +sub Connect{ + my ($self) = @_; + my ($Result); + $Result = PipeConnect($self->{'Pipe'}); + return $Result; +} + +sub Disconnect{ + my ($self, $iPurge) = @_; + my ($Result); + if (! $iPurge){ + $iPurge = 1; + } + $Result = PipeDisconnect($self->{'Pipe'}, $iPurge); + return $Result; +} + +sub BufferSize{ + my($self) = @_; + my($Result) = PipeBufferSize($self->{'Pipe'}); + return $Result; +} + +sub ResizeBuffer{ + my($self, $Size) = @_; + my($Result) = PipeResizeBuffer($self->{'Pipe'}, $Size); + return $Result; +} + + +#### +# Auto-Kill an instance of this module +#### +sub DESTROY +{ + my ($self) = shift; + Close($self); +} + + +sub Credit{ + my($Name, $Version, $Date, $Author, $CompileDate, $CompileTime, $Credits) = Win32::Pipe::Info(); + my($Out, $iWidth); + $iWidth = 60; + $Out .= "\n"; + $Out .= " +". "=" x ($iWidth). "+\n"; + $Out .= " |". Center("", $iWidth). "|\n"; + $Out .= " |" . Center("", $iWidth). "|\n"; + $Out .= " |". Center("$Name", $iWidth). "|\n"; + $Out .= " |". Center("-" x length("$Name"), $iWidth). "|\n"; + $Out .= " |". Center("", $iWidth). "|\n"; + + $Out .= " |". Center("Version $Version ($Date)", $iWidth). "|\n"; + $Out .= " |". Center("by $Author", $iWidth). "|\n"; + $Out .= " |". Center("Compiled on $CompileDate at $CompileTime.", $iWidth). "|\n"; + $Out .= " |". Center("", $iWidth). "|\n"; + $Out .= " |". Center("Credits:", $iWidth). "|\n"; + $Out .= " |". Center(("-" x length("Credits:")), $iWidth). "|\n"; + foreach $Temp (split("\n", $Credits)){ + $Out .= " |". Center("$Temp", $iWidth). "|\n"; + } + $Out .= " |". Center("", $iWidth). "|\n"; + $Out .= " +". "=" x ($iWidth). "+\n"; + return $Out; +} + +sub Center{ + local($Temp, $Width) = @_; + local($Len) = ($Width - length($Temp)) / 2; + return " " x int($Len) . $Temp . " " x (int($Len) + (($Len != int($Len))? 1:0)); +} + +# ------------------ A U T O L O A D F U N C T I O N --------------------- + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + $val = constant($constname, @_ ? $_[0] : 0); + + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + + # Added by JOC 06-APR-96 + # $pack = 0; + $pack = 0; + ($pack,$file,$line) = caller; + print "Your vendor has not defined Win32::Pipe macro $constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::Pipe; + +1; +__END__ + +=head1 NAME + +Win32::Pipe - Win32 Named Pipe + +=head1 SYNOPSIS + +To use this extension, follow these basic steps. First, you need to +'use' the pipe extension: + + use Win32::Pipe; + +Then you need to create a server side of a named pipe: + + $Pipe = new Win32::Pipe("My Pipe Name"); + +or if you are going to connect to pipe that has already been created: + + $Pipe = new Win32::Pipe("\\\\server\\pipe\\My Pipe Name"); + + NOTE: The "\\\\server\\pipe\\" is necessary when connecting + to an existing pipe! If you are accessing the same + machine you could use "\\\\.\\pipe\\" but either way + works fine. + +You should check to see if C<$Pipe> is indeed defined otherwise there +has been an error. + +Whichever end is the server, it must now wait for a connection... + + $Result = $Pipe->Connect(); + + NOTE: The client end does not do this! When the client creates + the pipe it has already connected! + +Now you can read and write data from either end of the pipe: + + $Data = $Pipe->Read(); + + $Result = $Pipe->Write("Howdy! This is cool!"); + +When the server is finished it must disconnect: + + $Pipe->Disconnect(); + +Now the server could C<Connect> again (and wait for another client) or +it could destroy the named pipe... + + $Data->Close(); + +The client should C<Close> in order to properly end the session. + +=head1 DESCRIPTION + +=head2 General Use + +This extension gives Win32 Perl the ability to use Named Pipes. Why? +Well considering that Win32 Perl does not (yet) have the ability to +C<fork> I could not see what good the C<pipe(X,Y)> was. Besides, where +I am as an admin I must have several perl daemons running on several +NT Servers. It dawned on me one day that if I could pipe all these +daemons' output to my workstation (across the net) then it would be +much easier to monitor. This was the impetus for an extension using +Named Pipes. I think that it is kinda cool. :) + +=head2 Benefits + +And what are the benefits of this module? + +=over + +=item * + +You may create as many named pipes as you want (uh, well, as many as +your resources will allow). + +=item * + +Currently there is a limit of 256 instances of a named pipe (once a +pipe is created you can have 256 client/server connections to that +name). + +=item * + +The default buffer size is 512 bytes; this can be altered by the +C<ResizeBuffer> method. + +=item * + +All named pipes are byte streams. There is currently no way to alter a +pipe to be message based. + +=item * + +Other things that I cannot think of right now... :) + +=back + +=head1 CONSTRUCTOR + +=over + +=item new ( NAME ) + +Creates a named pipe if used in server context or a connection to the +specified named pipe if used in client context. Client context is +determined by prepending $Name with "\\\\". + +Returns I<true> on success, I<false> on failure. + +=back + +=head1 METHODS + +=over + +=item BufferSize () + +Returns the size of the instance of the buffer of the named pipe. + +=item Connect () + +Tells the named pipe to create an instance of the named pipe and wait +until a client connects. Returns I<true> on success, I<false> on +failure. + +=item Close () + +Closes the named pipe. + +=item Disconnect () + +Disconnects (and destroys) the instance of the named pipe from the +client. Returns I<true> on success, I<false> on failure. + +=item Error () + +Returns the last error messages pertaining to the named pipe. If used +in context to the package. Returns a list containing C<ERROR_NUMBER> +and C<ERROR_TEXT>. + +=item Read () + +Reads from the named pipe. Returns data read from the pipe on success, +undef on failure. + +=item ResizeBuffer ( SIZE ) + +Sets the size of the buffer of the instance of the named pipe to +C<SIZE>. Returns the size of the buffer on success, I<false> on +failure. + +=item Write ( DATA ) + +Writes C<DATA> to the named pipe. Returns I<true> on success, I<false> +on failure. + +=back + +=head1 LIMITATIONS + +What known problems does this thing have? + +=over + +=item * + +If someone is waiting on a C<Read> and the other end terminates then +you will wait for one B<REALLY> long time! (If anyone has an idea on +how I can detect the termination of the other end let me know!) + +=item * + +All pipes are blocking. I am considering using threads and callbacks +into Perl to perform async IO but this may be too much for my time +stress. ;) + +=item * + +There is no security placed on these pipes. + +=item * + +This module has neither been optimized for speed nor optimized for +memory consumption. This may run into memory bloat. + +=back + +=head1 INSTALLATION NOTES + +If you wish to use this module with a build of Perl other than +ActivePerl, you may wish to fetch the source distribution for this +module. The source is included as part of the C<libwin32> bundle, +which you can find in any CPAN mirror here: + + modules/by-authors/Gurusamy_Sarathy/libwin32-0.151.tar.gz + +The source distribution also contains a pair of sample client/server +test scripts. For the latest information on this module, consult the +following web site: + + http://www.roth.net/perl + +=head1 AUTHOR + +Dave Roth <rothd@roth.net> + +=head1 DISCLAIMER + +I do not guarantee B<ANYTHING> with this package. If you use it you +are doing so B<AT YOUR OWN RISK>! I may or may not support this +depending on my time schedule. + +=head1 COPYRIGHT + +Copyright (c) 1996 Dave Roth. All rights reserved. +This program is free software; you can redistribute +it and/or modify it under the same terms as Perl itself. + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/Process.pm b/Master/tlpkg/tlperl/lib/Win32/Process.pm new file mode 100644 index 00000000000..f07169b4080 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Process.pm @@ -0,0 +1,217 @@ +package Win32::Process; + +require Exporter; +require DynaLoader; +@ISA = qw(Exporter DynaLoader); + +$VERSION = '0.10'; + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + CREATE_DEFAULT_ERROR_MODE + CREATE_NEW_CONSOLE + CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW + CREATE_SEPARATE_WOW_VDM + CREATE_SUSPENDED + CREATE_UNICODE_ENVIRONMENT + DEBUG_ONLY_THIS_PROCESS + DEBUG_PROCESS + DETACHED_PROCESS + HIGH_PRIORITY_CLASS + IDLE_PRIORITY_CLASS + INFINITE + NORMAL_PRIORITY_CLASS + REALTIME_PRIORITY_CLASS + THREAD_PRIORITY_ABOVE_NORMAL + THREAD_PRIORITY_BELOW_NORMAL + THREAD_PRIORITY_ERROR_RETURN + THREAD_PRIORITY_HIGHEST + THREAD_PRIORITY_IDLE + THREAD_PRIORITY_LOWEST + THREAD_PRIORITY_NORMAL + THREAD_PRIORITY_TIME_CRITICAL +); + +@EXPORT_OK = qw( + STILL_ACTIVE +); + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + local $! = 0; + my $val = constant($constname); + if ($! != 0) { + my ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::Process macro $constname, used at $file line $line."; + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} # end AUTOLOAD + +bootstrap Win32::Process; + +# Win32::IPC > 1.02 uses the get_Win32_IPC_HANDLE method: +*get_Win32_IPC_HANDLE = \&get_process_handle; + +1; +__END__ + +=head1 NAME + +Win32::Process - Create and manipulate processes. + +=head1 SYNOPSIS + + use Win32::Process; + use Win32; + + sub ErrorReport{ + print Win32::FormatMessage( Win32::GetLastError() ); + } + + Win32::Process::Create($ProcessObj, + "C:\\winnt\\system32\\notepad.exe", + "notepad temp.txt", + 0, + NORMAL_PRIORITY_CLASS, + ".")|| die ErrorReport(); + + $ProcessObj->Suspend(); + $ProcessObj->Resume(); + $ProcessObj->Wait(INFINITE); + +=head1 DESCRIPTION + +This module provides access to the process control functions in the +Win32 API. + +=head1 METHODS + +=over 8 + +=item Win32::Process::Create($obj,$appname,$cmdline,$iflags,$cflags,$curdir) + +Creates a new process. + + Args: + + $obj container for process object + $appname full path name of executable module + $cmdline command line args + $iflags flag: inherit calling processes handles or not + $cflags flags for creation (see exported vars below) + $curdir working dir of new process + +Returns non-zero on success, 0 on failure. + +=item Win32::Process::Open($obj,$pid,$iflags) + +Creates a handle Perl can use to an existing process as identified by $pid. +The $iflags is the inherit flag that is passed to OpenProcess. Currently +Win32::Process objects created using Win32::Process::Open cannot Suspend +or Resume the process. All other calls should work. + +Win32::Process::Open returns non-zero on success, 0 on failure. + +=item Win32::Process::KillProcess($pid, $exitcode) + +Terminates any process identified by $pid. $exitcode will be set to +the exit code of the process. + +=item $ProcessObj->Suspend() + +Suspend the process associated with the $ProcessObj. + +=item $ProcessObj->Resume() + +Resume a suspended process. + +=item $ProcessObj->Kill($exitcode) + +Kill the associated process, have it terminate with exit code $ExitCode. + +=item $ProcessObj->GetPriorityClass($class) + +Get the priority class of the process. + +=item $ProcessObj->SetPriorityClass($class) + +Set the priority class of the process (see exported values below for +options). + +=item $ProcessObj->GetProcessAffinityMask($processAffinityMask, $systemAffinityMask) + +Get the process affinity mask. This is a bitvector in which each bit +represents the processors that a process is allowed to run on. + +=item $ProcessObj->SetProcessAffinityMask($processAffinityMask) + +Set the process affinity mask. Only available on Windows NT. + +=item $ProcessObj->GetExitCode($exitcode) + +Retrieve the exitcode of the process. Will return STILL_ACTIVE if the +process is still running. The STILL_ACTIVE constant is only exported +by explicit request. + +=item $ProcessObj->Wait($timeout) + +Wait for the process to die. $timeout should be specified in milliseconds. +To wait forever, specify the constant C<INFINITE>. + +=item $ProcessObj->GetProcessID() + +Returns the Process ID. + +=item Win32::Process::GetCurrentProcessID() + +Returns the current process ID, which is the same as $$. But not on cygwin, +where $$ is the cygwin-internal PID and not the windows PID. +On cygwin GetCurrentProcessID() returns the windows PID as needed for all +the Win32::Process functions. + +=back + +=head1 EXPORTS + +The following constants are exported by default: + + CREATE_DEFAULT_ERROR_MODE + CREATE_NEW_CONSOLE + CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW + CREATE_SEPARATE_WOW_VDM + CREATE_SUSPENDED + CREATE_UNICODE_ENVIRONMENT + DEBUG_ONLY_THIS_PROCESS + DEBUG_PROCESS + DETACHED_PROCESS + HIGH_PRIORITY_CLASS + IDLE_PRIORITY_CLASS + INFINITE + NORMAL_PRIORITY_CLASS + REALTIME_PRIORITY_CLASS + THREAD_PRIORITY_ABOVE_NORMAL + THREAD_PRIORITY_BELOW_NORMAL + THREAD_PRIORITY_ERROR_RETURN + THREAD_PRIORITY_HIGHEST + THREAD_PRIORITY_IDLE + THREAD_PRIORITY_LOWEST + THREAD_PRIORITY_NORMAL + THREAD_PRIORITY_TIME_CRITICAL + +The following additional constants are exported by request only: + + STILL_ACTIVE + +=cut + +# Local Variables: +# tmtrack-file-task: "Win32::Process" +# End: diff --git a/Master/tlpkg/tlperl/lib/Win32/Registry.pm b/Master/tlpkg/tlperl/lib/Win32/Registry.pm new file mode 100644 index 00000000000..c83fca5a3b1 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Registry.pm @@ -0,0 +1,547 @@ +package Win32::Registry; + +=head1 NAME + +Win32::Registry - accessing the Windows registry [obsolete, use Win32::TieRegistry] + +=head1 SYNOPSIS + + use Win32::Registry; + my $tips; + $::HKEY_LOCAL_MACHINE->Open("SOFTWARE\\Microsoft\\Windows" + ."\\CurrentVersion\\Explorer\\Tips", $tips) + or die "Can't open tips: $^E"; + my ($type, $value); + $tips->QueryValueEx("18", $type, $value) or die "No tip #18: $^E"; + print "Here's a tip: $value\n"; + +=head1 DESCRIPTION + + NOTE: This module provides a very klunky interface to access the + Windows registry, and is not currently being developed actively. It + only exists for backward compatibility with old code that uses it. + For more powerful and flexible ways to access the registry, use + Win32::TieRegistry. + +Win32::Registry provides an object oriented interface to the Windows +Registry. + +The following "root" registry objects are exported to the main:: name +space. Additional keys must be opened by calling the provided methods +on one of these. + + $HKEY_CLASSES_ROOT + $HKEY_CURRENT_USER + $HKEY_LOCAL_MACHINE + $HKEY_USERS + $HKEY_PERFORMANCE_DATA + $HKEY_CURRENT_CONFIG + $HKEY_DYN_DATA + +=cut + +use strict; +require Exporter; +require DynaLoader; +use Win32::WinError; + +require Win32 unless defined &Win32::GetLastError; + +use vars qw($VERSION $AUTOLOAD @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +$VERSION = '0.07'; + +@ISA = qw( Exporter DynaLoader ); +@EXPORT = qw( + HKEY_CLASSES_ROOT + HKEY_CURRENT_USER + HKEY_LOCAL_MACHINE + HKEY_PERFORMANCE_DATA + HKEY_CURRENT_CONFIG + HKEY_DYN_DATA + HKEY_USERS + KEY_ALL_ACCESS + KEY_CREATE_LINK + KEY_CREATE_SUB_KEY + KEY_ENUMERATE_SUB_KEYS + KEY_EXECUTE + KEY_NOTIFY + KEY_QUERY_VALUE + KEY_READ + KEY_SET_VALUE + KEY_WRITE + REG_BINARY + REG_CREATED_NEW_KEY + REG_DWORD + REG_DWORD_BIG_ENDIAN + REG_DWORD_LITTLE_ENDIAN + REG_EXPAND_SZ + REG_FULL_RESOURCE_DESCRIPTOR + REG_LEGAL_CHANGE_FILTER + REG_LEGAL_OPTION + REG_LINK + REG_MULTI_SZ + REG_NONE + REG_NOTIFY_CHANGE_ATTRIBUTES + REG_NOTIFY_CHANGE_LAST_SET + REG_NOTIFY_CHANGE_NAME + REG_NOTIFY_CHANGE_SECURITY + REG_OPENED_EXISTING_KEY + REG_OPTION_BACKUP_RESTORE + REG_OPTION_CREATE_LINK + REG_OPTION_NON_VOLATILE + REG_OPTION_RESERVED + REG_OPTION_VOLATILE + REG_REFRESH_HIVE + REG_RESOURCE_LIST + REG_RESOURCE_REQUIREMENTS_LIST + REG_SZ + REG_WHOLE_HIVE_VOLATILE +); + +@EXPORT_OK = qw( + RegCloseKey + RegConnectRegistry + RegCreateKey + RegCreateKeyEx + RegDeleteKey + RegDeleteValue + RegEnumKey + RegEnumValue + RegFlushKey + RegGetKeySecurity + RegLoadKey + RegNotifyChangeKeyValue + RegOpenKey + RegOpenKeyEx + RegQueryInfoKey + RegQueryValue + RegQueryValueEx + RegReplaceKey + RegRestoreKey + RegSaveKey + RegSetKeySecurity + RegSetValue + RegSetValueEx + RegUnLoadKey +); +$EXPORT_TAGS{ALL}= \@EXPORT_OK; + +bootstrap Win32::Registry; + +sub import { + my $pkg = shift; + if ($_[0] && "Win32" eq $_[0]) { + Exporter::export($pkg, "Win32", @EXPORT_OK); + shift; + } + Win32::Registry->export_to_level(1+$Exporter::ExportLevel, $pkg, @_); +} + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, 0); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + my ($pack,$file,$line) = caller; + die "Unknown constant $constname in Win32::Registry " + . "at $file line $line.\n"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +####################################################################### +# _new is a private constructor, not intended for public use. +# + +sub _new { + my $self; + if ($_[0]) { + $self->{'handle'} = $_[0]; + bless $self; + } + $self; +} + +#define the basic registry objects to be exported. +#these had to be hardwired unfortunately. +# XXX Yuck! + +{ + package main; + use vars qw( + $HKEY_CLASSES_ROOT + $HKEY_CURRENT_USER + $HKEY_LOCAL_MACHINE + $HKEY_USERS + $HKEY_PERFORMANCE_DATA + $HKEY_CURRENT_CONFIG + $HKEY_DYN_DATA + ); +} + +$::HKEY_CLASSES_ROOT = _new(&HKEY_CLASSES_ROOT); +$::HKEY_CURRENT_USER = _new(&HKEY_CURRENT_USER); +$::HKEY_LOCAL_MACHINE = _new(&HKEY_LOCAL_MACHINE); +$::HKEY_USERS = _new(&HKEY_USERS); +$::HKEY_PERFORMANCE_DATA = _new(&HKEY_PERFORMANCE_DATA); +$::HKEY_CURRENT_CONFIG = _new(&HKEY_CURRENT_CONFIG); +$::HKEY_DYN_DATA = _new(&HKEY_DYN_DATA); + +=head2 Methods + +The following methods are supported. Note that subkeys can be +specified as a path name, separated by backslashes (which may +need to be doubled if you put them in double quotes). + +=over 8 + +=item Open + + $reg_obj->Open($sub_key_name, $sub_reg_obj); + +Opens a subkey of a registry object, returning the new registry object +in $sub_reg_obj. + +=cut + +sub Open { + my $self = shift; + die 'usage: $obj->Open($sub_key_name, $sub_reg_obj)' if @_ != 2; + + my ($subkey) = @_; + my ($result,$subhandle); + + $result = RegOpenKey($self->{'handle'},$subkey,$subhandle); + $_[1] = _new($subhandle); + + return 0 unless $_[1]; + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item Close + + $reg_obj->Close(); + +Closes an open registry key. + +=cut + +sub Close { + my $self = shift; + die 'usage: $obj->Close()' if @_ != 0; + + return unless exists $self->{'handle'}; + my $result = RegCloseKey($self->{'handle'}); + if ($result) { + delete $self->{'handle'}; + } + else { + $! = Win32::GetLastError(); + } + return $result; +} + +sub DESTROY { + my $self = shift; + return unless exists $self->{'handle'}; + RegCloseKey($self->{'handle'}); + delete $self->{'handle'}; +} + + +=item Connect + + $reg_obj->Connect($node_name, $new_reg_obj); + +Connects to a remote Registry on the node specified by $node_name, +returning it in $new_reg_obj. Returns false if it fails. + +=cut + +sub Connect { + my $self = shift; + die 'usage: $obj->Connect($node_name, $new_reg_obj)' if @_ != 2; + + my ($node) = @_; + my ($result,$subhandle); + + $result = RegConnectRegistry ($node, $self->{'handle'}, $subhandle); + $_[1] = _new($subhandle); + + return 0 unless $_[1]; + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item Create + + $reg_obj->Create($sub_key_name, $new_reg_obj); + +Opens the subkey specified by $sub_key_name, returning the new registry +object in $new_reg_obj. If the specified subkey doesn't exist, it is +created. + +=cut + +sub Create { + my $self = shift; + die 'usage: $obj->Create($sub_key_name, $new_reg_obj)' if @_ != 2; + + my ($subkey) = @_; + my ($result,$subhandle); + + $result = RegCreateKey($self->{'handle'},$subkey,$subhandle); + $_[1] = _new ($subhandle); + + return 0 unless $_[1]; + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item SetValue + + $reg_obj->SetValue($sub_key_name, $type, $value); + +Sets the default value for a subkey specified by $sub_key_name. + +=cut + +sub SetValue { + my $self = shift; + die 'usage: $obj->SetValue($subkey, $type, $value)' if @_ != 3; + my $result = RegSetValue($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item SetValueEx + + $reg_obj->SetValueEx($value_name, $reserved, $type, $value); + +Sets the value for the value name identified by $value_name +in the key specified by $reg_obj. + +=cut + +sub SetValueEx { + my $self = shift; + die 'usage: $obj->SetValueEx($value_name, $reserved, $type, $value)' if @_ != 4; + my $result = RegSetValueEx($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item QueryValue + + $reg_obj->QueryValue($sub_key_name, $value); + +Gets the default value of the subkey specified by $sub_key_name. + +=cut + +sub QueryValue { + my $self = shift; + die 'usage: $obj->QueryValue($sub_key_name, $value)' if @_ != 2; + my $result = RegQueryValue($self->{'handle'}, $_[0], $_[1]); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item QueryKey + + $reg_obj->QueryKey($classref, $number_of_subkeys, $number_of_values); + +Gets information on a key specified by $reg_obj. + +=cut + +sub QueryKey { + my $garbage; + my $self = shift; + die 'usage: $obj->QueryKey($classref, $number_of_subkeys, $number_of_values)' + if @_ != 3; + + my $result = RegQueryInfoKey($self->{'handle'}, $_[0], + $garbage, $garbage, $_[1], + $garbage, $garbage, $_[2], + $garbage, $garbage, $garbage, $garbage); + + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item QueryValueEx + + $reg_obj->QueryValueEx($value_name, $type, $value); + +Gets the value for the value name identified by $value_name +in the key specified by $reg_obj. + +=cut + +sub QueryValueEx { + my $self = shift; + die 'usage: $obj->QueryValueEx($value_name, $type, $value)' if @_ != 3; + my $result = RegQueryValueEx($self->{'handle'}, $_[0], undef, $_[1], $_[2]); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item GetKeys + + my @keys; + $reg_obj->GetKeys(\@keys); + +Populates the supplied array reference with the names of all the keys +within the registry object $reg_obj. + +=cut + +sub GetKeys { + my $self = shift; + die 'usage: $obj->GetKeys($arrayref)' if @_ != 1 or ref($_[0]) ne 'ARRAY'; + + my ($result, $i, $keyname); + $keyname = "DummyVal"; + $i = 0; + $result = 1; + + while ( $result ) { + $result = RegEnumKey( $self->{'handle'},$i++, $keyname ); + if ($result) { + push( @{$_[0]}, $keyname ); + } + } + return(1); +} + +=item GetValues + + my %values; + $reg_obj->GetValues(\%values); + +Populates the supplied hash reference with entries of the form + + $value_name => [ $value_name, $type, $data ] + +for each value in the registry object $reg_obj. + +=cut + +sub GetValues { + my $self = shift; + die 'usage: $obj->GetValues($hashref)' if @_ != 1; + + my ($result,$name,$type,$data,$i); + $name = "DummyVal"; + $i = 0; + while ( $result=RegEnumValue( $self->{'handle'}, + $i++, + $name, + undef, + $type, + $data )) + { + $_[0]->{$name} = [ $name, $type, $data ]; + } + return(1); +} + +=item DeleteKey + + $reg_obj->DeleteKey($sub_key_name); + +Deletes a subkey specified by $sub_key_name from the registry. + +=cut + +sub DeleteKey { + my $self = shift; + die 'usage: $obj->DeleteKey($sub_key_name)' if @_ != 1; + my $result = RegDeleteKey($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item DeleteValue + + $reg_obj->DeleteValue($value_name); + +Deletes a value identified by $value_name from the registry. + +=cut + +sub DeleteValue { + my $self = shift; + die 'usage: $obj->DeleteValue($value_name)' if @_ != 1; + my $result = RegDeleteValue($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item Save + + $reg_obj->Save($filename); + +Saves the hive specified by $reg_obj to a file. + +=cut + +sub Save { + my $self = shift; + die 'usage: $obj->Save($filename)' if @_ != 1; + my $result = RegSaveKey($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item Load + + $reg_obj->Load($sub_key_name, $file_name); + +Loads a key specified by $sub_key_name from a file. + +=cut + +sub Load { + my $self = shift; + die 'usage: $obj->Load($sub_key_name, $file_name)' if @_ != 2; + my $result = RegLoadKey($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +=item UnLoad + + $reg_obj->Unload($sub_key_name); + +Unloads a registry hive. + +=cut + +sub UnLoad { + my $self = shift; + die 'usage: $obj->UnLoad($sub_key_name)' if @_ != 1; + my $result = RegUnLoadKey($self->{'handle'}, @_); + $! = Win32::GetLastError() unless $result; + return $result; +} + +1; +__END__ diff --git a/Master/tlpkg/tlperl/lib/Win32/Semaphore.pm b/Master/tlpkg/tlperl/lib/Win32/Semaphore.pm new file mode 100644 index 00000000000..2e2096eb6ed --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Semaphore.pm @@ -0,0 +1,128 @@ +#--------------------------------------------------------------------- +package Win32::Semaphore; +# +# Copyright 1998 Christopher J. Madsen +# +# Created: 3 Feb 1998 from the ActiveWare version +# (c) 1995 Microsoft Corporation. All rights reserved. +# Developed by ActiveWare Internet Corp., http://www.ActiveWare.com +# +# Other modifications (c) 1997 by Gurusamy Sarathy <gsar@activestate.com> +# +# Author: Christopher J. Madsen <cjm@pobox.com> +# Version: 1.00 (6-Feb-1998) +# +# This program is free software; you can redistribute it and/or modify +# it under the same terms as Perl itself. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the +# GNU General Public License or the Artistic License for more details. +# +# Use Win32 semaphore objects for synchronization +#--------------------------------------------------------------------- + +$VERSION = '1.02'; + +use Win32::IPC 1.00 '/./'; # Import everything +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader Win32::IPC); +@EXPORT_OK = qw( + wait_all wait_any +); + +bootstrap Win32::Semaphore; + +sub Create { $_[0] = new('Win32::Semaphore',@_[1..3]) } +sub Open { $_[0] = Win32::Semaphore->open($_[1]) } +sub Release { &release } + +1; +__END__ + +=head1 NAME + +Win32::Semaphore - Use Win32 semaphore objects from Perl + +=head1 SYNOPSIS + require Win32::Semaphore; + + $sem = Win32::Semaphore->new($initial,$maximum,$name); + $sem->wait; + +=head1 DESCRIPTION + +This module allows access to Win32 semaphore objects. The C<wait> +method and C<wait_all> & C<wait_any> functions are inherited from the +L<"Win32::IPC"> module. + +=head2 Methods + +=over 4 + +=item $semaphore = Win32::Semaphore->new($initial, $maximum, [$name]) + +Constructor for a new semaphore object. C<$initial> is the initial +count, and C<$maximum> is the maximum count for the semaphore. If +C<$name> is omitted, creates an unnamed semaphore object. + +If C<$name> signifies an existing semaphore object, then C<$initial> +and C<$maximum> are ignored and the object is opened. If this +happens, C<$^E> will be set to 183 (ERROR_ALREADY_EXISTS). + +=item $semaphore = Win32::Semaphore->open($name) + +Constructor for opening an existing semaphore object. + +=item $semaphore->release([$increment, [$previous]]) + +Increment the count of C<$semaphore> by C<$increment> (default 1). +If C<$increment> plus the semaphore's current count is more than its +maximum count, the count is not changed. Returns true if the +increment is successful. + +The semaphore's count (before incrementing) is stored in the second +argument (if any). + +It is not necessary to wait on a semaphore before calling C<release>, +but you'd better know what you're doing. + +=item $semaphore->wait([$timeout]) + +Wait for C<$semaphore>'s count to be nonzero, then decrement it by 1. +See L<"Win32::IPC">. + +=back + +=head2 Deprecated Functions and Methods + +B<Win32::Semaphore> still supports the ActiveWare syntax, but its use +is deprecated. + +=over 4 + +=item Win32::Semaphore::Create($SemObject,$Initial,$Max,$Name) + +Use C<$SemObject = Win32::Semaphore-E<gt>new($Initial,$Max,$Name)> instead. + +=item Win32::Semaphore::Open($SemObject, $Name) + +Use C<$SemObject = Win32::Semaphore-E<gt>open($Name)> instead. + +=item $SemObj->Release($Count,$LastVal) + +Use C<$SemObj-E<gt>release($Count,$LastVal)> instead. + +=back + +=head1 AUTHOR + +Christopher J. Madsen E<lt>F<cjm@pobox.com>E<gt> + +Loosely based on the original module by ActiveWare Internet Corp., +F<http://www.ActiveWare.com> + +=cut diff --git a/Master/tlpkg/tlperl/lib/Win32/Server.pl b/Master/tlpkg/tlperl/lib/Win32/Server.pl new file mode 100644 index 00000000000..ecfb91ba864 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Server.pl @@ -0,0 +1,48 @@ +use strict; +use Win32::Pipe; + +my $PipeName = "TEST this long named pipe!"; +my $NewSize = 2048; +my $iMessage; + +while () { + print "Creating pipe \"$PipeName\".\n"; + if (my $Pipe = new Win32::Pipe($PipeName)) { + my $PipeSize = $Pipe->BufferSize(); + print "This pipe's current size is $PipeSize byte" . (($PipeSize == 1)? "":"s") . ".\nWe shall change it to $NewSize ..."; + print +(($Pipe->ResizeBuffer($NewSize) == $NewSize)? "Successful":"Unsucessful") . "!\n\n"; + + print "\n\nR e a d y f o r r e a d i n g :\n"; + print "-----------------------------------\n"; + + print "Openning the pipe...\n"; + while ($Pipe->Connect()) { + while () { + ++$iMessage; + print "Reading Message #$iMessage: "; + my $In = $Pipe->Read(); + unless ($In) { + print "Recieved no data, closing connection....\n"; + last; + } + if ($In =~ /^quit/i){ + print "\n\nQuitting this connection....\n"; + last; + } + elsif ($In =~ /^exit/i){ + print "\n\nExitting.....\n"; + exit; + } + else{ + print "\"$In\"\n"; + } + } + print "Disconnecting...\n"; + $Pipe->Disconnect(); + } + print "Closing...\n"; + $Pipe->Close(); + } +} + +print "You can't get here...\n"; diff --git a/Master/tlpkg/tlperl/lib/Win32/Service.pm b/Master/tlpkg/tlperl/lib/Win32/Service.pm new file mode 100644 index 00000000000..0ae33b13ef8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Service.pm @@ -0,0 +1,103 @@ +package Win32::Service; + +# +# Service.pm +# Written by Douglas_Lankshear@ActiveWare.com +# +# subsequently hacked by Gurusamy Sarathy <gsar@activestate.com> +# + +$VERSION = '0.05'; + +require Exporter; +require DynaLoader; + +require Win32 unless defined &Win32::IsWinNT; +die "The Win32::Service module works only on Windows NT" unless Win32::IsWinNT(); + +@ISA= qw( Exporter DynaLoader ); +@EXPORT_OK = + qw( + StartService + StopService + GetStatus + PauseService + ResumeService + GetServices + ); + +=head1 NAME + +Win32::Service - manage system services in perl + +=head1 SYNOPSIS + + use Win32::Service; + +=head1 DESCRIPTION + +This module offers control over the administration of system services. + +=head1 FUNCTIONS + +=head2 NOTE: + +All of the functions return false if they fail, unless otherwise noted. +If hostName is an empty string, the local machine is assumed. + +=over 10 + +=item StartService(hostName, serviceName) + +Start the service serviceName on machine hostName. + +=item StopService(hostName, serviceName) + +Stop the service serviceName on the machine hostName. + +=item GetStatus(hostName, serviceName, status) + +Get the status of a service. The third argument must be a hash +reference that will be populated with entries corresponding +to the SERVICE_STATUS structure of the Win32 API. See the +Win32 Platform SDK documentation for details of this structure. + +=item PauseService(hostName, serviceName) + +=item ResumeService(hostName, serviceName) + +=item GetServices(hostName, hashref) + +Enumerates both active and inactive Win32 services at the specified host. +The hashref is populated with the descriptive service names as keys +and the short names as the values. + +=back + +=cut + +sub AUTOLOAD +{ + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname); + if ($! != 0) { + if($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::Service macro $constname, used in $file at line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::Service; + +1; +__END__ diff --git a/Master/tlpkg/tlperl/lib/Win32/Shortcut.pm b/Master/tlpkg/tlperl/lib/Win32/Shortcut.pm new file mode 100644 index 00000000000..d4dadafdcf2 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Shortcut.pm @@ -0,0 +1,323 @@ +package Win32::Shortcut; +####################################################################### +# +# Win32::Shortcut - Perl Module for Shell Link Interface +# ^^^^^^^^^^^^^^^ +# This module creates an object oriented interface to the Win32 +# Shell Links (IShellLink interface). +# +####################################################################### + +$VERSION = "0.04"; + +require Exporter; +require DynaLoader; + +@ISA= qw( Exporter DynaLoader ); +@EXPORT = qw( + SW_SHOWMAXIMIZED + SW_SHOWMINNOACTIVE + SW_SHOWNORMAL +); + + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. +# + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $!; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($!) { + my(undef, $file, $line) = caller; + die "Win32::Shortcut::$constname is not defined, used at $file line $line."; + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +####################################################################### +# PUBLIC METHODS +# + +#======== +sub new { +#======== + my($class, $file) = @_; + my $self = {}; + my $ilink = 0; + my $ifile = 0; + + ($ilink, $ifile) = _Instance(); + + if($ilink and $ifile) { + $self->{'ilink'} = $ilink; + $self->{'ifile'} = $ifile; + bless $self; + # Initialize properties + $self->{'File'} = ""; + $self->{'Path'} = ""; + $self->{'Arguments'} = ""; + $self->{'WorkingDirectory'} = ""; + $self->{'Description'} = ""; + $self->{'ShowCmd'} = 0; + $self->{'Hotkey'} = 0; + $self->{'IconLocation'} = ""; + $self->{'IconNumber'} = 0; + + $self->Load($file) if $file; + + } else { + return undef; + } + $self; +} + +#========= +sub Load { +#========= + my($self, $file) = @_; + return undef unless ref($self); + + my $result = _Load($self->{'ilink'}, $self->{'ifile'}, $file); + + if ($result) { + + # fill the properties of $self + $self->{'File'} = $file; + $self->{'Path'} = _GetPath($self->{'ilink'}, $self->{'ifile'},0); + $self->{'ShortPath'} = _GetPath($self->{'ilink'}, $self->{'ifile'},1); + $self->{'Arguments'} = _GetArguments($self->{'ilink'}, $self->{'ifile'}); + $self->{'WorkingDirectory'} = _GetWorkingDirectory($self->{'ilink'}, $self->{'ifile'}); + $self->{'Description'} = _GetDescription($self->{'ilink'}, $self->{'ifile'}); + $self->{'ShowCmd'} = _GetShowCmd($self->{'ilink'}, $self->{'ifile'}); + $self->{'Hotkey'} = _GetHotkey($self->{'ilink'}, $self->{'ifile'}); + ($self->{'IconLocation'}, + $self->{'IconNumber'}) = _GetIconLocation($self->{'ilink'}, $self->{'ifile'}); + } + return $result; +} + + +#======== +sub Set { +#======== + my($self, $path, $arguments, $dir, $description, $show, $hotkey, + $iconlocation, $iconnumber) = @_; + return undef unless ref($self); + + $self->{'Path'} = $path; + $self->{'Arguments'} = $arguments; + $self->{'WorkingDirectory'} = $dir; + $self->{'Description'} = $description; + $self->{'ShowCmd'} = $show; + $self->{'Hotkey'} = $hotkey; + $self->{'IconLocation'} = $iconlocation; + $self->{'IconNumber'} = $iconnumber; + return 1; +} + + +#========= +sub Save { +#========= + my($self, $file) = @_; + return unless ref($self); + + $file = $self->{'File'} unless $file; + return unless $file; + + require Win32 unless defined &Win32::GetFullPathName; + $file = Win32::GetFullPathName($file); + + _SetPath($self->{'ilink'}, $self->{'ifile'}, $self->{'Path'}); + _SetArguments($self->{'ilink'}, $self->{'ifile'}, $self->{'Arguments'}); + _SetWorkingDirectory($self->{'ilink'}, $self->{'ifile'}, $self->{'WorkingDirectory'}); + _SetDescription($self->{'ilink'}, $self->{'ifile'}, $self->{'Description'}); + _SetShowCmd($self->{'ilink'}, $self->{'ifile'}, $self->{'ShowCmd'}); + _SetHotkey($self->{'ilink'}, $self->{'ifile'}, $self->{'Hotkey'}); + _SetIconLocation($self->{'ilink'}, $self->{'ifile'}, + $self->{'IconLocation'}, $self->{'IconNumber'}); + + my $result = _Save($self->{'ilink'}, $self->{'ifile'}, $file); + if ($result) { + $self->{'File'} = $file unless $self->{'File'}; + } + return $result; +} + +#============ +sub Resolve { +#============ + my($self, $flags) = @_; + return undef unless ref($self); + $flags = 1 unless defined($flags); + my $result = _Resolve($self->{'ilink'}, $self->{'ifile'}, $flags); + return $result; +} + + +#========== +sub Close { +#========== + my($self) = @_; + return undef unless ref($self); + + my $result = _Release($self->{'ilink'}, $self->{'ifile'}); + $self->{'released'} = 1; + return $result; +} + +#========= +sub Path { +#========= + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'Path'}; + } else { + $self->{'Path'} = $value; + } + return $self->{'Path'}; +} + +#============== +sub ShortPath { +#============== + my($self) = @_; + return undef unless ref($self); + return $self->{'ShortPath'}; +} + +#============== +sub Arguments { +#============== + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'Arguments'}; + } else { + $self->{'Arguments'} = $value; + } + return $self->{'Arguments'}; +} + +#===================== +sub WorkingDirectory { +#===================== + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'WorkingDirectory'}; + } else { + $self->{'WorkingDirectory'} = $value; + } + return $self->{'WorkingDirectory'}; +} + + +#================ +sub Description { +#================ + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'Description'}; + } else { + $self->{'Description'} = $value; + } + return $self->{'Description'}; +} + +#============ +sub ShowCmd { +#============ + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'ShowCmd'}; + } else { + $self->{'ShowCmd'} = $value; + } + return $self->{'ShowCmd'}; +} + +#=========== +sub Hotkey { +#=========== + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'Hotkey'}; + } else { + $self->{'Hotkey'} = $value; + } + return $self->{'Hotkey'}; +} + +#================= +sub IconLocation { +#================= + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'IconLocation'}; + } else { + $self->{'IconLocation'} = $value; + } + return $self->{'IconLocation'}; +} + +#=============== +sub IconNumber { +#=============== + my($self, $value) = @_; + return undef unless ref($self); + + if(not defined($value)) { + return $self->{'IconNumber'}; + } else { + $self->{'IconNumber'} = $value; + } + return $self->{'IconNumber'}; +} + +#============ +sub Version { +#============ + # [dada] to get rid of the "used only once" warning... + return $VERSION; +} + + +####################################################################### +# PRIVATE METHODS +# + +#============ +sub DESTROY { +#============ + my($self) = @_; + + if (not $self->{'released'}) { + _Release($self->{'ilink'}, $self->{'ifile'}); + $self->{'released'} = 1; + } +} + +bootstrap Win32::Shortcut; + +1; diff --git a/Master/tlpkg/tlperl/lib/Win32/Sound.pm b/Master/tlpkg/tlperl/lib/Win32/Sound.pm new file mode 100644 index 00000000000..a8d52a95117 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Sound.pm @@ -0,0 +1,582 @@ +####################################################################### +# +# Win32::Sound - An extension to play with Windows sounds +# +# Author: Aldo Calpini <dada@divinf.it> +# Version: 0.47 +# Info: +# http://www.divinf.it/dada/perl +# http://www.perl.com/CPAN/authors/Aldo_Calpini +# +####################################################################### +# Version history: +# 0.01 (19 Nov 1996) file created +# 0.03 (08 Apr 1997) first release +# 0.30 (20 Oct 1998) added Volume/Format/Devices/DeviceInfo +# (thanks Dave Roth!) +# 0.40 (16 Mar 1999) added the WaveOut object +# 0.45 (09 Apr 1999) added $! support, documentation et goodies +# 0.46 (25 Sep 1999) fixed small bug in DESTROY, wo was used without being +# initialized (Gurusamy Sarathy <gsar@activestate.com>) +# 0.47 (22 May 2000) support for passing Unicode string to Play() +# (Doug Lankshear <dougl@activestate.com>) + +package Win32::Sound; + +# See the bottom of this file for the POD documentation. +# Search for the string '=head'. + +require Exporter; # to export the constants to the main:: space +require DynaLoader; # to dynuhlode the module. + +@ISA= qw( Exporter DynaLoader ); +@EXPORT = qw( + SND_ASYNC + SND_NODEFAULT + SND_LOOP + SND_NOSTOP +); + +####################################################################### +# This AUTOLOAD is used to 'autoload' constants from the constant() +# XS function. If a constant is not found then control is passed +# to the AUTOLOAD in AutoLoader. +# + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + + # [dada] This results in an ugly Autoloader error + + #if ($! =~ /Invalid/) { + # $AutoLoader::AUTOLOAD = $AUTOLOAD; + # goto &AutoLoader::AUTOLOAD; + #} else { + + # [dada] ... I prefer this one :) + + ($pack, $file, $line) = caller; + undef $pack; # [dada] and get rid of "used only once" warning... + die "Win32::Sound::$constname is not defined, used at $file line $line."; + + #} + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +####################################################################### +# STATIC OBJECT PROPERTIES +# +$VERSION="0.47"; +undef unless $VERSION; # [dada] to avoid "possible typo" warning + +####################################################################### +# METHODS +# + +sub Version { $VERSION } + +sub Volume { + my(@in) = @_; + # Allows '0%'..'100%' + $in[0] =~ s{ ([\d\.]+)%$ }{ int($1*100/255) }ex if defined $in[0]; + $in[1] =~ s{ ([\d\.]+)%$ }{ int($1*100/255) }ex if defined $in[1]; + _Volume(@in); +} + +####################################################################### +# dynamically load in the Sound.dll module. +# + +bootstrap Win32::Sound; + +####################################################################### +# Win32::Sound::WaveOut +# + +package Win32::Sound::WaveOut; + +sub new { + my($class, $one, $two, $three) = @_; + my $self = {}; + bless($self, $class); + + if($one !~ /^\d+$/ + and not defined($two) + and not defined($three)) { + # Looks like a file + $self->Open($one); + } else { + # Default format if not given + $self->{samplerate} = ($one or 44100); + $self->{bits} = ($two or 16); + $self->{channels} = ($three or 2); + $self->OpenDevice(); + } + return $self; +} + +sub Volume { + my(@in) = @_; + # Allows '0%'..'100%' + $in[0] =~ s{ ([\d\.]+)%$ }{ int($1*255/100) }ex if defined $in[0]; + $in[1] =~ s{ ([\d\.]+)%$ }{ int($1*255/100) }ex if defined $in[1]; + _Volume(@in); +} + +sub Pitch { + my($self, $pitch) = @_; + my($int, $frac); + if(defined($pitch)) { + $pitch =~ /(\d+).?(\d+)?/; + $int = $1; + $frac = $2 or 0; + $int = $int << 16; + $frac = eval("0.$frac * 65536"); + $pitch = $int + $frac; + return _Pitch($self, $pitch); + } else { + $pitch = _Pitch($self); + $int = ($pitch & 0xFFFF0000) >> 16; + $frac = $pitch & 0x0000FFFF; + return eval("$int.$frac"); + } +} + +sub PlaybackRate { + my($self, $rate) = @_; + my($int, $frac); + if(defined($rate)) { + $rate =~ /(\d+).?(\d+)?/; + $int = $1; + $frac = $2 or 0; + $int = $int << 16; + $frac = eval("0.$frac * 65536"); + $rate = $int + $frac; + return _PlaybackRate($self, $rate); + } else { + $rate = _PlaybackRate($self); + $int = ($rate & 0xFFFF0000) >> 16; + $frac = $rate & 0x0000FFFF; + return eval("$int.$frac"); + } +} + +# Preloaded methods go here. + +#Currently Autoloading is not implemented in Perl for win32 +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; +__END__ + + +=head1 NAME + +Win32::Sound - An extension to play with Windows sounds + +=head1 SYNOPSIS + + use Win32::Sound; + Win32::Sound::Volume('100%'); + Win32::Sound::Play("file.wav"); + Win32::Sound::Stop(); + + # ...and read on for more fun ;-) + +=head1 FUNCTIONS + +=over 4 + +=item B<Win32::Sound::Play(SOUND, [FLAGS])> + +Plays the specified sound: SOUND can the be name of a WAV file +or one of the following predefined sound names: + + SystemDefault + SystemAsterisk + SystemExclamation + SystemExit + SystemHand + SystemQuestion + SystemStart + +Additionally, if the named sound could not be found, the +function plays the system default sound (unless you specify the +C<SND_NODEFAULT> flag). If no parameters are given, this function +stops the sound actually playing (see also Win32::Sound::Stop). + +FLAGS can be a combination of the following constants: + +=over 4 + +=item C<SND_ASYNC> + +The sound is played asynchronously and the function +returns immediately after beginning the sound +(if this flag is not specified, the sound is +played synchronously and the function returns +when the sound ends). + +=item C<SND_LOOP> + +The sound plays repeatedly until it is stopped. +You must also specify C<SND_ASYNC> flag. + +=item C<SND_NODEFAULT> + +No default sound is used. If the specified I<sound> +cannot be found, the function returns without +playing anything. + +=item C<SND_NOSTOP> + +If a sound is already playing, the function fails. +By default, any new call to the function will stop +previously playing sounds. + +=back + +=item B<Win32::Sound::Stop()> + +Stops the sound currently playing. + +=item B<Win32::Sound::Volume()> + +Returns the wave device volume; if +called in an array context, returns left +and right values. Otherwise, returns a single +32 bit value (left in the low word, right +in the high word). +In case of error, returns C<undef> and sets +$!. + +Examples: + + ($L, $R) = Win32::Sound::Volume(); + if( not defined Win32::Sound::Volume() ) { + die "Can't get volume: $!"; + } + +=item B<Win32::Sound::Volume(LEFT, [RIGHT])> + +Sets the wave device volume; if two arguments +are given, sets left and right channels +independently, otherwise sets them both to +LEFT (eg. RIGHT=LEFT). Values range from +0 to 65535 (0xFFFF), but they can also be +given as percentage (use a string containing +a number followed by a percent sign). + +Returns C<undef> and sets $! in case of error, +a true value if successful. + +Examples: + + Win32::Sound::Volume('50%'); + Win32::Sound::Volume(0xFFFF, 0x7FFF); + Win32::Sound::Volume('100%', '50%'); + Win32::Sound::Volume(0); + +=item B<Win32::Sound::Format(filename)> + +Returns information about the specified WAV file format; +the array contains: + +=over + +=item * sample rate (in Hz) + +=item * bits per sample (8 or 16) + +=item * channels (1 for mono, 2 for stereo) + +=back + +Example: + + ($hz, $bits, $channels) + = Win32::Sound::Format("file.wav"); + + +=item B<Win32::Sound::Devices()> + +Returns all the available sound devices; +their names contain the type of the +device (WAVEOUT, WAVEIN, MIDIOUT, +MIDIIN, AUX or MIXER) and +a zero-based ID number: valid devices +names are for example: + + WAVEOUT0 + WAVEOUT1 + WAVEIN0 + MIDIOUT0 + MIDIIN0 + AUX0 + AUX1 + AUX2 + +There are also two special device +names, C<WAVE_MAPPER> and C<MIDI_MAPPER> +(the default devices for wave output +and midi output). + +Example: + + @devices = Win32::Sound::Devices(); + +=item Win32::Sound::DeviceInfo(DEVICE) + +Returns an associative array of information +about the sound device named DEVICE (the +same format of Win32::Sound::Devices). + +The content of the array depends on the device +type queried. Each device type returns B<at least> +the following information: + + manufacturer_id + product_id + name + driver_version + +For additional data refer to the following +table: + + WAVEIN..... formats + channels + + WAVEOUT.... formats + channels + support + + MIDIOUT.... technology + voices + notes + channels + support + + AUX........ technology + support + + MIXER...... destinations + support + +The meaning of the fields, where not +obvious, can be evinced from the +Microsoft SDK documentation (too long +to report here, maybe one day... :-). + +Example: + + %info = Win32::Sound::DeviceInfo('WAVE_MAPPER'); + print "$info{name} version $info{driver_version}\n"; + +=back + +=head1 THE WaveOut PACKAGE + +Win32::Sound also provides a different, more +powerful approach to wave audio data with its +C<WaveOut> package. It has methods to load and +then play WAV files, with the additional feature +of specifying the start and end range, so you +can play only a portion of an audio file. + +Furthermore, it is possible to load arbitrary +binary data to the soundcard to let it play and +save them back into WAV files; in a few words, +you can do some sound synthesis work. + +=head2 FUNCTIONS + +=over + +=item new Win32::Sound::WaveOut(FILENAME) + +=item new Win32::Sound::WaveOut(SAMPLERATE, BITS, CHANNELS) + +=item new Win32::Sound::WaveOut() + +This function creates a C<WaveOut> object; the +first form opens the specified wave file (see +also C<Open()> ), so you can directly C<Play()> it. + +The second (and third) form opens the +wave output device with the format given +(or if none given, defaults to 44.1kHz, +16 bits, stereo); to produce something +audible you can either C<Open()> a wave file +or C<Load()> binary data to the soundcard +and then C<Write()> it. + +=item Close() + +Closes the wave file currently opened. + +=item CloseDevice() + +Closes the wave output device; you can change +format and reopen it with C<OpenDevice()>. + +=item GetErrorText(ERROR) + +Returns the error text associated with +the specified ERROR number; note it only +works for wave-output-specific errors. + +=item Load(DATA) + +Loads the DATA buffer in the soundcard. +The format of the data buffer depends +on the format used; for example, with +8 bit mono each sample is one character, +while with 16 bit stereo each sample is +four characters long (two 16 bit values +for left and right channels). The sample +rate defines how much samples are in one +second of sound. For example, to fit one +second at 44.1kHz 16 bit stereo your buffer +must contain 176400 bytes (44100 * 4). + +=item Open(FILE) + +Opens the specified wave FILE. + +=item OpenDevice() + +Opens the wave output device with the +current sound format (not needed unless +you used C<CloseDevice()>). + +=item Pause() + +Pauses the sound currently playing; +use C<Restart()> to continue playing. + +=item Play( [FROM, TO] ) + +Plays the opened wave file. You can optionally +specify a FROM - TO range, where FROM and TO +are expressed in samples (or use FROM=0 for the +first sample and TO=-1 for the last sample). +Playback happens always asynchronously, eg. in +the background. + +=item Position() + +Returns the sample number currently playing; +note that the play position is not zeroed +when the sound ends, so you have to call a +C<Reset()> between plays to receive the +correct position in the current sound. + +=item Reset() + +Stops playing and resets the play position +(see C<Position()>). + +=item Restart() + +Continues playing the sound paused by C<Pause()>. + +=item Save(FILE, [DATA]) + +Writes the DATA buffer (if not given, uses the +buffer currently loaded in the soundcard) +to the specified wave FILE. + +=item Status() + +Returns 0 if the soundcard is currently playing, +1 if it's free, or C<undef> on errors. + +=item Unload() + +Frees the soundcard from the loaded data. + +=item Volume( [LEFT, RIGHT] ) + +Gets or sets the volume for the wave output device. +It works the same way as Win32::Sound::Volume. + +=item Write() + +Plays the data currently loaded in the soundcard; +playback happens always asynchronously, eg. in +the background. + +=back + +=head2 THE SOUND FORMAT + +The sound format is stored in three properties of +the C<WaveOut> object: C<samplerate>, C<bits> and +C<channels>. +If you need to change them without creating a +new object, you should close before and reopen +afterwards the device. + + $WAV->CloseDevice(); + $WAV->{samplerate} = 44100; # 44.1kHz + $WAV->{bits} = 8; # 8 bit + $WAV->{channels} = 1; # mono + $WAV->OpenDevice(); + +You can also use the properties to query the +sound format currently used. + +=head2 EXAMPLE + +This small example produces a 1 second sinusoidal +wave at 440Hz and saves it in F<sinus.wav>: + + use Win32::Sound; + + # Create the object + $WAV = new Win32::Sound::WaveOut(44100, 8, 2); + + $data = ""; + $counter = 0; + $increment = 440/44100; + + # Generate 44100 samples ( = 1 second) + for $i (1..44100) { + + # Calculate the pitch + # (range 0..255 for 8 bits) + $v = sin($counter/2*3.14) * 128 + 128; + + # "pack" it twice for left and right + $data .= pack("cc", $v, $v); + + $counter += $increment; + } + + $WAV->Load($data); # get it + $WAV->Write(); # hear it + 1 until $WAV->Status(); # wait for completion + $WAV->Save("sinus.wav"); # write to disk + $WAV->Unload(); # drop it + +=head1 VERSION + +Win32::Sound version 0.46, 25 Sep 1999. + +=head1 AUTHOR + +Aldo Calpini, C<dada@divinf.it> + +Parts of the code provided and/or suggested by Dave Roth. + +=cut + + diff --git a/Master/tlpkg/tlperl/lib/Win32/Test.pl b/Master/tlpkg/tlperl/lib/Win32/Test.pl new file mode 100644 index 00000000000..235e94bdd78 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/Test.pl @@ -0,0 +1,477 @@ +##### +# T E S T . P L +# ------------- +# A test script for exercising the Win32::ODBC extension. Install +# the ODBC.PLL extension and the ODBC.PM wrapper, set up an ODBC +# DSN (Data Source Name) by the ODBC administrator, then give this a try! +# +# READ THE DOCUMENTATION -- I AM NOT RESPOSIBLE FOR ANY PROBLEMS THAT +# THIS MAY CAUSE WHATSOEVER. BY USING THIS OR ANY --- +# OF THE WIN32::ODBC PARTS FOUND IN THE DISTRIBUTION YOU ARE AGREEING +# WITH THE TERMS OF THIS DISTRIBUTION!!!!! +# +# +# You have been warned. +# --- ---- ---- ------ +# +# Updated to test newest version v961007. Dave Roth <rothd@roth.net> +# This version contains a small sample database (in MS Access 7.0 +# format) called ODBCTest.mdb. Place this database in the same +# directory as this test.pl file. +# +# -------------------------------------------------------------------- +# +# SYNTAX: +# perl test.pl ["DSN Name" [Max Rows]] +# +# DSN Name....Name of DSN that will be used. If this is +# omitted then we will use the obnoxious default DSN. +# Max Rows....Maximum number of rows wanted to be retrieved from +# the DSN. +# - If this is 0 then the request is to retrieve as +# many as possible. +# - If this is a value greater than that which the DSN +# driver can handle the value will be the greatest +# the DSN driver allows. +# - If omitted then we use the default value. +##### + + use Win32::ODBC; + + + $TempDSN = "Win32 ODBC Test --123xxYYzz987--"; + $iTempDSN = 1; + + if (!($DSN = $ARGV[0])){ + $DSN = $TempDSN; + } + $MaxRows = 8 unless defined ($MaxRows = $ARGV[1]); + + $DriverType = "Microsoft Access Driver (*.mdb)"; + $Desc = "Description=The Win32::ODBC Test DSN for Perl"; + $Dir = Win32::GetCwd(); + $DBase = "ODBCTest.mdb"; + + $iWidth=60; + %SQLStmtTypes = (SQL_CLOSE, "SQL_CLOSE", SQL_DROP, "SQL_DROP", SQL_UNBIND, "SQL_UNBIND", SQL_RESET_PARAMS, "SQL_RESET_PARAMS"); + +# Initialize(); + + ($Name, $Version, $Date, $Author, $CompileDate, $CompileTime, $Credits) = Win32::ODBC::Info(); + print "\n"; + print "\t+", "=" x ($iWidth), "+\n"; + print "\t|", Center("", $iWidth), "|\n"; + print "\t|", Center("", $iWidth), "|\n"; + print "\t|", Center("$Name", $iWidth), "|\n"; + print "\t|", Center("-" x length("$Name"), $iWidth), "|\n"; + print "\t|", Center("", $iWidth), "|\n"; + + print "\t|", Center("Version $Version ($Date)", $iWidth), "|\n"; + print "\t|", Center("by $Author", $iWidth), "|\n"; + print "\t|", Center("Compiled on $CompileDate at $CompileTime.", $iWidth), "|\n"; + print "\t|", Center("", $iWidth), "|\n"; + print "\t|", Center("Credits:", $iWidth), "|\n"; + print "\t|", Center(("-" x length("Credits:")), $iWidth), "|\n"; + foreach $Temp (split("\n", $Credits)){ + print "\t|", Center("$Temp", $iWidth), "|\n"; + } + print "\t|", Center("", $iWidth), "|\n"; + print "\t+", "=" x ($iWidth), "+\n"; + +#### +# T E S T 1 +#### + PrintTest(1, "Dump available ODBC Drivers"); + print "\nAvailable ODBC Drivers:\n"; + if (!(%Drivers = Win32::ODBC::Drivers())){ + $Failed{'Test 1'} = "Drivers(): " . Win32::ODBC::Error(); + } + foreach $Driver (keys(%Drivers)){ + print " Driver=\"$Driver\"\n Attributes: ", join("\n" . " "x14, sort(split(';', $Drivers{$Driver}))), "\n\n"; + } + + +#### +# T E S T 2 +#### + PrintTest(2,"Dump available datasources"); + + #### + # Notice you don't need an instantiated object to use this... + #### + print "\nHere are the available datasources...\n"; + if (!(%DSNs = Win32::ODBC::DataSources())){ + $Failed{'Test 2'} = "DataSources(): " . Win32::ODBC::Error(); + } + foreach $Temp (keys(%DSNs)){ + if (($Temp eq $TempDSN) && ($DSNs{$Temp} eq $DriverType)){ + $iTempDSNExists++; + } + if ($DSN =~ /$Temp/i){ + $iTempDSN = 0; + $DriverType = $DSNs{$Temp}; + } + print "\tDSN=\"$Temp\" (\"$DSNs{$Temp}\")\n"; + } + +#### +# T E S T 2.5 +#### + # IF WE DO NOT find the DSN the user specified... + if ($iTempDSN){ + PrintTest("2.5", "Create a Temporary DSN"); + + print "\n\tCould not find the DSN (\"$DSN\") so we will\n\tuse a temporary one (\"$TempDSN\")...\n\n"; + + $DSN = $TempDSN; + + if (! $iTempDSNExists){ + print "\tAdding DSN \"$DSN\"..."; + if (Win32::ODBC::ConfigDSN(ODBC_ADD_DSN, $DriverType, ("DSN=$DSN", "Description=The Win32 ODBC Test DSN for Perl", "DBQ=$Dir\\$DBase", "DEFAULTDIR=$Dir", "UID=", "PWD="))){ + print "Successful!\n"; + }else{ + print "Failure\n"; + $Failed{'Test 2.5'} = "ConfigDSN(): Could not add \"$DSN\": " . Win32::ODBC::Error(); + # If we failed here then use the last DSN we listed in Test 2 + $DriverType = $DSNs{$Temp}; + $DSN = $Temp; + print "\n\tCould not add a temporary DSN so using the last one listed:\n"; + print "\t\t$DSN ($DriverType)\n"; + + } + } + } + +#### +# Report What Driver/DSN we are using +#### + + print "\n\nWe are using the DSN:\n\tDSN = \"$DSN\"\n"; + print "\tDriver = \"$DriverType\"\n\n"; + + +#### +# T E S T 3 +#### + PrintTest(3, "Open several ODBC connections"); + print "\n\tOpening ODBC connection for \"$DSN\"...\n\t\t"; + if (!($O = new Win32::ODBC($DSN))){ + print "Failure. \n\n"; + $Failed{'Test 3a'} = "new(): " . Win32::ODBC::Error(); + PresentErrors(); + exit(); + }else{ + print "Success (connection #", $O->Connection(), ")\n\n"; + } + + print "\tOpening ODBC connection for \"$DSN\"...\n\t\t"; + if (!($O2 = new Win32::ODBC($DSN))){ + $Failed{'Test 3b'} = "new(): " . Win32::ODBC::Error(); + print "Failure. \n\n"; + }else{ + print "Success (connection #", $O2->Connection(), ")\n\n"; + } + + print "\tOpening ODBC connection for \"$DSN\"\n\t\t"; + if (!($O3 = new Win32::ODBC($DSN))){ + $Failed{'Test 3c'} = "new(): " . Win32::ODBC::Error(); + print "Failure. \n\n"; + }else{ + print "Success (connection #", $O3->Connection(), ")\n\n"; + } + + +#### +# T E S T 4 +#### + PrintTest(4, "Close all but one connection"); + + print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O2->GetConnections())), "\"\n"; + print "\tClosing ODBC connection #", $O2->Connection(), "...\n"; + print "\t\t...", (($O2->Close())? "Successful.":"Failure."), "\n"; + + print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O3->GetConnections())), "\"\n"; + print "\tClosing ODBC connection #", $O3->Connection(), "...\n"; + print "\t\t...", (($O3->Close())? "Successful.":"Failure."), "\n"; + + print "\n\tCurrently open ODBC connections are: \"", join(", ", sort($O2->GetConnections())), "\"\n"; + +#### +# T E S T 5 +#### + PrintTest(5, "Set/query Max Buffer size for a connection"); + + srand(time); + $Temp = int(rand(10240)) + 10240; + print "\nMaximum Buffer Size for connection #", $O->Connection(), ":\n"; + print "\tValue set at ", $O->GetMaxBufSize(), "\n"; + + print "\tSetting Maximum Buffer Size to $Temp... it has been set to ", $O->SetMaxBufSize($Temp), "\n"; + print "\tValue set at ", $O->GetMaxBufSize(), "\n"; + + $Temp += int(rand(10240)) + 102400; + print "\tSetting Maximum Buffer Size to $Temp... (can not be more than 102400)\n\t\t...it has been set to ", $O->SetMaxBufSize($Temp), "\n"; + print "\tValue set at ", $O->GetMaxBufSize(), "\n"; + + $Temp = int(rand(1024)) + 2048; + print "\tSetting Maximum Buffer Size to $Temp... it has been set to ", $O->SetMaxBufSize($Temp), "\n"; + + print "\tValue set at ", $O->GetMaxBufSize(), "\n"; + + +#### +# T E S T 6 +#### + PrintTest(6, "Set/query Stmt Close Type"); + + print "\n\tStatement Close Type is currently set as ", $O->GetStmtCloseType(), " " . $O->Error . "\n"; + print "\tSetting Statement Close Type to SQL_CLOSE: (returned code of ", $O->SetStmtCloseType(SQL_CLOSE), ")" . $O->Error . "\n"; + print "\tStatement Close Type is currently set as ", $O->GetStmtCloseType(), " " . $O->Error ."\n"; + + +#### +# T E S T 7 +#### + PrintTest(7, "Dump DSN for current connection"); + + if (! (%DSNAttributes = $O->GetDSN())){ + $Failed{'Test 7'} = "GetDSN(): " . $O->Error(); + }else{ + print"\nThe DSN for connection #", $O->Connection(), ":\n"; + print "\tDSN...\n"; + foreach (sort(keys(%DSNAttributes))){ + print "\t$_ = \"$DSNAttributes{$_}\"\n"; + } + } + + + +#### +# T E S T 8 +#### + PrintTest(8, "Dump list of ALL tables in datasource"); + + print "\nList of tables for \"$DSN\"\n\n"; + $Num = 0; + if ($O->Catalog("", "", "%", "'TABLE','VIEW','SYSTEM TABLE', 'GLOBAL TEMPORARY','LOCAL TEMPORARY','ALIAS','SYNONYM'")){ + + print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n"; + print "\tRenaming cursor to \"TestCursor\"...", (($O->SetCursorName("TestCursor"))? "Success":"Failure"), ".\n"; + print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n\n"; + + @FieldNames = $O->FieldNames(); + + $~ = "Test_8_Header"; + write; + + $~ = "Test_8_Body"; + while($O->FetchRow()){ + undef %Data; + %Data = $O->DataHash(); + write; + } + } + print "\n\tTotal number of tables displayed: $Num\n"; + + + +#### +# T E S T 9 +#### + PrintTest(9, "Dump list of non-system tables and views in datasource"); + + print "\n"; + $Num = 0; + + foreach $Temp ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){ + $Table = $Temp; + print "\t", ++$Num, ".) \"$Temp\"\n"; + } + print "\n\tTotal number of tables displayed: $Num\n"; + + +#### +# T E S T 10 +#### + PrintTest(10, "Dump contents of the table: \"$Table\""); + + print "\n"; + + print "\tResetting (dropping) cursor...", (($O->DropCursor())? "Successful":"Failure"), ".\n\n"; + + print "\tCurrently the cursor type is: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n"; + print "\tSetting Cursor to Dynamic (", ($O->SQL_CURSOR_DYNAMIC), ")...", (($O->SetStmtOption($O->SQL_CURSOR_TYPE, $O->SQL_CURSOR_DYNAMIC))? "Success":"Failure"), ".\n"; + print "\t\tThis may have failed depending on your ODBC Driver.\n"; + print "\t\tThis is not really a problem, it will default to another value.\n"; + print "\tUsing the cursor type of: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n\n"; + + print "\tSetting the connection to only grab $MaxRows row", ($MaxRows == 1)? "":"s", " maximum..."; + if ($O->SetStmtOption($O->SQL_MAX_ROWS, $MaxRows)){ + print "Success!\n"; + }else{ + $Failed{'Test 10a'} = "SetStmtOption(): " . Win32::ODBC::Error(); + print "Failure.\n"; + } + + $iTemp = $O->GetStmtOption($O->SQL_MAX_ROWS); + print "\tUsing the maximum rows: ", (($iTemp)? $iTemp:"No maximum limit"), "\n\n"; + + print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n"; + print "\tRenaming cursor to \"TestCursor\"...", (($O->SetCursorName("TestCursor"))? "Success":"Failure"), ".\n"; + print "\tCursor is currently named \"", $O->GetCursorName(), "\".\n\n"; + + if (! $O->Sql("SELECT * FROM [$Table]")){ + @FieldNames = $O->FieldNames(); + $Cols = $#FieldNames + 1; + $Cols = 8 if ($Cols > 8); + + $FmH = "format Test_10_Header =\n"; + $FmH2 = ""; + $FmH3 = ""; + $FmB = "format Test_10_Body = \n"; + $FmB2 = ""; + + for ($iTemp = 0; $iTemp < $Cols; $iTemp++){ + $FmH .= "@" . "<" x (80/$Cols - 2) . " "; + $FmH2 .= "\$FieldNames[$iTemp],"; + $FmH3 .= "-" x (80/$Cols - 1) . " "; + + $FmB .= "@" . "<" x (80/$Cols - 2) . " "; + $FmB2 .= "\$Data{\$FieldNames[$iTemp]},"; + } + chop $FmH2; + chop $FmB2; + + eval"$FmH\n$FmH2\n$FmH3\n.\n"; + eval "$FmB\n$FmB2\n.\n"; + + $~ = "Test_10_Header"; + write(); + $~ = "Test_10_Body"; + + # Fetch the next rowset + while($O->FetchRow()){ + undef %Data; + %Data = $O->DataHash(); + write(); + } + #### + # THE preceeding block could have been written like this: + # ------------------------------------------------------ + # + # print "\tCurrently the cursor type is: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n"; + # print "\tSetting Cursor to Dynamic (", ($O->SQL_CURSOR_DYNAMIC), ")...", (($O->SetStmtOption($O->SQL_CURSOR_TYPE, $O->SQL_CURSOR_DYNAMIC))? "Success":"Failure"), ".\n"; + # print "\t\tThis may have failed depending on your ODBC Driver. No real problem.\n"; + # print "\tUsing the cursor type of: ", $O->GetStmtOption($O->SQL_CURSOR_TYPE), "\n\n"; + # + # print "\tSetting rowset size = 15 ...", (($O->SetStmtOption($O->SQL_ROWSET_SIZE, 15))? "Success":"Failure"), ".\n"; + # print "\tGetting rowset size: ", $O->GetStmtOption($O->SQL_ROWSET_SIZE), "\n\n"; + # + # while($O->FetchRow()){ + # $iNum = 1; + # # Position yourself in the rowset + # while($O->SetPos($iNum++ ,$O->SQL_POSITION, $O->SQL_LOCK_NO_CHANGE)){ + # undef %Data; + # %Data = $O->DataHash(); + # write(); + # } + # print "\t\tNext rowset...\n"; + # } + # + # The reason I didn't write it that way (which is easier) is to + # show that we can now SetPos(). Also Fetch() now uses + # SQLExtendedFetch() so it can position itself and retrieve + # rowsets. Notice earlier in this Test 10 we set the + # SQL_ROWSET_SIZE. If this was not set it would default to + # no limit (depending upon your ODBC Driver). + #### + + print "\n\tNo more records available.\n"; + }else{ + $Failed{'Test 10'} = "Sql(): " . $O->Error(); + } + + $O->Close(); + +#### +# T E S T 11 +#### + if ($iTempDSN){ + PrintTest(11, "Remove the temporary DSN"); + print "\n\tRemoving the temporary DSN:\n"; + print "\t\tDSN = \"$DSN\"\n\t\tDriver = \"$DriverType\"\n"; + + if (Win32::ODBC::ConfigDSN(ODBC_REMOVE_DSN, $DriverType, "DSN=$DSN")){ + print "\tSuccessful!\n"; + }else{ + print "\tFailed.\n"; + $Failed{'Test 11'} = "ConfigDSN(): Could not remove \"$DSN\":" . Win32::ODBC::Error(); + } + } + + + PrintTest("E N D O F T E S T"); + PresentErrors(); + + + +#----------------------- F U N C T I O N S --------------------------- + +sub Error{ + my($Data) = @_; + $Data->DumpError() if ref($Data); + Win32::ODBC::DumpError() if ! ref($Data); +} + + +sub Center{ + local($Temp, $Width) = @_; + local($Len) = ($Width - length($Temp)) / 2; + return " " x int($Len), $Temp, " " x (int($Len) + (($Len != int($Len))? 1:0)); +} + +sub PrintTest{ + my($Num, $String) = @_; + my($Temp); + if (length($String)){ + $Temp = " T E S T $Num $String "; + }else{ + $Temp = " $Num "; + } + $Len = length($Temp); + print "\n", "-" x ((79 - $Len)/2), $Temp, "-" x ((79 - $Len)/2 - 1), "\n"; + print "\t$String\n"; +} + +sub PresentErrors{ + PrintTest("", "Error Report:"); + if (keys(%Failed)){ + print "The following were errors:\n"; + foreach (sort(keys(%Failed))){ + print "$_ = $Failed{$_}\n"; + } + }else{ + print "\n\nThere were no errors reported during this test.\n\n"; + } +} + + +sub Initialize{ +format Test_8_Header = + @<<<<<<<<<<<<<<<<<<<<<<<<<<< @|||||||||||| @|||||||||||| @||||||||||| + $FieldNames[0], $FieldNames[1], $FieldNames[2], $FieldNames[3] + ---------------------------- ------------- ------------- ------------ +. +format Test_8_Body = + @>. @<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<< + ++$Num, $Data{$FieldNames[0]}, $Data{$FieldNames[1]}, $Data{$FieldNames[2]}, $Data{$FieldNames[3]} +. +format Test_9_Header = + @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< + $FieldNames[0], $FieldNames[1], $FieldNames[2], $FieldNames[3] +. +format Test_9_Body = + @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<< + $Data{$FieldNames[0]}, $Data{$FieldNames[1]}, $Data{$FieldNames[2]}, $Data{$FieldNames[3]} +. +} diff --git a/Master/tlpkg/tlperl/lib/Win32/TieRegistry.pm b/Master/tlpkg/tlperl/lib/Win32/TieRegistry.pm new file mode 100644 index 00000000000..0abbbddb6b8 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/TieRegistry.pm @@ -0,0 +1,3801 @@ +# Win32/TieRegistry.pm -- Perl module to easily use a Registry +# (on Win32 systems so far). +# by Tye McQueen, tye@metronet.com, see http://www.metronet.com/~tye/. + +# +# Skip to "=head" line for user documentation. +# + + +package Win32::TieRegistry; + + +use strict; +use vars qw( $PACK $VERSION @ISA @EXPORT @EXPORT_OK ); + +$PACK= "Win32::TieRegistry"; # Used in error messages. +$VERSION= '0.26'; + + +use Carp; + +require Tie::Hash; +@ISA= qw(Tie::Hash); + +# Required other modules: +use Win32API::Registry 0.12 qw( :KEY_ :HKEY_ :REG_ ); + +#Optional other modules: +use vars qw( $_NoMoreItems $_FileNotFound $_TooSmall $_MoreData $_SetDualVar ); + +if( eval { require Win32::WinError } ) { + $_NoMoreItems= Win32::WinError::constant("ERROR_NO_MORE_ITEMS",0); + $_FileNotFound= Win32::WinError::constant("ERROR_FILE_NOT_FOUND",0); + $_TooSmall= Win32::WinError::constant("ERROR_INSUFFICIENT_BUFFER",0); + $_MoreData= Win32::WinError::constant("ERROR_MORE_DATA",0); +} else { + $_NoMoreItems= "^No more data"; + $_FileNotFound= "cannot find the file"; + $_TooSmall= " data area passed to "; + $_MoreData= "^more data is avail"; +} +if( $_SetDualVar= eval { require SetDualVar } ) { + import SetDualVar; +} + + +#Implementation details: +# When opened: +# HANDLE long; actual handle value +# MACHINE string; name of remote machine ("" if local) +# PATH list ref; machine-relative full path for this key: +# ["LMachine","System","Disk"] +# ["HKEY_LOCAL_MACHINE","System","Disk"] +# DELIM char; delimiter used to separate subkeys (def="\\") +# OS_DELIM char; always "\\" for Win32 +# ACCESS long; usually KEY_ALL_ACCESS, perhaps KEY_READ, etc. +# ROOTS string; var name for "Lmachine"->HKEY_LOCAL_MACHINE map +# FLAGS int; bits to control certain options +# Often: +# VALUES ref to list of value names (data/type never cached) +# SUBKEYS ref to list of subkey names +# SUBCLASSES ref to list of subkey classes +# SUBTIMES ref to list of subkey write times +# MEMBERS ref to list of subkey_name.DELIM's, DELIM.value_name's +# MEMBHASH hash ref to with MEMBERS as keys and 1's as values +# Once Key "Info" requested: +# Class CntSubKeys CntValues MaxSubKeyLen MaxSubClassLen +# MaxValNameLen MaxValDataLen SecurityLen LastWrite +# If is tied to a hash and iterating over key values: +# PREVIDX int; index of last MEMBERS element return +# If is the key object returned by Load(): +# UNLOADME list ref; information about Load()ed key +# If is a subkey of a "loaded" key other than the one returned by Load(): +# DEPENDON obj ref; object that can't be destroyed before us + + +#Package-local variables: + +# Option flag bits: +use vars qw( $Flag_ArrVal $Flag_TieVal $Flag_DualTyp $Flag_DualBin + $Flag_FastDel $Flag_HexDWord $Flag_Split $Flag_FixNulls ); +$Flag_ArrVal= 0x0001; +$Flag_TieVal= 0x0002; +$Flag_FastDel= 0x0004; +$Flag_HexDWord= 0x0008; +$Flag_Split= 0x0010; +$Flag_DualTyp= 0x0020; +$Flag_DualBin= 0x0040; +$Flag_FixNulls= 0x0080; + + +use vars qw( $RegObj %_Roots %RegHash $Registry ); + +# Short-hand for HKEY_* constants: +%_Roots= ( + "Classes" => HKEY_CLASSES_ROOT, + "CUser" => HKEY_CURRENT_USER, + "LMachine" => HKEY_LOCAL_MACHINE, + "Users" => HKEY_USERS, + "PerfData" => HKEY_PERFORMANCE_DATA, # Too picky to be useful + "CConfig" => HKEY_CURRENT_CONFIG, + "DynData" => HKEY_DYN_DATA, # Too picky to be useful +); + +# Basic master Registry object: +$RegObj= {}; +@$RegObj{qw( HANDLE MACHINE PATH DELIM OS_DELIM ACCESS FLAGS ROOTS )}= ( + "NONE", "", [], "\\", "\\", + KEY_READ|KEY_WRITE, $Flag_HexDWord|$Flag_FixNulls, "${PACK}::_Roots" ); +$RegObj->{FLAGS} |= $Flag_DualTyp|$Flag_DualBin if $_SetDualVar; +bless $RegObj; + +# Fill cache for master Registry object: +@$RegObj{qw( VALUES SUBKEYS SUBCLASSES SUBTIMES )}= ( + [], [ keys(%_Roots) ], [], [] ); +grep( s#$#$RegObj->{DELIM}#, + @{ $RegObj->{MEMBERS}= [ @{$RegObj->{SUBKEYS}} ] } ); +@$RegObj{qw( Class MaxSubKeyLen MaxSubClassLen MaxValNameLen + MaxValDataLen SecurityLen LastWrite CntSubKeys CntValues )}= + ( "", 0, 0, 0, 0, 0, 0, 0, 0 ); + +# Create master Registry tied hash: +$RegObj->Tie( \%RegHash ); + +# Create master Registry combination object and tied hash reference: +$Registry= \%RegHash; +bless $Registry; + + +# Preloaded methods go here. + + +# Map option names to name of subroutine that controls that option: +use vars qw( @_opt_subs %_opt_subs ); +@_opt_subs= qw( Delimiter ArrayValues TieValues SplitMultis DWordsToHex + FastDelete FixSzNulls DualTypes DualBinVals AllowLoad AllowSave ); +@_opt_subs{@_opt_subs}= @_opt_subs; + +sub import +{ + my $pkg= shift(@_); + my $level= $Exporter::ExportLevel; + my $expto= caller($level); + my @export= (); + my @consts= (); + my $registry= $Registry->Clone; + local( $_ ); + while( @_ ) { + $_= shift(@_); + if( /^\$(\w+::)*\w+$/ ) { + push( @export, "ObjVar" ) if /^\$RegObj$/; + push( @export, $_ ); + } elsif( /^\%(\w+::)*\w+$/ ) { + push( @export, $_ ); + } elsif( /^[$%]/ ) { + croak "${PACK}->import: Invalid variable name ($_)"; + } elsif( /^:/ || /^(H?KEY|REG)_/ ) { + push( @consts, $_ ); + } elsif( ! @_ ) { + croak "${PACK}->import: Missing argument after option ($_)"; + } elsif( exists $_opt_subs{$_} ) { + $_= $_opt_subs{$_}; + $registry->$_( shift(@_) ); + } elsif( /^TiedRef$/ ) { + $_= shift(@_); + if( ! ref($_) && /^(\$?)(\w+::)*\w+$/ ) { + $_= '$'.$_ unless '$' eq $1; + } elsif( "SCALAR" ne ref($_) ) { + croak "${PACK}->import: Invalid var after TiedRef ($_)"; + } + push( @export, $_ ); + } elsif( /^TiedHash$/ ) { + $_= shift(@_); + if( ! ref($_) && /^(\%?)(\w+::)*\w+$/ ) { + $_= '%'.$_ unless '%' eq $1; + } elsif( "HASH" ne ref($_) ) { + croak "${PACK}->import: Invalid var after TiedHash ($_)"; + } + push( @export, $_ ); + } elsif( /^ObjectRef$/ ) { + $_= shift(@_); + if( ! ref($_) && /^(\$?)(\w+::)*\w+$/ ) { + push( @export, "ObjVar" ); + $_= '$'.$_ unless '$' eq $1; + } elsif( "SCALAR" eq ref($_) ) { + push( @export, "ObjRef" ); + } else { + croak "${PACK}->import: Invalid var after ObjectRef ($_)"; + } + push( @export, $_ ); + } elsif( /^ExportLevel$/ ) { + $level= shift(@_); + $expto= caller($level); + } elsif( /^ExportTo$/ ) { + undef $level; + $expto= caller($level); + } else { + croak "${PACK}->import: Invalid option ($_)"; + } + } + Win32API::Registry->export( $expto, @consts ) if @consts; + @export= ('$Registry') unless @export; + while( @export ) { + $_= shift( @export ); + if( /^\$((?:\w+::)*)(\w+)$/ ) { + my( $pack, $sym )= ( $1, $2 ); + $pack= $expto unless defined($pack) && "" ne $pack; + no strict 'refs'; + *{"${pack}::$sym"}= \${"${pack}::$sym"}; + ${"${pack}::$sym"}= $registry; + } elsif( /^\%((?:\w+::)*)(\w+)$/ ) { + my( $pack, $sym )= ( $1, $2 ); + $pack= $expto unless defined($pack) && "" ne $pack; + no strict 'refs'; + *{"${pack}::$sym"}= \%{"${pack}::$sym"}; + $registry->Tie( \%{"${pack}::$sym"} ); + } elsif( "SCALAR" eq ref($_) ) { + $$_= $registry; + } elsif( "HASH" eq ref($_) ) { + $registry->Tie( $_ ); + } elsif( /^ObjVar$/ ) { + $_= shift( @_ ); + /^\$((?:\w+::)*)(\w+)$/; + my( $pack, $sym )= ( $1, $2 ); + $pack= $expto unless defined($pack) && "" ne $pack; + no strict 'refs'; + *{"${pack}::$sym"}= \${"${pack}::$sym"}; + ${"${pack}::$sym"}= $registry->ObjectRef; + } elsif( /^ObjRef$/ ) { + ${shift(@_)}= $registry->ObjectRef; + } else { + die "Impossible var to export ($_)"; + } + } +} + + +use vars qw( @_new_Opts %_new_Opts ); +@_new_Opts= qw( ACCESS DELIM MACHINE DEPENDON ); +@_new_Opts{@_new_Opts}= (1) x @_new_Opts; + +sub _new +{ + my $this= shift( @_ ); + $this= tied(%$this) if ref($this) && tied(%$this); + my $class= ref($this) || $this; + my $self= {}; + my( $handle, $rpath, $opts )= @_; + if( @_ < 2 || "ARRAY" ne ref($rpath) || 3 < @_ + || 3 == @_ && "HASH" ne ref($opts) ) { + croak "Usage: ${PACK}->_new( \$handle, \\\@path, {OPT=>VAL,...} );\n", + " options: @_new_Opts\nCalled"; + } + @$self{qw( HANDLE PATH )}= ( $handle, $rpath ); + @$self{qw( MACHINE ACCESS DELIM OS_DELIM ROOTS FLAGS )}= + ( $this->Machine, $this->Access, $this->Delimiter, + $this->OS_Delimiter, $this->_Roots, $this->_Flags ); + if( ref($opts) ) { + my @err= grep( ! $_new_Opts{$_}, keys(%$opts) ); + @err and croak "${PACK}->_new: Invalid options (@err)"; + @$self{ keys(%$opts) }= values(%$opts); + } + bless $self, $class; + return $self; +} + + +sub _split +{ + my $self= shift( @_ ); + $self= tied(%$self) if tied(%$self); + my $path= shift( @_ ); + my $delim= @_ ? shift(@_) : $self->Delimiter; + my $list= [ split( /\Q$delim/, $path ) ]; + return $list; +} + + +sub _rootKey +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $keyPath= shift(@_); + my $delim= @_ ? shift(@_) : $self->Delimiter; + my( $root, $subPath ); + if( "ARRAY" eq ref($keyPath) ) { + $subPath= $keyPath; + } else { + $subPath= $self->_split( $keyPath, $delim ); + } + $root= shift( @$subPath ); + if( $root =~ /^HKEY_/ ) { + my $handle= Win32API::Registry::constant($root,0); + $handle or croak "Invalid HKEY_ constant ($root): $!"; + return( $self->_new( $handle, [$root], {DELIM=>$delim} ), + $subPath ); + } elsif( $root =~ /^([-+]|0x)?\d/ ) { + return( $self->_new( $root, [sprintf("0x%lX",$root)], + {DELIM=>$delim} ), + $subPath ); + } else { + my $roots= $self->Roots; + if( $roots->{$root} ) { + return( $self->_new( $roots->{$root}, [$root], {DELIM=>$delim} ), + $subPath ); + } + croak "No such root key ($root)"; + } +} + + +sub _open +{ + my $this= shift(@_); + $this= tied(%$this) if ref($this) && tied(%$this); + my $subPath= shift(@_); + my $sam= @_ ? shift(@_) : $this->Access; + my $subKey= join( $this->OS_Delimiter, @$subPath ); + my $handle= 0; + $this->RegOpenKeyEx( $subKey, 0, $sam, $handle ) + or return (); + return $this->_new( $handle, [ @{$this->_Path}, @$subPath ], + { ACCESS=>$sam, ( defined($this->{UNLOADME}) ? ("DEPENDON",$this) + : defined($this->{DEPENDON}) ? ("DEPENDON",$this->{DEPENDON}) : () ) + } ); +} + + +sub ObjectRef +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + return $self; +} + + +sub _constant +{ + my( $name, $desc )= @_; + my $value= Win32API::Registry::constant( $name, 0 ); + my $func= (caller(1))[3]; + if( 0 == $value ) { + if( $! =~ /invalid/i ) { + croak "$func: Invalid $desc ($name)"; + } elsif( 0 != $! ) { + croak "$func: \u$desc ($name) not support on this platform"; + } + } + return $value; +} + + +sub _connect +{ + my $this= shift(@_); + $this= tied(%$this) if ref($this) && tied(%$this); + my $subPath= pop(@_); + $subPath= $this->_split( $subPath ) unless ref($subPath); + my $machine= @_ ? shift(@_) : shift(@$subPath); + my $handle= 0; + my( $temp )= $this->_rootKey( [@$subPath] ); + $temp->RegConnectRegistry( $machine, $temp->Handle, $handle ) + or return (); + my $self= $this->_new( $handle, [shift(@$subPath)], {MACHINE=>$machine} ); + return( $self, $subPath ); +} + + +use vars qw( @Connect_Opts %Connect_Opts ); +@Connect_Opts= qw(Access Delimiter); +@Connect_Opts{@Connect_Opts}= (1) x @Connect_Opts; + +sub Connect +{ + my $this= shift(@_); + my $tied= ref($this) && tied(%$this); + $this= tied(%$this) if $tied; + my( $machine, $key, $opts )= @_; + my $delim= ""; + my $sam; + my $subPath; + if( @_ < 2 || 3 < @_ + || 3 == @_ && "HASH" ne ref($opts) ) { + croak "Usage: \$obj= ${PACK}->Connect(", + " \$Machine, \$subKey, { OPT=>VAL,... } );\n", + " options: @Connect_Opts\nCalled"; + } + if( ref($opts) ) { + my @err= grep( ! $Connect_Opts{$_}, keys(%$opts) ); + @err and croak "${PACK}->Connect: Invalid options (@err)"; + } + $delim= "$opts->{Delimiter}" if defined($opts->{Delimiter}); + $delim= $this->Delimiter if "" eq $delim; + $sam= defined($opts->{Access}) ? $opts->{Access} : $this->Access; + $sam= _constant($sam,"key access type") if $sam =~ /^KEY_/; + ( $this, $subPath )= $this->_connect( $machine, $key ); + return () unless defined($this); + my $self= $this->_open( $subPath, $sam ); + return () unless defined($self); + $self->Delimiter( $delim ); + $self= $self->TiedRef if $tied; + return $self; +} + + +my @_newVirtual_keys= qw( MEMBERS VALUES SUBKEYS SUBTIMES SUBCLASSES + Class SecurityLen LastWrite CntValues CntSubKeys + MaxValNameLen MaxValDataLen MaxSubKeyLen MaxSubClassLen ); + +sub _newVirtual +{ + my $self= shift(@_); + my( $rPath, $root, $opts )= @_; + my $new= $self->_new( "NONE", $rPath, $opts ) + or return (); + @{$new}{@_newVirtual_keys}= @{$root->ObjectRef}{@_newVirtual_keys}; + return $new; +} + + +#$key= new Win32::TieRegistry "LMachine/System/Disk"; +#$key= new Win32::TieRegistry "//Server1/LMachine/System/Disk"; +#Win32::TieRegistry->new( HKEY_LOCAL_MACHINE, {DELIM=>"/",ACCESS=>KEY_READ} ); +#Win32::TieRegistry->new( [ HKEY_LOCAL_MACHINE, ".../..." ], {DELIM=>$DELIM} ); +#$key->new( ... ); + +use vars qw( @new_Opts %new_Opts ); +@new_Opts= qw(Access Delimiter); +@new_Opts{@new_Opts}= (1) x @new_Opts; + +sub new +{ + my $this= shift( @_ ); + $this= tied(%$this) if ref($this) && tied(%$this); + if( ! ref($this) ) { + no strict "refs"; + my $self= ${"${this}::Registry"}; + croak "${this}->new failed since ${PACK}::new sees that ", + "\$${this}::Registry is not an object." + if ! ref($self); + $this= $self->Clone; + } + my( $subKey, $opts )= @_; + my $delim= ""; + my $dlen; + my $sam; + my $subPath; + if( @_ < 1 || 2 < @_ + || 2 == @_ && "HASH" ne ref($opts) ) { + croak "Usage: \$obj= ${PACK}->new( \$subKey, { OPT=>VAL,... } );\n", + " options: @new_Opts\nCalled"; + } + if( defined($opts) ) { + my @err= grep( ! $new_Opts{$_}, keys(%$opts) ); + @err and die "${PACK}->new: Invalid options (@err)"; + } + $delim= "$opts->{Delimiter}" if defined($opts->{Delimiter}); + $delim= $this->Delimiter if "" eq $delim; + $dlen= length($delim); + $sam= defined($opts->{Access}) ? $opts->{Access} : $this->Access; + $sam= _constant($sam,"key access type") if $sam =~ /^KEY_/; + if( "ARRAY" eq ref($subKey) ) { + $subPath= $subKey; + if( "NONE" eq $this->Handle && @$subPath ) { + ( $this, $subPath )= $this->_rootKey( $subPath ); + } + } elsif( $delim x 2 eq substr($subKey,0,2*$dlen) ) { + my $path= $this->_split( substr($subKey,2*$dlen), $delim ); + my $mach= shift(@$path); + if( ! @$path ) { + return $this->_newVirtual( $path, $Registry, + {MACHINE=>$mach,DELIM=>$delim,ACCESS=>$sam} ); + } + ( $this, $subPath )= $this->_connect( $mach, $path ); + return () if ! defined($this); + if( 0 == @$subPath ) { + $this->Delimiter( $delim ); + return $this; + } + } elsif( $delim eq substr($subKey,0,$dlen) ) { + ( $this, $subPath )= $this->_rootKey( substr($subKey,$dlen), $delim ); + } elsif( "NONE" eq $this->Handle && "" ne $subKey ) { + my( $mach )= $this->Machine; + if( $mach ) { + ( $this, $subPath )= $this->_connect( $mach, $subKey ); + } else { + ( $this, $subPath )= $this->_rootKey( $subKey, $delim ); + } + } else { + $subPath= $this->_split( $subKey, $delim ); + } + return () unless defined($this); + if( 0 == @$subPath && "NONE" eq $this->Handle ) { + return $this->_newVirtual( $this->_Path, $this, + { DELIM=>$delim, ACCESS=>$sam } ); + } + my $self= $this->_open( $subPath, $sam ); + return () unless defined($self); + $self->Delimiter( $delim ); + return $self; +} + + +sub Open +{ + my $self= shift(@_); + my $tied= ref($self) && tied(%$self); + $self= tied(%$self) if $tied; + $self= $self->new( @_ ); + $self= $self->TiedRef if defined($self) && $tied; + return $self; +} + + +sub Clone +{ + my $self= shift( @_ ); + my $new= $self->Open(""); + return $new; +} + + +{ my @flush; + sub Flush + { + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( $flush )= shift(@_); + @_ and croak "Usage: \$key->Flush( \$bFlush );"; + return 0 if "NONE" eq $self->Handle; + @flush= qw( VALUES SUBKEYS SUBCLASSES SUBTIMES MEMBERS Class + CntSubKeys CntValues MaxSubKeyLen MaxSubClassLen + MaxValNameLen MaxValDataLen SecurityLen LastWrite PREVIDX ) + unless @flush; + delete( @$self{@flush} ); + if( defined($flush) && $flush ) { + return $self->RegFlushKey(); + } else { + return 1; + } + } +} + + +sub _DualVal +{ + my( $hRef, $num )= @_; + if( $_SetDualVar && $$hRef{$num} ) { + &SetDualVar( $num, "$$hRef{$num}", 0+$num ); + } + return $num; +} + + +use vars qw( @_RegDataTypes %_RegDataTypes ); +@_RegDataTypes= qw( REG_SZ REG_EXPAND_SZ REG_BINARY REG_LINK REG_MULTI_SZ + REG_DWORD_LITTLE_ENDIAN REG_DWORD_BIG_ENDIAN REG_DWORD + REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR + REG_RESOURCE_REQUIREMENTS_LIST REG_NONE ); +# Make sure that REG_DWORD appears _after_ other REG_DWORD_* +# items above and that REG_NONE appears _last_. +foreach( @_RegDataTypes ) { + $_RegDataTypes{Win32API::Registry::constant($_,0)}= $_; +} + +sub GetValue +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + 1 == @_ or croak "Usage: (\$data,\$type)= \$key->GetValue('ValName');"; + my( $valName )= @_; + my( $valType, $valData, $dLen )= (0,"",0); + return () if "NONE" eq $self->Handle; + $self->RegQueryValueEx( $valName, [], $valType, $valData, + $dLen= ( defined($self->{MaxValDataLen}) ? $self->{MaxValDataLen} : 0 ) + ) or return (); + if( REG_DWORD == $valType ) { + my $val= unpack("L",$valData); + $valData= sprintf "0x%08.8lX", $val if $self->DWordsToHex; + &SetDualVar( $valData, $valData, $val ) if $self->DualBinVals + } elsif( REG_BINARY == $valType && length($valData) <= 4 ) { + &SetDualVar( $valData, $valData, hex reverse unpack("h*",$valData) ) + if $self->DualBinVals; + } elsif( ( REG_SZ == $valType || REG_EXPAND_SZ == $valType ) + && $self->FixSzNulls ) { + substr($valData,-1)= "" if "\0" eq substr($valData,-1); + } elsif( REG_MULTI_SZ == $valType && $self->SplitMultis ) { + ## $valData =~ s/\0\0$//; # Why does this often fail?? + substr($valData,-2)= "" if "\0\0" eq substr($valData,-2); + $valData= [ split( /\0/, $valData, -1 ) ] + } + if( ! wantarray ) { + return $valData; + } elsif( ! $self->DualTypes ) { + return( $valData, $valType ); + } else { + return( $valData, _DualVal( \%_RegDataTypes, $valType ) ); + } +} + + +sub _ErrNum +{ + # return $^E; + return Win32::GetLastError(); +} + + +sub _ErrMsg +{ + # return $^E; + return Win32::FormatMessage( Win32::GetLastError() ); +} + +sub _Err +{ + my $err; + # return $^E; + return _ErrMsg if ! $_SetDualVar; + return &SetDualVar( $err, _ErrMsg, _ErrNum ); +} + +sub _NoMoreItems +{ + return + $_NoMoreItems =~ /^\d/ + ? _ErrNum == $_NoMoreItems + : _ErrMsg =~ /$_NoMoreItems/io; +} + + +sub _FileNotFound +{ + return + $_FileNotFound =~ /^\d/ + ? _ErrNum == $_FileNotFound + : _ErrMsg =~ /$_FileNotFound/io; +} + + +sub _TooSmall +{ + return + $_TooSmall =~ /^\d/ + ? _ErrNum == $_TooSmall + : _ErrMsg =~ /$_TooSmall/io; +} + + +sub _MoreData +{ + return + $_MoreData =~ /^\d/ + ? _ErrNum == $_MoreData + : _ErrMsg =~ /$_MoreData/io; +} + + +sub _enumValues +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( @names )= (); + my $pos= 0; + my $name= ""; + my $nlen= 1+$self->Information("MaxValNameLen"); + while( $self->RegEnumValue($pos++,$name,$nlen,[],[],[],[]) ) { + push( @names, $name ); + } + if( ! _NoMoreItems() ) { + return (); + } + $self->{VALUES}= \@names; + return 1; +} + + +sub ValueNames +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \@names= \$key->ValueNames;"; + $self->_enumValues unless $self->{VALUES}; + return @{$self->{VALUES}}; +} + + +sub _enumSubKeys +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( @subkeys, @classes, @times )= (); + my $pos= 0; + my( $subkey, $class, $time )= ("","",""); + my( $namSiz, $clsSiz )= $self->Information( + qw( MaxSubKeyLen MaxSubClassLen )); + $namSiz++; $clsSiz++; + while( $self->RegEnumKeyEx( + $pos++, $subkey, $namSiz, [], $class, $clsSiz, $time ) ) { + push( @subkeys, $subkey ); + push( @classes, $class ); + push( @times, $time ); + } + if( ! _NoMoreItems() ) { + return (); + } + $self->{SUBKEYS}= \@subkeys; + $self->{SUBCLASSES}= \@classes; + $self->{SUBTIMES}= \@times; + return 1; +} + + +sub SubKeyNames +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \@names= \$key->SubKeyNames;"; + $self->_enumSubKeys unless $self->{SUBKEYS}; + return @{$self->{SUBKEYS}}; +} + + +sub SubKeyClasses +{ + my $self= shift(@_); + @_ and croak "Usage: \@classes= \$key->SubKeyClasses;"; + $self->_enumSubKeys unless $self->{SUBCLASSES}; + return @{$self->{SUBCLASSES}}; +} + + +sub SubKeyTimes +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \@times= \$key->SubKeyTimes;"; + $self->_enumSubKeys unless $self->{SUBTIMES}; + return @{$self->{SUBTIMES}}; +} + + +sub _MemberNames +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$arrayRef= \$key->_MemberNames;"; + if( ! $self->{MEMBERS} ) { + $self->_enumValues unless $self->{VALUES}; + $self->_enumSubKeys unless $self->{SUBKEYS}; + my( @members )= ( map( $_.$self->{DELIM}, @{$self->{SUBKEYS}} ), + map( $self->{DELIM}.$_, @{$self->{VALUES}} ) ); + $self->{MEMBERS}= \@members; + } + return $self->{MEMBERS}; +} + + +sub _MembersHash +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$hashRef= \$key->_MembersHash;"; + if( ! $self->{MEMBHASH} ) { + my $aRef= $self->_MemberNames; + $self->{MEMBHASH}= {}; + @{$self->{MEMBHASH}}{@$aRef}= (1) x @$aRef; + } + return $self->{MEMBHASH}; +} + + +sub MemberNames +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \@members= \$key->MemberNames;"; + return @{$self->_MemberNames}; +} + + +sub Information +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( $time, $nkeys, $nvals, $xsec, $xkey, $xcls, $xname, $xdata )= + ("",0,0,0,0,0,0,0); + my $clen= 8; + if( ! $self->RegQueryInfoKey( [], [], $nkeys, $xkey, $xcls, + $nvals, $xname, $xdata, $xsec, $time ) ) { + return (); + } + if( defined($self->{Class}) ) { + $clen= length($self->{Class}); + } else { + $self->{Class}= ""; + } + while( ! $self->RegQueryInfoKey( $self->{Class}, $clen, + [],[],[],[],[],[],[],[],[]) + && _MoreData ) { + $clen *= 2; + } + my( %info ); + @info{ qw( LastWrite CntSubKeys CntValues SecurityLen + MaxValDataLen MaxSubKeyLen MaxSubClassLen MaxValNameLen ) + }= ( $time, $nkeys, $nvals, $xsec, + $xdata, $xkey, $xcls, $xname ); + if( @_ ) { + my( %check ); + @check{keys(%info)}= keys(%info); + my( @err )= grep( ! $check{$_}, @_ ); + if( @err ) { + croak "${PACK}::Information- Invalid info requested (@err)"; + } + return @info{@_}; + } else { + return %info; + } +} + + +sub Delimiter +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + $self= $RegObj unless ref($self); + my( $oldDelim )= $self->{DELIM}; + if( 1 == @_ && "" ne "$_[0]" ) { + delete $self->{MEMBERS}; + delete $self->{MEMBHASH}; + $self->{DELIM}= "$_[0]"; + } elsif( 0 != @_ ) { + croak "Usage: \$oldDelim= \$key->Delimiter(\$newDelim);"; + } + return $oldDelim; +} + + +sub Handle +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$handle= \$key->Handle;"; + $self= $RegObj unless ref($self); + return $self->{HANDLE}; +} + + +sub Path +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$path= \$key->Path;"; + my $delim= $self->{DELIM}; + $self= $RegObj unless ref($self); + if( "" eq $self->{MACHINE} ) { + return( $delim . join( $delim, @{$self->{PATH}} ) . $delim ); + } else { + return( $delim x 2 + . join( $delim, $self->{MACHINE}, @{$self->{PATH}} ) + . $delim ); + } +} + + +sub _Path +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$arrRef= \$key->_Path;"; + $self= $RegObj unless ref($self); + return $self->{PATH}; +} + + +sub Machine +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$machine= \$key->Machine;"; + $self= $RegObj unless ref($self); + return $self->{MACHINE}; +} + + +sub Access +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$access= \$key->Access;"; + $self= $RegObj unless ref($self); + return $self->{ACCESS}; +} + + +sub OS_Delimiter +{ + my $self= shift(@_); + @_ and croak "Usage: \$backslash= \$key->OS_Delimiter;"; + return $self->{OS_DELIM}; +} + + +sub _Roots +{ + my $self= shift(@_); + $self= tied(%$self) if ref($self) && tied(%$self); + @_ and croak "Usage: \$varName= \$key->_Roots;"; + $self= $RegObj unless ref($self); + return $self->{ROOTS}; +} + + +sub Roots +{ + my $self= shift(@_); + $self= tied(%$self) if ref($self) && tied(%$self); + @_ and croak "Usage: \$hashRef= \$key->Roots;"; + $self= $RegObj unless ref($self); + return eval "\\%$self->{ROOTS}"; +} + + +sub TIEHASH +{ + my( $this )= shift(@_); + $this= tied(%$this) if ref($this) && tied(%$this); + my( $key )= @_; + if( 1 == @_ && ref($key) && "$key" =~ /=/ ) { + return $key; # $key is already an object (blessed reference). + } + return $this->new( @_ ); +} + + +sub Tie +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( $hRef )= @_; + if( 1 != @_ || ! ref($hRef) || "$hRef" !~ /(^|=)HASH\(/ ) { + croak "Usage: \$key->Tie(\\\%hash);"; + } + return tie %$hRef, ref($self), $self; +} + + +sub TiedRef +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $hRef= @_ ? shift(@_) : {}; + return () if ! defined($self); + $self->Tie($hRef); + bless $hRef, ref($self); + return $hRef; +} + + +sub _Flags +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlags= $self->{FLAGS}; + if( 1 == @_ ) { + $self->{FLAGS}= shift(@_); + } elsif( 0 != @_ ) { + croak "Usage: \$oldBits= \$key->_Flags(\$newBits);"; + } + return $oldFlags; +} + + +sub ArrayValues +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_ArrVal == ( $Flag_ArrVal & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + $self->{FLAGS} |= $Flag_ArrVal; + } else { + $self->{FLAGS} &= ~( $Flag_ArrVal | $Flag_TieVal ); + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->ArrayValues(\$newBool);"; + } + return $oldFlag; +} + + +sub TieValues +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_TieVal == ( $Flag_TieVal & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + croak "${PACK}->TieValues cannot be enabled with this version"; + $self->{FLAGS} |= $Flag_TieVal; + } else { + $self->{FLAGS} &= ~$Flag_TieVal; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->TieValues(\$newBool);"; + } + return $oldFlag; +} + + +sub FastDelete +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_FastDel == ( $Flag_FastDel & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + $self->{FLAGS} |= $Flag_FastDel; + } else { + $self->{FLAGS} &= ~$Flag_FastDel; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->FastDelete(\$newBool);"; + } + return $oldFlag; +} + + +sub SplitMultis +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_Split == ( $Flag_Split & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + $self->{FLAGS} |= $Flag_Split; + } else { + $self->{FLAGS} &= ~$Flag_Split; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->SplitMultis(\$newBool);"; + } + return $oldFlag; +} + + +sub DWordsToHex +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_HexDWord == ( $Flag_HexDWord & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + $self->{FLAGS} |= $Flag_HexDWord; + } else { + $self->{FLAGS} &= ~$Flag_HexDWord; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->DWordsToHex(\$newBool);"; + } + return $oldFlag; +} + + +sub FixSzNulls +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_FixNulls == ( $Flag_FixNulls & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + $self->{FLAGS} |= $Flag_FixNulls; + } else { + $self->{FLAGS} &= ~$Flag_FixNulls; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->FixSzNulls(\$newBool);"; + } + return $oldFlag; +} + + +sub DualTypes +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_DualTyp == ( $Flag_DualTyp & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + croak "${PACK}->DualTypes cannot be enabled since ", + "SetDualVar module not installed" + unless $_SetDualVar; + $self->{FLAGS} |= $Flag_DualTyp; + } else { + $self->{FLAGS} &= ~$Flag_DualTyp; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->DualTypes(\$newBool);"; + } + return $oldFlag; +} + + +sub DualBinVals +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $oldFlag= $Flag_DualBin == ( $Flag_DualBin & $self->{FLAGS} ); + if( 1 == @_ ) { + my $bool= shift(@_); + if( $bool ) { + croak "${PACK}->DualBinVals cannot be enabled since ", + "SetDualVar module not installed" + unless $_SetDualVar; + $self->{FLAGS} |= $Flag_DualBin; + } else { + $self->{FLAGS} &= ~$Flag_DualBin; + } + } elsif( 0 != @_ ) { + croak "Usage: \$oldBool= \$key->DualBinVals(\$newBool);"; + } + return $oldFlag; +} + + +sub GetOptions +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my( $opt, $meth ); + if( ! @_ || 1 == @_ && "HASH" eq ref($_[0]) ) { + my $href= @_ ? $_[0] : {}; + foreach $opt ( grep !/^Allow/, @_opt_subs ) { + $meth= $_opt_subs{$opt}; + $href->{$opt}= $self->$meth(); + } + return @_ ? $self : $href; + } + my @old; + foreach $opt ( @_ ) { + $meth= $_opt_subs{$opt}; + if( defined $meth ) { + if( $opt eq "AllowLoad" || $opt eq "AllowSave" ) { + croak "${PACK}->GetOptions: Getting current setting of $opt ", + "not supported in this release"; + } + push( @old, $self->$meth() ); + } else { + croak "${PACK}->GetOptions: Invalid option ($opt) ", + "not one of ( ", join(" ",grep !/^Allow/, @_opt_subs), " )"; + } + } + return wantarray ? @old : $old[-1]; +} + + +sub SetOptions +{ + my $self= shift(@_); + # Don't get object if hash ref so "ref" returns original ref. + my( $opt, $meth, @old ); + while( @_ ) { + $opt= shift(@_); + $meth= $_opt_subs{$opt}; + if( ! @_ ) { + croak "${PACK}->SetOptions: Option value missing ", + "after option name ($opt)"; + } elsif( defined $meth ) { + push( @old, $self->$meth( shift(@_) ) ); + } elsif( $opt eq substr("reference",0,length($opt)) ) { + shift(@_) if @_; + push( @old, $self ); + } else { + croak "${PACK}->SetOptions: Invalid option ($opt) ", + "not one of ( @_opt_subs )"; + } + } + return wantarray ? @old : $old[-1]; +} + + +sub _parseTiedEnt +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $ent= shift(@_); + my $delim= shift(@_); + my $dlen= length( $delim ); + my $parent= @_ ? shift(@_) : 0; + my $off; + if( $delim x 2 eq substr($ent,0,2*$dlen) && "NONE" eq $self->Handle ) { + if( 0 <= ( $off= index( $ent, $delim x 2, 2*$dlen ) ) ) { + return( substr( $ent, 0, $off ), substr( $ent, 2*$dlen+$off ) ); + } elsif( $delim eq substr($ent,-$dlen) ) { + return( substr($ent,0,-$dlen) ); + } elsif( 2*$dlen <= ( $off= rindex( $ent, $delim ) ) ) { + return( substr( $ent, 0, $off ), + undef, substr( $ent, $dlen+$off ) ); + } elsif( $parent ) { + return(); + } else { + return( $ent ); + } + } elsif( $delim eq substr($ent,0,$dlen) && "NONE" ne $self->Handle ) { + return( undef, substr($ent,$dlen) ); + } elsif( $self->{MEMBERS} && $self->_MembersHash->{$ent} ) { + return( substr($ent,0,-$dlen) ); + } elsif( 0 <= ( $off= index( $ent, $delim x 2 ) ) ) { + return( substr( $ent, 0, $off ), substr( $ent, 2*$dlen+$off ) ); + } elsif( $delim eq substr($ent,-$dlen) ) { + if( $parent + && 0 <= ( $off= rindex( $ent, $delim, length($ent)-2*$dlen ) ) ) { + return( substr($ent,0,$off), + undef, undef, substr($ent,$dlen+$off,-$dlen) ); + } else { + return( substr($ent,0,-$dlen) ); + } + } elsif( 0 <= ( $off= rindex( $ent, $delim ) ) ) { + return( + substr( $ent, 0, $off ), undef, substr( $ent, $dlen+$off ) ); + } else { + return( undef, undef, $ent ); + } +} + + +sub _FetchValue +{ + my $self= shift( @_ ); + my( $val, $createKey )= @_; + my( $data, $type ); + if( ( $data, $type )= $self->GetValue( $val ) ) { + return $self->ArrayValues ? [ $data, $type ] + : wantarray ? ( $data, $type ) + : $data; + } elsif( $createKey and $data= $self->new($val) ) { + return $data->TiedRef; + } else { + return (); + } +} + + +sub FETCH +{ + my $self= shift(@_); + my $ent= shift(@_); + my $delim= $self->Delimiter; + my( $key, $val, $ambig )= $self->_parseTiedEnt( $ent, $delim, 0 ); + my $sub; + if( defined($key) ) { + if( defined($self->{MEMBHASH}) + && $self->{MEMBHASH}->{$key.$delim} + && 0 <= index($key,$delim) ) { + return () + unless $sub= $self->new( $key, + {"Delimiter"=>$self->OS_Delimiter} ); + $sub->Delimiter($delim); + } else { + return () + unless $sub= $self->new( $key ); + } + } else { + $sub= $self; + } + if( defined($val) ) { + return $sub->_FetchValue( $val ); + } elsif( ! defined($ambig) ) { + return $sub->TiedRef; + } elsif( defined($key) ) { + return $sub->FETCH( $ambig ); + } else { + return $sub->_FetchValue( $ambig, "" ne $ambig ); + } +} + + +sub _FetchOld +{ + my( $self, $key )= @_; + my $old= $self->FETCH($key); + if( $old ) { + my $copy= {}; + %$copy= %$old; + return $copy; + } + # return $^E; + return _Err; +} + + +sub DELETE +{ + my $self= shift(@_); + my $ent= shift(@_); + my $delim= $self->Delimiter; + my( $key, $val, $ambig, $subkey )= $self->_parseTiedEnt( $ent, $delim, 1 ); + my $sub; + my $fast= defined(wantarray) ? $self->FastDelete : 2; + my $old= 1; # Value returned if FastDelete is set. + if( defined($key) + && ( defined($val) || defined($ambig) || defined($subkey) ) ) { + return () + unless $sub= $self->new( $key ); + } else { + $sub= $self; + } + if( defined($val) ) { + $old= $sub->GetValue($val) || _Err unless 2 <= $fast; + $sub->RegDeleteValue( $val ); + } elsif( defined($subkey) ) { + $old= $sub->_FetchOld( $subkey.$delim ) unless $fast; + $sub->RegDeleteKey( $subkey ); + } elsif( defined($ambig) ) { + if( defined($key) ) { + $old= $sub->DELETE($ambig); + } else { + $old= $sub->GetValue($ambig) || _Err unless 2 <= $fast; + if( defined( $old ) ) { + $sub->RegDeleteValue( $ambig ); + } else { + $old= $sub->_FetchOld( $ambig.$delim ) unless $fast; + $sub->RegDeleteKey( $ambig ); + } + } + } elsif( defined($key) ) { + $old= $sub->_FetchOld( $key.$delim ) unless $fast; + $sub->RegDeleteKey( $key ); + } else { + croak "${PACK}->DELETE: Key ($ent) can never be deleted"; + } + return $old; +} + + +sub SetValue +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + my $name= shift(@_); + my $data= shift(@_); + my( $type )= @_; + my $size; + if( ! defined($type) ) { + if( "ARRAY" eq ref($data) ) { + croak "${PACK}->SetValue: Value is array reference but ", + "no data type given" + unless 2 == @$data; + ( $data, $type )= @$data; + } else { + $type= REG_SZ; + } + } + $type= _constant($type,"registry value data type") if $type =~ /^REG_/; + if( REG_MULTI_SZ == $type && "ARRAY" eq ref($data) ) { + $data= join( "\0", @$data ) . "\0\0"; + ## $data= pack( "a*" x (1+@$data), map( $_."\0", @$data, "" ) ); + } elsif( ( REG_SZ == $type || REG_EXPAND_SZ == $type ) + && $self->FixSzNulls ) { + $data .= "\0" unless "\0" eq substr($data,0,-1); + } elsif( REG_DWORD == $type && $data =~ /^0x[0-9a-fA-F]{3,}$/ ) { + $data= pack( "L", hex($data) ); + # We could to $data=pack("L",$data) for REG_DWORD but I see + # no nice way to always destinguish when to do this or not. + } + return $self->RegSetValueEx( $name, 0, $type, $data, length($data) ); +} + + +sub StoreKey +{ + my $this= shift(@_); + $this= tied(%$this) if ref($this) && tied(%$this); + my $subKey= shift(@_); + my $data= shift(@_); + my $ent; + my $self; + if( ! ref($data) || "$data" !~ /(^|=)HASH/ ) { + croak "${PACK}->StoreKey: For ", $this->Path.$subKey, ",\n", + " subkey data must be a HASH reference"; + } + if( defined( $$data{""} ) && "HASH" eq ref($$data{""}) ) { + $self= $this->CreateKey( $subKey, delete $$data{""} ); + } else { + $self= $this->CreateKey( $subKey ); + } + return () if ! defined($self); + foreach $ent ( keys(%$data) ) { + return () + unless $self->STORE( $ent, $$data{$ent} ); + } + return $self; +} + + +# = { "" => {OPT=>VAL}, "val"=>[], "key"=>{} } creates a new key +# = "string" creates a new REG_SZ value +# = [ data, type ] creates a new value +sub STORE +{ + my $self= shift(@_); + my $ent= shift(@_); + my $data= shift(@_); + my $delim= $self->Delimiter; + my( $key, $val, $ambig, $subkey )= $self->_parseTiedEnt( $ent, $delim, 1 ); + my $sub; + if( defined($key) + && ( defined($val) || defined($ambig) || defined($subkey) ) ) { + return () + unless $sub= $self->new( $key ); + } else { + $sub= $self; + } + if( defined($val) ) { + croak "${PACK}->STORE: For ", $sub->Path.$delim.$val, ",\n", + " value data cannot be a HASH reference" + if ref($data) && "$data" =~ /(^|=)HASH/; + $sub->SetValue( $val, $data ); + } elsif( defined($subkey) ) { + croak "${PACK}->STORE: For ", $sub->Path.$subkey.$delim, ",\n", + " subkey data must be a HASH reference" + unless ref($data) && "$data" =~ /(^|=)HASH/; + $sub->StoreKey( $subkey, $data ); + } elsif( defined($ambig) ) { + if( ref($data) && "$data" =~ /(^|=)HASH/ ) { + $sub->StoreKey( $ambig, $data ); + } else { + $sub->SetValue( $ambig, $data ); + } + } elsif( defined($key) ) { + croak "${PACK}->STORE: For ", $sub->Path.$key.$delim, ",\n", + " subkey data must be a HASH reference" + unless ref($data) && "$data" =~ /(^|=)HASH/; + $sub->StoreKey( $key, $data ); + } else { + croak "${PACK}->STORE: Key ($ent) can never be created nor set"; + } +} + + +sub EXISTS +{ + my $self= shift(@_); + my $ent= shift(@_); + return defined( $self->FETCH($ent) ); +} + + +sub FIRSTKEY +{ + my $self= shift(@_); + my $members= $self->_MemberNames; + $self->{PREVIDX}= 0; + return @{$members} ? $members->[0] : undef; +} + + +sub NEXTKEY +{ + my $self= shift(@_); + my $prev= shift(@_); + my $idx= $self->{PREVIDX}; + my $members= $self->_MemberNames; + if( ! defined($idx) || $prev ne $members->[$idx] ) { + $idx= 0; + while( $idx < @$members && $prev ne $members->[$idx] ) { + $idx++; + } + } + $self->{PREVIDX}= ++$idx; + return $members->[$idx]; +} + + +sub DESTROY +{ + my $self= shift(@_); + return if tied(%$self); + my $unload; + local $@; + eval { $unload= $self->{UNLOADME}; 1 } + or return; + my $debug= $ENV{DEBUG_TIE_REGISTRY}; + if( defined($debug) ) { + if( 1 < $debug ) { + my $hand= $self->Handle; + my $dep= $self->{DEPENDON}; + carp "${PACK} destroying ", $self->Path, " (", + "NONE" eq $hand ? $hand : sprintf("0x%lX",$hand), ")", + defined($dep) ? (" [depends on ",$dep->Path,"]") : (); + } else { + warn "${PACK} destroying ", $self->Path, ".\n"; + } + } + $self->RegCloseKey + unless "NONE" eq $self->Handle; + if( defined($unload) ) { + if( defined($debug) && 1 < $debug ) { + my( $obj, $subKey, $file )= @$unload; + warn "Unloading ", $self->Path, + " (from ", $obj->Path, ", $subKey)...\n"; + } + $self->UnLoad + || warn "Couldn't unload ", $self->Path, ": ", _ErrMsg, "\n"; + ## carp "Never unloaded ${PACK}::Load($$unload[2])"; + } + #delete $self->{DEPENDON}; +} + + +use vars qw( @CreateKey_Opts %CreateKey_Opts %_KeyDispNames ); +@CreateKey_Opts= qw( Access Class Options Delimiter + Disposition Security Volatile Backup ); +@CreateKey_Opts{@CreateKey_Opts}= (1) x @CreateKey_Opts; +%_KeyDispNames= ( REG_CREATED_NEW_KEY() => "REG_CREATED_NEW_KEY", + REG_OPENED_EXISTING_KEY() => "REG_OPENED_EXISTING_KEY" ); + +sub CreateKey +{ + my $self= shift(@_); + my $tied= tied(%$self); + $self= tied(%$self) if $tied; + my( $subKey, $opts )= @_; + my( $sam )= $self->Access; + my( $delim )= $self->Delimiter; + my( $class )= ""; + my( $flags )= 0; + my( $secure )= []; + my( $garb )= []; + my( $result )= \$garb; + my( $handle )= 0; + if( @_ < 1 || 2 < @_ + || 2 == @_ && "HASH" ne ref($opts) ) { + croak "Usage: \$new= \$old->CreateKey( \$subKey, {OPT=>VAL,...} );\n", + " options: @CreateKey_Opts\nCalled"; + } + if( defined($opts) ) { + $sam= $opts->{"Access"} if defined($opts->{"Access"}); + $class= $opts->{Class} if defined($opts->{Class}); + $flags= $opts->{Options} if defined($opts->{Options}); + $delim= $opts->{"Delimiter"} if defined($opts->{"Delimiter"}); + $secure= $opts->{Security} if defined($opts->{Security}); + if( defined($opts->{Disposition}) ) { + "SCALAR" eq ref($opts->{Disposition}) + or croak "${PACK}->CreateKey option `Disposition'", + " must provide a scalar reference"; + $result= $opts->{Disposition}; + } + if( 0 == $flags ) { + $flags |= REG_OPTION_VOLATILE + if defined($opts->{Volatile}) && $opts->{Volatile}; + $flags |= REG_OPTION_BACKUP_RESTORE + if defined($opts->{Backup}) && $opts->{Backup}; + } + } + my $subPath= ref($subKey) ? $subKey : $self->_split($subKey,$delim); + $subKey= join( $self->OS_Delimiter, @$subPath ); + $self->RegCreateKeyEx( $subKey, 0, $class, $flags, $sam, + $secure, $handle, $$result ) + or return (); + if( ! ref($$result) && $self->DualTypes ) { + $$result= _DualVal( \%_KeyDispNames, $$result ); + } + my $new= $self->_new( $handle, [ @{$self->_Path}, @{$subPath} ] ); + $new->{ACCESS}= $sam; + $new->{DELIM}= $delim; + $new= $new->TiedRef if $tied; + return $new; +} + + +use vars qw( $Load_Cnt @Load_Opts %Load_Opts ); +$Load_Cnt= 0; +@Load_Opts= qw(NewSubKey); +@Load_Opts{@Load_Opts}= (1) x @Load_Opts; + +sub Load +{ + my $this= shift(@_); + my $tied= ref($this) && tied(%$this); + $this= tied(%$this) if $tied; + my( $file, $subKey, $opts )= @_; + if( 2 == @_ && "HASH" eq ref($subKey) ) { + $opts= $subKey; + undef $subKey; + } + @_ < 1 || 3 < @_ || defined($opts) && "HASH" ne ref($opts) + and croak "Usage: \$key= ", + "${PACK}->Load( \$fileName, [\$newSubKey,] {OPT=>VAL...} );\n", + " options: @Load_Opts @new_Opts\nCalled"; + if( defined($opts) && exists($opts->{NewSubKey}) ) { + $subKey= delete $opts->{NewSubKey}; + } + if( ! defined( $subKey ) ) { + if( "" ne $this->Machine ) { + ( $this )= $this->_connect( [$this->Machine,"LMachine"] ); + } else { + ( $this )= $this->_rootKey( "LMachine" ); # Could also be "Users" + } + $subKey= "PerlTie:$$." . ++$Load_Cnt; + } + $this->RegLoadKey( $subKey, $file ) + or return (); + my $self= $this->new( $subKey, defined($opts) ? $opts : () ); + if( ! defined( $self ) ) { + { my $err= Win32::GetLastError(); + #{ local( $^E ); #} + $this->RegUnLoadKey( $subKey ) or carp + "Can't unload $subKey from ", $this->Path, ": ", _ErrMsg, "\n"; + Win32::SetLastError($err); + } + return (); + } + $self->{UNLOADME}= [ $this, $subKey, $file ]; + $self= $self->TiedRef if $tied; + return $self; +} + + +sub UnLoad +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + @_ and croak "Usage: \$key->UnLoad;"; + my $unload= $self->{UNLOADME}; + "ARRAY" eq ref($unload) + or croak "${PACK}->UnLoad called on a key which was not Load()ed"; + my( $obj, $subKey, $file )= @$unload; + $self->RegCloseKey; + return Win32API::Registry::RegUnLoadKey( $obj->Handle, $subKey ); +} + + +sub AllowSave +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + return $self->AllowPriv( "SeBackupPrivilege", @_ ); +} + + +sub AllowLoad +{ + my $self= shift(@_); + $self= tied(%$self) if tied(%$self); + return $self->AllowPriv( "SeRestorePrivilege", @_ ); +} + + +# RegNotifyChangeKeyValue( hKey, bWatchSubtree, iNotifyFilter, hEvent, bAsync ) + + +sub RegCloseKey { my $self= shift(@_); + Win32API::Registry::RegCloseKey $self->Handle, @_; } +sub RegConnectRegistry { my $self= shift(@_); + Win32API::Registry::RegConnectRegistry @_; } +sub RegCreateKey { my $self= shift(@_); + Win32API::Registry::RegCreateKey $self->Handle, @_; } +sub RegCreateKeyEx { my $self= shift(@_); + Win32API::Registry::RegCreateKeyEx $self->Handle, @_; } +sub RegDeleteKey { my $self= shift(@_); + Win32API::Registry::RegDeleteKey $self->Handle, @_; } +sub RegDeleteValue { my $self= shift(@_); + Win32API::Registry::RegDeleteValue $self->Handle, @_; } +sub RegEnumKey { my $self= shift(@_); + Win32API::Registry::RegEnumKey $self->Handle, @_; } +sub RegEnumKeyEx { my $self= shift(@_); + Win32API::Registry::RegEnumKeyEx $self->Handle, @_; } +sub RegEnumValue { my $self= shift(@_); + Win32API::Registry::RegEnumValue $self->Handle, @_; } +sub RegFlushKey { my $self= shift(@_); + Win32API::Registry::RegFlushKey $self->Handle, @_; } +sub RegGetKeySecurity { my $self= shift(@_); + Win32API::Registry::RegGetKeySecurity $self->Handle, @_; } +sub RegLoadKey { my $self= shift(@_); + Win32API::Registry::RegLoadKey $self->Handle, @_; } +sub RegNotifyChangeKeyValue { my $self= shift(@_); + Win32API::Registry::RegNotifyChangeKeyValue $self->Handle, @_; } +sub RegOpenKey { my $self= shift(@_); + Win32API::Registry::RegOpenKey $self->Handle, @_; } +sub RegOpenKeyEx { my $self= shift(@_); + Win32API::Registry::RegOpenKeyEx $self->Handle, @_; } +sub RegQueryInfoKey { my $self= shift(@_); + Win32API::Registry::RegQueryInfoKey $self->Handle, @_; } +sub RegQueryMultipleValues { my $self= shift(@_); + Win32API::Registry::RegQueryMultipleValues $self->Handle, @_; } +sub RegQueryValue { my $self= shift(@_); + Win32API::Registry::RegQueryValue $self->Handle, @_; } +sub RegQueryValueEx { my $self= shift(@_); + Win32API::Registry::RegQueryValueEx $self->Handle, @_; } +sub RegReplaceKey { my $self= shift(@_); + Win32API::Registry::RegReplaceKey $self->Handle, @_; } +sub RegRestoreKey { my $self= shift(@_); + Win32API::Registry::RegRestoreKey $self->Handle, @_; } +sub RegSaveKey { my $self= shift(@_); + Win32API::Registry::RegSaveKey $self->Handle, @_; } +sub RegSetKeySecurity { my $self= shift(@_); + Win32API::Registry::RegSetKeySecurity $self->Handle, @_; } +sub RegSetValue { my $self= shift(@_); + Win32API::Registry::RegSetValue $self->Handle, @_; } +sub RegSetValueEx { my $self= shift(@_); + Win32API::Registry::RegSetValueEx $self->Handle, @_; } +sub RegUnLoadKey { my $self= shift(@_); + Win32API::Registry::RegUnLoadKey $self->Handle, @_; } +sub AllowPriv { my $self= shift(@_); + Win32API::Registry::AllowPriv @_; } + + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +Win32::TieRegistry - Powerful and easy ways to manipulate a registry +[on Win32 for now]. + +=head1 SYNOPSIS + + use Win32::TieRegistry 0.20 ( UseOptionName=>UseOptionValue[,...] ); + + $Registry->SomeMethodCall(arg1,...); + + $subKey= $Registry->{"Key\\SubKey\\"}; + $valueData= $Registry->{"Key\\SubKey\\\\ValueName"}; + $Registry->{"Key\\SubKey\\"}= { "NewSubKey" => {...} }; + $Registry->{"Key\\SubKey\\\\ValueName"}= "NewValueData"; + $Registry->{"\\ValueName"}= [ pack("fmt",$data), REG_DATATYPE ]; + +=head1 EXAMPLES + + use Win32::TieRegistry( Delimiter=>"#", ArrayValues=>0 ); + $pound= $Registry->Delimiter("/"); + $diskKey= $Registry->{"LMachine/System/Disk/"} + or die "Can't read LMachine/System/Disk key: $^E\n"; + $data= $key->{"/Information"} + or die "Can't read LMachine/System/Disk//Information value: $^E\n"; + $remoteKey= $Registry->{"//ServerA/LMachine/System/"} + or die "Can't read //ServerA/LMachine/System/ key: $^E\n"; + $remoteData= $remoteKey->{"Disk//Information"} + or die "Can't read ServerA's System/Disk//Information value: $^E\n"; + foreach $entry ( keys(%$diskKey) ) { + ... + } + foreach $subKey ( $diskKey->SubKeyNames ) { + ... + } + $diskKey->AllowSave( 1 ); + $diskKey->RegSaveKey( "C:/TEMP/DiskReg", [] ); + +=head1 DESCRIPTION + +The I<Win32::TieRegistry> module lets you manipulate the Registry +via objects [as in "object oriented"] or via tied hashes. But +you will probably mostly use a combination reference, that is, a +reference to a tied hash that has also been made an object so that +you can mix both access methods [as shown above]. + +If you did not get this module as part of L<libwin32>, you might +want to get a recent version of L<libwin32> from CPAN which should +include this module and the I<Win32API::Registry> module that it +uses. + +Skip to the L<SUMMARY> section if you just want to dive in and start +using the Registry from Perl. + +Accessing and manipulating the registry is extremely simple using +I<Win32::TieRegistry>. A single, simple expression can return +you almost any bit of information stored in the Registry. +I<Win32::TieRegistry> also gives you full access to the "raw" +underlying API calls so that you can do anything with the Registry +in Perl that you could do in C. But the "simple" interface has +been carefully designed to handle almost all operations itself +without imposing arbitrary limits while providing sensible +defaults so you can list only the parameters you care about. + +But first, an overview of the Registry itself. + +=head2 The Registry + +The Registry is a forest: a collection of several tree structures. +The root of each tree is a key. These root keys are identified by +predefined constants whose names start with "HKEY_". Although all +keys have a few attributes associated with each [a class, a time +stamp, and security information], the most important aspect of keys +is that each can contain subkeys and can contain values. + +Each subkey has a name: a string which cannot be blank and cannot +contain the delimiter character [backslash: C<'\\'>] nor nul +[C<'\0'>]. Each subkey is also a key and so can contain subkeys +and values [and has a class, time stamp, and security information]. + +Each value has a name: a string which E<can> be blank and E<can> +contain the delimiter character [backslash: C<'\\'>] and any +character except for null, C<'\0'>. Each value also has data +associated with it. Each value's data is a contiguous chunk of +bytes, which is exactly what a Perl string value is so Perl +strings will usually be used to represent value data. + +Each value also has a data type which says how to interpret the +value data. The primary data types are: + +=over + +=item REG_SZ + +A null-terminated string. + +=item REG_EXPAND_SZ + +A null-terminated string which contains substrings consisting of a +percent sign [C<'%'>], an environment variable name, then a percent +sign, that should be replaced with the value associate with that +environment variable. The system does I<not> automatically do this +substitution. + +=item REG_BINARY + +Some arbitrary binary value. You can think of these as being +"packed" into a string. + +If your system has the L<SetDualVar> module installed, +the C<DualBinVals()> option wasn't turned off, and you +fetch a C<REG_BINARY> value of 4 bytes or fewer, then +you can use the returned value in a numeric context to +get at the "unpacked" numeric value. See C<GetValue()> +for more information. + +=item REG_MULTI_SZ + +Several null-terminated strings concatenated together with an +extra trailing C<'\0'> at the end of the list. Note that the list +can include empty strings so use the value's length to determine +the end of the list, not the first occurrence of C<'\0\0'>. +It is best to set the C<SplitMultis()> option so I<Win32::TieRegistry> +will split these values into an array of strings for you. + +=item REG_DWORD + +A long [4-byte] integer value. These values are expected either +packed into a 4-character string or as a hex string of E<more than> +4 characters [but I<not> as a numeric value, unfortunately, as there is +no sure way to tell a numeric value from a packed 4-byte string that +just happens to be a string containing a valid numeric value]. + +How such values are returned depends on the C<DualBinVals()> and +C<DWordsToHex()> options. See C<GetValue()> for details. + +=back + +In the underlying Registry calls, most places which take a +subkey name also allow you to pass in a subkey "path" -- a +string of several subkey names separated by the delimiter +character, backslash [C<'\\'>]. For example, doing +C<RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\DISK",...)> is much +like opening the C<"SYSTEM"> subkey of C<HKEY_LOCAL_MACHINE>, +then opening its C<"DISK"> subkey, then closing the C<"SYSTEM"> +subkey. + +All of the I<Win32::TieRegistry> features allow you to use your +own delimiter in place of the system's delimiter, [C<'\\'>]. In +most of our examples we will use a forward slash [C<'/'>] as our +delimiter as it is easier to read and less error prone to use when +writing Perl code since you have to type two backslashes for each +backslash you want in a string. Note that this is true even when +using single quotes -- C<'\\HostName\LMachine\'> is an invalid +string and must be written as C<'\\\\HostName\\LMachine\\'>. + +You can also connect to the registry of other computers on your +network. This will be discussed more later. + +Although the Registry does not have a single root key, the +I<Win32::TieRegistry> module creates a virtual root key for you +which has all of the I<HKEY_*> keys as subkeys. + +=head2 Tied Hashes Documentation + +Before you can use a tied hash, you must create one. One way to +do that is via: + + use Win32::TieRegistry ( TiedHash => '%RegHash' ); + +which exports a C<%RegHash> variable into your package and ties it +to the virtual root key of the Registry. An alternate method is: + + my %RegHash; + use Win32::TieRegistry ( TiedHash => \%RegHash ); + +There are also several ways you can tie a hash variable to any +other key of the Registry, which are discussed later. + +Note that you will most likely use C<$Registry> instead of using +a tied hash. C<$Registry> is a reference to a hash that has +been tied to the virtual root of your computer's Registry [as if, +C<$Registry= \%RegHash>]. So you would use C<$Registry-E<gt>{Key}> +rather than C<$RegHash{Key}> and use C<keys %{$Registry}> rather +than C<keys %RegHash>, for example. + +For each hash which has been tied to a Registry key, the Perl +C<keys> function will return a list containing the name of each +of the key's subkeys with a delimiter character appended to it and +containing the name of each of the key's values with a delimiter +prepended to it. For example: + + keys( %{ $Registry->{"HKEY_CLASSES_ROOT\\batfile\\"} } ) + +might yield the following list value: + + ( "DefaultIcon\\", # The subkey named "DefaultIcon" + "shell\\", # The subkey named "shell" + "shellex\\", # The subkey named "shellex" + "\\", # The default value [named ""] + "\\EditFlags" ) # The value named "EditFlags" + +For the virtual root key, short-hand subkey names are used as +shown below. You can use the short-hand name, the regular +I<HKEY_*> name, or any numeric value to access these keys, but +the short-hand names are all that will be returned by the C<keys> +function. + +=over + +=item "Classes" for HKEY_CLASSES_ROOT + +Contains mappings between file name extensions and the uses +for such files along with configuration information for COM +[MicroSoft's Common Object Model] objects. Usually a link to +the C<"SOFTWARE\\Classes"> subkey of the C<HKEY_LOCAL_MACHINE> +key. + +=item "CUser" for HKEY_CURRENT_USER + +Contains information specific to the currently logged-in user. +Mostly software configuration information. Usually a link to +a subkey of the C<HKEY_USERS> key. + +=item "LMachine" for HKEY_LOCAL_MACHINE + +Contains all manner of information about the computer. + +=item "Users" for HKEY_USERS + +Contains one subkey, C<".DEFAULT">, which gets copied to a new +subkey whenever a new user is added. Also contains a subkey for +each user of the system, though only those for active users +[usually only one] are loaded at any given time. + +=item "PerfData" for HKEY_PERFORMANCE_DATA + +Used to access data about system performance. Access via this key +is "special" and all but the most carefully constructed calls will +fail, usually with C<ERROR_INSUFFICIENT_BUFFER>. For example, you +can't enumerate key names without also enumerating values which +require huge buffers but the exact buffer size required cannot be +determined beforehand because C<RegQueryInfoKey()> E<always> fails +with C<ERROR_INSUFFICIENT_BUFFER> for C<HKEY_PERFORMANCE_DATA> no +matter how it is called. So it is currently not very useful to +tie a hash to this key. You can use it to create an object to use +for making carefully constructed calls to the underlying Reg*() +routines. + +=item "CConfig" for HKEY_CURRENT_CONFIG + +Contains minimal information about the computer's current +configuration that is required very early in the boot process. +For example, setting for the display adapter such as screen +resolution and refresh rate are found in here. + +=item "DynData" for HKEY_DYN_DATA + +Dynamic data. We have found no documentation for this key. + +=back + +A tied hash is much like a regular hash variable in Perl -- you give +it a key string inside braces, [C<{> and C<}>], and it gives you +back a value [or lets you set a value]. For I<Win32::TieRegistry> +hashes, there are two types of values that will be returned. + +=over + +=item SubKeys + +If you give it a string which represents a subkey, then it will +give you back a reference to a hash which has been tied to that +subkey. It can't return the hash itself, so it returns a +reference to it. It also blesses that reference so that it is +also an object so you can use it to call method functions. + +=item Values + +If you give it a string which is a value name, then it will give +you back a string which is the data for that value. Alternately, +you can request that it give you both the data value string and +the data value type [we discuss how to request this later]. In +this case, it would return a reference to an array where the value +data string is element C<[0]> and the value data type is element +C<[1]>. + +=back + +The key string which you use in the tied hash must be interpreted +to determine whether it is a value name or a key name or a path +that combines several of these or even other things. There are +two simple rules that make this interpretation easy and +unambiguous: + + Put a delimiter after each key name. + Put a delimiter in front of each value name. + +Exactly how the key string will be intepreted is governed by the +following cases, in the order listed. These cases are designed +to "do what you mean". Most of the time you won't have to think +about them, especially if you follow the two simple rules above. +After the list of cases we give several examples which should be +clear enough so feel free to skip to them unless you are worried +about the details. + +=over + +=item Remote machines + +If the hash is tied to the virtual root of the registry [or the +virtual root of a remote machine's registry], then we treat hash +key strings which start with the delimiter character specially. + +If the hash key string starts with two delimiters in a row, then +those should be immediately followed by the name of a remote +machine whose registry we wish to connect to. That can be +followed by a delimiter and more subkey names, etc. If the +machine name is not following by anything, then a virtual root +for the remote machine's registry is created, a hash is tied to +it, and a reference to that hash it is returned. + +=item Hash key string starts with the delimiter + +If the hash is tied to a virtual root key, then the leading +delimiter is ignored. It should be followed by a valid Registry +root key name [either a short-hand name like C<"LMachine">, an +I<HKEY_*> value, or a numeric value]. This alternate notation is +allowed in order to be more consistant with the C<Open()> method +function. + +For all other Registry keys, the leading delimiter indicates +that the rest of the string is a value name. The leading +delimiter is stripped and the rest of the string [which can +be empty and can contain more delimiters] is used as a value +name with no further parsing. + +=item Exact match with direct subkey name followed by delimiter + +If you have already called the Perl C<keys> function on the tied +hash [or have already called C<MemberNames> on the object] and the +hash key string exactly matches one of the strings returned, then +no further parsing is done. In other words, if the key string +exactly matches the name of a direct subkey with a delimiter +appended, then a reference to a hash tied to that subkey is +returned [but only if C<keys> or C<MemberNames> has already +been called for that tied hash]. + +This is only important if you have selected a delimiter other than +the system default delimiter and one of the subkey names contains +the delimiter you have chosen. This rule allows you to deal with +subkeys which contain your chosen delimiter in their name as long +as you only traverse subkeys one level at a time and always +enumerate the list of members before doing so. + +The main advantage of this is that Perl code which recursively +traverses a hash will work on hashes tied to Registry keys even if +a non-default delimiter has been selected. + +=item Hash key string contains two delimiters in a row + +If the hash key string contains two [or more] delimiters in a row, +then the string is split between the first pair of delimiters. +The first part is interpreted as a subkey name or a path of subkey +names separated by delimiters and with a trailing delimiter. The +second part is interpreted as a value name with one leading +delimiter [any extra delimiters are considered part of the value +name]. + +=item Hash key string ends with a delimiter + +If the key string ends with a delimiter, then it is treated +as a subkey name or path of subkey names separated by delimiters. + +=item Hash key string contains a delimiter + +If the key string contains a delimiter, then it is split after +the last delimiter. The first part is treated as a subkey name or +path of subkey names separated by delimiters. The second part +is ambiguous and is treated as outlined in the next item. + +=item Hash key string contains no delimiters + +If the hash key string contains no delimiters, then it is ambiguous. + +If you are reading from the hash [fetching], then we first use the +key string as a value name. If there is a value with a matching +name in the Registry key which the hash is tied to, then the value +data string [and possibly the value data type] is returned. +Otherwise, we retry by using the hash key string as a subkey name. +If there is a subkey with a matching name, then we return a +reference to a hash tied to that subkey. Otherwise we return +C<undef>. + +If you are writing to the hash [storing], then we use the key +string as a subkey name only if the value you are storing is a +reference to a hash value. Otherwise we use the key string as +a value name. + +=back + +=head3 Examples + +Here are some examples showing different ways of accessing Registry +information using references to tied hashes: + +=over + +=item Canonical value fetch + + $tip18= $Registry->{"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\" + . 'Windows\\CurrentVersion\\Explorer\\Tips\\\\18'}; + +Should return the text of important tip number 18. Note that two +backslashes, C<"\\">, are required to get a single backslash into +a Perl double-quoted or single-qouted string. Note that C<"\\"> +is appended to each key name [C<"HKEY_LOCAL_MACHINE"> through +C<"Tips">] and C<"\\"> is prepended to the value name, C<"18">. + +=item Changing your delimiter + + $Registry->Delimiter("/"); + $tip18= $Registry->{"HKEY_LOCAL_MACHINE/Software/Microsoft/" + . 'Windows/CurrentVersion/Explorer/Tips//18'}; + +This usually makes things easier to read when working in Perl. +All remaining examples will assume the delimiter has been changed +as above. + +=item Using intermediate keys + + $ms= $Registry->{"LMachine/Software/Microsoft/"}; + $tips= $ms->{"Windows/CurrentVersion/Explorer/Tips/"}; + $tip18= $winlogon->{"/18"}; + +Same as above but opens more keys into the Registry which lets you +efficiently re-access those intermediate keys. This is slightly +less efficient if you never reuse those intermediate keys. + +=item Chaining in a single statement + + $tip18= $Registry->{"LMachine/Software/Microsoft/"}-> + {"Windows/CurrentVersion/Explorer/Tips/"}->{"/18"}; + +Like above, this creates intermediate key objects then uses +them to access other data. Once this statement finishes, the +intermediate key objects are destroyed. Several handles into +the Registry are opened and closed by this statement so it is +less efficient but there are times when this will be useful. + +=item Even less efficient example of chaining + + $tip18= $Registry->{"LMachine/Software/Microsoft"}-> + {"Windows/CurrentVersion/Explorer/Tips"}->{"/18"}; + +Because we left off the trailing delimiters, I<Win32::TieRegistry> +doesn't know whether final names, C<"Microsoft"> and C<"Tips">, +are subkey names or value names. So this statement ends up +executing the same code as the next one. + +=item What the above really does + + $tip18= $Registry->{"LMachine/Software/"}->{"Microsoft"}-> + {"Windows/CurrentVersion/Explorer/"}->{"Tips"}->{"/18"}; + +With more chains to go through, more temporary objects are created +and later destroyed than in our first chaining example. Also, +when C<"Microsoft"> is looked up, I<Win32::TieRegistry> first +tries to open it as a value and fails then tries it as a subkey. +The same is true for when it looks up C<"Tips">. + +=item Getting all of the tips + + $tips= $Registry->{"LMachine/Software/Microsoft/"}-> + {"Windows/CurrentVersion/Explorer/Tips/"} + or die "Can't find the Windows tips: $^E\n"; + foreach( keys %$tips ) { + print "$_: ", $tips->{$_}, "\n"; + } + +First notice that we actually check for failure for the first +time. We are assuming that the C<"Tips"> key contains no subkeys. +Otherwise the C<print> statement would show something like +C<"Win32::TieRegistry=HASH(0xc03ebc)"> for each subkey. + +The output from the above code will start something like: + + /0: If you don't know how to do something,[...] + +=back + +=head3 Deleting items + +You can use the Perl C<delete> function to delete a value from a +Registry key or to delete a subkey as long that subkey contains +no subkeys of its own. See L<More Examples>, below, for more +information. + +=head3 Storing items + +You can use the Perl assignment operator [C<=>] to create new +keys, create new values, or replace values. The values you store +should be in the same format as the values you would fetch from a +tied hash. For example, you can use a single assignment statement +to copy an entire Registry tree. The following statement: + + $Registry->{"LMachine/Software/Classes/Tie_Registry/"}= + $Registry->{"LMachine/Software/Classes/batfile/"}; + +creates a C<"Tie_Registry"> subkey under the C<"Software\\Classes"> +subkey of the C<HKEY_LOCAL_MACHINE> key. Then it populates it +with copies of all of the subkeys and values in the C<"batfile"> +subkey and all of its subkeys. Note that you need to have +called C<$Registry-E<gt>ArrayValues(1)> for the proper value data +type information to be copied. Note also that this release of +I<Win32::TieRegistry> does not copy key attributes such as class +name and security information [this is planned for a future release]. + +The following statement creates a whole subtree in the Registry: + + $Registry->{"LMachine/Software/FooCorp/"}= { + "FooWriter/" => { + "/Version" => "4.032", + "Startup/" => { + "/Title" => "Foo Writer Deluxe ][", + "/WindowSize" => [ pack("LL",$wid,$ht), "REG_BINARY" ], + "/TaskBarIcon" => [ "0x0001", "REG_DWORD" ], + }, + "Compatibility/" => { + "/AutoConvert" => "Always", + "/Default Palette" => "Windows Colors", + }, + }, + "/License", => "0123-9C8EF1-09-FC", + }; + +Note that all but the last Registry key used on the left-hand +side of the assignment [that is, "LMachine/Software/" but not +"FooCorp/"] must already exist for this statement to succeed. + +By using the leading a trailing delimiters on each subkey name and +value name, I<Win32::TieRegistry> will tell you if you try to assign +subkey information to a value or visa-versa. + +=head3 More examples + +=over + +=item Adding a new tip + + $tips= $Registry->{"LMachine/Software/Microsoft/"}-> + {"Windows/CurrentVersion/Explorer/Tips/"} + or die "Can't find the Windows tips: $^E\n"; + $tips{'/186'}= "Be very careful when making changes to the Registry!"; + +=item Deleting our new tip + + $tips= $Registry->{"LMachine/Software/Microsoft/"}-> + {"Windows/CurrentVersion/Explorer/Tips/"} + or die "Can't find the Windows tips: $^E\n"; + $tip186= delete $tips{'/186'}; + +Note that Perl's C<delete> function returns the value that was deleted. + +=item Adding a new tip differently + + $Registry->{"LMachine/Software/Microsoft/" . + "Windows/CurrentVersion/Explorer/Tips//186"}= + "Be very careful when making changes to the Registry!"; + +=item Deleting differently + + $tip186= delete $Registry->{"LMachine/Software/Microsoft/Windows/" . + "CurrentVersion/Explorer/Tips//186"}; + +Note that this only deletes the tail of what we looked up, the +C<"186"> value, not any of the keys listed. + +=item Deleting a key + +WARNING: The following code will delete all information about the +current user's tip preferences. Actually executing this command +would probably cause the user to see the Welcome screen the next +time they log in and may cause more serious problems. This +statement is shown as an example only and should not be used when +experimenting. + + $tips= delete $Registry->{"CUser/Software/Microsoft/Windows/" . + "CurrentVersion/Explorer/Tips/"}; + +This deletes the C<"Tips"> key and the values it contains. The +C<delete> function will return a reference to a hash [not a tied +hash] containing the value names and value data that were deleted. + +The information to be returned is copied from the Registry into a +regular Perl hash before the key is deleted. If the key has many +subkeys, this copying could take a significant amount of memory +and/or processor time. So you can disable this process by calling +the C<FastDelete> member function: + + $prevSetting= $regKey->FastDelete(1); + +which will cause all subsequent delete operations via C<$regKey> +to simply return a true value if they succeed. This optimization +is automatically done if you use C<delete> in a void context. + +=item Technical notes on deleting + +If you use C<delete> to delete a Registry key or value and use +the return value, then I<Win32::TieRegistry> usually looks up the +current contents of that key or value so they can be returned if +the deletion is successful. If the deletion succeeds but the +attempt to lookup the old contents failed, then the return value +of C<delete> will be C<$^E> from the failed part of the operation. + +=item Undeleting a key + + $Registry->{"LMachine/Software/Microsoft/Windows/" . + "CurrentVersion/Explorer/Tips/"}= $tips; + +This adds back what we just deleted. Note that this version of +I<Win32::TieRegistry> will use defaults for the key attributes +[such as class name and security] and will not restore the +previous attributes. + +=item Not deleting a key + +WARNING: Actually executing the following code could cause +serious problems. This statement is shown as an example only and +should not be used when experimenting. + + $res= delete $Registry->{"CUser/Software/Microsoft/Windows/"} + defined($res) || die "Can't delete URL key: $^E\n"; + +Since the "Windows" key should contain subkeys, that C<delete> +statement should make no changes to the Registry, return C<undef>, +and set C<$^E> to "Access is denied". + +=item Not deleting again + + $tips= $Registry->{"CUser/Software/Microsoft/Windows/" . + "CurrentVersion/Explorer/Tips/"}; + delete $tips; + +The Perl C<delete> function requires that its argument be an +expression that ends in a hash element lookup [or hash slice], +which is not the case here. The C<delete> function doesn't +know which hash $tips came from and so can't delete it. + +=back + +=head2 Objects Documentation + +The following member functions are defined for use on +I<Win32::TieRegistry> objects: + +=over + +=item new + +The C<new> method creates a new I<Win32::TieRegistry> object. +C<new> is mostly a synonym for C<Open()> so see C<Open()> below for +information on what arguments to pass in. Examples: + + $machKey= new Win32::TieRegistry "LMachine" + or die "Can't access HKEY_LOCAL_MACHINE key: $^E\n"; + $userKey= Win32::TieRegistry->new("CUser") + or die "Can't access HKEY_CURRENT_USER key: $^E\n"; + +Note that calling C<new> via a reference to a tied hash returns +a simple object, not a reference to a tied hash. + +=item Open + +=item $subKey= $key->Open( $sSubKey, $rhOptions ) + +The C<Open> method opens a Registry key and returns a new +I<Win32::TieRegistry> object associated with that Registry key. +If C<Open> is called via a reference to a tied hash, then C<Open> +returns another reference to a tied hash. Otherwise C<Open> +returns a simple object and you should then use C<TiedRef> to get +a reference to a tied hash. + +C<$sSubKey> is a string specifying a subkey to be opened. +Alternately C<$sSubKey> can be a reference to an array value +containing the list of increasingly deep subkeys specifying the +path to the subkey to be opened. + +C<$rhOptions> is an optional reference to a hash containing extra +options. The C<Open> method supports two options, C<"Delimiter"> +and C<"Access">, and C<$rhOptions> should have only have zero or +more of these strings as keys. See the "Examples" section below +for more information. + +The C<"Delimiter"> option specifies what string [usually a single +character] will be used as the delimiter to be appended to subkey +names and prepended to value names. If this option is not specified, +the new key [C<$subKey>] inherits the delimiter of the old key +[C<$key>]. + +The C<"Access"> option specifies what level of access to the +Registry key you wish to have once it has been opened. If this +option is not specified, the new key [C<$subKey>] is opened with +the same access level used when the old key [C<$key>] was opened. +The virtual root of the Registry pretends it was opened with +access C<KEY_READ()|KEY_WRITE()> so this is the default access when +opening keys directory via C<$Registry>. If you don't plan on +modifying a key, you should open it with C<KEY_READ> access as +you may not have C<KEY_WRITE> access to it or some of its subkeys. + +If the C<"Access"> option value is a string that starts with +C<"KEY_">, then it should match E<one> of the predefined access +levels [probably C<"KEY_READ">, C<"KEY_WRITE">, or +C<"KEY_ALL_ACCESS">] exported by the I<Win32API::Registry> module. +Otherwise, a numeric value is expected. For maximum flexibility, +include C<use Win32::TieRegistry qw(:KEY_);>, for example, near +the top of your script so you can specify more complicated access +levels such as C<KEY_READ()|KEY_WRITE()>. + +If C<$sSubKey> does not begin with the delimiter [or C<$sSubKey> +is an array reference], then the path to the subkey to be opened +will be relative to the path of the original key [C<$key>]. If +C<$sSubKey> begins with a single delimiter, then the path to the +subkey to be opened will be relative to the virtual root of the +Registry on whichever machine the original key resides. If +C<$sSubKey> begins with two consectutive delimiters, then those +must be followed by a machine name which causes the C<Connect()> +method function to be called. + +Examples: + + $machKey= $Registry->Open( "LMachine", {Access=>KEY_READ(),Delimiter=>"/"} ) + or die "Can't open HKEY_LOCAL_MACHINE key: $^E\n"; + $swKey= $machKey->Open( "Software" ); + $logonKey= $swKey->Open( "Microsoft/Windows NT/CurrentVersion/Winlogon/" ); + $NTversKey= $swKey->Open( ["Microsoft","Windows NT","CurrentVersion"] ); + $versKey= $swKey->Open( qw(Microsoft Windows CurrentVersion) ); + + $remoteKey= $Registry->Open( "//HostA/LMachine/System/", {Delimiter=>"/"} ) + or die "Can't connect to HostA or can't open subkey: $^E\n"; + +=item Clone + +=item $copy= $key->Clone + +Creates a new object that is associated with the same Registry key +as the invoking object. + +=item Connect + +=item $remoteKey= $Registry->Connect( $sMachineName, $sKeyPath, $rhOptions ) + +The C<Connect> method connects to the Registry of a remote machine, +and opens a key within it, then returns a new I<Win32::TieRegistry> +object associated with that remote Registry key. If C<Connect> +was called using a reference to a tied hash, then the return value +will also be a reference to a tied hash [or C<undef>]. Otherwise, +if you wish to use the returned object as a tied hash [not just as +an object], then use the C<TiedRef> method function after C<Connect>. + +C<$sMachineName> is the name of the remote machine. You don't have +to preceed the machine name with two delimiter characters. + +C<$sKeyPath> is a string specifying the remote key to be opened. +Alternately C<$sKeyPath> can be a reference to an array value +containing the list of increasingly deep keys specifying the path +to the key to be opened. + +C<$rhOptions> is an optional reference to a hash containing extra +options. The C<Connect> method supports two options, C<"Delimiter"> +and C<"Access">. See the C<Open> method documentation for more +information on these options. + +C<$sKeyPath> is already relative to the virtual root of the Registry +of the remote machine. A single leading delimiter on C<sKeyPath> +will be ignored and is not required. + +C<$sKeyPath> can be empty in which case C<Connect> will return an +object representing the virtual root key of the remote Registry. +Each subsequent use of C<Open> on this virtual root key will call +the system C<RegConnectRegistry> function. + +The C<Connect> method can be called via any I<Win32::TieRegistry> +object, not just C<$Registry>. Attributes such as the desired +level of access and the delimiter will be inherited from the +object used but the C<$sKeyPath> will always be relative to the +virtual root of the remote machine's registry. + +Examples: + + $remMachKey= $Registry->Connect( "HostA", "LMachine", {Delimiter->"/"} ) + or die "Can't connect to HostA's HKEY_LOCAL_MACHINE key: $^E\n"; + + $remVersKey= $remMachKey->Connect( "www.microsoft.com", + "LMachine/Software/Microsoft/Inetsrv/CurrentVersion/", + { Access=>KEY_READ, Delimiter=>"/" } ) + or die "Can't check what version of IIS Microsoft is running: $^E\n"; + + $remVersKey= $remMachKey->Connect( "www", + qw(LMachine Software Microsoft Inetsrv CurrentVersion) ) + or die "Can't check what version of IIS we are running: $^E\n"; + +=item ObjectRef + +=item $object_ref= $obj_or_hash_ref->ObjectRef + +For a simple object, just returns itself [C<$obj == $obj->ObjectRef>]. + +For a reference to a tied hash [if it is also an object], C<ObjectRef> +returns the simple object that the hash is tied to. + +This is primarilly useful when debugging since typing C<x $Registry> +will try to display your I<entire> registry contents to your screen. +But the debugger command C<x $Registry->ObjectRef> will just dump +the implementation details of the underlying object to your screen. + +=item Flush( $bFlush ) + +Flushes all cached information about the Registry key so that future +uses will get fresh data from the Registry. + +If the optional C<$bFlush> is specified and a true value, then +C<RegFlushKey()> will be called, which is almost never necessary. + +=item GetValue + +=item $ValueData= $key->GetValue( $sValueName ) + +=item ($ValueData,$ValueType)= $key->GetValue( $sValueName ) + +Gets a Registry value's data and data type. + +C<$ValueData> is usually just a Perl string that contains the +value data [packed into it]. For certain types of data, however, +C<$ValueData> may be processed as described below. + +C<$ValueType> is the C<REG_*> constant describing the type of value +data stored in C<$ValueData>. If the C<DualTypes()> option is on, +then C<$ValueType> will be a dual value. That is, when used in a +numeric context, C<$ValueType> will give the numeric value of a +C<REG_*> constant. However, when used in a non-numeric context, +C<$ValueType> will return the name of the C<REG_*> constant, for +example C<"REG_SZ"> [note the quotes]. So both of the following +can be true at the same time: + + $ValueType == REG_SZ() + $ValueType eq "REG_SZ" + +=over + +=item REG_SZ and REG_EXPAND_SZ + +If the C<FixSzNulls()> option is on, then the trailing C<'\0'> will be +stripped [unless there isn't one] before values of type C<REG_SZ> +and C<REG_EXPAND_SZ> are returned. Note that C<SetValue()> will add +a trailing C<'\0'> under similar circumstances. + +=item REG_MULTI_SZ + +If the C<SplitMultis()> option is on, then values of this type are +returned as a reference to an array containing the strings. For +example, a value that, with C<SplitMultis()> off, would be returned as: + + "Value1\000Value2\000\000" + +would be returned, with C<SplitMultis()> on, as: + + [ "Value1", "Value2" ] + +=item REG_DWORD + +If the C<DualBinVals()> option is on, then the value is returned +as a scalar containing both a string and a number [much like +the C<$!> variable -- see the L<SetDualVar> module for more +information] where the number part is the "unpacked" value. +Use the returned value in a numeric context to access this part +of the value. For example: + + $num= 0 + $Registry->{"CUser/Console//ColorTable01"}; + +If the C<DWordsToHex()> option is off, the string part of the +returned value is a packed, 4-byte string [use C<unpack("L",$value)> +to get the numeric value. + +If C<DWordsToHex()> is on, the string part of the returned value is +a 10-character hex strings [with leading "0x"]. You can use +C<hex($value)> to get the numeric value. + +Note that C<SetValue()> will properly understand each of these +returned value formats no matter how C<DualBinVals()> is set. + +=back + +=item ValueNames + +=item @names= $key->ValueNames + +Returns the list of value names stored directly in a Registry key. +Note that the names returned do I<not> have a delimiter prepended +to them like with C<MemberNames()> and tied hashes. + +Once you request this information, it is cached in the object and +future requests will always return the same list unless C<Flush()> +has been called. + +=item SubKeyNames + +=item @key_names= $key->SubKeyNames + +Returns the list of subkey names stored directly in a Registry key. +Note that the names returned do I<not> have a delimiter appended +to them like with C<MemberNames()> and tied hashes. + +Once you request this information, it is cached in the object and +future requests will always return the same list unless C<Flush()> +has been called. + +=item SubKeyClasses + +=item @classes= $key->SubKeyClasses + +Returns the list of classes for subkeys stored directly in a +Registry key. The classes are returned in the same order as +the subkey names returned by C<SubKeyNames()>. + +=item SubKeyTimes + +=item @times= $key->SubKeyTimes + +Returns the list of last-modified times for subkeys stored +directly in a Registry key. The times are returned in the same +order as the subkey names returned by C<SubKeyNames()>. Each +time is a C<FILETIME> structure packed into a Perl string. + +Once you request this information, it is cached in the object and +future requests will always return the same list unless C<Flush()> +has been called. + +=item MemberNames + +=item @members= $key->MemberNames + +Returns the list of subkey names and value names stored directly +in a Registry key. Subkey names have a delimiter appended to the +end and value names have a delimiter prepended to the front. + +Note that a value name could end in a delimiter [or could be C<""> +so that the member name returned is just a delimiter] so the +presence or absence of the leading delimiter is what should be +used to determine whether a particular name is for a subkey or a +value, not the presence or absence of a trailing delimiter. + +Once you request this information, it is cached in the object and +future requests will always return the same list unless C<Flush()> +has been called. + +=item Information + +=item %info= $key->Information + +=item @items= $key->Information( @itemNames ); + +Returns the following information about a Registry key: + +=over + +=item LastWrite + +A C<FILETIME> structure indicating when the key was last modified +and packed into a Perl string. + +=item CntSubKeys + +The number of subkeys stored directly in this key. + +=item CntValues + +The number of values stored directly in this key. + +=item SecurityLen + +The length [in bytes] of the largest[?] C<SECURITY_DESCRIPTOR> +associated with the Registry key. + +=item MaxValDataLen + +The length [in bytes] of the longest value data associated with +a value stored in this key. + +=item MaxSubKeyLen + +The length [in chars] of the longest subkey name associated with +a subkey stored in this key. + +=item MaxSubClassLen + +The length [in chars] of the longest class name associated with +a subkey stored directly in this key. + +=item MaxValNameLen + +The length [in chars] of the longest value name associated with +a value stored in this key. + +=back + +With no arguments, returns a hash [not a reference to a hash] where +the keys are the names for the items given above and the values +are the information describe above. For example: + + %info= ( "CntValues" => 25, # Key contains 25 values. + "MaxValNameLen" => 20, # One of which has a 20-char name. + "MaxValDataLen" => 42, # One of which has a 42-byte value. + "CntSubKeys" => 1, # Key has 1 immediate subkey. + "MaxSubKeyLen" => 13, # One of which has a 12-char name. + "MaxSubClassLen" => 0, # All of which have class names of "". + "SecurityLen" => 232, # One SECURITY_DESCRIPTOR is 232 bytes. + "LastWrite" => "\x90mZ\cX{\xA3\xBD\cA\c@\cA" + # Key was last modifed 1998/06/01 16:29:32 GMT + ); + +With arguments, each one must be the name of a item given above. +The return value is the information associated with the listed +names. In other words: + + return $key->Information( @names ); + +returns the same list as: + + %info= $key->Information; + return @info{@names}; + +=item Delimiter + +=item $oldDelim= $key->Delimiter + +=item $oldDelim= $key->Delimiter( $newDelim ) + +Gets and possibly changes the delimiter used for this object. The +delimiter is appended to subkey names and prepended to value names +in many return values. It is also used when parsing keys passed +to tied hashes. + +The delimiter defaults to backslash (C<'\\'>) but is inherited from +the object used to create a new object and can be specified by an +option when a new object is created. + +=item Handle + +=item $handle= $key->Handle + +Returns the raw C<HKEY> handle for the associated Registry key as +an integer value. This value can then be used to Reg*() calls +from I<Win32API::Registry>. However, it is usually easier to just +call the I<Win32API::Registry> calls directly via: + + $key->RegNotifyChangeKeyValue( ... ); + +For the virtual root of the local or a remote Registry, +C<Handle()> return C<"NONE">. + +=item Path + +=item $path= $key->Path + +Returns a string describing the path of key names to this +Registry key. The string is built so that if it were passed +to C<$Registry->Open()>, it would reopen the same Registry key +[except in the rare case where one of the key names contains +C<$key->Delimiter>]. + +=item Machine + +=item $computerName= $key->Machine + +Returns the name of the computer [or "machine"] on which this Registry +key resides. Returns C<""> for local Registry keys. + +=item Access + +Returns the numeric value of the bit mask used to specify the +types of access requested when this Registry key was opened. Can +be compared to C<KEY_*> values. + +=item OS_Delimiter + +Returns the delimiter used by the operating system's RegOpenKeyEx() +call. For Win32, this is always backslash (C<"\\">). + +=item Roots + +Returns the mapping from root key names like C<"LMachine"> to their +associated C<HKEY_*> constants. Primarily for internal use and +subject to change. + +=item Tie + +=item $key->Tie( \%hash ); + +Ties the referenced hash to that Registry key. Pretty much the +same as + + tie %hash, ref($key), $key; + +Since C<ref($key)> is the class [package] to tie the hash to and +C<TIEHASH()> just returns its argument, C<$key>, [without calling +C<new()>] when it sees that it is already a blessed object. + +=item TiedRef + +=item $TiedHashRef= $hash_or_obj_ref->TiedRef + +For a simple object, returns a reference to a hash tied to the +object. Used to promote a simple object into a combined object +and hash ref. + +If already a reference to a tied hash [that is also an object], +it just returns itself [C<$ref == $ref->TiedRef>]. + +Mostly used internally. + +=item ArrayValues + +=item $oldBool= $key->ArrayValues + +=item $oldBool= $key->ArrayValues( $newBool ) + +Gets the current setting of the C<ArrayValues> option and possibly +turns it on or off. + +When off, Registry values fetched via a tied hash are returned as +just a value scalar [the same as C<GetValue()> in a scalar context]. +When on, they are returned as a reference to an array containing +the value data as the C<[0]> element and the data type as the C<[1]> +element. + +=item TieValues + +=item $oldBool= TieValues + +=item $oldBool= TieValues( $newBool ) + +Gets the current setting of the C<TieValues> option and possibly +turns it on or off. + +Turning this option on is not yet supported in this release of +I<Win32::TieRegistry>. In a future release, turning this option +on will cause Registry values returned from a tied hash to be +a tied array that you can use to modify the value in the Registry. + +=item FastDelete + +=item $oldBool= $key->FastDelete + +=item $oldBool= $key->FastDelete( $newBool ) + +Gets the current setting of the C<FastDelete> option and possibly +turns it on or off. + +When on, successfully deleting a Registry key [via a tied hash] +simply returns C<1>. + +When off, successfully deleting a Registry key [via a tied hash +and not in a void context] returns a reference to a hash that +contains the values present in the key when it was deleted. This +hash is just like that returned when referencing the key before it +was deleted except that it is an ordinary hash, not one tied to +the I<Win32::TieRegistry> package. + +Note that deleting either a Registry key or value via a tied hash +I<in a void context> prevents any overhead in trying to build an +appropriate return value. + +Note that deleting a Registry I<value> via a tied hash [not in +a void context] returns the value data even if <FastDelete> is on. + +=item SplitMultis + +=item $oldBool= $key->SplitMultis + +=item $oldBool= $key->SplitMultis( $newBool ) + +Gets the current setting of the C<SplitMultis> option and possibly +turns it on or off. + +If on, Registry values of type C<REG_MULTI_SZ> are returned as +a reference to an array of strings. See C<GetValue()> for more +information. + +=item DWordsToHex + +=item $oldBool= $key->DWordsToHex + +=item $oldBool= $key->DWordsToHex( $newBool ) + +Gets the current setting of the C<DWordsToHex> option and possibly +turns it on or off. + +If on, Registry values of type C<REG_DWORD> are returned as a hex +string with leading C<"0x"> and longer than 4 characters. See +C<GetValue()> for more information. + +=item FixSzNulls + +=item $oldBool= $key->FixSzNulls + +=item $oldBool= $key->FixSzNulls( $newBool ) + +Gets the current setting of the C<FixSzNulls> option and possibly +turns it on or off. + +If on, Registry values of type C<REG_SZ> and C<REG_EXPAND_SZ> have +trailing C<'\0'>s added before they are set and stripped before +they are returned. See C<GetValue()> and C<SetValue()> for more +information. + +=item DualTypes + +=item $oldBool= $key->DualTypes + +=item $oldBool= $key->DualTypes( $newBool ) + +Gets the current setting of the C<DualTypes> option and possibly +turns it on or off. + +If on, data types are returned as a combined numeric/string value +holding both the numeric value of a C<REG_*> constant and the +string value of the constant's name. See C<GetValue()> for +more information. + +=item DualBinVals + +=item $oldBool= $key->DualBinVals + +=item $oldBool= $key->DualBinVals( $newBool ) + +Gets the current setting of the C<DualBinVals> option and possibly +turns it on or off. + +If on, Registry value data of type C<REG_BINARY> and no more than +4 bytes long and Registry values of type C<REG_DWORD> are returned +as a combined numeric/string value where the numeric value is the +"unpacked" binary value as returned by: + + hex reverse unpack( "h*", $valData ) + +on a "little-endian" computer. [Would be C<hex unpack("H*",$valData)> +on a "big-endian" computer if this module is ever ported to one.] + +See C<GetValue()> for more information. + +=item GetOptions + +=item @oldOptValues= $key->GetOptions( @optionNames ) + +=item $refHashOfOldOpts= $key->GetOptions() + +=item $key->GetOptions( \%hashForOldOpts ) + +Returns the current setting of any of the following options: + + Delimiter FixSzNulls DWordsToHex + ArrayValues SplitMultis DualBinVals + TieValues FastDelete DualTypes + +Pass in one or more of the above names (as strings) to get back +an array of the corresponding current settings in the same order: + + my( $fastDel, $delim )= $key->GetOptions("FastDelete","Delimiter"); + +Pass in no arguments to get back a reference to a hash where +the above option names are the keys and the values are +the corresponding current settings for each option: + + my $href= $key->GetOptions(); + my $delim= $href->{Delimiter}; + +Pass in a single reference to a hash to have the above key/value +pairs I<added> to the referenced hash. For this case, the +return value is the original object so further methods can be +chained after the call to GetOptions: + + my %oldOpts; + $key->GetOptions( \%oldOpts )->SetOptions( Delimiter => "/" ); + +=item SetOptions + +=item @oldOpts= $key->SetOptions( optNames=>$optValue,... ) + +Changes the current setting of any of the following options, +returning the previous setting(s): + + Delimiter FixSzNulls DWordsToHex AllowLoad + ArrayValues SplitMultis DualBinVals AllowSave + TieValues FastDelete DualTypes + +For C<AllowLoad> and C<AllowSave>, instead of the previous +setting, C<SetOptions> returns whether or not the change was +successful. + +In a scalar context, returns only the last item. The last +option can also be specified as C<"ref"> or C<"r"> [which doesn't +need to be followed by a value] to allow chaining: + + $key->SetOptions(AllowSave=>1,"ref")->RegSaveKey(...) + +=item SetValue + +=item $okay= $key->SetValue( $ValueName, $ValueData ); + +=item $okay= $key->SetValue( $ValueName, $ValueData, $ValueType ); + +Adds or replaces a Registry value. Returns a true value if +successfully, false otherwise. + +C<$ValueName> is the name of the value to add or replace and +should I<not> have a delimiter prepended to it. Case is ignored. + +C<$ValueType> is assumed to be C<REG_SZ> if it is omitted. Otherwise, +it should be one the C<REG_*> constants. + +C<$ValueData> is the data to be stored in the value, probably packed +into a Perl string. Other supported formats for value data are +listed below for each posible C<$ValueType>. + +=over + +=item REG_SZ or REG_EXPAND_SZ + +The only special processing for these values is the addition of +the required trailing C<'\0'> if it is missing. This can be +turned off by disabling the C<FixSzNulls> option. + +=item REG_MULTI_SZ + +These values can also be specified as a reference to a list of +strings. For example, the following two lines are equivalent: + + $key->SetValue( "Val1\000Value2\000LastVal\000\000", "REG_MULTI_SZ" ); + $key->SetValue( ["Val1","Value2","LastVal"], "REG_MULTI_SZ" ); + +Note that if the required two trailing nulls (C<"\000\000">) are +missing, then this release of C<SetValue()> will I<not> add them. + +=item REG_DWORD + +These values can also be specified as a hex value with the leading +C<"0x"> included and totaling I<more than> 4 bytes. These will be +packed into a 4-byte string via: + + $data= pack( "L", hex($data) ); + +=item REG_BINARY + +This value type is listed just to emphasize that no alternate +format is supported for it. In particular, you should I<not> pass +in a numeric value for this type of data. C<SetValue()> cannot +distinguish such from a packed string that just happens to match +a numeric value and so will treat it as a packed string. + +=back + +An alternate calling format: + + $okay= $key->SetValue( $ValueName, [ $ValueData, $ValueType ] ); + +[two arguments, the second of which is a reference to an array +containing the value data and value type] is supported to ease +using tied hashes with C<SetValue()>. + +=item CreateKey + +=item $newKey= $key->CreateKey( $subKey ); + +=item $newKey= $key->CreateKey( $subKey, { Option=>OptVal,... } ); + +Creates a Registry key or just updates attributes of one. Calls +C<RegCreateKeyEx()> then, if it succeeded, creates an object +associated with the [possibly new] subkey. + +C<$subKey> is the name of a subkey [or a path to one] to be +created or updated. It can also be a reference to an array +containing a list of subkey names. + +The second argument, if it exists, should be a reference to a +hash specifying options either to be passed to C<RegCreateKeyEx()> +or to be used when creating the associated object. The following +items are the supported keys for this options hash: + +=over + +=item Delimiter + +Specifies the delimiter to be used to parse C<$subKey> and to be +used in the new object. Defaults to C<$key->Delimiter>. + +=item Access + +Specifies the types of access requested when the subkey is opened. +Should be a numeric bit mask that combines one or more C<KEY_*> +constant values. + +=item Class + +The name to assign as the class of the new or updated subkey. +Defaults to C<""> as we have never seen a use for this information. + +=item Disposition + +Lets you specify a reference to a scalar where, upon success, will be +stored either C<REG_CREATED_NEW_KEY()> or C<REG_OPENED_EXISTING_KEY()> +depending on whether a new key was created or an existing key was +opened. + +If you, for example, did C<use Win32::TieRegistry qw(REG_CREATED_NEW_KEY)> +then you can use C<REG_CREATED_NEW_KEY()> to compare against the numeric +value stored in the referenced scalar. + +If the C<DualTypes> option is enabled, then in addition to the +numeric value described above, the referenced scalar will also +have a string value equal to either C<"REG_CREATED_NEW_KEY"> or +C<"REG_OPENED_EXISTING_KEY">, as appropriate. + +=item Security + +Lets you specify a C<SECURITY_ATTRIBUTES> structure packed into a +Perl string. See C<Win32API::Registry::RegCreateKeyEx()> for more +information. + +=item Volatile + +If true, specifies that the new key should be volatile, that is, +stored only in memory and not backed by a hive file [and not saved +if the computer is rebooted]. This option is ignored under +Windows 95. Specifying C<Volatile=E<GT>1> is the same as +specifying C<Options=E<GT>REG_OPTION_VOLATILE>. + +=item Backup + +If true, specifies that the new key should be opened for +backup/restore access. The C<Access> option is ignored. If the +calling process has enabled C<"SeBackupPrivilege">, then the +subkey is opened with C<KEY_READ> access as the C<"LocalSystem"> +user which should have access to all subkeys. If the calling +process has enabled C<"SeRestorePrivilege">, then the subkey is +opened with C<KEY_WRITE> access as the C<"LocalSystem"> user which +should have access to all subkeys. + +This option is ignored under Windows 95. Specifying C<Backup=E<GT>1> +is the same as specifying C<Options=E<GT>REG_OPTION_BACKUP_RESTORE>. + +=item Options + +Lets you specify options to the C<RegOpenKeyEx()> call. The value +for this option should be a numeric value combining zero or more +of the C<REG_OPTION_*> bit masks. You may with to used the +C<Volatile> and/or C<Backup> options instead of this one. + +=back + +=item StoreKey + +=item $newKey= $key->StoreKey( $subKey, \%Contents ); + +Primarily for internal use. + +Used to create or update a Registry key and any number of subkeys +or values under it or its subkeys. + +C<$subKey> is the name of a subkey to be created [or a path of +subkey names separated by delimiters]. If that subkey already +exists, then it is updated. + +C<\%Contents> is a reference to a hash containing pairs of +value names with value data and/or subkey names with hash +references similar to C<\%Contents>. Each of these cause +a value or subkey of C<$subKey> to be created or updated. + +If C<$Contents{""}> exists and is a reference to a hash, then +it used as the options argument when C<CreateKey()> is called +for C<$subKey>. This allows you to specify ... + + if( defined( $$data{""} ) && "HASH" eq ref($$data{""}) ) { + $self= $this->CreateKey( $subKey, delete $$data{""} ); + +=item Load + +=item $newKey= $key->Load( $file ) + +=item $newKey= $key->Load( $file, $newSubKey ) + +=item $newKey= $key->Load( $file, $newSubKey, { Option=>OptVal... } ) + +=item $newKey= $key->Load( $file, { Option=>OptVal... } ) + +Loads a hive file into a Registry. That is, creates a new subkey +and associates a hive file with it. + +C<$file> is a hive file, that is a file created by calling +C<RegSaveKey()>. The C<$file> path is interpreted relative to +C<%SystemRoot%/System32/config> on the machine where C<$key> +resides. + +C<$newSubKey> is the name to be given to the new subkey. If +C<$newSubKey> is specified, then C<$key> must be +C<HKEY_LOCAL_MACHINE> or C<HKEY_USERS> of the local computer +or a remote computer and C<$newSubKey> should not contain any +occurrences of either the delimiter or the OS delimiter. + +If C<$newSubKey> is not specified, then it is as if C<$key> +was C<$Registry-E<GT>{LMachine}> and C<$newSubKey> is +C<"PerlTie:999"> where C<"999"> is actually a sequence number +incremented each time this process calls C<Load()>. + +You can specify as the last argument a reference to a hash +containing options. You can specify the same options that you +can specify to C<Open()>. See C<Open()> for more information on +those. In addition, you can specify the option C<"NewSubKey">. +The value of this option is interpretted exactly as if it was +specified as the C<$newSubKey> parameter and overrides the +C<$newSubKey> if one was specified. + +The hive is automatically unloaded when the returned object +[C<$newKey>] is destroyed. Registry key objects opened within +the hive will keep a reference to the C<$newKey> object so that +it will not be destroyed before these keys are closed. + +=item UnLoad + +=item $okay= $key->UnLoad + +Unloads a hive that was loaded via C<Load()>. Cannot unload other +hives. C<$key> must be the return from a previous call to C<Load()>. +C<$key> is closed and then the hive is unloaded. + +=item AllowSave + +=item $okay= AllowSave( $bool ) + +Enables or disables the C<"ReBackupPrivilege"> privilege for the +current process. You will probably have to enable this privilege +before you can use C<RegSaveKey()>. + +The return value indicates whether the operation succeeded, not +whether the privilege was previously enabled. + +=item AllowLoad + +=item $okay= AllowLoad( $bool ) + +Enables or disables the C<"ReRestorePrivilege"> privilege for the +current process. You will probably have to enable this privilege +before you can use C<RegLoadKey()>, C<RegUnLoadKey()>, +C<RegReplaceKey()>, or C<RegRestoreKey> and thus C<Load()> and +C<UnLoad()>. + +The return value indicates whether the operation succeeded, not +whether the privilege was previously enabled. + +=back + +=head2 Exports [C<use> and C<import()>] + +To have nothing imported into your package, use something like: + + use Win32::TieRegistry 0.20 (); + +which would verify that you have at least version 0.20 but wouldn't +call C<import()>. The F<Changes> file can be useful in figuring out +which, if any, prior versions of I<Win32::TieRegistry> you want to +support in your script. + +The code + + use Win32::TieRegistry; + +imports the variable C<$Registry> into your package and sets it +to be a reference to a hash tied to a copy of the master Registry +virtual root object with the default options. One disadvantage +to this "default" usage is that Perl does not support checking +the module version when you use it. + +Alternately, you can specify a list of arguments on the C<use> +line that will be passed to the C<Win32::TieRegistry->import()> +method to control what items to import into your package. These +arguments fall into the following broad categories: + +=over + +=item Import a reference to a hash tied to a Registry virtual root + +You can request that a scalar variable be imported (possibly) +and set to be a reference to a hash tied to a Registry virtual root +using any of the following types of arguments or argument pairs: + +=over + +=item "TiedRef", '$scalar' + +=item "TiedRef", '$pack::scalar' + +=item "TiedRef", 'scalar' + +=item "TiedRef", 'pack::scalar' + +All of the above import a scalar named C<$scalar> into your package +(or the package named "pack") and then sets it. + +=item '$scalar' + +=item '$pack::scalar' + +These are equivalent to the previous items to support a more +traditional appearance to the list of exports. Note that the +scalar name cannot be "RegObj" here. + +=item "TiedRef", \$scalar + +=item \$scalar + +These versions don't import anything but set the referenced C<$scalar>. + +=back + +=item Import a hash tied to the Registry virtual root + +You can request that a hash variable be imported (possibly) +and tied to a Registry virtual root using any of the following +types of arguments or argument pairs: + +=over + +=item "TiedHash", '%hash' + +=item "TiedHash", '%pack::hash' + +=item "TiedHash", 'hash' + +=item "TiedHash", 'pack::hash' + +All of the above import a hash named C<%hash> into your package +(or the package named "pack") and then sets it. + +=item '%hash' + +=item '%pack::hash' + +These are equivalent to the previous items to support a more +traditional appearance to the list of exports. + +=item "TiedHash", \%hash + +=item \%hash + +These versions don't import anything but set the referenced C<%hash>. + +=back + +=item Import a Registry virtual root object + +You can request that a scalar variable be imported (possibly) +and set to be a Registry virtual root object using any of the +following types of arguments or argument pairs: + +=over + +=item "ObjectRef", '$scalar' + +=item "ObjectRef", '$pack::scalar' + +=item "ObjectRef", 'scalar' + +=item "ObjectRef", 'pack::scalar' + +All of the above import a scalar named C<$scalar> into your package +(or the package named "pack") and then sets it. + +=item '$RegObj' + +This is equivalent to the previous items for backward compatibility. + +=item "ObjectRef", \$scalar + +This version doesn't import anything but sets the referenced C<$scalar>. + +=back + +=item Import constant(s) exported by I<Win32API::Registry> + +You can list any constants that are exported by I<Win32API::Registry> +to have them imported into your package. These constants have names +starting with "KEY_" or "REG_" (or even "HKEY_"). + +You can also specify C<":KEY_">, C<":REG_">, and even C<":HKEY_"> to +import a whole set of constants. + +See I<Win32API::Registry> documentation for more information. + +=item Options + +You can list any option names that can be listed in the C<SetOptions()> +method call, each folowed by the value to use for that option. +A Registry virtual root object is created, all of these options are +set for it, then each variable to be imported/set is associated with +this object. + +In addition, the following special options are supported: + +=over + +=item ExportLevel + +Whether to import variables into your package or some +package that uses your package. Defaults to the value of +C<$Exporter::ExportLevel> and has the same meaning. See +the L<Exporter> module for more information. + +=item ExportTo + +The name of the package to import variables and constants into. +Overrides I<ExportLevel>. + +=back + +=back + +=head3 Specifying constants in your Perl code + +This module was written with a strong emphasis on the convenience of +the module user. Therefore, most places where you can specify a +constant like C<REG_SZ()> also allow you to specify a string +containing the name of the constant, C<"REG_SZ">. This is convenient +because you may not have imported that symbolic constant. + +Perl also emphasizes programmer convenience so the code C<REG_SZ> +can be used to mean C<REG_SZ()> or C<"REG_SZ"> or be illegal. +Note that using C<®_SZ> (as we've seen in much Win32 Perl code) +is not a good idea since it passes the current C<@_> to the +C<constant()> routine of the module which, at the least, can give +you a warning under B<-w>. + +Although greatly a matter of style, the "safest" practice is probably +to specifically list all constants in the C<use Win32::TieRegistry> +statement, specify C<use strict> [or at least C<use strict qw(subs)>], +and use bare constant names when you want the numeric value. This will +detect mispelled constant names at compile time. + + use strict; + my $Registry; + use Win32::TieRegistry 0.20 ( + TiedRef => \$Registry, Delimiter => "/", ArrayValues => 1, + SplitMultis => 1, AllowLoad => 1, + qw( REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ + KEY_READ KEY_WRITE KEY_ALL_ACCESS ), + ); + $Registry->{"LMachine/Software/FooCorp/"}= { + "FooWriter/" => { + "/Fonts" => [ ["Times","Courier","Lucinda"], REG_MULTI_SZ ], + "/WindowSize" => [ pack("LL",24,80), REG_BINARY ], + "/TaskBarIcon" => [ "0x0001", REG_DWORD ], + }, + } or die "Can't create Software/FooCorp/: $^E\n"; + +If you don't want to C<use strict qw(subs)>, the second safest practice +is similar to the above but use the C<REG_SZ()> form for constants +when possible and quoted constant names when required. Note that +C<qw()> is a form of quoting. + + use Win32::TieRegistry 0.20 qw( + TiedRef $Registry + Delimiter / ArrayValues 1 SplitMultis 1 AllowLoad 1 + REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ + KEY_READ KEY_WRITE KEY_ALL_ACCESS + ); + $Registry->{"LMachine/Software/FooCorp/"}= { + "FooWriter/" => { + "/Fonts" => [ ["Times","Courier","Lucinda"], REG_MULTI_SZ() ], + "/WindowSize" => [ pack("LL",24,80), REG_BINARY() ], + "/TaskBarIcon" => [ "0x0001", REG_DWORD() ], + }, + } or die "Can't create Software/FooCorp/: $^E\n"; + +The examples in this document mostly use quoted constant names +(C<"REG_SZ">) since that works regardless of which constants +you imported and whether or not you have C<use strict> in your +script. It is not the best choice for you to use for real +scripts (vs. examples) because it is less efficient and is not +supported by most other similar modules. + +=head1 SUMMARY + +Most things can be done most easily via tied hashes. Skip down to the +the L<Tied Hashes Summary> to get started quickly. + +=head2 Objects Summary + +Here are quick examples that document the most common functionality +of all of the method functions [except for a few almost useless ones]. + + # Just another way of saying Open(): + $key= new Win32::TieRegistry "LMachine\\Software\\", + { Access=>KEY_READ()|KEY_WRITE(), Delimiter=>"\\" }; + + # Open a Registry key: + $subKey= $key->Open( "SubKey/SubSubKey/", + { Access=>KEY_ALL_ACCESS, Delimiter=>"/" } ); + + # Connect to a remote Registry key: + $remKey= $Registry->Connect( "MachineName", "LMachine/", + { Access=>KEY_READ, Delimiter=>"/" } ); + + # Get value data: + $valueString= $key->GetValue("ValueName"); + ( $valueString, $valueType )= $key->GetValue("ValueName"); + + # Get list of value names: + @valueNames= $key->ValueNames; + + # Get list of subkey names: + @subKeyNames= $key->SubKeyNames; + + # Get combined list of value names (with leading delimiters) + # and subkey names (with trailing delimiters): + @memberNames= $key->MemberNames; + + # Get all information about a key: + %keyInfo= $key->Information; + # keys(%keyInfo)= qw( Class LastWrite SecurityLen + # CntSubKeys MaxSubKeyLen MaxSubClassLen + # CntValues MaxValNameLen MaxValDataLen ); + + # Get selected information about a key: + ( $class, $cntSubKeys )= $key->Information( "Class", "CntSubKeys" ); + + # Get and/or set delimiter: + $delim= $key->Delimiter; + $oldDelim= $key->Delimiter( $newDelim ); + + # Get "path" for an open key: + $path= $key->Path; + # For example, "/CUser/Control Panel/Mouse/" + # or "//HostName/LMachine/System/DISK/". + + # Get name of machine where key is from: + $mach= $key->Machine; + # Will usually be "" indicating key is on local machine. + + # Control different options (see main documentation for descriptions): + $oldBool= $key->ArrayValues( $newBool ); + $oldBool= $key->FastDelete( $newBool ); + $oldBool= $key->FixSzNulls( $newBool ); + $oldBool= $key->SplitMultis( $newBool ); + $oldBool= $key->DWordsToHex( $newBool ); + $oldBool= $key->DualBinVals( $newBool ); + $oldBool= $key->DualTypes( $newBool ); + @oldBools= $key->SetOptions( ArrayValues=>1, FastDelete=>1, FixSzNulls=>0, + Delimiter=>"/", AllowLoad=>1, AllowSave=>1 ); + @oldBools= $key->GetOptions( ArrayValues, FastDelete, FixSzNulls ); + + # Add or set a value: + $key->SetValue( "ValueName", $valueDataString ); + $key->SetValue( "ValueName", pack($format,$valueData), "REG_BINARY" ); + + # Add or set a key: + $key->CreateKey( "SubKeyName" ); + $key->CreateKey( "SubKeyName", + { Access=>"KEY_ALL_ACCESS", Class=>"ClassName", + Delimiter=>"/", Volatile=>1, Backup=>1 } ); + + # Load an off-line Registry hive file into the on-line Registry: + $newKey= $Registry->Load( "C:/Path/To/Hive/FileName" ); + $newKey= $key->Load( "C:/Path/To/Hive/FileName", "NewSubKeyName", + { Access=>"KEY_READ" } ); + # Unload a Registry hive file loaded via the Load() method: + $newKey->UnLoad; + + # (Dis)Allow yourself to load Registry hive files: + $success= $Registry->AllowLoad( $bool ); + + # (Dis)Allow yourself to save a Registry key to a hive file: + $success= $Registry->AllowSave( $bool ); + + # Save a Registry key to a new hive file: + $key->RegSaveKey( "C:/Path/To/Hive/FileName", [] ); + +=head3 Other Useful Methods + +See I<Win32API::Registry> for more information on these methods. +These methods are provided for coding convenience and are +identical to the I<Win32API::Registry> functions except that these +don't take a handle to a Registry key, instead getting the handle +from the invoking object [C<$key>]. + + $key->RegGetKeySecurity( $iSecInfo, $sSecDesc, $lenSecDesc ); + $key->RegLoadKey( $sSubKeyName, $sPathToFile ); + $key->RegNotifyChangeKeyValue( + $bWatchSubtree, $iNotifyFilter, $hEvent, $bAsync ); + $key->RegQueryMultipleValues( + $structValueEnts, $cntValueEnts, $Buffer, $lenBuffer ); + $key->RegReplaceKey( $sSubKeyName, $sPathToNewFile, $sPathToBackupFile ); + $key->RegRestoreKey( $sPathToFile, $iFlags ); + $key->RegSetKeySecurity( $iSecInfo, $sSecDesc ); + $key->RegUnLoadKey( $sSubKeyName ); + +=head2 Tied Hashes Summary + +For fast learners, this may be the only section you need to read. +Always append one delimiter to the end of each Registry key name +and prepend one delimiter to the front of each Registry value name. + +=head3 Opening keys + + use Win32::TieRegistry ( Delimiter=>"/", ArrayValues=>1 ); + $Registry->Delimiter("/"); # Set delimiter to "/". + $swKey= $Registry->{"LMachine/Software/"}; + $winKey= $swKey->{"Microsoft/Windows/CurrentVersion/"}; + $userKey= $Registry-> + {"CUser/Software/Microsoft/Windows/CurrentVersion/"}; + $remoteKey= $Registry->{"//HostName/LMachine/"}; + +=head3 Reading values + + $progDir= $winKey->{"/ProgramFilesDir"}; # "C:\\Program Files" + $tip21= $winKey->{"Explorer/Tips//21"}; # Text of tip #21. + + $winKey->ArrayValues(1); + ( $devPath, $type )= $winKey->{"/DevicePath"}; + # $devPath eq "%SystemRoot%\\inf" + # $type eq "REG_EXPAND_SZ" [if you have SetDualVar.pm installed] + # $type == REG_EXPAND_SZ() [if did C<use Win32::TieRegistry qw(:REG_)>] + +=head3 Setting values + + $winKey->{"Setup//SourcePath"}= "\\\\SwServer\\SwShare\\Windows"; + # Simple. Assumes data type of REG_SZ. + + $winKey->{"Setup//Installation Sources"}= + [ "D:\x00\\\\SwServer\\SwShare\\Windows\0\0", "REG_MULTI_SZ" ]; + # "\x00" and "\0" used to mark ends of each string and end of list. + + $winKey->{"Setup//Installation Sources"}= + [ ["D:","\\\\SwServer\\SwShare\\Windows"], "REG_MULTI_SZ" ]; + # Alternate method that is easier to read. + + $userKey->{"Explorer/Tips//DisplayInitialTipWindow"}= + [ pack("L",0), "REG_DWORD" ]; + $userKey->{"Explorer/Tips//Next"}= [ pack("S",3), "REG_BINARY" ]; + $userKey->{"Explorer/Tips//Show"}= [ pack("L",0), "REG_BINARY" ]; + +=head3 Adding keys + + $swKey->{"FooCorp/"}= { + "FooWriter/" => { + "/Version" => "4.032", + "Startup/" => { + "/Title" => "Foo Writer Deluxe ][", + "/WindowSize" => [ pack("LL",$wid,$ht), "REG_BINARY" ], + "/TaskBarIcon" => [ "0x0001", "REG_DWORD" ], + }, + "Compatibility/" => { + "/AutoConvert" => "Always", + "/Default Palette" => "Windows Colors", + }, + }, + "/License", => "0123-9C8EF1-09-FC", + }; + +=head3 Listing all subkeys and values + + @members= keys( %{$swKey} ); + @subKeys= grep( m#^/#, keys( %{$swKey->{"Classes/batfile/"}} ) ); + # @subKeys= ( "/", "/EditFlags" ); + @valueNames= grep( ! m#^/#, keys( %{$swKey->{"Classes/batfile/"}} ) ); + # @valueNames= ( "DefaultIcon/", "shell/", "shellex/" ); + +=head3 Deleting values or keys with no subkeys + + $oldValue= delete $userKey->{"Explorer/Tips//Next"}; + + $oldValues= delete $userKey->{"Explorer/Tips/"}; + # $oldValues will be reference to hash containing deleted keys values. + +=head3 Closing keys + + undef $swKey; # Explicit way to close a key. + $winKey= "Anything else"; # Implicitly closes a key. + exit 0; # Implicitly closes all keys. + +=head2 Tie::Registry + +This module was originally called I<Tie::Registry>. Changing code +that used I<Tie::Registry> over to I<Win32::TieRegistry> is trivial +as the module name should only be mentioned once, in the C<use> +line. However, finding all of the places that used I<Tie::Registry> +may not be completely trivial so we have included F<Tie/Registry.pm> +which you can install to provide backward compatibility. + +=head1 AUTHOR + +Tye McQueen. See http://www.metronet.com/~tye/ or e-mail +tye@metronet.com with bug reports. + +=head1 SEE ALSO + +I<Win32API::Registry> - Provides access to C<Reg*()>, C<HKEY_*>, +C<KEY_*>, C<REG_*> [required]. + +I<Win32::WinError> - Defines C<ERROR_*> values [optional]. + +L<SetDualVar> - For returning C<REG_*> values as combined +string/integer values [optional]. + +=head1 BUGS + +Perl5.004_02 has bugs that make I<Win32::TieRegistry> fail in +strange and subtle ways. + +Using I<Win32::TieRegistry> with versions of Perl prior to 5.005 +can be tricky or impossible. Most notes about this have been +removed from the documentation (they get rather complicated +and confusing). This includes references to C<$^E> perhaps not +being meaningful. + +Because Perl hashes are case sensitive, certain lookups are also +case sensistive. In particular, the root keys ("Classes", "CUser", +"LMachine", "Users", "PerfData", "CConfig", "DynData", and HKEY_*) +must always be entered without changing between upper and lower +case letters. Also, the special rule for matching subkey names +that contain the user-selected delimiter only works if case is +matched. All other key name and value name lookups should be case +insensitive because the underlying Reg*() calls ignore case. + +Information about each key is cached when using a tied hash. +This cache is not flushed nor updated when changes are made, +I<even when the same tied hash is used> to make the changes. + +Current implementations of Perl's "global destruction" phase can +cause objects returned by C<Load()> to be destroyed while keys +within the hive are still open, if the objects still exist when +the script starts to exit. When this happens, the automatic +C<UnLoad()> will report a failure and the hive will remain loaded +in the Registry. + +Trying to C<Load()> a hive file that is located on a remote network +share may silently delete all data from the hive. This is a bug +in the Win32 APIs, not any Perl code or modules. This module does +not try to protect you from this bug. + +There is no test suite. + +=head1 FUTURE DIRECTIONS + +The following items are desired by the author and may appear in a +future release of this module. + +=over + +=item TieValues option + +Currently described in main documentation but no yet implemented. + +=item AutoRefresh option + +Trigger use of C<RegNotifyChangeKeyValue()> to keep tied hash +caches up-to-date even when other programs make changes. + +=item Error options + +Allow the user to have unchecked calls (calls in a "void context") +to automatically report errors via C<warn> or C<die>. + +For complex operations, such a copying an entire subtree, provide +access to detailed information about errors (and perhaps some +warnings) that were encountered. Let the user control whether +the complex operation continues in spite of errors. + +=back + +=cut + +# Autoload not currently supported by Perl under Windows. diff --git a/Master/tlpkg/tlperl/lib/Win32/WinError.pm b/Master/tlpkg/tlperl/lib/Win32/WinError.pm new file mode 100644 index 00000000000..46028a79321 --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/WinError.pm @@ -0,0 +1,1017 @@ +package Win32::WinError; + +require Exporter; +require DynaLoader; + +$VERSION = '0.02'; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + GetLastError + CACHE_E_FIRST + CACHE_E_LAST + CACHE_E_NOCACHE_UPDATED + CACHE_S_FIRST + CACHE_S_FORMATETC_NOTSUPPORTED + CACHE_S_LAST + CACHE_S_SAMECACHE + CACHE_S_SOMECACHES_NOTUPDATED + CLASSFACTORY_E_FIRST + CLASSFACTORY_E_LAST + CLASSFACTORY_S_FIRST + CLASSFACTORY_S_LAST + CLASS_E_CLASSNOTAVAILABLE + CLASS_E_NOAGGREGATION + CLIENTSITE_E_FIRST + CLIENTSITE_E_LAST + CLIENTSITE_S_FIRST + CLIENTSITE_S_LAST + CLIPBRD_E_BAD_DATA + CLIPBRD_E_CANT_CLOSE + CLIPBRD_E_CANT_EMPTY + CLIPBRD_E_CANT_OPEN + CLIPBRD_E_CANT_SET + CLIPBRD_E_FIRST + CLIPBRD_E_LAST + CLIPBRD_S_FIRST + CLIPBRD_S_LAST + CONVERT10_E_FIRST + CONVERT10_E_LAST + CONVERT10_E_OLESTREAM_BITMAP_TO_DIB + CONVERT10_E_OLESTREAM_FMT + CONVERT10_E_OLESTREAM_GET + CONVERT10_E_OLESTREAM_PUT + CONVERT10_E_STG_DIB_TO_BITMAP + CONVERT10_E_STG_FMT + CONVERT10_E_STG_NO_STD_STREAM + CONVERT10_S_FIRST + CONVERT10_S_LAST + CONVERT10_S_NO_PRESENTATION + CO_E_ALREADYINITIALIZED + CO_E_APPDIDNTREG + CO_E_APPNOTFOUND + CO_E_APPSINGLEUSE + CO_E_BAD_PATH + CO_E_CANTDETERMINECLASS + CO_E_CLASSSTRING + CO_E_CLASS_CREATE_FAILED + CO_E_DLLNOTFOUND + CO_E_ERRORINAPP + CO_E_ERRORINDLL + CO_E_FIRST + CO_E_IIDSTRING + CO_E_INIT_CLASS_CACHE + CO_E_INIT_MEMORY_ALLOCATOR + CO_E_INIT_ONLY_SINGLE_THREADED + CO_E_INIT_RPC_CHANNEL + CO_E_INIT_SCM_EXEC_FAILURE + CO_E_INIT_SCM_FILE_MAPPING_EXISTS + CO_E_INIT_SCM_MAP_VIEW_OF_FILE + CO_E_INIT_SCM_MUTEX_EXISTS + CO_E_INIT_SHARED_ALLOCATOR + CO_E_INIT_TLS + CO_E_INIT_TLS_CHANNEL_CONTROL + CO_E_INIT_TLS_SET_CHANNEL_CONTROL + CO_E_INIT_UNACCEPTED_USER_ALLOCATOR + CO_E_LAST + CO_E_NOTINITIALIZED + CO_E_OBJISREG + CO_E_OBJNOTCONNECTED + CO_E_OBJNOTREG + CO_E_OBJSRV_RPC_FAILURE + CO_E_RELEASED + CO_E_SCM_ERROR + CO_E_SCM_RPC_FAILURE + CO_E_SERVER_EXEC_FAILURE + CO_E_SERVER_STOPPING + CO_E_WRONGOSFORAPP + CO_S_FIRST + CO_S_LAST + DATA_E_FIRST + DATA_E_LAST + DATA_S_FIRST + DATA_S_LAST + DATA_S_SAMEFORMATETC + DISP_E_ARRAYISLOCKED + DISP_E_BADCALLEE + DISP_E_BADINDEX + DISP_E_BADPARAMCOUNT + DISP_E_BADVARTYPE + DISP_E_EXCEPTION + DISP_E_MEMBERNOTFOUND + DISP_E_NONAMEDARGS + DISP_E_NOTACOLLECTION + DISP_E_OVERFLOW + DISP_E_PARAMNOTFOUND + DISP_E_PARAMNOTOPTIONAL + DISP_E_TYPEMISMATCH + DISP_E_UNKNOWNINTERFACE + DISP_E_UNKNOWNLCID + DISP_E_UNKNOWNNAME + DRAGDROP_E_ALREADYREGISTERED + DRAGDROP_E_FIRST + DRAGDROP_E_INVALIDHWND + DRAGDROP_E_LAST + DRAGDROP_E_NOTREGISTERED + DRAGDROP_S_CANCEL + DRAGDROP_S_DROP + DRAGDROP_S_FIRST + DRAGDROP_S_LAST + DRAGDROP_S_USEDEFAULTCURSORS + DV_E_CLIPFORMAT + DV_E_DVASPECT + DV_E_DVTARGETDEVICE + DV_E_DVTARGETDEVICE_SIZE + DV_E_FORMATETC + DV_E_LINDEX + DV_E_NOIVIEWOBJECT + DV_E_STATDATA + DV_E_STGMEDIUM + DV_E_TYMED + ENUM_E_FIRST + ENUM_E_LAST + ENUM_S_FIRST + ENUM_S_LAST + EPT_S_CANT_CREATE + EPT_S_CANT_PERFORM_OP + EPT_S_INVALID_ENTRY + EPT_S_NOT_REGISTERED + ERROR_ACCESS_DENIED + ERROR_ACCOUNT_DISABLED + ERROR_ACCOUNT_EXPIRED + ERROR_ACCOUNT_LOCKED_OUT + ERROR_ACCOUNT_RESTRICTION + ERROR_ACTIVE_CONNECTIONS + ERROR_ADAP_HDW_ERR + ERROR_ADDRESS_ALREADY_ASSOCIATED + ERROR_ADDRESS_NOT_ASSOCIATED + ERROR_ALIAS_EXISTS + ERROR_ALLOTTED_SPACE_EXCEEDED + ERROR_ALREADY_ASSIGNED + ERROR_ALREADY_EXISTS + ERROR_ALREADY_REGISTERED + ERROR_ALREADY_RUNNING_LKG + ERROR_ALREADY_WAITING + ERROR_ARENA_TRASHED + ERROR_ARITHMETIC_OVERFLOW + ERROR_ATOMIC_LOCKS_NOT_SUPPORTED + ERROR_AUTODATASEG_EXCEEDS_64k + ERROR_BADDB + ERROR_BADKEY + ERROR_BAD_ARGUMENTS + ERROR_BAD_COMMAND + ERROR_BAD_DESCRIPTOR_FORMAT + ERROR_BAD_DEVICE + ERROR_BAD_DEV_TYPE + ERROR_BAD_DRIVER + ERROR_BAD_DRIVER_LEVEL + ERROR_BAD_ENVIRONMENT + ERROR_BAD_EXE_FORMAT + ERROR_BAD_FORMAT + ERROR_BAD_IMPERSONATION_LEVEL + ERROR_BAD_INHERITANCE_ACL + ERROR_BAD_LENGTH + ERROR_BAD_LOGON_SESSION_STATE + ERROR_BAD_NETPATH + ERROR_BAD_NET_NAME + ERROR_BAD_NET_RESP + ERROR_BAD_PATHNAME + ERROR_BAD_PIPE + ERROR_BAD_PROFILE + ERROR_BAD_PROVIDER + ERROR_BAD_REM_ADAP + ERROR_BAD_THREADID_ADDR + ERROR_BAD_TOKEN_TYPE + ERROR_BAD_UNIT + ERROR_BAD_USERNAME + ERROR_BAD_VALIDATION_CLASS + ERROR_BEGINNING_OF_MEDIA + ERROR_BOOT_ALREADY_ACCEPTED + ERROR_BROKEN_PIPE + ERROR_BUFFER_OVERFLOW + ERROR_BUSY + ERROR_BUSY_DRIVE + ERROR_BUS_RESET + ERROR_CALL_NOT_IMPLEMENTED + ERROR_CANCELLED + ERROR_CANCEL_VIOLATION + ERROR_CANNOT_COPY + ERROR_CANNOT_FIND_WND_CLASS + ERROR_CANNOT_IMPERSONATE + ERROR_CANNOT_MAKE + ERROR_CANNOT_OPEN_PROFILE + ERROR_CANTOPEN + ERROR_CANTREAD + ERROR_CANTWRITE + ERROR_CANT_ACCESS_DOMAIN_INFO + ERROR_CANT_DISABLE_MANDATORY + ERROR_CANT_OPEN_ANONYMOUS + ERROR_CAN_NOT_COMPLETE + ERROR_CAN_NOT_DEL_LOCAL_WINS + ERROR_CHILD_MUST_BE_VOLATILE + ERROR_CHILD_NOT_COMPLETE + ERROR_CHILD_WINDOW_MENU + ERROR_CIRCULAR_DEPENDENCY + ERROR_CLASS_ALREADY_EXISTS + ERROR_CLASS_DOES_NOT_EXIST + ERROR_CLASS_HAS_WINDOWS + ERROR_CLIPBOARD_NOT_OPEN + ERROR_CLIPPING_NOT_SUPPORTED + ERROR_CONNECTION_ABORTED + ERROR_CONNECTION_ACTIVE + ERROR_CONNECTION_COUNT_LIMIT + ERROR_CONNECTION_INVALID + ERROR_CONNECTION_REFUSED + ERROR_CONNECTION_UNAVAIL + ERROR_CONTROL_ID_NOT_FOUND + ERROR_COUNTER_TIMEOUT + ERROR_CRC + ERROR_CURRENT_DIRECTORY + ERROR_DATABASE_DOES_NOT_EXIST + ERROR_DC_NOT_FOUND + ERROR_DEPENDENT_SERVICES_RUNNING + ERROR_DESTROY_OBJECT_OF_OTHER_THREAD + ERROR_DEVICE_ALREADY_REMEMBERED + ERROR_DEVICE_IN_USE + ERROR_DEVICE_NOT_PARTITIONED + ERROR_DEV_NOT_EXIST + ERROR_DIRECTORY + ERROR_DIRECT_ACCESS_HANDLE + ERROR_DIR_NOT_EMPTY + ERROR_DIR_NOT_ROOT + ERROR_DISCARDED + ERROR_DISK_CHANGE + ERROR_DISK_CORRUPT + ERROR_DISK_FULL + ERROR_DISK_OPERATION_FAILED + ERROR_DISK_RECALIBRATE_FAILED + ERROR_DISK_RESET_FAILED + ERROR_DLL_INIT_FAILED + ERROR_DOMAIN_CONTROLLER_NOT_FOUND + ERROR_DOMAIN_EXISTS + ERROR_DOMAIN_LIMIT_EXCEEDED + ERROR_DOMAIN_TRUST_INCONSISTENT + ERROR_DRIVE_LOCKED + ERROR_DUPLICATE_SERVICE_NAME + ERROR_DUP_DOMAINNAME + ERROR_DUP_NAME + ERROR_DYNLINK_FROM_INVALID_RING + ERROR_EAS_DIDNT_FIT + ERROR_EAS_NOT_SUPPORTED + ERROR_EA_ACCESS_DENIED + ERROR_EA_FILE_CORRUPT + ERROR_EA_LIST_INCONSISTENT + ERROR_EA_TABLE_FULL + ERROR_END_OF_MEDIA + ERROR_ENVVAR_NOT_FOUND + ERROR_EOM_OVERFLOW + ERROR_EVENTLOG_CANT_START + ERROR_EVENTLOG_FILE_CHANGED + ERROR_EVENTLOG_FILE_CORRUPT + ERROR_EXCEPTION_IN_SERVICE + ERROR_EXCL_SEM_ALREADY_OWNED + ERROR_EXE_MARKED_INVALID + ERROR_EXTENDED_ERROR + ERROR_FAILED_SERVICE_CONTROLLER_CONNECT + ERROR_FAIL_I24 + ERROR_FILEMARK_DETECTED + ERROR_FILENAME_EXCED_RANGE + ERROR_FILE_CORRUPT + ERROR_FILE_EXISTS + ERROR_FILE_INVALID + ERROR_FILE_NOT_FOUND + ERROR_FLOPPY_BAD_REGISTERS + ERROR_FLOPPY_ID_MARK_NOT_FOUND + ERROR_FLOPPY_UNKNOWN_ERROR + ERROR_FLOPPY_WRONG_CYLINDER + ERROR_FULLSCREEN_MODE + ERROR_FULL_BACKUP + ERROR_GENERIC_NOT_MAPPED + ERROR_GEN_FAILURE + ERROR_GLOBAL_ONLY_HOOK + ERROR_GRACEFUL_DISCONNECT + ERROR_GROUP_EXISTS + ERROR_HANDLE_DISK_FULL + ERROR_HANDLE_EOF + ERROR_HOOK_NEEDS_HMOD + ERROR_HOOK_NOT_INSTALLED + ERROR_HOST_UNREACHABLE + ERROR_HOTKEY_ALREADY_REGISTERED + ERROR_HOTKEY_NOT_REGISTERED + ERROR_HWNDS_HAVE_DIFF_PARENT + ERROR_ILL_FORMED_PASSWORD + ERROR_INCORRECT_ADDRESS + ERROR_INC_BACKUP + ERROR_INFLOOP_IN_RELOC_CHAIN + ERROR_INSUFFICIENT_BUFFER + ERROR_INTERNAL_DB_CORRUPTION + ERROR_INTERNAL_DB_ERROR + ERROR_INTERNAL_ERROR + ERROR_INVALID_ACCEL_HANDLE + ERROR_INVALID_ACCESS + ERROR_INVALID_ACCOUNT_NAME + ERROR_INVALID_ACL + ERROR_INVALID_ADDRESS + ERROR_INVALID_AT_INTERRUPT_TIME + ERROR_INVALID_BLOCK + ERROR_INVALID_BLOCK_LENGTH + ERROR_INVALID_CATEGORY + ERROR_INVALID_COMBOBOX_MESSAGE + ERROR_INVALID_COMPUTERNAME + ERROR_INVALID_CURSOR_HANDLE + ERROR_INVALID_DATA + ERROR_INVALID_DATATYPE + ERROR_INVALID_DOMAINNAME + ERROR_INVALID_DOMAIN_ROLE + ERROR_INVALID_DOMAIN_STATE + ERROR_INVALID_DRIVE + ERROR_INVALID_DWP_HANDLE + ERROR_INVALID_EA_HANDLE + ERROR_INVALID_EA_NAME + ERROR_INVALID_EDIT_HEIGHT + ERROR_INVALID_ENVIRONMENT + ERROR_INVALID_EVENTNAME + ERROR_INVALID_EVENT_COUNT + ERROR_INVALID_EXE_SIGNATURE + ERROR_INVALID_FILTER_PROC + ERROR_INVALID_FLAGS + ERROR_INVALID_FLAG_NUMBER + ERROR_INVALID_FORM_NAME + ERROR_INVALID_FORM_SIZE + ERROR_INVALID_FUNCTION + ERROR_INVALID_GROUPNAME + ERROR_INVALID_GROUP_ATTRIBUTES + ERROR_INVALID_GW_COMMAND + ERROR_INVALID_HANDLE + ERROR_INVALID_HOOK_FILTER + ERROR_INVALID_HOOK_HANDLE + ERROR_INVALID_ICON_HANDLE + ERROR_INVALID_ID_AUTHORITY + ERROR_INVALID_INDEX + ERROR_INVALID_LB_MESSAGE + ERROR_INVALID_LEVEL + ERROR_INVALID_LIST_FORMAT + ERROR_INVALID_LOGON_HOURS + ERROR_INVALID_LOGON_TYPE + ERROR_INVALID_MEMBER + ERROR_INVALID_MENU_HANDLE + ERROR_INVALID_MESSAGE + ERROR_INVALID_MESSAGEDEST + ERROR_INVALID_MESSAGENAME + ERROR_INVALID_MINALLOCSIZE + ERROR_INVALID_MODULETYPE + ERROR_INVALID_MSGBOX_STYLE + ERROR_INVALID_NAME + ERROR_INVALID_NETNAME + ERROR_INVALID_ORDINAL + ERROR_INVALID_OWNER + ERROR_INVALID_PARAMETER + ERROR_INVALID_PASSWORD + ERROR_INVALID_PASSWORDNAME + ERROR_INVALID_PIXEL_FORMAT + ERROR_INVALID_PRIMARY_GROUP + ERROR_INVALID_PRINTER_COMMAND + ERROR_INVALID_PRINTER_NAME + ERROR_INVALID_PRINTER_STATE + ERROR_INVALID_PRIORITY + ERROR_INVALID_SCROLLBAR_RANGE + ERROR_INVALID_SECURITY_DESCR + ERROR_INVALID_SEGDPL + ERROR_INVALID_SEGMENT_NUMBER + ERROR_INVALID_SEPARATOR_FILE + ERROR_INVALID_SERVER_STATE + ERROR_INVALID_SERVICENAME + ERROR_INVALID_SERVICE_ACCOUNT + ERROR_INVALID_SERVICE_CONTROL + ERROR_INVALID_SERVICE_LOCK + ERROR_INVALID_SHARENAME + ERROR_INVALID_SHOWWIN_COMMAND + ERROR_INVALID_SID + ERROR_INVALID_SIGNAL_NUMBER + ERROR_INVALID_SPI_VALUE + ERROR_INVALID_STACKSEG + ERROR_INVALID_STARTING_CODESEG + ERROR_INVALID_SUB_AUTHORITY + ERROR_INVALID_TARGET_HANDLE + ERROR_INVALID_THREAD_ID + ERROR_INVALID_TIME + ERROR_INVALID_USER_BUFFER + ERROR_INVALID_VERIFY_SWITCH + ERROR_INVALID_WINDOW_HANDLE + ERROR_INVALID_WINDOW_STYLE + ERROR_INVALID_WORKSTATION + ERROR_IOPL_NOT_ENABLED + ERROR_IO_DEVICE + ERROR_IO_INCOMPLETE + ERROR_IO_PENDING + ERROR_IRQ_BUSY + ERROR_IS_JOINED + ERROR_IS_JOIN_PATH + ERROR_IS_JOIN_TARGET + ERROR_IS_SUBSTED + ERROR_IS_SUBST_PATH + ERROR_IS_SUBST_TARGET + ERROR_ITERATED_DATA_EXCEEDS_64k + ERROR_JOIN_TO_JOIN + ERROR_JOIN_TO_SUBST + ERROR_JOURNAL_HOOK_SET + ERROR_KEY_DELETED + ERROR_KEY_HAS_CHILDREN + ERROR_LABEL_TOO_LONG + ERROR_LAST_ADMIN + ERROR_LB_WITHOUT_TABSTOPS + ERROR_LISTBOX_ID_NOT_FOUND + ERROR_LM_CROSS_ENCRYPTION_REQUIRED + ERROR_LOCAL_USER_SESSION_KEY + ERROR_LOCKED + ERROR_LOCK_FAILED + ERROR_LOCK_VIOLATION + ERROR_LOGIN_TIME_RESTRICTION + ERROR_LOGIN_WKSTA_RESTRICTION + ERROR_LOGON_FAILURE + ERROR_LOGON_NOT_GRANTED + ERROR_LOGON_SESSION_COLLISION + ERROR_LOGON_SESSION_EXISTS + ERROR_LOGON_TYPE_NOT_GRANTED + ERROR_LOG_FILE_FULL + ERROR_LUIDS_EXHAUSTED + ERROR_MAPPED_ALIGNMENT + ERROR_MAX_THRDS_REACHED + ERROR_MEDIA_CHANGED + ERROR_MEMBERS_PRIMARY_GROUP + ERROR_MEMBER_IN_ALIAS + ERROR_MEMBER_IN_GROUP + ERROR_MEMBER_NOT_IN_ALIAS + ERROR_MEMBER_NOT_IN_GROUP + ERROR_METAFILE_NOT_SUPPORTED + ERROR_META_EXPANSION_TOO_LONG + ERROR_MOD_NOT_FOUND + ERROR_MORE_DATA + ERROR_MORE_WRITES + ERROR_MR_MID_NOT_FOUND + ERROR_NEGATIVE_SEEK + ERROR_NESTING_NOT_ALLOWED + ERROR_NETLOGON_NOT_STARTED + ERROR_NETNAME_DELETED + ERROR_NETWORK_ACCESS_DENIED + ERROR_NETWORK_BUSY + ERROR_NETWORK_UNREACHABLE + ERROR_NET_WRITE_FAULT + ERROR_NOACCESS + ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT + ERROR_NOLOGON_SERVER_TRUST_ACCOUNT + ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT + ERROR_NONE_MAPPED + ERROR_NON_MDICHILD_WINDOW + ERROR_NOTIFY_ENUM_DIR + ERROR_NOT_ALL_ASSIGNED + ERROR_NOT_CHILD_WINDOW + ERROR_NOT_CONNECTED + ERROR_NOT_CONTAINER + ERROR_NOT_DOS_DISK + ERROR_NOT_ENOUGH_MEMORY + ERROR_NOT_ENOUGH_QUOTA + ERROR_NOT_ENOUGH_SERVER_MEMORY + ERROR_NOT_JOINED + ERROR_NOT_LOCKED + ERROR_NOT_LOGON_PROCESS + ERROR_NOT_OWNER + ERROR_NOT_READY + ERROR_NOT_REGISTRY_FILE + ERROR_NOT_SAME_DEVICE + ERROR_NOT_SUBSTED + ERROR_NOT_SUPPORTED + ERROR_NO_BROWSER_SERVERS_FOUND + ERROR_NO_DATA + ERROR_NO_DATA_DETECTED + ERROR_NO_IMPERSONATION_TOKEN + ERROR_NO_INHERITANCE + ERROR_NO_LOGON_SERVERS + ERROR_NO_LOG_SPACE + ERROR_NO_MEDIA_IN_DRIVE + ERROR_NO_MORE_FILES + ERROR_NO_MORE_ITEMS + ERROR_NO_MORE_SEARCH_HANDLES + ERROR_NO_NETWORK + ERROR_NO_NET_OR_BAD_PATH + ERROR_NO_PROC_SLOTS + ERROR_NO_QUOTAS_FOR_ACCOUNT + ERROR_NO_SCROLLBARS + ERROR_NO_SECURITY_ON_OBJECT + ERROR_NO_SHUTDOWN_IN_PROGRESS + ERROR_NO_SIGNAL_SENT + ERROR_NO_SPOOL_SPACE + ERROR_NO_SUCH_ALIAS + ERROR_NO_SUCH_DOMAIN + ERROR_NO_SUCH_GROUP + ERROR_NO_SUCH_LOGON_SESSION + ERROR_NO_SUCH_MEMBER + ERROR_NO_SUCH_PACKAGE + ERROR_NO_SUCH_PRIVILEGE + ERROR_NO_SUCH_USER + ERROR_NO_SYSTEM_MENU + ERROR_NO_TOKEN + ERROR_NO_TRUST_LSA_SECRET + ERROR_NO_TRUST_SAM_ACCOUNT + ERROR_NO_UNICODE_TRANSLATION + ERROR_NO_USER_SESSION_KEY + ERROR_NO_VOLUME_LABEL + ERROR_NO_WILDCARD_CHARACTERS + ERROR_NT_CROSS_ENCRYPTION_REQUIRED + ERROR_NULL_LM_PASSWORD + ERROR_OPEN_FAILED + ERROR_OPEN_FILES + ERROR_OPERATION_ABORTED + ERROR_OUTOFMEMORY + ERROR_OUT_OF_PAPER + ERROR_OUT_OF_STRUCTURES + ERROR_PARTIAL_COPY + ERROR_PARTITION_FAILURE + ERROR_PASSWORD_EXPIRED + ERROR_PASSWORD_MUST_CHANGE + ERROR_PASSWORD_RESTRICTION + ERROR_PATH_BUSY + ERROR_PATH_NOT_FOUND + ERROR_PIPE_BUSY + ERROR_PIPE_CONNECTED + ERROR_PIPE_LISTENING + ERROR_PIPE_NOT_CONNECTED + ERROR_POPUP_ALREADY_ACTIVE + ERROR_PORT_UNREACHABLE + ERROR_POSSIBLE_DEADLOCK + ERROR_PRINTER_ALREADY_EXISTS + ERROR_PRINTER_DELETED + ERROR_PRINTER_DRIVER_ALREADY_INSTALLED + ERROR_PRINTER_DRIVER_IN_USE + ERROR_PRINTQ_FULL + ERROR_PRINT_CANCELLED + ERROR_PRINT_MONITOR_ALREADY_INSTALLED + ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED + ERROR_PRIVATE_DIALOG_INDEX + ERROR_PRIVILEGE_NOT_HELD + ERROR_PROCESS_ABORTED + ERROR_PROC_NOT_FOUND + ERROR_PROTOCOL_UNREACHABLE + ERROR_READ_FAULT + ERROR_REC_NON_EXISTENT + ERROR_REDIRECTOR_HAS_OPEN_HANDLES + ERROR_REDIR_PAUSED + ERROR_REGISTRY_CORRUPT + ERROR_REGISTRY_IO_FAILED + ERROR_REGISTRY_RECOVERED + ERROR_RELOC_CHAIN_XEEDS_SEGLIM + ERROR_REMOTE_SESSION_LIMIT_EXCEEDED + ERROR_REM_NOT_LIST + ERROR_REQUEST_ABORTED + ERROR_REQ_NOT_ACCEP + ERROR_RESOURCE_DATA_NOT_FOUND + ERROR_RESOURCE_LANG_NOT_FOUND + ERROR_RESOURCE_NAME_NOT_FOUND + ERROR_RESOURCE_TYPE_NOT_FOUND + ERROR_RETRY + ERROR_REVISION_MISMATCH + ERROR_RING2SEG_MUST_BE_MOVABLE + ERROR_RING2_STACK_IN_USE + ERROR_RPL_NOT_ALLOWED + ERROR_RXACT_COMMIT_FAILURE + ERROR_RXACT_INVALID_STATE + ERROR_SAME_DRIVE + ERROR_SCREEN_ALREADY_LOCKED + ERROR_SECRET_TOO_LONG + ERROR_SECTOR_NOT_FOUND + ERROR_SEEK + ERROR_SEEK_ON_DEVICE + ERROR_SEM_IS_SET + ERROR_SEM_NOT_FOUND + ERROR_SEM_OWNER_DIED + ERROR_SEM_TIMEOUT + ERROR_SEM_USER_LIMIT + ERROR_SERIAL_NO_DEVICE + ERROR_SERVER_DISABLED + ERROR_SERVER_HAS_OPEN_HANDLES + ERROR_SERVER_NOT_DISABLED + ERROR_SERVICE_ALREADY_RUNNING + ERROR_SERVICE_CANNOT_ACCEPT_CTRL + ERROR_SERVICE_DATABASE_LOCKED + ERROR_SERVICE_DEPENDENCY_DELETED + ERROR_SERVICE_DEPENDENCY_FAIL + ERROR_SERVICE_DISABLED + ERROR_SERVICE_DOES_NOT_EXIST + ERROR_SERVICE_EXISTS + ERROR_SERVICE_LOGON_FAILED + ERROR_SERVICE_MARKED_FOR_DELETE + ERROR_SERVICE_NEVER_STARTED + ERROR_SERVICE_NOT_ACTIVE + ERROR_SERVICE_NOT_FOUND + ERROR_SERVICE_NO_THREAD + ERROR_SERVICE_REQUEST_TIMEOUT + ERROR_SERVICE_SPECIFIC_ERROR + ERROR_SERVICE_START_HANG + ERROR_SESSION_CREDENTIAL_CONFLICT + ERROR_SETCOUNT_ON_BAD_LB + ERROR_SETMARK_DETECTED + ERROR_SHARING_BUFFER_EXCEEDED + ERROR_SHARING_PAUSED + ERROR_SHARING_VIOLATION + ERROR_SHUTDOWN_IN_PROGRESS + ERROR_SIGNAL_PENDING + ERROR_SIGNAL_REFUSED + ERROR_SOME_NOT_MAPPED + ERROR_SPECIAL_ACCOUNT + ERROR_SPECIAL_GROUP + ERROR_SPECIAL_USER + ERROR_SPL_NO_ADDJOB + ERROR_SPL_NO_STARTDOC + ERROR_SPOOL_FILE_NOT_FOUND + ERROR_STACK_OVERFLOW + ERROR_STATIC_INIT + ERROR_SUBST_TO_JOIN + ERROR_SUBST_TO_SUBST + ERROR_SUCCESS + ERROR_SWAPERROR + ERROR_SYSTEM_TRACE + ERROR_THREAD_1_INACTIVE + ERROR_TLW_WITH_WSCHILD + ERROR_TOKEN_ALREADY_IN_USE + ERROR_TOO_MANY_CMDS + ERROR_TOO_MANY_CONTEXT_IDS + ERROR_TOO_MANY_LUIDS_REQUESTED + ERROR_TOO_MANY_MODULES + ERROR_TOO_MANY_MUXWAITERS + ERROR_TOO_MANY_NAMES + ERROR_TOO_MANY_OPEN_FILES + ERROR_TOO_MANY_POSTS + ERROR_TOO_MANY_SECRETS + ERROR_TOO_MANY_SEMAPHORES + ERROR_TOO_MANY_SEM_REQUESTS + ERROR_TOO_MANY_SESS + ERROR_TOO_MANY_SIDS + ERROR_TOO_MANY_TCBS + ERROR_TRANSFORM_NOT_SUPPORTED + ERROR_TRUSTED_DOMAIN_FAILURE + ERROR_TRUSTED_RELATIONSHIP_FAILURE + ERROR_TRUST_FAILURE + ERROR_UNABLE_TO_LOCK_MEDIA + ERROR_UNABLE_TO_UNLOAD_MEDIA + ERROR_UNEXP_NET_ERR + ERROR_UNKNOWN_PORT + ERROR_UNKNOWN_PRINTER_DRIVER + ERROR_UNKNOWN_PRINTPROCESSOR + ERROR_UNKNOWN_PRINT_MONITOR + ERROR_UNKNOWN_REVISION + ERROR_UNRECOGNIZED_MEDIA + ERROR_UNRECOGNIZED_VOLUME + ERROR_USER_EXISTS + ERROR_USER_MAPPED_FILE + ERROR_VC_DISCONNECTED + ERROR_WAIT_NO_CHILDREN + ERROR_WINDOW_NOT_COMBOBOX + ERROR_WINDOW_NOT_DIALOG + ERROR_WINDOW_OF_OTHER_THREAD + ERROR_WINS_INTERNAL + ERROR_WRITE_FAULT + ERROR_WRITE_PROTECT + ERROR_WRONG_DISK + ERROR_WRONG_PASSWORD + E_ABORT + E_ACCESSDENIED + E_FAIL + E_HANDLE + E_INVALIDARG + E_NOINTERFACE + E_NOTIMPL + E_OUTOFMEMORY + E_POINTER + E_UNEXPECTED + FACILITY_CONTROL + FACILITY_DISPATCH + FACILITY_ITF + FACILITY_NT_BIT + FACILITY_NULL + FACILITY_RPC + FACILITY_STORAGE + FACILITY_WIN32 + FACILITY_WINDOWS + INPLACE_E_FIRST + INPLACE_E_LAST + INPLACE_E_NOTOOLSPACE + INPLACE_E_NOTUNDOABLE + INPLACE_S_FIRST + INPLACE_S_LAST + INPLACE_S_TRUNCATED + MARSHAL_E_FIRST + MARSHAL_E_LAST + MARSHAL_S_FIRST + MARSHAL_S_LAST + MEM_E_INVALID_LINK + MEM_E_INVALID_ROOT + MEM_E_INVALID_SIZE + MK_E_CANTOPENFILE + MK_E_CONNECTMANUALLY + MK_E_ENUMERATION_FAILED + MK_E_EXCEEDEDDEADLINE + MK_E_FIRST + MK_E_INTERMEDIATEINTERFACENOTSUPPORTED + MK_E_INVALIDEXTENSION + MK_E_LAST + MK_E_MUSTBOTHERUSER + MK_E_NEEDGENERIC + MK_E_NOINVERSE + MK_E_NOOBJECT + MK_E_NOPREFIX + MK_E_NOSTORAGE + MK_E_NOTBINDABLE + MK_E_NOTBOUND + MK_E_NO_NORMALIZED + MK_E_SYNTAX + MK_E_UNAVAILABLE + MK_S_FIRST + MK_S_HIM + MK_S_LAST + MK_S_ME + MK_S_MONIKERALREADYREGISTERED + MK_S_REDUCED_TO_SELF + MK_S_US + NOERROR + NO_ERROR + OLEOBJ_E_FIRST + OLEOBJ_E_INVALIDVERB + OLEOBJ_E_LAST + OLEOBJ_E_NOVERBS + OLEOBJ_S_CANNOT_DOVERB_NOW + OLEOBJ_S_FIRST + OLEOBJ_S_INVALIDHWND + OLEOBJ_S_INVALIDVERB + OLEOBJ_S_LAST + OLE_E_ADVF + OLE_E_ADVISENOTSUPPORTED + OLE_E_BLANK + OLE_E_CANTCONVERT + OLE_E_CANT_BINDTOSOURCE + OLE_E_CANT_GETMONIKER + OLE_E_CLASSDIFF + OLE_E_ENUM_NOMORE + OLE_E_FIRST + OLE_E_INVALIDHWND + OLE_E_INVALIDRECT + OLE_E_LAST + OLE_E_NOCACHE + OLE_E_NOCONNECTION + OLE_E_NOSTORAGE + OLE_E_NOTRUNNING + OLE_E_NOT_INPLACEACTIVE + OLE_E_OLEVERB + OLE_E_PROMPTSAVECANCELLED + OLE_E_STATIC + OLE_E_WRONGCOMPOBJ + OLE_S_FIRST + OLE_S_LAST + OLE_S_MAC_CLIPFORMAT + OLE_S_STATIC + OLE_S_USEREG + REGDB_E_CLASSNOTREG + REGDB_E_FIRST + REGDB_E_IIDNOTREG + REGDB_E_INVALIDVALUE + REGDB_E_KEYMISSING + REGDB_E_LAST + REGDB_E_READREGDB + REGDB_E_WRITEREGDB + REGDB_S_FIRST + REGDB_S_LAST + RPC_E_ATTEMPTED_MULTITHREAD + RPC_E_CALL_CANCELED + RPC_E_CALL_REJECTED + RPC_E_CANTCALLOUT_AGAIN + RPC_E_CANTCALLOUT_INASYNCCALL + RPC_E_CANTCALLOUT_INEXTERNALCALL + RPC_E_CANTCALLOUT_ININPUTSYNCCALL + RPC_E_CANTPOST_INSENDCALL + RPC_E_CANTTRANSMIT_CALL + RPC_E_CHANGED_MODE + RPC_E_CLIENT_CANTMARSHAL_DATA + RPC_E_CLIENT_CANTUNMARSHAL_DATA + RPC_E_CLIENT_DIED + RPC_E_CONNECTION_TERMINATED + RPC_E_DISCONNECTED + RPC_E_FAULT + RPC_E_INVALIDMETHOD + RPC_E_INVALID_CALLDATA + RPC_E_INVALID_DATA + RPC_E_INVALID_DATAPACKET + RPC_E_INVALID_PARAMETER + RPC_E_NOT_REGISTERED + RPC_E_OUT_OF_RESOURCES + RPC_E_RETRY + RPC_E_SERVERCALL_REJECTED + RPC_E_SERVERCALL_RETRYLATER + RPC_E_SERVERFAULT + RPC_E_SERVER_CANTMARSHAL_DATA + RPC_E_SERVER_CANTUNMARSHAL_DATA + RPC_E_SERVER_DIED + RPC_E_SERVER_DIED_DNE + RPC_E_SYS_CALL_FAILED + RPC_E_THREAD_NOT_INIT + RPC_E_UNEXPECTED + RPC_E_WRONG_THREAD + RPC_S_ADDRESS_ERROR + RPC_S_ALREADY_LISTENING + RPC_S_ALREADY_REGISTERED + RPC_S_BINDING_HAS_NO_AUTH + RPC_S_BINDING_INCOMPLETE + RPC_S_CALL_CANCELLED + RPC_S_CALL_FAILED + RPC_S_CALL_FAILED_DNE + RPC_S_CALL_IN_PROGRESS + RPC_S_CANNOT_SUPPORT + RPC_S_CANT_CREATE_ENDPOINT + RPC_S_COMM_FAILURE + RPC_S_DUPLICATE_ENDPOINT + RPC_S_ENTRY_ALREADY_EXISTS + RPC_S_ENTRY_NOT_FOUND + RPC_S_FP_DIV_ZERO + RPC_S_FP_OVERFLOW + RPC_S_FP_UNDERFLOW + RPC_S_GROUP_MEMBER_NOT_FOUND + RPC_S_INCOMPLETE_NAME + RPC_S_INTERFACE_NOT_FOUND + RPC_S_INTERNAL_ERROR + RPC_S_INVALID_AUTH_IDENTITY + RPC_S_INVALID_BINDING + RPC_S_INVALID_BOUND + RPC_S_INVALID_ENDPOINT_FORMAT + RPC_S_INVALID_NAF_ID + RPC_S_INVALID_NAME_SYNTAX + RPC_S_INVALID_NETWORK_OPTIONS + RPC_S_INVALID_NET_ADDR + RPC_S_INVALID_OBJECT + RPC_S_INVALID_RPC_PROTSEQ + RPC_S_INVALID_STRING_BINDING + RPC_S_INVALID_STRING_UUID + RPC_S_INVALID_TAG + RPC_S_INVALID_TIMEOUT + RPC_S_INVALID_VERS_OPTION + RPC_S_MAX_CALLS_TOO_SMALL + RPC_S_NAME_SERVICE_UNAVAILABLE + RPC_S_NOTHING_TO_EXPORT + RPC_S_NOT_ALL_OBJS_UNEXPORTED + RPC_S_NOT_CANCELLED + RPC_S_NOT_LISTENING + RPC_S_NOT_RPC_ERROR + RPC_S_NO_BINDINGS + RPC_S_NO_CALL_ACTIVE + RPC_S_NO_CONTEXT_AVAILABLE + RPC_S_NO_ENDPOINT_FOUND + RPC_S_NO_ENTRY_NAME + RPC_S_NO_INTERFACES + RPC_S_NO_MORE_BINDINGS + RPC_S_NO_MORE_MEMBERS + RPC_S_NO_PRINC_NAME + RPC_S_NO_PROTSEQS + RPC_S_NO_PROTSEQS_REGISTERED + RPC_S_OBJECT_NOT_FOUND + RPC_S_OUT_OF_RESOURCES + RPC_S_PROCNUM_OUT_OF_RANGE + RPC_S_PROTOCOL_ERROR + RPC_S_PROTSEQ_NOT_FOUND + RPC_S_PROTSEQ_NOT_SUPPORTED + RPC_S_SEC_PKG_ERROR + RPC_S_SERVER_TOO_BUSY + RPC_S_SERVER_UNAVAILABLE + RPC_S_STRING_TOO_LONG + RPC_S_TYPE_ALREADY_REGISTERED + RPC_S_UNKNOWN_AUTHN_LEVEL + RPC_S_UNKNOWN_AUTHN_SERVICE + RPC_S_UNKNOWN_AUTHN_TYPE + RPC_S_UNKNOWN_AUTHZ_SERVICE + RPC_S_UNKNOWN_IF + RPC_S_UNKNOWN_MGR_TYPE + RPC_S_UNSUPPORTED_AUTHN_LEVEL + RPC_S_UNSUPPORTED_NAME_SYNTAX + RPC_S_UNSUPPORTED_TRANS_SYN + RPC_S_UNSUPPORTED_TYPE + RPC_S_UUID_LOCAL_ONLY + RPC_S_UUID_NO_ADDRESS + RPC_S_WRONG_KIND_OF_BINDING + RPC_S_ZERO_DIVIDE + RPC_X_BAD_STUB_DATA + RPC_X_BYTE_COUNT_TOO_SMALL + RPC_X_ENUM_VALUE_OUT_OF_RANGE + RPC_X_INVALID_ES_ACTION + RPC_X_NO_MORE_ENTRIES + RPC_X_NULL_REF_POINTER + RPC_X_SS_CANNOT_GET_CALL_HANDLE + RPC_X_SS_CHAR_TRANS_OPEN_FAIL + RPC_X_SS_CHAR_TRANS_SHORT_FILE + RPC_X_SS_CONTEXT_DAMAGED + RPC_X_SS_HANDLES_MISMATCH + RPC_X_SS_IN_NULL_CONTEXT + RPC_X_WRONG_ES_VERSION + RPC_X_WRONG_STUB_VERSION + SEVERITY_ERROR + SEVERITY_SUCCESS + STG_E_ABNORMALAPIEXIT + STG_E_ACCESSDENIED + STG_E_CANTSAVE + STG_E_DISKISWRITEPROTECTED + STG_E_EXTANTMARSHALLINGS + STG_E_FILEALREADYEXISTS + STG_E_FILENOTFOUND + STG_E_INSUFFICIENTMEMORY + STG_E_INUSE + STG_E_INVALIDFLAG + STG_E_INVALIDFUNCTION + STG_E_INVALIDHANDLE + STG_E_INVALIDHEADER + STG_E_INVALIDNAME + STG_E_INVALIDPARAMETER + STG_E_INVALIDPOINTER + STG_E_LOCKVIOLATION + STG_E_MEDIUMFULL + STG_E_NOMOREFILES + STG_E_NOTCURRENT + STG_E_NOTFILEBASEDSTORAGE + STG_E_OLDDLL + STG_E_OLDFORMAT + STG_E_PATHNOTFOUND + STG_E_READFAULT + STG_E_REVERTED + STG_E_SEEKERROR + STG_E_SHAREREQUIRED + STG_E_SHAREVIOLATION + STG_E_TOOMANYOPENFILES + STG_E_UNIMPLEMENTEDFUNCTION + STG_E_UNKNOWN + STG_E_WRITEFAULT + STG_S_CONVERTED + S_FALSE + S_OK + TYPE_E_AMBIGUOUSNAME + TYPE_E_BADMODULEKIND + TYPE_E_BUFFERTOOSMALL + TYPE_E_CANTCREATETMPFILE + TYPE_E_CANTLOADLIBRARY + TYPE_E_CIRCULARTYPE + TYPE_E_DLLFUNCTIONNOTFOUND + TYPE_E_DUPLICATEID + TYPE_E_ELEMENTNOTFOUND + TYPE_E_INCONSISTENTPROPFUNCS + TYPE_E_INVALIDID + TYPE_E_INVALIDSTATE + TYPE_E_INVDATAREAD + TYPE_E_IOERROR + TYPE_E_LIBNOTREGISTERED + TYPE_E_NAMECONFLICT + TYPE_E_OUTOFBOUNDS + TYPE_E_QUALIFIEDNAMEDISALLOWED + TYPE_E_REGISTRYACCESS + TYPE_E_SIZETOOBIG + TYPE_E_TYPEMISMATCH + TYPE_E_UNDEFINEDTYPE + TYPE_E_UNKNOWNLCID + TYPE_E_UNSUPFORMAT + TYPE_E_WRONGTYPEKIND + VIEW_E_DRAW + VIEW_E_FIRST + VIEW_E_LAST + VIEW_S_ALREADY_FROZEN + VIEW_S_FIRST + VIEW_S_LAST +); + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + #reset $! to zero to reset any current errors. + local $! = 0; + local $^E = 0; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + ($pack,$file,$line) = caller; + die "Your vendor has not defined Win32::WinError macro $constname, used at $file line $line."; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap Win32::WinError; + +# Preloaded methods go here. + +# Autoload methods go after __END__, and are processed by the autosplit program. + +1; +__END__ diff --git a/Master/tlpkg/tlperl/lib/Win32/test-async.pl b/Master/tlpkg/tlperl/lib/Win32/test-async.pl new file mode 100644 index 00000000000..c47e2df04ec --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Win32/test-async.pl @@ -0,0 +1,129 @@ +# +# TEST-ASYNC.PL +# Test Win32::Internet's Asynchronous Operations +# by Aldo Calpini <dada@divinf.it> +# +# WARNING: this code is most likely to fail with almost-random errors +# I don't know what is wrong here, any hint will be greatly +# appreciated! + +use Win32::Internet; + +$params{'flags'} = INTERNET_FLAG_ASYNC; +$params{'opentype'} = INTERNET_OPEN_TYPE_DIRECT; +$I = new Win32::Internet(\%params); + +# print "Error: ", $I->Error(), "\n"; +print "I.handle=", $I->{'handle'}, "\n"; + +$return = $I->SetStatusCallback(); +print "SetStatusCallback=$return"; +print "ERROR" if $return eq undef; +print "\n"; + +$buffer = $I->QueryOption(INTERNET_OPTION_READ_BUFFER_SIZE); +print "Buffer=$buffer\n"; + +$host = "ftp.activeware.com"; +$user = "anonymous"; +$pass = "dada\@divinf.it"; + + +print "Doing FTP()...\n"; + +$handle2 = $I->FTP($FTP, $host, $user, $pass, 21, 1); + +print "Returned from FTP()...\n"; + +($n, $t) = $I->Error(); + +if($n == 997) { + print "Going asynchronous...\n"; + ($status, $info) = $I->GetStatusCallback(1); + while($status != 100 and $status != 70) { + if($oldstatus != $status) { + if($status == 60) { + $FTP->{'handle'} = $info; + } elsif($status == 10) { + print "resolving name... \n"; + } elsif($status == 11) { + print "name resolved... \n"; + } elsif($status == 20) { + print "connecting... \n"; + } elsif($status == 21) { + print "connected... \n"; + } elsif($status == 30) { + print "sending... \n"; + } elsif($status == 31) { + print "$info bytes sent. \n"; + } elsif($status == 40) { + print "receiving... \n"; + } elsif($status == 41) { + print "$info bytes received. \n"; + } else { + print "status=$status\n"; + } + } + $oldstatus = $status; + ($status, $info) = $I->GetStatusCallback(1); + } +} else { + print "Error=", $I->Error(), "\n"; +} +print "FTP.handle=", $FTP->{'handle'}, "\n"; +print "STATUS(after FTP)=", $I->GetStatusCallback(1), "\n"; + +# "/pub/microsoft/sdk/activex13.exe", + +print "Doing Get()...\n"; + +$file = "/Perl-Win32/perl5.001m/currentBuild/110-i86.zip"; + +$FTP->Get($file, "110-i86.zip", 1, 0, 2); + +print "Returned from Get()...\n"; + +($n, $t) = $I->Error(); +if($n == 997) { + print "Going asynchronous...\n"; + $bytes = 0; + $oldstatus = 0; + ($status, $info) = $I->GetStatusCallback(2); + while($status != 100 and $status != 70) { + # print "status=$status info=$info\n"; + # if($oldstatus!=$status) { + if($status == 10) { + print "resolving name... \n"; + } elsif($status == 11) { + print "name resolved... \n"; + } elsif($status == 20) { + print "connecting... \n"; + } elsif($status == 21) { + print "connected... \n"; + #} elsif($status == 30) { + # print "sending... \n"; + } elsif($status == 31) { + print "$info bytes sent. \n"; + #} elsif($status == 40) { + # print "receiving... \n"; + } elsif($status == 41) { + $bytes = $bytes+$info; + print "$bytes bytes received. \n"; + #} else { + # print "status=$status\n"; + } + # } + $oldstatus = $status; + undef $status, $info; + ($status, $info) = $I->GetStatusCallback(2); + } +} else { + print "Error=[$n] $t\n"; +} +print "\n"; +($status, $info) = $I->GetStatusCallback(2); +print "STATUS(after Get)=$status\n"; +print "Error=", $I->Error(), "\n"; +exit(0); + + |