Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Exactly what is in that 4 byte memo field in the DBF? 1

Status
Not open for further replies.

rlawrence

Programmer
Sep 14, 2000
182
US
Hi,

I'm trying to recover data from a corrupt memo file. The FPT file is bloated (1.5Gb). I've tried packing...no good. Now I can still open the table in Foxpro 7. When I navigate to troublesome memo fields, I get a Fatal Error and get kicked out of Foxpro. However, most of the records are still intact. I can certainly see the memo fields' contents in record 1 and they all seem fine.

So, I've actually written two programs to look into the content of both the DBF and FPT files. I seem to be reading the blocks in the FPT file correctly. As far as I can tell, I'm getting the content of the 4 bytes in the memo field of the DBF correctly as well. There is a consistency among the several memo fields I have retrieved.

I understand that these bytes are inverted. So, for example, the DBF has a street address stored in a memo field. The first record content in this field is: 01 71 EA 51. My question is: How should I interpret this number (or address)?

I assumed that it would be an offset to the memo block in the FPT file. However, when I use HexEdit to look at the content of the memo file, if I go to that address, I'm in the middle of another completely unrelated memo block.

So, can anyone help me understand what that 4-byte number refers to?

Thanks,

Ron
 
Unfortunately I don't have any advice on how to interpret the 4-byte content of the DBF file (hopefully others will have that info), but you might want to look at:
Table Corruption Repair Tools
or
Advanced DBF Repair

Perhaps they can help you out.

Remember to run the routines on a COPY of your data table files.

Good Luck,
JRB-Bldr
 
On the odd occasion something like this happens, I copy the table to a new one, zap the existing and then append back in

Code:
use MyProblem exclusive
copy to MyTemp
zap
append from MyTemp

I find that VFP6 is better at this, more tolerant of problems, than VFP9

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.
 
Thanks guys,

JRB-Bldr, thanks for the suggestion, but this effort is in part a quest to better understand the internals of the database structure myself. It seems that I have all of the pieces, except the proper interpretation for those 4 bytes in the DBF file.

Dan, I'd already found the msdn articles. That's what allowed me to write my routines to begin with. The problem is that the documentation doesn't say how to interpret the 4-byte memo field content. It makes casual mention that, "Integers in table files are stored with the least significant byte first." And indeed, the content of the memo fields (the 4 bytes in the DBF) seem to make more sense when I invert the bytes.

Here is some sample output from the procedure that reads the DBF:

Code:
Opening Table file: C:\USERS\PUBLIC\PADATA\PUBASSIST.COM\CONTACT.DBF.
File Handle:  9
File Size:  372981  0x0005B0F5
Record#:    1	PO_ADDR: 01 71 EA 51 	COUR_ADDR: 00 00 00 00 	EMAIL: 01 71 EA 53 	WEB_URL: 00 00 00 00 	WEBSERVICE: 00 00 00 00 	BIOGRAPHY: 00 00 00 00 	PORTRAIT: 00 00 00 00 	COMMENT: 00 00 00 00 	
Record#:    2	PO_ADDR: 01 71 EA 58 	COUR_ADDR: 00 00 00 00 	EMAIL: 01 71 EA 59 	WEB_URL: 00 00 00 00 	WEBSERVICE: 00 00 00 00 	BIOGRAPHY: 01 71 EA 5A 	PORTRAIT: 01 71 EA 5F 	COMMENT: 00 00 00 00 	
Record#:    3	PO_ADDR: 01 71 EA 60 	COUR_ADDR: 00 00 00 00 	EMAIL: 01 71 EA 61 	WEB_URL: 00 00 00 00 	WEBSERVICE: 01 71 EA 62 	BIOGRAPHY: 01 71 EA 63 	PORTRAIT: 01 71 EA 71 	COMMENT: 00 00 00 00 	
Record#:    4	PO_ADDR: 00 00 00 00 	COUR_ADDR: 00 00 00 00 	EMAIL: 00 00 00 00 	WEB_URL: 00 00 00 00 	WEBSERVICE: 00 00 00 00 	BIOGRAPHY: 00 00 00 00 	PORTRAIT: 00 00 00 00 	COMMENT: 00 00 00 00 	
.
.
.

