ActivePerl Documentation
|
NAMEWin32::API - Implementation of arbitrary Win32 APIs.
SUPPORTED PLATFORMS
SYNOPSIS
use Win32::API;
$function = new Win32::API($library,
$functionname,
\@argumenttypes,
$returntype);
$return = $function->Call(@arguments);
ABSTRACTWith this module you can import and call arbitrary functions from Win32's Dynamic Link Libraries (DLL). The current version of Win32::API is available at: http://www.divinf.it/dada/perl/api/ It is also available on your nearest CPAN mirror (but allow a few days for worldwide spreading of the latest version) reachable at: http://www.perl.com/CPAN/authors/Aldo_Calpini/
CREDITSAll the credits go to Andrea Frosini ( frosini@programmers.net ),
for his bits of magic - eg. the assembler trick that make this thing work.
A big thank you also to Gurusamy Sarathy ( gsar@engin.umich.edu ) for his
help in XS development
INSTALLATIONThis module comes with pre-built binaries for:
To install the package, just change to the directory in which you uncompressed it and type the following:
install
This will take care of copying the right files to the right places for use by all your perl scripts. If you're running the core Perl 5.004 distribution, you can also build the extension by yourself with the following procedure:
perl Makefile.PL
nmake
nmake install
If you are instead running the ActiveWare Perl for Win32 port, the sources to rebuild the extension are in the ActiveWare/source directory. You should put those files in the following directory:
(perl-src)\ext\Win32\API
Where
DESCRIPTIONTo use this module put the following line at the beginning of your script:
use Win32::API;
You can now use the
IMPORTING A FUNCTIONYou can import a function from a Dynamic Link Library (DLL) file with
the
To explain better their meaning, let's make an example:
I want to import and call the Win32 API
DWORD WINAPI GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer );
This is documented in the Win32 SDK Reference; look for it on the Microsoft's WWW site. If you own Visual C++, searching in the include files is much faster. 1. The first parameter is the name of the library file that exports this function; our function resides in the KERNEL32.DLL system file. When specifying this name as parameter, the .dll extension is implicit, and if no path is given, the file is searched through the Windows directories. So I don't have to write C:\windows\system\kernel32.dll; only kernel32 is enough:
$GetTempPath = new Win32::API("kernel32", ...
2. Now for the second parameter: the name of the function. It must be written exactly as it is exported by the library (case is significant here). If you are using Windows 95 or NT 4.0, you can use the Quick View command on the DLL file to see the function it exports. Note that many Win32 APIs are exported twice, with the addition of a final A or W to their name, for - respectively - the ASCII and the Unicode version. Win32::API, when a function name is not found, will actually append an A to the name and try again. If you are using Unicode, you will just need to rebuild the module; then Win32::API will try with the W. So my function name will be:
$GetTempPath = new Win32::API("kernel32", "GetTempPath", ...
Note that 3. The third parameter, the input parameter list, specifies how many arguments the function wants, and their types. It MUST be passed as a list reference. The following forms are valid:
[a, b, c, d]
\@LIST
But those are not:
(a, b, c, d)
@LIST
The number of elements in the list specifies the number of parameters, and each element in the list specifies the type of an argument; allowed types are:
Our function needs two parameters: a number (
$GetTempPath = new Win32::API("kernel32", "GetTempPath", [N, P], ...
4. The fourth and final parameter is the type of the value returned by the
function. It can be one of the types seen above, plus another type named V
(that stands for
$GetTempPath = new Win32::API("kernel32", "GetTempPath", [N, P], N);
Now the line is complete, and the API
CALLING AN IMPORTED FUNCTIONTo effectively make a call to an imported function you must use the
$GetTempPath->Call(...
Of course I have to pass the parameters as defined in the import phase.
In particular, if the number of parameters does not match (in the example,
if I call So I need two parameters here: the first is the length of the buffer that will hold the returned temporary path, the second is the buffer itself. For numerical parameters you can use either a constant expression or a variable, while for pointers you must use a variable name (no reference, just a plain variable name). Also note that memory must be allocated before calling the function. For example, if I want to pass a buffer of 80 characters to GetTempPath(), I have to initialize it before with:
$lpBuffer = " " x 80;
This allocates a string of 80 characters. If you don't do so, you'll
probably get '
$lpBuffer = " " x 80;
$GetTempPath->Call(80, $lpBuffer);
And the result will be stored in the $lpBuffer variable.
Note, however, that Perl does not trim the variable, so $lpBuffer
will contain 80 characters in return; the exceeding characters
will be spaces, since I initialized the variable with
$lpBuffer = " " x 80;
$return = $GetTempPath->Call(80, $lpBuffer);
$TempPath = substr($lpBuffer, 0, $return);
If you don't know the length of the string, you can usually cut it at the \0 (ASCII zero) character, which is the string delimiter in C:
$TempPath = ((split(/\0/, $lpBuffer))[0];
# or
$lpBuffer =~ s/\0.*$//;
$TempPath = $lpBuffer;
Another note: to pass a pointer to a structure in C, you'll have
to
typedef struct {
LONG x;
LONG y;
} POINT;
Thus, to call a function that uses a
$GetCursorPos = new Win32::API("user32", "GetCursorPos", [P], V);
$lpPoint = pack("LL", 0, 0); # store two LONGs
$GetCursorPos->Call($lpPoint);
($x, $y) = unpack("LL", $lpPoint); # get the actual values
The rest is left as an exercise to the reader...
AUTHORAldo Calpini ( dada@divinf.it ).
|