187 lines
5 KiB
C++
187 lines
5 KiB
C++
////////////////////////////////////////////////////////////////
|
|
// MSDN -- August 2000
|
|
// If this code works, it was written by Paul DiLascia.
|
|
// If not, I don't know who wrote it.
|
|
// Largely based on original implementation by Michael Lemley.
|
|
// Compiles with Visual C++ 6.0, runs on Windows 98 and probably NT too.
|
|
//
|
|
// CFileDialogEx implements a CFileDialog that uses the new Windows
|
|
// 2000 style open/save dialog. Use companion class CDocManagerEx in an
|
|
// MFC framework app.
|
|
//
|
|
#include "stdafx.h"
|
|
#include <afxpriv.h>
|
|
#include "FileDialogEx.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
static BOOL IsWin2000();
|
|
|
|
IMPLEMENT_DYNAMIC(CFileDialogEx, CFileDialog)
|
|
|
|
CFileDialogEx::CFileDialogEx(BOOL bOpenFileDialog, LPCTSTR lpszDefExt,
|
|
LPCTSTR lpszFileName, DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
|
|
CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName,
|
|
dwFlags, lpszFilter, pParentWnd)
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CFileDialogEx, CFileDialog)
|
|
//{{AFX_MSG_MAP(CFileDialogEx)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
BOOL IsWin2000()
|
|
{
|
|
OSVERSIONINFOEX osvi;
|
|
BOOL bOsVersionInfoEx;
|
|
|
|
// Try calling GetVersionEx using the OSVERSIONINFOEX structure,
|
|
// which is supported on Windows 2000.
|
|
//
|
|
// If that fails, try using the OSVERSIONINFO structure.
|
|
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
|
|
{
|
|
// If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
|
|
return FALSE;
|
|
}
|
|
|
|
switch (osvi.dwPlatformId)
|
|
{
|
|
case VER_PLATFORM_WIN32_NT:
|
|
|
|
if ( osvi.dwMajorVersion >= 5 )
|
|
return TRUE;
|
|
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//////////////////
|
|
// DoModal override copied mostly from MFC, with modification to use
|
|
// m_ofnEx instead of m_ofn.
|
|
//
|
|
INT_PTR CFileDialogEx::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));
|
|
|
|
// WINBUG: 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_ofn.Flags & OFN_EXPLORER)
|
|
pThreadState->m_pAlternateWndInit = this;
|
|
else
|
|
AfxHookWindowCreate(this);
|
|
|
|
memset(&m_ofnEx, 0, sizeof(m_ofnEx));
|
|
memcpy(&m_ofnEx, &m_ofn, sizeof(m_ofn));
|
|
if (IsWin2000())
|
|
m_ofnEx.lStructSize = sizeof(m_ofnEx);
|
|
|
|
INT_PTR nResult;
|
|
if (m_bOpenFileDialog)
|
|
nResult = ::GetOpenFileName((OPENFILENAME*)&m_ofnEx);
|
|
else
|
|
nResult = ::GetSaveFileName((OPENFILENAME*)&m_ofnEx);
|
|
|
|
memcpy(&m_ofn, &m_ofnEx, sizeof(m_ofn));
|
|
m_ofn.lStructSize = sizeof(m_ofn);
|
|
|
|
if (nResult)
|
|
ASSERT(pThreadState->m_pAlternateWndInit == NULL);
|
|
pThreadState->m_pAlternateWndInit = NULL;
|
|
|
|
// WINBUG: Second part of special case for file open/save dialog.
|
|
if (bEnableParent)
|
|
::EnableWindow(m_ofnEx.hwndOwner, TRUE);
|
|
if (::IsWindow(hWndFocus))
|
|
::SetFocus(hWndFocus);
|
|
|
|
PostModal();
|
|
return nResult ? nResult : IDCANCEL;
|
|
}
|
|
|
|
//////////////////
|
|
// When the open dialog sends a notification, copy m_ofnEx to m_ofn in
|
|
// case handler function is expecting updated information in the
|
|
// OPENFILENAME struct.
|
|
//
|
|
BOOL CFileDialogEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
memcpy(&m_ofn, &m_ofnEx, sizeof(m_ofn));
|
|
m_ofn.lStructSize = sizeof(m_ofn);
|
|
|
|
return CFileDialog::OnNotify( wParam, lParam, pResult);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// The following functions are provided for testing purposes, to
|
|
// demonstrate that they in fact called; ie, that MFC's internal dialog
|
|
// proc is hooked up properly. Delete them if you like.
|
|
//
|
|
BOOL CFileDialogEx::OnFileNameOK()
|
|
{
|
|
TRACE(_T("CFileDialogEx::OnFileNameOK\n"));
|
|
return CFileDialog::OnFileNameOK();
|
|
}
|
|
|
|
void CFileDialogEx::OnInitDone()
|
|
{
|
|
TRACE(_T("CFileDialogEx::OnInitDone\n"));
|
|
CFileDialog::OnInitDone();
|
|
}
|
|
|
|
void CFileDialogEx::OnFileNameChange()
|
|
{
|
|
TRACE(_T("CFileDialogEx::OnFileNameChange\n"));
|
|
CFileDialog::OnFileNameChange();
|
|
}
|
|
|
|
void CFileDialogEx::OnFolderChange()
|
|
{
|
|
TRACE(_T("CFileDialogEx::OnFolderChange\n"));
|
|
CFileDialog::OnFolderChange();
|
|
}
|
|
|
|
void CFileDialogEx::OnTypeChange()
|
|
{
|
|
TRACE(_T("OnTypeChange(), index = %d\n"), m_ofn.nFilterIndex);
|
|
CFileDialog::OnTypeChange();
|
|
}
|
|
|
|
|