Note that the number given in the first record's PO_ADDR field is: 01 71 EA 51. Prior to this run, the number stored in the COUR_ADDR fields was: 01 71 EA 52. And the number in the EMAIL field is: 01 71 EA 53. I then opened the table in Foxpro and found that several of the memo fields of the first record had a blank character. So, I selected the entire content and deleted it. The result, as you can see above, is that those fields that were empty, now have 00 00 00 00 in the memo field. If these are addresses (i.e. offsets) then they would not be consecutive. The PO_ADDR field in the first record is still intact, and reads: "41 Lawrence Heights". That's at least 19 bytes long.

Here is some sample output from the procedure that reads the memo file blocks:

Code:
Opening memo file: C:\USERS\PUBLIC\PADATA\PUBASSIST.COM\CONTACT.FPT.
File Handle:  21
Memo File Size:  1551539328  0x5C7A9C80

***** Header Details *********
Byte offset 0 - 3: Location of the next free block:  1 71 EA 72 
Byte offset 4 - 5: Unused
Byte offset 6 - 7:  Block Size (bytes per block):  64,  0x040
Byte offset 8 - 511: Unused


***** Memo Block Data ********
Address: 512, 0x00000200	Block Type: 1,  0x0001	Memo Length:   17,  0x00011		Content: 2720 Annelise Wayist.com/admin/ 
Address: 576, 0x00000240	Block Type: 1,  0x0001	Memo Length:   27,  0x0001B		Content: liz@entangledpublishing.com
Address: 640, 0x00000280	Block Type: 1,  0x0001	Memo Length:   19,  0x00013		Content: 41 Lawrence Heights
.
.
.

You can see that the first block had already been clobbered, but the following blocks seem to be intact. There is also a clear indication that some memo fields have been updated repeatedly. That's how the memo file gets bloated. The procedure will run through the whole FPT file if I allow it, but that would create a results file larger than the FTP!

It's a puzzle. I'm fairly convinced that I am getting the correct bytes for the (DBF) memo field content. I may still be misinterpreting those contents. Any other thoughts on what these 4 bytes are supposed to be? That so many of the memo field contents seem consecutive troubles me. This wouldn't be the memo block number, would it? That seems terribly inefficient for looking up the content of a memo field. Foxpro would have to process through every block from the beginning for every reference from the DBF. Yuck!
 
Thanks Mike! I've tried many similar things--including a procedure to copy the records one-by-one to a new table. Your method failed with an error that I've run into before: "There is not enough disk space for c:\users\...9lpg001m.tmp."

Although the file is large, there should be plenty of disk space to process it. Also, while this might take care of my corruption problem, it doesn't answer my question. (Clearly, my heals are dug in. :))
 
"this effort is in part a quest to better understand the internals of the database structure myself."[/I]

That's an admirable goal, but if you have a corrupted table that is preventing an application from working (what most of us encounter from time to time), I'd think that the first goal would be to get it fixed.

You can always make a copy of the bad files and work with those copies towards better understanding when everything else is working.

Regardless, you have a good goal and we hope that you share your new levels of understanding with the community.

Good Luck,
JRB-Bldr
 
Hey Griff!

Love the signature. Quite appropriate for this thread. :)

Yes, I have a series of these tricks that I have used over the years as well. I get a similar behavior to Mike's suggestion. I wonder if I'm bumping up against that 2gb limit? There is more than enough room on the hard drive to handle a complete copy of the FPT file.
 
JRB-Bldr, normally that would be true. In this case, the data is my own and the (web) application is not dead. I simply can't use the data for a marketing effort because of the memo file problem.

Mike, the fatal error is the typical C0000005 error. Here's the entry from VFP7Error.log:

Fatal error: Exception code=C0000005 @ 3/7/2011 4:19:43 PM. Error log file: C:\Program Files\Microsoft Visual FoxPro 7\vfp7err.log

I get a similar error in my program to copy the records individually. The error occurs when I attemtp a SCATTER NAME ... MEMO command. I bet I have a whopper of a memo in this file somewhere.
 
Listen, you guys have helped me out before with some tough questions. (Thank you for being there.) We've all been doing VFP for years. So, none of us know the specific answer. Can I continue to pick your brains to try to develop an answer?

Here's what I know:

Several of the memo field entries are consecutive.

