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 %return_types %prototypes %loaded_modules);
35 # Items to export into callers namespace by default. Note: do not export
36 # names by default without a very good reason. Use EXPORT_OK instead.
37 # Do not simply export all your public functions/methods/constants.
52 bootstrap wine $VERSION;
56 $wine::exit_status = 0;
57 $wine::debug = defined($ENV{WINETEST_DEBUG}) ? $ENV{WINETEST_DEBUG} : 1;
58 $wine::platform = defined($ENV{WINETEST_PLATFORM}) ? $ENV{WINETEST_PLATFORM} : "windows";
67 # --------------------------------------------------------------
68 # | Return-type constants |
70 # | [todo] I think there's a way to define these in a C |
71 # | header file, so that both the C functions in the |
72 # | XS module and the Perl routines in the .pm have |
73 # | access to them. But I haven't worked it out |
75 # --------------------------------------------------------------
78 "int" => 1, "long" => 1,
81 "str" => 4, "wstr" => 4
85 # ------------------------------------------------------------------------
87 # | -------------------------------------------------------------------- |
88 # | Purpose: Used to catch calls to undefined routines |
90 # | Any routine which is called and not defined is assumed to be |
91 # | a call to the Wine API function of the same name. We trans- |
92 # | late it into a call to the call() subroutine, with FUNCTION |
93 # | set to the function invoked and all other args passed thru. |
94 # ------------------------------------------------------------------------
97 # --------------------------------------------------------------
98 # | Figure out who we are |
99 # --------------------------------------------------------------
100 my ($pkg, $func) = (split /::/, $AUTOLOAD)[0,1];
102 # --------------------------------------------------------------
103 # | Any function that is in the @EXPORT array is passed thru |
104 # | to AutoLoader to pick up the appropriate XS extension |
105 # --------------------------------------------------------------
106 if (grep ($_ eq $func, @EXPORT))
108 $AutoLoader::AUTOLOAD = $AUTOLOAD;
109 goto &AutoLoader::AUTOLOAD;
112 # --------------------------------------------------------------
114 # --------------------------------------------------------------
116 if ($func eq 'DESTROY');
118 # --------------------------------------------------------------
119 # | Otherwise, assume any undefined method is the name of a |
120 # | wine API call, and all the args are to be passed through |
121 # --------------------------------------------------------------
122 if (defined($prototypes{$func}))
124 return call( $func, @_ );
126 die "Function '$func' not declared";
131 # ------------------------------------------------------------------------
133 # | -------------------------------------------------------------------- |
134 # | Purpose: Call a wine API function |
136 # | Usage: call FUNCTION, [ARGS ...]
138 # | Returns: value returned by API function called |
139 # ------------------------------------------------------------------------
142 my ($function,@args) = @_;
143 my ($module,$funcptr,$ret_type,$arg_types) = @{$prototypes{$function}};
147 my $handle = $loaded_modules{$module};
148 $funcptr = get_proc_address( $handle, $function ) or die "Could not get address for $module.$function";
149 ${$prototypes{$function}}[1] = $funcptr;
152 if ($wine::debug > 1)
154 print STDERR "==== Call $function(";
157 print STDERR " ", +(ref () ? ("(" . ${$_} . ")") : "$_");
159 print STDERR " " if (scalar @args);
163 # Check and translate args before call
165 if (defined($arg_types)) {
166 my @arg_types = @$arg_types;
168 if($#args != $#arg_types) {
169 die "$function: Wrong number of arguments, expected " .
170 ($#arg_types + 1) . ", got " . ($#args + 1) . "\n";
173 while (defined(my $arg = shift @args) &&
174 defined(my $arg_type = shift @arg_types))
176 if($arg_type == 1 || $arg_type == 2) { # int || word
185 # Now call call_wine_API(), which will turn around and call
186 # the appropriate wine API function.
187 my ($err,$r) = call_wine_API( $funcptr, $ret_type, $wine::debug-1, @args2 );
189 if ($wine::debug > 1)
191 print STDERR "==== Ret $function()";
192 if (defined($r)) { printf STDERR " ret=0x%x", $r; }
193 if (defined($err)) { printf STDERR " err=%d", $err; }
197 # Pass the return value back
203 # ----------------------------------------------------------------------
204 # | Subroutine: declare
205 # ----------------------------------------------------------------------
208 my ($module, %list) = @_;
211 if (defined($loaded_modules{$module}))
213 $handle = $loaded_modules{$module};
217 $handle = load_library($module) or die "Could not load '$module'";
218 $loaded_modules{$module} = $handle;
221 foreach $func (keys %list)
223 if(ref($list{$func}) eq "ARRAY") {
224 my ($return_type, $argument_types) = @{$list{$func}};
226 my $ret_type = $return_types{$return_type};
227 my $arg_types = [map { $return_types{$_} } @$argument_types];
229 $prototypes{$func} = [ $module, 0, $ret_type, $arg_types ];
231 my $ret_type = $return_types{$list{$func}};
233 $prototypes{$func} = [ $module, 0, $ret_type ];
239 # ------------------------------------------------------------------------
240 # | Sub: alloc_callback |
241 # | -------------------------------------------------------------------- |
242 # | Purpose: Allocate a thunk for a Wine API callback function. |
244 # | Basically a thin wrapper over alloc_thunk(); see wine.xs for |
247 # | Usage: alloc_callback SUB_REF, [ ARGS_TYPES ... ] |
249 # | Returns: Pointer to thunk allocated (as an integer value) |
251 # | The returned value is just a raw pointer to a block of memory |
252 # | allocated by the C code (cast into a Perl integer). It isn't |
253 # | really suitable for anything but to be passed to a wine API |
255 # ------------------------------------------------------------------------
256 sub alloc_callback($@)
258 # ----------------------------------------------
261 # | [todo] Check arg types |
262 # ----------------------------------------------
264 my @callback_arg_types = @_;
267 # [todo] Some way of specifying args passed to callback
269 # --------------------------------------------------------------
270 # | Convert arg types to integers |
271 # --------------------------------------------------------------
272 map { $_ = $return_types{$_} } @callback_arg_types;
274 # --------------------------------------------------------------
275 # | Pass thru to alloc_thunk() |
276 # --------------------------------------------------------------
277 return alloc_thunk ($sub_ref, @callback_arg_types);
281 # ----------------------------------------------------------------------
284 # | Purpose: Display a hex dump of a string |
287 # | Usage: hd STR, LENGTH |
289 # | Returns: (none) |
290 # ----------------------------------------------------------------------
296 my ($str1, $str2, $str, $t);
301 # --------------------------------------------------------------
302 # | Get args; if no BUF specified, blow |
303 # --------------------------------------------------------------
305 $length = (shift or length ($buf));
307 if ((not defined ($buf)) || ($length <= 0));
309 # --------------------------------------------------------------
311 # --------------------------------------------------------------
316 # --------------------------------------------------------------
317 # | For each character |
318 # --------------------------------------------------------------
319 for (0 .. ($length - 1))
321 $c = substr ($buf, $_, 1);
322 $x = sprintf ("%02x", ord ($c));
324 $str2 .= (((ord ($c) >= 33) && (ord ($c) <= 126)) ? $c : ".");
326 # --------------------------------------------------------------
327 # | Every group of 4, add an extra space |
328 # --------------------------------------------------------------
331 ((($_ + 1) % 16) == 4) ||
332 ((($_ + 1) % 16) == 12)
339 # --------------------------------------------------------------
340 # | Every group of 8, add a '-' |
341 # --------------------------------------------------------------
344 ((($_ + 1) % 16) == 8)
351 # --------------------------------------------------------------
352 # | Every group of 16, dump |
353 # --------------------------------------------------------------
356 ((($_ + 1) % 16) == 0) ||
357 ($_ == ($length - 1))
360 $str = sprintf ("%-64s%s", $str1, $str2);
363 $t = ("-" x length ($str));
365 print " | $length bytes\n";
370 $str1 = sprintf ("%05d:", ($_ + 1));
372 if ($_ == ($length - 1))
381 # --------------------------------------------------------------
383 # --------------------------------------------------------------
390 # ----------------------------------------------------------------------
393 # | Purpose: Generate unicode string |
395 # | Usage: wc ASCII_STRING |
397 # | Returns: string generated |
398 # ----------------------------------------------------------------------
401 return pack("S*",unpack("C*",shift));
406 # ----------------------------------------------------------------------
407 # | Subroutine: wclen |
409 # | Purpose: Return length of unicode string |
411 # | Usage: wclen UNICODE_STRING |
413 # | Returns: string generated |
414 # ----------------------------------------------------------------------
424 while (length ($str) > 0)
426 $c1 = substr ($str, 0, 1, "");
427 $c2 = substr ($str, 0, 1, "");
428 (($c1 eq "\x00") && ($c2 eq "\x00")) ? last : $n++;
437 # ----------------------------------------------------------------------
440 # Purpose: Print warning if something fails
442 # Usage: ok CONDITION [DESCRIPTION]
445 # ----------------------------------------------------------------------
448 my $assertion = shift;
449 my $description = shift;
450 my ($filename, $line) = (caller (0))[1,2];
455 print STDERR ("$filename:$line: Test succeeded inside todo block" .
456 ($description ? ": $description" : "") . "\n");
459 else { $todo_successes++; }
465 print STDERR ("$filename:$line: Test failed" .
466 ($description ? ": $description" : "") . "\n");
469 else { $successes++; }
474 # ----------------------------------------------------------------------
477 # Purpose: Print error and die if something fails
479 # Usage: assert CONDITION [DESCRIPTION]
482 # ----------------------------------------------------------------------
485 my $assertion = shift;
486 my $description = shift;
487 my ($filename, $line) = (caller (0))[1,2];
490 die ("$filename:$line: Assertion failed" . ($description ? ": $description" : "") . "\n");
495 # ----------------------------------------------------------------------
498 # Purpose: Print debugging traces
500 # Usage: trace format [arguments]
501 # ----------------------------------------------------------------------
504 return unless ($wine::debug > 0);
506 my $filename = (caller(0))[1];
507 $filename =~ s!.*/!!;
508 printf "trace:$filename $format", @_;
511 # ----------------------------------------------------------------------
514 # Purpose: Specify a block of code as todo for a given platform
516 # Usage: todo name coderef
517 # ----------------------------------------------------------------------
520 my ($platform,$code) = @_;
521 if ($wine::platform eq $platform)
534 # ----------------------------------------------------------------------
535 # Subroutine: todo_wine
537 # Purpose: Specify a block of test as todo for the Wine platform
539 # Usage: todo_wine { code }
540 # ----------------------------------------------------------------------
544 todo( "wine", $code );
548 # ----------------------------------------------------------------------
551 # Purpose: Called at the end of execution, print results summary
552 # ----------------------------------------------------------------------
555 return if $?; # got some other error already
556 if ($wine::debug > 0)
558 my $filename = (caller(0))[1];
559 printf STDERR ("%s: %d tests executed, %d marked as todo, %d %s.\n",
560 $filename, $successes + $failures + $todo_successes + $todo_failures,
561 $todo_successes, $failures + $todo_failures,
562 ($failures + $todo_failures != 1) ? "failures" : "failure" );
564 $? = ($failures + $todo_failures < 255) ? $failures + $todo_failures : 255;
568 # Autoload methods go after =cut, and are processed by the autosplit program.
574 # ------------------------------------------------------------------------
575 # | pod documentation |
578 # ------------------------------------------------------------------------
582 wine - Perl extension for calling wine API functions
588 wine::declare( "kernel32",
589 SetLastError => ["void", ["int"]],
590 GetLastError => ["int", []] );
591 SetLastError( 1234 );
592 printf "%d\n", GetLastError();
597 This module provides a gateway for calling Win32 API functions from
600 =head1 CALLING WIN32 API FUNCTIONS
602 The functions you want to call must first be declared by calling
603 the wine::declare method. The first argument is the name of the
604 module containing the APIs, and the next argument is a list of
605 function names and their return and argument types. For instance:
607 wine::declare( "kernel32",
608 SetLastError => ["void", ["int"]],
609 GetLastError => ["int", []] );
611 declares that the functions SetLastError and GetLastError are
612 contained in the kernel32 dll.
614 Once you have done that you can call the functions directly just
615 like native Perl functions:
617 SetLastError( $some_error );
619 The supported return types are:
637 =head1 $wine::err VARIABLE
639 In the Win32 API, an integer error code is maintained which always
640 contains the status of the last API function called. In C code,
641 it is accessed via the GetLastError() function. From a Perl script,
642 it can be accessed via the package global $wine::err. For example:
644 GlobalGetAtomNameA ($atom, \$buf, -1);
645 if ($wine::err == 234)
650 Wine returns 234 (ERROR_MORE_DATA) from the GlobalGetAtomNameA()
651 API function in this case because the buffer length passed is -1
652 (hardly enough room to store anything in ...)
654 If the called API didn't set the last error code, $wine:;err is
657 =head1 $wine::debug VARIABLE
659 This variable can be set to 1 to enable debugging of the API calls,
660 which will print a lot of information about what's going on inside the
661 wine package while calling an API function.
663 =head1 OTHER USEFUL FUNCTIONS
665 The bundle that includes the wine extension also includes a module of
666 plain ol' Perl subroutines which are useful for interacting with wine
667 API functions. Currently supported functions are:
671 =item hd BUF [, LENGTH]
673 Dump a formatted hex dump to STDOUT. BUF is a string containing
674 the buffer to dump; LENGTH is the length to dump (length (BUF) if
675 omitted). This is handy because wine often writes a null character
676 into the middle of a buffer, thinking that the next piece of code to
677 look at the buffer will be a piece of C code that will regard it as
678 a string terminator. Little does it know that the buffer is going
679 to be returned to a Perl script, which may not ...
683 Generate and return a wide-character (Unicode) string from the given
688 Return the length of the given wide-character string
690 =item assert CONDITION
692 Print a message if the assertion fails (i.e., CONDITION is false),
693 or do nothing quietly if it is true. The message includes the script
694 name and line number of the assertion that failed.
702 John F Sturtz, jsturtz@codeweavers.com