/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : machine.cpp Abstract: IIS Machine properties page Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "comprop.h" #include "mime.h" #define DLL_BASED __declspec(dllimport) #include "mmc.h" #include "machine.h" #include "inetprop.h" #include "..\mmc\constr.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CIISMachinePage, CPropertyPage) typedef struct tagMASTER_DLL { LPCTSTR lpszDllName; UINT nID; } MASTER_DLL; MASTER_DLL rgMasters[] = { // // Note: path should not be neccesary for these // config DLLs, because they should really already // be loaded by inetmgr at this point. // { _T("W3SCFG.DLL"), IDS_WWW_MASTER }, { _T("FSCFG.DLL"), IDS_FTP_MASTER }, }; #define NUM_MASTER_DLL ARRAY_SIZE(rgMasters) CMasterDll::CMasterDll( IN UINT nID, IN LPCTSTR lpszDllName, IN LPCTSTR lpszMachineName ) /*++ Routine Description: Construct master dll object Arguments: UINT nID : Resource ID LPCTSTR lpszDllName : Dll filename and path LPCTSTR lpszMachineName : Current machine name Return Value: N/A --*/ : m_hDll(NULL), m_pfnConfig(NULL), m_strText() { m_hDll = ::AfxLoadLibrary(lpszDllName); if (m_hDll != NULL) { // // Check to see if this service is installed // pfnQueryServerInfo pfnInfo = (pfnQueryServerInfo) ::GetProcAddress(m_hDll, SZ_SERVERINFO_PROC); if (pfnInfo != NULL) { ISMSERVERINFO ism; ism.dwSize = ISMSERVERINFO_SIZE; CError err((*pfnInfo)(lpszMachineName, &ism)); if (err.Succeeded()) { m_pfnConfig = (pfnConfigure)::GetProcAddress( m_hDll, SZ_CONFIGURE_PROC ); if (m_pfnConfig != NULL) { HINSTANCE hOld = AfxGetResourceHandle(); AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME)); VERIFY(m_strText.LoadString(nID)); AfxSetResourceHandle(hOld); // // Success! // return; } } } } // // Library didn't exist, was bogus, or unable to provide information // about itself. // SAFE_AFXFREELIBRARY(m_hDll); } CMasterDll::~CMasterDll() /*++ Routine Description: Destructor -- decrement library reference count Arguments: N/A Return Value: N/A --*/ { TRACEEOLID("Deleting: " << m_strText); SAFE_AFXFREELIBRARY(m_hDll); } /* static */ void CIISMachinePage::ParseMaxNetworkUse( IN OUT CILong & nMaxNetworkUse, OUT BOOL & fLimitNetworkUse ) /*++ Routine Description: Break out max network use function Arguments: CILong & nMaxNetworkUse : Maximum network value (will be changed) BOOL & fLimitMaxNetworkUse : TRUE if max network is not infinite Return Value None/ --*/ { fLimitNetworkUse = (nMaxNetworkUse != INFINITE_BANDWIDTH); nMaxNetworkUse = fLimitNetworkUse ? (nMaxNetworkUse / KILOBYTE) : (DEF_BANDWIDTH / KILOBYTE); } CIISMachinePage::CIISMachinePage( IN LPCTSTR lpstrMachineName, IN HINSTANCE hInstance ) /*++ Routine Description: Constructor for IIS Machine property page Arguments: LPCTSTR lpstrMachineName : Machine name HINSTANCE hInstance : Instance handle Return Value: N/A --*/ : CPropertyPage(CIISMachinePage::IDD), m_strMachineName(lpstrMachineName), m_fLocal(IsServerLocal(lpstrMachineName)), m_ppropMimeTypes(NULL), m_ppropMachine(NULL), m_lstMasterDlls(), m_hr(S_OK) { #if 0 // Keep class wizard happy //{{AFX_DATA_INIT(CIISMachinePage) m_fLimitNetworkUse = FALSE; m_nMasterType = -1; //}}AFX_DATA_INIT m_nMaxNetworkUse = 0; #endif m_nMasterType = 0; // // Data will be fetched later to prevent marshalling across // threads errors. The dialog is constructed in one thread, // and operates in another. // } CIISMachinePage::~CIISMachinePage() /*++ Routine Description: Destructor Arguments: N/A Return Value: N/A --*/ { } // // COMPILER ISSUE::: Inlining this function doesn't // work on x86 using NT 5! // HRESULT CIISMachinePage::QueryResult() const { return m_hr; } void CIISMachinePage::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { // // Make sure data was fetched // ASSERT(m_ppropMachine != NULL); ASSERT(m_ppropMimeTypes != NULL); CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CIISMachinePage) DDX_CBIndex(pDX, IDC_COMBO_MASTER_TYPE, m_nMasterType); DDX_Control(pDX, IDC_EDIT_MAX_NETWORK_USE, m_edit_MaxNetworkUse); DDX_Control(pDX, IDC_STATIC_THROTTLE_PROMPT, m_static_ThrottlePrompt); DDX_Control(pDX, IDC_STATIC_MAX_NETWORK_USE, m_static_MaxNetworkUse); DDX_Control(pDX, IDC_STATIC_KBS, m_static_KBS); DDX_Control(pDX, IDC_BUTTON_EDIT_DEFAULT, m_button_EditDefault); DDX_Control(pDX, IDC_CHECK_LIMIT_NETWORK_USE, m_check_LimitNetworkUse); DDX_Control(pDX, IDC_COMBO_MASTER_TYPE, m_combo_MasterType); DDX_Check(pDX, IDC_CHECK_LIMIT_NETWORK_USE, m_fLimitNetworkUse); //}}AFX_DATA_MAP if (m_edit_MaxNetworkUse.IsWindowEnabled()) { DDX_Text(pDX, IDC_EDIT_MAX_NETWORK_USE, m_nMaxNetworkUse); DDV_MinMaxLong(pDX, m_nMaxNetworkUse, 1, UD_MAXVAL); } } // // Message Map // BEGIN_MESSAGE_MAP(CIISMachinePage, CPropertyPage) //{{AFX_MSG_MAP(CIISMachinePage) ON_BN_CLICKED(IDC_CHECK_LIMIT_NETWORK_USE, OnCheckLimitNetworkUse) ON_BN_CLICKED(IDC_BUTTON_EDIT_DEFAULT, OnButtonEditDefault) ON_BN_CLICKED(IDC_BUTTON_FILE_TYPES, OnButtonFileTypes) ON_COMMAND(ID_HELP, OnHelp) ON_COMMAND(ID_CONTEXT_HELP, OnHelp) ON_WM_DESTROY() ON_WM_HELPINFO() //}}AFX_MSG_MAP ON_EN_CHANGE(IDC_EDIT_MAX_NETWORK_USE, OnItemChanged) END_MESSAGE_MAP() BOOL CIISMachinePage::SetControlStates() /*++ Routine Description: Set button states depending on contents of the controls. Return whether or not "Limit network use" is on. Arguments: None Return Value: TRUE if "Limit network use" is checked --*/ { BOOL fLimitOn = m_check_LimitNetworkUse.GetCheck() > 0; m_static_MaxNetworkUse.EnableWindow(fLimitOn); m_static_ThrottlePrompt.EnableWindow(fLimitOn); m_edit_MaxNetworkUse.EnableWindow(fLimitOn); m_static_KBS.EnableWindow(fLimitOn); return fLimitOn; } HRESULT CIISMachinePage::LoadDelayedValues() /*++ Routine Description: Load the metabase parameters Arguments: None Return Value: HRESULT --*/ { // // Fetch the properties from the metabase // ASSERT(m_ppropMachine == NULL); ASSERT(m_ppropMimeTypes == NULL); // // Share interface between the objects here // m_ppropMachine = new CMachineProps(m_strMachineName); if (NULL == m_ppropMachine) return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); else if (FAILED(m_ppropMachine->QueryResult())) return m_ppropMachine->QueryResult(); m_ppropMimeTypes = new CMimeTypes(m_ppropMachine); if (NULL == m_ppropMimeTypes) return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); else if (FAILED(m_ppropMimeTypes->QueryResult())) return m_ppropMimeTypes->QueryResult(); m_hr = m_ppropMachine->LoadData(); if (SUCCEEDED(m_hr)) { m_nMaxNetworkUse = m_ppropMachine->m_nMaxNetworkUse; ParseMaxNetworkUse(m_nMaxNetworkUse, m_fLimitNetworkUse); m_hr = m_ppropMimeTypes->LoadData(); if (SUCCEEDED(m_hr)) { m_strlMimeTypes = m_ppropMimeTypes->m_strlMimeTypes; } } return S_OK; } // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< void CIISMachinePage::OnHelp() /*++ Routine Description: 'Help' button handler Arguments: None Return Value: None --*/ { if (m_strHelpFile.IsEmpty()) { CRMCRegKey rk(REG_KEY, SZ_PARAMETERS, KEY_READ); rk.QueryValue(SZ_HELPPATH, m_strHelpFile, EXPANSION_ON); m_strHelpFile += _T("\\inetmgr.hlp"); TRACEEOLID("Initialized help file " << m_strHelpFile); } CWnd * pWnd = ::AfxGetMainWnd(); HWND hWndParent = pWnd != NULL ? pWnd->m_hWnd : NULL; ::WinHelp(m_hWnd, m_strHelpFile, HELP_CONTEXT, HIDD_IIS_MACHINE); } BOOL CIISMachinePage::OnHelpInfo(HELPINFO * pHelpInfo) { OnHelp(); return FALSE; } void CIISMachinePage::OnCheckLimitNetworkUse() /*++ Routine Description: The "limit network use" checkbox has been clicked Enable/disable the "max network use" controls. Arguments: None Return Value: None --*/ { if (SetControlStates()) { m_edit_MaxNetworkUse.SetSel(0,-1); m_edit_MaxNetworkUse.SetFocus(); } OnItemChanged(); } void CIISMachinePage::OnItemChanged() /*++ Routine Description: All EN_CHANGE messages map to this function Arguments: None Return Value: None --*/ { SetModified(TRUE); } void CIISMachinePage::OnButtonEditDefault() /*++ Routine Description: 'edit default' button handler Arguments: None Return Value: None --*/ { // // Get selection, and convert to index into server table // via associative array. // CError err; int nSel = m_combo_MasterType.GetCurSel(); ASSERT(nSel >= 0 && nSel < NUM_MASTER_DLL); POSITION pos = m_lstMasterDlls.FindIndex(nSel); ASSERT(pos != NULL); CMasterDll * pDll = m_lstMasterDlls.GetAt(pos); ASSERT(pDll != NULL); // // Allocate string with 2 terminating NULLS // int nLen = m_strMachineName.GetLength(); LPTSTR lpServers = AllocTString(nLen + 2); if (lpServers == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; } else { ::lstrcpy(lpServers, m_strMachineName); lpServers[nLen + 1] = _T('\0'); err = pDll->Config(m_hWnd, lpServers); } SAFE_FREEMEM(lpServers); err.MessageBoxOnFailure(); } void CIISMachinePage::OnButtonFileTypes() /*++ Routine Description: 'file types' button handler - bring up mime types dialog. Arguments: None Return Value: None --*/ { HINSTANCE hOld = AfxGetResourceHandle(); AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME)); CMimeDlg dlg(m_strlMimeTypes, this); if (dlg.DoModal() == IDOK) { OnItemChanged(); } AfxSetResourceHandle(hOld); } BOOL CIISMachinePage::OnInitDialog() /*++ Routine Description: WM_INITDIALOG handler. Initialize the dialog. Arguments: None. Return Value: TRUE if no focus is to be set automatically, FALSE if the focus is already set. --*/ { CServerCapabilities caps(m_strMachineName, SZ_MBN_WEB); BOOL fHasThrottling = caps.HasBwThrottling(); CError err(LoadDelayedValues()); if (err.Failed()) { fHasThrottling = FALSE; } CPropertyPage::OnInitDialog(); // // Fill the master combo box // int cServices = 0; CMasterDll * pDll; for (int n = 0; n < NUM_MASTER_DLL; ++n) { pDll = new CMasterDll( rgMasters[n].nID, rgMasters[n].lpszDllName, m_strMachineName ); if (pDll == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } if (pDll->IsLoaded()) { m_combo_MasterType.AddString(*pDll); m_lstMasterDlls.AddTail(pDll); ++cServices; } else { // // Dll didn't load, toss it. // delete pDll; } } if (cServices == 0) { // // No master-programmable services installed, so disallow // master editing. // GetDlgItem(IDC_BUTTON_EDIT_DEFAULT)->EnableWindow(FALSE); GetDlgItem(IDC_GROUP_MASTER)->EnableWindow(FALSE); GetDlgItem(IDC_STATIC_MASTER_PROMPT1)->EnableWindow(FALSE); GetDlgItem(IDC_STATIC_MASTER_PROMPT2)->EnableWindow(FALSE); m_combo_MasterType.EnableWindow(FALSE); } m_check_LimitNetworkUse.EnableWindow(fHasThrottling); m_combo_MasterType.SetCurSel(0); SetControlStates(); err.MessageBoxOnFailure(); return TRUE; } BOOL CIISMachinePage::OnApply() /*++ Routine Description: 'Apply' button handler. Called when OK or APPLY is pressed. Arguments: None. Return Value: TRUE to continue, FALSE otherwise --*/ { // // Don't use m_nMaxNetworkUse, because it would // alter the values on the screen when DDX happens next. // CILong nMaxNetworkUse = m_nMaxNetworkUse; BuildMaxNetworkUse(nMaxNetworkUse, m_fLimitNetworkUse); m_ppropMachine->m_nMaxNetworkUse = nMaxNetworkUse; CError err(m_ppropMachine->WriteDirtyProps()); if (err.Succeeded()) { m_ppropMimeTypes->m_strlMimeTypes = m_strlMimeTypes; err = m_ppropMimeTypes->WriteDirtyProps(); } if (err.Succeeded()) { return CPropertyPage::OnApply(); } // // Failed // err.MessageBox(); return FALSE; } void CIISMachinePage::OnDestroy() /*++ Routine Description: Window is being destroyed. Time to clean up Arguments: None. Return Value: None. --*/ { ASSERT(m_ppropMachine != NULL); ASSERT(m_ppropMimeTypes != NULL); SAFE_DELETE(m_ppropMachine); SAFE_DELETE(m_ppropMimeTypes); while (!m_lstMasterDlls.IsEmpty()) { CMasterDll * pDll = m_lstMasterDlls.RemoveHead(); delete pDll; } // // Remove the help window if it's currently open // ::WinHelp(m_hWnd, NULL, HELP_QUIT, 0L); CPropertyPage::OnDestroy(); } void CIISMachinePage::PostNcDestroy() /*++ Routine Description: handle destruction of the window by freeing the this pointer (as this modeless dialog must have been created on the heap) Arguments: None. Return Value: None --*/ { delete this; }