If the memo field is empty, the entry in the DBF is empty (all zeros).

Because of the nature of the web application, most of these memo fields are empty. The two primary memo fields that are collected are the street address (PO_ADDR) and the email (EMAIL) fields.

Here is another sample from the DBF procedure log with the blank memo fields removed:

Code:
Record#:    8	PO_ADDR: 00 00 10 5A 	EMAIL: 00 00 14 F9 	
Record#:    9	PO_ADDR: 00 00 10 5B 	EMAIL: 00 00 14 FA 	
Record#:   10	PO_ADDR: 00 00 10 5C 	EMAIL: 00 00 14 FB 	
Record#:   11	PO_ADDR: 00 00 10 5D 	EMAIL: 00 00 14 FC 	
Record#:   12	PO_ADDR: 00 00 10 5E 	EMAIL: 00 00 00 00 	
Record#:   13	PO_ADDR: 00 00 10 5F 	EMAIL: 00 00 14 FD 	
Record#:   14	PO_ADDR: 00 00 10 60 	EMAIL: 00 00 00 00 	
Record#:   15	PO_ADDR: 00 00 10 61 	EMAIL: 00 00 14 FE 	
Record#:   16	PO_ADDR: 00 00 10 62 	EMAIL: 00 00 14 FF 	
Record#:   17	PO_ADDR: 00 00 10 63 	EMAIL: 00 00 15 00 	
Record#:   18	PO_ADDR: 00 00 10 64 	EMAIL: 00 00 00 00 	
Record#:   19	PO_ADDR: 00 00 10 65 	EMAIL: 00 00 15 01 	
Record#:   20	PO_ADDR: 00 00 10 66 	EMAIL: 00 00 15 02

If I look at record number 8, the content for PO_ADDR is: 105A. But, the PO_Address for record 9 has a value of 105B. So, this can't be an offset. These two memos would have to be only 1 byte apart. As you can see, the values in consecutive records are too nicely lined up to be coincidence.

This particular table has all memo fields. There are no General fields or Blobs.

There is no block identifier in the memo blocks.

The first block (64 bytes) of a memo contains:
bytes 0-3, the block type. In this case always 00000001
bytes 4-7, the length of the memo.
bytes 8-63, the memo content.

If the memo is more longer than 56 bytes, subsequent 64-byte blocks contain the remaining memo content.

Hmmm... I wonder if the number could be the block number. In other words, the actual offset would be 105A * 64.
 
>Hmmm... I wonder if the number could be the block number. In other words, the actual offset would be 105A * 64.

That would also be my guess. 0x105A*0x40. You might need to add an offset to that, eg the 0x200 (512) Bytes for the fpt file header.

Experiment with a new table, that should be easier to analize, SET BLOCKSIZE 0, create that table and then compare the adresses found in the DBF with the adresses of the fpt file. Then try with other Blocksizes...

Bye, Olaf.
 
Aha!

0x105A * 0x40 yields an offset of 0x41680. That is the beginning of a memo block with the content of the PO_ADDR field in record number 8!

0x105B * 0x40 yields an offset of 0x416C0. And that is the beginning of a memo block with the content of the PO_ADDR for record 9!

