2

嗨,我已将 VC++6 项目转换为 VC++ 2010,并且在显示模式打开文件对话框时一直遇到错误。

它显示对话框的底部但顶部丢失,过滤器也未填充。

标头具有用于存储文件信息的公共成员:

CString m_strFilePathName;
CString m_strFileExtName;

我显示对话框的代码:

    static TCHAR BASED_CODE szFilter[] = _T("Open Bin File(*.abs)|")
       _T("Default DataBase File(*.ddf)|")
       _T("SatCodex File(*.sdx)|")
       _T("Format Text File(*.txt)");

// TODO: Add your command handler code here
CFileDlg fd(TRUE, NULL, "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
    //"Open Bin File(*.abs)|Default DataBase File(*.ddf)|SatCodex File(*.sdx)|Format Text File(*.txt)");

const int c_cMaxFiles = 1;
const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
fd.GetOFN().lpstrFile = m_strFilePathName.GetBuffer(c_cbBuffSize);
fd.GetOFN().nMaxFile = c_cbBuffSize;

    // Dialog hangs on this line:
if(fd.DoModal() != IDOK) return;

诊断返回:AliEditor.exe 中 0x006c69cc 的第一次机会异常:0xC0000005:访问冲突读取位置 0x00000020。

在挂起模式调用堆栈中中断会返回以下信息:

user32.dll!_NtUserWaitMessage@0()  + 0x15 bytes <-STOPPED HERE
user32.dll!_NtUserWaitMessage@0()  + 0x15 bytes 
user32.dll!_DialogBox2@16()  + 0x109 bytes  
user32.dll!_InternalDialogBox@24()  + 0xc9 bytes    
user32.dll!_DialogBoxIndirectParamAorW@24()  + 0x36 bytes   
user32.dll!_DialogBoxIndirectParamW@20()  + 0x1b bytes  
comdlg32.dll!CFileOpenSave::Show()  + 0x146 bytes   

AliEditor.exe!CFileDialog::DoModal() 第 748 行 + 0x26 字节 C++ AliEditor.exe!CMainFrame::OnFileOpen() 第 195 行 + 0xb 字节 C++ AliEditor.exe!_AfxDispatchCmdMsg(CCmdTarget * pTarget, unsigned int nID, int nCode, void (void)* pfn, void * pExtra, unsigned int nSig, AFX_CMDHANDLERINFO * pHandlerInfo) 第 82 行 C++ AliEditor.exe!CCmdTarget::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) 第 381 行 + 0x27 字节C++ AliEditor.exe!CFrameWnd::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) 第 973 行 + 0x18 字节 C++ AliEditor.exe!CWnd::OnCommand(unsigned int wParam, long lParam) 第 2729 行 C++ AliEditor.exe!CFrameWnd::OnCommand(unsigned int wParam, long lParam) 第 371 行 C++ AliEditor.exe!CWnd::OnWndMsg(unsigned int message,unsigned int wParam, long lParam, long * pResult) Line 2101 + 0x1e bytes C++ AliEditor.exe!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam) Line 2087 + 0x20 bytes C++ AliEditor.exe!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) 第 257 行 + 0x1c 字节 C++ AliEditor.exe!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) 第 420 行 C++unsigned int nMsg, unsigned int wParam, long lParam) 第 420 行 C++unsigned int nMsg, unsigned int wParam, long lParam) 第 420 行 C++

我猜的声明(我不是 C++ 开发人员)覆盖(fileDlg.cpp):

#include "stdafx.h"
#include "AliEditor.h"
#include "FileDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFileDlg

IMPLEMENT_DYNAMIC(CFileDlg, CFileDialog)

CFileDlg::CFileDlg(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
        CFileExportDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
}


BEGIN_MESSAGE_MAP(CFileDlg, CFileExportDialog)
    //{{AFX_MSG_MAP(CFileDlg)
    ON_WM_CLOSE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

文件“dlgfile.cpp”非常大,但这只是顶部:

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include <dlgs.h>       // for standard control IDs for commdlg
#include "afxglobals.h"

#define new DEBUG_NEW

