(Updated: 2008.01.23 12:43:02 PM)
| |
MemoFileMissingOrInvalid - Error 41 - What causes this?
_____________________________________
Found a new article: MSKB #812696 -
PRB: Error 41: "Memo File is Missing or Invalid" Error Message When You Access Tables on Computers That Are Running Windows 98 or Earlier from Computers That Are Running Windows XP http://support.microsoft.com/?id=812696.
_____________________________________
search keys: memo problems, bad memo, missing or invalid
Tip: If you can open the table exclusively do this and modify the structure. Change the name of the field containing the memo and exit. Sometimes it works. Then just change the name back again. kipdole
The latest incarnation of this problem is visible when I run:
select clm_id, notes from mc_mdclm where at(chr(0), notes) > 0 into cursor csrNull nofilter
Then when you look at the 600+ records in the cursor you see stuff like:
(good memo text)
(null chars)
(good memo text)
(null chars)
(good memo text)
(null chars)
(pattern repeats)
My guess is the pointer from the dbf to the fpt is off and once that is off the length bytes in the memo block are off so that memos span original block boundaries.
My hex editor (list.exe) doesn't accomodate large files so I need a better hex editor.
Go get Ultra Edit
from Ultra Edit
.com, it's well worth the $40!
I want a memo editor that will go into the dbf and show me the pointer to the fpt and the corresponding memo and let me change the pointer and view the results. Something that will help me get this stuff back in sync. Anyone know of one?
Xitech FoxFix (5.2 is the latest version) is a kind of such tool. --
Igor Korolyov
_____________________________________
It all happened again, but this time we got the table, memo file and cdx and it was a small memo file so we could deal with it easily. We discovered that the memo file was corrupt at the end. After the last visually good block we could see a block or two of nulls and then a block or two of garbage.
|-> block signature
000740 00 00 00 01 00 00 00 32 43 6F 76 65 72 74 65 64 good block
000750 20 66 72 6F 6D 20 48 61 72 72 69 73 20 49 6E 64
000760 69 76 69 64 75 61 6C 20 46 61 6D 69 6C 79 20 70
000770 6C 61 6E 2E 20 76 6C 79 6E 6E 00 00 00 00 00 00
000780 00 00 00 01 00 00 00 30 31 30 31 31 30 30 3A 20 good block
000790 6F 6E 20 41 75 67 20 32 30 30 30 20 63 75 72 72
0007A0 65 6E 74 20 62 65 6E 65 66 69 74 73 20 66 69 6C
0007B0 65 2E 20 76 6C 79 6E 6E 00 00 00 00 00 00 00 00
0007C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 null block
0007D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0007E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0007F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000800 C8 8D 07 64 C9 8D 07 64 CA 8D 07 64 CB 8D 07 64 garbage block
000810 CC 8D 07 64 CD 8D 07 64 CE 8D 07 64 00 00 00 00
000820 00 00 00 00 00 00 00 00 00 00 00 80 02 00 76 00
000830 00 7C 5C 01 00 80 5C 01 0F 00 FF FF FF 03 07 07
end of file
The memo file was even too short! Based on the location of the next free block in the header there should have been more data. In the end the thing that worked the best was to run a replace statement for len(memo) = 0.
replace our_memo with NULL for len(our_memo) = 0
This took care of all the empty blocks. Then we did a select for memos with a null char in them. (do this first) We did a visual inspection of the memos for these records and deleted the bad data out of them. In our case all the data was bad. When we packed the table the last thing in the memo file was a known good block and the memo header record was perfect. Looking for nulls chars is a pretty good method because the null char is the filler used by Fox. While this may not always work I think you've got a pretty good chance with it. You could also look for unusually long memos.
Along the way we tried:
1. Changing the location of the next free block in the memo header record to the block after the last visually good block. This was a bad idea because there was still a pointer in the dbf to the bad areas of the memo file. When we packed the table the location of the next free block changed right back to where it was when we started.
2. We also tried filling in the bad areas with empty blocks which is all nulls except for a block signature (see "Memo File Structure" in help). We didn't like that solution because then you've got unused blocks lying around and empty memos that should be nulled out.
The method we used described above was great because it sucked up the end of the file to the last good block and adjusted the location of the next free block to what we tried to do manually.
Joe Kuhn
It turns out someone did a DOS copy of the data on the WAN while users were using the system. I'm not sure who got what files first, but this is our prime suspect.
See code at bottom to fix. Joe Kuhn

