想使用CFileDialog,产生一个文件多选的对话窗口。1、CFileDialog默认是单文件操作的窗口。
如果设置如下标记
CFileDialog getFileDlg(TRUE, NULL, "T*.*", NULL, "Touch file(T*.*)|T*.*||", NULL);
getFileDlg.m_ofn.Flags |= OFN_ALLOWMULTISELECT | OFN_EXPLORER;这样的话,倒是可以选择多个文件了。2、但是它的缓冲区只有固定的大小(256字节?),我选择比较多的文件的时候(40多个),会有如下错误返回
FNERR_BUFFERTOOSMALL (注:CommDlgExtendedError()返回)问题,怎样设置缓冲区大小,使它可以选择的文件数目比较多呢?
在线等待,答者有分。

解决方案 »

  1.   

    缓冲区有默认大小,选择比较多的文件的时候
    需要设置CFileDialog::m_ofn
    有一个lpstrFile 属性指向缓冲区,自己设置一个大一点的缓冲区
      

  2.   

    MSDN:How To Handle FNERR_BUFFERTOOSMALL in Windows 95SUMMARY
    When an application uses the Open File common dialog with the OFN_ALLOWMULTISELECT flag, there is a danger that the buffer passed to the common dialog in the OPENFILENAME.lpstrFile field will be too small. In this situation, GetOpenFileName() will return an error value and CommDlgExtendedError() will return FNERR_BUFFERTOOSMALL. To work around this problem, watch for the Open or OK button to be pressed in the dialog hook; then reallocate the buffer if necessary. This technique works on Windows version 3.1, Windows NT, and Windows 95, but the implementation details are different when dealing with Windows 95 Explorer-type dialog boxes versus traditional Open and Save common dialog boxes. This article explains how to do it in Windows 95. MORE INFORMATION
    With the introduction of the new common dialogs for Windows 95, a new way of handling the FNERR_BUFFERTOOSMALL error was developed. It is still necessary to watch for the Open button to be pressed and reallocate the buffer if needed, but the way to watch for the OK is much different. When you install a hook on the Open File common dialog in Windows 95 using the OPENFILENAME.lpfnHook member, the dialog you are hooking is a child of the main Open File dialog. Therefore, to intercept the OK button, you need to subclass the parent dialog. To do this, you can install the hook procedure and watch for the CDN_INITDONE notification. The Open File dialog will send this as part of a WM_NOTIFY message when the initialization for the dialog is complete. For example: LRESULT CALLBACK DialogHook(HWND hwnd, UINT uMsg, WPARAM wParam,                             LPARAM lParam)
    {
        static HWND hwndParentDialog;
        LPOFNOTIFY lpofn;    switch (uMsg)
        {
            case WM_INITDIALOG:
                // You need to use a copy of the OPENFILENAME struct used to
                // create this dialog. You can store a pointer to the
                // OPENFILENAME struct in the ofn.lCustData so you can retrieve
                // it here in the lParam. Once you have it, you need to hang on
                // to it. Using window properties provides a good thread safe
                // solution to using a global variable.            SetProp(hwnd, "OFN", lParam);
                return (0);        case WM_NOTIFY:
                // The OFNOTIFY struct is passed in the lParam of this message.            lpofn = (LPOFNOTIFY) lParam;            switch (lpofn->hdr.code)
                {
                    case CDN_INITDONE:
                        // Subclass the parent dialog to watch for the OK
                        // button.                    hwndParentDialog = GetParent(hwnd);
                        g_lpfnDialogProc =
                                (FARPROC) SetWindowLong(hwndParentDialog,
                                                        DWL_DLGPROC,
                                                        OpenFileSubclassProc);
                        break;            }
                return (0);        case WM_DESTROY:
                // Need to clean up the subclassing we did on the dialog.
                SetWindowLong(hwndParentDialog, DWL_DLGPROC, g_lpfnDialogProc);            // Also need to free the property with the OPENFILENAME struct
                RemoveProp(hwnd, "OFN");
                return (0);
        }
        return (0);} 
    Once the parent dialog is subclassed, the program can watch for the actual Open button. When the program gets the Open button command, it needs to check to see if the buffer originally allocated is large enough to handle all the files selected. The CommDlg_OpenSave_GetFilePath() API will return the length needed. Here is an example of the subclass procedure: LRESULT CALLBACK OpenFileSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,                                       LPARAM lParam)
    {
        LPTSTR lpsz;
        WORD   cbLength;    switch (uMsg)
        {
            case WM_COMMAND:
                switch (LOWORD(wParam))
                {
                    case IDOK:
                        // Need to verify the original buffer size is large
                        // enough to handle the files selected. The
                        // CommDlg_OpenSave_GetFilePath() API will return the
                        // length needed for this buffer.                    cbLength = CommDlg_OpenSave_GetFilePath(hwnd, NULL, 0);                    // OFN_BUFFER_SIZE is the size of the buffer originally
                        // used in the OPENFILENAME.lpstrFile member.                    if (OFN_BUFFER_SIZE < cbLength)
                        {
                            // The buffer is too small, so allocate a
                            // new buffer.
                            lpsz = (LPTSTR) HeapAlloc(GetProcessHeap(),
                                                      HEAP_ZERO_MEMORY,
                                                      cbLength);
                            if (lpsz)
                            {
                                // The OFN struct is stored in a property of
                                // the dialog window.                            lpofn = (LPOPENFILENAME) GetProp(hwnd, "OFN");                            lpofn->lpstrFile = lpsz;
                                lpofn->nMaxFile  = cbLength;
                            }
                        }                    // Now let the dialog handle the message normally.
                        break;
                }
                break;
        }    return (CallWindowProc(g_lpfnDialogProc, hwnd, uMsg, wParam, lParam));} 
    The dialog should now return without error. Be aware that the buffer allocated in the subclass procedure needs to be freed once the dialog returns. Finally, this technique only works for 32-bit applications that are using the Explorer-type common dialogs. For 32-bit applications that don't use the OFN_EXPLORER flag, Windows 95 thunks to the 16-bit common dialog and the hook function only gets a copy of the OPENFILENAME structure. 
      

  3.   

    使用CFileDialog类选择多个文件,CFileDialog会把选择后的文件名拷贝到一个缓冲区,默认这个缓冲区有200多个字符,这对于很多情况来说太小了。你可以将m_ofn.lpstrFile替换成自己的缓冲区指针: 
         char sBuffer[6000]; 
         CFileDialog dlg(TRUE, NULL, NULL, 
         OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | 
         OFN_ALLOWMULTISELECT, 
         "C++ source|*.cpp|All files|*.*||"); 
         dlg.m_ofn.lpstrFile = sBuffer; 
         dlg.m_ofn.nMaxFile = 6000; 
        如果缓冲区不够大,CommDlgExtendedError()函数的返回值为FNERR_BUFFERTOOSMALL,并且缓冲区的前两个字节包括需要的大小。
      

  4.   

    http://expert.csdn.net/Expert/topic/1963/1963897.xml?temp=3.303164E-02
      

  5.   

    If the buffer is too small, the function returns FALSE and the CommDlgExtendedError function returns FNERR_BUFFERTOOSMALL. In this case, the first two bytes of the lpstrFile buffer contain the required size, in bytes or characters.
      

  6.   

    but how to hook?can you talk more about it?
      

  7.   

    2562#ifndef _FOLDERDIALOG_H_
    #define _FOLDERDIALOG_H_#if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000class CFileFolderDialog : public CFileDialog
    {
    DECLARE_DYNAMIC(CFileFolderDialog)public:
    CFileFolderDialog(BOOL bOpenFileDialog, DWORD dwFlags = OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING |OFN_EXPLORER, 
    LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL); ~CFileFolderDialog();
    void SelectFolder(HWND hWnd,CString& strSelectPath);
        virtual int DoModal();
    CString GetNextPathName(POSITION &pos) const;
    POSITION GetStartPosition();protected:
    //{{AFX_MSG(CFileFolderDialog)
    // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()private:
    // char* lpFile;
    BOOL bParsed;
    TCHAR *Folder;
    TCHAR *Files; virtual void OnFileNameChange();
    virtual void OnInitDone( );
    };#endif#include "stdafx.h"
    #include "FileFolderDialog.h"
    #include <DLGS.H>
    #include <WINUSER.H>
    #include "CDERR.H"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // CFolderDialogIMPLEMENT_DYNAMIC(CFileFolderDialog, CFileDialog)CFileFolderDialog::CFileFolderDialog(BOOL bOpenFileDialog,DWORD dwFlags, 
    LPCTSTR lpszFilter,CWnd* pParentWnd) 
    : CFileDialog(bOpenFileDialog,NULL,NULL,
    dwFlags,lpszFilter,pParentWnd)
    {
        Files = NULL;
        Folder = NULL;
        bParsed = FALSE;
    // m_ofn.nMaxFile = 2562;
    //    lpFile = new char[2562];
    //    m_ofn.lpstrFile = lpFile;
    //    m_ofn.lpstrFile[0] = NULL;
    }CFileFolderDialog::~CFileFolderDialog()
    {
    // delete lpFile;
        if (Files)
        {
            delete[] Files;
            delete[] Folder;
        }
    }BEGIN_MESSAGE_MAP(CFileFolderDialog, CFileDialog)
    //{{AFX_MSG_MAP(CFileFolderDialog)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    void CFileFolderDialog::OnInitDone()
    {
    HideControl(chx1); const UINT iExtraSize = 150;
    // Number of controls in the File Dialog
    const UINT nControls = 7; // Get a pointer to the original dialog box.
    CWnd *wndDlg = GetParent(); RECT Rect;
    wndDlg->GetWindowRect(&Rect);
    // Change the size
    wndDlg->SetWindowPos(NULL, 0, 0, 
     Rect.right - Rect.left, 
     Rect.bottom - Rect.top + iExtraSize, 
     SWP_NOMOVE);
    wndDlg->CenterWindow();
    // Control ID's - defined in <dlgs.h>
    UINT Controls[nControls] = {stc3, stc2,  // The two label controls
    edt1, cmb1,  // The eidt control and the drop-down box
    IDOK, IDCANCEL, 
    lst1};       // Explorer vinduet // Go through each of the controls in the dialog box, and move them to a new position
    for (int i=0 ; i<nControls ; i++)
    {
    CWnd *wndCtrl = wndDlg->GetDlgItem(Controls[i]);
    wndCtrl->GetWindowRect(&Rect);
    wndDlg->ScreenToClient(&Rect); // Remember it is child controls // Move all the controls according to the new size of the dialog.
    if (Controls[i] != lst1)
    wndCtrl->SetWindowPos(NULL, 
      Rect.left, Rect.top + iExtraSize,
      0, 0, SWP_NOSIZE);
    else // This is the explorer like window. It should be sized - not moved.
    wndCtrl->SetWindowPos(NULL, 0, 0,
     Rect.right - Rect.left, 
     Rect.bottom - Rect.top + iExtraSize, 
     SWP_NOMOVE);
    }
    }int CFileFolderDialog::DoModal()
    {
        if (Files)
        {
            delete[] Files;
            Files = NULL;
            delete[] Folder;
            Folder = NULL;
        }    int ret = CFileDialog::DoModal();    if (ret == IDCANCEL)
        {
            DWORD err = CommDlgExtendedError();
            if (err == FNERR_BUFFERTOOSMALL/*0x3003*/ && Files)
                ret = IDOK;
        }
    return ret;
    }CString CFileFolderDialog::GetNextPathName(POSITION& pos) const
    {
        if (!Files)
            return CFileDialog::GetNextPathName(pos);    ASSERT(pos);    
        TCHAR *ptr = (TCHAR *)pos;    CString ret = Folder;
        ret += _T("\\");
        ret += ptr;    ptr += _tcslen(ptr) + 1;
        if (*ptr)
            pos = (POSITION)ptr;
        else
            pos = NULL;    return ret;
    }POSITION CFileFolderDialog::GetStartPosition()
    {
        if (!Files)
            return CFileDialog::GetStartPosition();    if (!bParsed)
        {
            CString temp = Files;
            temp.Replace(_T("\" \""), _T("\""));
            temp.Delete(0, 1);                      // remove leading quote 
            temp.Delete(temp.GetLength() - 1, 1);   // remove trailing space
        
            _tcscpy(Files, temp);
        
            TCHAR *ptr = Files;
            while (*ptr)
            {
                if ('\"' == *ptr)
                    *ptr = '\0';
                ++ptr;
            }
            bParsed = TRUE;
        }
        
        return (POSITION)Files;
    }void CFileFolderDialog::OnFileNameChange()
    {
        TCHAR dummy_buffer;
        
        // Get the required size for the 'files' buffer
        UINT nfiles = CommDlg_OpenSave_GetSpec(GetParent()->m_hWnd, &dummy_buffer, 1);    // Get the required size for the 'folder' buffer
        UINT nfolder = CommDlg_OpenSave_GetFolderPath(GetParent()->m_hWnd, &dummy_buffer, 1);    // Check if lpstrFile and nMaxFile are large enough
        if (nfiles + nfolder > m_ofn.nMaxFile)
        {
            bParsed = FALSE;
            if (Files)
                delete[] Files;
            Files = new TCHAR[nfiles + 1];
            CommDlg_OpenSave_GetSpec(GetParent()->m_hWnd, Files, nfiles);        if (Folder)
                delete[] Folder;
            Folder = new TCHAR[nfolder + 1];
            CommDlg_OpenSave_GetFolderPath(GetParent()->m_hWnd, Folder, nfolder);
        }
        else if (Files)
        {
            delete[] Files;
            Files = NULL;
            delete[] Folder;
            Folder = NULL;
        }    CFileDialog::OnFileNameChange();
    }#define BIF_NEWDIALOGSTYLE     0x0040
    #define BIF_USENEWUI           (BIF_NEWDIALOGSTYLE | BIF_EDITBOX)void CFileFolderDialog::SelectFolder(HWND hWnd,CString& strSelectPath)
    {
    BROWSEINFO bi;
    char FileName[MAX_PATH]; ZeroMemory(&bi,sizeof(BROWSEINFO));
    bi.hwndOwner = hWnd;
    bi.pszDisplayName = FileName;
    bi.lpszTitle="Select Folder";
    bi.ulFlags= BIF_USENEWUI; LPITEMIDLIST idl=SHBrowseForFolder(&bi);
    if(idl==NULL)
    return; SHGetPathFromIDList(idl,FileName);
    strSelectPath.Format("%s",FileName);
    }