////////////////////////////////////////////////////////////////////////////
// FileOpen/FileSaveAs common dialog helper

CFileDialog::CFileDialog(BOOL bOpenFileDialog,
    LPCTSTR lpszDefExt, LPCTSTR lpszFileName, DWORD dwFlags,
    LPCTSTR lpszFilter, CWnd* pParentWnd, DWORD dwSize, BOOL bVistaStyle)
    : CCommonDialog(pParentWnd)
{
    OSVERSIONINFO vi;
    ZeroMemory(&vi, sizeof(OSVERSIONINFO));
    vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    ::GetVersionEx(&vi);

    // if running under Vista
    if (vi.dwMajorVersion >= 6)
    {
        m_bVistaStyle = bVistaStyle;
    }
    else
    {
        m_bVistaStyle = FALSE;
    }

    m_bPickFoldersMode = FALSE;

    // determine size of OPENFILENAME struct if dwSize is zero
    if (dwSize == 0)
    {
        dwSize = sizeof(OPENFILENAME);
    }

    // size of OPENFILENAME must be at least version 5
    ASSERT(dwSize >= sizeof(OPENFILENAME));
    // allocate memory for OPENFILENAME struct based on size passed in
    m_pOFN = static_cast<LPOPENFILENAME>(malloc(dwSize));
    ASSERT(m_pOFN != NULL);
    if (m_pOFN == NULL)
        AfxThrowMemoryException();

    memset(&m_ofn, 0, dwSize); // initialize structure to 0/NULL
    m_szFileName[0] = '\0';
    m_szFileTitle[0] = '\0';
    m_pofnTemp = NULL;

    m_bOpenFileDialog = bOpenFileDialog;
    m_nIDHelp = bOpenFileDialog ? AFX_IDD_FILEOPEN : AFX_IDD_FILESAVE;

    m_ofn.lStructSize = dwSize;
    m_ofn.lpstrFile = m_szFileName;
    m_ofn.nMaxFile = _countof(m_szFileName);
    m_ofn.lpstrDefExt = lpszDefExt;
    m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
    m_ofn.nMaxFileTitle = _countof(m_szFileTitle);
    m_ofn.Flags |= dwFlags | OFN_ENABLEHOOK | OFN_EXPLORER;
    if(dwFlags & OFN_ENABLETEMPLATE)
        m_ofn.Flags &= ~OFN_ENABLESIZING;
    m_ofn.hInstance = AfxGetResourceHandle();
    m_ofn.lpfnHook = (COMMDLGPROC)_AfxCommDlgProc;

    // setup initial file name
    if (lpszFileName != NULL)
        Checked::tcsncpy_s(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);

    // Translate filter into commdlg format (lots of \0)
    if (lpszFilter != NULL)
    {
        m_strFilter = lpszFilter;
        LPTSTR pch = m_strFilter.GetBuffer(0); // modify the buffer in place
        // MFC delimits with '|' not '\0'
        while ((pch = _tcschr(pch, '|')) != NULL)
            *pch++ = '\0';
        m_ofn.lpstrFilter = m_strFilter;
        // do not call ReleaseBuffer() since the string contains '\0' characters
    }

    if (m_bVistaStyle == TRUE)
    {
        if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
        { // multi-threaded is not supported
            IFileDialog* pIFileDialog;
            IFileDialogCustomize* pIFileDialogCustomize;

            HRESULT hr;

            USE_INTERFACE_PART_STD(FileDialogEvents);
            USE_INTERFACE_PART_STD(FileDialogControlEvents);

            if (m_bOpenFileDialog)
            {
                hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
                                      IID_PPV_ARGS(&pIFileDialog));
            }
            else
            {
                hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, 
                                      IID_PPV_ARGS(&pIFileDialog));
            }
            if (FAILED(hr))
            {
                m_bVistaStyle = FALSE;
                return;
            }

            hr = pIFileDialog->QueryInterface(IID_PPV_ARGS(&pIFileDialogCustomize));
            ENSURE(SUCCEEDED(hr));

            hr = pIFileDialog->Advise(reinterpret_cast<IFileDialogEvents*>(&m_xFileDialogEvents), &m_dwCookie);
            ENSURE(SUCCEEDED(hr));

            m_pIFileDialog = static_cast<void*>(pIFileDialog);
            m_pIFileDialogCustomize = static_cast<void*>(pIFileDialogCustomize);
        }
        else
        {
            m_bVistaStyle = FALSE;
        }
    }
}

