1 # --------------------------------------------------------------------------------
3 # | ---------------------------------------------------------------------------- |
4 # | Purpose: Module to supply wrapper around and support for gateway to wine |
6 # --------------------------------------------------------------------------------
11 use vars
qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD
12 %return_types %prototypes %loaded_modules);
18 # Items to export into callers namespace by default. Note: do not export
19 # names by default without a very good reason. Use EXPORT_OK instead.
20 # Do not simply export all your public functions/methods/constants.
31 bootstrap wine
$VERSION;
39 # --------------------------------------------------------------
40 # | Return-type constants |
42 # | [todo] I think there's a way to define these in a C |
43 # | header file, so that both the C functions in the |
44 # | XS module and the Perl routines in the .pm have |
45 # | access to them. But I haven't worked it out |
47 # --------------------------------------------------------------
48 %return_types = ( "void" => 0, "int" => 1, "word" => 2, "ptr" => 3 );
51 # ------------------------------------------------------------------------
53 # | -------------------------------------------------------------------- |
54 # | Purpose: Used to catch calls to undefined routines |
56 # | Any routine which is called and not defined is assumed to be |
57 # | a call to the Wine API function of the same name. We trans- |
58 # | late it into a call to the call() subroutine, with FUNCTION |
59 # | set to the function invoked and all other args passed thru. |
60 # ------------------------------------------------------------------------
63 # --------------------------------------------------------------
64 # | Figure out who we are |
65 # --------------------------------------------------------------
66 my ($pkg, $func) = (split /::/, $AUTOLOAD)[0,1];
68 # --------------------------------------------------------------
69 # | Any function that is in the @EXPORT array is passed thru |
70 # | to AutoLoader to pick up the appropriate XS extension |
71 # --------------------------------------------------------------
72 if (grep ($_ eq $func, @EXPORT))
74 $AutoLoader::AUTOLOAD
= $AUTOLOAD;
75 goto &AutoLoader
::AUTOLOAD
;
78 # --------------------------------------------------------------
80 # --------------------------------------------------------------
82 if ($func eq 'DESTROY');
84 # --------------------------------------------------------------
85 # | Otherwise, assume any undefined method is the name of a |
86 # | wine API call, and all the args are to be passed through |
87 # --------------------------------------------------------------
88 if (defined($prototypes{$func}))
90 return call
( $func, $wine::debug
, @_ );
92 die "Function '$func' not declared";
97 # ------------------------------------------------------------------------
99 # | -------------------------------------------------------------------- |
100 # | Purpose: Call a wine API function |
102 # | Usage: call FUNCTION, DEBUG, [ARGS ...]
104 # | Returns: value returned by API function called |
105 # ------------------------------------------------------------------------
108 my ($function,$debug,@args) = @_;
109 my ($funcptr,$ret_type) = @
{$prototypes{$function}};
113 print STDERR
"==== [$function() / " . scalar (@args) . " arg(s)]";
116 print STDERR
" ", +(ref () ?
("(" . ${$_} . ")") : "$_");
118 print STDERR
" ====\n";
121 # Now call call_wine_API(), which will turn around and call
122 # the appropriate wine API function.
123 my ($err,$r) = call_wine_API
( $funcptr, $ret_type, $debug, @args );
127 my $z = "[$function()] -> ";
128 $z .= defined($r) ?
sprintf("[0x%x/%d]", $r, $r) : "[void]";
129 if (defined($err)) { $z .= sprintf " err=%d", $err; }
130 print STDERR
"==== $z ====\n";
133 # Pass the return value back
139 # ----------------------------------------------------------------------
140 # | Subroutine: declare
141 # ----------------------------------------------------------------------
144 my ($module, %list) = @_;
147 if (defined($loaded_modules{$module}))
149 $handle = $loaded_modules{$module};
153 $handle = load_library
($module) or die "Could not load '$module'";
154 $loaded_modules{$module} = $handle;
157 foreach $func (keys %list)
159 my $ptr = get_proc_address
( $handle, $func ) or die "Could not find '$func' in '$module'";
160 my $ret_type = $return_types{$list{$func}};
161 $prototypes{$func} = [ $ptr, $ret_type ];
166 # ------------------------------------------------------------------------
167 # | Sub: alloc_callback |
168 # | -------------------------------------------------------------------- |
169 # | Purpose: Allocate a thunk for a Wine API callback function. |
171 # | Basically a thin wrapper over alloc_thunk(); see wine.xs for |
174 # | Usage: alloc_callback SUB_REF, [ ARGS_TYPES ... ] |
176 # | Returns: Pointer to thunk allocated (as an integer value) |
178 # | The returned value is just a raw pointer to a block of memory |
179 # | allocated by the C code (cast into a Perl integer). It isn't |
180 # | really suitable for anything but to be passed to a wine API |
182 # ------------------------------------------------------------------------
185 # ----------------------------------------------
188 # | [todo] Check arg types |
189 # ----------------------------------------------
191 my @callback_arg_types = @_;
194 # [todo] Some way of specifying args passed to callback
196 # --------------------------------------------------------------
197 # | Convert arg types to integers |
198 # --------------------------------------------------------------
199 map { $_ = $return_types{$_} } @callback_arg_types;
201 # --------------------------------------------------------------
202 # | Pass thru to alloc_thunk() |
203 # --------------------------------------------------------------
204 return alloc_thunk
($sub_ref, @callback_arg_types);
208 # ----------------------------------------------------------------------
211 # | Purpose: Display a hex dump of a string |
214 # | Usage: hd STR, LENGTH |
216 # | Returns: (none) |
217 # ----------------------------------------------------------------------
223 my ($str1, $str2, $str, $t);
228 # --------------------------------------------------------------
229 # | Get args; if no BUF specified, blow |
230 # --------------------------------------------------------------
232 $length = (shift or length ($buf));
234 if ((not defined ($buf)) || ($length <= 0));
236 # --------------------------------------------------------------
238 # --------------------------------------------------------------
243 # --------------------------------------------------------------
244 # | For each character |
245 # --------------------------------------------------------------
246 for (0 .. ($length - 1))
248 $c = substr ($buf, $_, 1);
249 $x = sprintf ("%02x", ord ($c));
251 $str2 .= (((ord ($c) >= 33) && (ord ($c) <= 126)) ?
$c : ".");
253 # --------------------------------------------------------------
254 # | Every group of 4, add an extra space |
255 # --------------------------------------------------------------
258 ((($_ + 1) % 16) == 4) ||
259 ((($_ + 1) % 16) == 12)
266 # --------------------------------------------------------------
267 # | Every group of 8, add a '-' |
268 # --------------------------------------------------------------
271 ((($_ + 1) % 16) == 8)
278 # --------------------------------------------------------------
279 # | Every group of 16, dump |
280 # --------------------------------------------------------------
283 ((($_ + 1) % 16) == 0) ||
284 ($_ == ($length - 1))
287 $str = sprintf ("%-64s%s", $str1, $str2);
290 $t = ("-" x
length ($str));
292 print " | $length bytes\n";
297 $str1 = sprintf ("%05d:", ($_ + 1));
299 if ($_ == ($length - 1))
308 # --------------------------------------------------------------
310 # --------------------------------------------------------------
317 # ----------------------------------------------------------------------
320 # | Purpose: Generate unicode string |
322 # | Usage: wc ASCII_STRING |
324 # | Returns: string generated |
325 # ----------------------------------------------------------------------
328 return pack("S*",unpack("C*",shift));
333 # ----------------------------------------------------------------------
334 # | Subroutine: wclen |
336 # | Purpose: Return length of unicode string |
338 # | Usage: wclen UNICODE_STRING |
340 # | Returns: string generated |
341 # ----------------------------------------------------------------------
351 while (length ($str) > 0)
353 $c1 = substr ($str, 0, 1, "");
354 $c2 = substr ($str, 0, 1, "");
355 (($c1 eq "\x00") && ($c2 eq "\x00")) ?
last : $n++;
364 # ----------------------------------------------------------------------
365 # | Subroutine: assert |
367 # | Purpose: Print warning if something fails |
369 # | Usage: assert CONDITION |
371 # | Returns: (none) |
372 # ----------------------------------------------------------------------
376 my $assertion = shift;
381 ($fn, $line) = (caller (0))[1,2];
382 unless ($assertion) { print "Assertion failed [$fn, line $line]\n"; exit 1; }
387 # Autoload methods go after =cut, and are processed by the autosplit program.
393 # ------------------------------------------------------------------------
394 # | pod documentation |
397 # ------------------------------------------------------------------------
401 wine - Perl extension for calling wine API functions
407 wine::declare( "kernel32",
408 SetLastError => "void",
409 GetLastError => "int" );
410 SetLastError( 1234 );
411 printf "%d\n", GetLastError();
416 This module provides a gateway for calling Win32 API functions from
419 =head1 CALLING WIN32 API FUNCTIONS
421 The functions you want to call must first be declared by calling
422 the wine::declare method. The first argument is the name of the
423 module containing the APIs, and the next argument is a list of
424 function names and their return types. For instance:
426 wine::declare( "kernel32",
427 SetLastError => "void",
428 GetLastError => "int" );
430 declares that the functions SetLastError and GetLastError are
431 contained in the kernel32 dll.
433 Once you have done that you can call the functions directly just
434 like native Perl functions:
436 SetLastError( $some_error );
438 The supported return types are:
452 =head1 $wine::err VARIABLE
454 In the Win32 API, an integer error code is maintained which always
455 contains the status of the last API function called. In C code,
456 it is accessed via the GetLastError() function. From a Perl script,
457 it can be accessed via the package global $wine::err. For example:
459 GlobalGetAtomNameA ($atom, \$buf, -1);
460 if ($wine::err == 234)
465 Wine returns 234 (ERROR_MORE_DATA) from the GlobalGetAtomNameA()
466 API function in this case because the buffer length passed is -1
467 (hardly enough room to store anything in ...)
469 If the called API didn't set the last error code, $wine:;err is
472 =head1 $wine::debug VARIABLE
474 This variable can be set to 1 to enable debugging of the API calls,
475 which will print a lot of information about what's going on inside the
476 wine package while calling an API function.
478 =head1 OTHER USEFUL FUNCTIONS
480 The bundle that includes the wine extension also includes a module of
481 plain ol' Perl subroutines which are useful for interacting with wine
482 API functions. Currently supported functions are:
486 =item hd BUF [, LENGTH]
488 Dump a formatted hex dump to STDOUT. BUF is a string containing
489 the buffer to dump; LENGTH is the length to dump (length (BUF) if
490 omitted). This is handy because wine often writes a null character
491 into the middle of a buffer, thinking that the next piece of code to
492 look at the buffer will be a piece of C code that will regard it as
493 a string terminator. Little does it know that the buffer is going
494 to be returned to a Perl script, which may not ...
498 Generate and return a wide-character (Unicode) string from the given
503 Return the length of the given wide-character string
505 =item assert CONDITION
507 Print a message if the assertion fails (i.e., CONDITION is false),
508 or do nothing quietly if it is true. The message includes the script
509 name and line number of the assertion that failed.
517 John F Sturtz, jsturtz@codeweavers.com