holli
asked on
Warning using Win32::API
i use the following code to use a dll - function:
use Win32::API;
$timer = Win32::API->new( "winmm.dll", "long timeGetTime()" );
but the module complains
>> Win32::API::parse_prototyp e: WARNING unknown output parameter type 'long' at C:/Perl/site/lib/Win32/API .pm line 273.
Why is this? "int" doesn´t work also.
To me it seems to be a bug in the module.
use Win32::API;
$timer = Win32::API->new( "winmm.dll", "long timeGetTime()" );
but the module complains
>> Win32::API::parse_prototyp
Why is this? "int" doesn´t work also.
To me it seems to be a bug in the module.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
i forgot to say, that i use the module in a WSH/PerlScript - file (*.wsf)
all perl code in such files is implicitly eval()ed.
so the code:
use Win32::API;
Win32::API->Import( "winmm.dll", "I timeGetTime()" );
print timeGetTime();
works fine, but this:
eval
qq{
use Win32::API;
Win32::API->Import( "winmm.dll", "I timeGetTime()" );
print timeGetTime();
};
does not (prints the same warning as mentioned above).
inq,
changing long to LONG has no effect.
all perl code in such files is implicitly eval()ed.
so the code:
use Win32::API;
Win32::API->Import( "winmm.dll", "I timeGetTime()" );
print timeGetTime();
works fine, but this:
eval
qq{
use Win32::API;
Win32::API->Import( "winmm.dll", "I timeGetTime()" );
print timeGetTime();
};
does not (prints the same warning as mentioned above).
inq,
changing long to LONG has no effect.
it would seem that INIT sections are not called when in eval()
you have to call them yourself
there is an INIT section in Type.pm responsibe of loading the types and their meanings.
solution:
in Win32/API/Type.pm find the init section (there is only one), and copy it into a function, name it something like eval_init, and call it before using win32::API
use Win32::API;
Win32::API::Type::eval_ini t();
$timer = Win32::API->new( "winmm.dll", "long timeGetTime()" );
if you dont feel like finding the init and stuff, you can just copy mine:
sub eval_init
{
my $section = 'nothing';
foreach (<DATA>) {
next if /^\s*#/ or /^\s*$/;
chomp;
if( /\[(.+)\]/) {
$section = $1;
next;
}
if($section eq 'TYPE') {
my($name, $packing) = split(/\s+/);
# DEBUG "(PM)Type::INIT: Known('$name') => '$packing'\n";
$Known{$name} = $packing;
} elsif($section eq 'PACKSIZE') {
my($packing, $size) = split(/\s+/);
# DEBUG "(PM)Type::INIT: PackSize('$packing') => '$size'\n";
$PackSize{$packing} = $size;
} elsif($section eq 'MODIFIER') {
my($modifier, $mapto) = split(/\s+/, $_, 2);
my %maps = ();
foreach my $item (split(/\s+/, $mapto)) {
my($k, $v) = split(/=/, $item);
$maps{$k} = $v;
}
# DEBUG "(PM)Type::INIT: Modifier('$modifier') => '%maps'\n";
$Modifier{$modifier} = { %maps };
} elsif($section eq 'POINTER') {
my($pointer, $pointto) = split(/\s+/);
# DEBUG "(PM)Type::INIT: Pointer('$pointer') => '$pointto'\n";
$Pointer{$pointer} = $pointto;
}
}
}
stick that in type.pm and all should be well!
hope that helps
you have to call them yourself
there is an INIT section in Type.pm responsibe of loading the types and their meanings.
solution:
in Win32/API/Type.pm find the init section (there is only one), and copy it into a function, name it something like eval_init, and call it before using win32::API
use Win32::API;
Win32::API::Type::eval_ini
$timer = Win32::API->new( "winmm.dll", "long timeGetTime()" );
if you dont feel like finding the init and stuff, you can just copy mine:
sub eval_init
{
my $section = 'nothing';
foreach (<DATA>) {
next if /^\s*#/ or /^\s*$/;
chomp;
if( /\[(.+)\]/) {
$section = $1;
next;
}
if($section eq 'TYPE') {
my($name, $packing) = split(/\s+/);
# DEBUG "(PM)Type::INIT: Known('$name') => '$packing'\n";
$Known{$name} = $packing;
} elsif($section eq 'PACKSIZE') {
my($packing, $size) = split(/\s+/);
# DEBUG "(PM)Type::INIT: PackSize('$packing') => '$size'\n";
$PackSize{$packing} = $size;
} elsif($section eq 'MODIFIER') {
my($modifier, $mapto) = split(/\s+/, $_, 2);
my %maps = ();
foreach my $item (split(/\s+/, $mapto)) {
my($k, $v) = split(/=/, $item);
$maps{$k} = $v;
}
# DEBUG "(PM)Type::INIT: Modifier('$modifier') => '%maps'\n";
$Modifier{$modifier} = { %maps };
} elsif($section eq 'POINTER') {
my($pointer, $pointto) = split(/\s+/);
# DEBUG "(PM)Type::INIT: Pointer('$pointer') => '$pointto'\n";
$Pointer{$pointer} = $pointto;
}
}
}
stick that in type.pm and all should be well!
hope that helps
ASKER
uh, that sucks.
is it not possible to call the INIT manually? i just don`t want to change module code.
is it not possible to call the INIT manually? i just don`t want to change module code.
if you want to avoid changing the module code, you can add the code to the module at runtime:
$function = sub {
# INIT code here....
};
*Win32::API::Type::eval_in it=$functi on;
can create a new module (Win32::API::EvalCompatibl e for example) whos is to add the code and execute it;
hope that helps
$function = sub {
# INIT code here....
};
*Win32::API::Type::eval_in
can create a new module (Win32::API::EvalCompatibl
hope that helps
ASKER
why can´t i just Module::INIT()?
isn´t it supposed to be a function like any other?
It must have a entry in the Symbol table?
if so, it should be possible to get a ref to this symbol.
isn´t it supposed to be a function like any other?
It must have a entry in the Symbol table?
if so, it should be possible to get a ref to this symbol.
ASKER
i did a little investigation.
package t;
sub INIT
{
print "INIT";
}
sub import
{
my ($pkg, @args) = @_;
print "package $pkg loaded, args ", join(':',@args), "\n";
@foo::args = @args;
my $init = $t::{INIT};
my $foo = $t::{foo};
$init = \&$init;
$foo = \&$foo;
print "* $init *";
print "* $foo *";
&foo();
&$init();
print "end";
}
sub foo
{
print "FOO";
}
1;
______________
#t.pl
use lib qw (c:/ );
use t qw (x y);
print "main";
outcome:
package t loaded, args x:y
Undefined subroutine &t::INIT called at c://t.pm line 21.
BEGIN failed--compilation aborted at c:\t.pl line 2.
* CODE(0x186a230) ** CODE(0x186a170) *FOO
Why?
"CODE(0x186a230)" looks like a code-reference. why can´t i call it?
package t;
sub INIT
{
print "INIT";
}
sub import
{
my ($pkg, @args) = @_;
print "package $pkg loaded, args ", join(':',@args), "\n";
@foo::args = @args;
my $init = $t::{INIT};
my $foo = $t::{foo};
$init = \&$init;
$foo = \&$foo;
print "* $init *";
print "* $foo *";
&foo();
&$init();
print "end";
}
sub foo
{
print "FOO";
}
1;
______________
#t.pl
use lib qw (c:/ );
use t qw (x y);
print "main";
outcome:
package t loaded, args x:y
Undefined subroutine &t::INIT called at c://t.pm line 21.
BEGIN failed--compilation aborted at c:\t.pl line 2.
* CODE(0x186a230) ** CODE(0x186a170) *FOO
Why?
"CODE(0x186a230)" looks like a code-reference. why can´t i call it?
INIT is not a subroutene. INIT is a block of code. the only way init is diferent from just any code between curley brackets is in that is is executed as soon as compiled, thus being useful for running initialisation code. you can have multiple INIT blocks. none of them are subroutenes, and none of them can be called.
ASKER
bad news :-(
This may not help, but does it work that you change it to LONG or INT?
Cheers!