Microsoft KB Archive/141417

= FIX: Problem Occurs During File Open on Win32s =

Article ID: 141417

Article Last Modified on 10/16/2002

-

APPLIES TO


 * Microsoft Visual C++ 4.0 Standard Edition

-



This article was previously published under Q141417



SYMPTOMS
A problem occurs on Win32s when the user tries to open a file using the standard MFC file opening procedures. This only occurs with an MFC application running under Win32s version 1.3 that uses MFC in a shared DLL (Mfc40.dll for Win32s) and the C runtime libraries in a DLL (Msvcrt40.dll for Win32s). Note that this is the default configuration for a default AppWizard generated application.

Two known symptoms are access violation and EMM386 error #06 (Invalid opcode). Symptoms will vary depending on the condition of the call stack.



CAUSE
AfxResolveShortcut (an internal MFC function) calls SHGetFileInfo, which is not correctly implemented on Win32s. This happens as a result of the ID_FILE_OPEN command. AfxResolveShortcut is called from CDocManager::OpenDocumentFile, which is in turn called from CWinApp::OpenDocumentFile.



RESOLUTION
Derive a class from CDocManager and override the OpenDocumentFile function by copying the existing code and make some small changes. Because this fix is dependent on the internal MFC implementation, make sure you include the #if _MFC_VER == 0x400 statements.

Copy the following code into your application's .cpp file above the implementation of InitInstance. If you're looking at a paper copy of this article, note that you can find most of the code for OpenDocumentFile in Mfc\Src\Docmgr.cpp; rather than retyping the entire text, you could copy most of the code and make the change noted below:
 * 1) if _MFC_VER == 0x400

static inline BOOL IsDirSep(TCHAR ch) {   return (ch == _T('\\') || ch == _T('/')); }

BOOL AFXAPI AfxResolveShortcut(CWnd* pWnd, LPCTSTR pszShortcutFile,                                      LPTSTR pszPath, int cchPath);
 * 1) ifndef _MAC
 * 1) endif


 * 1) define _countof(array) (sizeof(array)/sizeof(array[0]))

BOOL AFXAPI AfxFullPath(LPTSTR lpszPathOut, LPCTSTR lpszFileIn); void AFXAPI AfxGetRoot(LPCTSTR lpszPath, CString& strRoot);

class CMyDocManager : public CDocManager { public: CMyDocManager {}; virtual ~CMyDocManager {}; virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); };

CDocument* CMyDocManager::OpenDocumentFile(LPCTSTR lpszFileName) {   // find the highest confidence POSITION pos = m_templateList.GetHeadPosition; CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt; CDocTemplate* pBestTemplate = NULL; CDocument* pOpenDocument = NULL;

TCHAR szPath[_MAX_PATH]; ASSERT(lstrlen(lpszFileName) < _countof(szPath)); TCHAR szTemp[_MAX_PATH]; if (lpszFileName[0] == '\"')       ++lpszFileName;    lstrcpyn(szTemp, lpszFileName, _MAX_PATH);    LPTSTR lpszLast = _tcsrchr(szTemp, '\"'); if (lpszLast != NULL) *lpszLast = 0; AfxFullPath(szPath, szTemp); TCHAR szLinkName[_MAX_PATH];
 * 1) ifndef _MAC

// CHANGE: check the windows version before calling AfxResolveShortcut if((BYTE)GetVersion >=4 && AfxResolveShortcut(AfxGetMainWnd, szPath, szLinkName,_MAX_PATH)) lstrcpy(szPath, szLinkName); lstrcpyn(szPath, lpszFileName, _MAX_PATH); WIN32_FIND_DATA fileData; HANDLE hFind = FindFirstFile(lpszFileName, &fileData); if (hFind != INVALID_HANDLE_VALUE) VERIFY(FindClose(hFind)); else fileData.dwFileType = 0;   // won't match any type while (pos != NULL) {       CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos); ASSERT_KINDOF(CDocTemplate, pTemplate);
 * 1) else
 * 1) endif

CDocTemplate::Confidence match; ASSERT(pOpenDocument == NULL); match = pTemplate->MatchDocType(szPath, pOpenDocument); match = pTemplate->MatchDocType(szPath,                        fileData.dwFileType, pOpenDocument); if (match > bestMatch) {           bestMatch = match; pBestTemplate = pTemplate; }       if (match == CDocTemplate::yesAlreadyOpen) break;     // stop here }
 * 1) ifndef _MAC
 * 1) else
 * 1) endif

if (pOpenDocument != NULL) {       POSITION pos = pOpenDocument->GetFirstViewPosition; if (pos != NULL) {           CView* pView = pOpenDocument->GetNextView(pos); // get first one ASSERT_VALID(pView); CFrameWnd* pFrame = pView->GetParentFrame; if (pFrame != NULL) pFrame->ActivateFrame; else TRACE0(               "Error: Cannot find frame for document to activate.\n"); CFrameWnd* pAppFrame; if (pFrame !=                   (pAppFrame = (CFrameWnd*)AfxGetApp->m_pMainWnd)) {               ASSERT_KINDOF(CFrameWnd, pAppFrame); pAppFrame->ActivateFrame; }       }        else {           TRACE0(              "Error: Can not find view for document to activate.\n"); }       return pOpenDocument; }

if (pBestTemplate == NULL) {       AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC); return NULL; }

return pBestTemplate->OpenDocumentFile(szPath); }

Now, include the following three lines to the first part of your MyApp::InitInstance function: m_pDocManager = new CMyDocManager;
 * 1) endif //mfc version 4.0 workaround
 * 1) if _MFC_VER == 0x400
 * 1) endif



STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This bug was corrected in Visual C++ 4.1.



Steps to Reproduce Problem
 Open the scribble tutorial sample from:

\Msdev\Samples\Mfc\Tutorial\Scribble\Step6\Scribble.mdb

 Open the Project Settings dialog box. In Settings For, select Win32 Release. From the Project Settings dialog box, click the general tab. From the Microsoft Foundation Classes list box, select Use MFC in a shared DLL (MFC40(d).DLL). Click OK to dismiss the project settings dialog box. Open the default configuration dialog box, and select the Release build. Rebuild the program.</li> Run the program under Win32s.</li> Create, save, and close a scribble document.</li> Try to open the document you just closed. An access violation occurs.</li></ol>

Additional query words: kbVC400bug 4.00 4.10 1.30

Keywords: kbbug kbfix kbnoupdate kbvc410fix kbdocview kbcode KB141417

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.