PH has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I am trying to pass in a scalar to the DoAttach C function, which is then modified by the C function and returned to the perl program. It is getting modified okay, but not as I want/expect!! Here's the perl code:-
$hObject = 0; $result = &testmain::DoAttach( 123, 0x1234, $hObject);
This is the code in the XS file:-
long dsmFSAttach(PID,service,hFS) unsigned short PID unsigned short service unsigned long * hFS OUTPUT: hFS RETVAL
And here is the C code that tries to modify the var:-
long DoAttach(unsigned short PID, unsigned short service, unsigned long *hFS) { *hFS = ReturnFromSomeFunc(...) return foo; }
When this is run the hFS variable in the C function is set to 48 (The ASCII value for 0), and after it is altered by the function it is filled with F's, i.e Print it as an 8bit value and it will print 255... I have tried several combinations in the typemap file - unsigned long * T_PV unsigned long * T_IV unsigned long * T_RV None seem to work! Any help would be excellent, Thanks in advance Paul
PS If you read this and can answer tonight (Thursday 31st May) could you plz email me at paul.hunt@blueyonder.co.uk, if not p_hunt@bitwise.co.uk Thanks again

Replies are listed 'Best First'.
(tye)Re: PerlXS type problem
by tye (Sage) on May 31, 2001 at 20:58 UTC

    Change the "*" to "&" in your XS file. Feel free to reply with questions you have as to why this fixes things. I'd just try to explain it but there are just too many possible sources of confusion here for me to easily zero in on what to talk about.

            - tye (but my friends call me "Tye")
      Thanks tye, that was an excellent help, got me going again ;-))
      Now I have another problem though, one of the C functions calls another C function which returns a ULONG value. The ULONG returning function is declared as static in a .C file and takes a structure as a parameter (The structure is typedef'd in a C file aswell).
      Here's what I've got so far:
      testmain.XS File: This is the declaration for the ULONG returning function-
      unsigned long GetHandle(row,entry) unsigned long row CACHE *entry OUTPUT: RETVAL
      Typemap:
      const char * T_PV unsigned char * T_PV CACHE * T_PTROBJ
      When I compile this I get the following error (First of many!)
      Error C2065: 'CACHE': Undeclared identifier.
      I have included all headers and added all .obj files to the makefile.pl.
      Is there any way around these problems?? I can't modify the c code BTW!
      Again, thanks,
      Paul

        Sounds exactly like you aren't managing to include the definition of the CACHE struct successfully. You'll need to look at the *.c file and perhaps preprocessed output of that and dig around in the headers to figure out why.

        I don't think your simple typemap will work either, though. I suppose it might if there is some other function you call to initialize "entry". BTW, I'm not a big fan of T_PTROBJ. I usually prefer to stuff my C structs into Perl strings. But that is a whole 'nother topic. (:

                - tye (but my friends call me "Tye")
      Hello again, Here's the code I'm stuck with:-
      /* Below is the 3 functions that are supplied to me for testing (alon +g with a whole bunch of others!) */ long ResolveAsync (UCHAR* filepath, ULONG gateway, ULONG *hFS) { long result; ULONG hBiopSRG; // Display hFS value - It is '0', which is correct printf("[DEBUG] Entered ResolveAsync - filepath[%s], gateway[%d], +hFS[%d]\n", filepath, gateway, *hFS); result = FSCacheResolve (filepath, hBiopSRG, hFS, FLAG_NO_LOAD); // Display hFS value - It is '4294967295', which is incorrect. Whe +n this code // is run in a C environment it works fine and the result is eithe +r 2 or 9 // which is what it should be! printf("[DEBUG] Leaving ResolveAsync - filepath[%s], gateway[%d], +hFS[%Lu], Result[%d]\n", filepath, gateway, *hFS, result); return (result); } ////////////////////////////////////////////////////////////////////// +/// long FSCacheResolve (UCHAR* filepath, ULONG gateway, ULONG *handle, UCHAR flag) { // Display the value, it is 0, which it should be printf("[DEBUG] Entered FSCacheResolve(...) - hFS:[%Lu]\n", *handl +e); // ... // Do stuff ... // ... // This is the func that messes the handle!!! *handle = CacheGetHandle (row, hit); // Display the value now, it is WRONG - (handle == 4294967295) printf("[DEBUG] Leaving FSCacheResolve(...) - hFS:[%Lu]\n", *handl +e); return (result); } ////////////////////////////////////////////////////////////////////// +/////////////// // This function is declared as static, so I cant access it directly!! +! // Is there a way round this in PerlXS or will the function HAVE to be // made externaly available to get the correct results in C ??? // The CACHE structure is also declared in a .C file, and is // 'undeclared' as far as PERLXS is concerned. I have the .objs files // included in the makefile settings (O_FILES) static ULONG CacheGetHandle (uint32_t row, CACHE *entry) { ULONG hFS = INVALID_FS_HANDLE; hFS = (entry->llnode[COLLISION_LIST].handle * HASH_TABLE_SIZE) + +row; // hFS now has the correct value, which should be either '2' or '9 +' // but when the value is returned an examined in the calling funct +ion // (FSCacheResolve), its value is shown as 4294967295 // The following line prints either 2 or 9! printf("[DEBUG] In CacheGetHandle(...) - hFS:[%Lu]\n", hFS); return (hFS); } ////////////////////////////////////////////////////////////////////// +/////////////// Here's some of the XS file contents:- long dsmFSResolveAsync(filepath,gateway,hFS) unsigned char *filepath unsigned long gateway unsigned long & hFS OUTPUT: hFS RETVAL long FSCacheResolve(filepath,gateway,handle,flag) unsigned char *filepath unsigned long gateway unsigned long & handle unsigned char flag OUTPUT: handle RETVAL I have tried putting info about CacheGetHandle(...) here but it complains about the unresolved external, so is there a way around this??? ////////////////////////////////////////////////////////////////////// +//////// There's nothing really in the typemap file, just:- unsigned char * T_PV const char * T_PV And here's the test.pl file (Some of it!) $hObject = 0; $result = &testmain::ResolveAsync( "Dir0/binary", $gateway, $hObject); print $result == 0 ? "ok 8 {dsmFSResolveAsync} Handle:[$hObject]\n" : +"not ok 8 {dsmFSResolveAsync} Handle:[$hObject]\n"; # The value of $hObject ends up being 4294967295, when the same functi +on is called # under C, hObject equals either 2 or 9!!!!!
      Basically, am I stuck with making the function external, or is there some way round this?
      Thanks in advance,
      Paul

        I doubt it. "static" means that you can't call the function from outside that source file. You could try to force the linker to export the symbol when you build the DLL, but if you can rebuild the DLL then you should just remove "static" and recompile instead.

                - tye (but my friends call me "Tye")
Re: PerlXS type problem
by bikeNomad (Priest) on May 31, 2001 at 21:00 UTC
    I'm no perlguts expert, but I think that if you set up the argument as an SV * and then use sv_setuv() to change its value, it might work better:
    long change(unsigned short PID, unsigned short service, SV* returnedHF +S) { unsigned long hFS; long retval; retval = DoAttach(PID, service, &hFS); sv_setuv(returnedHFS, hFS); return retval; }

    Updated: added example code