//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation 1996-2001. // // File: uithread.cpp // // Contents: implementation of CUIThread // //---------------------------------------------------------------------------- #include "stdafx.h" #include "wsecmgr.h" #include "resource.h" #include #include "servperm.h" #include "stdafx.h" #include "wsecmgr.h" #include "snapmgr.h" #include "util.h" #include "UIThread.h" #include "attr.h" #include "aaudit.h" #include "aenable.h" #include "AMember.h" #include "anumber.h" #include "AObject.h" #include "ARet.h" #include "ARight.h" #include "aservice.h" #include "astring.h" #include "CAudit.h" #include "CEnable.h" #include "CGroup.h" #include "CName.h" #include "CNumber.h" #include "cobject.h" #include "CPrivs.h" #include "CRet.h" #include "cservice.h" #include "regvldlg.h" #include "perfanal.h" #include "applcnfg.h" #include "wrapper.h" #include "locdesc.h" #include "profdesc.h" #include "newprof.h" #include "laudit.h" #include "lenable.h" #include "lret.h" #include "lnumber.h" #include "lstring.h" #include "lright.h" #include "achoice.h" #include "cchoice.h" #include "lchoice.h" #include "dattrs.h" #include "lflags.h" #include "aflags.h" #include "multisz.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CUIThread IMPLEMENT_DYNCREATE(CUIThread, CWinThread) CUIThread::CUIThread() { } CUIThread::~CUIThread() { } BOOL CUIThread::InitInstance() { // TODO: perform and per-thread initialization here return TRUE; } int CUIThread::ExitInstance() { // TODO: perform any per-thread cleanup here return CWinThread::ExitInstance(); } BEGIN_MESSAGE_MAP(CUIThread, CWinThread) //{{AFX_MSG_MAP(CUIThread) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_THREAD_MESSAGE( SCEM_APPLY_PROFILE, OnApplyProfile) ON_THREAD_MESSAGE( SCEM_ANALYZE_PROFILE, OnAnalyzeProfile) ON_THREAD_MESSAGE( SCEM_DESCRIBE_PROFILE, OnDescribeProfile) ON_THREAD_MESSAGE( SCEM_DESCRIBE_LOCATION, OnDescribeLocation) ON_THREAD_MESSAGE( SCEM_DESTROY_DIALOG, OnDestroyDialog) ON_THREAD_MESSAGE( SCEM_NEW_CONFIGURATION, OnNewConfiguration) ON_THREAD_MESSAGE( SCEM_ADD_PROPSHEET, OnAddPropSheet) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CUIThread message handlers //+-------------------------------------------------------------------------- // // Method: DefaultLogFile // // Synopsis: Find the default log file for the inf file last applied // pass back the log file via the out parameter strLogFile // //--------------------------------------------------------------------------- void CUIThread::DefaultLogFile(CComponentDataImpl *pCDI,GWD_TYPES LogID,LPCTSTR szBase, CString& strLogFile) { // // Base log file on the db passed in // CString strDefExt; strDefExt.LoadString(IDS_LOGFILE_DEF_EXT); // make sure that the extension includes '.' if (strDefExt.GetLength() > 0 && strDefExt[0] != L'.') { CString tempExt = strDefExt; strDefExt = L'.'; strDefExt += tempExt; } CString strInfFile = szBase; // // Get the default working directory // LPTSTR szDir = NULL; if (pCDI->GetWorkingDir(LogID, &szDir, FALSE, FALSE)) { strLogFile = szDir; LocalFree(szDir); szDir = NULL; } if (strLogFile.Right(1) != TEXT("\\")) { strLogFile += L"\\"; } if ( strInfFile.GetLength() < 5) { // // The default log file. // strLogFile += TEXT("SceStus") + strDefExt; } else { int nFilePartIndex = 0; int nFilePartCount = 0; // // +1 to change index base from 0 to 1 for the Mid // nFilePartIndex = strInfFile.ReverseFind(L'\\') +1; nFilePartCount = strInfFile.ReverseFind(L'.') - nFilePartIndex; strLogFile += strInfFile.Mid(nFilePartIndex,nFilePartCount) + strDefExt; } } //+-------------------------------------------------------------------------- // // Method: OnApplyProfile // // Synopsis: Create and display a dialog for applying a profile to the // system // // Arguments: [uParam] - A string with the name of the database to assign to // [lParam] - A pointer to the CComponentDataImpl // //--------------------------------------------------------------------------- void CUIThread::OnApplyProfile(WPARAM uParam, LPARAM lParam) { CComponentDataImpl *pCDI = NULL; CApplyConfiguration *pAP = NULL; CWnd cwndParent; pCDI = reinterpret_cast(lParam); // // Look for a preexisting version of this dialog in pCDI's cache. // If it's not there then create a new one and add it. // pAP = (CApplyConfiguration *)pCDI->GetPopupDialog(IDM_APPLY); if (NULL == pAP) { pAP = new CApplyConfiguration; if (NULL == pAP) { return; } pCDI->AddPopupDialog(IDM_APPLY,pAP); } pAP->m_strDataBase = reinterpret_cast(uParam); DefaultLogFile(pCDI,GWD_CONFIGURE_LOG, pAP->m_strDataBase, pAP->m_strLogFile); pAP->SetComponentData(pCDI); if (!pAP->GetSafeHwnd()) { cwndParent.Attach(pCDI->GetParentWindow()); CThemeContextActivator activator; pAP->Create(IDD_APPLY_CONFIGURATION,&cwndParent); cwndParent.Detach(); } pAP->UpdateData(FALSE); pAP->BringWindowToTop(); pAP->ShowWindow(SW_SHOWNORMAL); } //+-------------------------------------------------------------------------- // // Method: OnAnalyzeProfile // // Synopsis: Create and display a dialog for applying a profile to the // system // // Arguments: [uParam] - A string with the name of the database to assign to // [lParam] - A pointer to the CComponentDataImpl // //--------------------------------------------------------------------------- void CUIThread::OnAnalyzeProfile(WPARAM uParam, LPARAM lParam) { CComponentDataImpl *pCDI = NULL; CPerformAnalysis *pPA = NULL; CWnd cwndParent; pCDI = reinterpret_cast(lParam); // // Look for a preexisting version of this dialog in pCDI's cache. // If it's not there then create a new one and add it. // pPA = (CPerformAnalysis *)pCDI->GetPopupDialog(IDM_ANALYZE); if (NULL == pPA) { pPA = new CPerformAnalysis (0, 0); if (NULL == pPA) { return; } pPA->m_strDataBase = reinterpret_cast(uParam); DefaultLogFile(pCDI,GWD_ANALYSIS_LOG, pPA->m_strDataBase, pPA->m_strLogFile); pPA->SetComponentData(pCDI); pCDI->AddPopupDialog(IDM_ANALYZE,pPA); } if (!pPA->GetSafeHwnd()) { cwndParent.Attach(pCDI->GetParentWindow()); CThemeContextActivator activator; pPA->Create(IDD_PERFORM_ANALYSIS,&cwndParent); cwndParent.Detach(); } pPA->BringWindowToTop(); pPA->ShowWindow(SW_SHOWNORMAL); } //+-------------------------------------------------------------------------- // // Method: OnDescribeProfile // // Synopsis: Create and display a dialog for editing a profile's description // // Arguments: [uParam] - A pointer to the CFolder for the object // [lParam] - The CComponentDataImpl owning the scope pane // //--------------------------------------------------------------------------- void CUIThread::OnDescribeProfile(WPARAM uParam, LPARAM lParam) { CSetProfileDescription *pSPD; CFolder *pFolder; CComponentDataImpl *pCDI; CWnd cwndParent; LPTSTR szDesc; pFolder = reinterpret_cast(uParam); pCDI = reinterpret_cast(lParam); LONG_PTR dwKey = DLG_KEY(pFolder, CSetProfileDescription::IDD); // // Look for a preexisting version of this dialog in pCDI's cache. // If it's not there then create a new one and add it. // pSPD = (CSetProfileDescription *)pCDI->GetPopupDialog( dwKey ); if (NULL == pSPD) { pSPD = new CSetProfileDescription; if (NULL == pSPD) { return; } pCDI->AddPopupDialog( dwKey, pSPD); } if (!pSPD->GetSafeHwnd()) { if (GetProfileDescription(pFolder->GetInfFile(),&szDesc)) pSPD->m_strDesc = szDesc; pSPD->Initialize(pFolder,pCDI); cwndParent.Attach(pCDI->GetParentWindow()); CThemeContextActivator activator; pSPD->Create(IDD_SET_DESCRIPTION,&cwndParent); cwndParent.Detach(); } pSPD->UpdateData(FALSE); pSPD->BringWindowToTop(); pSPD->ShowWindow(SW_SHOWNORMAL); } //+-------------------------------------------------------------------------- // // Method: OnDescribeLocation // // Synopsis: Create and display a dialog for editing a Location's description // // Arguments: [uParam] - A pointer to the CFolder for the object // [lParam] - The CComponentDataImpl owning the scope pane // //--------------------------------------------------------------------------- void CUIThread::OnDescribeLocation(WPARAM uParam, LPARAM lParam) { CSetLocationDescription *pSPD; CFolder *pFolder; CComponentDataImpl *pCDI; CWnd cwndParent; LPTSTR szDesc; pFolder = reinterpret_cast(uParam); pCDI = reinterpret_cast(lParam); LONG_PTR dwKey = DLG_KEY(pFolder, CSetLocationDescription::IDD); // // Look for a preexisting version of this dialog in pCDI's cache. // If it's not there then create a new one and add it. // pSPD = (CSetLocationDescription *)pCDI->GetPopupDialog( dwKey ); if (NULL == pSPD) { pSPD = new CSetLocationDescription; if (NULL == pSPD) { return; } pCDI->AddPopupDialog(dwKey ,pSPD); } // pSPD->Initialize(pFolder,pCDI); if (!pSPD->GetSafeHwnd()) { pSPD->Initialize(pFolder,pCDI); cwndParent.Attach(pCDI->GetParentWindow()); CThemeContextActivator activator; pSPD->Create(IDD_SET_DESCRIPTION,&cwndParent); pSPD->SetWindowText(pFolder->GetName()); cwndParent.Detach(); } pSPD->UpdateData(FALSE); pSPD->BringWindowToTop(); pSPD->ShowWindow(SW_SHOWNORMAL); } /*----------------------------------------------------------------------------------- Method: OnDestroyDialog Synopsis: Destroys and deletes the CAttribute object associated with [pDlg] Arguments: [pDlg] - Is a pointer to the object to delete. Histroy: -----------------------------------------------------------------------------------*/ void CUIThread::OnDestroyDialog(WPARAM pDlg, LPARAM) { if(pDlg){ CAttribute *pAttr = reinterpret_cast(pDlg); delete pAttr; } } //+-------------------------------------------------------------------------- // // Method: OnNewConfiguration // // Synopsis: Create and display a dialog for adding a new configuration file // // Arguments: [uParam] - A pointer to the CFolder parent of the new config file // [lParam] - A pointer to the CComponentDataItem // //--------------------------------------------------------------------------- void CUIThread::OnNewConfiguration(WPARAM uParam, LPARAM lParam) { CNewProfile *pNP; CFolder *pFolder; CComponentDataImpl *pCDI; CWnd cwndParent; LPTSTR szDesc; pFolder = reinterpret_cast(uParam); pCDI = reinterpret_cast(lParam); LONG_PTR dwKey = DLG_KEY(pFolder, CNewProfile::IDD); // // Look for a preexisting version of this dialog in pCDI's cache. // If it's not there then create a new one and add it. // pNP = (CNewProfile *)pCDI->GetPopupDialog( dwKey); if (NULL == pNP) { pNP = new CNewProfile; if (NULL == pNP) { return; } pCDI->AddPopupDialog( dwKey, pNP); } // pNP->Initialize(pFolder,pCDI); if (!pNP->GetSafeHwnd()) { pNP->Initialize(pFolder,pCDI); cwndParent.Attach(pCDI->GetParentWindow()); CThemeContextActivator activator; pNP->Create(IDD_NEW_PROFILE,&cwndParent); pNP->SetWindowText(pFolder->GetName()); cwndParent.Detach(); } pNP->UpdateData(FALSE); pNP->BringWindowToTop(); pNP->ShowWindow(SW_SHOWNORMAL); } //+-------------------------------------------------------------------------- // Method: OnAddPropsheet // // Synopsis: Adds a property sheet to the list of sheets to which to pass messages // in PreTranslateMessage // // Arguments: [wParam] - HWND of the added property sheet // [lParam] - unused // //--------------------------------------------------------------------------- void CUIThread::OnAddPropSheet(WPARAM wParam, LPARAM lParam) { if (IsWindow((HWND)wParam)) { m_PSHwnds.AddHead((HWND)wParam); } } BOOL CUIThread::PreTranslateMessage(MSG* pMsg) { // // check PropSheet_GetCurrentPageHwnd to see if we need to destroy // one of our modeless property sheets // POSITION pos; POSITION posCur; HWND hwnd; pos= m_PSHwnds.GetHeadPosition(); while (pos) { posCur = pos; hwnd = m_PSHwnds.GetNext(pos); if (!IsWindow(hwnd)) { m_PSHwnds.RemoveAt(posCur); } else if (NULL == PropSheet_GetCurrentPageHwnd(hwnd)) { // // hwnd is a closed property sheet. destroy it and remove it from the list // DestroyWindow(hwnd); m_PSHwnds.RemoveAt(posCur); } if (PropSheet_IsDialogMessage(hwnd,pMsg)) { // // Message has been handled, so don't do anything else with it // return TRUE; } } return CWinThread::PreTranslateMessage(pMsg); } ///////////////////////////////////////////////////////////////////////////// // CModelessDlgUIThread implementation IMPLEMENT_DYNCREATE(CModelessDlgUIThread, CUIThread) //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ CModelessDlgUIThread::CModelessDlgUIThread() { m_hReadyForMsg = ::CreateEvent(NULL, TRUE, FALSE, NULL); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ CModelessDlgUIThread::~CModelessDlgUIThread() { if (NULL != m_hReadyForMsg) ::CloseHandle(m_hReadyForMsg); } BEGIN_MESSAGE_MAP(CModelessDlgUIThread, CUIThread) //{{AFX_MSG_MAP(CModelessDlgUIThread) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_THREAD_MESSAGE( SCEM_CREATE_MODELESS_SHEET, OnCreateModelessSheet) ON_THREAD_MESSAGE( SCEM_DESTROY_WINDOW, OnDestroyWindow) END_MESSAGE_MAP() //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ int CModelessDlgUIThread::Run() { if (m_hReadyForMsg) ::SetEvent(m_hReadyForMsg); return CWinThread::Run(); } //------------------------------------------------------------------------------ // wparam is PMLSHEET_DATA, and lparam is not used and can be used in the future // for telling what property sheet is to be created (right now, it only works // for ACL editor) //------------------------------------------------------------------------------ void CModelessDlgUIThread::OnCreateModelessSheet(WPARAM wparam, LPARAM lparam) { PMLSHEET_DATA pSheetData = (PMLSHEET_DATA)wparam; if (pSheetData) { HWND hSheet = (HWND)MyCreateSecurityPage2(pSheetData->bIsContainer, pSheetData->ppSeDescriptor, pSheetData->pSeInfo, pSheetData->strObjectName, pSheetData->SeType, pSheetData->flag, pSheetData->hwndParent, TRUE); *(pSheetData->phwndSheet) = hSheet; OnAddPropSheet((WPARAM)hSheet, 0); } } //------------------------------------------------------------------------------ // wparam is the window handle and lparam is not used at this time // Since destroying a window must happen on the thread where it is contructed, // this is necessary. Basic window management rules must be followed, e.g., // don't ask this thread to destroy windows that is not created by it //------------------------------------------------------------------------------ void CModelessDlgUIThread::OnDestroyWindow(WPARAM wparam, LPARAM lparam) { if (::IsWindow((HWND)wparam)) { DestroyWindow((HWND)wparam); } } //------------------------------------------------------------------------------ // immediately after this thread object is created, creating thread needs to // wait by calling this function so that the newly created thread has a chance // to be scheduled to run. //------------------------------------------------------------------------------ void CModelessDlgUIThread::WaitTillRun() { if (NULL != m_hReadyForMsg) { // $UNDONE:shawnwu I found that MMC runs at THREAD_PRIORITY_ABOVE_NORMAL (or higher) priority // becaues only when I run this UI thread at THREAD_PRIORITY_HIGHEST will this thread schedule to run. // But running at that level of priority makes me feel a little bit nervous. I thus // leave this sleep(10) code here. Up to the UI team to decide. ::Sleep(10); ::WaitForSingleObject(m_hReadyForMsg, INFINITE); // don't care about result of this waiting // now the event is useless. To reduce resource overhead, close the handle ::CloseHandle(m_hReadyForMsg); m_hReadyForMsg = NULL; } }