// Dialogs.cpp - Create all of our dialogs to get data from the user. // // Copyright (c) 1998-1999 Microsoft Corporation #include #include #include #include "StdAfx.h" #include "Dialogs.h" #include "DataObj.h" #include "CompData.h" #include "Resource.h" #include "resrc1.h" // These are the lists of file type for the Save/Open Common Control Dialogs. CString strMSInfoSaveFileTypes; CString strMSInfoOpenFileTypes; CString strMSInfoReportTypes; // These are the default file types CString strMSInfoSaveType; CString strMSInfoReportType; // This is to implement a change to load the strings for file types, etc., // from resources. This is called by the app init. void LoadDialogResources() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); strMSInfoSaveFileTypes.LoadString(IDS_SAVE_FILE_TYPES); strMSInfoOpenFileTypes.LoadString(IDS_OPEN_FILE_TYPES); strMSInfoReportTypes.LoadString(IDS_REPORT_TYPES); strMSInfoSaveType.LoadString(IDS_SAVE_TYPE); strMSInfoReportType.LoadString(IDS_REPORT_TYPE); } // The custom message number we use to UINT CFindDialog::WM_MSINFO_FIND = WM_USER + 0x119; // static data members must be initialized at file scope TCHAR CMSInfoFileDialog::m_szCurrentDirectory[MAX_PATH] = _T("My Documents"); /* * GetPathFromIDList - Copy the path from the iilFolder to szPathBuffer. * * History: a-jsari 10/31/97 Initial version */ inline void GetBasePath(HWND hOwner, LPTSTR szPathBuffer) { LPITEMIDLIST iilFolder; HRESULT hResult; hResult = SHGetSpecialFolderLocation(hOwner, CSIDL_PERSONAL, &iilFolder); ASSERT(hResult == NOERROR); VERIFY(SHGetPathFromIDList(iilFolder, szPathBuffer)); } /* * CMSInfoFileDialog - Brings up the CFileDialog window, with a few of our * own specifications. * * History: a-jsari 10/24/97 Initial version */ CMSInfoFileDialog::CMSInfoFileDialog( BOOL bDialogIsOpen, HWND hOwner, LPCTSTR lpszDefaultExtension, LPCTSTR lpszExtensionFilters) :CFileDialog(bDialogIsOpen, // Open dialog or Save dialog? lpszDefaultExtension, // Default file extension NULL, // File name (don't specify) OFN_EXPLORER, // OPN Flags lpszExtensionFilters) // Filetype filter string. { m_ofn.hwndOwner = hOwner; m_ofn.nFilterIndex = 0; // default to "My Documents" GetBasePath(hOwner, m_szCurrentDirectory); m_ofn.lpstrInitialDir = m_szCurrentDirectory; } /* * we override DoModal so we can keep track of where the file was last opened from * * */ INT_PTR CMSInfoFileDialog::DoModal() { INT_PTR iRC; m_ofn.lpstrInitialDir = m_szCurrentDirectory; iRC = CFileDialog::DoModal(); // remember path user browsed to TCHAR szDir[MAX_PATH]; TCHAR szDrive[10]; int iLen; _tsplitpath(GetPathName(), szDrive, szDir, NULL, NULL); _tmakepath( m_szCurrentDirectory, szDrive, szDir, NULL, NULL); iLen = _tcslen( CMSInfoFileDialog::m_szCurrentDirectory); if ( m_szCurrentDirectory[iLen-1] == '\\' ) m_szCurrentDirectory[iLen-1] = 0; return iRC; } /* * CMSInfoReportDialog - Apply settings specific to the report dialog * * History: a-jsari 10/24/97 Initial version */ CMSInfoReportDialog::CMSInfoReportDialog(HWND hOwner) :CMSInfoSaveDialog(hOwner, strMSInfoReportType, strMSInfoReportTypes) { m_ofn.Flags |= OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; } /* * CMSInfoSaveDialog - Apply settings specific to the save dialog * * History: a-jsari 10/24/97 Initial version */ CMSInfoSaveDialog::CMSInfoSaveDialog(HWND hOwner, LPCTSTR lpszDefaultExtension, LPCTSTR lpszExtensionFilters) :CMSInfoFileDialog(FALSE, hOwner, lpszDefaultExtension, lpszExtensionFilters) { m_ofn.Flags |= OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; } /* * CMSInfoOpenDialog - Apply settings specific to the open dialog. * * History: a-jsari 10/24/97 Initial version */ CMSInfoOpenDialog::CMSInfoOpenDialog(HWND hOwner) :CMSInfoFileDialog(TRUE, hOwner, strMSInfoSaveType, strMSInfoOpenFileTypes) { m_ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; } /* * CMSInfoPrintDialog - Create the Print dialog * * History: a-jsari 12/8/97 Initial version */ CMSInfoPrintDialog::CMSInfoPrintDialog(HWND hOwner) :CPrintDialog(FALSE, PD_SELECTION | PD_USEDEVMODECOPIES | PD_HIDEPRINTTOFILE) { m_pd.hwndOwner = hOwner; } ///////////////////////////////////////////////////////////////////////////// // CFindDialog dialog /* * CFindDialog - Create the modal find dialog (which we will run in its own * thread, to make it appear modeless. * * History: a-jsari 11/28/97 Initial version. */ CFindDialog::CFindDialog(CSystemInfoScope *pScope, HWND hPostWindow, HWND hwndMMCWindow) :CDialog(IDD, NULL), m_pScope(pScope), m_hPostWindow(hPostWindow), m_hMMCWindow(hwndMMCWindow), m_strSearch(_T("")), m_fRunning(FALSE) { } /* * ~CFindDialog - Destroy the find dialog. * * History: a-jsari 11/28/97 Initial version. */ CFindDialog::~CFindDialog() { OnCancel(); if (m_iTimer) { KillTimer(m_iTimer); m_iTimer = 0; } } /* * Create - Creates the dialog box. * * History: a-jsari 1/21/98 Initial version. */ BOOL CFindDialog::Create() { DoModal(); return FALSE; } /* * SetFocus - Set focus to our Search window. * * History: a-jsari 12/17/97 Initial version */ CWnd *CFindDialog::SetFocus() { CWnd *pwFind; pwFind = GetDlgItem(IDC_SEARCHTERM); ASSERT(pwFind != NULL); return pwFind->SetFocus(); } /* * OnInitDialog - ClassWizard generated function * * History: a-jsari 12/2/97 */ BOOL CFindDialog::OnInitDialog() { CDialog::OnInitDialog(); ::SetWindowPos(GetSafeHwnd(), m_hPostWindow, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); m_iTimer = SetTimer(1, 150, NULL); return TRUE;// return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } BEGIN_MESSAGE_MAP(CFindDialog, CDialog) //{{AFX_MSG_MAP(CFindDialog) ON_EN_CHANGE(IDC_SEARCHTERM, OnSearchTerm) ON_COMMAND(IDC_FINDNEXT, OnFindNext) ON_COMMAND(IDC_STOPFIND, OnStopFind) ON_COMMAND(IDC_NEWSEARCH, OnNewSearch) ON_WM_ACTIVATE() ON_WM_HELPINFO() ON_WM_TIMER() ON_MESSAGE(WM_HELP, OnHelp) ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu) ON_WM_SETCURSOR() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFindDialog message handlers /* * OnActivate - Set our window position when we activate. * * History: a-jsari 3/4/98 Initial version */ afx_msg void CFindDialog::OnActivate(UINT, CWnd *, BOOL bMinimized) { // If we aren't minimized if (bMinimized == FALSE) { // Don't do this - it makes us stay on top of ALL the windows... // // SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); } } //----------------------------------------------------------------------------- // Catch the WM_HELPINFO message, so we can show context sensitive help on // the controls in the dialog box. //----------------------------------------------------------------------------- #include static DWORD helparray[] = { IDC_SEARCHTERM, 1000001, IDC_FINDIN, 1000002, IDC_CATEGORYCHECK, 1000003, IDC_FINDNEXT, 1000004, IDC_STOPFIND, 1000005, IDC_NEWSEARCH, 1000006, IDCANCEL, 1000007, 0, 0 }; afx_msg BOOL CFindDialog::OnHelpInfo(HELPINFO * pHelpInfo) { if (pHelpInfo && (pHelpInfo->iContextType == HELPINFO_WINDOW)) ::WinHelp((HWND)pHelpInfo->hItemHandle, TEXT("msinfo32.hlp"), HELP_WM_HELP, (DWORD_PTR)helparray); return TRUE; } //----------------------------------------------------------------------------- // Every time we get a timer message, check to see if the find window is // behind the MMC window. If it is, bring it forward. What we really want // is an application always on top effect, but this seems to be the way to // get this (since we can't change MMC). // // I hate this. //----------------------------------------------------------------------------- afx_msg void CFindDialog::OnTimer(UINT) { if (m_hMMCWindow == NULL) return; for (HWND hwndWalk = GetSafeHwnd(); hwndWalk != NULL; hwndWalk = ::GetNextWindow(hwndWalk, GW_HWNDPREV)) if (hwndWalk == m_hMMCWindow) { // This is how we bring the find window to the top. Using wndTop with // SetWindowPos doesn't seem to do anything. SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); break; } } LONG CFindDialog::OnHelp(WPARAM wParam, LPARAM lParam) { LONG lResult = 0; if (lParam) ::WinHelp((HWND)(((LPHELPINFO)lParam)->hItemHandle), TEXT("msinfo32.hlp"), HELP_WM_HELP, (DWORD_PTR)helparray); return lResult; } LONG CFindDialog::OnContextMenu(WPARAM wParam, LPARAM lParam) { LONG lResult = 0; ::WinHelp((HWND)wParam, TEXT("msinfo32.hlp"), HELP_CONTEXTMENU,(DWORD_PTR)helparray); return lResult; } /* * OnSetCursor - Set our cursor depending on whether we are executing the find. * * History: a-jsari 3/21/98 Initial version */ afx_msg BOOL CFindDialog::OnSetCursor(CWnd *pWndOther, UINT nHitTest, UINT message) { static HCURSOR hcPointerHourglass = NULL; // Set the pointer & hourglass cursor. if (m_fRunning) { if (hcPointerHourglass == NULL) { hcPointerHourglass = ::LoadCursor(NULL, IDC_APPSTARTING); #ifdef DEBUG DWORD dwError = ::GetLastError(); #endif ASSERT(hcPointerHourglass != NULL); } ::SetCursor(hcPointerHourglass); return TRUE; } else return CDialog::OnSetCursor(pWndOther, nHitTest, message); } /* * OnCancel - Destroy the window when the cancel button is selected. * * History: a-jsari 12/2/97 */ afx_msg void CFindDialog::OnCancel() { OnStopFind(); ::PostQuitMessage(0); // Exit the containing UI thread. m_pScope->CloseFindWindow(); } /* * OnFindNext - Execute the find next operation, when the "Find Next" button * is clicked or when a return is hit in the "Find In". * * History: a-jsari 12/11/97 */ afx_msg void CFindDialog::OnFindNext() { int wCount; long lFindState; // Save our last search. CString strLast = m_strSearch; AFX_MANAGE_STATE(::AfxGetStaticModuleState()); // Save our current search wCount = GetDlgItemText(IDC_SEARCHTERM, m_strSearch); ASSERT(wCount != 0); // Enable the Stop button (Disabled in FindComplete). CButton *pwStop = reinterpret_cast(GetDlgItem(IDC_STOPFIND)); ASSERT(pwStop != NULL); pwStop->EnableWindow(TRUE); // Disable our button so we can't activate it while we're running. // (Enabled in FindComplete) CButton *pwFindNext = reinterpret_cast(GetDlgItem(IDC_FINDNEXT)); ASSERT(pwFindNext != NULL); pwFindNext->EnableWindow(FALSE); // Set the flag indicating whether we search only category names. CButton *pwCheck = reinterpret_cast(GetDlgItem(IDC_CATEGORYCHECK)); ASSERT(pwCheck != NULL); lFindState = pwCheck->GetCheck() ? CDataSource::FIND_OPTION_CATEGORY_ONLY : 0; // Set the flag indicating whether we search the selected category alone. pwCheck = reinterpret_cast(GetDlgItem(IDC_FINDIN)); ASSERT(pwCheck != NULL); lFindState |= (pwCheck->GetCheck()) ? CDataSource::FIND_OPTION_ONE_CATEGORY : 0; // Set the flag indicating whether we are repeating a previous search. if (::_tcsicmp((LPCTSTR)strLast, (LPCTSTR)m_strSearch) == 0) lFindState |= CDataSource::FIND_OPTION_REPEAT_SEARCH; m_fRunning = TRUE; // In order to perform the find multi-threaded and allow a stop operation, // we post a custom message to a hidden window attached to the main MMC window // created in CSystemInfoScope::Initialize // Our custom WindowProc processes this message, running Find in the main // window's UI thread. ::PostMessage(m_hPostWindow, WM_MSINFO_FIND, (WPARAM)m_pScope, (LPARAM) lFindState); } /* * OnNewSearch - Clear the controls * * History: a-jsari 12/11/97 */ afx_msg void CFindDialog::OnNewSearch() { ResetSearch(); // Clear the text box. SetDlgItemText(IDC_SEARCHTERM, _T("")); // Clear the category check box. CButton *pwCheck = (CButton *) GetDlgItem(IDC_CATEGORYCHECK); ASSERT(pwCheck != NULL); pwCheck->SetCheck(0); // Clear the Restrict Search check box pwCheck = (CButton *) GetDlgItem(IDC_FINDIN); ASSERT(pwCheck != NULL); pwCheck->SetCheck(0); // Refocus on the text box. SetFocus(); } /* * OnSearchTerm - Callback for when the Search edit box is changed. * * History: a-jsari 12/11/97 Initial version. */ afx_msg void CFindDialog::OnSearchTerm() { CString strSearch; CWnd *wControl; int wSearch; // Get the length of the text box text. wSearch = GetDlgItemText(IDC_SEARCHTERM, strSearch); wControl = GetDlgItem(IDC_FINDNEXT); wControl->EnableWindow(wSearch > 0); wControl = GetDlgItem(IDC_SEARCHTERM); wControl->SetFocus(); } /* * OnStopFind - MULTI-THREADED Callback for the "Stop Find" button, intended * to be called while the find is running in the main window thread. * * History: a-jsari 1/19/98 Initial version */ afx_msg void CFindDialog::OnStopFind() { // This will abort the find operation in the main thread which will // then call FindComplete. m_pScope->StopFind(); } /* * FindComplete - Reset the find dialog upon completion, either by abort or * by normal completion. * * History: a-jsari 2/4/98 Initial version. */ void CFindDialog::FindComplete() { AFX_MANAGE_STATE(::AfxGetStaticModuleState()); m_fRunning = FALSE; // Enable our Find Button CButton *pwFindNext = reinterpret_cast(GetDlgItem(IDC_FINDNEXT)); ASSERT(pwFindNext != NULL); CString strSearch; int wSearch = GetDlgItemText(IDC_SEARCHTERM, strSearch); pwFindNext->EnableWindow(wSearch > 0); // Disable the Stop Button CButton *pwStop = reinterpret_cast(GetDlgItem(IDC_STOPFIND)); ASSERT(pwStop != NULL); pwStop->EnableWindow(FALSE); OnActivate(0, NULL, FALSE); } /* * ResetSearch - Resets the search so that the next search will register as * new. * * History: a-jsari 2/20/98 Initial version. */ void CFindDialog::ResetSearch() { m_strSearch = _T(""); } IMPLEMENT_DYNCREATE(CFindThread, CWinThread) /* * CFindThread - Default constructor * * History: a-jsari 1/19/98 Initial version. */ CFindThread::CFindThread() :m_pdlgFind(NULL), m_pScope(NULL), m_pDataSource(NULL) { } /* * ~CFindThread - Our destructor. * * History: a-jsari 1/19/98 Initial version. */ CFindThread::~CFindThread() { } /* * SetScope - Sets the scope item for the Find Dialog. * * History: a-jsari 1/21/98 Initial version. */ void CFindThread::SetScope(CSystemInfoScope *pScope) { ASSERT(pScope != NULL); m_pScope = pScope; } /* * SetParent - Sets the parent window for the Find Dialog. * * History: a-jsari 1/21/98 Initial version. */ void CFindThread::SetParent(HWND hParent, HWND hMMC) { m_hParentWindow = hParent; m_hMMCWindow = hMMC; } /* * Activate - Reactivate the thread after it's been deselected. * * History: a-jsari 1/22/98 Initial version. */ void CFindThread::Activate() { ASSERT(m_pdlgFind != NULL); m_pdlgFind->OnActivate(0, NULL, FALSE); } /* * InitInstance - Starts the thread and the dialog object. * * History: a-jsari 1/19/98 Initial version */ BOOL CFindThread::InitInstance() { // else increment some instance pointer? // Create our new Modal find dialog. m_pdlgFind = new CFindDialog(m_pScope, m_hParentWindow, m_hMMCWindow); ASSERT(m_pdlgFind != NULL); if (m_pdlgFind == NULL) ::AfxThrowMemoryException(); m_pdlgFind->Create(); // We won't get here until our dialog is exiting, since create calls // DoModal(), which blocks. return TRUE; } /* * ExitInstance - Ends the thread, destroying the dialog object. * * History: a-jsari 1/19/98 Inital version */ int CFindThread::ExitInstance() { delete m_pdlgFind; m_pdlgFind = NULL; return CWinThread::ExitInstance(); } /* * RemoteQuit - Ends the thread from an alternate thread, by sending the appropriate * message to our dialog, waiting for its exit. * * History: a-jsari 1/29/98 Initial version */ void CFindThread::RemoteQuit() { const DWORD dwWaitTimeout = 100000; // 100 ms, Presumably long enough. DWORD dwResult; m_pdlgFind->SendMessage(WM_COMMAND, IDCANCEL); // Wait for the thread to exit, avoiding its using an object destroyed // by our main thread in CSystemInfoScope. dwResult = ::WaitForSingleObject(m_hThread, dwWaitTimeout); ASSERT(dwResult == WAIT_OBJECT_0); }