Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
How to define data type for integer,binary & hexadecima
Message
From
24/01/1999 10:44:53
 
 
To
24/01/1999 10:41:02
General information
Forum:
Visual FoxPro
Category:
Coding, syntax & commands
Miscellaneous
Thread ID:
00179567
Message ID:
00179576
Views:
31
>Ed Rauh,
> Sorry i can't find the .prg you mention. Can you send it to me ?
>kengwen@yahoo.com
> thanks

It will be posted when the sysops at UT have reviewed it and decided that it's worth adding to the Files collection here. In the meantime, I've embedded the code here. I've had problems sending code in messages before, so you'd be better off waiting for the file to be available for download:
**************************************************
*-- Class:        heap 
*-- ParentClass:  custom
*-- BaseClass:    custom
*
*  Another in the family of relatively undocuemnted sample classes I've inflicted on others
*  Warning - there's no error handling in here, so be careful to check for null returns and
*  invalid pointers.  Unless you get frisky, or you're resource-tight, it should work well.
*
*  It doesn't seem to bleed, either, at the moment.
*
*	Overwheming guilt hit early this morning;  maybe I should explain the concept of the Heap class
*	and give an example of how to use it, in conjunction with the add-on functions that follow in
*	this procedure library here.
*
*	Windows allocates memory from several places;  it also provides a way to define your own small corner
*	of the universe where you can allocate and deallocate blocks of memory for your own purposes.  These
*	public or private memory areas are referred to commonly as heaps.
*
*	VFP is great in most cases;  it provides flexible allocation and alteration of variables on the fly
*	in a program.  This makes most programming tasks easy.  However, in exchange for VFP's flexibility in
*	memory variable allocation, we give up several things, the most annoying of which are not knowing the
*	exact location of a VFP variable in memory, and not being able to define new kinds of memory structures
*	within VFP to manipulate as a structure directly.
*
*	Enter Heap.  Heap creates a growable, private Heap, from which you can allocate blocks of memory that
*	have a known location and size in your memory address space.  It also provides a way of transferring
*	data to and from these allocated blocks.
*
*	Heap does its work using a number of Win32 API functions;  HeapCreate(), which sets up a private heap 
*	and assigns it a handle, is invoked in the Init method.  This sets up the heap that all future allocations
*	for the class will be constructed from.  I set up the heap to use a base allocation size of twice the size
*	of a swap file 'page' in the x86 world (8K), and made the heap able to grow;  it adds 8K chunks of memory
*	to itself as it grows.  There's no fixed limit (other than available -virtual- memory) on the size of the
*	heap constructed;  just realize that huge allocations are likely to bump heads with VFP's own desire
*	for mondo RAM.
*
*	Once the Heap is established, we can allocate blocks of any size we want in the heap, outside of VFP's
*	memory, but within the virtual addrss space owned by VFP.  Blocks are allocated by HeapAlloc(), and a
*	pointer to the block is returned as an integer.  KEEP THE POINTER RETURNED BY THE Alloc METHOD, it's the
*	key to doing things with the block in the future.
*
*	Periodically, we need to load things into the block we've created.  Thanks to work done by Christof Lange,
*	George Tasker and others, we found a Win32API call that will do transfers between memory locations, called
*	RtlMoveMemory().  RtlMoveMemory() acts like the Win32API MoveMemory() call;  it takes two pointers 
*	(destination and source) and a length.  In order to make life easy, at times we DECLARE the pointers as
*	INTEGER (we pass a number, which is treated as a DWORD (32 bit unsigned integer) whose content is the
*	address to use, and at other times as STRING @, which passes the physical address of a VFP string variable
*	contents, allowing RtlMoveMemory() to read and write VFP strings without knowing how to manipulate VFP's
*	internal variable structures.  RtlMoveMemory() is used by both the CopyFrom and CopyTo methods.
*
*	At some point, we're finished with a block of memory.  We can free up that memory via HeapFree(), which
*	releases a previously-allocated block on the heap.  It does not compact or rearrange the heap allocations
*	but simply makes the memory allocated no long valid, and the addess could be reused by annother Alloc
*	operation.  We track the active state of allocations in a member array iaAllocs[] which has 3 members
*	per row;  the pointer, which is used as a key, the actual size of the allocation (sometimes HeapAlloc()
*	gives you a larger block than requested;  we can see it here.  This is the property returned by the
*	SizeOfBlock method) and whether or not it's active and available.
*
*	When we're done, we need to release the allocations and the heap itself.  HeapDestroy() releases the 
*	entire heap back to the Windows memory pool.  This is invoked in the Destroy method of the class to
*	ensure that it gets explcitly released, since it remains alive until released.  I put this in the
*	Destroy method to ensure that the heap went away when the heap object went out of scope.
*
*	The class methods are:
*
*		Init				Creates the heap for use
*		Alloc(nSize)		Allocates a block of nSize bytes, returns an nPtr to it.  nPtr is NULL if fail
*		DeAlloc(nPtr)		Releases the block whose base address is nPtr.  Returns T/F
*		CopyTo(nPtr,cSrc)	Copies the Content of cStr to the buffer at nPtr, up to the smaller of LEN(cSrc)
*							or the length of the block (we look in the iaAllocs[] array).  Returns T/F
*		CopyFrom(nPtr)		Copys the content of the block at nPtr (size is from iaAllocs[]) and returns
*							it as a VFP string.  Returns a string, or NULL if fails
*		SizeOfBlock(nPtr)	Returns the actual allocated size of the block pointed to by nPtr
*		Destroy				DeAllocs anything still active, and then frees the heap.
*
* The ancillary goodies in the procedure library are there to make life easier for people working with structures;
* they are not optimal and infinitely complete, but they do the things that are commonly needed when dealing with
* stuff in structures.  The functions are of two types;  converters, which convert standard C structures to an
* equivalent VFP numeric, or make a string whose value is equivalent to a C data type from a number, so that you
* can embed integers, pointers, etc. in the strings used to assemble a structure which you load up with CopyTo, 
* or pull out pointers and integers that come back embedded in a structure you've grabbed with CopyFrom.
*
* The second type of functions provided are memory copiers.  The CopyFrom and CopyTo methods are set up to work
* with our heap, and nPtrs must take on the values of block addresses grabbed from our heap.  There will be
* lots of times where you need to get the content of memory not necessarily on our heap, so SetMem, GetMem and 
* GetMemString go to work for us here.  SetMem copies the content of a string into the absolute memory block
* at nPtr, for the length of the string, using RtlMoveMemory().  BE AWARE THAT MISUSE CAN (and most likely will)
* RESULT IN C0000005 ERRORS, memory access violations, or similar OPERATING SYSTEM level errors that will smash
* VFP like an empty beer can in a trash compactor.
*
* There are two functions to copy things from a known address back to the VFP world.  If you know the size of the
* block to grab, GetMem(nPtr,nSize) will copy nSize bytes from the address nPtr and return it as a VFP string.  See
* the caveat above.  GetMemString(nPtr) uses a different API call, lstrcpyn(), to copy a null terminated string
* from the address specified by nPtr.  You can hurt yourself with this one, too.
*
*	Functions in the procedure library not a part of the class:
*
*	GetMem(nPtr,nSize)			Copy nSize bytes at address nPtr into a VFP string
*	SetMem(nPtr,cSource)		Copy the string in cSource to the block beginning at nPtr
*	GetMemString(nPtr)			Get the null-terminated string (up to 512 bytes) from the address at nPtr
*
*	DWORDToNum(cString)			Convert the first 4 bytes of cString as a DWORD to a VFP numeric (0 to 2^32)
*	SHORTToNum(cString)			Convert the first 2 bytes of cString as a SHORT to a VFP numeric (-32768 to 32767)
*	WORDToNum(cString)			Convert the first 2 bytes of cString as a WORD to a VFP numeric  (0 to 65535)
*	NumToDWORD(nInteger)		Converts nInteger into a string equivalent to a C DWORD (4 byte unsigned)
*	NumToWORD(nInteger)			Converts nInteger into a string equivalent to a C WORD (2 byte unsigned)
*	NumToSHORT(nInteger)		Converts nInteger into a string equivalent to a C SHORT ( 2 byte signed)
*
*	That's it for the docs to date;  more stuff to come.  The code below is copyright Ed Rauh, 1999;  you may
*	use it without royalties in your own code as you see fit, as long as the code is attributed to me.
*
*	This is provided as-is, with no implied warranty.  Be aware that you can hurt yourself with this code, most
*	easily when using the SetMem(), GetMem() and GetMemString() functions.  I will continue to add features and
*	functions to this periodically.  If you find a bug, please notify me.  It does no good to tell me that "It
*	doesn't work the way I think it should..WAAAAH!"  I need to know exactly how things fail to work with the
*	code I supplied.  A small code snippet that can be used to test the failure would be most helpful in trying
*	to track down miscues.  I'm not going to run through hundreds or thousands of lines of code to try to track
*	down where exactly something broke.  
*
*	Please post questions regarding this code on Universal Thread;  I go out there regularly and will respond
*	pretty quickly.  In addition, other API gurus and FoxWizards frequent UT, and they may well be able to 
*	help, in many cases better than I could.  Posting questions on UT helps not only with getting support
*	from the VFP community at large, it also makes the information about the problem and its solution available
*	to others who might have the same or similar problems.
*
*	If you do request help other than by UT, especially if you have to send files to help diagnose the problem,
*	send them to me at edrauh@earthlink.net or erauh@weatherhill.com, preferably the earthlink.net account.
*
*	If you have questions about this code, you can ask.  If you have questions about using it with API calls and
*	the like, you can ask.  If you have enhancements that you'd like to see added to the code, you can ask.
*	Flames will be ignored.  I'll try to answer promptly, but realize that support and enhancements for this are
*	done in my own spare time.  If you need specific support that goes beyond what I feel is reasonable, I'll
*	tell you.
*
*	Do not call me at home or work for support.  Period. <Mumble><something about ripping out internal organs><Grr>
*
*	Feel free to modify this code to fit your specific needs.  Since I'm not providing any warranty with this
*	in any case, if you change it and it breaks, you own both pieces.
*
DEFINE CLASS heap AS custom


	PROTECTED inHandle
	inHandle = NULL
	PROTECTED inNumAllocsActive
	inNumAllocsActive = 0
	Name = "heap"
	*  I've been debating whether this should be protected;  for now, it isn't
	*  It probably should be.
	DIMENSION iaAllocs[1,3]


	PROCEDURE Alloc
		*  Allocate a block, returning a pointer to it
		LPARAMETER nSize
		DECLARE INTEGER HeapAlloc IN WIN32API AS HAlloc;
			INTEGER hHeap, ;
			INTEGER dwFlags, ;
			INTEGER dwBytes
		LOCAL nPtr
		WITH this
			nPtr = HAlloc(.inHandle, 0, @nSize)
			*  Bump the allocation array
			.inNumAllocsActive = .inNumAllocsActive + 1
			DIMENSION .iaAllocs[.inNumAllocsActive,3]
			*  Pointer
			.iaAllocs[.inNumAllocsActive,1] = nPtr
			*  Size actually allocated
			.iaAllocs[.inNumAllocsActive,2] = nSize
			*  It's alive...alive I tell you!
			.iaAllocs[.inNumAllocsActive,3] = .T.
		ENDWITH
		RETURN nPtr
	ENDPROC


	PROCEDURE DeAlloc
		*  Discard a previous Allocated block
		LPARAMETER nPtr
		DECLARE INTEGER HeapFree IN WIN32API AS HFree ;
			INTEGER hHeap, ;
			INTEGER dwFlags, ;
			INTEGER lpMem
		LOCAL nCtr, lSucceeds
		lSucceeds = .F.
		WITH this
			FOR nCtr = 1 TO .inNumAllocsActive
				IF .iaAllocs[nCtr,1] = nPtr
					IF .iaAllocs[nCtr,3]
						=HFree(.inHandle, 0, nPtr)
						.iaAllocs[nCtr,3] = .F.
					ENDIF
					lSucceeds = .T.
					EXIT
				ENDIF
			ENDFOR
		ENDWITH
		RETURN lSucceeds
	ENDPROC


	PROCEDURE CopyTo
		*  Copy a VFP string into a block
		LPARAMETER nPtr, cSource
		*  ReDECLARE RtlMoveMemory to make copy parameters easy
		DECLARE RtlMoveMemory IN WIN32API AS RtlCopy ;
			INTEGER nDestBuffer, ;
			STRING @pVoidSource, ;
			INTEGER nLength
		LOCAL nCtr, lSucceeds
		lSucceeds = .F.
		WITH this
			*  Find the Allocation pointed to by nPtr
			FOR nCtr = 1 TO .inNumAllocsActive
				IF .iaAllocs[nCtr,1] = nPtr
					*  Is it active
					IF .iaAllocs[nCtr,3]
						*  We can copy to it
						lSucceeds = .T.
						EXIT
					ENDIF
				ENDIF
			ENDFOR
			IF lSucceeds
				*  Copy the smaller of the buffer size or the source string
				=RtlCopy((.iaAllocs[nCtr,1]), ;
						cSource, ;
						MIN(LEN(cSource),.iaAllocs[nCtr,2]))
			ENDIF
		ENDWITH
		RETURN lSucceeds
	ENDPROC


	PROCEDURE CopyFrom
		*  Copy the content of a buffer back to the VFP world
		LPARAMETER nPtr
		*  Note that we reDECLARE RtlMoveMemory to make passing things easier
		DECLARE RtlMoveMemory IN WIN32API AS RtlCopy ;
			STRING @DestBuffer, ;
			INTEGER pVoidSource, ;
			INTEGER nLength
		LOCAL nCtr, lSucceeds
		lSucceeds = .F.
		WITH this
			*  Find the allocation whose address is nPtr
			FOR nCtr = 1 TO .inNumAllocsActive
				IF .iaAllocs[nCtr,1] = nPtr
					*  Is it active?
					IF this.iaAllocs[nCtr,3]
						* Yes - we can copy there
						lSucceeds = .T.
						EXIT
					ENDIF
				ENDIF
			ENDFOR
			IF lSucceeds
				LOCAL uBuffer
				* Allocate a buffer in VFP big enough to receive the block
				uBuffer = REPL(CHR(0),.iaAllocs[nCtr,2])
				=RtlCopy(@uBuffer, ;
						(.iaAllocs[nCtr,1]), ;
						(.iaAllocs[nCtr,2]))
			ELSE
				uBuffer = NULL
			ENDIF
		ENDWITH
		RETURN uBuffer
	ENDPROC

	PROCEDURE SizeOfBlock
		*  Retrieve the actual memory size of an allocated block
		LPARAMETERS nPtr
		LOCAL nCtr, nSizeOfBlock
		nSizeOfBlock = NULL
		WITH this
			*  Find the allocation whose address is nPtr
			FOR nCtr = 1 TO .inNumAllocsActive
				IF .iaAllocs[nCtr,1] = nPtr
					*  Is it active?
					IF this.iaAllocs[nCtr,3]
						* Yes - we can copy there
						nSizeOfBlock = .iaAllocs[nCtr,2]
						EXIT
					ENDIF
				ENDIF
			ENDFOR
		ENDWITH
		RETURN nSizeOfBlock


	PROCEDURE Destroy
		DECLARE HeapDestroy IN WIN32API AS HDestroy ;
		  INTEGER hHeap

		LOCAL nCtr
		WITH this
			FOR nCtr = 1 TO .inNumAllocsActive
				IF .iaAllocs[nCtr,3]
					.Dealloc(.iaAllocs[nCtr,1])
				ENDIF
			ENDFOR
			HDestroy[.inHandle]
		ENDWITH
		DODEFAULT()
	ENDPROC


	PROCEDURE Init
		DECLARE INTEGER HeapCreate IN WIN32API AS HCreate ;
			INTEGER dwOptions, ;
			INTEGER dwInitialSize, ;
			INTEGER dwMaxSize
		#DEFINE SwapFilePageSize  4096
		#DEFINE BlockAllocSize    2 * SwapFilePageSize
		WITH this
			.inHandle = HCreate(0, BlockAllocSize, 0)
			DIMENSION .iaAllocs[1,3]
			.iaAllocs[1,1] = 0
			.iaAllocs[1,2] = 0
			.iaAllocs[1,3] = .F.
			.inNumAllocsActive = 0
		ENDWITH
		RETURN (this.inHandle # 0)
	ENDPROC


ENDDEFINE
*
*-- EndDefine: heap
**************************************************
*
*  Additional functions for working with structures and pointers and stuff
*
FUNCTION SetMem
LPARAMETERS nPtr, cSource
*  Copy cSource to the memory location specified by nPtr
*  ReDECLARE RtlMoveMemory to make copy parameters easy
*  nPtr is not validated against legal allocations on the heap
DECLARE RtlMoveMemory IN WIN32API AS RtlCopy ;
	INTEGER nDestBuffer, ;
	STRING @pVoidSource, ;
	INTEGER nLength

RtlCopy(nPtr, ;
		cSource, ;
		LEN(cSource))
RETURN .T.

FUNCTION GetMem
LPARAMETERS nPtr, nLen
*  Copy the content of a memory block at nPtr for nLen bytes back to a VFP string
*  Note that we ReDECLARE RtlMoveMemory to make passing things easier
*  nPtr is not validated against legal allocations on the heap
DECLARE RtlMoveMemory IN WIN32API AS RtlCopy ;
	STRING @DestBuffer, ;
	INTEGER pVoidSource, ;
	INTEGER nLength
LOCAL uBuffer
* Allocate a buffer in VFP big enough to receive the block
uBuffer = REPL(CHR(0),nLen)
=RtlCopy(@uBuffer, ;
		 nPtr, ;
		 nLen)
RETURN uBuffer

FUNCTION GetMemString
LPARAMETERS nPtr
*  Copy the string at location nPtr into a VFP string
*  We're going to use lstrcpyn rather than RtlMoveMemory to copy up to a terminating null
*  nPtr is not validated against legal allocations on the heap
DECLARE INTEGER lstrcpyn IN WIN32API AS StrCpyN ;
	STRING @ lpDestString, ;
	INTEGER lpSource, ;
	INTEGER nMaxLength
LOCAL uBuffer
*  Allocate a buffer big enough to receive the data
uBuffer = REPL(CHR(0), 512)
IF StrCpyN(@uBuffer, nPtr, 512) # 0
	uBuffer = LEFT(uBuffer, MAX(0,AT(CHR(0),uBuffer) - 1))
ELSE
	uBuffer = NULL
ENDIF
RETURN uBuffer

FUNCTION DWORDToNum
	* Take a binary DWORD and convert it to a VFP Numeric
	* use this to extract an embedded pointer in a structure in a string to an nPtr
	LPARAMETER tcDWORD
	LOCAL b0,b1,b2,b3
	b0=asc(tcDWORD)
	b1=asc(subs(tcDWORD,2,1))
	b2=asc(subs(tcDWORD,3,1))
	b3=asc(subs(tcDWORD,4,1))
    RETURN ( ( (b3*256 + b2)*256 + b1) * 256 + b0)

FUNCTION SHORTToNum
	* Converts a 16 bit signed integer in a structure to a VFP Numeric
 	LPARAMETER tcInt
	LOCAL b0,b1,nRetVal
	b0=asc(tcInt)
	b1=asc(subs(tcInt,2,1))
	if b1<128
		*
		*  positive - do a straight conversion
		*
		nRetVal=b1 * 256 + b0
	else
		*
		*  negative value - take twos complement and negate
		*
		b1=255-b1
		b0=256-b0
		nRetVal= -( (b1 * 256) + b0)
	endif
	return nRetVal

FUNCTION WORDToNum
	*Take a binary WORD (16 bit USHORT) and convert it to a VFP Numeric
	LPARAMETER tcWORD
	RETURN (256 *  ASC(SUBST(tcWORD,2,1)) ) + ASC(tcWORD)

FUNCTION NumToDWORD
*
*  Creates a 4 byte binary string equivalent to a C DWORD from a number
*  use to embed a pointer or other DWORD in a structure
*  Parameters:
*
*	tnNum			(R)  Number to convert
*
 	LPARAMETER tnNum
 	*
 	*  x,n,i,b[] will hold small ints
 	*
 	LOCAL x,n,i,b[4]
	x=INT(tnNum)
	FOR i=3 TO 0 STEP -1
		b[i+1]=INT(x/(256^i))
		x=MOD(x,(256^i))
	ENDFOR
	RETURN CHR(b[1])+CHR(b[2])+CHR(b[3])+CHR(b[4])


FUNCTION NumToSHORT
*
*  Creates a C SHORT as a string from a number
*
*  Parameters:
*
*	tnNum			(R)  Number to convert
*
	LPARAMETER tnNum
	*
	*  b0, b1, x hold small ints
	*
	LOCAL b0,b1,x
	IF tnNum>=0
		x=INT(tnNum)
		b1=INT(x/256)
		b0=MOD(x,256)
	ELSE
		x=INT(-tnNum)
		b1=255-INT(x/256)
		b0=256-MOD(x,256)
		IF b0=256
			b0=0
			b1=b1+1
		ENDIF
	ENDIF
	RETURN CHR(b0)+CHR(b1)

FUNCTION NumToWORD
*
*  Creates a C USHORT (WORD) from a number
*
*  Parameters:
*
*	tnNum			(R)  Number to convert
*
	LPARAMETER tnNum
	*
	*  x holds an int
	*
	LOCAL x
	x=INT(tnNum)
	RETURN CHR(MOD(x,256))+CHR(INT(x/256))
EMail: EdR@edrauh.com
"See, the sun is going down..."
"No, the horizon is moving up!"
- Firesign Theater


NT and Win2K FAQ .. cWashington WSH/ADSI/WMI site
MS WSH site ........... WSH FAQ Site
Wrox Press .............. Win32 Scripting Journal
eSolutions Services, LLC

The Surgeon General has determined that prolonged exposure to the Windows Script Host may be addictive to laboratory mice and codemonkeys
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform