1570 lines
41 KiB
C++
1570 lines
41 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
||
|
//
|
||
|
// File: snapdata.cpp
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include "preDNSsn.h"
|
||
|
#include <SnapBase.h>
|
||
|
|
||
|
#include "resource.h"
|
||
|
#include "DNSSnap.h"
|
||
|
|
||
|
#include "dnsutil.h"
|
||
|
#include "snapdata.h"
|
||
|
#include "server.h"
|
||
|
#include "servwiz.h"
|
||
|
|
||
|
#include <prsht.h>
|
||
|
#include <svcguid.h>
|
||
|
|
||
|
#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<DWORD>(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)
|
||
|
{
|
||
|
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<IUnknown> spUnknown;
|
||
|
CComPtr<IMessageView> 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(UINT), &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(UINT), &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)
|
||
|
{
|
||
|
UINT nCount;
|
||
|
ULONG cbWrite;
|
||
|
// 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
|
||
|
ULONG nLen = static_cast<ULONG>(wcslen(GetDisplayName())+1); // WCHAR including NULL
|
||
|
VERIFY(SUCCEEDED(pStm->Write((void*)&nLen, sizeof(UINT),&cbWrite)));
|
||
|
ASSERT(cbWrite == sizeof(UINT));
|
||
|
VERIFY(SUCCEEDED(pStm->Write((void*)(GetDisplayName()), sizeof(WCHAR)*nLen,&cbWrite)));
|
||
|
ASSERT(cbWrite == sizeof(WCHAR)*nLen);
|
||
|
|
||
|
// write # of servers
|
||
|
nCount = (UINT)m_containerChildList.GetCount();
|
||
|
VERIFY(SUCCEEDED(pStm->Write((void*)&nCount, sizeof(UINT),&cbWrite)));
|
||
|
ASSERT(cbWrite == sizeof(UINT));
|
||
|
|
||
|
// 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()
|
||
|
{
|
||
|
return (IDCANCEL != DNSMessageBox(IDS_MSG_CONT_CLOSE_SHEET, MB_OKCANCEL));
|
||
|
}
|
||
|
|
||
|
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:
|
||
|
{
|
||
|
long serverCookie = (long)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:
|
||
|
{
|
||
|
long serverCookie = (long)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->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);
|
||
|
|
||
|
//
|
||
|
// Get the next data block from the query
|
||
|
//
|
||
|
iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL, &dwBufLen,
|
||
|
pBuffer);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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,
|
||
|
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;
|
||
|
}
|