CFileDialog::~CFileDialog()
{
    free(m_pOFN);

    if (m_bVistaStyle == TRUE)
    {
        HRESULT hr;
        hr = (static_cast<IFileDialog*>(m_pIFileDialog))->Unadvise(m_dwCookie);
        ENSURE(SUCCEEDED(hr));

        (static_cast<IFileDialogCustomize*>(m_pIFileDialogCustomize))->Release();
        (static_cast<IFileDialog*>(m_pIFileDialog))->Release();

        CoUninitialize();
    }
}

const OPENFILENAME& CFileDialog::GetOFN() const
{
    return *m_pOFN;
}

OPENFILENAME& CFileDialog::GetOFN()
{
    return *m_pOFN;
}

一步一步地,我在同一个(“dlgfile.cpp”)文件中到达这一点:

INT_PTR CFileDialog::DoModal()
{
    ASSERT_VALID(this);
    ASSERT(m_ofn.Flags & OFN_ENABLEHOOK);
    ASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook

    // zero out the file buffer for consistent parsing later
    ASSERT(AfxIsValidAddress(m_ofn.lpstrFile, m_ofn.nMaxFile));
    DWORD nOffset = lstrlen(m_ofn.lpstrFile)+1;
    ASSERT(nOffset <= m_ofn.nMaxFile);
    memset(m_ofn.lpstrFile+nOffset, 0, (m_ofn.nMaxFile-nOffset)*sizeof(TCHAR));

    //  This is a special case for the file open/save dialog,
    //  which sometimes pumps while it is coming up but before it has
    //  disabled the main window.
    HWND hWndFocus = ::GetFocus();
    BOOL bEnableParent = FALSE;
    m_ofn.hwndOwner = PreModal();
    AfxUnhookWindowCreate();
    if (m_ofn.hwndOwner != NULL && ::IsWindowEnabled(m_ofn.hwndOwner))
    {
        bEnableParent = TRUE;
        ::EnableWindow(m_ofn.hwndOwner, FALSE);
    }

    _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
    ASSERT(pThreadState->m_pAlternateWndInit == NULL);

    if (m_bVistaStyle == TRUE)
    {
        AfxHookWindowCreate(this);
    }
    else if (m_ofn.Flags & OFN_EXPLORER)
        pThreadState->m_pAlternateWndInit = this;
    else
        AfxHookWindowCreate(this);

    INT_PTR nResult = 0;

    if (m_bVistaStyle == TRUE)
    {
        ApplyOFNToShellDialog();


// HERE CALLS **OPENFILENAME& CFileDialog::GetOFN()** method and then hangs
            HRESULT hr = (static_cast<IFileDialog*>(m_pIFileDialog))->Show(m_ofn.hwndOwner);



        nResult = (hr == S_OK) ? IDOK : IDCANCEL;
    }
    else if (m_bOpenFileDialog)
        nResult = ::AfxCtxGetOpenFileName(&m_ofn);
    else
        nResult = ::AfxCtxGetSaveFileName(&m_ofn);

    if (nResult)
        ASSERT(pThreadState->m_pAlternateWndInit == NULL);
    pThreadState->m_pAlternateWndInit = NULL;

    // Second part of special case for file open/save dialog.
    if (bEnableParent)
        ::EnableWindow(m_ofn.hwndOwner, TRUE);
    if (::IsWindow(hWndFocus))
        ::SetFocus(hWndFocus);

    PostModal();
    return nResult ? nResult : IDCANCEL;
}

有人可以帮我吗?

[更新] 由于现阶段没有人可以帮助我,我已将项目上传到这里的公共场所。任何人都可以下载并告诉我单击打开文件时出了什么问题?

4

1 回答 1

5