A very interesting observation about the corruption: The contents of these two fields turns out to be what should have been the content of several of the memo fields for a single record (record #2). That particular record seems to be completely intact. However, the contents of the memo fields seems to be repeated throughout the FPT file, and the pointers to those memos have been saved to other records in the DBF.
 
Thanks Olaf. I got the answer just as you were posting. Thanks to all for letting me brainstorm so publicly.

For the sake of others who may want to go down this path, here is my program for dumping the contents of the FPT file. You can see that I have incorporated a conversion function I found in this forum:

Code:
*	READ_MEMO.PRG - This procedure attempts to read the segments of a VFP7 Memo file.  It assumes 
*			the structure published in the following MSDN Article:

*		[URL unfurl="true"]http://msdn.microsoft.com/en-us/library/8599s21w(v=VS.71).aspx[/URL]

CLEAR 

* Locate the memo file.
cFilePath = GETFILE("FPT", "Memo File:", "Open", 0)
IF EMPTY(cFilePath)
	WAIT "No Memo file was selected." WINDOW NOWAIT
	RETURN
ENDIF

* Create a log file.
cLogPath = JUSTSTEM(cFilePath) + [_FPT.LOG]
SET TEXTMERGE TO (cLogPath)
SET TEXTMERGE ON 

* Open the file.
\Opening memo file: <<cFilePath>>.
nHandle = FOPEN(cFilePath)
IF nHandle < 0
	\Can't open Memo file.
	SET TEXTMERGE OFF
	SET TEXTMERGE TO 
	RETURN
ENDIF
\File Handle:  <<nHandle>>

* Check the file size.
nSize = FSEEK(nHandle, 0, 2)
\Memo File Size:  <<ALLTRIM(STR(nSize))>>  <<TRANSFORM(nSize, "@0")>>
IF nSize <= 0
	\"Memo file is empty."
	=FCLOSE(nHandle)
	SET TEXTMERGE OFF
	SET TEXTMERGE TO 
	RETURN
ENDIF
=FSEEK(nHandle, 0, 0)

* Read the header.
\
\
\***** Header Details *********
\Byte offset 0 - 3: Location of the next free block:  

cStr = FREAD(nHandle, 4)
cHex = Str2Hex(cStr)
\\<<cHex>>

* Get by Unused bytes.
cStr = FREAD(nHandle, 2)
\Byte offset 4 - 5: Unused

\Byte offset 6 - 7:  Block Size (bytes per block):  
cStr = FREAD(nHandle, 2)
cHex = [0x] + STRTRAN(Str2Hex(cStr), " ")
nBlockSize = EVALUATE(cHex)
\\<<nBlockSize>>,  <<cHex>>

* Get by Unused bytes.
cStr = FREAD(nHandle, 504)
\Byte offset 8 - 511: Unused


\
\
\***** Memo Block Data ********

* Read each block.
lEOF = .F.
*DO WHILE NOT lEOF
FOR i = 1 TO 1050
	lEOF = ReadBlock(nSize, 64)	&& Submit the file size and block size.
	IF lEOF
		EXIT
	ENDIF
ENDFOR 
*ENDDO

* Close and exit.
SET TEXTMERGE OFF
SET TEXTMERGE TO 
=FCLOSE(nHandle)
MODIFY FILE (cLogPath) NOWAIT


FUNCTION ReadBlock
PARAMETERS nFileSize, nBlockSize
LOCAL nOffset, cStr, cHex, nBlockType, nLen

	nOffset = FSEEK(nHandle, 0, 1)
	\Address: <<nOffset>>, <<TRANSFORM(nOffset, "@0")>>	
	 
	* Read the first block.
	cStr = FREAD(nHandle, nBlockSize)

	* Obtain the block type.
	\\Block Type: 
	cHex = SUBSTR(cStr, 1, 4)
	cHex = [0x] + STRTRAN(Str2Hex(cHex), " ")
	nBlockType = EVALUATE(cHex)
	\\<<nBlockType>>,  <<cHex>>	

	* Check for problems.
	IF nBlockType > 1
		\Bad Block Signature!
		RETURN .T.
	ENDIF

	* Obtain the memo length.

	\\Memo Length: 
	cHex = SUBSTR(cStr, 5, 4)
	cHex = [0x] + STRTRAN(Str2Hex(cHex), " ")
	nLen = EVALUATE(cHex)
	\\<<STR(nLen, 4)>>,  <<cHex>>	

	* Check for problems.
	IF nLen > nFileSize
		\Bad Block Length!
		RETURN .T.
	ENDIF

	* Capture the memo content.
	cMemo = SUBSTR(cStr, 9)
	\\	Content: 
	IF nBlockType = 1
		\\<<cMemo>>
	ELSE
		\\<<Str2Hex(cMemo)>>
	ENDIF

	* How many blocks to hold the memo?
	nBlocks = CEILING(nLen/64)
	FOR i = 2 TO nBlocks
	
		cStr = FREAD(nHandle, nBlockSize)
		\ <<REPLICATE(CHR(9), 23)>> 
		\\<<cStr>>

	ENDFOR 

	nOffset = FSEEK(nHandle, 0, 1)
	IF nOffset < nFileSize
		RETURN .F.
	ELSE 
		RETURN .T.
	ENDIF 
ENDFUNC 


*..............................................................................
*   Function: DEC2BASX
*    Purpose:  Convert whole number 0-?, to base 2-16 
*
* Parameters: nTempNum - number to convert (0-9007199254740992)
*             base    - base to convert to i.e., 2 4 8 16...
*    returns: string
*      Usage:  cresult=Dec2BasX(nParm1, nParm2)
*              STORE Dec2BasX(255, 16) TO cMyString  &&... cMyString contains 'ff'
*
* Taken from: [URL unfurl="true"]http://www.tek-tips.com/faqs.cfm?fid=4461[/URL]
*..............................................................................
FUNCTION dec2basx
PARAMETERS nTempNum, nNewBase

STORE 0 TO nWorkVal,;
   remainder,;
   dividend,;
   nextnum,;
   digit

nWorkVal = nTempNum  
ret_str = ''

DO WHILE .T.
   digit = MOD(nWorkVal, nNewBase)
   dividend = nWorkVal / nNewBase
   nWorkVal = INT(dividend)

   DO CASE
      CASE digit = 10
         ret_str = 'a' + ret_str
      CASE digit = 11
         ret_str = 'b' + ret_str
      CASE digit = 12
         ret_str = 'c' + ret_str
      CASE digit = 13
         ret_str = 'd' + ret_str
      CASE digit = 14
         ret_str = 'e' + ret_str
      CASE digit = 15
         ret_str = 'f' + ret_str
      OTHERWISE
         ret_str = LTRIM(STR(digit)) + ret_str
   ENDCASE

   IF nWorkVal = 0
      EXIT
   ENDIF ( nWorkVal = 0 )
ENDDO ( .T. )
RETURN ret_str
*: eof dec2basx


FUNCTION Str2Hex
PARAMETERS cStr
LOCAL i, nLen, cByte, cHex

*	Converts the contents of the submitted string to Hexidecimal format.

	nLen = LEN(cStr)
	cHex = ""
	FOR i = 1 TO nLen
		cByte = SUBSTR(cStr, i, 1)
		cHex = cHex + UPPER(Dec2BasX(ASC(cByte), 16)) + " "
	ENDFOR 
	RETURN cHex
ENDFUNC


And here is my procedure for dumping the content of the DBF. This procedure is specific to my particular table structure, so it is not likely to work for another table. But, it may still provide you with a clue about how to approach this yourself:

Code:
*	This procedure prints out the memo field locations in the Contact Table.

CLEAR 
CLOSE TABLES

* Locate the DBF file.
cFilePath = GETFILE("DBF", "Table File:", "Open", 0)
IF EMPTY(cFilePath)
	WAIT "No file was selected." WINDOW NOWAIT
	RETURN
ENDIF

* Create a log file.
cLogPath = JUSTSTEM(cFilePath) + [_DBF.LOG]
SET TEXTMERGE TO (cLogPath)
SET TEXTMERGE ON 

* Open the file.
\Opening Table file: <<cFilePath>>.
nHandle = FOPEN(cFilePath)
IF nHandle < 0
	\Can't open table file.
	SET TEXTMERGE OFF
	SET TEXTMERGE TO 
	RETURN
ENDIF
\File Handle:  <<nHandle>>

* Check the file size.
nSize = FSEEK(nHandle, 0, 2)
\File Size:  <<ALLTRIM(STR(nSize))>>  <<TRANSFORM(nSize, "@0")>>
IF nSize <= 0
	\"File is empty."
	=FCLOSE(nHandle)
	SET TEXTMERGE OFF
	SET TEXTMERGE TO 
	RETURN
ENDIF
=FSEEK(nHandle, 0, 0)

* Obtain the record size
nRecLen = 0x0199

* The position of the first record.
nFirstRec = 0x0648
cStr = FREAD(nHandle, nFirstRec)

* Read each record.
lEOF = .F.
i = 1
DO WHILE !lEOF

	* Read the reoord.
	cStr = FREAD(nHandle, nRecLen)

	\Record#: <<STR(i, 4)>>	

	* Pull the memo field locations from the record.
	nOffset = 0x0090 + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\PO_ADDR: <<nLocation>>	
	
	nOffset = 0x0094 + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\COUR_ADDR: <<nLocation>>	
	
	nOffset = 0x0108 + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\EMAIL: <<nLocation>>	

	nOffset = 0x010C + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\WEB_URL: <<nLocation>>	

	nOffset = 0x0110 + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\WEBSERVICE: <<nLocation>>	

	nOffset = 0x0166 + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\BIOGRAPHY: <<nLocation>>	

	nOffset = 0x016A + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\PORTRAIT: <<nLocation>>	

	nOffset = 0x016E + 1
	nLocation = str2hex(SUBSTR(cStr, nOffset, 4))
	\\COMMENT: <<nLocation>>	

	i = i + 1
	nOffset = FSEEK(nHandle, 0, 1)
	lEOF = (nOffset >= nSize)
ENDDO

* Close and exit.
SET TEXTMERGE OFF
SET TEXTMERGE TO 
=FCLOSE(nHandle)
MODIFY FILE (cLogPath) NOWAIT



*..............................................................................
*   Function: DEC2BASX
*    Purpose:  Convert whole number 0-?, to base 2-16 
*
* Parameters: nTempNum - number to convert (0-9007199254740992)
*             base    - base to convert to i.e., 2 4 8 16...
*    returns: string
*      Usage:  cresult=Dec2BasX(nParm1, nParm2)
*              STORE Dec2BasX(255, 16) TO cMyString  &&... cMyString contains 'ff'
*
* Taken from: [URL unfurl="true"]http://www.tek-tips.com/faqs.cfm?fid=4461[/URL]
*..............................................................................
FUNCTION dec2basx
PARAMETERS nTempNum, nNewBase

STORE 0 TO nWorkVal,;
   remainder,;
   dividend,;
   nextnum,;
   digit

nWorkVal = nTempNum  
ret_str = ''

DO WHILE .T.
   digit = MOD(nWorkVal, nNewBase)
   dividend = nWorkVal / nNewBase
   nWorkVal = INT(dividend)

   DO CASE
      CASE digit = 10
         ret_str = 'a' + ret_str
      CASE digit = 11
         ret_str = 'b' + ret_str
      CASE digit = 12
         ret_str = 'c' + ret_str
      CASE digit = 13
         ret_str = 'd' + ret_str
      CASE digit = 14
         ret_str = 'e' + ret_str
      CASE digit = 15
         ret_str = 'f' + ret_str
      OTHERWISE
         ret_str = LTRIM(STR(digit)) + ret_str
   ENDCASE

   IF nWorkVal = 0
      EXIT
   ENDIF ( nWorkVal = 0 )
ENDDO ( .T. )
RETURN ret_str
*: eof dec2basx


FUNCTION Str2Hex
PARAMETERS cStr
LOCAL i, nLen, cByte, cHex

*	Converts the contents of the submitted string to Hexidecimal format.

	nLen = LEN(cStr)
	cHex = ""
	FOR i = nLen TO 1 STEP -1		&& Least significant digits are first.
		cByte = SUBSTR(cStr, i, 1)
		cHex = cHex + PADL(UPPER(Dec2BasX(ASC(cByte), 16)), 2, "0") + " "
	ENDFOR 
	RETURN cHex
ENDFUNC
 
Despite the fact that I too have never needed this info either, so that your work doesn't get lost in the multiple pages of this forum, you might want to consider posting your considerable work as a FAQ.

Thanks,
JRB-Bldr
 
O.K. Never done that. How do you do that?

Also, do you think this thread is an appropriate FAQ?
 
"do you think this thread is an appropriate FAQ"

Your info is regarding a VFP data table, so Yes, it would appear to be the appropriate FAQ location.

To enter your FAQ, go onto the FAQ page and, at the bottom of the page, there is a place to make your new entry (just like posting a new question).

Good Luck,
JRB-Bldr
 
How do you do that?

1. Click on the FAQ tab at the top of this page.

2. In the resulting page, scroll down to the bottom, and enter your text in the appropriate box.

3. Be sure to select the most sensible category, and to give the FAQ a meaningful title.

Also, be clear about the subject of this particular FAQ. Do you want to explain to people what the 4-byte memo field contains? Or do you want to present a program for analysing the contents of the FPT file? (The thread contains information about both.)

Personally, I think the first option would be more useful. Either way, it's best for the FAQ to be on one subject only, and for the nature of that subject to be indicated by its title.

Give it a try.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top