Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1569 lines
41 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: snapdata.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "preDNSsn.h"
  11. #include <SnapBase.h>
  12. #include "resource.h"
  13. #include "DNSSnap.h"
  14. #include "dnsutil.h"
  15. #include "snapdata.h"
  16. #include "server.h"
  17. #include "servwiz.h"
  18. #include <prsht.h>
  19. #include <svcguid.h>
  20. #ifdef DEBUG_ALLOCATOR
  21. #ifdef _DEBUG
  22. #define new DEBUG_NEW
  23. #undef THIS_FILE
  24. static char THIS_FILE[] = __FILE__;
  25. #endif
  26. #endif
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // GLOBAL FUNCTIONS
  29. HRESULT SaveStringHelper(LPCWSTR pwsz, IStream* pStm)
  30. {
  31. ASSERT(pStm);
  32. ULONG nBytesWritten;
  33. HRESULT hr;
  34. DWORD nLen = static_cast<DWORD>(wcslen(pwsz)+1); // WCHAR including NULL
  35. hr = pStm->Write((void*)&nLen, sizeof(DWORD),&nBytesWritten);
  36. ASSERT(nBytesWritten == sizeof(DWORD));
  37. if (FAILED(hr))
  38. return hr;
  39. hr = pStm->Write((void*)pwsz, sizeof(WCHAR)*nLen,&nBytesWritten);
  40. ASSERT(nBytesWritten == sizeof(WCHAR)*nLen);
  41. TRACE(_T("SaveStringHelper(<%s> nLen = %d\n"),pwsz,nLen);
  42. return hr;
  43. }
  44. HRESULT LoadStringHelper(CString& sz, IStream* pStm)
  45. {
  46. ASSERT(pStm);
  47. HRESULT hr;
  48. ULONG nBytesRead;
  49. DWORD nLen = 0;
  50. hr = pStm->Read((void*)&nLen,sizeof(DWORD), &nBytesRead);
  51. ASSERT(nBytesRead == sizeof(DWORD));
  52. if (FAILED(hr) || (nBytesRead != sizeof(DWORD)))
  53. return hr;
  54. hr = pStm->Read((void*)sz.GetBuffer(nLen),sizeof(WCHAR)*nLen, &nBytesRead);
  55. ASSERT(nBytesRead == sizeof(WCHAR)*nLen);
  56. sz.ReleaseBuffer();
  57. TRACE(_T("LoadStringHelper(<%s> nLen = %d\n"),(LPCTSTR)sz,nLen);
  58. return hr;
  59. }
  60. HRESULT SaveDWordHelper(IStream* pStm, DWORD dw)
  61. {
  62. ULONG nBytesWritten;
  63. HRESULT hr = pStm->Write((void*)&dw, sizeof(DWORD),&nBytesWritten);
  64. if (nBytesWritten < sizeof(DWORD))
  65. hr = STG_E_CANTSAVE;
  66. return hr;
  67. }
  68. HRESULT LoadDWordHelper(IStream* pStm, DWORD* pdw)
  69. {
  70. ULONG nBytesRead;
  71. HRESULT hr = pStm->Read((void*)pdw,sizeof(DWORD), &nBytesRead);
  72. ASSERT(nBytesRead == sizeof(DWORD));
  73. return hr;
  74. }
  75. //////////////////////////////////////////////////////////////////////
  76. // CDNSQueryFilterPageBase
  77. class CDNSQueryFilterSheet; // fwd decl
  78. class CDNSQueryFilterPageBase : public CPropertyPage
  79. {
  80. public:
  81. CDNSQueryFilterPageBase(UINT nIDD, CDNSQueryFilterSheet* pSheet)
  82. : CPropertyPage(nIDD)
  83. {
  84. m_pSheet = pSheet;
  85. m_bDirty = FALSE;
  86. m_bInit = FALSE;
  87. }
  88. protected:
  89. CDNSQueryFilterSheet* m_pSheet;
  90. void SetDirty();
  91. void Init();
  92. BOOL IsDirty() { return m_bDirty;}
  93. virtual BOOL OnInitDialog();
  94. afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
  95. afx_msg void OnWhatsThis();
  96. afx_msg BOOL OnHelp(WPARAM wParam, LPARAM lParam);
  97. private:
  98. BOOL m_bInit;
  99. BOOL m_bDirty;
  100. HWND m_hWndWhatsThis; // hwnd of right click "What's this" help
  101. DECLARE_MESSAGE_MAP()
  102. };
  103. //////////////////////////////////////////////////////////////////////
  104. // CDNSQueryFilterNamePage
  105. class CDNSQueryFilterNamePage : public CDNSQueryFilterPageBase
  106. {
  107. public:
  108. CDNSQueryFilterNamePage(CDNSQueryFilterSheet* pSheet)
  109. : CDNSQueryFilterPageBase(IDD_FILTERING_NAME, pSheet)
  110. {
  111. }
  112. protected:
  113. virtual BOOL OnInitDialog();
  114. virtual BOOL OnApply();
  115. afx_msg void OnRadioClicked();
  116. afx_msg void OnEditChange();
  117. private:
  118. CEdit* GetStartsStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_STARTS);}
  119. CEdit* GetContainsStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_CONTAINS);}
  120. CEdit* GetRangeFromStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_RANGE_FROM);}
  121. CEdit* GetRangeToStringEdit() { return (CEdit*)GetDlgItem(IDC_EDIT_FILTER_RANGE_TO);}
  122. CButton* GetRadioNone() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_NONE);}
  123. CButton* GetRadioStarts() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_STARTS);}
  124. CButton* GetRadioContains() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_CONTAINS);}
  125. CButton* GetRadioRange() { return (CButton*)GetDlgItem(IDC_RADIO_FILTER_RANGE);}
  126. // utility methods
  127. UINT GetSelectedRadioButtonID();
  128. void SyncControls(UINT nRadioID);
  129. void GetEditText(UINT nID, CString& s);
  130. DECLARE_MESSAGE_MAP()
  131. };
  132. //////////////////////////////////////////////////////////////////////
  133. // CDNSQueryFilterAdvancedPage
  134. class CDNSQueryFilterAdvancedPage : public CDNSQueryFilterPageBase
  135. {
  136. public:
  137. CDNSQueryFilterAdvancedPage(CDNSQueryFilterSheet* pSheet)
  138. : CDNSQueryFilterPageBase(IDD_FILTERING_LIMITS, pSheet)
  139. {
  140. }
  141. protected:
  142. virtual BOOL OnInitDialog();
  143. virtual BOOL OnApply();
  144. afx_msg void OnCountEditChange();
  145. CDNSUnsignedIntEdit m_maxCountEdit;
  146. DECLARE_MESSAGE_MAP()
  147. };
  148. //////////////////////////////////////////////////////////////////////
  149. // CDNSQueryFilterSheet
  150. class CDNSQueryFilterSheet : public CPropertySheet
  151. {
  152. public:
  153. CDNSQueryFilterSheet(CDNSQueryFilter* pQueryFilter, CComponentDataObject* pComponentData)
  154. : CPropertySheet(IDS_SNAPIN_FILTERING_TITLE),
  155. m_namePage(this), m_advancedPage(this), m_pComponentData(pComponentData)
  156. {
  157. m_psh.dwFlags |= PSH_NOAPPLYNOW;
  158. m_pQueryFilter = pQueryFilter;
  159. AddPage(&m_namePage);
  160. AddPage(&m_advancedPage);
  161. m_bInit = FALSE;
  162. }
  163. CDNSQueryFilter* GetQueryFilter() { return m_pQueryFilter;}
  164. CComponentDataObject* GetComponentData() { return m_pComponentData; }
  165. void SetSheetStyle()
  166. {
  167. DWORD dwStyle = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
  168. dwStyle |= WS_EX_CONTEXTHELP; // force the [?] button
  169. ::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, dwStyle);
  170. }
  171. private:
  172. void Init()
  173. {
  174. if (m_bInit)
  175. return;
  176. m_bInit = TRUE;
  177. CWnd* p = GetDlgItem(IDOK);
  178. if (p)
  179. p->EnableWindow(FALSE);
  180. }
  181. void SetDirty()
  182. {
  183. if (!m_bInit)
  184. return;
  185. GetDlgItem(IDOK)->EnableWindow(TRUE);
  186. }
  187. BOOL m_bInit;
  188. CComponentDataObject* m_pComponentData;
  189. CDNSQueryFilter* m_pQueryFilter;
  190. CDNSQueryFilterNamePage m_namePage;
  191. CDNSQueryFilterAdvancedPage m_advancedPage;
  192. friend class CDNSQueryFilterPageBase;
  193. friend class CDNSQueryFilterNamePage;
  194. friend class CDNSQueryFilterAdvancedPage;
  195. };
  196. //////////////////////////////////////////////////////////////////////
  197. // CDNSQueryFilterPageBase IMPLEMENTATION
  198. BOOL CDNSQueryFilterPageBase::OnInitDialog()
  199. {
  200. BOOL bRet = CPropertyPage::OnInitDialog();
  201. m_pSheet->SetSheetStyle();
  202. return bRet;
  203. }
  204. void CDNSQueryFilterPageBase::SetDirty()
  205. {
  206. if (!m_bInit)
  207. return;
  208. m_bDirty = TRUE;
  209. m_pSheet->SetDirty();
  210. }
  211. void CDNSQueryFilterPageBase::Init()
  212. {
  213. m_bInit = TRUE;
  214. m_pSheet->Init();
  215. }
  216. BEGIN_MESSAGE_MAP(CDNSQueryFilterPageBase, CPropertyPage)
  217. ON_WM_CONTEXTMENU()
  218. ON_MESSAGE(WM_HELP, OnHelp)
  219. ON_COMMAND(IDM_WHATS_THIS, OnWhatsThis)
  220. END_MESSAGE_MAP()
  221. void CDNSQueryFilterPageBase::OnWhatsThis()
  222. {
  223. //
  224. // Display context help for a control
  225. //
  226. if ( m_hWndWhatsThis )
  227. {
  228. //
  229. // Build our own HELPINFO struct to pass to the underlying
  230. // CS help functions built into the framework
  231. //
  232. int iCtrlID = ::GetDlgCtrlID(m_hWndWhatsThis);
  233. HELPINFO helpInfo;
  234. ZeroMemory(&helpInfo, sizeof(HELPINFO));
  235. helpInfo.cbSize = sizeof(HELPINFO);
  236. helpInfo.hItemHandle = m_hWndWhatsThis;
  237. helpInfo.iCtrlId = iCtrlID;
  238. m_pSheet->GetComponentData()->OnDialogContextHelp(m_nIDHelp, &helpInfo);
  239. }
  240. }
  241. BOOL CDNSQueryFilterPageBase::OnHelp(WPARAM /*wParam*/, LPARAM lParam)
  242. {
  243. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  244. if (pHelpInfo && pHelpInfo->iContextType == HELPINFO_WINDOW)
  245. {
  246. //
  247. // Display context help for a control
  248. //
  249. m_pSheet->GetComponentData()->OnDialogContextHelp(m_nIDHelp, pHelpInfo);
  250. }
  251. return TRUE;
  252. }
  253. void CDNSQueryFilterPageBase::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
  254. {
  255. //
  256. // point is in screen coordinates
  257. //
  258. CMenu bar;
  259. if ( bar.LoadMenu(IDR_WHATS_THIS_CONTEXT_MENU1) )
  260. {
  261. CMenu& popup = *bar.GetSubMenu (0);
  262. ASSERT(popup.m_hMenu);
  263. if ( popup.TrackPopupMenu (TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
  264. point.x, // in screen coordinates
  265. point.y, // in screen coordinates
  266. this) ) // route commands through main window
  267. {
  268. m_hWndWhatsThis = 0;
  269. ScreenToClient (&point);
  270. CWnd* pChild = ChildWindowFromPoint (point, // in client coordinates
  271. CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
  272. if ( pChild )
  273. {
  274. m_hWndWhatsThis = pChild->m_hWnd;
  275. }
  276. }
  277. }
  278. }
  279. //////////////////////////////////////////////////////////////////////
  280. // CDNSQueryFilterNamePage IMPLEMENTATION
  281. BEGIN_MESSAGE_MAP(CDNSQueryFilterNamePage, CDNSQueryFilterPageBase)
  282. ON_BN_CLICKED(IDC_RADIO_FILTER_NONE, OnRadioClicked)
  283. ON_BN_CLICKED(IDC_RADIO_FILTER_STARTS, OnRadioClicked)
  284. ON_BN_CLICKED(IDC_RADIO_FILTER_CONTAINS, OnRadioClicked)
  285. ON_BN_CLICKED(IDC_RADIO_FILTER_RANGE, OnRadioClicked)
  286. ON_EN_CHANGE(IDC_EDIT_FILTER_STARTS, OnEditChange)
  287. ON_EN_CHANGE(IDC_EDIT_FILTER_CONTAINS, OnEditChange)
  288. ON_EN_CHANGE(IDC_EDIT_FILTER_RANGE_FROM, OnEditChange)
  289. ON_EN_CHANGE(IDC_EDIT_FILTER_RANGE_TO, OnEditChange)
  290. END_MESSAGE_MAP()
  291. UINT CDNSQueryFilterNamePage::GetSelectedRadioButtonID()
  292. {
  293. return GetCheckedRadioButton(IDC_RADIO_FILTER_NONE, IDC_RADIO_FILTER_RANGE);
  294. }
  295. void CDNSQueryFilterNamePage::OnRadioClicked()
  296. {
  297. UINT nRadioID = GetSelectedRadioButtonID();
  298. SyncControls(nRadioID);
  299. }
  300. void CDNSQueryFilterNamePage::SyncControls(UINT nRadioID)
  301. {
  302. BOOL bStartsStringEditEnabled = FALSE;
  303. BOOL bContainsStringEditEnabled = FALSE;
  304. BOOL bRangeEnabled = FALSE;
  305. if (nRadioID == IDC_RADIO_FILTER_STARTS)
  306. {
  307. bStartsStringEditEnabled = TRUE;
  308. }
  309. else if (nRadioID == IDC_RADIO_FILTER_CONTAINS)
  310. {
  311. bContainsStringEditEnabled = TRUE;
  312. }
  313. else if (nRadioID == IDC_RADIO_FILTER_RANGE)
  314. {
  315. bRangeEnabled = TRUE;
  316. }
  317. GetStartsStringEdit()->SetReadOnly(!bStartsStringEditEnabled);
  318. GetContainsStringEdit()->SetReadOnly(!bContainsStringEditEnabled);
  319. GetRangeFromStringEdit()->SetReadOnly(!bRangeEnabled);
  320. GetRangeToStringEdit()->SetReadOnly(!bRangeEnabled);
  321. SetDirty();
  322. }
  323. void CDNSQueryFilterNamePage::GetEditText(UINT nID, CString& s)
  324. {
  325. GetDlgItemText(nID, s);
  326. s.TrimLeft();
  327. s.TrimRight();
  328. }
  329. void CDNSQueryFilterNamePage::OnEditChange()
  330. {
  331. SetDirty();
  332. }
  333. BOOL CDNSQueryFilterNamePage::OnInitDialog()
  334. {
  335. CDNSQueryFilterPageBase::OnInitDialog();
  336. // write data to edit fields
  337. SetDlgItemText(IDC_EDIT_FILTER_STARTS, m_pSheet->m_pQueryFilter->m_szStartsString);
  338. SetDlgItemText(IDC_EDIT_FILTER_CONTAINS, m_pSheet->m_pQueryFilter->m_szContainsString);
  339. SetDlgItemText(IDC_EDIT_FILTER_RANGE_FROM, m_pSheet->m_pQueryFilter->m_szRangeFrom);
  340. SetDlgItemText(IDC_EDIT_FILTER_RANGE_TO, m_pSheet->m_pQueryFilter->m_szRangeTo);
  341. // set the radio buttons
  342. UINT nRadioID = IDC_RADIO_FILTER_NONE;
  343. switch(m_pSheet->m_pQueryFilter->m_nFilterOption)
  344. {
  345. case DNS_QUERY_FILTER_NONE:
  346. {
  347. GetRadioNone()->SetCheck(TRUE);
  348. nRadioID = IDC_RADIO_FILTER_NONE;
  349. }
  350. break;
  351. case DNS_QUERY_FILTER_STARTS:
  352. {
  353. GetRadioStarts()->SetCheck(TRUE);
  354. nRadioID = IDC_RADIO_FILTER_STARTS;
  355. }
  356. break;
  357. case DNS_QUERY_FILTER_CONTAINS:
  358. {
  359. GetRadioContains()->SetCheck(TRUE);
  360. nRadioID = IDC_RADIO_FILTER_CONTAINS;
  361. }
  362. break;
  363. case DNS_QUERY_FILTER_RANGE:
  364. {
  365. GetRadioRange()->SetCheck(TRUE);
  366. nRadioID = IDC_RADIO_FILTER_RANGE;
  367. }
  368. break;
  369. default:
  370. ASSERT(FALSE);
  371. }
  372. // enable/disable the edit fields
  373. SyncControls(nRadioID);
  374. Init();
  375. return TRUE; // return TRUE unless you set the focus to a control
  376. }
  377. BOOL CDNSQueryFilterNamePage::OnApply()
  378. {
  379. if (!IsDirty())
  380. return TRUE;
  381. UINT nRadioID = GetSelectedRadioButtonID();
  382. // get data from edit controls
  383. GetEditText(IDC_EDIT_FILTER_STARTS, m_pSheet->m_pQueryFilter->m_szStartsString);
  384. GetEditText(IDC_EDIT_FILTER_CONTAINS, m_pSheet->m_pQueryFilter->m_szContainsString);
  385. GetEditText(IDC_EDIT_FILTER_RANGE_FROM, m_pSheet->m_pQueryFilter->m_szRangeFrom);
  386. GetEditText(IDC_EDIT_FILTER_RANGE_TO, m_pSheet->m_pQueryFilter->m_szRangeTo);
  387. // get radio button selection
  388. switch(nRadioID)
  389. {
  390. case IDC_RADIO_FILTER_NONE:
  391. {
  392. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE;
  393. }
  394. break;
  395. case IDC_RADIO_FILTER_STARTS:
  396. {
  397. if (m_pSheet->m_pQueryFilter->m_szStartsString.IsEmpty())
  398. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE;
  399. else
  400. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_STARTS;
  401. }
  402. break;
  403. case IDC_RADIO_FILTER_CONTAINS:
  404. {
  405. if (m_pSheet->m_pQueryFilter->m_szContainsString.IsEmpty())
  406. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE;
  407. else
  408. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_CONTAINS;
  409. }
  410. break;
  411. case IDC_RADIO_FILTER_RANGE:
  412. {
  413. if (m_pSheet->m_pQueryFilter->m_szRangeFrom.IsEmpty() &&
  414. m_pSheet->m_pQueryFilter->m_szRangeTo.IsEmpty() )
  415. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_NONE;
  416. else
  417. m_pSheet->m_pQueryFilter->m_nFilterOption = DNS_QUERY_FILTER_RANGE;
  418. }
  419. break;
  420. default:
  421. ASSERT(FALSE);
  422. }
  423. return TRUE;
  424. }
  425. //////////////////////////////////////////////////////////////////////
  426. // CDNSQueryFilterAdvancedPage IMPLEMENTATION
  427. BEGIN_MESSAGE_MAP(CDNSQueryFilterAdvancedPage, CDNSQueryFilterPageBase)
  428. ON_EN_CHANGE(IDC_EDIT_COUNT, OnCountEditChange)
  429. END_MESSAGE_MAP()
  430. void CDNSQueryFilterAdvancedPage::OnCountEditChange()
  431. {
  432. SetDirty();
  433. }
  434. BOOL CDNSQueryFilterAdvancedPage::OnInitDialog()
  435. {
  436. CDNSQueryFilterPageBase::OnInitDialog();
  437. // set the range of the edit control for range validation
  438. VERIFY(m_maxCountEdit.SubclassDlgItem(IDC_EDIT_COUNT, this));
  439. m_maxCountEdit.SetRange(DNS_QUERY_OBJ_COUNT_MIN, DNS_QUERY_OBJ_COUNT_MAX);
  440. // Disable IME support on the control
  441. ImmAssociateContext(m_maxCountEdit.GetSafeHwnd(), NULL);
  442. // set limit on the # of digits based on the max value
  443. CString s;
  444. s.Format(_T("%u"), DNS_QUERY_OBJ_COUNT_MAX);
  445. m_maxCountEdit.LimitText(s.GetLength());
  446. // set the value
  447. m_maxCountEdit.SetVal(m_pSheet->m_pQueryFilter->m_nMaxObjectCount);
  448. Init();
  449. return TRUE;
  450. }
  451. BOOL CDNSQueryFilterAdvancedPage::OnApply()
  452. {
  453. if (!IsDirty())
  454. return TRUE;
  455. m_pSheet->m_pQueryFilter->m_nMaxObjectCount = m_maxCountEdit.GetVal();
  456. return TRUE;
  457. }
  458. //////////////////////////////////////////////////////////////////////
  459. // CDNSQueryFilter
  460. BOOL CDNSQueryFilter::EditFilteringOptions(CComponentDataObject* pComponentData)
  461. {
  462. CDNSQueryFilterSheet dlg(this, pComponentData);
  463. return IDOK == dlg.DoModal();
  464. }
  465. HRESULT CDNSQueryFilter::Load(IStream* pStm)
  466. {
  467. HRESULT hr;
  468. // name filtering
  469. if (FAILED(hr = LoadDWordHelper(pStm, (DWORD*)(&m_nFilterOption))))
  470. return hr;
  471. if (FAILED(hr = LoadStringHelper(m_szStartsString, pStm)))
  472. return hr;
  473. if (FAILED(hr = LoadStringHelper(m_szContainsString, pStm)))
  474. return hr;
  475. if (FAILED(hr = LoadStringHelper(m_szRangeFrom, pStm)))
  476. return hr;
  477. if (FAILED(hr = LoadStringHelper(m_szRangeTo, pStm)))
  478. return hr;
  479. // query limit
  480. if (FAILED(hr = LoadDWordHelper(pStm, (DWORD*)(&m_nMaxObjectCount))))
  481. return hr;
  482. return LoadDWordHelper(pStm, (DWORD*)(&m_bGetAll));
  483. }
  484. HRESULT CDNSQueryFilter::Save(IStream* pStm)
  485. {
  486. HRESULT hr;
  487. // name filtering
  488. if (FAILED(hr = SaveDWordHelper(pStm, (DWORD)m_nFilterOption)))
  489. return hr;
  490. if (FAILED(hr = SaveStringHelper(m_szStartsString, pStm)))
  491. return hr;
  492. if (FAILED(hr = SaveStringHelper(m_szContainsString, pStm)))
  493. return hr;
  494. if (FAILED(hr = SaveStringHelper(m_szRangeFrom, pStm)))
  495. return hr;
  496. if (FAILED(hr = SaveStringHelper(m_szRangeTo, pStm)))
  497. return hr;
  498. // query limit
  499. if (FAILED(hr = SaveDWordHelper(pStm, (DWORD)(m_nMaxObjectCount))))
  500. return hr;
  501. return SaveDWordHelper(pStm, (DWORD)(m_bGetAll));
  502. }
  503. //////////////////////////////////////////////////////////////////////
  504. // CDNSRootData
  505. const GUID CDNSRootData::NodeTypeGUID =
  506. { 0x2faebfa3, 0x3f1a, 0x11d0, { 0x8c, 0x65, 0x0, 0xc0, 0x4f, 0xd8, 0xfe, 0xcb } };
  507. BEGIN_TOOLBAR_MAP(CDNSRootData)
  508. TOOLBAR_EVENT(toolbarNewServer, OnConnectToServer)
  509. END_TOOLBAR_MAP()
  510. CDNSRootData::CDNSRootData(CComponentDataObject* pComponentData) : CRootData(pComponentData)
  511. {
  512. m_bAdvancedView = FALSE;
  513. m_pColumnSet = NULL;
  514. m_szDescriptionBar = _T("");
  515. m_bCreatePTRWithHost = FALSE;
  516. }
  517. CDNSRootData::~CDNSRootData()
  518. {
  519. TRACE(_T("~CDNSRootData(), name <%s>\n"),GetDisplayName());
  520. }
  521. STDAPI DnsSetup(LPCWSTR lpszFwdZoneName,
  522. LPCWSTR lpszFwdZoneFileName,
  523. LPCWSTR lpszRevZoneName,
  524. LPCWSTR lpszRevZoneFileName,
  525. DWORD dwFlags);
  526. BOOL CDNSRootData::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem2,
  527. long*)
  528. {
  529. CComponentDataObject* pComponentData = GetComponentDataObject();
  530. if (pContextMenuItem2->lCommandID == IDM_SNAPIN_CONNECT_TO_SERVER)
  531. {
  532. ASSERT(pComponentData != NULL);
  533. if (pComponentData->IsExtensionSnapin())
  534. return FALSE; // extensions do not have this menu item
  535. return TRUE;
  536. }
  537. // add toggle menu item for advanced view
  538. if (pContextMenuItem2->lCommandID == IDM_SNAPIN_ADVANCED_VIEW)
  539. {
  540. pContextMenuItem2->fFlags = IsAdvancedView() ? MF_CHECKED : 0;
  541. }
  542. if (pContextMenuItem2->lCommandID == IDM_SNAPIN_FILTERING)
  543. {
  544. if (IsFilteringEnabled())
  545. {
  546. pContextMenuItem2->fFlags = MF_CHECKED;
  547. }
  548. return TRUE;
  549. }
  550. return TRUE;
  551. }
  552. HRESULT CDNSRootData::GetResultViewType(CComponentDataObject*,
  553. LPOLESTR *ppViewType,
  554. long *pViewOptions)
  555. {
  556. HRESULT hr = S_FALSE;
  557. if (m_containerChildList.IsEmpty() && m_leafChildList.IsEmpty())
  558. {
  559. *pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
  560. LPOLESTR psz = NULL;
  561. StringFromCLSID(CLSID_MessageView, &psz);
  562. USES_CONVERSION;
  563. if (psz != NULL)
  564. {
  565. *ppViewType = psz;
  566. hr = S_OK;
  567. }
  568. }
  569. else
  570. {
  571. *pViewOptions = MMC_VIEW_OPTIONS_NONE;
  572. *ppViewType = NULL;
  573. hr = S_FALSE;
  574. }
  575. return hr;
  576. }
  577. HRESULT CDNSRootData::OnShow(LPCONSOLE lpConsole)
  578. {
  579. CComPtr<IUnknown> spUnknown;
  580. CComPtr<IMessageView> spMessageView;
  581. HRESULT hr = lpConsole->QueryResultView(&spUnknown);
  582. if (FAILED(hr))
  583. return S_OK;
  584. hr = spUnknown->QueryInterface(IID_IMessageView, (PVOID*)&spMessageView);
  585. if (SUCCEEDED(hr))
  586. {
  587. // Load and set the title text of the message view
  588. CString szTitle;
  589. VERIFY(szTitle.LoadString(IDS_MESSAGE_VIEW_NO_SERVER_TITLE));
  590. spMessageView->SetTitleText(szTitle);
  591. // Load and set the body text of the message view
  592. CString szMessage;
  593. VERIFY(szMessage.LoadString(IDS_MESSAGE_VIEW_NO_SERVER_MESSAGE));
  594. spMessageView->SetBodyText(szMessage);
  595. // Use the standard information icon
  596. spMessageView->SetIcon(Icon_Information);
  597. }
  598. return S_OK;
  599. }
  600. BOOL CDNSRootData::IsFilteringEnabled()
  601. {
  602. UINT nFilterOption = GetFilter()->GetFilterOption();
  603. if (nFilterOption == DNS_QUERY_FILTER_DISABLED || nFilterOption == DNS_QUERY_FILTER_NONE)
  604. {
  605. return FALSE;
  606. }
  607. return TRUE;
  608. }
  609. BOOL CDNSRootData::OnSetRefreshVerbState(DATA_OBJECT_TYPES,
  610. BOOL* pbHide,
  611. CNodeList*)
  612. {
  613. *pbHide = FALSE;
  614. return !IsThreadLocked();
  615. }
  616. HRESULT CDNSRootData::OnSetToolbarVerbState(IToolbar* pToolbar,
  617. CNodeList*)
  618. {
  619. HRESULT hr = S_OK;
  620. //
  621. // Set the button state for each button on the toolbar
  622. //
  623. hr = pToolbar->SetButtonState(toolbarNewServer, ENABLED, TRUE);
  624. ASSERT(SUCCEEDED(hr));
  625. hr = pToolbar->SetButtonState(toolbarNewRecord, ENABLED, FALSE);
  626. ASSERT(SUCCEEDED(hr));
  627. hr = pToolbar->SetButtonState(toolbarNewZone, ENABLED, FALSE);
  628. ASSERT(SUCCEEDED(hr));
  629. return hr;
  630. }
  631. HRESULT CDNSRootData::OnCommand(long nCommandID,
  632. DATA_OBJECT_TYPES,
  633. CComponentDataObject* pComponentData,
  634. CNodeList* pNodeList)
  635. {
  636. if (pNodeList->GetCount() > 1) // multiple selection
  637. {
  638. return E_FAIL;
  639. }
  640. switch (nCommandID)
  641. {
  642. case IDM_SNAPIN_CONNECT_TO_SERVER:
  643. OnConnectToServer(pComponentData, pNodeList);
  644. break;
  645. case IDM_SNAPIN_ADVANCED_VIEW:
  646. OnViewOptions(pComponentData);
  647. break;
  648. case IDM_SNAPIN_FILTERING:
  649. {
  650. if (OnFilteringOptions(pComponentData))
  651. {
  652. pComponentData->SetDescriptionBarText(this);
  653. }
  654. }
  655. break;
  656. default:
  657. ASSERT(FALSE); // Unknown command!
  658. return E_FAIL;
  659. }
  660. return S_OK;
  661. }
  662. BOOL CDNSRootData::OnEnumerate(CComponentDataObject* pComponentData, BOOL)
  663. {
  664. if (m_containerChildList.IsEmpty())
  665. {
  666. // the list is empty, need to add
  667. ASSERT(pComponentData != NULL);
  668. // create a modal dialog + possibly the wizard proper
  669. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  670. CDNSServerWizardHolder holder(this, pComponentData, NULL);
  671. holder.DoModalConnectOnLocalComputer();
  672. return FALSE;
  673. }
  674. return TRUE; // there are already children, add them to the UI now
  675. }
  676. #define DNS_STREAM_VERSION_W2K ((DWORD)0x06)
  677. #define DNS_STREAM_VERSION ((DWORD)0x07)
  678. // IStream manipulation helpers overrides
  679. HRESULT CDNSRootData::Load(IStream* pStm)
  680. {
  681. // assume never get multiple loads
  682. if(!m_containerChildList.IsEmpty() || !m_leafChildList.IsEmpty())
  683. return E_FAIL;
  684. WCHAR szBuffer[256];
  685. ULONG nLen; // WCHAR counting NULL
  686. UINT nCount;
  687. ULONG cbRead;
  688. // read the version ##
  689. DWORD dwVersion;
  690. VERIFY(SUCCEEDED(pStm->Read((void*)&dwVersion,sizeof(DWORD), &cbRead)));
  691. ASSERT(cbRead == sizeof(DWORD));
  692. if (dwVersion != DNS_STREAM_VERSION && dwVersion != DNS_STREAM_VERSION_W2K)
  693. return E_FAIL;
  694. // load filtering options
  695. VERIFY(SUCCEEDED(m_filterObj.Load(pStm)));
  696. // load view option
  697. VERIFY(SUCCEEDED(pStm->Read((void*)&m_bAdvancedView,sizeof(BOOL), &cbRead)));
  698. ASSERT(cbRead == sizeof(BOOL));
  699. //
  700. // load the Create PTR record with host flag
  701. //
  702. if (dwVersion > DNS_STREAM_VERSION_W2K)
  703. {
  704. VERIFY(SUCCEEDED(pStm->Read((void*)&m_bCreatePTRWithHost,sizeof(BOOL), &cbRead)));
  705. ASSERT(cbRead == sizeof(BOOL));
  706. }
  707. // load the name of the snapin root display string
  708. VERIFY(SUCCEEDED(pStm->Read((void*)&nLen,sizeof(UINT), &cbRead)));
  709. ASSERT(cbRead == sizeof(UINT));
  710. VERIFY(SUCCEEDED(pStm->Read((void*)szBuffer,sizeof(WCHAR)*nLen, &cbRead)));
  711. ASSERT(cbRead == sizeof(WCHAR)*nLen);
  712. SetDisplayName(szBuffer);
  713. // load the list of servers
  714. VERIFY(SUCCEEDED(pStm->Read((void*)&nCount,sizeof(UINT), &cbRead)));
  715. ASSERT(cbRead == sizeof(UINT));
  716. CComponentDataObject* pComponentData = GetComponentDataObject();
  717. for (int k=0; k< (int)nCount; k++)
  718. {
  719. CDNSServerNode* p = NULL;
  720. VERIFY(SUCCEEDED(CDNSServerNode::CreateFromStream(pStm, &p)));
  721. ASSERT(p != NULL);
  722. VERIFY(AddChildToList(p));
  723. AddServerToThreadList(p, pComponentData);
  724. }
  725. if (nCount > 0)
  726. MarkEnumerated();
  727. ASSERT(m_containerChildList.GetCount() == (int)nCount);
  728. return S_OK;
  729. }
  730. HRESULT CDNSRootData::Save(IStream* pStm, BOOL fClearDirty)
  731. {
  732. UINT nCount;
  733. ULONG cbWrite;
  734. // write the version ##
  735. DWORD dwVersion = DNS_STREAM_VERSION;
  736. VERIFY(SUCCEEDED(pStm->Write((void*)&dwVersion, sizeof(DWORD),&cbWrite)));
  737. ASSERT(cbWrite == sizeof(DWORD));
  738. // save filtering options
  739. VERIFY(SUCCEEDED(m_filterObj.Save(pStm)));
  740. // save view options
  741. VERIFY(SUCCEEDED(pStm->Write((void*)&m_bAdvancedView, sizeof(BOOL),&cbWrite)));
  742. ASSERT(cbWrite == sizeof(BOOL));
  743. //
  744. // save the create PTR record with host flag
  745. //
  746. VERIFY(SUCCEEDED(pStm->Write((void*)&m_bCreatePTRWithHost, sizeof(BOOL),&cbWrite)));
  747. ASSERT(cbWrite == sizeof(BOOL));
  748. // save the name of the snapin root display string
  749. ULONG nLen = static_cast<ULONG>(wcslen(GetDisplayName())+1); // WCHAR including NULL
  750. VERIFY(SUCCEEDED(pStm->Write((void*)&nLen, sizeof(UINT),&cbWrite)));
  751. ASSERT(cbWrite == sizeof(UINT));
  752. VERIFY(SUCCEEDED(pStm->Write((void*)(GetDisplayName()), sizeof(WCHAR)*nLen,&cbWrite)));
  753. ASSERT(cbWrite == sizeof(WCHAR)*nLen);
  754. // write # of servers
  755. nCount = (UINT)m_containerChildList.GetCount();
  756. VERIFY(SUCCEEDED(pStm->Write((void*)&nCount, sizeof(UINT),&cbWrite)));
  757. ASSERT(cbWrite == sizeof(UINT));
  758. // loop through the list of servers and serialize them
  759. POSITION pos;
  760. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  761. {
  762. CDNSServerNode* pServerNode = (CDNSServerNode*)m_containerChildList.GetNext(pos);
  763. VERIFY(SUCCEEDED(pServerNode->SaveToStream(pStm)));
  764. }
  765. if (fClearDirty)
  766. SetDirtyFlag(FALSE);
  767. return S_OK;
  768. }
  769. HRESULT CDNSRootData::IsDirty()
  770. {
  771. return CRootData::IsDirty();
  772. }
  773. HRESULT CDNSRootData::OnConnectToServer(CComponentDataObject* pComponentData,
  774. CNodeList*)
  775. {
  776. ASSERT(pComponentData != NULL);
  777. // create a modal dialog + possibly the wizard proper
  778. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  779. CDNSServerWizardHolder holder(this, pComponentData, NULL);
  780. holder.DoModalConnect();
  781. pComponentData->UpdateResultPaneView(this);
  782. return S_OK;
  783. }
  784. void CDNSRootData::AddServer(CDNSServerNode* p, CComponentDataObject* pComponentData)
  785. {
  786. ASSERT(p != NULL);
  787. AddChildToListAndUISorted(p, pComponentData);
  788. AddServerToThreadList(p, pComponentData);
  789. pComponentData->UpdateResultPaneView(this);
  790. pComponentData->SetDescriptionBarText(this);
  791. }
  792. BOOL CDNSRootData::VerifyServerName(LPCTSTR lpszServerName)
  793. {
  794. POSITION pos;
  795. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  796. {
  797. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  798. ASSERT(pNode->IsContainer());
  799. //
  800. // case insensitive compare
  801. //
  802. if (_wcsicmp(pNode->GetDisplayName(), lpszServerName) == 0)
  803. {
  804. return FALSE;
  805. }
  806. }
  807. return TRUE;
  808. }
  809. BOOL CDNSRootData::OnViewOptions(CComponentDataObject* pComponentData)
  810. {
  811. // make sure there are not property sheets up: we do this because:
  812. // a) some folders might be removed and might have sheets up
  813. // b) some RR property pages (PTR) might not be switchable
  814. // on the fly between view types
  815. if (IsSheetLocked())
  816. {
  817. if (!CanCloseSheets())
  818. return TRUE;
  819. pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this);
  820. }
  821. ASSERT(!IsSheetLocked());
  822. // toggle the view state
  823. m_bAdvancedView = !m_bAdvancedView;
  824. // loop through the servers
  825. POSITION pos;
  826. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  827. {
  828. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  829. ASSERT(pNode->IsContainer());
  830. CDNSServerNode* pServerNode = (CDNSServerNode*)pNode;
  831. // pass the new view option
  832. pServerNode->ChangeViewOption(m_bAdvancedView, pComponentData);
  833. }
  834. // dirty the MMC document
  835. SetDirtyFlag(TRUE);
  836. return TRUE;
  837. }
  838. BOOL CDNSRootData::OnFilteringOptions(CComponentDataObject* pComponentData)
  839. {
  840. BOOL bRet = m_filterObj.EditFilteringOptions(pComponentData);
  841. if (bRet)
  842. {
  843. SetDirtyFlag(TRUE);
  844. }
  845. return bRet;
  846. }
  847. BOOL CDNSRootData::CanCloseSheets()
  848. {
  849. return (IDCANCEL != DNSMessageBox(IDS_MSG_CONT_CLOSE_SHEET, MB_OKCANCEL));
  850. }
  851. BOOL CDNSRootData::OnRefresh(CComponentDataObject* pComponentData,
  852. CNodeList* pNodeList)
  853. {
  854. if (pNodeList->GetCount() > 1) // multiple selection
  855. {
  856. BOOL bRet = TRUE;
  857. POSITION pos = pNodeList->GetHeadPosition();
  858. while (pos != NULL)
  859. {
  860. CTreeNode* pNode = pNodeList->GetNext(pos);
  861. ASSERT(pNode != NULL);
  862. CNodeList nodeList;
  863. nodeList.AddTail(pNode);
  864. if (!pNode->OnRefresh(pComponentData, &nodeList))
  865. {
  866. bRet = FALSE;
  867. }
  868. }
  869. return bRet;
  870. }
  871. if (IsSheetLocked())
  872. {
  873. if (!CanCloseSheets())
  874. return FALSE;
  875. pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this);
  876. }
  877. ASSERT(!IsSheetLocked());
  878. POSITION pos;
  879. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  880. {
  881. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  882. ASSERT(pNode->IsContainer());
  883. CNodeList nodeList;
  884. nodeList.AddTail(pNode);
  885. ((CDNSServerNode*)pNode)->OnRefresh(pComponentData, &nodeList);
  886. }
  887. return TRUE;
  888. }
  889. LPWSTR CDNSRootData::GetDescriptionBarText()
  890. {
  891. static CString szFilterEnabled;
  892. static CString szServersFormat;
  893. INT_PTR nContainerCount = GetContainerChildList()->GetCount();
  894. INT_PTR nLeafCount = GetLeafChildList()->GetCount();
  895. //
  896. // If not already loaded, then load the format string L"%d record(s)"
  897. //
  898. if (szServersFormat.IsEmpty())
  899. {
  900. szServersFormat.LoadString(IDS_FORMAT_SERVERS);
  901. }
  902. //
  903. // Format the child count into the description bar text
  904. //
  905. m_szDescriptionBar.Format(szServersFormat, nContainerCount + nLeafCount);
  906. //
  907. // Add L"[Filter Activated]" if the filter is on
  908. //
  909. if(IsFilteringEnabled())
  910. {
  911. //
  912. // If not already loaded, then load the L"[Filter Activated]" string
  913. //
  914. if (szFilterEnabled.IsEmpty())
  915. {
  916. szFilterEnabled.LoadString(IDS_FILTER_ENABLED);
  917. }
  918. m_szDescriptionBar += szFilterEnabled;
  919. }
  920. return (LPWSTR)(LPCWSTR)m_szDescriptionBar;
  921. }
  922. void CDNSRootData::TestServers(DWORD dwCurrTime, DWORD dwTimeInterval,
  923. CComponentDataObject* pComponentData)
  924. {
  925. //TRACE(_T("CDNSRootData::TestServers()\n"));
  926. POSITION pos;
  927. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  928. {
  929. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  930. ASSERT(pNode->IsContainer());
  931. CDNSServerNode* pServerNode = (CDNSServerNode*)pNode;
  932. if (pServerNode->IsTestEnabled() && !pServerNode->m_bTestQueryPending
  933. && (pServerNode->m_dwTestTime <= dwCurrTime))
  934. {
  935. DWORD dwQueryFlags =
  936. CDNSServerTestQueryResult::Pack(pServerNode->IsTestSimpleQueryEnabled(),
  937. pServerNode->IsRecursiveQueryEnabled());
  938. pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_SEND_QUERY,
  939. (WPARAM)pServerNode,
  940. (WPARAM)dwQueryFlags);
  941. pServerNode->m_dwTestTime = dwCurrTime + pServerNode->GetTestInterval();
  942. }
  943. }
  944. // check if the time counter has wrapped (it should be very unlikely, because
  945. // the timeline is on a DWORD in seconds (about 47000 days) from the console startup.
  946. if ((dwCurrTime + dwTimeInterval) < dwCurrTime)
  947. {
  948. // just reset the whole set of server times (not accurate, but acceptable)
  949. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  950. {
  951. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  952. ASSERT(pNode->IsContainer());
  953. CDNSServerNode* pServerNode = (CDNSServerNode*)pNode;
  954. pServerNode->m_dwTestTime = 0;
  955. }
  956. }
  957. }
  958. void CDNSRootData::OnServerTestData(WPARAM wParam, LPARAM lParam, CComponentDataObject* pComponentData)
  959. {
  960. ASSERT(lParam == 0);
  961. CDNSServerTestQueryResult* pTestResult = (CDNSServerTestQueryResult*)wParam;
  962. ASSERT(pTestResult != NULL);
  963. // loop through the list of servers to find where it belongs
  964. POSITION pos;
  965. for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; )
  966. {
  967. CTreeNode* pNode = m_containerChildList.GetNext(pos);
  968. ASSERT(pNode->IsContainer());
  969. CDNSServerNode* pServerNode = (CDNSServerNode*)pNode;
  970. if ( (CDNSServerNode*)(pTestResult->m_serverCookie) == pServerNode)
  971. {
  972. pServerNode->AddTestQueryResult(pTestResult, pComponentData);
  973. return;
  974. }
  975. }
  976. }
  977. void CDNSRootData::AddServerToThreadList(CDNSServerNode* pServerNode,
  978. CComponentDataObject* pComponentData)
  979. {
  980. CDNSServerTestQueryInfo* pInfo = new CDNSServerTestQueryInfo;
  981. if (pInfo)
  982. {
  983. pInfo->m_szServerName = pServerNode->GetDisplayName();
  984. pInfo->m_serverCookie = (MMC_COOKIE)pServerNode;
  985. pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_ADD_SERVER, (WPARAM)pInfo,0);
  986. }
  987. }
  988. void CDNSRootData::RemoveServerFromThreadList(CDNSServerNode* pServerNode,
  989. CComponentDataObject* pComponentData)
  990. {
  991. WPARAM serverCookie = (WPARAM)pServerNode;
  992. pComponentData->PostMessageToTimerThread(WM_TIMER_THREAD_REMOVE_SERVER, serverCookie,0);
  993. }
  994. ///////////////////////////////////////////////////////////////////
  995. // CDNSServerTestTimerThread
  996. int CDNSServerTestTimerThread::Run()
  997. {
  998. MSG msg;
  999. // initialize the message pump
  1000. ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1001. // get let the main thread know we are entering the loop
  1002. // (0,0) means just acknowkedge
  1003. PostMessageToWnd(0,0);
  1004. while(::GetMessage(&msg, NULL, 0, 0))
  1005. {
  1006. switch(msg.message)
  1007. {
  1008. case WM_TIMER_THREAD_SEND_QUERY:
  1009. case WM_TIMER_THREAD_SEND_QUERY_TEST_NOW:
  1010. {
  1011. long serverCookie = (long)msg.wParam;
  1012. ASSERT(serverCookie != NULL);
  1013. POSITION pos;
  1014. for (pos = m_serverInfoList.GetHeadPosition(); pos != NULL; )
  1015. {
  1016. CDNSServerTestQueryInfo* pCurrInfo =
  1017. (CDNSServerTestQueryInfo*)m_serverInfoList.GetNext(pos);
  1018. if (serverCookie == pCurrInfo->m_serverCookie)
  1019. {
  1020. OnExecuteQuery(pCurrInfo, (DWORD)msg.lParam,
  1021. (msg.message == WM_TIMER_THREAD_SEND_QUERY_TEST_NOW));
  1022. break;
  1023. }
  1024. }
  1025. }
  1026. break;
  1027. case WM_TIMER_THREAD_ADD_SERVER:
  1028. {
  1029. CDNSServerTestQueryInfo* pInfo = (CDNSServerTestQueryInfo*)msg.wParam;
  1030. ASSERT(pInfo != NULL);
  1031. m_serverInfoList.AddTail(pInfo);
  1032. }
  1033. break;
  1034. case WM_TIMER_THREAD_REMOVE_SERVER:
  1035. {
  1036. long serverCookie = (long)msg.wParam;
  1037. ASSERT(serverCookie != NULL);
  1038. POSITION pos;
  1039. POSITION posDel = NULL;
  1040. CDNSServerTestQueryInfo* pInfo = NULL;
  1041. for (pos = m_serverInfoList.GetHeadPosition(); pos != NULL; )
  1042. {
  1043. posDel = pos;
  1044. CDNSServerTestQueryInfo* pCurrInfo =
  1045. (CDNSServerTestQueryInfo*)m_serverInfoList.GetNext(pos);
  1046. if (serverCookie == pCurrInfo->m_serverCookie)
  1047. {
  1048. pInfo = pCurrInfo;
  1049. break;
  1050. }
  1051. }
  1052. if (pInfo != NULL)
  1053. {
  1054. ASSERT(posDel != NULL);
  1055. m_serverInfoList.RemoveAt(posDel);
  1056. delete pInfo;
  1057. }
  1058. }
  1059. break;
  1060. //default:
  1061. //ASSERT(FALSE);
  1062. }
  1063. }
  1064. return 0;
  1065. }
  1066. void CDNSServerTestTimerThread::OnExecuteQuery(CDNSServerTestQueryInfo* pInfo,
  1067. DWORD dwQueryFlags,
  1068. BOOL bAsyncQuery)
  1069. {
  1070. // initialize a query result object
  1071. CDNSServerTestQueryResult* pTestResult = new CDNSServerTestQueryResult;
  1072. if (!pTestResult)
  1073. {
  1074. return;
  1075. }
  1076. pTestResult->m_serverCookie = pInfo->m_serverCookie;
  1077. pTestResult->m_dwQueryFlags = dwQueryFlags;
  1078. pTestResult->m_bAsyncQuery = bAsyncQuery;
  1079. ::GetLocalTime(&(pTestResult->m_queryTime));
  1080. // execute query
  1081. BOOL bPlainQuery, bRecursiveQuery;
  1082. CDNSServerTestQueryResult::Unpack(dwQueryFlags, &bPlainQuery, &bRecursiveQuery);
  1083. IP_ADDRESS* ipArray;
  1084. int nIPCount;
  1085. pTestResult->m_dwAddressResolutionResult = FindIP(pInfo->m_szServerName, &ipArray, &nIPCount);
  1086. if (pTestResult->m_dwAddressResolutionResult == 0)
  1087. {
  1088. ASSERT(ipArray != NULL);
  1089. ASSERT(nIPCount > 0);
  1090. PIP_ARRAY pipArr = (PIP_ARRAY)malloc(sizeof(DWORD)+sizeof(IP_ADDRESS)*nIPCount);
  1091. if (pipArr && ipArray)
  1092. {
  1093. pipArr->AddrCount = nIPCount;
  1094. memcpy(pipArr->AddrArray, ipArray, sizeof(IP_ADDRESS)*nIPCount);
  1095. if (bPlainQuery)
  1096. {
  1097. pTestResult->m_dwPlainQueryResult = DoNothingQuery(pipArr, TRUE);
  1098. }
  1099. if (bRecursiveQuery)
  1100. {
  1101. pTestResult->m_dwRecursiveQueryResult = DoNothingQuery(pipArr, FALSE);
  1102. }
  1103. free(pipArr);
  1104. pipArr = 0;
  1105. }
  1106. }
  1107. if (!PostMessageToWnd((WPARAM)pTestResult, 0))
  1108. delete pTestResult; // could not deliver
  1109. if (ipArray != NULL)
  1110. free(ipArray);
  1111. }
  1112. DNS_STATUS CDNSServerTestTimerThread::FindIP(LPCTSTR lpszServerName, IP_ADDRESS** pipArray, int* pnIPCount)
  1113. {
  1114. DNS_STATUS dwErr = 0;
  1115. *pipArray = NULL;
  1116. *pnIPCount = 0;
  1117. // try to see if the name is already an IP address
  1118. IP_ADDRESS ipAddr = IPStringToAddr(lpszServerName);
  1119. if (ipAddr != INADDR_NONE)
  1120. {
  1121. *pnIPCount = 1;
  1122. *pipArray = (IP_ADDRESS*)malloc((*pnIPCount)*sizeof(IP_ADDRESS));
  1123. if (*pipArray != NULL)
  1124. {
  1125. *pipArray[0] = ipAddr;
  1126. }
  1127. }
  1128. else
  1129. {
  1130. //
  1131. // Originally we were doing a DnsQuery() to retrieve the IP address of the server so that we
  1132. // could perform a query to that server to monitor its response. The problem with this is that
  1133. // if the user enters a single label hostname as the server and they are administering remotely
  1134. // and the two machines have different domain suffixes, then the DnsQuery() to get the IP address
  1135. // of the server would fail. DnsQuery() appends the name of the Domain suffix to the single label
  1136. // host name and then tries to resolve the using that FQDN which is incorrect. So instead of
  1137. // performing a DnsQuery() to get the IP address, the following uses WSALookupServiceBegin(),
  1138. // Next(), and End() to get the IP address. This has a better chance of resolving the name because
  1139. // it uses DNS, WINS, etc. I am leaving in the old stuff just in case we run into some problems.
  1140. //
  1141. HANDLE hLookup;
  1142. WSAQUERYSET qsQuery;
  1143. DWORD dwBufLen = 0;
  1144. GUID gHostAddrByName = SVCID_INET_HOSTADDRBYNAME;
  1145. WSAQUERYSET* pBuffer = NULL;
  1146. //
  1147. // Initialize the query structure
  1148. //
  1149. memset(&qsQuery, 0, sizeof(WSAQUERYSET));
  1150. qsQuery.dwSize = sizeof(WSAQUERYSET); // the dwSize field has to be initialised like this
  1151. qsQuery.dwNameSpace = NS_ALL;
  1152. qsQuery.lpServiceClassId = &gHostAddrByName; // this is the GUID to perform forward name resolution (name to IP)
  1153. qsQuery.lpszServiceInstanceName = (LPWSTR)lpszServerName; // this is the name queried for.
  1154. hLookup = NULL;
  1155. //
  1156. // Get the handle for the query
  1157. //
  1158. int iStartupRet = 0;
  1159. int iResult = WSALookupServiceBegin(&qsQuery,LUP_RETURN_ALL,&hLookup);
  1160. if (iResult != 0)
  1161. {
  1162. //
  1163. // Find out what socket error it was
  1164. //
  1165. int iErrorRet = WSAGetLastError();
  1166. //
  1167. // If the service wasn't started try starting it
  1168. //
  1169. if (iErrorRet == WSANOTINITIALISED)
  1170. {
  1171. WSADATA wsaData;
  1172. WORD wVersion = MAKEWORD(2,0);
  1173. iStartupRet = WSAStartup(wVersion, &wsaData);
  1174. if (iStartupRet == 0)
  1175. {
  1176. //
  1177. // Startup succeeded, lets try to begin again
  1178. //
  1179. iResult = WSALookupServiceBegin(&qsQuery,LUP_RETURN_ALL,&hLookup);
  1180. }
  1181. }
  1182. //
  1183. // Clear the error
  1184. //
  1185. WSASetLastError(0);
  1186. }
  1187. if(0 == iResult)
  1188. {
  1189. //
  1190. // Get the size of the first data block from the query
  1191. //
  1192. iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen,
  1193. pBuffer);
  1194. //
  1195. // Allocate the required space for the query data
  1196. //
  1197. pBuffer = (WSAQUERYSET*)malloc(dwBufLen);
  1198. ASSERT(pBuffer != NULL);
  1199. if (pBuffer == NULL)
  1200. {
  1201. return E_OUTOFMEMORY;
  1202. }
  1203. else
  1204. {
  1205. //
  1206. // Get the first data block from the query
  1207. //
  1208. iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen,
  1209. pBuffer);
  1210. //
  1211. // Loop through all the data in the query but stop if we get a valid IP address
  1212. // for the remote machine.
  1213. //
  1214. while(0 == iResult)
  1215. {
  1216. if (pBuffer->lpcsaBuffer != NULL && pBuffer->lpcsaBuffer->RemoteAddr.lpSockaddr != NULL)
  1217. {
  1218. //
  1219. // We are only interested in the socket address so get a pointer to the sockaddr structure
  1220. //
  1221. sockaddr_in* pSockAddr = (sockaddr_in*)pBuffer->lpcsaBuffer->RemoteAddr.lpSockaddr;
  1222. ASSERT(pSockAddr != NULL);
  1223. //
  1224. // Pull the IP address of the remote machine and pack it into a DWORD
  1225. //
  1226. DWORD dwIP = 0;
  1227. dwIP = pSockAddr->sin_addr.S_un.S_un_b.s_b1;
  1228. dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b2 << 8;
  1229. dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b3 << 16;
  1230. dwIP |= pSockAddr->sin_addr.S_un.S_un_b.s_b4 << 24;
  1231. //
  1232. // Increment the IP count and allocate space for the address
  1233. //
  1234. (*pnIPCount)++;
  1235. *pipArray = (IP_ADDRESS*)malloc((*pnIPCount)*sizeof(IP_ADDRESS));
  1236. if (*pipArray != NULL)
  1237. {
  1238. //
  1239. // Copy the IP address into the IP array
  1240. //
  1241. PIP_ADDRESS pCurrAddr = *pipArray;
  1242. *pCurrAddr = dwIP;
  1243. }
  1244. //
  1245. // Break since we were able to obtain an IP address
  1246. //
  1247. break;
  1248. }
  1249. //
  1250. // Free the buffer if it is still there
  1251. //
  1252. if (pBuffer != NULL)
  1253. {
  1254. free(pBuffer);
  1255. pBuffer = NULL;
  1256. dwBufLen = 0;
  1257. }
  1258. //
  1259. // Get the size of the next data block from the query
  1260. //
  1261. iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL | LUP_FLUSHCACHE, &dwBufLen,
  1262. pBuffer);
  1263. //
  1264. // Allocate enough space for the next data block from the query
  1265. //
  1266. pBuffer = (WSAQUERYSET*)malloc(dwBufLen);
  1267. ASSERT(pBuffer != NULL);
  1268. //
  1269. // Get the next data block from the query
  1270. //
  1271. iResult = WSALookupServiceNext(hLookup, LUP_RETURN_ALL, &dwBufLen,
  1272. pBuffer);
  1273. }
  1274. //
  1275. // Free the buffer if it hasn't already been freed
  1276. //
  1277. if (pBuffer != NULL)
  1278. {
  1279. free(pBuffer);
  1280. pBuffer = NULL;
  1281. }
  1282. }
  1283. //
  1284. // Close the handle to the query
  1285. //
  1286. iResult = WSALookupServiceEnd(hLookup);
  1287. ASSERT(iResult == 0);
  1288. //
  1289. // If we didn't get an IP address return an error
  1290. //
  1291. dwErr = (*pnIPCount < 1) ? -1 : 0;
  1292. }
  1293. }
  1294. return dwErr;
  1295. }
  1296. DNS_STATUS CDNSServerTestTimerThread::DoNothingQuery(PIP_ARRAY pipArr, BOOL bSimple)
  1297. {
  1298. PDNS_RECORD pRecordList = NULL;
  1299. DNS_STATUS dwErr = 0;
  1300. if (bSimple)
  1301. {
  1302. dwErr = ::DnsQuery(_T("1.0.0.127.in-addr.arpa"),
  1303. DNS_TYPE_PTR,
  1304. DNS_QUERY_NO_RECURSION | DNS_QUERY_BYPASS_CACHE | DNS_QUERY_ACCEPT_PARTIAL_UDP,
  1305. pipArr, &pRecordList, NULL);
  1306. }
  1307. else
  1308. {
  1309. dwErr = ::DnsQuery(_T("."),
  1310. DNS_TYPE_NS,
  1311. DNS_QUERY_STANDARD | DNS_QUERY_BYPASS_CACHE | DNS_QUERY_ACCEPT_PARTIAL_UDP,
  1312. pipArr, &pRecordList, NULL);
  1313. }
  1314. if (pRecordList != NULL)
  1315. ::DnsRecordListFree(pRecordList, DnsFreeRecordListDeep);
  1316. return dwErr;
  1317. }