我能看到的唯一问题是您的过滤器字符串看起来不正确。看起来您的代码基于 MSDN 示例之一。根据该示例,您的 szFilter 应如下所示:

static TCHAR BASED_CODE szFilter[] = _T("Open Bin File(*.abs)|*.abs|")
   _T("Default DataBase File(*.ddf)|*.ddf|")
   _T("SatCodex File(*.sdx)|*.sdx|")
   _T("Format Text File(*.txt)|*.txt||");

仅供参考,我使用http://msdn.microsoft.com/en-US/library/wh5hz49d(v=vs.100).aspx作为参考。

[更新]

我创建了一个小型 MFC 应用程序并粘贴到您的代码中。您的代码示例中有错字。该类是 CFileDialog,而不是 CFileDlg。我修复了它,然后应用上述更改来修复 szFilter 字符串。这个对我有用。显示文件对话框,我输入一些数据并关闭文件对话框。没有访问冲突,没有断言。我认为您需要在代码中的其他地方查找问题。

[更新 2]

忽略我之前所说的一切。您最初的访问冲突在 FileExportDialog.cpp 的第 174 行左右

void CFileExportDialog::OnTypeChange()
{
  // get current filename
  CWnd *fileNameBox = GetParent()->GetDlgItem(edt1);
  ASSERT_VALID(fileNameBox);
  CString fileName; fileNameBox->GetWindowText(fileName);

  // get current extension
  CWnd *typeNameBox = GetParent()->GetDlgItem(cmb1);
  ASSERT_VALID(typeNameBox);
  CString typeName; typeNameBox->GetWindowText(typeName);
...

真正的调用栈是:

AliEditor.exe!CWnd::GetDlgItem(int nID)  Line 92 + 0x3 bytes    C++
AliEditor.exe!CFileExportDialog::OnTypeChange()  Line 177 + 0x14 bytes  C++
AliEditor.exe!CFileDialog::XFileDialogEvents::OnTypeChange(IFileDialog * __formal)  Line 619    C++
comdlg32.dll!76138057()     
[Frames below may be incorrect and/or missing, no symbols loaded for comdlg32.dll]  
comctl32.dll!731c7613()     
comdlg32.dll!7612bdda()     
comdlg32.dll!7612c5a0()     
KernelBase.dll!76096055()   
comctl32.dll!7458b575()     
user32.dll!767281c8()   
user32.dll!76728326()   
user32.dll!76728347()   
user32.dll!76730d27()   
user32.dll!7673794a()   
AliEditor.exe!_AfxActivationWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam)  Line 456 + 0x1a bytes  C++
user32.dll!767262fa()   
user32.dll!76726d3a()   
user32.dll!76726ce9()   
user32.dll!7672965e()   
user32.dll!7675206f()   
user32.dll!7674cf4b()   
user32.dll!7674ce8a()   
user32.dll!7674cc0e()   
comdlg32.dll!7612597b()     
AliEditor.exe!CFileDialog::DoModal()  Line 748 + 0x26 bytes C++
...

程序在 CWnd::GetDlgItem 处崩溃,因为 CWnd“this”指针为 0。这是因为 CFileExportDialog::OnTypeChange 的第一行是 GetParent(),它为 NULL,因为此对话框没有父对话框。

CFileExportDialog 类不是 Visual Studio 的一部分,它似乎基于 1999 年从http://www.codeguru.com/cpp/wd/dislog/commondialogs/article.php/c1863/CFileExportDialog-Class编写的一些公共域代码.htm。看起来 OnTypeChange 的实现是基于原始开发人员对 Microsoft CFileDialog 类的细节进行逆向工程,因为它是在 1999 年实现的。我猜在 VS 2010 中内部结构发生了变化,因此该类不再有用。

下次运行程序时,在 FileExportDialog.cpp 的第 177 行设置断点。当您遇到断点时,单步执行代码并观察崩溃和断言,因为过时的代码会尝试做它一开始就不应该做的事情。

Recommend you dump the CFileExportDialog class and rewrite your program using the standard MFC CFileDialog class.

于 2012-10-01T16:25:13.913 回答