From 04fc34e7231a4eb3b895fc622eaacdfd5fdad25b Mon Sep 17 00:00:00 2001 From: Pavel Yosifovich Date: Sat, 25 Jan 2025 15:34:31 +0200 Subject: [PATCH] added filter list page to layer properties --- WFPExplorer/FiltersListPage.cpp | 85 ++++++++++++++++++++++++ WFPExplorer/FiltersListPage.h | 49 ++++++++++++++ WFPExplorer/MainFrm.cpp | 75 +++++++++++---------- WFPExplorer/MainFrm.h | 4 +- WFPExplorer/WFPExplorer.rc | 2 +- WFPExplorer/WFPExplorer.vcxproj | 2 + WFPExplorer/WFPExplorer.vcxproj.filters | 6 ++ WFPExplorer/WFPHelper.cpp | 17 +++-- WFPExplorer/res/Condition.ico | Bin 22886 -> 15286 bytes WFPExplorer/res/Filter.ico | Bin 22486 -> 15086 bytes WFPExplorer/res/Object.ico | Bin 22486 -> 15086 bytes WFPExplorer/res/WFPExplorer.ico | Bin 22486 -> 15086 bytes WFPExplorer/res/engine.ico | Bin 22486 -> 15086 bytes WFPExplorer/res/tree.ico | Bin 43006 -> 19278 bytes 14 files changed, 197 insertions(+), 43 deletions(-) create mode 100644 WFPExplorer/FiltersListPage.cpp create mode 100644 WFPExplorer/FiltersListPage.h diff --git a/WFPExplorer/FiltersListPage.cpp b/WFPExplorer/FiltersListPage.cpp new file mode 100644 index 0000000..2164e00 --- /dev/null +++ b/WFPExplorer/FiltersListPage.cpp @@ -0,0 +1,85 @@ +#include "pch.h" +#include "FiltersListPage.h" +#include +#include "StringHelper.h" +#include + +CFiltersListPage::CFiltersListPage(WFPEngine& engine, FWPM_LAYER* layer) : m_Engine(engine), m_Layer(layer) { + WFPFilterEnumerator enumerator(engine.Handle()); + DWORD count = 0; + DWORD maxCount = 8000; + do { + m_Filters.Append(enumerator.NextFiltered([&](auto& filter) { return filter->layerKey == layer->layerKey; }, maxCount)); + count += maxCount; + } while (m_Filters.size() == count); + +} + +size_t CFiltersListPage::GetFilterCount() const { + return m_Filters.size(); +} + +CString CFiltersListPage::GetColumnText(HWND, int row, int col) const { + auto& f = m_Filters[row]; + switch (col) { + case 0: return std::to_wstring(f.Index).c_str(); + case 1: return f.Data->displayData.name; + case 2: return std::to_wstring(f.Data->numFilterConditions).c_str(); + case 3: return std::format(L"0x{:X}", *f.Data->effectiveWeight.uint64).c_str(); + case 4: return StringHelper::WFPFilterActionTypeToString(f.Data->action.type); + } + return CString(); +} + +void CFiltersListPage::DoSort(SortInfo const* si) { + auto sort = [&](auto& f1, auto& f2) { + switch (si->SortColumn) { + case 0: return SortHelper::Sort(f1.Index, f2.Index, si->SortAscending); + case 1: return SortHelper::Sort(f1.Data->displayData.name, f2.Data->displayData.name, si->SortAscending); + case 2: return SortHelper::Sort(f1.Data->numFilterConditions, f2.Data->numFilterConditions, si->SortAscending); + case 3: return SortHelper::Sort(*f1.Data->effectiveWeight.uint64, *f2.Data->effectiveWeight.uint64, si->SortAscending); + case 4: return SortHelper::Sort(StringHelper::WFPFilterActionTypeToString(f1.Data->action.type), StringHelper::WFPFilterActionTypeToString(f2.Data->action.type), si->SortAscending); + } + return false; + }; + + std::ranges::sort(m_Filters, sort); +} + +int CFiltersListPage::GetRowImage(HWND, int row, int) const { + switch (m_Filters[row].Data->action.type) { + case FWP_ACTION_BLOCK: return 2; + case FWP_ACTION_PERMIT: return 1; + case FWP_ACTION_CONTINUE: return 3; + } + return 4; +} + +LRESULT CFiltersListPage::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { + InitDynamicLayout(false); + m_List.Attach(GetDlgItem(IDC_LIST)); + m_List.SetExtendedListViewStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT); + + CImageList images; + images.Create(16, 16, ILC_COLOR32 | ILC_MASK, 6, 4); + UINT icons[] = { IDI_FILTER, IDI_FILTER_PERMIT, IDI_FILTER_BLOCK, IDI_FILTER_REFRESH, IDI_CALLOUT }; + for (auto icon : icons) + images.AddIcon(AtlLoadIconImage(icon, 0, 16, 16)); + m_List.SetImageList(images, LVSIL_SMALL); + + auto cm = GetColumnManager(m_List); + cm->AddColumn(L"", 0, 0); + cm->AddColumn(L"#", LVCFMT_RIGHT, 50); + cm->AddColumn(L"Name", 0, 240); + cm->AddColumn(L"Conditions", LVCFMT_RIGHT, 60); + cm->AddColumn(L"Weight", LVCFMT_RIGHT, 130); + cm->AddColumn(L"Action", 0, 110); + cm->DeleteColumn(0); + + int i = 1; + for (auto& f : m_Filters) + f.Index = i++; + + m_List.SetItemCount((int)m_Filters.size()); + return 0; +} diff --git a/WFPExplorer/FiltersListPage.h b/WFPExplorer/FiltersListPage.h new file mode 100644 index 0000000..02b4dab --- /dev/null +++ b/WFPExplorer/FiltersListPage.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include "resource.h" +#include +#include + +class WFPEngine; + +class CFiltersListPage : + public CPropertyPageImpl, + public CVirtualListView, + public CDynamicDialogLayout, + public CDialogHelper { +public: + enum { IDD = IDD_LAYERFIELDS }; + + CFiltersListPage(WFPEngine& engine, FWPM_LAYER* layer); + + size_t GetFilterCount() const; + CString GetColumnText(HWND, int row, int col) const; + void DoSort(SortInfo const* si); + int GetRowImage(HWND, int row, int) const; + + BEGIN_MSG_MAP(CFiltersListPage) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + CHAIN_MSG_MAP(CDynamicDialogLayout) + CHAIN_MSG_MAP(CVirtualListView) + END_MSG_MAP() + +private: + struct FilterInfo { + FWPM_FILTER* Data; + int Index; + }; + + // Handler prototypes (uncomment arguments if needed): + // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + +private: + WFPEngine& m_Engine; + FWPM_LAYER* m_Layer; + WFPObjectVector m_Filters; + CListViewCtrl m_List; +}; diff --git a/WFPExplorer/MainFrm.cpp b/WFPExplorer/MainFrm.cpp index 130ec98..02bd2c5 100644 --- a/WFPExplorer/MainFrm.cpp +++ b/WFPExplorer/MainFrm.cpp @@ -30,7 +30,7 @@ BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) { if (CFrameWindowImpl::PreTranslateMessage(pMsg)) return TRUE; - return m_view.PreTranslateMessage(pMsg); + return m_Tabs.PreTranslateMessage(pMsg); } BOOL CMainFrame::OnIdle() { @@ -77,7 +77,7 @@ LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ UIAddToolBar(tb); //m_view.m_bTabCloseButton = false; - m_hWndClient = m_view.Create(m_hWnd, rcDefault, nullptr, + m_hWndClient = m_Tabs.Create(m_hWnd, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); CImageList images; images.Create(16, 16, ILC_COLOR32, 8, 4); @@ -87,17 +87,17 @@ LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ }; for (auto icon : icons) images.AddIcon(AtlLoadIconImage(icon, 0, 16, 16)); - m_view.SetImageList(images); + m_Tabs.SetImageList(images); CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); pLoop->AddIdleHandler(this); CMenuHandle menuMain = GetMenu(); - m_view.SetWindowMenu(menuMain.GetSubMenu(WINDOW_MENU_POSITION)); + m_Tabs.SetWindowMenu(menuMain.GetSubMenu(WINDOW_MENU_POSITION)); LOGFONT lf; - ((CFontHandle)m_view.GetFont()).GetLogFont(lf); + ((CFontHandle)m_Tabs.GetFont()).GetLogFont(lf); wcscpy_s(lf.lfFaceName, L"Consolas"); m_MonoFont.CreateFontIndirect(&lf); @@ -169,6 +169,9 @@ void CMainFrame::InitMenu() { { ID_FILE_SAVE, IDI_SAVE }, { ID_EDIT_FIND, IDI_FIND }, { ID_EDIT_FINDNEXT, IDI_FIND_NEXT }, + { ID_NEW_FILTER, IDI_FILTER }, + { ID_NEW_PROVIDER, IDI_PROVIDER }, + { ID_NEW_SUBLAYER, IDI_SUBLAYER }, }; for (auto& cmd : cmds) { if (cmd.icon) @@ -179,7 +182,7 @@ void CMainFrame::InitMenu() { } void CMainFrame::UpdateUI() { - bool anyPage = m_view.GetPageCount() > 0; + bool anyPage = m_Tabs.GetPageCount() > 0; UIEnable(ID_FILE_SAVE, anyPage); UIEnable(ID_EDIT_COPY, false); UIEnable(ID_EDIT_CUT, false); @@ -224,9 +227,9 @@ LRESULT CMainFrame::OnShowWindow(UINT, WPARAM, LPARAM, BOOL&) { } LRESULT CMainFrame::OnRebuildWindowMenu(UINT, WPARAM, LPARAM, BOOL& bHandled) { - auto il = CImageList(m_view.GetImageList()); - for (int i = 0; i < m_view.GetPageCount(); i++) { - auto image = m_view.GetPageImage(i); + auto il = CImageList(m_Tabs.GetImageList()); + for (int i = 0; i < m_Tabs.GetPageCount(); i++) { + auto image = m_Tabs.GetPageImage(i); AddCommand(ID_WINDOW_TABFIRST + i, il.GetIcon(image)); } AddSubMenu(GetSubMenu(GetMenu(), WINDOW_MENU_POSITION)); @@ -241,16 +244,16 @@ LRESULT CMainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt LRESULT CMainFrame::OnViewSessions(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { auto view = new CSessionsView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Sessions", 0, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Sessions", 0, view); return 0; } LRESULT CMainFrame::OnViewFilters(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { auto view = new CFiltersView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Filters", 1, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Filters", 1, view); view->Refresh(); return 0; @@ -258,56 +261,56 @@ LRESULT CMainFrame::OnViewFilters(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn LRESULT CMainFrame::OnViewProviders(WORD, WORD, HWND, BOOL&) { auto view = new CProvidersView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Providers", 2, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Providers", 2, view); return 0; } LRESULT CMainFrame::OnViewProviderContexts(WORD, WORD, HWND, BOOL&) { auto view = new CProviderContextView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Provider Contexts", 6, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Provider Contexts", 6, view); return 0; } LRESULT CMainFrame::OnViewLayers(WORD, WORD, HWND, BOOL&) { auto view = new CLayersView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Layers", 3, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Layers", 3, view); return 0; } LRESULT CMainFrame::OnViewNetEvents(WORD, WORD, HWND, BOOL&) { auto view = new CNetEventsView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Net Events", 8, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Net Events", 8, view); return 0; } LRESULT CMainFrame::OnViewHierarchy(WORD, WORD, HWND, BOOL&) { auto view = new CHierarchyView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Hierarchy", 7, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Hierarchy", 7, view); return 0; } LRESULT CMainFrame::OnViewSublayers(WORD, WORD, HWND, BOOL&) { auto view = new CSublayersView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Sublayers", 4, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Sublayers", 4, view); return 0; } LRESULT CMainFrame::OnViewCallouts(WORD, WORD, HWND, BOOL&) { auto view = new CCalloutsView(this, m_Engine); - view->Create(m_view, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - m_view.AddPage(view->m_hWnd, L"Callouts", 5, view); + view->Create(m_Tabs, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); + m_Tabs.AddPage(view->m_hWnd, L"Callouts", 5, view); view->Refresh(); return 0; @@ -328,9 +331,9 @@ LRESULT CMainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt } LRESULT CMainFrame::OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - int nActivePage = m_view.GetActivePage(); + int nActivePage = m_Tabs.GetActivePage(); if (nActivePage != -1) - m_view.RemovePage(nActivePage); + m_Tabs.RemovePage(nActivePage); else ::MessageBeep((UINT)-1); @@ -338,23 +341,23 @@ LRESULT CMainFrame::OnWindowClose(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn } LRESULT CMainFrame::OnWindowCloseAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - m_view.RemoveAllPages(); + m_Tabs.RemoveAllPages(); return 0; } LRESULT CMainFrame::OnWindowActivate(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { int nPage = wID - ID_WINDOW_TABFIRST; - m_view.SetActivePage(nPage); + m_Tabs.SetActivePage(nPage); return 0; } LRESULT CMainFrame::OnPageActivated(int, LPNMHDR, BOOL&) { - int page = m_view.GetActivePage(); + int page = m_Tabs.GetActivePage(); bool handled = false; if (page >= 0) { - handled = ::SendMessage(m_view.GetPageHWND(page), WM_ACTIVATE, 1, 0); + handled = ::SendMessage(m_Tabs.GetPageHWND(page), WM_ACTIVATE, 1, 0); } if (!handled) { UpdateUI(); @@ -370,7 +373,7 @@ LRESULT CMainFrame::OnAlwaysOnTop(WORD, WORD, HWND, BOOL&) { } LRESULT CMainFrame::OnEditFind(WORD, WORD, HWND, BOOL&) { - ATLASSERT(m_view.GetPageCount() > 0); + ATLASSERT(m_Tabs.GetPageCount() > 0); if (m_pFindDlg == nullptr) { m_pFindDlg = new CFindReplaceDialog; @@ -388,9 +391,9 @@ LRESULT CMainFrame::OnFind(UINT msg, WPARAM wp, LPARAM lp, BOOL&) { } m_pFindDlg->SetFocus(); - if (auto page = m_view.GetActivePage(); page >= 0) { + if (auto page = m_Tabs.GetActivePage(); page >= 0) { m_SearchText = m_pFindDlg->GetFindString(); - ::SendMessage(m_view.GetPageHWND(page), msg, wp, lp); + ::SendMessage(m_Tabs.GetPageHWND(page), msg, wp, lp); } return 0; } diff --git a/WFPExplorer/MainFrm.h b/WFPExplorer/MainFrm.h index 6402939..62cf42b 100644 --- a/WFPExplorer/MainFrm.h +++ b/WFPExplorer/MainFrm.h @@ -20,7 +20,7 @@ public: virtual BOOL OnIdle(); BEGIN_MSG_MAP(CMainFrame) - COMMAND_TABVIEW_HANDLER(m_view, 1) + COMMAND_TABVIEW_HANDLER(m_Tabs, 1) COMMAND_ID_HANDLER(ID_VIEW_FILTERS, OnViewFilters) COMMAND_ID_HANDLER(ID_VIEW_SESSIONS, OnViewSessions) COMMAND_ID_HANDLER(ID_VIEW_PROVIDERS, OnViewProviders) @@ -103,7 +103,7 @@ private: WFPEngine m_Engine; CFont m_MonoFont; - CCustomTabView m_view; + CCustomTabView m_Tabs; CMultiPaneStatusBarCtrl m_StatusBar; CFindReplaceDialog* m_pFindDlg{ nullptr }; CString m_SearchText; diff --git a/WFPExplorer/WFPExplorer.rc b/WFPExplorer/WFPExplorer.rc index 1d18cc3..b77b0ab 100644 --- a/WFPExplorer/WFPExplorer.rc +++ b/WFPExplorer/WFPExplorer.rc @@ -611,7 +611,7 @@ BEGIN VALUE "FileDescription", "Windows Filtering Platform Explorer" VALUE "FileVersion", "0.5.7.0" VALUE "InternalName", "WFPExplorer" - VALUE "LegalCopyright", "©2022-2024 Pavel Yosifovich" + VALUE "LegalCopyright", "©2022-2025 Pavel Yosifovich" VALUE "OriginalFilename", "WFPExplorer.exe" VALUE "ProductName", "WFP Explorer" VALUE "ProductVersion", "0.5.7.0" diff --git a/WFPExplorer/WFPExplorer.vcxproj b/WFPExplorer/WFPExplorer.vcxproj index 41c4752..421f4e4 100644 --- a/WFPExplorer/WFPExplorer.vcxproj +++ b/WFPExplorer/WFPExplorer.vcxproj @@ -364,6 +364,7 @@ + @@ -399,6 +400,7 @@ + diff --git a/WFPExplorer/WFPExplorer.vcxproj.filters b/WFPExplorer/WFPExplorer.vcxproj.filters index 199cb9c..c13a3d6 100644 --- a/WFPExplorer/WFPExplorer.vcxproj.filters +++ b/WFPExplorer/WFPExplorer.vcxproj.filters @@ -108,6 +108,9 @@ Dialogs + + PropertyPages + @@ -194,6 +197,9 @@ Dialogs + + PropertyPages + diff --git a/WFPExplorer/WFPHelper.cpp b/WFPExplorer/WFPHelper.cpp index 6b64b5e..f524cd0 100644 --- a/WFPExplorer/WFPHelper.cpp +++ b/WFPExplorer/WFPHelper.cpp @@ -11,6 +11,8 @@ #include "ProviderDlg.h" #include "CalloutDlg.h" #include "SubLayerDlg.h" +#include "WFPEnumerators.h" +#include "FiltersListPage.h" CString WFPHelper::GetProviderName(WFPEngine const& engine, GUID const& key) { auto provider = engine.GetProviderByKey(key); @@ -55,19 +57,26 @@ CString WFPHelper::GetSublayerName(WFPEngine const& engine, GUID const& key) { int WFPHelper::ShowLayerProperties(WFPEngine& engine, FWPM_LAYER* layer) { auto name = L"Layer Properties (" + GetLayerName(engine, layer->layerKey) + L")"; CPropertySheet sheet((PCWSTR)name); - sheet.m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_USEICONID | PSH_NOCONTEXTHELP | PSH_RESIZABLE; + sheet.m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_USEICONID | PSH_NOCONTEXTHELP; sheet.m_psh.pszIcon = MAKEINTRESOURCE(IDI_LAYERS); CLayerGeneralPage general(engine, layer); - general.m_psp.dwFlags |= PSP_USEICONID; - general.m_psp.pszIcon = MAKEINTRESOURCE(IDI_CUBE); + general.m_psp.dwFlags |= PSP_USEHICON; + general.m_psp.hIcon = AtlLoadIconImage(IDI_CUBE, LR_LOADTRANSPARENT | LR_CREATEDIBSECTION, 16, 16); sheet.AddPage(general); - + CLayerFieldsPage fields(engine, layer); if (layer->numFields > 0) { fields.m_psp.dwFlags |= PSP_USEICONID; fields.m_psp.pszIcon = MAKEINTRESOURCE(IDI_FIELD); sheet.AddPage(fields); } + CFiltersListPage filterPage(engine, layer); + if (filterPage.GetFilterCount()) { + filterPage.SetTitle(L"Filters"); + filterPage.m_psp.dwFlags |= PSP_USEICONID; + filterPage.m_psp.pszIcon = MAKEINTRESOURCE(IDI_FILTER); + sheet.AddPage(filterPage); + } return (int)sheet.DoModal(); } diff --git a/WFPExplorer/res/Condition.ico b/WFPExplorer/res/Condition.ico index 907de647ba0e57a82ad09417d4a95f455c36f315..b11f34432da167b27713388304426b6c9c0f5138 100644 GIT binary patch delta 63 zcmaF1iE&%G2?GNo12cnx0Rs>yFfgbwFqnZ@Kqi9B1Oy=b1{NUSeDf38CTjo* C69`HG delta 5038 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 TR%^rC=%~T~T)wMEV$c5pF{hw; diff --git a/WFPExplorer/res/Filter.ico b/WFPExplorer/res/Filter.ico index b1075d456d2e7e99ecfca21a199841a0ed565cd9..694b56edf221698158bb1132773842f79744e69f 100644 GIT binary patch delta 63 zcmcb%p7C9&2?GNo12cnx0Rs>yFsx8zU@!x*6rg+o28Me;F##YAlFwjaU}!VjEF-(i F3II$p3J3rI delta 7034 zcmcJTd0fre|Hoh2gi56$p|WIbLr9iENhvgzy3!`ny}CDbtGnp7=u^2ZbP=VJ5W{?J z^OLa*W6Nk}7-l9j(RRyKN%LhIOy3#4LLFH_KTJ{?c4WTE++ooN1UH=3{S!;`ByczAv@8ox|K<7p-CACJS` z!|R~lABwyA0r=+^@py7M1AqPS8UDPnAIy_)cA@FQb~Ihyjz<@_;n#C2+&__k+RtNA z^O*#7DkuDTeGeX<+X(gEP^j|*q0aS&X8U~H&6tOKs+p)uorK!t322D_5O+6DN6nVG zP;YlfRkjx@^8!#+AcFcIa#S6NMEw>QG@eXE%>gm)<#{ux%Wy*N76;UCoPv8B#^HYA z2-Gt}(I6jyrgN#d7d-&gQ3G)QbSiF3%~72^8JgT>s0uShS)?g6u|rUnu?XtJ(P+Ao zjlauIqvD_p7yW?p?Mra?^Yy4bk%Y2OB`C}GLB$qVRHl858fGLaY&^f7k3TNc?^n1UMP9)7EA?7k5Ox%hz$4?nv&?JtguMns`5`~Jxu~2`W0L^I?8qRG+$yx(E zy0R0+E9v_y4K_f-m+AN+2zY!}iJRf(xD!1bWlDRX7Y`94G58`G1bk1(xo>q8{=La1DTe0?5PFP1>Q$l%TnE*3zl6u)NHJF!h+y(h9Xx5aE)dE3fbY((Li~C&_5JAE-UQX^OWhvf5&EEZ-M8YH*4NmQtb8V^0b8sQ>IM$ zzvM|#G#y_b&-A5>mZ^qjX1=S#c81;#JAHRI&-9c+ zDakF34N`lXzqJFsOA-4reUm-YgL%tLt&ENO8X3%$g|vC-^!`boMAO;o;zr}sbXdKG z#UR5tX+~R*j!$~`Nh11j{d|)*r7z{FMp_OwvasMsT5L{`Zs{m&$$JQe9yA?Vt&g`I z4Nucyj0TZjEVi&okZtVTLoSqiB#Aa~<4>|nu^-ki)xg-uW{^diSZot7jqR)_`MQ?z z9bzUk76hYJLPh{#BOSg6Fx zdSoA|RA&Chw&CI7>dCXRGF`^=TJG)R>+84B-{0TWbw$9+Re`I6_<}W7{d#rSHeB64 z9NvHah;g$&n&3ERj+3*Ci_3xq3tQ8I1upKNELyyTF<#oXia7>zXK3q8n>mYmjOV&I zIkTNwlC!gu(;P=fTYHOntsV5t4Gj&Z&-l2d$4BEG9LWtOClXR}bR0i!(&*8n$C$P` z(9<7iV`F4wJaXsRWHr8})n59sOjG#^O6 z=%7JHMn;2;jfYrTTA7%bSeu%f_UqSg=&<1fbaY3&ma{o6>Z9MQcOL@-L+aDFuaU8V zfr)89vk&?Y(9zK)e0npnU_?o)HEFjdQg+g2t{71~(2B^2@TjP7%QK;8%M;p}Gi;Q4 zkJ*u|GK+0SF|C9}^wpj^0ao3v<*3W^;vlOoX9)*db=w!9cAFb&GhA^m!xA|Zh>haeEUKh5a@$4o%V7^eI_SpIs^4hl+ zHQCEiyPXEz=7I#)pn?|1^oFV$=WPkf{P zEQ$lE%DqC=>>xTMZfZ#Xm?OcbUuSc4z``5Dl2+BORjAG+Fd}qd!HNZ{Hke|ei3K3_ zhKZ=!G@FB>D%AoGDOjpwiH#+K((Dx+cGPY9n4`Rg4Ij3^S?mB*Nm~Gn#Nf<4Wl0 z>u{iTX=P7b3p3~7j0G~5@L0(DPuWS1gPz|g;MnOQanvs=4-T+SEvH?L#XlCFek4q+ zJ{rpb@AF$nIizF>?;@{-;#jz1A&Q0OC&fDn2?;xig;{D-M-M^84u1|OSs-I^vV3O? zaIt(`s+!LsX|ceN!_umZ1swPO!sH2{Ik}OeEfyhvy_|#Z1$rDR{ur#sq2bRWJq`(3 z^sG!A54+k>IFs@8!yqJ6j1Pl~ET0#KLb9TmFqD$j7lh$48NLgH0omZ+!Z3<#T0b$I z$#~PnVEFV$wo(iwSyr+b2gptx6{DD}^p+U)WX*qxq4P`(Gs|#Tli50lV!tjzeT;)!`^6E7giXJz4Xp2h?`4qIkLdc6pbKk0L3C=NQ_hzO`aiNJvaIkQ(6X{?X_(v*jbEFdGv(Dtw|8iR|z$$_ZnVQ-%k}2g{g+ zuLaZ`O~X4nySm2>G&UW!K3+hA_7Qw2Kne{D;)}z*1#8x$)lkoBJ@%8gx z;W9J8YmO(64Tb!J82%_T!J1&9h;_1Hq5BXkigji!S?b{E;mPAITgKygdN_L7F6S79 z0*|3nr%@m?bJncc4i0P(<22XVWuB|6+k9@42G$g5j4B=m*R<@8bF(@2WwQ;&WyM3-x^&wc8DnGQnx*^*SG9-ZQU-q z!re{JJpriSZhXprPB*N=ZMIOZ%g8ods&*>0nQt zj;d{oxNF>^04?06vsRrl9o6Y`a5u#cns^(O(ZPK~XoMfb2clyASlrpOmWw|Aed`z< z;s!QXdIf_YVa5icvx;Xf5;@Z!!FbZ8$&)#r)0?5BnE z^qXE?sf$};6I3fFqarte!WagR>EM1+oQFF{5>Vu?g$uq~_?8@$Nk2ekx)aLCd2L}L zZtbVOjV+pw8Pa#T}2^zl2z;9pY z;VNCRR?(Yy@YPld%68+s0J;HH3_t_LQ%~t|uQ{T??-#eCD%X#KIVD|YuSR@f140Va zSdyj2w6q$GO3=VUQ42GP8vSLJlviU|oCfwOYRprq;g!v(vF=C>;C~6@!RE;Yeh3;4bDyJ5c> z?|cpXIje_vt_D0Z;QPSVU>2cU;Z2N7D5t?n zDN?A1iYB-!tArdCVNijN@~n4rVWC1Ml*kFTKi^;s2#+)`XO|E+##_{*`Ww_bEPt^zctam zOJDfwG@r1vohRw;&Xc$76R-ADc|PsLEOWLhXs2!2XWh5~SO9F@hG$a+x7l)x$nLZN z?W*jiYH4LXbRzA>q-fi8**%vVK}%bU_E(nvsK}AoWqLXQFEh{27^_#L4QP6vu={Gp F{{jcR#7qDH diff --git a/WFPExplorer/res/Object.ico b/WFPExplorer/res/Object.ico index 5bc75d8d0f3233ad0fd7236c4811055ca7d917d7..d3b2aa086deaf2242644b2c1a2bedfcd246a4e33 100644 GIT binary patch delta 63 zcmcb%p7C9&2?GNo12cnx0Rs>yFsx8zU@!x*6rg+o28Me;F##YAlFwjaU}!VjEF-(i F3II$p3J3rI literal 22486 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 QAiYR?eH-{)Sr}UV7df(L2mk;8 diff --git a/WFPExplorer/res/WFPExplorer.ico b/WFPExplorer/res/WFPExplorer.ico index b160fc514b54008772d800779223208816b5ad3c..9ec8e27f900f78ac33677c273638b83360a07d17 100644 GIT binary patch delta 63 zcmcb%p7C9&2?GNo12cnx0Rs>yFsx8zU@!x*6rg+o28Me;F##YAlFwjaU}!VjEF-(i F3II$p3J3rI delta 4987 zcmZvg2~<=^y2t-qAdQGLhz*Er(trYj+RfH%jUpIm5SpvVX3HYVBC-gG1Z)t&4Mb#B z1Ox*r=(t6V8Fh@4r*n=olbG}3yf@}$OfoTVW*iSXa}r)ca^F|C!DY@Ar@C%^-&f16 z`l`O)PUS@5 zQBN|yySD`sH*|PS9whRwh+RLewx^Q%Fi*jbpeiRU2wfT8ZWLT(!jf^^Ip<@j^pbj_>aa2nxqE8 zA9h0c_8^4kr|@}?Kd!yA6k}WL(6`o@vI4)_rPAZu(`=A5eB9!Xt2=x!yitndYlCp1 zEEHe#1mVSvG@3vO&DI#l(?T$k6@)uYN_u-aPUqU-V&x(n)ke^SLU5@e9KUIe#Dn$# zv}VVltg;4G6%`n4(BS?-1zOAEP_?}Xt$Z8~9qGY?&-8!9p8c)ZQC*7*<#HU`?1kRr zC-9EG5p7#DF*zlmt{{U}!W@Uv9q{MB{2jOM+(V}}3eR4AkD-w&n>f4Q$=31OPTt&XI z0iQI+VW_SI11V9MxRZ;g=QJc+hadm2kG7x8{|SG=@H#oB{;Lw>#c~{7=Z0g6UbtQp zP5TI3D_=p|q96w?qU~IbYxPQ;-R6UHB}&}f8H8)qO5AA-#jzAGJZK3(?^*{u>src3r;>{9cFKT-rPm&8mEcLyU2knwQdi$lKeulN@1=I@`{NZe%=0T z*sO3fvsLcx=2};sW?Vz|XWPv@lv1fO+G>_{N?fGs-0Sv^dUq=iOUr19nb=!i%nFVh z3-^%v+u3#cMw{8s4+>VDo^HVQlWUb&N@X%%rH5I&bxOQuoJ1$AMrEGP&H#Y&nKz7Mp8~Rw^xN5nSfli00sW_Z~fVbZ=j4 zw*|+w9JiGzCGOUyY&wRmZ)*)d?A~rY+oE7vaAaRcXUD#Rt~uQam6aUV)7#qmhX2ya z)|tq;rae3b97o1djO*n_KY$j;_>H`eXp zcU7hH?ONOUe0p{Eba&vk6=m|Zb<|mUF)8is`TVLG9kvx^^99^mp3l!@Iy*jdd-{x$ zFV3bBc>W#M%)yqg&S!O&L=Df^WUxjKGCs2~Yq}AiPY*o5GoKWW^Z07AFtn)VDWz{= z4IFLw>_Wp7_;j-8vv;r&oagfSG&n6lL3u?b&lhdUW>RZDJ2yXjTY^nVX<0d+nZbH? zwc_&&i};Osks96B?BZNzNV4qQjLc1Wc`=*$tS$L`0m-Cke0oOa2A$4pBcGL#okKU# zLMtwr=hv=FNr`n>zm`vpm6OoLnp+c}m}G4pW^S#Gjn}9&E17gI_jYU)owQZqv%;cc z<20)H1QI*X8b^4%3sP22=%-7y zg$t`ss?7|gi;Pxg*JArQTpdBTb8EN`qOwk)gazFUgut zNDSqa+E5b4k(`mAE9FSaFUgOn@MRL;&`@IyI%9~t2nL9~^actnj1}qc>7|V#%{}T> zQxI0;XmSKPV?%InXPg1Fp6!S5zs-1lM~6QR2jN_)QiQlmg)#W)(-H{JhycI8K{jpp ziGYrg;Eg?gIH{B4QEx1MqTnt(>!cTXh$rXbiLvxboY`c9o_Jpjq^SujBk(;TsPGlx zRaAT2vC{sccbwfYF+3#9H@bpp=*%gTq{z{b`eW}J`m4 zjHDUkBmo~IjedHW{;Uwxm1W>aZ4R#MTcSl)W#l$m9g3#HWbEFo5HVQ6#=O$1sD;GX~UZ)hU0+n2eR_<1%SJp3cds%k{WD&Aa(z9a>@ax@~$ zF)&+~wn2oxiVW(9+O_Cwp=YGVFtMV#9#@F)Zc=VJdl-l;uz8OB^l$w&QJzz7|gN3_+~k-ly_XTN^8%0*q)`tA>O63>CLv%%+#nMFxPL`p?119nd4D1{2F5;`|jZsXn=INZ>4+^ebATROMjH)X(r=`Bo6T^2~2rCtjEFu$V>Jre1{Lx+18 z$YVT?mH@|$O^WA8ychb|Hyv2w-nX;?mipa3ZEp5Q6dj$Oz#J3Hz4cw?_Ve2gdsCZk z8Fg5*@L-F#(lN%F+8ejl)JQ6e_Z?z-MNB)rAxvtlciT1E%p+UuscCAi*{hzjZ$AyN zSk2UcX|=>#%jj7TjPqir6v)>znN0=*QPQ_L0&ov^OB0*)KV>JgQ(BTOWT~fCF`Y{K8>eS z>ZW8iL~?RknogJ2uC=j9UY`YI=j5iX-IUd?oi{sey(T?FtWL5YF1O~Cb7cKVk_VMxdTH@>1p*50On6hB!w$P4(q9^q?%ht|*K7~3*r;co; zojHX%D{JXoTJ?6Vof-F*A<7Yvn6MDnuJzNiyL>|US$bPNXBW^HHmd!QCD4=Eh*{QVaE?P3aUHu_V)b1<4G$1fWdxL8fAmE%BR&ynPAu>3`-7tWWv z(HE;F1~-t?M2q(wU3s_YgLHR>dO^M@J`TW;K%x z{ykFzh~nnSY+uzG-dTxvoIz%A`PcO1_;0=bx$x>O8P)9lk}i+iVqOYn#`13R!G9zI UKW-#Kqq+XOJf*(q|3S$A10i3kc>n+a diff --git a/WFPExplorer/res/engine.ico b/WFPExplorer/res/engine.ico index 95de402afbcba4849704010db0a583458eda0092..40f1480c93e5b483c49a1105fe93283a7200fbc0 100644 GIT binary patch delta 63 zcmcb%p7C9&2?GNo12cnx0Rs>yFsx8zU@!x*6rg+o28Me;F##YAlFwjaU}!VjEF-(i F3II$p3J3rI delta 5654 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 nA`t!#HUF54XKoA(o98*LQQf?$$ww6cKid&B literal 43006 zcmeHQJ8vXK5N>vTSyby&zIu@fYR{sZ6@0i;C47g=_M-?l7SUJ(%@ArT=G5+Y85 zgmC#I=p<4QMi+RI%?@A9ZrQ!PGt<*E(>pyoHBz~zU)5FB)sO1#9V<1bmQ<&s@NBBB zkCi&Z+xGS_{No2oeUG@UtzmfYeWgCxL(a`n`ifFNeW}#i+A#dpQ>8xtMyb`+Vffc4 zO8x$wQY*+u^!FB(`t}FVL#PAj0_G4OKd46@(SWN4E-o(S0qZF+?@F&p`LC|7{_A$T zQ5I01qB8w*@zGmAG(}i);g#fue3|l79@xg53ti3|viy)~k=s2=c`h$6W8IvcoxRI4 zx!|VD&-yt&K5n)A`}_OR-rk-wyguKVX5Xi}a`*o{_RsC#cKK)2{uj7?`~7~D1e|_) zdiv63+~d3;H@Y+fM(N=f9%s`Oy78@qfo#me;@IvBg8v^nIzW;+zgkivQO>|4+9W zY5!{XzjWP(_>S@4_xbMt+n@(M^hE=+tbvK2wRW$EQEG?wxRxTd5#zxGj>o%ggl|_y*NnLqS#Ip~92@(sv@Z0j~i3oro^JNg+@8 z8pyhvLgzL%34E_}v+Ae&B58L^_)bYyc}lC9|M&Rrhu*VpZ*L#ImC$tl={`U2_nVl~ zLf3!O`48NF8r^?Mw@n^DP21q#-k9-C3G?{U6n;%Uo2dUL+rO+I!e9S1eg17a|K=EF zhHGBG$@;mL^Tm-R!9_HVWg&tGPIQ^HMMKd^pFDId-+(V?;DrrG?{{LzL|bR(0E$oIjpA4*F1V=vbRNjg^l;WY zc$=#Vvg*;(T=>(=P3t{G{$&0b?y(o`A5EU$%z1;uF5?R4^`SqRKOWD2(#9y6KkV~N zn(oZ_5XWbo#}N6G`9tOpo;MitoZy0G{&?)^E_&m6D~dRBkTt~p<-t$tg&@F(q?&(e}}+3d@f-gf&-)@uE+ zqhk|wv(Z%xU}pj&E{=aON@qOEKZtsCe5D3NNW&9!n0_GinBN|KJ^(zqV%8g-F>L}m z06u5xt{@QbgEioQ&y5IEIEh_bpU#m^rZe{79`L-mhel!S{X8AZh(HedwmCa@{d^xy z$DZns@8RCv-9-!}|KZ``ROBZe*V+Dh8$;KB>S6O8`hNnT|M&Y+0}4~T6-;_&*jB%p zzsfM$dl~irb#QPn_1~}5+5Xc1hu`twzE4>Ce{#OL{$?7Q_EB$}`jtccZectDH z*q?2EVM|Y1f5`klvRvEzJIno_RA7_8a0gE*2z~xrflcc+KVjb~Rmag%zv#ba`?LBC z;4jJNVE-fbJ+f>(EsgdI-t^T%?*f1=6~Yw0>#L6!0& z=$mEohJEe>_|(7Hf3k0&x4TdM>-G4wPpYSB^wHPLtaGhvTA{C7-{iY*{Y=(aT@02{ z^qVd920zH^9mMBCF{bd{{er?eOJS{+oQ`-(C+Mo{2_U+(4qF8f=5^TDPty6fjUmvr z?vJIuQw@2>>?-JCym;78ainKmleo|$nXA+v(c=d)CZ3sbx(lvy4N#@LVlR_tqptSH zc2M;k8X7(5rP4V!GVwLOQUpx;jfViV*-qS znS2w^S1Sl@0(jo)EFxe$G-hB7dibV0?X6Ro&-bCX)H#aM(#9N~Q*xAFraIHk*K(A9 zmNkavDbFe?GDkrEXH>rEoX~dtv+fC(9V3gBx7mlDuJg+8db;hM%jnovMo-tv@w=XG ed*?Dbo*M-S(}4K}E?0dDFysG59D&*xhyMXMH5HQp