Article ID:qGEN003
Date Revised:June 06, 1998
Keywords:API, struct, Internal memory storage
See Also:Download ConvertAPI.PRG   

Question: How do I use 4 byte integer and 2 byte word values inside of a struct in API calls?

Answer: When you are trying to use C structs from VFP you have to worry about the way values are stored in memory because you have to build the struct in a VFP string and pass that string to the DLL function you are trying to use. This is complicated a little by the memory architecture used with Intel CPUs.

If you have a 2 byte decimal value 291, which in hexadecimal is 0x0123, that value stored in memory is reversed so the lowest memory byte address contains the 0x23 and the next byte contains 0x01. So the 2 consecutive bytes in memory are:

...0x230x01...

If you have a 4 byte decimal value 19088743, which in hexadecimal is 0x01234567, that value stored in memory is word reversed, and each word is byte reversed. So the 4 consecutive bytes of memory are:

...0x670x450x230x01...

You can try this in the command window:

set procedure to convertapi additive

x = ToLong( 0x01234567 )

? x

? transform( asc( substr(x,1,1) ), "@0" )

? transform( asc( substr(x,2,1) ), "@0" )

? transform( asc( substr(x,3,1) ), "@0" )

? transform( asc( substr(x,4,1) ), "@0" )

When you print x you'll see gE# followed by a little box which is the chr(0x01) character.

If your C struct is:

struct {
	long nItem1,
	long nItem2,
	char cString1[32],
	char cString2[128] }

in VFP to stuff nX into nItem1 and nY into nItem2:

declare integer TheFunction in TheDLL string@ TheArgument

cStruct = ToLong( nX ) + ToLong( nY ) + replicate( chr(0), 32 ) + replicate( chr(0), 128 )

?TheFunction( @cStruct )

If the DLL changes the long values to see the new values:

? FromLong( cStruct, 1, 4 )

? FromLong( cStruct, 5, 4 )

To take a VFP number (in the range 0..65535) into a WORD:

function ToWord( pnNumber )
local lnMSB, lnLSB
lnMSB = int( pnNumber / 256 )  && most significant byte
lnLSB = pnNumber % 256  && least significant byte
return chr( lnLSB ) + chr( lnMSB )

To take a VFP number (in the range 0..2 gig) into a LONG:

function ToLong( pnNumber )
local lnMSW, lnLSW
lnMSW = int( pnNumber / 65536 )  && most significant word
lnLSW = pnNumber % 65536  && least significant word
return ToWord( lnLSW ) + ToWord( lnMSW )

Longs are stored least significant word then most significant word, showing the same kind of reversal that the bytes have inside a word.

To convert from those internal representations that are buried inside the string:

function FromWord( pcBuffer )
return asc( substr( pcBuffer, 2, 1 ) ) * 256 + asc( left( pcBuffer, 1 ) )

function FromLong( pcBuffer )
return FromWord( substr( pcBuffer, 3, 2 ) ) * 65536 + FromWord( left( pcBuffer, 2 ) )

The above two From functions do just the opposite of the To functions.

There is a another sample that comes with VFP in do home() + "\SAMPLES\SOLUTION\SOLUTION.APP"

Here is ConvertAPI.PRG if you just want to copy it from this page directly:

* ConvertAPI.prg 08-Oct-97

* these functions convert to/from internal binary storage

function ToWord( pnNumber )
local lnMSB, lnLSB
lnMSB = int( pnNumber / 256 )  && most significant byte
lnLSB = pnNumber % 256  && least significant byte
return chr( lnLSB ) + chr( lnMSB )

function ToLong( pnNumber )
local lnMSW, lnLSW
lnMSW = int( pnNumber / 65536 )  && most significant word
lnLSW = pnNumber% 65536  && least significant word
return ToWord( lnLSW ) + ToWord( lnMSW )

function FromWord( pcBuffer )
return asc( substr( pcBuffer, 2, 1 ) ) * 256 + asc( left( pcBuffer, 1 ) )

function FromLong( pcBuffer )
return FromWord( substr( pcBuffer, 3, 2 ) ) * 65536 + FromWord( left( pcBuffer, 2 ) )


1