The hook function of CFileDialog solves the multi choice DoModal problem of dialog boxes

  • 2020-04-01 21:29:31
  • OfStack



        I talked about my idea: m_ofn of CFileDialog has a data member as a hook function pointer. By setting this function, we can check the relevant cancellation of CFileDialog, such as the message of the user changing the path, and then get the number of files in the current path, and set the buffer size based on this. The leader didn't quite understand my idea, so he searched the Internet and found a method to do it by deriving the CFileDialog class. The details are as follows:

        (link: http://www.codeproject.com/KB/dialog/pja_multiselect.aspx)

      The method mentioned in the link above works. But I also believe that my method is feasible. After work, I searched the Internet and found a solution to this problem on Microsoft's website. The link is as follows:

(link: http://support.microsoft.com/kb/131462/zh-cn)  

        The link the code provided suitable is Win 32 program, is not suitable for MFC program, and I built a Win32 application test of the example code, found a problem, is that when selecting files too much, is the need to allocate a buffer is long, use the HeapAlloc functions in the link will appear error, error is as follows:

  < img Alt = "" border = 0 height = 191 SRC =" / / files.jb51.net/file_images/article/201212/201212071406409.jpg "width = 444 >

        So replace the HeapAlloc and HeapFree functions that allocate and free memory in the link with C++ 's new and delete operators, respectively.

          On the basis of the practices provided in the official website of Microsoft, I explored the practices used in the MFC program. The specific code is as follows:

 
//Hook function
UINT_PTR CALLBACK MyOFNHookProc( HWND hdlg, // handle to child dialog box 
UINT uiMsg, // message identifier 
WPARAM wParam, // message parameter 
LPARAM lParam // message parameter 
) 
{ 
int nResult = FALSE; 
if (hdlg == NULL) 
return 0; 
#ifdef _DEBUG 
// from "_AfxCommDlgProc()" of the file "dlgcomm.cpp" 
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); 
if (pThreadState->m_pAlternateWndInit != NULL) 
pThreadState->m_pAlternateWndInit = NULL; 
#endif 
switch(uiMsg) 
{ 
case WM_NOTIFY: 
{ 
LPOFNOTIFY pOfn = (LPOFNOTIFY)lParam; 
switch(pOfn->hdr.code) 
{ 
case CDN_SELCHANGE: 
{ 
TCHAR dummy_buffer; 
// Get the required size for the 'files' buffer 
HWND hOwner = GetParent(hdlg); 
HWND hParent = GetParent(hOwner); 
UINT nfiles = CommDlg_OpenSave_GetSpec(hOwner, &dummy_buffer, 1); 
// Get the required size for the 'folder' buffer 
int cbLength = CommDlg_OpenSave_GetSpec(GetParent(hdlg), NULL, 0); 
cbLength += _MAX_PATH; 
if(cbLength>(pOfn->lpOFN)->nMaxFile) 
{ 
delete (pOfn->lpOFN)->lpstrFile; 
(pOfn->lpOFN)->lpstrFile = new TCHAR[cbLength]; 
ZeroMemory((pOfn->lpOFN)->lpstrFile,cbLength); 
(pOfn->lpOFN)->nMaxFile = cbLength; 
} 
nResult = TRUE; 
break; 
} 
default: 
break; 
} 
break; 
} 
default: 
break; 
} 
return nResult; 
} 
#define NAMEBUF 1024 
//Call a function
void CMultiSelectDlg::OnButton1() 
{ 
m_listbox.ResetContent(); 
m_static.SetWindowText(_T("0 files selected")); 
TCHAR szFilters[]= _T("MyType Files (*.doc)|*.doc||"); 
// Create an Open dialog; the default file name extension is ".doc". 
CFileDialog fileDlg(TRUE, _T("doc"), _T("*.doc"), 
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT, szFilters); 
fileDlg.m_ofn.lpstrFile=new TCHAR[NAMEBUF]; //Redefine the lpstrFile buffer size
memset(fileDlg.m_ofn.lpstrFile,0,NAMEBUF); //Initializes the defined buffer
fileDlg.m_ofn.nMaxFile = NAMEBUF; //Redefine nMaxFile
fileDlg.m_ofn.lpfnHook = (LPOFNHOOKPROC)MyOFNHookProc; 
INT_PTR ret = fileDlg.DoModal(); 
if (ret == IDOK) 
{ 
int width = 0; 
CString str; 
CDC *pDC = m_listbox.GetDC(); 
int saved = pDC->SaveDC(); 
pDC->SelectObject(GetFont()); 
UINT count = 0; 
POSITION pos = fileDlg.GetStartPosition(); 
while (pos) 
{ 
str = fileDlg.GetNextPathName(pos); 
m_listbox.AddString(str); 
CSize size(0, 0); 
size = pDC->GetTextExtent(str); 
width = width > size.cx ? width : size.cx; 
++count; 
} 
pDC->RestoreDC(saved); 
ReleaseDC(pDC); 
m_listbox.SetHorizontalExtent(width + 5); 
str.Format(_T("%u files selected"), count); 
m_static.SetWindowText(str); 
} 
DWORD dwCode = CommDlgExtendedError(); 
if (FNERR_BUFFERTOOSMALL==dwCode) 
{ 
AfxMessageBox(_T(" Failed to get the file path! ")); 
} 
delete []fileDlg.m_ofn.lpstrFile; 
fileDlg.m_ofn.lpstrFile = NULL; 
} 

      Another serious drawback to using hook functions is that the program must be compiled using Unicode character sets, and FNERR_BUFFERTOOSMALL error after compiling the program using multi-byte character sets (this has been tested, and I have a hard time understanding why Microsoft doesn't support multi-byte programs at this point). My test environment is: VS C++ 2005 + sp1,Win XP + sp3,unicode character set.


Related articles: