I have an MFC application. 2 users (using XP) are reporting that they often
get an "an unnamed file was not found" error of when saving a document.
During a save, it looks like the MFC writes the document to a mirror file
(e.g. MFCxx.tmp) then calls ReplaceFile() (from CMirrorFile::Close()) to
replace the original version of the doc with the mirror file. When the error
occurs, the document is being saved correctly to the original file name but
the mirror file is not removed. That suggests the error is occurring inside
the ReplaceFile() function which seems odd.
My question is: Any idea what this error means and is there anything that my
application could be doing to cause this?
I am thinking that some external program (driver, anti-virus etc) might be
causing it but could it be a bug in the MFC code?
Thanks.
Currently I have not found any known product issue for this. For further
research, could you please share us some of your code snippets here or send
me (changliw_At_microsoft_dot_com) a simple project for demonstrating how
you saved the file? Thanks for your cooperations.
Best regards,
Charles Wang
Microsoft Online Community Support
=====================================================
When responding to posts, please "Reply to Group" via
your newsreader so that others may learn and benefit
from this issue.
======================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
======================================================
Tom
"MikeMio" <Mik...@newsgroups.nospam> wrote in message
news:FF6E1962-D728-402C...@microsoft.com...
Mike
The save is standard MFC. Below is the code (I'll call the class COurDoc)
that calls the MFC CDocument::OnSaveDocument()
The attached CMirrorFile::Close() from MFC is where the problem seem to be
occurring
Mike
------------------------------------------------------
void COurDoc::OnFileSave()
{
BOOL bNotAccessible=FALSE;
if(m_docfile.IsEmpty())
{
// no file currently open
bNotAccessible=TRUE;
}
else //if(!m_docfile.IsEmpty())
{
if(!ReSaveImage())
{
return; //cancelled
}
//look for write access now so we can avoid cryptic message from MFC
DWORD dwAttrs = GetFileAttributes(LPCTSTR(m_docfile));
//if no file or read only save as
if(dwAttrs==0xffffffff ||(dwAttrs & FILE_ATTRIBUTE_READONLY))
{
bNotAccessible=TRUE;
}
else // or, if not writable, save as
{
HANDLE hAppend = CreateFile(m_docfile, GENERIC_WRITE,
FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hAppend)
{
bNotAccessible=TRUE;
}
else
{
CloseHandle(hAppend);
}
}
}
if(bNotAccessible)
{
OnFileSaveAs();
}
else if(OnSaveDocument(LPCTSTR(m_docfile)))
{
// backup saved file
MakeBackupCopy(LPCTSTR(m_docfile));
}
}
BOOL CIMSDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
....
here we adjust some internal items and save a values in the registry with
WriteProfileInt()
...
AfxGetApp()->AddToRecentFileList(lpszPathName );
BOOL res = CDocument::OnSaveDocument(lpszPathName);
return res;
}
void COurDoc::MakeBackupCopy(LPCTSTR pszDocPath)
{
// backup saved file
if(CopyFile(LPCTSTR(m_docfile),LPCTSTR(sSAVPath),false))
{
//make sure the backup file is not read only even if the source file is
DWORD dwAttrs = GetFileAttributes(LPCTSTR(szSAVPath));
if((dwAttrs & FILE_ATTRIBUTE_READONLY))
{
SetFileAttributes(LPCTSTR(szSAVPath),dwAttrs &= ~FILE_ATTRIBUTE_READONLY);
}
}
}
------------------------------------------------------
void CMirrorFile::Close()
{
CString strName = m_strFileName; //file close empties string
CFile::Close();
if (!m_strMirrorName.IsEmpty())
{
BOOL (__stdcall *pfnReplaceFile)(LPCTSTR, LPCTSTR, LPCTSTR, DWORD, LPVOID,
LPVOID);
HMODULE hModule = GetModuleHandle(_T("KERNEL32"));
ASSERT(hModule != NULL);
pfnReplaceFile = (BOOL (__stdcall *)(LPCTSTR, LPCTSTR, LPCTSTR, DWORD,
LPVOID, LPVOID))
#ifndef _UNICODE
GetProcAddress(hModule, "ReplaceFileA");
#else
GetProcAddress(hModule, "ReplaceFileW");
#endif
if(!pfnReplaceFile || !pfnReplaceFile(strName, m_strMirrorName, NULL, 0,
NULL, NULL))
{
CFile::Remove(strName);
CFile::Rename(m_strMirrorName, strName);
}
}
}
------------------------------------------------------
"Charles Wang[MSFT]" wrote:
> I understand that your MFC application ocassionally reported the error "an
> unamed file was not found" when a document was being saved.
> ... could you please share us some of your code snippets here or send
Tom
"MikeMio" <Mik...@newsgroups.nospam> wrote in message
news:CB176439-FAB7-4CA0...@microsoft.com...
I don't think the file is open in exclusive mode because the
CreateFile/GENERIC_WRITE test would fail and send the save to save as. I
tried locking the file explictly after the test but then I get a different
message (sharing violation).
Mike
Your code looks fine. Now I recommend that you use GetLastError() to
retrieve extend error information after you call ReplaceFile.
From your description, it seemed that your ReplaceFile function might
return the error ERROR_UNABLE_TO_REMOVE_REPLACED since you said that the
mirror file was not removed.
You may also use Process Monitor to monitor the process (filter the records
by the process name) to see which file your process was looking for. You
can download Process Monitor from:
Process Monitor v1.25
http://www.microsoft.com/technet/sysinternals/utilities/processmonitor.mspx
Please also mail me the process monitor logs for further research.
If you have any other questions or concerns, please feel free to let me
know. Have a nice day!
I will try the processmonitor to see what can be found. Adding the
GetLastError() may be a little more difficult because the code is in the MFC
dll.
I was thinking about the improbability of ReplaceFile replacing the document
file but not removing the temp when I realized I made a mistake. The code
that these users have is calling the the old MFC dlls not the new ones from
VS2005. I apologize for that error.
So the CMirrorFile::Close() code would be as follows below. That makes a
little more sense now. I seems more possible that the error is occurring at
the final CFile::Remove(strBackupName), although it still doesn't explain why
it would happen. Does that give you any new insights?
I'll let you know what I find out with the processmonitor. It may take some
time. It has to go out to the end users and back.
Thanks for your help.
Mike
==============================
void CMirrorFile::Close()
{
CString m_strName = m_strFileName; //file close empties string
CFile::Close();
if (!m_strMirrorName.IsEmpty())
{
BOOL bWorked = FALSE;
DWORD dwResult = 0;
ReplaceAPIPtr pfn = NULL;
CString strBackupName;
if (!afxData.bWin95)
{
HMODULE hModule = GetModuleHandleA("KERNEL32");
ASSERT(hModule != NULL);
pfn = (ReplaceAPIPtr) GetProcAddress(hModule, "ReplaceFile");
if (pfn != NULL)
{
USES_CONVERSION;
strBackupName = GetTempName(m_strMirrorName, FALSE);
// this NT API handles copying all attributes for us
bWorked = (pfn)(T2W((LPTSTR)(LPCTSTR)m_strName),
T2W((LPTSTR)(LPCTSTR)m_strMirrorName),
T2W((LPTSTR)(LPCTSTR)strBackupName),
REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS,
NULL, NULL);
if (!bWorked)
dwResult = GetLastError();
}
}
if (!bWorked)
{
if (dwResult == ERROR_UNABLE_TO_MOVE_REPLACEMENT || dwResult == 0)
CFile::Remove(m_strName);
if (dwResult == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2)
CFile::Remove(strBackupName);
CFile::Rename(m_strMirrorName, m_strName);
}
else if (pfn != NULL)
{
CFile::Remove(strBackupName);
}
}
}
==============================
Unfortunately the information is not enough just according to the code
snippet, to speed up our research process, could you please mail me
(changliw_at_microsoft_dot_com) a small project so that I can reproduce
your issue and perform debugging?
Appreciate your understanding on this and have a good day!
The program is standard MFC document/view program but I don't think you will
be able to reproduce the problem. I can't reproduce. It is only happening for
a couple of end users out of many.
But...I have just gotten results from someone trying the process monitor
and, guess what, the problem goes away when the process monitor is on.
So it looks like this is a latency problem right in the CMirrorFile::Close()
function. Would you agree?
It there anything that can be done besides rewriting the MFC function?
Cheers,
Mike
If this is a latency problem, you may try using Sleep function after each
file operation to see if it helps.
Please feel free to let me know if you have any other questions or
concerns. It is my pleasure to be of assistance.
If it is the MFC dll that is causing the problem, I wonder if this is a
known problem that was perhaps fixed in a newer release (of the VC6 version
of MFC)? I tried to search for this but could not find anything.
Alternately, do you happen to know of any workaround for the end user?
Perhaps an OS setting to turn off lazy write (or other applicable option) for
the specific file or directory. As I mentioned this error is only reported by
two of many (thousands) but for them it is a big problem.
Thanks again for your help in this.
Mike
Unfortunately I have not found any known issue in MFC regarding this
problem. Since this issue could not be reproduced, to track the root cause
of this issue, dump analysis will be required, however this work can only
be done by Microsoft Customer Support Services (CSS). Effectively and
immediately I recommend that you contact CSS via telephone so that a
dedicated Support Professional can assist you in a more efficient manner.
Please be advised that contacting phone support will be a charged call. If
this issue is proved to be a product issue, the charge will be refunded to
you at last.
To obtain the phone numbers for specific technology request please take a
look at the web site listed below.
http://support.microsoft.com/default.aspx?scid=fh;EN-US;PHONENUMBERS
If you are outside the US please see http://support.microsoft.com for
regional support phone numbers.
If you have any other questions or concerns, please feel free to let me
know. It is my pleasure to be of assistance.
Cheers,
Mike