Link to home
Start Free TrialLog in
Avatar of sapbucket
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.

Avatar of roee_f
roee_f

The problem is that you cannot pass any type of variable via Inline::C.
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.
Avatar of sapbucket

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/xsubpp  -typemap C:\Perl\lib\ExtUtils\typemap  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.exe' : 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\testInlineC_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





ASKER CERTIFIED SOLUTION
Avatar of roee_f
roee_f

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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);

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!


SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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 .
how did u know to use %ld?
   pointer = (unsigned char*)lp;
see
man printf


           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!
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.ICImagingControl') 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->ShowDeviceSettingsDialog();
#$imaging->SaveDeviceStateToFile("c:\\ocr\\device_state.xml");
# end section
#--------------------------------

#---------------------------------
# This section is used by all following sections.
# start section
$imaging->LoadDeviceStateFromFile("c:\\ocr\\device_state.xml",1);
$imaging->MemorySnapImage();
$imaging->MemorySaveImage("c:\\ocr\\test1.bmp");
$buffer = $imaging->ImageBuffers->Item(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->ImageDataPtr();
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();print ", ";
print $imaging->ImageHeight();print "\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);

}