home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / API.pm < prev    next >
Encoding:
Perl POD Document  |  2003-03-10  |  21.4 KB  |  720 lines

  1. package Win32::API;
  2.  
  3. # See the bottom of this file for the POD documentation.  Search for the
  4. # string '=head'.
  5.  
  6. #######################################################################
  7. #
  8. # Win32::API - Perl Win32 API Import Facility
  9. # Version: 0.41 
  10. # Date: 10 Mar 2003
  11. # Author: Aldo Calpini <dada@perl.it>
  12. # $Id: API.pm,v 1.0 2001/10/30 13:57:31 dada Exp $
  13. #######################################################################
  14.  
  15. require Exporter;       # to export the constants to the main:: space
  16. require DynaLoader;     # to dynuhlode the module.
  17. @ISA = qw( Exporter DynaLoader );
  18.  
  19. use vars qw( $DEBUG );
  20. $DEBUG = 0;
  21.  
  22. sub DEBUG { 
  23.     if ($Win32::API::DEBUG) { 
  24.         printf @_ if @_ or return 1; 
  25.     } else {
  26.         return 0;
  27.     }
  28. }
  29.  
  30. use Win32::API::Type;
  31. use Win32::API::Struct;
  32.  
  33. #######################################################################
  34. # STATIC OBJECT PROPERTIES
  35. #
  36. $VERSION = "0.41";
  37.  
  38. #### some package-global hash to 
  39. #### keep track of the imported 
  40. #### libraries and procedures
  41. my %Libraries = ();
  42. my %Procedures = ();
  43.  
  44.  
  45. #######################################################################
  46. # dynamically load in the API extension module.
  47. #
  48. bootstrap Win32::API;
  49.  
  50. #######################################################################
  51. # PUBLIC METHODS
  52. #
  53. sub new {
  54.     my($class, $dll, $proc, $in, $out) = @_;
  55.     my $hdll;   
  56.     my $self = {};
  57.   
  58.     #### avoid loading a library more than once
  59.     if(exists($Libraries{$dll})) {
  60.         # print "Win32::API::new: Library '$dll' already loaded, handle=$Libraries{$dll}\n";
  61.         $hdll = $Libraries{$dll};
  62.     } else {
  63.         # print "Win32::API::new: Loading library '$dll'\n";
  64.         $hdll = Win32::API::LoadLibrary($dll);
  65.         $Libraries{$dll} = $hdll;
  66.     }
  67.  
  68.     #### if the dll can't be loaded, set $! to Win32's GetLastError()
  69.     if(!$hdll) {
  70.         $! = Win32::GetLastError();
  71.         return undef;
  72.     }
  73.  
  74.     #### determine if we have a prototype or not
  75.     if( (not defined $in) and (not defined $out) ) {
  76.         ($proc, $self->{in}, $self->{intypes}, $self->{out}) = parse_prototype( $proc );
  77.         return undef unless $proc;
  78.         $self->{proto} = 1;
  79.     } else {
  80.         $self->{in} = [];
  81.         if(ref($in) eq 'ARRAY') {
  82.             foreach (@$in) {
  83.                 push(@{ $self->{in} }, type_to_num($_));
  84.             }   
  85.         } else {
  86.             my @in = split '', $in;
  87.             foreach (@in) {
  88.                 push(@{ $self->{in} }, type_to_num($_));
  89.             }           
  90.         }
  91.         $self->{out} = type_to_num($out);
  92.     }
  93.  
  94.     #### first try to import the function of given name...
  95.     my $hproc = Win32::API::GetProcAddress($hdll, $proc);
  96.  
  97.     #### ...then try appending either A or W (for ASCII or Unicode)
  98.     if(!$hproc) {
  99.         my $tproc = $proc;
  100.         $tproc .= (IsUnicode() ? "W" : "A");
  101.         # print "Win32::API::new: procedure not found, trying '$tproc'...\n";
  102.         $hproc = Win32::API::GetProcAddress($hdll, $tproc);
  103.     }
  104.  
  105.     #### ...if all that fails, set $! accordingly
  106.     if(!$hproc) {
  107.         $! = Win32::GetLastError();
  108.         return undef;
  109.     }
  110.     
  111.     #### ok, let's stuff the object
  112.     $self->{procname} = $proc;
  113.     $self->{dll} = $hdll;
  114.     $self->{dllname} = $dll;
  115.     $self->{proc} = $hproc;
  116.  
  117.     #### keep track of the imported function
  118.     $Libraries{$dll} = $hdll;
  119.     $Procedures{$dll}++;
  120.  
  121.     #### cast the spell
  122.     bless($self, $class);
  123.     return $self;
  124. }
  125.  
  126. sub Import {
  127.     my($class, $dll, $proc, $in, $out) = @_;
  128.     $Imported{"$dll:$proc"} = Win32::API->new($dll, $proc, $in, $out) or return 0;
  129.     my $P = (caller)[0];
  130.     eval qq(
  131.         sub ${P}::$Imported{"$dll:$proc"}->{procname} { \$Win32::API::Imported{"$dll:$proc"}->Call(\@_); }
  132.     );
  133.     return $@ ? 0 : 1;
  134. }
  135.  
  136.  
  137. #######################################################################
  138. # PRIVATE METHODS
  139. #
  140. sub DESTROY {
  141.     my($self) = @_;
  142.  
  143.     #### decrease this library's procedures reference count
  144.     $Procedures{$self->{dllname}}--;
  145.  
  146.     #### once it reaches 0, free it
  147.     if($Procedures{$self->{dllname}} == 0) {
  148.         # print "Win32::API::DESTROY: Freeing library '$self->{dllname}'\n";
  149.         Win32::API::FreeLibrary($Libraries{$self->{dllname}});
  150.         delete($Libraries{$self->{dllname}});
  151.     }    
  152. }
  153.  
  154. sub type_to_num {
  155.     my $type = shift;
  156.     my $out = shift;
  157.     my $num;
  158.     
  159.     if(     $type eq 'N'
  160.     or      $type eq 'n'
  161.     or      $type eq 'l'
  162.     or      $type eq 'L'
  163.     ) {
  164.         $num = 1;
  165.     } elsif($type eq 'P'
  166.     or      $type eq 'p'
  167.     ) {
  168.         $num = 2;
  169.     } elsif($type eq 'I'
  170.     or      $type eq 'i'
  171.     ) {
  172.         $num = 3;
  173.     } elsif($type eq 'f'
  174.     or      $type eq 'F'
  175.     ) {
  176.         $num = 4;
  177.     } elsif($type eq 'D'
  178.     or      $type eq 'd'
  179.     ) {
  180.         $num = 5;
  181.     } elsif($type eq 'c'
  182.     or      $type eq 'C'
  183.     ) {
  184.         $num = 6;
  185.     } else {
  186.         $num = 0;
  187.     }       
  188.     unless(defined $out) {
  189.         if(     $type eq 's'
  190.         or      $type eq 'S'
  191.         ) {
  192.             $num = 51;
  193.         } elsif($type eq 'b'
  194.         or      $type eq 'B'
  195.         ) {
  196.             $num = 22;
  197.         } elsif($type eq 'k'
  198.         or      $type eq 'K'
  199.         ) {
  200.             $num = 101;
  201.         }       
  202.     }
  203.     return $num;
  204. }
  205.  
  206. sub parse_prototype {
  207.     my($proto) = @_;
  208.     
  209.     my @in_params = ();
  210.     my @in_types = ();
  211.     if($proto =~ /^\s*(\S+)\s+(\S+)\s*\(([^\)]*)\)/) {
  212.         my $ret = $1;
  213.         my $proc = $2;
  214.         my $params = $3;
  215.         
  216.         $params =~ s/^\s+//;
  217.         $params =~ s/\s+$//;
  218.         
  219.         DEBUG "(PM)parse_prototype: got PROC '%s'\n", $proc;
  220.         DEBUG "(PM)parse_prototype: got PARAMS '%s'\n", $params;
  221.         
  222.         foreach my $param (split(/\s*,\s*/, $params)) {
  223.             my($type, $name);
  224.             if($param =~ /(\S+)\s+(\S+)/) {
  225.                 ($type, $name) = ($1, $2);
  226.             }
  227.             
  228.             if(Win32::API::Type::is_known($type)) {
  229.                 if(Win32::API::Type::is_pointer($type)) {
  230.                     DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n",
  231.                         $type, 
  232.                         Win32::API::Type->packing( $type ), 
  233.                         type_to_num('P');
  234.                     push(@in_params, type_to_num('P'));
  235.                 } else {        
  236.                     DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n",
  237.                         $type, 
  238.                         Win32::API::Type->packing( $type ), 
  239.                         type_to_num( Win32::API::Type->packing( $type ) );
  240.                     push(@in_params, type_to_num( Win32::API::Type->packing( $type ) ));
  241.                 }
  242.             } elsif( Win32::API::Struct::is_known( $type ) ) {
  243.                 DEBUG "(PM)parse_prototype: IN='%s' PACKING='%s' API_TYPE=%d\n",
  244.                     $type, 'S', type_to_num('S');
  245.                 push(@in_params, type_to_num('S'));
  246.             } else {
  247.                 warn "Win32::API::parse_prototype: WARNING unknown parameter type '$type'";
  248.                 push(@in_params, type_to_num('I'));
  249.             }
  250.             push(@in_types, $type);
  251.             
  252.         }
  253.         DEBUG "parse_prototype: IN=[ @in_params ]\n";
  254.  
  255.  
  256.             
  257.         if(Win32::API::Type::is_known($ret)) {
  258.             if(Win32::API::Type::is_pointer($ret)) {
  259.                 DEBUG "parse_prototype: OUT='%s' PACKING='%s' API_TYPE=%d\n",
  260.                     $ret, 
  261.                     Win32::API::Type->packing( $ret ), 
  262.                     type_to_num('P');
  263.                 return ( $proc, \@in_params, \@in_types, type_to_num('P') );
  264.             } else {        
  265.                 DEBUG "parse_prototype: OUT='%s' PACKING='%s' API_TYPE=%d\n",
  266.                     $ret, 
  267.                     Win32::API::Type->packing( $ret ), 
  268.                     type_to_num( Win32::API::Type->packing( $ret ) );
  269.                 return ( $proc, \@in_params, \@in_types, type_to_num(Win32::API::Type->packing($ret)) );
  270.             }
  271.         } else {
  272.             warn "Win32::API::parse_prototype: WARNING unknown output parameter type '$ret'";
  273.             return ( $proc, \@in_params, \@in_types, type_to_num('I') );
  274.         }
  275.  
  276.     } else {
  277.         warn "Win32::API::parse_prototype: bad prototype '$proto'";
  278.         return undef;
  279.     }
  280. }   
  281.  
  282. 1;
  283.  
  284. __END__
  285.  
  286. #######################################################################
  287. # DOCUMENTATION
  288. #
  289.  
  290. =head1 NAME
  291.  
  292. Win32::API - Perl Win32 API Import Facility
  293.  
  294. =head1 SYNOPSIS
  295.  
  296.   #### Method 1: with prototype
  297.  
  298.   use Win32::API;
  299.   $function = Win32::API->new(
  300.       'mydll, 'int sum_integers(int a, int b)',
  301.   );
  302.   $return = $function->Call(3, 2);
  303.   
  304.   #### Method 2: with parameter list
  305.   
  306.   use Win32::API;
  307.   $function = Win32::API->new(
  308.       'mydll', 'sum_integers', 'II', 'I',
  309.   );
  310.   $return = $function->Call(3, 2);
  311.   
  312.   #### Method 3: with Import
  313.   
  314.   use Win32::API;
  315.   Win32::API->Import(
  316.       'mydll', 'int sum_integers(int a, int b)',
  317.   );  
  318.   $return = sum_integers(3, 2);
  319.  
  320.  
  321. =for LATER-UNIMPLEMENTED
  322.   #### or
  323.   use Win32::API mydll => 'int sum_integers(int a, int b)';
  324.   $return = sum_integers(3, 2);
  325.  
  326.  
  327. =head1 ABSTRACT
  328.  
  329. With this module you can import and call arbitrary functions
  330. from Win32's Dynamic Link Libraries (DLL), without having
  331. to write an XS extension. Note, however, that this module 
  332. can't do anything (parameters input and output is limited 
  333. to simpler cases), and anyway a regular XS extension is
  334. always safer and faster. 
  335.  
  336. The current version of Win32::API is available at my website:
  337.  
  338.   http://dada.perl.it/
  339.  
  340. It's also available on your nearest CPAN mirror (but allow a few days 
  341. for worldwide spreading of the latest version) reachable at:
  342.  
  343.   http://www.perl.com/CPAN/authors/Aldo_Calpini/
  344.  
  345. A short example of how you can use this module (it just gets the PID of 
  346. the current process, eg. same as Perl's internal C<$$>):
  347.  
  348.     use Win32::API;
  349.     Win32::API->Import("kernel32", "int GetCurrentProcessId()");
  350.     $PID = GetCurrentProcessId();
  351.  
  352. The possibilities are nearly infinite (but not all are good :-).
  353. Enjoy it.
  354.  
  355.  
  356. =head1 CREDITS
  357.  
  358. All the credits go to Andrea Frosini 
  359. for the neat assembler trick that makes this thing work.
  360. I've also used some work by Dave Roth for the prototyping stuff.
  361. A big thank you also to Gurusamy Sarathy for his
  362. unvaluable help in XS development, and to all the Perl community for
  363. being what it is.
  364.  
  365.  
  366. =head1 DESCRIPTION
  367.  
  368. To use this module put the following line at the beginning of your script:
  369.  
  370.     use Win32::API;
  371.  
  372. You can now use the C<new()> function of the Win32::API module to create a
  373. new Win32::API object (see L<IMPORTING A FUNCTION>) and then invoke the 
  374. C<Call()> method on this object to perform a call to the imported API
  375. (see L<CALLING AN IMPORTED FUNCTION>).
  376.  
  377. Starting from version 0.40, you can also avoid creating a Win32::API object
  378. and instead automatically define a Perl sub with the same name of the API
  379. function you're importing. The details of the API definitions are the same,
  380. just the call is different:
  381.  
  382.     my $GetCurrentProcessId = Win32::API->new(
  383.         "kernel32", "int GetCurrentProcessId()"
  384.     );
  385.     my $PID = $GetCurrentProcessId->Call();
  386.  
  387.     #### vs.
  388.  
  389.     Win32::API->Import("kernel32", "int GetCurrentProcessId()");
  390.     $PID = GetCurrentProcessId();
  391.  
  392. Note that C<Import> returns 1 on success and 0 on failure (in which case you
  393. can check the content of C<$^E>). 
  394.  
  395. =head2 IMPORTING A FUNCTION
  396.  
  397. You can import a function from a 32 bit Dynamic Link Library (DLL) file 
  398. with the C<new()> function. This will create a Perl object that contains the
  399. reference to that function, which you can later C<Call()>.
  400.  
  401. What you need to know is the prototype of the function you're going to import
  402. (eg. the definition of the function expressed in C syntax).
  403.  
  404. Starting from version 0.40, there are 2 different approaches for this step:
  405. (the preferred) one uses the prototype directly, while the other (now deprecated)
  406. one uses Win32::API's internal representation for parameters.
  407.  
  408. =head2 IMPORTING A FUNCTION BY PROTOTYPE
  409.  
  410. You need to pass 2 parameters:
  411.  
  412. =over 4
  413.  
  414. =item 1.
  415. The name of the library from which you want to import the function.
  416.  
  417. =item 2.
  418. The C prototype of the function.
  419.  
  420. =back
  421.  
  422. See L<Win32::API::Type> for a list of the known parameter types and
  423. L<Win32::API::Struct> for information on how to define a structure.
  424.  
  425. =head2 IMPORTING A FUNCTION WITH A PARAMETER LIST
  426.  
  427. You need to pass 4 parameters:
  428.  
  429. =over 4
  430.  
  431. =item 1.
  432. The name of the library from which you want to import the function.
  433.  
  434. =item 2.
  435. The name of the function (as exported by the library).
  436.  
  437. =item 3.
  438. The number and types of the arguments the function expects as input.
  439.  
  440. =item 4.
  441. The type of the value returned by the function.
  442.  
  443. =back
  444.  
  445. To better explain their meaning, let's suppose that we
  446. want to import and call the Win32 API C<GetTempPath()>.
  447. This function is defined in C as:
  448.  
  449.     DWORD WINAPI GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer );
  450.  
  451. This is documented in the B<Win32 SDK Reference>; you can look
  452. for it on the Microsoft's WWW site, or in your C compiler's 
  453. documentation, if you own one.
  454.  
  455. =over 4
  456.  
  457. =item B<1.>
  458.  
  459. The first parameter is the name of the library file that 
  460. exports this function; our function resides in the F<KERNEL32.DLL>
  461. system file.
  462. When specifying this name as parameter, the F<.DLL> extension
  463. is implicit, and if no path is given, the file is searched through
  464. a couple of directories, including: 
  465.  
  466. =over 4
  467.  
  468. =item 1. The directory from which the application loaded. 
  469.  
  470. =item 2. The current directory. 
  471.  
  472. =item 3. The Windows system directory (eg. c:\windows\system or system32).
  473.  
  474. =item 4. The Windows directory (eg. c:\windows).
  475.  
  476. =item 5. The directories that are listed in the PATH environment variable. 
  477.  
  478. =back
  479.  
  480. So, you don't have to write F<C:\windows\system\kernel32.dll>; 
  481. only F<kernel32> is enough:
  482.  
  483.     $GetTempPath = new Win32::API('kernel32', ...
  484.  
  485. =item B<2.>
  486.  
  487. Now for the second parameter: the name of the function.
  488. It must be written exactly as it is exported 
  489. by the library (case is significant here). 
  490. If you are using Windows 95 or NT 4.0, you can use the B<Quick View> 
  491. command on the DLL file to see the function it exports. 
  492. Remember that you can only import functions from 32 bit DLLs:
  493. in Quick View, the file's characteristics should report
  494. somewhere "32 bit word machine"; as a rule of thumb,
  495. when you see that all the exported functions are in upper case,
  496. the DLL is a 16 bit one and you can't use it. 
  497. If their capitalization looks correct, then it's probably a 32 bit
  498. DLL.
  499.  
  500. Also note that many Win32 APIs are exported twice, with the addition of
  501. a final B<A> or B<W> to their name, for - respectively - the ASCII 
  502. and the Unicode version.
  503. When a function name is not found, Win32::API will actually append
  504. an B<A> to the name and try again; if the extension is built on a
  505. Unicode system, then it will try with the B<W> instead.
  506. So our function name will be:
  507.  
  508.     $GetTempPath = new Win32::API('kernel32', 'GetTempPath', ...
  509.  
  510. In our case C<GetTempPath> is really loaded as C<GetTempPathA>.
  511.  
  512. =item B<3.>
  513.  
  514. The third parameter, the input parameter list, specifies how many 
  515. arguments the function wants, and their types. It can be passed as
  516. a single string, in which each character represents one parameter, 
  517. or as a list reference. The following forms are valid:
  518.  
  519.     "abcd"
  520.     [a, b, c, d]
  521.     \@LIST
  522.  
  523. But those are not:
  524.  
  525.     (a, b, c, d)
  526.     @LIST
  527.  
  528. The number of characters, or elements in the list, specifies the number 
  529. of parameters, and each character or element specifies the type of an 
  530. argument; allowed types are:
  531.  
  532. =over 4
  533.  
  534. =item C<I>: 
  535. value is an integer (int)
  536.  
  537. =item C<N>: 
  538. value is a number (long)
  539.  
  540. =item C<F>: 
  541. value is a floating point number (float)
  542.  
  543. =item C<D>: 
  544. value is a double precision number (double)
  545.  
  546. =item C<C>: 
  547. value is a char (char)
  548.  
  549. =item C<P>: 
  550. value is a pointer (to a string, structure, etc...)
  551.  
  552. =item C<S>: 
  553. value is a Win32::API::Struct object (see below)
  554.  
  555. =item C<K>:
  556. value is a Win32::API::Callback object (see L<Win32::API::Callback>)
  557.  
  558. =back
  559.  
  560. Our function needs two parameters: a number (C<DWORD>) and a pointer to a 
  561. string (C<LPSTR>):
  562.  
  563.     $GetTempPath = new Win32::API('kernel32', 'GetTempPath', 'NP', ...
  564.  
  565. =item B<4.>
  566.  
  567. The fourth and final parameter is the type of the value returned by the 
  568. function. It can be one of the types seen above, plus another type named B<V> 
  569. (for C<void>), used for functions that do not return a value.
  570. In our example the value returned by GetTempPath() is a C<DWORD>, so 
  571. our return type will be B<N>:
  572.  
  573.     $GetTempPath = new Win32::API('kernel32', 'GetTempPath', 'NP', 'N');
  574.  
  575. Now the line is complete, and the GetTempPath() API is ready to be used
  576. in Perl. Before calling it, you should test that $GetTempPath is 
  577. C<defined>, otherwise either the function or the library could not be
  578. loaded; in this case, C<$!> will be set to the error message reported 
  579. by Windows.
  580. Our definition, with error checking added, should then look like this:
  581.  
  582.     $GetTempPath = new Win32::API('kernel32', 'GetTempPath', 'NP', 'N');
  583.     if(not defined $GetTempPath) {
  584.         die "Can't import API GetTempPath: $!\n";
  585.     }
  586.  
  587. =back
  588.  
  589. =head2 CALLING AN IMPORTED FUNCTION
  590.  
  591. To effectively make a call to an imported function you must use the
  592. Call() method on the Win32::API object you created.
  593. Continuing with the example from the previous paragraph, 
  594. the GetTempPath() API can be called using the method:
  595.  
  596.     $GetTempPath->Call(...
  597.  
  598. Of course, parameters have to be passed as defined in the import phase.
  599. In particular, if the number of parameters does not match (in the example,
  600. if GetTempPath() is called with more or less than two parameters), 
  601. Perl will C<croak> an error message and C<die>.
  602.  
  603. The two parameters needed here are the length of the buffer
  604. that will hold the returned temporary path, and a pointer to the 
  605. buffer itself.
  606. For numerical parameters, you can use either a constant expression
  607. or a variable, while B<for pointers you must use a variable name> (no 
  608. Perl references, just a plain variable name).
  609. Also note that B<memory must be allocated before calling the function>,
  610. just like in C.
  611. For example, to pass a buffer of 80 characters to GetTempPath(),
  612. it must be initialized before with:
  613.  
  614.     $lpBuffer = " " x 80;
  615.  
  616. This allocates a string of 80 characters. If you don't do so, you'll
  617. probably get C<Runtime exception> errors, and generally nothing will 
  618. work. The call should therefore include:
  619.  
  620.     $lpBuffer = " " x 80;
  621.     $GetTempPath->Call(80, $lpBuffer);
  622.  
  623. And the result will be stored in the $lpBuffer variable.
  624. Note that you don't need to pass a reference to the variable
  625. (eg. you B<don't need> C<\$lpBuffer>), even if its value will be set 
  626. by the function. 
  627.  
  628. A little problem here is that Perl does not trim the variable, 
  629. so $lpBuffer will still contain 80 characters in return; the exceeding 
  630. characters will be spaces, because we said C<" " x 80>.
  631.  
  632. In this case we're lucky enough, because the value returned by 
  633. the GetTempPath() function is the length of the string, so to get
  634. the actual temporary path we can write:
  635.  
  636.     $lpBuffer = " " x 80;
  637.     $return = $GetTempPath->Call(80, $lpBuffer);
  638.     $TempPath = substr($lpBuffer, 0, $return);
  639.  
  640. If you don't know the length of the string, you can usually
  641. cut it at the C<\0> (ASCII zero) character, which is the string
  642. delimiter in C:
  643.  
  644.     $TempPath = ((split(/\0/, $lpBuffer))[0];  
  645.     # or    
  646.     $lpBuffer =~ s/\0.*$//;
  647.  
  648. =head2 USING STRUCTURES
  649.  
  650. Starting from version 0.40, Win32::API comes with a support package
  651. named Win32::API::Struct. The package is loaded automatically with
  652. Win32::API, so you don't need to use it explicitly.
  653.  
  654. With this module you can conveniently define structures and use
  655. them as parameters to Win32::API functions. A short example follows:
  656.  
  657.  
  658.     # the 'POINT' structure is defined in C as:
  659.     #     typedef struct {
  660.     #        LONG  x;
  661.     #        LONG  y;
  662.     #     } POINT;
  663.     
  664.  
  665.     #### define the structure
  666.     Win32::API::Struct->typedef( POINT => qw{
  667.         LONG x; 
  668.         LONG y; 
  669.     });
  670.     
  671.     #### import an API that uses this structure
  672.     Win32::API->Import('user32', 'BOOL GetCursorPos(LPPOINT lpPoint)');
  673.     
  674.     #### create a 'POINT' object
  675.     my $pt = Win32::API::Struct->new('POINT');
  676.     
  677.     #### call the function passing our structure object
  678.     GetCursorPos($pt);
  679.     
  680.     #### and now, access its members
  681.     print "The cursor is at: $pt->{x}, $pt->{y}\n";
  682.  
  683. Note that this works only when the function wants a 
  684. B<pointer to a structure>: as you can see, our structure is named 
  685. 'POINT', but the API used 'LPPOINT'. 'LP' is automatically added at 
  686. the beginning of the structure name when feeding it to a Win32::API
  687. call.
  688.  
  689. For more information, see also L<Win32::API::Struct>.
  690.  
  691. If you don't want (or can't) use the Win32::API::Struct facility,
  692. you can still use the low-level approach to use structures:
  693.  
  694.  
  695. =over 4
  696.  
  697. =item 1.
  698. you have to pack() the required elements in a variable:
  699.  
  700.     $lpPoint = pack('LL', 0, 0); # store two LONGs
  701.  
  702. =item 2. to access the values stored in a structure, unpack() it as required:
  703.  
  704.     ($x, $y) = unpack('LL', $lpPoint); # get the actual values
  705.  
  706. =back
  707.  
  708.  
  709. The rest is left as an exercise to the reader...
  710.  
  711.  
  712. =head1 AUTHOR
  713.  
  714. Aldo Calpini ( I<dada@perl.it> ).
  715.  
  716. =cut
  717.  
  718.  
  719.