I have this error show up in the VFE errorlog from time to time at 2 of my clients. It's always during login/logout of the app and occurs on one of the app/metadata tables (dbcxreg, I believe) However, it is not readily re-produceable. Is the memo really invalid or can this be caused by network flakiness too? Is VFP self healing on minor memo corruption? Again, I never do any DB maintenance to correct it, it just goes away. I think it is some kind of contention or related to network/server load (ie. everyone is logging in/out at the same time) --
Randy Jean
As soon as the DOS copy was finished (see above) the error went away. Sounds like contention to me. And what if somebody tries to save a change while there is contention? Permanant corruption I bet. Joe Kuhn

Although there can be a number of reasons for the error, the most common problem is the block size in the FPT header being set to 0. If you know the block size (the default is 64), you can write the correct block size value to the FPT file using low-level file routines.
Stonefield Database Toolkit will do this for you automatically when you use its Repair method, but you can also write a program to do it yourself. Of course, be sure to back up the FPT file first! --
Doug Hennig
If the memo field is
Read-Only while the table is read-write, you'll get this error, too. --
Ted Roche
If the memo file is actually missing, you can recover the table (not the missing data), by creating a table of identical structure in a temporary directory, and copying the FPT file to the directory with the memo-less table. Make backups before altering any of the tables, of course. --
Ted Roche
We recovered by writing the data to a cursor, zapping the table and writing the data back to the table from the cursor. This works well except that you stand to lose memo data which should never happen! Here we come Sql Server! (We discovered later this isn't such a good idea because it leaves plenty of garbage in your memos)
An aside: You have to be careful to include NULL in your create cursor statement for fields that accept nulls.
I found CDXCorruption Checklist which is very helpful as a list of possibilities. 583 Meg of free disk space may have been the culprit, but we also suspect sudden disconnects (gpf, terminal server unhook without app logout, user shutting machine off...) -- Joe Kuhn
local lcFileToFix, lnHdlIn
* Complete details are in the VFP help file (look for "memo file structure" on the index page).
lcFileToFix = getfile("FPT", "Memo File")
if len(lcFileToFix) = 0
return
endif
* Next line doesn't work when somebody else has the
* table open (shared) regardless of the value in the second parm.
lnHdlIn = fopen(lcFileToFix, 2)
if lnHdlIn < 0
MessageBox("Cannot open '" + lcFileToFix + "'", 0, "Cannot fix")
return
endif
* get the file's current block size from offset 06-07
lnResult = fseek(lnHdlIn, 6)
lcBlockSize = fread(lnHdlIn, 2)
lnBlockSize = (asc(substr(lcBlockSize, 1, 1)) * 256) + asc(substr(lcBlockSize, 2, 1))
* we never use anything other than the default of 64 for BLOCKSIZE
lcNewBlockSize = chr(0) + chr(64)
?"current block size: "+transform(lnBlockSize)
if lcBlockSize <> lcNewBlockSize
* write new blocksize at 06-07
lnResult = fseek(lnHdlIn, 6)
fwrite(lnHdlIn, lcNewBlockSize, 2)
?"new block size written: 64"
else
?"block size ok"
endif
fclose(lnHdlIn)
?"finished fixing memo file header for '"+lcFileToFix+"'"
messagebox("finished fixing memo file header for '"+lcFileToFix+"'")

A user shutting off or rebooting their workstation while having a table with a memo file open, is the traditional cause of this problem. I don't know if VFP7 is any more immune to this problem than earlier versions, but I have heard nothing to indicate that this problem has gone away. One of our team members here has worked on a project that used .dbc files. He said that the memo file associated with the .dbc where the stored procedures and triggers are kept was also vulnerable to this problem. Frequent trashing of the .dbc memo file caused by a user shutting off or rebooting.
Ray Kirk

We are having memo corruptions about once a month and I wondered how does Fox determine when or where the next memo block is written for a record being INSERT'ed. I think this is where our issue stems from. Is it possible for 2 users to "step on each others toes" when a new memo is added? The table in question contains large blobs of text, pdf's, etc and I wonder if the next user adding a record doesn't have the current memo pointer info? (I hope that makes sense).
Reading this comment in a KB article (KB 264867) got me thinking :
"File locking issues: If one user performs an action that results in a table's memo file being locked, and a second user attempts to open the same table and access the memo field information, the second user may open the memo file with an incorrect blocksize, resulting in memo file corruption. See the "References" section in this article for details."
I have got "Fatal error" when I tried to copy or append from a DBF file. When I tried PACK I have got "Invalid or missing memo file" message. I tried some methods mentioned here but had no success. I have managed to fix the file with the following trick:
set safe off
use badfile
copy structure to goodfile
use goodfile in 0
scan
copy to x record recno()
sele goodfile
append from x
sele badfile
endscan
set safe on
After it some memo fields contained garbage, I had to correct them manually.
Imre
Category Code Samples Category VFP Troubleshooting