sapbucket
asked on
Perl InlineC not working
I am trying to write an InlineC subroutine that inputs a 'long' memory address and returns (and prints to command line) the contents of the memory-address.
#### testInlineC.pl
use Inline C;
greet('Ingy');
greet(42);
$memory_address=136052768;
GetMem($memory_address);
__END__
__C__
void greet(char* name) {
printf("Hello %s!\n", name);
}
void GetMem(long *memory_address){
*memory_address = 255 - *memory_address;
memory_address++;
printf("Hello %l!\n", memory_address);
}
#### END testInlineC.pl
#### START COMMAND LINE OUTPUT
C:\OCR\Dev>perl testInlineC.pl
Hello Ingy!
Hello 42!
Can't locate auto/main/GetMem.al in @INC (@INC contains: C:\OCR\Dev\_Inline\lib c:/Perl/lib c:/Perl/site/lib .) at
testInlineC.pl line 6
#### END COMMAND LINE OUTPUT
You can see that greet() works just fine. However, GetMem() does not.
Can someone please help me with this? I have no clue how to get this subroutine working.
#### testInlineC.pl
use Inline C;
greet('Ingy');
greet(42);
$memory_address=136052768;
GetMem($memory_address);
__END__
__C__
void greet(char* name) {
printf("Hello %s!\n", name);
}
void GetMem(long *memory_address){
*memory_address = 255 - *memory_address;
memory_address++;
printf("Hello %l!\n", memory_address);
}
#### END testInlineC.pl
#### START COMMAND LINE OUTPUT
C:\OCR\Dev>perl testInlineC.pl
Hello Ingy!
Hello 42!
Can't locate auto/main/GetMem.al in @INC (@INC contains: C:\OCR\Dev\_Inline\lib c:/Perl/lib c:/Perl/site/lib .) at
testInlineC.pl line 6
#### END COMMAND LINE OUTPUT
You can see that greet() works just fine. However, GetMem() does not.
Can someone please help me with this? I have no clue how to get this subroutine working.
ASKER
Thanks for the quick reply,
I have modified the test script taking into account your advice. Looking in /lib/ExtUtils/typemap showed me the different types.
You can see that I use atol() to convert the char* into a long.
I think you are definitely on the right track here. Do you see a reason why the following does not work? How would you write it? I'm not sure I understand the concept of remapping...
Thanks for the help!
#### BEGIN TEST SCRIPT
use Inline C;
greet('Ingy');
greet(42);
$memory_address=136052768;
GetMem($memory_address);
__END__
__C__
void greet(char* name) {
printf("Hello %s!\n", name);
}
void GetMem(char* memory_address){
printf("Hello char: %s!\n", memory_address);
long lp;
lp = atol(memory_address);
printf("Hello long: %l!\n", lp);
}
#### END TEST SCRIPT
#### OUTPUT LOG
C:\OCR\Dev>perl testInlineC.pl
Microsoft (R) Program Maintenance Utility Version 1.50
Copyright (c) Microsoft Corp 1988-94. All rights reserved.
C:\Perl\bin\perl.exe C:\Perl\lib\ExtUtils/xsubp p -typemap C:\Perl\lib\ExtUtils\typem ap testInlineC_pl_68d
6.xs > testInlineC_pl_68d6.xsc && C:\Perl\bin\perl.exe -MExtUtils::Command -e mv testInlineC_pl_68d6.xsc testInline
C_pl_68d6.c
cl -c -IC:/OCR/Dev -nologo -Gf -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT
-DNO_HASH_SEED -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX -MD -Zi -DNDEBUG -O1
-DVERSION=\"0.00\" -DXS_VERSION=\"0.00\" "-IC:\Perl\lib\CORE" testInlineC_pl_68d6.c
testInlineC_pl_68d6.c
testInlineC_pl_68d6.xs(10) : error C2143: syntax error : missing ';' before 'type'
testInlineC_pl_68d6.xs(11) : error C2065: 'lp' : undeclared identifier
NMAKE : fatal error U1077: 'C:\WINDOWS\system32\cmd.e xe' : return code '0x2'
Stop.
A problem was encountered while attempting to compile and install your Inline
C code. The command that failed was:
nmake > out.make 2>&1
The build directory was:
C:\OCR\Dev\_Inline\build\t estInlineC _pl_68d6
To debug the problem, cd to the build directory, and inspect the output files.
at testInlineC.pl line 0
INIT failed--call queue aborted.
#### END LOG
I have modified the test script taking into account your advice. Looking in /lib/ExtUtils/typemap showed me the different types.
You can see that I use atol() to convert the char* into a long.
I think you are definitely on the right track here. Do you see a reason why the following does not work? How would you write it? I'm not sure I understand the concept of remapping...
Thanks for the help!
#### BEGIN TEST SCRIPT
use Inline C;
greet('Ingy');
greet(42);
$memory_address=136052768;
GetMem($memory_address);
__END__
__C__
void greet(char* name) {
printf("Hello %s!\n", name);
}
void GetMem(char* memory_address){
printf("Hello char: %s!\n", memory_address);
long lp;
lp = atol(memory_address);
printf("Hello long: %l!\n", lp);
}
#### END TEST SCRIPT
#### OUTPUT LOG
C:\OCR\Dev>perl testInlineC.pl
Microsoft (R) Program Maintenance Utility Version 1.50
Copyright (c) Microsoft Corp 1988-94. All rights reserved.
C:\Perl\bin\perl.exe C:\Perl\lib\ExtUtils/xsubp
6.xs > testInlineC_pl_68d6.xsc && C:\Perl\bin\perl.exe -MExtUtils::Command -e mv testInlineC_pl_68d6.xsc testInline
C_pl_68d6.c
cl -c -IC:/OCR/Dev -nologo -Gf -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT
-DNO_HASH_SEED -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX -MD -Zi -DNDEBUG -O1
-DVERSION=\"0.00\" -DXS_VERSION=\"0.00\" "-IC:\Perl\lib\CORE" testInlineC_pl_68d6.c
testInlineC_pl_68d6.c
testInlineC_pl_68d6.xs(10)
testInlineC_pl_68d6.xs(11)
NMAKE : fatal error U1077: 'C:\WINDOWS\system32\cmd.e
Stop.
A problem was encountered while attempting to compile and install your Inline
C code. The command that failed was:
nmake > out.make 2>&1
The build directory was:
C:\OCR\Dev\_Inline\build\t
To debug the problem, cd to the build directory, and inspect the output files.
at testInlineC.pl line 0
INIT failed--call queue aborted.
#### END LOG
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Sorry about the remark in the last code:
long lp; // < perfectly legal in C90
printf("Hello char: %s!\n", memory_address);
lp = atol(memory_address);
printf("Hello long: %l!\n", lp);
long lp; // < perfectly legal in C90
printf("Hello char: %s!\n", memory_address);
lp = atol(memory_address);
printf("Hello long: %l!\n", lp);
ASKER
roee_f,
thanks a bunch! that gets me through compilation no problem. However, can you think of a reason why atol() wouldn't work? In fact, I cannot even assign a value to the 'long' type.
#### SAMPLE CODE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
long lp;
lp=100;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
//lp = atol(SvPV(sv_name, PL_na));
printf("Hello long: %l!\n", lp);
}
#### END SAMPLE
#### OUTPUT
ptrData prior to muck() is 149225504
Hello string 149225504!
Hello long: !
#### END OUTPUT
I cannot print out a long value at all (let alone with atol()!). In the above sample I commented out the atol() subroutine in favor of direct assignment of the 'long' lp. It won't even print!
However, the following works just fine:
#### SAMPLE CODE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
int lp;
lp=100;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
//lp = atol(SvPV(sv_name, PL_na));
printf("Hello int: %i!\n", lp);
}
#### END SAMPLE
#### OUTPUT
ptrData prior to muck() is 149225504
Hello string 149225504!
Hello int: 100!
#### END OUTPUT
strange, huh? The 'long' type is supported by inline C (/lib/ExtUtils/typedef). Otherwise it wouldn't compile!
Any thoughts on that?
I appreciate the help!
thanks a bunch! that gets me through compilation no problem. However, can you think of a reason why atol() wouldn't work? In fact, I cannot even assign a value to the 'long' type.
#### SAMPLE CODE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
long lp;
lp=100;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
//lp = atol(SvPV(sv_name, PL_na));
printf("Hello long: %l!\n", lp);
}
#### END SAMPLE
#### OUTPUT
ptrData prior to muck() is 149225504
Hello string 149225504!
Hello long: !
#### END OUTPUT
I cannot print out a long value at all (let alone with atol()!). In the above sample I commented out the atol() subroutine in favor of direct assignment of the 'long' lp. It won't even print!
However, the following works just fine:
#### SAMPLE CODE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
int lp;
lp=100;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
//lp = atol(SvPV(sv_name, PL_na));
printf("Hello int: %i!\n", lp);
}
#### END SAMPLE
#### OUTPUT
ptrData prior to muck() is 149225504
Hello string 149225504!
Hello int: 100!
#### END OUTPUT
strange, huh? The 'long' type is supported by inline C (/lib/ExtUtils/typedef). Otherwise it wouldn't compile!
Any thoughts on that?
I appreciate the help!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
worked good. Didnt think of using %ld
Why does the following not print correctly?
#### SAMPLE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
long lp;
unsigned char *pointer;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
lp = atol(SvPV(sv_name, PL_na));
printf("Hello long: %ld!\n", lp);
// To get the content of a byte at a specified adress, use:
*pointer = (unsigned char*)lp;
printf("Adress %u, content %c\n",pointer, *pointer);
//The first line performes a type cast from long (return value of ImageDataPtr) to unsigned char*. After that it will not print correctly.
}
#### END SAMPLE
#### OUTPUT
C:\OCR\Dev>perl testActiveX.pl
ptrData: 140574752
value using peek(): 325674260
hex value using peek(): 13696514
640, 480
elapsed time is 2.038976 s
ptrData prior to muck() is 140574752
Hello string 140574752!
Hello long: 140574752!
Adress 27800872, content
#### END OUTPUT
Note that all of this headache stems from the fact the lib/extutils/typedef does not specify a long *.
Thanks for the advice!
You both have answered this dead on. This last step and I should be done with Inline C .
Why does the following not print correctly?
#### SAMPLE
print "ptrData prior to muck() is $ptrData\n";
muck("$ptrData");
use Inline C;
__END__
__C__
void muck(SV* sv_name) {
long lp;
unsigned char *pointer;
printf("Hello string %s!\n", SvPV(sv_name, PL_na));
lp = atol(SvPV(sv_name, PL_na));
printf("Hello long: %ld!\n", lp);
// To get the content of a byte at a specified adress, use:
*pointer = (unsigned char*)lp;
printf("Adress %u, content %c\n",pointer, *pointer);
//The first line performes a type cast from long (return value of ImageDataPtr) to unsigned char*. After that it will not print correctly.
}
#### END SAMPLE
#### OUTPUT
C:\OCR\Dev>perl testActiveX.pl
ptrData: 140574752
value using peek(): 325674260
hex value using peek(): 13696514
640, 480
elapsed time is 2.038976 s
ptrData prior to muck() is 140574752
Hello string 140574752!
Hello long: 140574752!
Adress 27800872, content
#### END OUTPUT
Note that all of this headache stems from the fact the lib/extutils/typedef does not specify a long *.
Thanks for the advice!
You both have answered this dead on. This last step and I should be done with Inline C .
ASKER
how did u know to use %ld?
pointer = (unsigned char*)lp;
see
man printf
man printf
ASKER
an optional l
(ell) specifying that a following d, i, o, u, x, or
X conversion character applies to a type long int or
unsigned long int argument; an optional l (ell)
specifying that a following n conversion character
applies to a pointer to a type long int argument; an
conversion character applies to a pointer to a long
long argument; or an optional L specifying that a fol-
lowing e, E, f, g, or G conversion character applies
to a type long double argument. If an h, l, ll, or L
appears with any other conversion character, the
behavior is undefined.
That is really obscure!
ASKER
The following is a working solution. Thanks ozo and roee_f!
#!/usr/bin/perl -w
#------------------------- -------
# start of profiler:
# start section
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
$t0 = [gettimeofday];
# end section
#------------------------- -------
#------------------------- -------
# instance an imaging control using Win32::OLE:
# start section:
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag ingControl ') or die "oops\n";
# end section
#------------------------- -------
#------------------------- -------
# Use the Dialog to get camera settings:
# start section
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti ngsDialog( );
#$imaging->SaveDeviceState ToFile("c: \\ocr\\dev ice_state. xml");
# end section
#------------------------- -------
#------------------------- --------
# This section is used by all following sections.
# start section
$imaging->LoadDeviceStateF romFile("c :\\ocr\\de vice_state .xml",1);
$imaging->MemorySnapImage( );
$imaging->MemorySaveImage( "c:\\ocr\\ test1.bmp" );
$buffer = $imaging->ImageBuffers->It em(1);
# end section
#------------------------- --------
#------------------------- ---------- --------
# This section tries to use ImageDataPtr() to access image data.
# Hopefully it will not interfere with saving the image.
# start section
$t3 = [gettimeofday];
$ptrData=$buffer->ImageDat aPtr();
print "ptrData prior to muck() is $ptrData\n";
$indexForImage = 640*480*3; # HARDCODED!!!! BEWARE CHANGES TO HARDWARE SETTINGS
for($i=0;$i<$indexForImage ; $i++) {
muck($ptrData); # will print output from muck...
$ptrData++;
}
$imaging->MemorySaveImage( "c:\\ocr\\ test2.bmp" ); # nope! saves great!!!
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t3, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#------------------------- ---------- --------
#------------------------- ---------- --------
# second half of profiler:
# start section
print $imaging->ImageWidth();pri nt ", ";
print $imaging->ImageHeight();pr int "\n";
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#------------------------- ---------- --------
use Inline C;
__END__
__C__
void muck(long memory_address) {
// convert using a type cast:
unsigned char* Adr = (unsigned char*)memory_address;
// perform some type of image processing:
*Adr = 255 - (*Adr);
// uncomment the following to see process from command line:
// remember to use %ld, NOT %l!!!!
//printf("Hello long: %ld!\n", memory_address);
//printf("Hello address: %ld\n", Adr);
//printf("Hello address contents: %ld\n", *Adr);
}
#!/usr/bin/perl -w
#-------------------------
# start of profiler:
# start section
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
$t0 = [gettimeofday];
# end section
#-------------------------
#-------------------------
# instance an imaging control using Win32::OLE:
# start section:
use Win32::OLE;
$imaging = Win32::OLE->new('IC.ICImag
# end section
#-------------------------
#-------------------------
# Use the Dialog to get camera settings:
# start section
# If we want to change settings we need to use the dialog and and save
# the state so we can load from file.
#$imaging->ShowDeviceSetti
#$imaging->SaveDeviceState
# end section
#-------------------------
#-------------------------
# This section is used by all following sections.
# start section
$imaging->LoadDeviceStateF
$imaging->MemorySnapImage(
$imaging->MemorySaveImage(
$buffer = $imaging->ImageBuffers->It
# end section
#-------------------------
#-------------------------
# This section tries to use ImageDataPtr() to access image data.
# Hopefully it will not interfere with saving the image.
# start section
$t3 = [gettimeofday];
$ptrData=$buffer->ImageDat
print "ptrData prior to muck() is $ptrData\n";
$indexForImage = 640*480*3; # HARDCODED!!!! BEWARE CHANGES TO HARDWARE SETTINGS
for($i=0;$i<$indexForImage
muck($ptrData); # will print output from muck...
$ptrData++;
}
$imaging->MemorySaveImage(
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t3, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#-------------------------
#-------------------------
# second half of profiler:
# start section
print $imaging->ImageWidth();pri
print $imaging->ImageHeight();pr
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
print "elapsed time is $elapsed s\n";
# end section
#-------------------------
use Inline C;
__END__
__C__
void muck(long memory_address) {
// convert using a type cast:
unsigned char* Adr = (unsigned char*)memory_address;
// perform some type of image processing:
*Adr = 255 - (*Adr);
// uncomment the following to see process from command line:
// remember to use %ld, NOT %l!!!!
//printf("Hello long: %ld!\n", memory_address);
//printf("Hello address: %ld\n", Adr);
//printf("Hello address contents: %ld\n", *Adr);
}
The types you can pass are defined in /lib/ExtUtils/typemap somewhere under your Perl dir.
long * is not one of these types (although char *, is!)
You'll have to map it yourself.
Than, you'll have to deal with the porblem that (at least) some fo the perl does deal well with in/out parameters.
The simplest way may be to use the variable as input only, define a copy inside it, and return the changed value in the return path.