//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: snapdata.cpp // //-------------------------------------------------------------------------- #include "preDNSsn.h" #include #include "resource.h" #include "DNSSnap.h" #include "dnsutil.h" #include "snapdata.h" #include "server.h" #include "servwiz.h" #include #include #ifdef DEBUG_ALLOCATOR #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif /////////////////////////////////////////////////////////////////////////////// // GLOBAL FUNCTIONS HRESULT SaveStringHelper(LPCWSTR pwsz, IStream* pStm) { ASSERT(pStm); ULONG nBytesWritten; HRESULT hr; DWORD nLen = static_cast(wcslen(pwsz)+1); // WCHAR including NULL hr = pStm->Write((void*)&nLen, sizeof(DWORD),&nBytesWritten); ASSERT(nBytesWritten == sizeof(DWORD)); if (FAILED(hr)) return hr; hr = pStm->Write((void*)pwsz, sizeof(WCHAR)*nLen,&nBytesWritten); ASSERT(nBytesWritten == sizeof(WCHAR)*nLen); TRACE(_T("SaveStringHelper(<%s> nLen = %d\n"),pwsz,nLen); return hr; } HRESULT LoadStringHelper(CString& sz, IStream* pStm) { ASSERT(pStm); HRESULT hr; ULONG nBytesRead; DWORD nLen = 0; hr = pStm->Read((void*)&nLen,sizeof(DWORD), &nBytesRead); ASSERT(nBytesRead == sizeof(DWORD)); if (FAILED(hr) || (nBytesRead != sizeof(DWORD))) return hr; hr = pStm->Read((void*)sz.GetBuffer(nLen),sizeof(WCHAR)*nLen, &nBytesRead); ASSERT(nBytesRead == sizeof(WCHAR)*nLen); sz.ReleaseBuffer(); TRACE(_T("LoadStringHelper(<%s> nLen = %d\n"),(LPCTSTR)sz,nLen); return hr; } HRESULT SaveDWordHelper(IStream* pStm, DWORD dw) { ULONG nBytesWritten; HRESULT hr = pStm->Write((void*)&dw, sizeof(DWORD),&nBytesWritten); if (nBytesWritten < sizeof(DWORD)) hr = STG_E_CANTSAVE; return hr; } HRESULT LoadDWordHelper(IStream* pStm, DWORD* pdw) { ULONG nBytesRead; HRESULT hr = pStm->Read((void*)pdw,sizeof(DWORD), &nBytesRead); ASSERT(nBytesRead == sizeof(DWORD)); return hr; } ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterPageBase class CDNSQueryFilterSheet; // fwd decl class CDNSQueryFilterPageBase : public CPropertyPage { public: CDNSQueryFilterPageBase(UINT nIDD, CDNSQueryFilterSheet* pSheet) : CPropertyPage(nIDD) { m_pSheet = pSheet; m_bDirty = FALSE; m_bInit = FALSE; } protected: CDNSQueryFilterSheet* m_pSheet; void SetDirty(); void Init(); BOOL IsDirty() { return m_bDirty;} virtual BOOL OnInitDialog(); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); afx_msg void OnWhatsThis(); afx_msg BOOL OnHelp(WPARAM wParam, LPARAM lParam); private: BOOL m_bInit; BOOL m_bDirty; HWND m_hWndWhatsThis; // hwnd of right click "What's this" help DECLARE_MESSAGE_MAP() }; ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterNamePage class CDNSQueryFilterNamePage : public CDNSQueryFilterPageBase { public: CDNSQueryFilterNamePage(CDNSQueryFilterSheet* pSheet) : CDNSQueryFilterPageBase(IDD_FILTERING_NAME, pSheet) { } protected: virtual BOOL OnInitDialog(); virtual BOOL OnApply(); afx_msg void OnRadioClicked(); afx_msg void OnEditChange(); private: CEdit* GetStartsStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_STARTS);} CEdit* GetContainsStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_CONTAINS);} CEdit* GetRangeFromStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_RANGE_FROM);} CEdit* GetRangeToStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_RANGE_TO);} CButton* GetRadioNone() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_NONE);} CButton* GetRadioStarts() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_STARTS);} CButton* GetRadioContains() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_CONTAINS);} CButton* GetRadioRange() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_RANGE);} // utility methods UINT GetSelectedRadioButtonID(); void SyncControls(UINT nRadioID); void GetEditText(UINT nID, CString& s); DECLARE_MESSAGE_MAP() }; ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterAdvancedPage class CDNSQueryFilterAdvancedPage : public CDNSQueryFilterPageBase { public: CDNSQueryFilterAdvancedPage(CDNSQueryFilterSheet* pSheet) : CDNSQueryFilterPageBase(IDD_FILTERING_LIMITS, pSheet) { } protected: virtual BOOL OnInitDialog(); virtual BOOL OnApply(); afx_msg void OnCountEditChange(); CDNSUnsignedIntEdit m_maxCountEdit; DECLARE_MESSAGE_MAP() }; ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterSheet class CDNSQueryFilterSheet : public CPropertySheet { public: CDNSQueryFilterSheet(CDNSQueryFilter* pQueryFilter, CComponentDataObject* pComponentData) : CPropertySheet(IDS_SNAPIN_FILTERING_TITLE), m_namePage(this), m_advancedPage(this), m_pComponentData(pComponentData) { m_psh.dwFlags |= PSH_NOAPPLYNOW; m_pQueryFilter = pQueryFilter; AddPage(&m_namePage); AddPage(&m_advancedPage); m_bInit = FALSE; } CDNSQueryFilter* GetQueryFilter() { return m_pQueryFilter;} CComponentDataObject* GetComponentData() { return m_pComponentData; } void SetSheetStyle() { DWORD dwStyle = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE); dwStyle |= WS_EX_CONTEXTHELP; // force the [?] button ::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, dwStyle); } private: void Init() { if (m_bInit) return; m_bInit = TRUE; CWnd* p = GetDlgItem(IDOK); if (p) p->EnableWindow(FALSE); } void SetDirty() { if (!m_bInit) return; GetDlgItem(IDOK)->EnableWindow(TRUE); } BOOL m_bInit; CComponentDataObject* m_pComponentData; CDNSQueryFilter* m_pQueryFilter; CDNSQueryFilterNamePage m_namePage; CDNSQueryFilterAdvancedPage m_advancedPage; friend class CDNSQueryFilterPageBase; friend class CDNSQueryFilterNamePage; friend class CDNSQueryFilterAdvancedPage; }; ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterPageBase IMPLEMENTATION BOOL CDNSQueryFilterPageBase::OnInitDialog() { BOOL bRet = CPropertyPage::OnInitDialog(); m_pSheet->SetSheetStyle(); return bRet; } void CDNSQueryFilterPageBase::SetDirty() { if (!m_bInit) return; m_bDirty = TRUE; m_pSheet->SetDirty(); } void CDNSQueryFilterPageBase::Init() { m_bInit = TRUE; m_pSheet->Init(); } BEGIN_MESSAGE_MAP(CDNSQueryFilterPageBase, CPropertyPage) ON_WM_CONTEXTMENU() ON_MESSAGE(WM_HELP, OnHelp) ON_COMMAND(IDM_WHATS_THIS, OnWhatsThis) END_MESSAGE_MAP() void CDNSQueryFilterPageBase::OnWhatsThis() { // // Display context help for a control // if ( m_hWndWhatsThis ) { // // Build our own HELPINFO struct to pass to the underlying // CS help functions built into the framework // int iCtrlID = ::GetDlgCtrlID(m_hWndWhatsThis); HELPINFO helpInfo; ZeroMemory(&helpInfo, sizeof(HELPINFO)); helpInfo.cbSize = sizeof(HELPINFO); helpInfo.hItemHandle = m_hWndWhatsThis; helpInfo.iCtrlId = iCtrlID; m_pSheet->GetComponentData()->OnDialogContextHelp(m_nIDHelp, &helpInfo); } } BOOL CDNSQueryFilterPageBase::OnHelp(WPARAM /*wParam*/, LPARAM lParam) { const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; if (pHelpInfo && pHelpInfo->iContextType == HELPINFO_WINDOW) { // // Display context help for a control // m_pSheet->GetComponentData()->OnDialogContextHelp(m_nIDHelp, pHelpInfo); } return TRUE; } void CDNSQueryFilterPageBase::OnContextMenu(CWnd* /*pWnd*/, CPoint point) { // // point is in screen coordinates // CMenu bar; if ( bar.LoadMenu(IDR_WHATS_THIS_CONTEXT_MENU1) ) { CMenu& popup = *bar.GetSubMenu (0); ASSERT(popup.m_hMenu); if ( popup.TrackPopupMenu (TPM_RIGHTBUTTON | TPM_LEFTBUTTON, point.x, // in screen coordinates point.y, // in screen coordinates this) ) // route commands through main window { m_hWndWhatsThis = 0; ScreenToClient (&point); CWnd* pChild = ChildWindowFromPoint (point, // in client coordinates CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); if ( pChild ) { m_hWndWhatsThis = pChild->m_hWnd; } } } } ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterNamePage IMPLEMENTATION BEGIN_MESSAGE_MAP(CDNSQueryFilterNamePage, CDNSQueryFilterPageBase) ON_BN_CLICKED(IDC_RADIO_FILTER_NONE, OnRadioClicked) ON_BN_CLICKED(IDC_RADIO_FILTER_STARTS, OnRadioClicked) ON_BN_CLICKED(IDC_RADIO_FILTER_CONTAINS, OnRadioClicked) ON_BN_CLICKED(IDC_RADIO_FILTER_RANGE, OnRadioClicked) ON_EN_CHANGE(IDC_EDIT_FILTER_STARTS, OnEditChange) ON_EN_CHANGE(IDC_EDIT_FILTER_CONTAINS, OnEditChange) ON_EN_CHANGE(IDC_EDIT_FILTER_RANGE_FROM, OnEditChange) ON_EN_CHANGE(IDC_EDIT_FILTER_RANGE_TO, OnEditChange) END_MESSAGE_MAP() UINT CDNSQueryFilterNamePage::GetSelectedRadioButtonID() { return GetCheckedRadioButton(IDC_RADIO_FILTER_NONE, IDC_RADIO_FILTER_RANGE); } void CDNSQueryFilterNamePage::OnRadioClicked() { UINT nRadioID = GetSelectedRadioButtonID(); SyncControls(nRadioID); } void CDNSQueryFilterNamePage::SyncControls(UINT nRadioID) { BOOL bStartsStringEditEnabled = FALSE; BOOL bContainsStringEditEnabled = FALSE; BOOL bRangeEnabled = FALSE; if (nRadioID == IDC_RADIO_FILTER_STARTS) { bStartsStringEditEnabled = TRUE; } else if (nRadioID == IDC_RADIO_FILTER_CONTAINS) { bContainsStringEditEnabled = TRUE; } else if (nRadioID == IDC_RADIO_FILTER_RANGE) { bRangeEnabled = TRUE; } GetStartsStringEdit()->SetReadOnly(!bStartsStringEditEnabled); GetContainsStringEdit()->SetReadOnly(!bContainsStringEditEnabled); GetRangeFromStringEdit()->SetReadOnly(!bRangeEnabled); GetRangeToStringEdit()->SetReadOnly(!bRangeEnabled); SetDirty(); } void CDNSQueryFilterNamePage::GetEditText(UINT nID, CString& s) { GetDlgItemText(nID, s); s.TrimLeft(); s.TrimRight(); } void CDNSQueryFilterNamePage::OnEditChange() { SetDirty(); } BOOL CDNSQueryFilterNamePage::OnInitDialog() { CDNSQueryFilterPageBase::OnInitDialog(); // write data to edit fields SetDlgItemText(IDC_EDIT_FILTER_STARTS, m_pSheet->m_pQueryFilter->m_szStartsString); SetDlgItemText(IDC_EDIT_FILTER_CONTAINS, m_pSheet->m_pQueryFilter->m_szContainsString); SetDlgItemText(IDC_EDIT_FILTER_RANGE_FROM, m_pSheet->m_pQueryFilter->m_szRangeFrom); SetDlgItemText(IDC_EDIT_FILTER_RANGE_TO, m_pSheet->m_pQueryFilter->m_szRangeTo); // set the radio buttons UINT nRadioID = IDC_RADIO_FILTER_NONE; switch(m_pSheet->m_pQueryFilter->m_nFilterOption) { case DNS_QUERY_FILTER_NONE: { GetRadioNone()->SetCheck(TRUE); nRadioID = IDC_RADIO_FILTER_NONE; } break; case DNS_QUERY_FILTER_STARTS: { GetRadioStarts()->SetCheck(TRUE); nRadioID = IDC_RADIO_FILTER_STARTS; } break; case DNS_QUERY_FILTER_CONTAINS: { GetRadioContains()->SetCheck(TRUE); nRadioID = IDC_RADIO_FILTER_CONTAINS; } break; case DNS_QUERY_FILTER_RANGE: { GetRadioRange()->SetCheck(TRUE); nRadioID = IDC_RADIO_FILTER_RANGE; } break; default: ASSERT(FALSE); } // enable/disable the edit fields SyncControls(nRadioID); Init(); return TRUE; // return TRUE unless you set the focus to a control } BOOL CDNSQueryFilterNamePage::OnApply() { if (!IsDirty()) return TRUE; UINT nRadioID = GetSelectedRadioButtonID(); // get data from edit controls GetEditText(IDC_EDIT_FILTER_STARTS, m_pSheet->m_pQueryFilter->m_szStartsString); GetEditText(IDC_EDIT_FILTER_CONTAINS, m_pSheet->m_pQueryFilter->m_szContainsString); GetEditText(IDC_EDIT_FILTER_RANGE_FROM, m_pSheet->m_pQueryFilter->m_szRangeFrom); GetEditText(IDC_EDIT_FILTER_RANGE_TO, m_pSheet->m_pQueryFilter->m_szRangeTo); // get radio button selection switch(nRadioID) { case IDC_RADIO_FILTER_NONE: { m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE; } break; case IDC_RADIO_FILTER_STARTS: { if (m_pSheet->m_pQueryFilter->m_szStartsString.IsEmpty()) m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE; else m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_STARTS; } break; case IDC_RADIO_FILTER_CONTAINS: { if (m_pSheet->m_pQueryFilter->m_szContainsString.IsEmpty()) m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE; else m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_CONTAINS; } break; case IDC_RADIO_FILTER_RANGE: { if (m_pSheet->m_pQueryFilter->m_szRangeFrom.IsEmpty() && m_pSheet->m_pQueryFilter->m_szRangeTo.IsEmpty() ) m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE; else m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_RANGE; } break; default: ASSERT(FALSE); } return TRUE; } ////////////////////////////////////////////////////////////////////// // CDNSQueryFilterAdvancedPage IMPLEMENTATION BEGIN_MESSAGE_MAP(CDNSQueryFilterAdvancedPage, CDNSQueryFilterPageBase) ON_EN_CHANGE(IDC_EDIT_COUNT, OnCountEditChange) END_MESSAGE_MAP() void CDNSQueryFilterAdvancedPage::OnCountEditChange() { SetDirty(); } BOOL CDNSQueryFilterAdvancedPage::OnInitDialog() { CDNSQueryFilterPageBase::OnInitDialog(); // set the range of the edit control for range validation VERIFY(m_maxCountEdit.SubclassDlgItem(IDC_EDIT_COUNT, this)); m_maxCountEdit.SetRange(DNS_QUERY_OBJ_COUNT_MIN, DNS_QUERY_OBJ_COUNT_MAX); // Disable IME support on the control ImmAssociateContext(m_maxCountEdit.GetSafeHwnd(), NULL); // set limit on the # of digits based on the max value CString s; s.Format(_T("%u"), DNS_QUERY_OBJ_COUNT_MAX); m_maxCountEdit.LimitText(s.GetLength()); // set the value m_maxCountEdit.SetVal(m_pSheet->m_pQueryFilter->m_nMaxObjectCount); Init(); return TRUE; } BOOL CDNSQueryFilterAdvancedPage::OnApply() { if (!IsDirty()) return TRUE; m_pSheet->m_pQueryFilter->m_nMaxObjectCount = m_maxCountEdit.GetVal(); return TRUE; } ////////////////////////////////////////////////////////////////////// // CDNSQueryFilter BOOL CDNSQueryFilter::EditFilteringOptions(CComponentDataObject* pComponentData) { CThemeContextActivator activator; CDNSQueryFilterSheet dlg(this, pComponentData); return IDOK == dlg.DoModal(); } HRESULT CDNSQueryFilter::Load(IStream* pStm) { HRESULT hr; // name filtering if (FAILED(hr = LoadDWordHelper(pStm, (DWORD*)(&m_nFilterOption)))) return hr; if (FAILED(hr = LoadStringHelper(m_szStartsString, pStm))) return hr; if (FAILED(hr = LoadStringHelper(m_szContainsString, pStm))) return hr; if (FAILED(hr = LoadStringHelper(m_szRangeFrom, pStm))) return hr; if (FAILED(hr = LoadStringHelper(m_szRangeTo, pStm))) return hr; // query limit if (FAILED(hr = LoadDWordHelper(pStm, (DWORD*)(&m_nMaxObjectCount)))) return hr; return LoadDWordHelper(pStm, (DWORD*)(&m_bGetAll)); } HRESULT CDNSQueryFilter::Save(IStream* pStm) { HRESULT hr; // name filtering if (FAILED(hr = SaveDWordHelper(pStm, (DWORD)m_nFilterOption))) return hr; if (FAILED(hr = SaveStringHelper(m_szStartsString, pStm))) return hr; if (FAILED(hr = SaveStringHelper(m_szContainsString, pStm))) return hr; if (FAILED(hr = SaveStringHelper(m_szRangeFrom, pStm))) return hr; if (FAILED(hr = SaveStringHelper(m_szRangeTo, pStm))) return hr; // query limit if (FAILED(hr = SaveDWordHelper(pStm, (DWORD)(m_nMaxObjectCount)))) return hr; return SaveDWordHelper(pStm, (DWORD)(m_bGetAll)); } ////////////////////////////////////////////////////////////////////// // CDNSRootData const GUID CDNSRootData::NodeTypeGUID = { 0x2faebfa3, 0x3f1a, 0x11d0, { 0x8c, 0x65, 0x0, 0xc0, 0x4f, 0xd8, 0xfe, 0xcb } }; BEGIN_TOOLBAR_MAP(CDNSRootData) TOOLBAR_EVENT(toolbarNewServer, OnConnectToServer) END_TOOLBAR_MAP() CDNSRootData::CDNSRootData(CComponentDataObject* pComponentData) : CRootData(pComponentData) { m_bAdvancedView = FALSE; m_pColumnSet = NULL; m_szDescriptionBar = _T(""); m_bCreatePTRWithHost = FALSE; } CDNSRootData::~CDNSRootData() { TRACE(_T("~CDNSRootData(), name <%s>\n"),GetDisplayName()); } STDAPI DnsSetup(LPCWSTR lpszFwdZoneName, LPCWSTR lpszFwdZoneFileName, LPCWSTR lpszRevZoneName, LPCWSTR lpszRevZoneFileName, DWORD dwFlags); BOOL CDNSRootData::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem2, long*) { CComponentDataObject* pComponentData = GetComponentDataObject(); if (pContextMenuItem2->lCommandID == IDM_SNAPIN_CONNECT_TO_SERVER) { ASSERT(pComponentData != NULL); if (pComponentData->IsExtensionSnapin()) return FALSE; // extensions do not have this menu item return TRUE; } // add toggle menu item for advanced view if (pContextMenuItem2->lCommandID == IDM_SNAPIN_ADVANCED_VIEW) { pContextMenuItem2->fFlags = IsAdvancedView() ? MF_CHECKED : 0; } if (pContextMenuItem2->lCommandID == IDM_SNAPIN_FILTERING) { if (IsFilteringEnabled()) { pContextMenuItem2->fFlags = MF_CHECKED; } return TRUE; } return TRUE; } HRESULT CDNSRootData::GetResultViewType(CComponentDataObject*, LPOLESTR *ppViewType, long *pViewOptions) { HRESULT hr = S_FALSE; if (m_containerChildList.IsEmpty() && m_leafChildList.IsEmpty()) { *pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS; LPOLESTR psz = NULL; StringFromCLSID(CLSID_MessageView, &psz); USES_CONVERSION; if (psz != NULL) { *ppViewType = psz; hr = S_OK; } } else { *pViewOptions = MMC_VIEW_OPTIONS_NONE; *ppViewType = NULL; hr = S_FALSE; } return hr; } HRESULT CDNSRootData::OnShow(LPCONSOLE lpConsole) { CComPtr spUnknown; CComPtr spMessageView; HRESULT hr = lpConsole->QueryResultView(&spUnknown); if (FAILED(hr)) return S_OK; hr = spUnknown->QueryInterface(IID_IMessageView, (PVOID*)&spMessageView); if (SUCCEEDED(hr)) { // Load and set the title text of the message view CString szTitle; VERIFY(szTitle.LoadString(IDS_MESSAGE_VIEW_NO_SERVER_TITLE)); spMessageView->SetTitleText(szTitle); // Load and set the body text of the message view CString szMessage; VERIFY(szMessage.LoadString(IDS_MESSAGE_VIEW_NO_SERVER_MESSAGE)); spMessageView->SetBodyText(szMessage); // Use the standard information icon spMessageView->SetIcon(Icon_Information); } return S_OK; } BOOL CDNSRootData::IsFilteringEnabled() { UINT nFilterOption = GetFilter()->GetFilterOption(); if (nFilterOption == DNS_QUERY_FILTER_DISABLED || nFilterOption == DNS_QUERY_FILTER_NONE) { return FALSE; } return TRUE; } BOOL CDNSRootData::OnSetRefreshVerbState(DATA_OBJECT_TYPES, BOOL* pbHide, CNodeList*) { *pbHide = FALSE; return !IsThreadLocked(); } HRESULT CDNSRootData::OnSetToolbarVerbState(IToolbar* pToolbar, CNodeList*) { HRESULT hr = S_OK; // // Set the button state for each button on the toolbar // hr = pToolbar->SetButtonState(toolbarNewServer, ENABLED, TRUE); ASSERT(SUCCEEDED(hr)); hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, FALSE); ASSERT(SUCCEEDED(hr)); hr = pToolbar->SetButtonState(toolbarNewZone, ENABLED, FALSE); ASSERT(SUCCEEDED(hr)); return hr; } HRESULT CDNSRootData::OnCommand(long nCommandID, DATA_OBJECT_TYPES, CComponentDataObject* pComponentData, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { return E_FAIL; } switch (nCommandID) { case IDM_SNAPIN_CONNECT_TO_SERVER: OnConnectToServer(pComponentData, pNodeList); break; case IDM_SNAPIN_ADVANCED_VIEW: OnViewOptions(pComponentData); break; case IDM_SNAPIN_FILTERING: { if (OnFilteringOptions(pComponentData)) { pComponentData->SetDescriptionBarText(this); } } break; default: ASSERT(FALSE); // Unknown command! return E_FAIL; } return S_OK; } BOOL CDNSRootData::OnEnumerate(CComponentDataObject* pComponentData, BOOL) { if (m_containerChildList.IsEmpty()) { // the list is empty, need to add ASSERT(pComponentData != NULL); // create a modal dialog + possibly the wizard proper AFX_MANAGE_STATE(AfxGetStaticModuleState()); CDNSServerWizardHolder holder(this, pComponentData, NULL); holder.DoModalConnectOnLocalComputer(); return FALSE; } return TRUE; // there are already children, add them to the UI now } #define DNS_STREAM_VERSION_W2K ((DWORD)0x06) #define DNS_STREAM_VERSION ((DWORD)0x07) // IStream manipulation helpers overrides HRESULT CDNSRootData::Load(IStream* pStm) { // assume never get multiple loads if(!m_containerChildList.IsEmpty() || !m_leafChildList.IsEmpty()) return E_FAIL; WCHAR szBuffer[256]; ULONG nLen; // WCHAR counting NULL UINT nCount; ULONG cbRead; // read the version ## DWORD dwVersion; VERIFY(SUCCEEDED(pStm->Read((void*)&dwVersion,sizeof(DWORD), &cbRead))); ASSERT(cbRead == sizeof(DWORD)); if (dwVersion != DNS_STREAM_VERSION && dwVersion != DNS_STREAM_VERSION_W2K) return E_FAIL; // load filtering options VERIFY(SUCCEEDED(m_filterObj.Load(pStm))); // load view option VERIFY(SUCCEEDED(pStm->Read((void*)&m_bAdvancedView,sizeof(BOOL), &cbRead))); ASSERT(cbRead == sizeof(BOOL)); // // load the Create PTR record with host flag // if (dwVersion > DNS_STREAM_VERSION_W2K) { VERIFY(SUCCEEDED(pStm->Read((void*)&m_bCreatePTRWithHost,sizeof(BOOL), &cbRead))); ASSERT(cbRead == sizeof(BOOL)); } // load the name of the snapin root display string VERIFY(SUCCEEDED(pStm->Read((void*)&nLen,sizeof(DWORD), &cbRead))); ASSERT(cbRead == sizeof(UINT)); VERIFY(SUCCEEDED(pStm->Read((void*)szBuffer,sizeof(WCHAR)*nLen, &cbRead))); ASSERT(cbRead == sizeof(WCHAR)*nLen); SetDisplayName(szBuffer); // load the list of servers VERIFY(SUCCEEDED(pStm->Read((void*)&nCount,sizeof(DWORD), &cbRead))); ASSERT(cbRead == sizeof(UINT)); CComponentDataObject* pComponentData = GetComponentDataObject(); for (int k=0; k< (int)nCount; k++) { CDNSServerNode* p = NULL; VERIFY(SUCCEEDED(CDNSServerNode::CreateFromStream(pStm, &p))); ASSERT(p != NULL); VERIFY(AddChildToList(p)); AddServerToThreadList(p, pComponentData); } if (nCount > 0) MarkEnumerated(); ASSERT(m_containerChildList.GetCount() == (int)nCount); return S_OK; } HRESULT CDNSRootData::Save(IStream* pStm, BOOL fClearDirty) { DWORD nCount = 0; ULONG cbWrite = 0; // write the version ## DWORD dwVersion = DNS_STREAM_VERSION; VERIFY(SUCCEEDED(pStm->Write((void*)&dwVersion, sizeof(DWORD),&cbWrite))); ASSERT(cbWrite == sizeof(DWORD)); // save filtering options VERIFY(SUCCEEDED(m_filterObj.Save(pStm))); // save view options VERIFY(SUCCEEDED(pStm->Write((void*)&m_bAdvancedView, sizeof(BOOL),&cbWrite))); ASSERT(cbWrite == sizeof(BOOL)); // // save the create PTR record with host flag // VERIFY(SUCCEEDED(pStm->Write((void*)&m_bCreatePTRWithHost, sizeof(BOOL),&cbWrite))); ASSERT(cbWrite == sizeof(BOOL)); // save the name of the snapin root display string DWORD nLen = static_cast(wcslen(GetDisplayName())+1); // WCHAR including NULL VERIFY(SUCCEEDED(pStm->Write((void*)&nLen, sizeof(DWORD),&cbWrite))); ASSERT(cbWrite == sizeof(DWORD)); VERIFY(SUCCEEDED(pStm->Write((void*)(GetDisplayName()), sizeof(WCHAR)*nLen,&cbWrite))); ASSERT(cbWrite == sizeof(WCHAR)*nLen); // write # of servers nCount = (DWORD)m_containerChildList.GetCount(); VERIFY(SUCCEEDED(pStm->Write((void*)&nCount, sizeof(DWORD),&cbWrite))); ASSERT(cbWrite == sizeof(DWORD)); // loop through the list of servers and serialize them POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CDNSServerNode* pServerNode = (CDNSServerNode*)m_containerChildList.GetNext(pos); VERIFY(SUCCEEDED(pServerNode->SaveToStream(pStm))); } if (fClearDirty) SetDirtyFlag(FALSE); return S_OK; } HRESULT CDNSRootData::IsDirty() { return CRootData::IsDirty(); } HRESULT CDNSRootData::OnConnectToServer(CComponentDataObject* pComponentData, CNodeList*) { ASSERT(pComponentData != NULL); // create a modal dialog + possibly the wizard proper AFX_MANAGE_STATE(AfxGetStaticModuleState()); CDNSServerWizardHolder holder(this, pComponentData, NULL); holder.DoModalConnect(); pComponentData->UpdateResultPaneView(this); return S_OK; } void CDNSRootData::AddServer(CDNSServerNode* p, CComponentDataObject* pComponentData) { ASSERT(p != NULL); AddChildToListAndUISorted(p, pComponentData); AddServerToThreadList(p, pComponentData); pComponentData->UpdateResultPaneView(this); pComponentData->SetDescriptionBarText(this); } BOOL CDNSRootData::VerifyServerName(LPCTSTR lpszServerName) { POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); // // case insensitive compare // if (_wcsicmp(pNode->GetDisplayName(), lpszServerName) == 0) { return FALSE; } } return TRUE; } BOOL CDNSRootData::OnViewOptions(CComponentDataObject* pComponentData) { // make sure there are not property sheets up: we do this because: // a) some folders might be removed and might have sheets up // b) some RR property pages (PTR) might not be switchable // on the fly between view types if (IsSheetLocked()) { if (!CanCloseSheets()) return TRUE; pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this); } ASSERT(!IsSheetLocked()); // toggle the view state m_bAdvancedView = !m_bAdvancedView; // loop through the servers POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); CDNSServerNode* pServerNode = (CDNSServerNode*)pNode; // pass the new view option pServerNode->ChangeViewOption(m_bAdvancedView, pComponentData); } // dirty the MMC document SetDirtyFlag(TRUE); return TRUE; } BOOL CDNSRootData::OnFilteringOptions(CComponentDataObject* pComponentData) { BOOL bRet = m_filterObj.EditFilteringOptions(pComponentData); if (bRet) { SetDirtyFlag(TRUE); } return bRet; } BOOL CDNSRootData::CanCloseSheets() { // NTRAID#NTBUG-594003-2002/04/11-JeffJon-Don't offer // to shutdown the sheets for the user because if the // sheet brought up a modal dialog we will deadlock // ourselves. DNSMessageBox(IDS_MSG_CONT_CLOSE_SHEET, MB_OK); return FALSE; } BOOL CDNSRootData::OnRefresh(CComponentDataObject* pComponentData, CNodeList* pNodeList) { if (pNodeList->GetCount() > 1) // multiple selection { BOOL bRet = TRUE; POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); ASSERT(pNode != NULL); CNodeList nodeList; nodeList.AddTail(pNode); if (!pNode->OnRefresh(pComponentData, &nodeList)) { bRet = FALSE; } } return bRet; } if (IsSheetLocked()) { if (!CanCloseSheets()) return FALSE; pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this); } ASSERT(!IsSheetLocked()); POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); CNodeList nodeList; nodeList.AddTail(pNode); ((CDNSServerNode*)pNode)->OnRefresh(pComponentData, &nodeList); } return TRUE; } LPWSTR CDNSRootData::GetDescriptionBarText() { static CString szFilterEnabled; static CString szServersFormat; INT_PTR nContainerCount = GetContainerChildList()->GetCount(); INT_PTR nLeafCount = GetLeafChildList()->GetCount(); // // If not already loaded, then load the format string L"%d record(s)" // if (szServersFormat.IsEmpty()) { szServersFormat.LoadString(IDS_FORMAT_SERVERS); } // // Format the child count into the description bar text // m_szDescriptionBar.Format(szServersFormat, nContainerCount + nLeafCount); // // Add L"[Filter Activated]" if the filter is on // if(IsFilteringEnabled()) { // // If not already loaded, then load the L"[Filter Activated]" string // if (szFilterEnabled.IsEmpty()) { szFilterEnabled.LoadString(IDS_FILTER_ENABLED); } m_szDescriptionBar += szFilterEnabled; } return (LPWSTR)(LPCWSTR)m_szDescriptionBar; } void CDNSRootData::TestServers(DWORD dwCurrTime, DWORD dwTimeInterval, CComponentDataObject* pComponentData) { //TRACE(_T("CDNSRootData::TestServers()\n")); POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); CDNSServerNode* pServerNode = (CDNSServerNode*)pNode; if (pServerNode->IsTestEnabled() && !pServerNode->m_bTestQueryPending && (pServerNode->m_dwTestTime <= dwCurrTime)) { DWORD dwQueryFlags = CDNSServerTestQueryResult::Pack(pServerNode->IsTestSimpleQueryEnabled(), pServerNode->IsRecursiveQueryEnabled()); pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_SEND_QUERY, (WPARAM)pServerNode, (WPARAM)dwQueryFlags); pServerNode->m_dwTestTime = dwCurrTime + pServerNode->GetTestInterval(); } } // check if the time counter has wrapped (it should be very unlikely, because // the timeline is on a DWORD in seconds (about 47000 days) from the console startup. if ((dwCurrTime + dwTimeInterval) < dwCurrTime) { // just reset the whole set of server times (not accurate, but acceptable) for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); CDNSServerNode* pServerNode = (CDNSServerNode*)pNode; pServerNode->m_dwTestTime = 0; } } } void CDNSRootData::OnServerTestData(WPARAM wParam, LPARAM lParam, CComponentDataObject* pComponentData) { ASSERT(lParam == 0); CDNSServerTestQueryResult* pTestResult = (CDNSServerTestQueryResult*)wParam; ASSERT(pTestResult != NULL); // loop through the list of servers to find where it belongs POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); ASSERT(pNode->IsContainer()); CDNSServerNode* pServerNode = (CDNSServerNode*)pNode; if ( (CDNSServerNode*)(pTestResult->m_serverCookie) == pServerNode) { pServerNode->AddTestQueryResult(pTestResult, pComponentData); return; } } } void CDNSRootData::AddServerToThreadList(CDNSServerNode* pServerNode, CComponentDataObject* pComponentData) { CDNSServerTestQueryInfo* pInfo = new CDNSServerTestQueryInfo; if (pInfo) { pInfo->m_szServerName = pServerNode->GetDisplayName(); pInfo->m_serverCookie = (MMC_COOKIE)pServerNode; pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_ADD_SERVER, (WPARAM)pInfo,0); } } void CDNSRootData::RemoveServerFromThreadList(CDNSServerNode* pServerNode, CComponentDataObject* pComponentData) { WPARAM serverCookie = (WPARAM)pServerNode; pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_REMOVE_SERVER, serverCookie,0); } /////////////////////////////////////////////////////////////////// // CDNSServerTestTimerThread int CDNSServerTestTimerThread::Run() { MSG msg; // initialize the message pump ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); // get let the main thread know we are entering the loop // (0,0) means just acknowkedge PostMessageToWnd(0,0); while(::GetMessage(&msg, NULL, 0, 0)) { switch(msg.message) { case WM_TIMER_THREAD_SEND_QUERY: case WM_TIMER_THREAD_SEND_QUERY_TEST_NOW: { MMC_COOKIE serverCookie = (MMC_COOKIE)msg.wParam; ASSERT(serverCookie != NULL); POSITION pos; for (pos = m_serverInfoList.GetHeadPosition(); pos != NULL; ) { CDNSServerTestQueryInfo* pCurrInfo = (CDNSServerTestQueryInfo*)m_serverInfoList.GetNext(pos); if (serverCookie == pCurrInfo->m_serverCookie) { OnExecuteQuery(pCurrInfo, (DWORD)msg.lParam, (msg.message == WM_TIMER_THREAD_SEND_QUERY_TEST_NOW)); break; } } } break; case WM_TIMER_THREAD_ADD_SERVER: { CDNSServerTestQueryInfo* pInfo = (CDNSServerTestQueryInfo*)msg.wParam; ASSERT(pInfo != NULL); m_serverInfoList.AddTail(pInfo); } break; case WM_TIMER_THREAD_REMOVE_SERVER: { MMC_COOKIE serverCookie = (MMC_COOKIE)msg.wParam; ASSERT(serverCookie != NULL); POSITION pos; POSITION posDel = NULL; CDNSServerTestQueryInfo* pInfo = NULL; for (pos = m_serverInfoList.GetHeadPosition(); pos != NULL; ) { posDel = pos; CDNSServerTestQueryInfo* pCurrInfo = (CDNSServerTestQueryInfo*)m_serverInfoList.GetNext(pos); if (serverCookie == pCurrInfo->m_serverCookie) { pInfo = pCurrInfo; break; } } if (pInfo != NULL) { ASSERT(posDel != NULL); m_serverInfoList.RemoveAt(posDel); delete pInfo; } } break; //default: //ASSERT(FALSE); } } return 0; } void CDNSServerTestTimerThread::OnExecuteQuery(CDNSServerTestQueryInfo* pInfo, DWORD dwQueryFlags, BOOL bAsyncQuery) { // initialize a query result object CDNSServerTestQueryResult* pTestResult = new CDNSServerTestQueryResult; if (!pTestResult) { return; } pTestResult->m_serverCookie = pInfo->m_serverCookie; pTestResult->m_dwQueryFlags = dwQueryFlags; pTestResult->m_bAsyncQuery = bAsyncQuery; ::GetLocalTime(&(pTestResult->m_queryTime)); // execute query BOOL bPlainQuery, bRecursiveQuery; CDNSServerTestQueryResult::Unpack(dwQueryFlags, &bPlainQuery, &bRecursiveQuery); IP_ADDRESS* ipArray; int nIPCount; pTestResult->m_dwAddressResolutionResult = FindIP(pInfo->m_szServerName, &ipArray, &nIPCount); if (pTestResult->m_dwAddressResolutionResult == 0) { ASSERT(ipArray != NULL); ASSERT(nIPCount > 0); PIP_ARRAY pipArr = (PIP_ARRAY)malloc(sizeof(DWORD)+sizeof(IP_ADDRESS)*nIPCount); if (pipArr && ipArray) { pipArr->AddrCount = nIPCount; memcpy(pipArr->AddrArray, ipArray, sizeof(IP_ADDRESS)*nIPCount); if (bPlainQuery) { pTestResult->m_dwPlainQueryResult = DoNothingQuery(pipArr, TRUE); } if (bRecursiveQuery) { pTestResult->m_dwRecursiveQueryResult = DoNothingQuery(pipArr, FALSE); } free(pipArr); pipArr = 0; } } if (!PostMessageToWnd((WPARAM)pTestResult, 0)) delete pTestResult; // could not deliver if (ipArray != NULL) free(ipArray); } DNS_STATUS CDNSServerTestTimerThread::FindIP(LPCTSTR lpszServerName, IP_ADDRESS** pipArray, int* pnIPCount) { DNS_STATUS dwErr = 0; *pipArray = NULL; *pnIPCount = 0; // try to see if the name is already an IP address IP_ADDRESS ipAddr = IPStringToAddr(lpszServerName); if (ipAddr != INADDR_NONE) { *pnIPCount = 1; *pipArray = (IP_ADDRESS*)malloc((*pnIPCount)*sizeof(IP_ADDRESS)); if (*pipArray != NULL) { *pipArray[0] = ipAddr; } } else { // // Originally we were doing a DnsQuery() to retrieve the IP address of the server so that we // could perform a query to that server to monitor its response. The problem with this is that // if the user enters a single label hostname as the server and they are administering remotely // and the two machines have different domain suffixes, then the DnsQuery() to get the IP address // of the server would fail. DnsQuery() appends the name of the Domain suffix to the single label // host name and then tries to resolve the using that FQDN which is incorrect. So instead of // performing a DnsQuery() to get the IP address, the following uses WSALookupServiceBegin(), // Next(), and End() to get the IP address. This has a better chance of resolving the name because // it uses DNS, WINS, etc. I am leaving in the old stuff just in case we run into some problems. // HANDLE hLookup; WSAQUERYSET qsQuery; DWORD dwBufLen = 0; GUID gHostAddrByName = SVCID_INET_HOSTADDRBYNAME; WSAQUERYSET* pBuffer = NULL; // // Initialize the query structure // memset(&qsQuery, 0, sizeof(WSAQUERYSET)); qsQuery.dwSize = sizeof(WSAQUERYSET); // the dwSize field has to be initialised like this qsQuery.dwNameSpace = NS_ALL; qsQuery.lpServiceClassId = &gHostAddrByName; // this is the GUID to perform forward name resolution (name to IP) qsQuery.lpszServiceInstanceName = (LPWSTR)lpszServerName; // this is the name queried for. hLookup = NULL; // // Get the handle for the query // int iStartupRet = 0; int iResult = WSALookupServiceBegin(&qsQuery,LUP_RETURN_ALL,&hLookup); if (iResult != 0) { // // Find out what socket error it was // int iErrorRet = WSAGetLastError(); // // If the service wasn't started try starting it // if (iErrorRet == WSANOTINITIALISED) { WSADATA wsaData; WORD wVersion = MAKEWORD(2,0); iStartupRet = WSAStartup(wVersion, &wsaData); if (iStartupRet == 0) { // // Startup succeeded, lets try to begin again // iResult = WSALookupServiceBegin(&qsQuery,LUP_RETURN_ALL,&hLookup); } } // // Clear the error // WSASetLastError(0); } if(0 == iResult) { // // Get the size of the first data block from the query // iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen, pBuffer); // // Allocate the required space for the query data // pBuffer = (WSAQUERYSET*)malloc(dwBufLen); ASSERT(pBuffer != NULL); if (pBuffer == NULL) { return E_OUTOFMEMORY; } else { // // Get the first data block from the query // iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen, pBuffer); // // Loop through all the data in the query but stop if we get a valid IP address // for the remote machine. // while(0 == iResult) { if (pBuffer != NULL && pBuffer->lpcsaBuffer != NULL && pBuffer->lpcsaBuffer->RemoteAddr.lpSockaddr != NULL) { // // We are only interested in the socket address so get a pointer to the sockaddr structure // sockaddr_in* pSockAddr = (sockaddr_in*)pBuffer->lpcsaBuffer->RemoteAddr.lpSockaddr; ASSERT(pSockAddr != NULL); // // Pull the IP address of the remote machine and pack it into a DWORD // DWORD dwIP = 0; dwIP = pSockAddr->sin_addr.S_un.S_un_b.s_b1; dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b2 << 8; dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b3 << 16; dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b4 << 24; // // Increment the IP count and allocate space for the address // (*pnIPCount)++; *pipArray = (IP_ADDRESS*)malloc((*pnIPCount)*sizeof(IP_ADDRESS)); if (*pipArray != NULL) { // // Copy the IP address into the IP array // PIP_ADDRESS pCurrAddr = *pipArray; *pCurrAddr = dwIP; } // // Break since we were able to obtain an IP address // break; } // // Free the buffer if it is still there // if (pBuffer != NULL) { free(pBuffer); pBuffer = NULL; dwBufLen = 0; } // // Get the size of the next data block from the query // iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen, pBuffer); // // Allocate enough space for the next data block from the query // pBuffer = (WSAQUERYSET*)malloc(dwBufLen); ASSERT(pBuffer != NULL); if (pBuffer) { // // Get the next data block from the query // iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL, &dwBufLen, pBuffer); } else { // NTRAID#NTBUG9-666458-2002/07/18-JeffJon // If the buffer is NULL at this point we have to act like we were // unable to obtain an IP address due to memory constraints break; } } // // Free the buffer if it hasn't already been freed // if (pBuffer != NULL) { free(pBuffer); pBuffer = NULL; } } // // Close the handle to the query // iResult = WSALookupServiceEnd(hLookup); ASSERT(iResult == 0); // // If we didn't get an IP address return an error // dwErr = (*pnIPCount < 1) ? -1 : 0; } } return dwErr; } DNS_STATUS CDNSServerTestTimerThread::DoNothingQuery(PIP_ARRAY pipArr, BOOL bSimple) { PDNS_RECORD pRecordList = NULL; DNS_STATUS dwErr = 0; if (bSimple) { dwErr = ::DnsQuery(_T("1.0.0.127.in-addr.arpa"), DNS_TYPE_PTR, DNS_QUERY_NO_RECURSION | DNS_QUERY_BYPASS_CACHE | DNS_QUERY_ACCEPT_PARTIAL_UDP | DNS_QUERY_WIRE_ONLY, pipArr, &pRecordList, NULL); } else { dwErr = ::DnsQuery(_T("."), DNS_TYPE_NS, DNS_QUERY_STANDARD | DNS_QUERY_BYPASS_CACHE | DNS_QUERY_ACCEPT_PARTIAL_UDP, pipArr, &pRecordList, NULL); } if (pRecordList != NULL) ::DnsRecordListFree(pRecordList, DnsFreeRecordListDeep); return dwErr; }