1 # --------------------------------------------------------------------
4 # Purpose: Module to supply wrapper around and support for gateway to
5 # Windows API functions
7 # Copyright 2001 John F Sturtz for Codeweavers
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # --------------------------------------------------------------------
27 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD $todo_level
28 $successes $failures $todo_successes $todo_failures
29 $winetest_report_success
30 %return_types %prototypes %loaded_modules);
36 # Items to export into callers namespace by default. Note: do not export
37 # names by default without a very good reason. Use EXPORT_OK instead.
38 # Do not simply export all your public functions/methods/constants.
53 bootstrap wine $VERSION;
57 $wine::exit_status = 0;
58 $wine::debug = defined($ENV{WINETEST_DEBUG}) ? $ENV{WINETEST_DEBUG} : 1;
59 $wine::platform = defined($ENV{WINETEST_PLATFORM}) ? $ENV{WINETEST_PLATFORM} : "windows";
67 $winetest_report_success = defined($ENV{WINETEST_REPORT_SUCCESS}) ? $ENV{WINETEST_REPORT_SUCCESS} : 0;
70 # --------------------------------------------------------------
71 # | Return-type constants |
73 # | [todo] I think there's a way to define these in a C |
74 # | header file, so that both the C functions in the |
75 # | XS module and the Perl routines in the .pm have |
76 # | access to them. But I haven't worked it out |
78 # --------------------------------------------------------------
81 "int" => 1, "long" => 1,
84 "str" => 4, "wstr" => 4
88 # ------------------------------------------------------------------------
90 # | -------------------------------------------------------------------- |
91 # | Purpose: Used to catch calls to undefined routines |
93 # | Any routine which is called and not defined is assumed to be |
94 # | a call to the Wine API function of the same name. We trans- |
95 # | late it into a call to the call() subroutine, with FUNCTION |
96 # | set to the function invoked and all other args passed thru. |
97 # ------------------------------------------------------------------------
100 # --------------------------------------------------------------
101 # | Figure out who we are |
102 # --------------------------------------------------------------
103 my ($pkg, $func) = (split /::/, $AUTOLOAD)[0,1];
105 # --------------------------------------------------------------
106 # | Any function that is in the @EXPORT array is passed thru |
107 # | to AutoLoader to pick up the appropriate XS extension |
108 # --------------------------------------------------------------
109 if (grep ($_ eq $func, @EXPORT))
111 $AutoLoader::AUTOLOAD = $AUTOLOAD;
112 goto &AutoLoader::AUTOLOAD;
115 # --------------------------------------------------------------
117 # --------------------------------------------------------------
119 if ($func eq 'DESTROY');
121 # --------------------------------------------------------------
122 # | Otherwise, assume any undefined method is the name of a |
123 # | wine API call, and all the args are to be passed through |
124 # --------------------------------------------------------------
125 if (defined($prototypes{$func}))
127 return call( $func, @_ );
129 die "Function '$func' not declared";
134 # ------------------------------------------------------------------------
136 # | -------------------------------------------------------------------- |
137 # | Purpose: Call a wine API function |
139 # | Usage: call FUNCTION, [ARGS ...]
141 # | Returns: value returned by API function called |
142 # ------------------------------------------------------------------------
145 my ($function,@args) = @_;
146 my ($module,$funcptr,$ret_type,$arg_types) = @{$prototypes{$function}};
150 my $handle = $loaded_modules{$module};
151 $funcptr = get_proc_address( $handle, $function ) or die "Could not get address for $module.$function";
152 ${$prototypes{$function}}[1] = $funcptr;
155 if ($wine::debug > 1)
157 print STDERR "==== Call $function(";
160 print STDERR " ", +(ref () ? ("(" . ${$_} . ")") : "$_");
162 print STDERR " " if (scalar @args);
166 # Check and translate args before call
168 if (defined($arg_types)) {
169 my @arg_types = @$arg_types;
171 if($#args != $#arg_types) {
172 die "$function: Wrong number of arguments, expected " .
173 ($#arg_types + 1) . ", got " . ($#args + 1) . "\n";
176 while (defined(my $arg = shift @args) &&
177 defined(my $arg_type = shift @arg_types))
179 if($arg_type == 1 || $arg_type == 2) { # int || word
188 # Now call call_wine_API(), which will turn around and call
189 # the appropriate wine API function.
190 my ($err,$r) = call_wine_API( $funcptr, $ret_type, $wine::debug-1, @args2 );
192 if ($wine::debug > 1)
194 print STDERR "==== Ret $function()";
195 if (defined($r)) { printf STDERR " ret=0x%x", $r; }
196 if (defined($err)) { printf STDERR " err=%d", $err; }
200 # Pass the return value back
206 # ----------------------------------------------------------------------
207 # | Subroutine: declare
208 # ----------------------------------------------------------------------
211 my ($module, %list) = @_;
214 if (defined($loaded_modules{$module}))
216 $handle = $loaded_modules{$module};
220 $handle = load_library($module) or die "Could not load '$module'";
221 $loaded_modules{$module} = $handle;
224 foreach $func (keys %list)
226 if(ref($list{$func}) eq "ARRAY") {
227 my ($return_type, $argument_types) = @{$list{$func}};
229 my $ret_type = $return_types{$return_type};
230 my $arg_types = [map { $return_types{$_} } @$argument_types];
232 $prototypes{$func} = [ $module, 0, $ret_type, $arg_types ];
234 my $ret_type = $return_types{$list{$func}};
236 $prototypes{$func} = [ $module, 0, $ret_type ];
242 # ------------------------------------------------------------------------
243 # | Sub: alloc_callback |
244 # | -------------------------------------------------------------------- |
245 # | Purpose: Allocate a thunk for a Wine API callback function. |
247 # | Basically a thin wrapper over alloc_thunk(); see wine.xs for |
250 # | Usage: alloc_callback SUB_REF, [ ARGS_TYPES ... ] |
252 # | Returns: Pointer to thunk allocated (as an integer value) |
254 # | The returned value is just a raw pointer to a block of memory |
255 # | allocated by the C code (cast into a Perl integer). It isn't |
256 # | really suitable for anything but to be passed to a wine API |
258 # ------------------------------------------------------------------------
259 sub alloc_callback($@)
261 # ----------------------------------------------
264 # | [todo] Check arg types |
265 # ----------------------------------------------
267 my @callback_arg_types = @_;
270 # [todo] Some way of specifying args passed to callback
272 # --------------------------------------------------------------
273 # | Convert arg types to integers |
274 # --------------------------------------------------------------
275 map { $_ = $return_types{$_} } @callback_arg_types;
277 # --------------------------------------------------------------
278 # | Pass thru to alloc_thunk() |
279 # --------------------------------------------------------------
280 return alloc_thunk ($sub_ref, @callback_arg_types);
284 # ----------------------------------------------------------------------
287 # | Purpose: Display a hex dump of a string |
290 # | Usage: hd STR, LENGTH |
292 # | Returns: (none) |
293 # ----------------------------------------------------------------------
299 my ($str1, $str2, $str, $t);
304 # --------------------------------------------------------------
305 # | Get args; if no BUF specified, blow |
306 # --------------------------------------------------------------
308 $length = (shift or length ($buf));
310 if ((not defined ($buf)) || ($length <= 0));
312 # --------------------------------------------------------------
314 # --------------------------------------------------------------
319 # --------------------------------------------------------------
320 # | For each character |
321 # --------------------------------------------------------------
322 for (0 .. ($length - 1))
324 $c = substr ($buf, $_, 1);
325 $x = sprintf ("%02x", ord ($c));
327 $str2 .= (((ord ($c) >= 33) && (ord ($c) <= 126)) ? $c : ".");
329 # --------------------------------------------------------------
330 # | Every group of 4, add an extra space |
331 # --------------------------------------------------------------
334 ((($_ + 1) % 16) == 4) ||
335 ((($_ + 1) % 16) == 12)
342 # --------------------------------------------------------------
343 # | Every group of 8, add a '-' |
344 # --------------------------------------------------------------
347 ((($_ + 1) % 16) == 8)
354 # --------------------------------------------------------------
355 # | Every group of 16, dump |
356 # --------------------------------------------------------------
359 ((($_ + 1) % 16) == 0) ||
360 ($_ == ($length - 1))
363 $str = sprintf ("%-64s%s", $str1, $str2);
366 $t = ("-" x length ($str));
368 print " | $length bytes\n";
373 $str1 = sprintf ("%05d:", ($_ + 1));
375 if ($_ == ($length - 1))
384 # --------------------------------------------------------------
386 # --------------------------------------------------------------
393 # ----------------------------------------------------------------------
396 # | Purpose: Generate unicode string |
398 # | Usage: wc ASCII_STRING |
400 # | Returns: string generated |
401 # ----------------------------------------------------------------------
404 return pack("S*",unpack("C*",shift));
409 # ----------------------------------------------------------------------
410 # | Subroutine: wclen |
412 # | Purpose: Return length of unicode string |
414 # | Usage: wclen UNICODE_STRING |
416 # | Returns: string generated |
417 # ----------------------------------------------------------------------
427 while (length ($str) > 0)
429 $c1 = substr ($str, 0, 1, "");
430 $c2 = substr ($str, 0, 1, "");
431 (($c1 eq "\x00") && ($c2 eq "\x00")) ? last : $n++;
440 # ----------------------------------------------------------------------
443 # Purpose: Print warning if something fails
445 # Usage: ok CONDITION [DESCRIPTION]
448 # ----------------------------------------------------------------------
451 my $assertion = shift;
452 my $description = shift;
453 my ($filename, $line) = (caller (0))[1,2];
458 print STDERR ("$filename:$line: Test succeeded inside todo block" .
459 ($description ? ": $description" : "") . "\n");
462 else { $todo_successes++; }
468 print STDERR ("$filename:$line: Test failed" .
469 ($description ? ": $description" : "") . "\n");
474 print STDERR ("$filename:$line: Test succeeded\n") if ($winetest_report_success);
481 # ----------------------------------------------------------------------
484 # Purpose: Print error and die if something fails
486 # Usage: assert CONDITION [DESCRIPTION]
489 # ----------------------------------------------------------------------
492 my $assertion = shift;
493 my $description = shift;
494 my ($filename, $line) = (caller (0))[1,2];
497 die ("$filename:$line: Assertion failed" . ($description ? ": $description" : "") . "\n");
502 # ----------------------------------------------------------------------
505 # Purpose: Print debugging traces
507 # Usage: trace format [arguments]
508 # ----------------------------------------------------------------------
511 return unless ($wine::debug > 0);
513 my $filename = (caller(0))[1];
514 $filename =~ s!.*/!!;
515 printf "trace:$filename $format", @_;
518 # ----------------------------------------------------------------------
521 # Purpose: Specify a block of code as todo for a given platform
523 # Usage: todo name coderef
524 # ----------------------------------------------------------------------
527 my ($platform,$code) = @_;
528 if ($wine::platform eq $platform)
541 # ----------------------------------------------------------------------
542 # Subroutine: todo_wine
544 # Purpose: Specify a block of test as todo for the Wine platform
546 # Usage: todo_wine { code }
547 # ----------------------------------------------------------------------
551 todo( "wine", $code );
555 # ----------------------------------------------------------------------
558 # Purpose: Called at the end of execution, print results summary
559 # ----------------------------------------------------------------------
562 return if $?; # got some other error already
563 if ($wine::debug > 0)
565 my $filename = (caller(0))[1];
566 printf STDERR ("%s: %d tests executed, %d marked as todo, %d %s.\n",
567 $filename, $successes + $failures + $todo_successes + $todo_failures,
568 $todo_successes, $failures + $todo_failures,
569 ($failures + $todo_failures != 1) ? "failures" : "failure" );
571 $? = ($failures + $todo_failures < 255) ? $failures + $todo_failures : 255;
575 # Autoload methods go after =cut, and are processed by the autosplit program.
581 # ------------------------------------------------------------------------
582 # | pod documentation |
585 # ------------------------------------------------------------------------
589 wine - Perl extension for calling wine API functions
595 wine::declare( "kernel32",
596 SetLastError => ["void", ["int"]],
597 GetLastError => ["int", []] );
598 SetLastError( 1234 );
599 printf "%d\n", GetLastError();
604 This module provides a gateway for calling Win32 API functions from
607 =head1 CALLING WIN32 API FUNCTIONS
609 The functions you want to call must first be declared by calling
610 the wine::declare method. The first argument is the name of the
611 module containing the APIs, and the next argument is a list of
612 function names and their return and argument types. For instance:
614 wine::declare( "kernel32",
615 SetLastError => ["void", ["int"]],
616 GetLastError => ["int", []] );
618 declares that the functions SetLastError and GetLastError are
619 contained in the kernel32 dll.
621 Once you have done that you can call the functions directly just
622 like native Perl functions:
624 SetLastError( $some_error );
626 The supported return types are:
644 =head1 $wine::err VARIABLE
646 In the Win32 API, an integer error code is maintained which always
647 contains the status of the last API function called. In C code,
648 it is accessed via the GetLastError() function. From a Perl script,
649 it can be accessed via the package global $wine::err. For example:
651 GlobalGetAtomNameA ($atom, \$buf, -1);
652 if ($wine::err == 234)
657 Wine returns 234 (ERROR_MORE_DATA) from the GlobalGetAtomNameA()
658 API function in this case because the buffer length passed is -1
659 (hardly enough room to store anything in ...)
661 If the called API didn't set the last error code, $wine:;err is
664 =head1 $wine::debug VARIABLE
666 This variable can be set to 1 to enable debugging of the API calls,
667 which will print a lot of information about what's going on inside the
668 wine package while calling an API function.
670 =head1 OTHER USEFUL FUNCTIONS
672 The bundle that includes the wine extension also includes a module of
673 plain ol' Perl subroutines which are useful for interacting with wine
674 API functions. Currently supported functions are:
678 =item hd BUF [, LENGTH]
680 Dump a formatted hex dump to STDOUT. BUF is a string containing
681 the buffer to dump; LENGTH is the length to dump (length (BUF) if
682 omitted). This is handy because wine often writes a null character
683 into the middle of a buffer, thinking that the next piece of code to
684 look at the buffer will be a piece of C code that will regard it as
685 a string terminator. Little does it know that the buffer is going
686 to be returned to a Perl script, which may not ...
690 Generate and return a wide-character (Unicode) string from the given
695 Return the length of the given wide-character string
697 =item assert CONDITION
699 Print a message if the assertion fails (i.e., CONDITION is false),
700 or do nothing quietly if it is true. The message includes the script
701 name and line number of the assertion that failed.
709 John F Sturtz, jsturtz@codeweavers.com