// Wfp Tool // Copyright (c) 2016 Henry++ #include #include #include #include #include #include #include #include #include #include "main.h" #include "rapp.h" #include "routine.h" #include "pugixml\pugixml.hpp" #include "resource.h" CONST UINT WM_FINDMSGSTRING = RegisterWindowMessage (FINDMSGSTRING); rapp app (APP_NAME, APP_NAME_SHORT, APP_VERSION, APP_COPYRIGHT); std::unordered_map applications; std::vector colors; std::vector processes; std::vector rules; std::vector rules_ext; STATIC_DATA config; #define MPS_SERVICE1 L"mpssvc" #define MPS_SERVICE2 L"mpsdrv" DWORD changeservicestate (LPCWSTR name, BOOL is_changeconfig, BOOL is_stop) { DWORD result = 0; SC_HANDLE scm = OpenSCManager (nullptr, nullptr, SC_MANAGER_ALL_ACCESS); if (!scm) { WDBG (L"OpenSCManager failed. Return value: 0x%.8lx.", GetLastError ()); } else { SC_HANDLE sc = OpenService (scm, name, is_changeconfig ? SERVICE_CHANGE_CONFIG : SERVICE_QUERY_CONFIG); if (!sc) { WDBG (L"OpenService failed. Return value: 0x%.8lx.", GetLastError ()); } else { if (is_changeconfig) { if (!ChangeServiceConfig (sc, SERVICE_NO_CHANGE, is_stop ? SERVICE_DISABLED : SERVICE_AUTO_START, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { WDBG (L"ChangeServiceConfig failed. Return value: 0x%.8lx.", GetLastError ()); } } else { LPVOID buff = nullptr; DWORD size = 0; DWORD needed = 0; while (TRUE) { if (QueryServiceConfig (sc, (LPQUERY_SERVICE_CONFIG)buff, size, &needed)) { LPQUERY_SERVICE_CONFIG ca = (LPQUERY_SERVICE_CONFIG)buff; result = ca->dwStartType; break; } if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) { free (buff); break; } size += needed; buff = realloc (buff, size); } } CloseServiceHandle (sc); } CloseServiceHandle (scm); } return result; } VOID _app_refreshstatus (HWND hwnd) { _r_status_settext (hwnd, IDC_STATUSBAR, 0, _r_fmt (I18N (&app, IDS_STATUS_TOTAL, 0), applications.size ())); switch (app.ConfigGet (L"Mode", Whitelist).AsUint ()) { case Whitelist: { _r_status_settext (hwnd, IDC_STATUSBAR, 1, I18N (&app, IDS_MODE_WHITELIST, 0)); break; } case Blacklist: { _r_status_settext (hwnd, IDC_STATUSBAR, 1, I18N (&app, IDS_MODE_BLACKLIST, 0)); break; } case TrustNoOne: { _r_status_settext (hwnd, IDC_STATUSBAR, 1, I18N (&app, IDS_MODE_TRUSTNOONE, 0)); break; } } } VOID _app_getinfo (ITEM_APPLICATION* ptr) { if (ptr) { SHFILEINFO shfi = {0}; SHGetFileInfo (ptr->full_path, 0, &shfi, sizeof (shfi), SHGFI_SYSICONINDEX); ptr->icon_id = shfi.iIcon; HINSTANCE h = LoadLibraryEx (ptr->full_path, nullptr, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); if (h) { HRSRC hv = FindResource (h, MAKEINTRESOURCE (VS_VERSION_INFO), RT_VERSION); if (hv) { HGLOBAL hg = LoadResource (h, hv); if (hg) { LPVOID versionInfo = LockResource (hg); if (versionInfo) { UINT vLen = 0, langD = 0; LPVOID retbuf = nullptr; WCHAR author_entry[MAX_PATH] = {0}; WCHAR description_entry[MAX_PATH] = {0}; WCHAR version_entry[MAX_PATH] = {0}; BOOL result = VerQueryValue (versionInfo, L"\\VarFileInfo\\Translation", &retbuf, &vLen); if (result && vLen == 4) { memcpy (&langD, retbuf, 4); StringCchPrintf (author_entry, _countof (author_entry), L"\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName", (langD & 0xff00) >> 8, langD & 0xff, (langD & 0xff000000) >> 24, (langD & 0xff0000) >> 16); StringCchPrintf (description_entry, _countof (description_entry), L"\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription", (langD & 0xff00) >> 8, langD & 0xff, (langD & 0xff000000) >> 24, (langD & 0xff0000) >> 16); StringCchPrintf (version_entry, _countof (version_entry), L"\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion", (langD & 0xff00) >> 8, langD & 0xff, (langD & 0xff000000) >> 24, (langD & 0xff0000) >> 16); } else { StringCchPrintf (author_entry, _countof (author_entry), L"\\StringFileInfo\\%04X04B0\\CompanyName", GetUserDefaultLangID ()); StringCchPrintf (description_entry, _countof (description_entry), L"\\StringFileInfo\\%04X04B0\\FileDescription", GetUserDefaultLangID ()); StringCchPrintf (version_entry, _countof (version_entry), L"\\StringFileInfo\\%04X04B0\\FileVersion", GetUserDefaultLangID ()); } if (VerQueryValue (versionInfo, author_entry, &retbuf, &vLen)) { StringCchCopy (ptr->author, _countof (ptr->author), static_cast(retbuf)); } if (VerQueryValue (versionInfo, description_entry, &retbuf, &vLen)) { StringCchCopy (ptr->description, _countof (ptr->description), static_cast(retbuf)); } if (VerQueryValue (versionInfo, version_entry, &retbuf, &vLen)) { StringCchCopy (ptr->version, _countof (ptr->version), static_cast(retbuf)); } } } // free memory UnlockResource (hg); FreeResource (hg); } FreeLibrary (h); // free memory } } } size_t _app_getposition (HWND hwnd, size_t hash) { for (size_t i = 0; i < _r_listview_getitemcount (hwnd, IDC_LISTVIEW); i++) { if ((size_t)_r_listview_getlparam (hwnd, IDC_LISTVIEW, i) == hash) return i; } return LAST_VALUE; } size_t _app_addapplication (HWND hwnd, rstring path, BOOL is_checked) { if (path.IsEmpty ()) return 0; _R_SPINLOCK (config.lock_add); const size_t hash = path.Hash (); if (applications.find (hash) == applications.end ()) { ITEM_APPLICATION* ptr = &applications[hash]; // application pointer config.is_firstapply = FALSE; // lock checkbox notifications // save config ptr->is_checked = is_checked; ptr->is_system = (_wcsnicmp (path, config.windows_dir, config.wd_length) == 0); StringCchCopy (ptr->full_path, _countof (ptr->full_path), path); StringCchCopy (ptr->file_dir, _countof (ptr->file_dir), path); StringCchCopy (ptr->file_name, _countof (ptr->file_name), PathFindFileName (path)); PathRemoveFileSpec (ptr->file_dir); _app_getinfo (ptr); // read file information size_t item = _r_listview_getitemcount (hwnd, IDC_LISTVIEW); _r_listview_additem (hwnd, IDC_LISTVIEW, path, item, 0, ptr->icon_id, LAST_VALUE, hash); _r_listview_setcheckstate (hwnd, IDC_LISTVIEW, item, is_checked); config.is_firstapply = TRUE; // unlock checkbox notifications } _R_SPINUNLOCK (config.lock_add); return hash; } VOID _wfp_destroyfilters () { HANDLE henum = nullptr; DWORD result = 0; if (!config.hengine || !config.is_admin) return; result = FwpmFilterCreateEnumHandle (config.hengine, nullptr, &henum); if (result != ERROR_SUCCESS) { WDBG (L"FwpmFilterCreateEnumHandle failed. Return value: 0x%.8lx.", result); } else { UINT32 count = 0; FWPM_FILTER** matchingFwpFilter = nullptr; result = FwpmFilterEnum (config.hengine, henum, 0xFFFFFFFF, &matchingFwpFilter, &count); if (result != ERROR_SUCCESS) { WDBG (L"FwpmFilterEnum failed. Return value: 0x%.8lx.", result); } else { if (matchingFwpFilter) { for (UINT32 i = 0; i < count; i++) { if (matchingFwpFilter[i]->providerKey && memcmp (matchingFwpFilter[i]->providerKey, &GUID_WfpProvider, sizeof (GUID)) == 0) FwpmFilterDeleteById (config.hengine, matchingFwpFilter[i]->filterId); } FwpmFreeMemory ((LPVOID*)&matchingFwpFilter); } } } if (henum) FwpmFilterDestroyEnumHandle (config.hengine, henum); } VOID _wfp_createfilter (LPCWSTR name, FWPM_FILTER_CONDITION* lpcond, UINT32 const count, UINT8 weight, GUID layer, GUID callout, FWP_ACTION_TYPE type) { if (!config.is_admin || !config.hengine) return; FWPM_FILTER filter = {0}; filter.flags = FWPM_FILTER_FLAG_PERSISTENT; WCHAR nameptr[MAX_PATH] = {0}; StringCchCopy (nameptr, _countof (nameptr), name ? name : L""); filter.displayData.name = APP_NAME; filter.displayData.description = nameptr; filter.providerKey = (LPGUID)&GUID_WfpProvider; filter.layerKey = layer; filter.subLayerKey = GUID_WfpSublayer; filter.numFilterConditions = count; filter.filterCondition = lpcond; filter.action.type = type; filter.action.calloutKey = callout; filter.weight.type = FWP_UINT8; filter.weight.uint8 = weight; UINT64 filter_id = 0; DWORD result = FwpmFilterAdd (config.hengine, &filter, nullptr, &filter_id); if (result != ERROR_SUCCESS) WDBG (L"FwpmFilterAdd failed. Return value: 0x%.8lx.", result); } INT CALLBACK CompareFunc (LPARAM lp1, LPARAM lp2, LPARAM sortParam) { BOOL isAsc = HIWORD (sortParam); BOOL isByFN = LOWORD (sortParam); size_t item1 = static_cast(lp1); size_t item2 = static_cast(lp2); INT result = 0; if (applications.find (item1) == applications.end () || applications.find (item2) == applications.end ()) return 0; const ITEM_APPLICATION* app1 = &applications[item1]; const ITEM_APPLICATION* app2 = &applications[item2]; if (app1->is_checked && !app2->is_checked) { result = -1; } else if (!app1->is_checked && app2->is_checked) { result = 1; } else { result = _wcsicmp (isByFN ? app1->file_name : app1->file_dir, isByFN ? app2->file_name : app2->file_dir); } return isAsc ? -result : result; } VOID _app_listviewsort (HWND hwnd) { LPARAM lparam = MAKELPARAM (app.ConfigGet (L"SortMode", 1).AsUint (), app.ConfigGet (L"IsSortDescending", FALSE).AsBool ()); CheckMenuRadioItem (GetMenu (hwnd), IDM_SORTBYFNAME, IDM_SORTBYFDIR, (LOWORD (lparam) ? IDM_SORTBYFNAME : IDM_SORTBYFDIR), MF_BYCOMMAND); CheckMenuItem (GetMenu (hwnd), IDM_SORTISDESCEND, MF_BYCOMMAND | (HIWORD (lparam) ? MF_CHECKED : MF_UNCHECKED)); SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_SORTITEMS, lparam, (LPARAM)&CompareFunc); } ADDRESS_FAMILY _wfp_parseip (LPCWSTR ip, FWPM_FILTER_CONDITION* pcond, FWP_V4_ADDR_AND_MASK* addrmask4, FWP_V6_ADDR_AND_MASK* addrmask6) { if (pcond) { NET_ADDRESS_INFO ni; SecureZeroMemory (&ni, sizeof (ni)); BYTE prefix = 0; DWORD result = ParseNetworkString (ip, NET_STRING_IP_ADDRESS | NET_STRING_IP_NETWORK | NET_STRING_IP_ADDRESS_NO_SCOPE, &ni, nullptr, &prefix); if (result == ERROR_SUCCESS) { pcond->fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS; pcond->matchType = FWP_MATCH_EQUAL; if (ni.IpAddress.sa_family == AF_INET && addrmask4) { pcond->conditionValue.type = FWP_V4_ADDR_MASK; pcond->conditionValue.v4AddrMask = addrmask4; addrmask4->addr = ntohl (ni.Ipv4Address.sin_addr.S_un.S_addr); ConvertLengthToIpv4Mask (prefix, (PULONG)&addrmask4->mask); addrmask4->mask = ntohl (addrmask4->mask); return AF_INET; } else if (ni.IpAddress.sa_family == AF_INET6 && addrmask6) { pcond->conditionValue.type = FWP_V6_ADDR_MASK; pcond->conditionValue.v6AddrMask = addrmask6; memcpy (addrmask6->addr, ni.Ipv6Address.sin6_addr.u.Byte, FWP_V6_ADDR_SIZE); addrmask6->prefixLength = prefix; return AF_INET6; } } else { WDBG (L"ParseNetworkString failed. Return value: 0x%.8lx.", result); } } return AF_UNSPEC; } LPWSTR LoadTextFromResource (UINT rc_id, LPDWORD size) { HRSRC res = FindResource (nullptr, MAKEINTRESOURCE (rc_id), RT_RCDATA); if (res) { HGLOBAL res_data = LoadResource (nullptr, res); if (res_data) { LPVOID ptr = LockResource (res_data); if (ptr) { if (size) *size = SizeofResource (nullptr, res); return (LPWSTR)ptr; } } } return nullptr; } VOID _app_loadrules () { pugi::xml_document doc; rules_ext.clear (); // load default rules if (app.ConfigGet (L"UseBlocklist", TRUE).AsBool ()) { DWORD size = 0; LPWSTR ptr = LoadTextFromResource (1, &size); if (ptr) { if (doc.load_buffer (ptr, size, pugi::parse_escapes, pugi::encoding_utf16_le)) { pugi::xml_node root = doc.child (L"root"); if (root) { for (pugi::xml_node item = root.child (L"item"); item; item = item.next_sibling (L"item")) { ITEM_RULE_EXT rule; SecureZeroMemory (&rule, sizeof (rule)); StringCchCopy (rule.name, _countof (rule.name), item.attribute (L"name").as_string ()); StringCchCopy (rule.rule, _countof (rule.rule), item.attribute (L"rule").as_string ()); rule.direction = (EnumDirection)item.attribute (L"direction").as_uint (); rule.is_block = item.attribute (L"is_block").as_bool (); rule.is_port = item.attribute (L"is_port").as_bool (); rule.is_enabled = item.attribute (L"is_enabled").as_bool (); rule.is_default = TRUE; rules_ext.push_back (rule); } } doc.reset (); } } } // load user rules if (doc.load_file (config.rules_path, pugi::parse_escapes, pugi::encoding_utf16_le)) { pugi::xml_node root = doc.child (L"root"); if (root) { for (pugi::xml_node item = root.child (L"item"); item; item = item.next_sibling (L"item")) { ITEM_RULE_EXT rule; SecureZeroMemory (&rule, sizeof (rule)); StringCchCopy (rule.name, _countof (rule.name), item.attribute (L"name").as_string ()); StringCchCopy (rule.rule, _countof (rule.rule), item.attribute (L"rule").as_string ()); rule.direction = (EnumDirection)item.attribute (L"direction").as_uint (); rule.is_block = item.attribute (L"is_block").as_bool (); rule.is_port = item.attribute (L"is_port").as_bool (); rule.is_enabled = item.attribute (L"is_enabled").as_bool (); rule.is_default = FALSE; rules_ext.push_back (rule); } } doc.reset (); } } VOID _app_profilesave (HWND hwnd) { _R_SPINLOCK (config.lock_profile); pugi::xml_document doc_apps; pugi::xml_node root_apps = doc_apps.append_child (L"root"); if (root_apps) { for (size_t i = 0; i < _r_listview_getitemcount (hwnd, IDC_LISTVIEW); i++) { const size_t hash = (size_t)_r_listview_getlparam (hwnd, IDC_LISTVIEW, i); if (!hash || applications.find (hash) == applications.end ()) continue; ITEM_APPLICATION const* ptr = &applications[hash]; pugi::xml_node item = root_apps.append_child (L"item"); item.append_attribute (L"path").set_value (ptr->full_path); item.append_attribute (L"is_enabled").set_value (ptr->is_checked); } doc_apps.save_file (config.config_path, L"\t", pugi::format_no_escapes | pugi::format_indent | pugi::format_write_bom, pugi::encoding_utf16_le); } pugi::xml_document doc_rules; pugi::xml_node root_rules = doc_rules.append_child (L"root"); if (root_rules) { for (size_t i = 0; i < rules_ext.size (); i++) { ITEM_RULE_EXT const* ptr = &rules_ext.at (i); if (ptr->is_default) continue; pugi::xml_node item = root_rules.append_child (L"item"); item.append_attribute (L"name").set_value (ptr->name); item.append_attribute (L"rule").set_value (ptr->rule); item.append_attribute (L"direction").set_value (ptr->direction); item.append_attribute (L"is_block").set_value (ptr->is_block); item.append_attribute (L"is_port").set_value (ptr->is_port); item.append_attribute (L"is_enabled").set_value (ptr->is_enabled); } doc_rules.save_file (config.rules_path, L"\t", pugi::format_no_escapes | pugi::format_indent | pugi::format_write_bom, pugi::encoding_utf16_le); } _R_SPINUNLOCK (config.lock_profile); } VOID _wfp_createportfilter (FWPM_FILTER_CONDITION* pcond, LPCWSTR name, UINT8 proto, GUID portdir, UINT16 port, UINT8 weight, GUID layer, GUID callout, FWP_ACTION_TYPE action) { UINT32 count = 1; if (pcond) { if (proto) { pcond[count].fieldKey = FWPM_CONDITION_IP_PROTOCOL; pcond[count].matchType = FWP_MATCH_EQUAL; pcond[count].conditionValue.type = FWP_UINT8; pcond[count].conditionValue.uint8 = proto; count += 1; } if (port) { pcond[count].fieldKey = portdir; pcond[count].matchType = FWP_MATCH_EQUAL; pcond[count].conditionValue.type = FWP_UINT16; pcond[count].conditionValue.uint16 = port; count += 1; } if (count) _wfp_createfilter (name, pcond, count, weight, layer, callout, action); } } VOID _wfp_applypath (LPCWSTR path, FWP_ACTION_TYPE action, BOOL is_service) { FWP_BYTE_BLOB* blob = nullptr; DWORD result = FwpmGetAppIdFromFileName (path, &blob); if (result != ERROR_SUCCESS) { WDBG (L"FwpmGetAppIdFromFileName failed. Return value: 0x%.8lx. (%s)", result, path); } else { FWPM_FILTER_CONDITION fwfc[3] = {0}; fwfc[0].fieldKey = FWPM_CONDITION_ALE_APP_ID; fwfc[0].matchType = FWP_MATCH_EQUAL; fwfc[0].conditionValue.type = FWP_BYTE_BLOB_TYPE; fwfc[0].conditionValue.byteBlob = blob; if (!is_service) { // set outbound connections _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); // set inbound connections _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); // set listen connections _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_LISTEN_V4, GUID_WfpListenCallout4, action); _wfp_createfilter (path, fwfc, 1, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_LISTEN_V6, GUID_WfpListenCallout6, action); } else { // allow dhcp service if (app.ConfigGet (L"AllowDhcpService", TRUE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 67, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 68, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 546, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 547, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); } // allow dns service if (app.ConfigGet (L"AllowDnsService", TRUE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 53, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 53, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); } // allow ntp service if (app.ConfigGet (L"AllowNtpService", TRUE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 123, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); } // allow snmp service if (app.ConfigGet (L"AllowSnmpService", FALSE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 161, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 162, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 161, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 162, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); } // allow ssdp service if (app.ConfigGet (L"AllowSsdpService", TRUE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 1900, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); } // allow windows update service if (app.ConfigGet (L"AllowWindowUpdateService", FALSE).AsBool ()) { _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 80, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 80, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 443, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 443, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); } // allow netwok discovery service if (app.ConfigGet (L"AllowNetworkDiscoveryService", TRUE).AsBool ()) { // microsoft directory _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 445, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); // netbios name _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 137, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); // netbios datagram _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 138, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_LOCAL_PORT, 138, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 138, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_UDP, FWPM_CONDITION_IP_REMOTE_PORT, 138, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); // netbios session _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 139, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_LOCAL_PORT, 139, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 139, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createportfilter (fwfc, path, IPPROTO_TCP, FWPM_CONDITION_IP_REMOTE_PORT, 139, FILTER_WEIGHT_APPLICATION, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); } } FwpmFreeMemory ((LPVOID*)&blob); } } VOID _wfp_applyfilters (HWND hwnd, BOOL is_silent) { if (!config.hengine || !config.is_admin) return; _R_SPINLOCK (config.lock_apply); const EnumMode mode = (EnumMode)app.ConfigGet (L"Mode", Whitelist).AsUint (); FWPM_FILTER_CONDITION fwfc[3] = {0}; DWORD result = FwpmTransactionBegin (config.hengine, 0); if (result != ERROR_SUCCESS) { WDBG (L"FwpmTransactionBegin failed. Return value: 0x%.8lx.", result); } else { _wfp_destroyfilters (); if (mode != TrustNoOne) { fwfc[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL; fwfc[0].matchType = FWP_MATCH_EQUAL; fwfc[0].conditionValue.type = FWP_UINT8; //fwfc[0].conditionValue.uint8 = IPPROTO_UDP; // allow outbound icmp protocol if (app.ConfigGet (L"AllowOutboundIcmp", TRUE).AsBool ()) { fwfc[0].conditionValue.uint8 = IPPROTO_ICMP; _wfp_createfilter (nullptr, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, FWP_ACTION_PERMIT); fwfc[0].conditionValue.uint8 = IPPROTO_ICMPV6; _wfp_createfilter (nullptr, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, FWP_ACTION_PERMIT); } // allow inbound icmp protocol if (app.ConfigGet (L"AllowInboundIcmp", FALSE).AsBool ()) { fwfc[0].conditionValue.uint8 = IPPROTO_ICMP; _wfp_createfilter (nullptr, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, FWP_ACTION_PERMIT); fwfc[0].conditionValue.uint8 = IPPROTO_ICMPV6; _wfp_createfilter (nullptr, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, FWP_ACTION_PERMIT); } // add loopback connections permission { FWP_V4_ADDR_AND_MASK addrmask4 = {0}; FWP_V6_ADDR_AND_MASK addrmask6 = {0}; // First condition. Match only unicast addresses. fwfc[0].fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE; fwfc[0].matchType = FWP_MATCH_EQUAL; fwfc[0].conditionValue.type = FWP_UINT8; fwfc[0].conditionValue.uint8 = NlatUnicast; // Second condition. Match all loopback (localhost) data. fwfc[1].fieldKey = FWPM_CONDITION_FLAGS; fwfc[1].matchType = FWP_MATCH_EQUAL; fwfc[1].conditionValue.type = FWP_UINT32; fwfc[1].conditionValue.uint32 = FWP_CONDITION_FLAG_IS_LOOPBACK; _wfp_createfilter (nullptr, fwfc, 2, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, FWP_ACTION_PERMIT); _wfp_createfilter (nullptr, fwfc, 2, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, FWP_ACTION_PERMIT); _wfp_createfilter (nullptr, fwfc, 2, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, FWP_ACTION_PERMIT); _wfp_createfilter (nullptr, fwfc, 2, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, FWP_ACTION_PERMIT); // ipv4/ipv6 loopback LPCWSTR loopback4[] = {L"10.0.0.0/8", L"172.16.0.0/12", L"169.254.0.0/16", L"192.168.0.0/16"}; for (size_t i = 0; i < _countof (loopback4); i++) { _wfp_parseip (loopback4[i], &fwfc[2], &addrmask4, &addrmask6); _wfp_createfilter (loopback4[i], fwfc, 3, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, FWP_ACTION_PERMIT); _wfp_createfilter (loopback4[i], fwfc, 3, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, FWP_ACTION_PERMIT); } LPCWSTR loopback6[] = {L"fd00::/8", L"fe80::/10"}; for (size_t i = 0; i < _countof (loopback6); i++) { _wfp_parseip (loopback6[i], &fwfc[2], &addrmask4, &addrmask6); _wfp_createfilter (loopback6[i], fwfc, 3, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, FWP_ACTION_PERMIT); _wfp_createfilter (loopback6[i], fwfc, 3, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, FWP_ACTION_PERMIT); } } // load rules from file _app_loadrules (); // apply IP rules { for (size_t i = 0; i < rules_ext.size (); i++) { if (!rules_ext.at (i).is_enabled || (app.ConfigGet (L"UseBlocklist", TRUE).AsBool () == FALSE && rules_ext.at (i).is_default)) continue; FWP_ACTION_TYPE action = rules_ext.at (i).is_block ? FWP_ACTION_BLOCK : FWP_ACTION_PERMIT; rstring arr = rules_ext.at (i).rule; rstring::rvector vc = arr.AsVector (L",; "); for (size_t j = 0; j < vc.size (); j++) { vc.at (j).Trim (L" "); // trim whitespace if (rules_ext.at (i).is_port) { //fwfc[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; fwfc[0].matchType = FWP_MATCH_EQUAL; fwfc[0].conditionValue.type = FWP_UINT16; fwfc[0].conditionValue.uint16 = (UINT16)vc.at (j).AsUint (); if (rules_ext.at (i).direction == Out || rules_ext.at (i).direction == Both) { fwfc[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, action); _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); } if (rules_ext.at (i).direction == In || rules_ext.at (i).direction == Both) { fwfc[0].fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS; _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, action); _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); } } else { FWP_V4_ADDR_AND_MASK addrmask4 = {0}; FWP_V6_ADDR_AND_MASK addrmask6 = {0}; ADDRESS_FAMILY af = _wfp_parseip (vc.at (j), &fwfc[0], &addrmask4, &addrmask6); if (af == AF_INET6) { // outbound ipv6 address if (rules_ext.at (i).direction == Out || rules_ext.at (i).direction == Both) _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, action); // inbound ipv6 address if (rules_ext.at (i).direction == In || rules_ext.at (i).direction == Both) _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, action); } else if (af == AF_INET) { // outbound ipv4 address if (rules_ext.at (i).direction == Out || rules_ext.at (i).direction == Both) _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, rules_ext.at (i).is_block ? FWP_ACTION_BLOCK : FWP_ACTION_PERMIT); // inbound ipv4 address if (rules_ext.at (i).direction == In || rules_ext.at (i).direction == Both) _wfp_createfilter (rules_ext.at (i).name, fwfc, 1, FILTER_WEIGHT_HIGHEST, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, rules_ext.at (i).is_block ? FWP_ACTION_BLOCK : FWP_ACTION_PERMIT); } } } } } // application filters { BOOL is_svchostallowed = FALSE; BOOL is_myselfallowed = FALSE; for (auto const& p : applications) { if (!p.second.is_checked) continue; if ((mode == Whitelist) && config.svchost_hash == p.first) is_svchostallowed = TRUE; if ((mode == Whitelist) && config.myself_hash == p.first && app.ConfigGet (L"DoNotBlockMainExecutable", TRUE).AsBool ()) is_myselfallowed = TRUE; _wfp_applypath (p.second.full_path, (mode == Whitelist) ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK, FALSE); } // unlock itself if (!is_myselfallowed && app.ConfigGet (L"DoNotBlockMainExecutable", TRUE).AsBool ()) _wfp_applypath (config.myself_path, FWP_ACTION_PERMIT, FALSE); // allow services if (!is_svchostallowed) { _wfp_applypath (L"System", FWP_ACTION_PERMIT, TRUE); _wfp_applypath (config.svchost_path, FWP_ACTION_PERMIT, TRUE); } } } // block all other traffic (only on "whitelist" & "trust no one" mode) if (mode == Whitelist || mode == TrustNoOne) { UINT8 weight = (mode == Whitelist) ? FILTER_WEIGHT_ALLOWBLOCK : FILTER_WEIGHT_HIGHEST; _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4, FWP_ACTION_BLOCK); _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6, FWP_ACTION_BLOCK); if (mode == TrustNoOne || app.ConfigGet (L"AllowInboundConnections", FALSE).AsBool () == FALSE) { _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4, FWP_ACTION_BLOCK); _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6, FWP_ACTION_BLOCK); _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_LISTEN_V4, GUID_WfpListenCallout4, FWP_ACTION_BLOCK); _wfp_createfilter (nullptr, nullptr, 0, weight, FWPM_LAYER_ALE_AUTH_LISTEN_V6, GUID_WfpListenCallout6, FWP_ACTION_BLOCK); } } FwpmTransactionCommit (config.hengine); } if (!is_silent && app.ConfigGet (L"ShowBalloonTips", TRUE).AsBool ()) app.TrayPopup (NIIF_INFO, APP_NAME, I18N (&app, IDS_STATUS_FILTERS, 0)); _app_listviewsort (hwnd); _app_profilesave (hwnd); _R_SPINUNLOCK (config.lock_apply); } VOID _wfp_createcallout (HANDLE h, const GUID layer_key, const GUID callout_key) { FWPM_CALLOUT0 callout = {0}; UINT32 callout_id = 0; callout.displayData.name = APP_NAME; callout.displayData.description = APP_NAME; callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; callout.providerKey = (LPGUID)&GUID_WfpProvider; callout.calloutKey = callout_key; callout.applicableLayer = layer_key; DWORD result = FwpmCalloutAdd (h, &callout, nullptr, &callout_id); if (result != ERROR_SUCCESS && result != FWP_E_ALREADY_EXISTS) WDBG (L"FwpmCalloutAdd failed. Return value: 0x%.8lx.", result); } VOID CALLBACK DropEventCallback (LPVOID, const FWPM_NET_EVENT1* pEvent) { WCHAR prot[100] = {0}; if (pEvent->header.ipProtocol == IPPROTO_ICMP) { StringCchCopy (prot, _countof (prot), L"ICMP"); } else if (pEvent->header.ipProtocol == IPPROTO_TCP) { StringCchCopy (prot, _countof (prot), L"TCP"); } else if (pEvent->header.ipProtocol == IPPROTO_UDP) { StringCchCopy (prot, _countof (prot), L"UDP"); } else if (pEvent->header.ipProtocol == IPPROTO_ICMPV6) { StringCchCopy (prot, _countof (prot), L"ICMPv6"); } else if (pEvent->header.ipProtocol == IPPROTO_ICMPV6) { StringCchCopy (prot, _countof (prot), L"ICMPv6"); } else if (pEvent->header.ipProtocol == IPPROTO_RAW) { StringCchCopy (prot, _countof (prot), L"RAW"); } else if (pEvent->header.ipProtocol == IPPROTO_IGMP) { StringCchCopy (prot, _countof (prot), L"IGMP"); } else if (pEvent->header.ipProtocol == IPPROTO_L2TP) { StringCchCopy (prot, _countof (prot), L"L2TP"); } else { StringCchCopy (prot, _countof (prot), L"N/A"); } if (pEvent->header.ipVersion == FWP_IP_VERSION_V4) { if ((pEvent->header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET) != 0) { WDBG (L"[%s] %s [%s:%d.%d.%d.%d:%d] Out", APP_NAME_SHORT, pEvent->header.appId.data, prot, pEvent->header.remoteAddrV6.byteArray16[3], pEvent->header.remoteAddrV6.byteArray16[2], pEvent->header.remoteAddrV6.byteArray16[1], pEvent->header.remoteAddrV6.byteArray16[0], pEvent->header.remotePort ); } if ((pEvent->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET) != 0) { WDBG (L"[%s] %s [%s:%d.%d.%d.%d:%d] In", APP_NAME_SHORT, pEvent->header.appId.data, prot, pEvent->header.localAddrV6.byteArray16[3], pEvent->header.localAddrV6.byteArray16[2], pEvent->header.localAddrV6.byteArray16[1], pEvent->header.localAddrV6.byteArray16[0], pEvent->header.localPort ); } } else if (pEvent->header.ipVersion == FWP_IP_VERSION_V6) { if ((pEvent->header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET) != 0) { WDBG (L"[%s] %s [%s:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d] Out", APP_NAME_SHORT, pEvent->header.appId.data, prot, pEvent->header.remoteAddrV6.byteArray16[0], pEvent->header.remoteAddrV6.byteArray16[1], pEvent->header.remoteAddrV6.byteArray16[2], pEvent->header.remoteAddrV6.byteArray16[3], pEvent->header.remoteAddrV6.byteArray16[4], pEvent->header.remoteAddrV6.byteArray16[5], pEvent->header.remoteAddrV6.byteArray16[6], pEvent->header.remoteAddrV6.byteArray16[7], pEvent->header.remoteAddrV6.byteArray16[8], pEvent->header.remoteAddrV6.byteArray16[9], pEvent->header.remoteAddrV6.byteArray16[10], pEvent->header.remoteAddrV6.byteArray16[11], pEvent->header.remoteAddrV6.byteArray16[12], pEvent->header.remoteAddrV6.byteArray16[13], pEvent->header.remoteAddrV6.byteArray16[14], pEvent->header.remoteAddrV6.byteArray16[15], pEvent->header.remotePort ); } if ((pEvent->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET) != 0) { WDBG (L"[%s] %s [%s:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d] In", APP_NAME_SHORT, pEvent->header.appId.data, prot, pEvent->header.localAddrV6.byteArray16[0], pEvent->header.localAddrV6.byteArray16[1], pEvent->header.localAddrV6.byteArray16[2], pEvent->header.localAddrV6.byteArray16[3], pEvent->header.localAddrV6.byteArray16[4], pEvent->header.localAddrV6.byteArray16[5], pEvent->header.localAddrV6.byteArray16[6], pEvent->header.localAddrV6.byteArray16[7], pEvent->header.localAddrV6.byteArray16[8], pEvent->header.localAddrV6.byteArray16[9], pEvent->header.localAddrV6.byteArray16[10], pEvent->header.localAddrV6.byteArray16[11], pEvent->header.localAddrV6.byteArray16[12], pEvent->header.localAddrV6.byteArray16[13], pEvent->header.localAddrV6.byteArray16[14], pEvent->header.localAddrV6.byteArray16[15], pEvent->header.localPort ); } } } VOID _wfp_setevents (BOOL is_install, LPGUID const session_key) { if (!config.hengine) return; DWORD result = 0; if (is_install) { FWP_VALUE val; SecureZeroMemory (&val, sizeof (val)); val.type = FWP_UINT32; val.uint32 = 1; result = FwpmEngineSetOption (config.hengine, FWPM_ENGINE_COLLECT_NET_EVENTS, &val); if (result != ERROR_SUCCESS) WDBG (L"FwpmEngineSetOption failed. Return value: 0x%.8lx.", result); } FWPMNES0 _FwpmNetEventSubscribe0 = (FWPMNES0)GetProcAddress (GetModuleHandle (L"fwpuclnt.dll"), "FwpmNetEventSubscribe0"); FWPMNEU0 _FwpmNetEventUnsubscribe0 = (FWPMNEU0)GetProcAddress (GetModuleHandle (L"fwpuclnt.dll"), "FwpmNetEventUnsubscribe0"); if (!_FwpmNetEventUnsubscribe0 || !_FwpmNetEventUnsubscribe0) { WDBG (L"GetProcAddress failed. Return value: 0x%.8lx.", GetLastError ()); } else { if (is_install) { FWPM_NET_EVENT_ENUM_TEMPLATE0 enumTemplate; FWPM_NET_EVENT_SUBSCRIPTION0 subscription; SecureZeroMemory (&enumTemplate, sizeof (enumTemplate)); SecureZeroMemory (&subscription, sizeof (subscription)); subscription.sessionKey = *session_key; subscription.enumTemplate = &enumTemplate; result = _FwpmNetEventSubscribe0 (config.hengine, &subscription, DropEventCallback, nullptr, &config.hevent); if (result != ERROR_SUCCESS) WDBG (L"FwpmNetEventSubscribe0 failed. Return value: 0x%.8lx.", result); } else { if (config.hevent) { result = _FwpmNetEventUnsubscribe0 (config.hengine, config.hevent); config.hevent = nullptr; if (result != ERROR_SUCCESS) WDBG (L"FwpmNetEventUnsubscribe0 failed. Return value: 0x%.8lx.", result); } } } if (!is_install) { FWP_VALUE val; SecureZeroMemory (&val, sizeof (val)); val.type = FWP_UINT32; val.uint32 = 0; result = FwpmEngineSetOption (config.hengine, FWPM_ENGINE_COLLECT_NET_EVENTS, &val); if (result != ERROR_SUCCESS) WDBG (L"FwpmEngineSetOption failed. Return value: 0x%.8lx.", result); } } UINT WINAPI ApplyThread (LPVOID) { HANDLE evts[] = {config.apply_evt, config.apply2_evt, config.stop_evt}; while (TRUE) { DWORD state = WaitForMultipleObjectsEx (_countof (evts), evts, FALSE, INFINITE, FALSE); if (state == WAIT_OBJECT_0 || (state == WAIT_OBJECT_0 + 1)) // apply event { BOOL is_silent = (state == WAIT_OBJECT_0 + 1); _wfp_applyfilters (app.GetHWND (), is_silent); } else if (state == WAIT_OBJECT_0 + 2) // stop event { _wfp_setevents (FALSE, nullptr); break; } } return ERROR_SUCCESS; } VOID _wfp_start () { if (config.hengine || !config.is_admin) return; FWPM_SESSION session = {0}; session.displayData.name = APP_NAME; session.displayData.description = APP_NAME; DWORD result = FwpmEngineOpen (nullptr, RPC_C_AUTHN_WINNT, nullptr, nullptr, &config.hengine); if (result != ERROR_SUCCESS) { WDBG (L"FwpmEngineOpen failed. Return value: 0x%.8lx.", result); } else { // configure net events (win7 and above) _wfp_setevents (TRUE, &session.sessionKey); result = FwpmTransactionBegin (config.hengine, 0); if (result != ERROR_SUCCESS) { WDBG (L"FwpmTransactionBegin failed. Return value: 0x%.8lx.", result); } else { FWPM_PROVIDER provider = {0}; provider.displayData.name = APP_NAME; provider.displayData.description = APP_NAME; provider.providerKey = GUID_WfpProvider; provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT; result = FwpmProviderAdd (config.hengine, &provider, nullptr); if (result != ERROR_SUCCESS && result != FWP_E_ALREADY_EXISTS) { WDBG (L"FwpmProviderAdd failed. Return value: 0x%.8lx.", result); FwpmTransactionAbort (config.hengine); } else { FWPM_SUBLAYER sublayer = {0}; sublayer.displayData.name = APP_NAME; sublayer.displayData.description = APP_NAME; sublayer.providerKey = (LPGUID)&GUID_WfpProvider; sublayer.subLayerKey = GUID_WfpSublayer; sublayer.flags = FWPM_SUBLAYER_FLAG_PERSISTENT; sublayer.weight = (UINT16)app.ConfigGet (L"SublayerWeight", 0x0000ffff).AsUint (); result = FwpmSubLayerAdd (config.hengine, &sublayer, nullptr); if (result != ERROR_SUCCESS && result != FWP_E_ALREADY_EXISTS) { WDBG (L"FwpmSubLayerAdd failed. Return value: 0x%.8lx.", result); FwpmTransactionAbort (config.hengine); } else { // create outbound callouts _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_CONNECT_V4, GUID_WfpOutboundCallout4); _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_CONNECT_V6, GUID_WfpOutboundCallout6); // create inbound callouts _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, GUID_WfpInboundCallout4); _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, GUID_WfpInboundCallout6); // create listen callouts _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_LISTEN_V4, GUID_WfpListenCallout4); _wfp_createcallout (config.hengine, FWPM_LAYER_ALE_AUTH_LISTEN_V6, GUID_WfpListenCallout6); result = FwpmTransactionCommit (config.hengine); if (result != ERROR_SUCCESS) { WDBG (L"FwpmTransactionCommit failed. Return value: 0x%.8lx.", result); } else { if (!config.hthread) config.hthread = (HANDLE)_beginthreadex (nullptr, 0, &ApplyThread, nullptr, 0, nullptr); app.SetIcon (IDI_MAIN); app.TraySetInfo (_r_loadicon (app.GetHINSTANCE (), MAKEINTRESOURCE (IDI_MAIN), GetSystemMetrics (SM_CXSMICON)), APP_NAME); SetEvent (config.apply2_evt); // apply filters return; } } } } } app.TrayPopup (NIIF_ERROR, APP_NAME, I18N (&app, IDS_STATUS_FILTERS_FAILED, 0)); } VOID _wfp_stop () { DWORD result = 0; if (config.hengine) { _wfp_setevents (FALSE, nullptr); // start transaction result = FwpmTransactionBegin (config.hengine, 0); if (result != ERROR_SUCCESS) { WDBG (L"FwpmTransactionBegin failed. Return value: 0x%.8lx.", result); } else { if (config.hthread) { SetEvent (config.stop_evt); // stop thread config.hthread = nullptr; } _wfp_destroyfilters (); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpOutboundCallout4); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpOutboundCallout6); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpInboundCallout4); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpInboundCallout6); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpListenCallout4); FwpmCalloutDeleteByKey (config.hengine, &GUID_WfpListenCallout6); FwpmSubLayerDeleteByKey (config.hengine, &GUID_WfpSublayer); result = FwpmProviderDeleteByKey (config.hengine, &GUID_WfpProvider); if (result != ERROR_SUCCESS) WDBG (L"FwpmProviderDeleteByKey failed. Return value: 0x%.8lx.", result); FwpmTransactionCommit (config.hengine); } FwpmEngineClose (config.hengine); config.hengine = nullptr; app.SetIcon (IDI_INACTIVE); app.TraySetInfo (_r_loadicon (app.GetHINSTANCE (), MAKEINTRESOURCE (IDI_INACTIVE), GetSystemMetrics (SM_CXSMICON)), APP_NAME); if (app.ConfigGet (L"ShowBalloonTips", TRUE).AsBool ()) app.TrayPopup (NIIF_INFO, APP_NAME, I18N (&app, IDS_STATUS_FILTERS_REMOVED, 0)); } } VOID addrule (LPCWSTR locale_sid, UINT locale_id, LPCWSTR cfg, BOOL defval, size_t group_id) { ITEM_RULE rule; rule.is_enabled = defval; rule.group_id = group_id; rule.locale_id = locale_id; StringCchCopy (rule.locale_sid, _countof (rule.locale_sid), locale_sid); StringCchCopy (rule.config, _countof (rule.config), cfg); rules.push_back (rule); } VOID addcolor (LPCWSTR locale_sid, UINT locale_id, LPCWSTR cfg, BOOL is_enabled, LPCWSTR config_color, COLORREF default_clr) { ITEM_COLOR color; StringCchCopy (color.config, _countof (color.config), cfg); StringCchCopy (color.config_color, _countof (color.config_color), config_color); color.is_enabled = is_enabled; color.default_clr = default_clr; color.locale_id = locale_id; StringCchCopy (color.locale_sid, _countof (color.locale_sid), locale_sid); colors.push_back (color); } VOID _app_getprocesslist (HWND hwnd, std::vector* pvc) { if (!config.is_admin) return; if (pvc) { for (size_t i = 0; i < pvc->size (); i++) DeleteObject (pvc->at (i).hbmp); // free memory pvc->clear (); } NTSTATUS status = 0; OBJECT_ATTRIBUTES oa = {0}; ULONG length = 0x4000; PVOID buffer = malloc (length); while (TRUE) { status = NtQuerySystemInformation (SystemProcessInformation, buffer, length, &length); if (status == 0xC0000023L /*STATUS_BUFFER_TOO_SMALL*/ || status == 0xc0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) { PVOID buffer_new = realloc (buffer, length); if (!buffer_new) { break; } else { buffer = buffer_new; } } else { break; } } if (NT_SUCCESS (status)) { PSYSTEM_PROCESS_INFORMATION spi = (PSYSTEM_PROCESS_INFORMATION)buffer; std::unordered_map checker; DWORD size = 0; do { HANDLE hprocess = nullptr; CLIENT_ID client_id = {0}; client_id.UniqueProcess = spi->UniqueProcessId; InitializeObjectAttributes (&oa, nullptr, 0, nullptr, nullptr); if (NT_SUCCESS (NtOpenProcess (&hprocess, PROCESS_QUERY_INFORMATION, &oa, &client_id))) { WCHAR path[512] = {0}; size = _countof (path); if (QueryFullProcessImageName (hprocess, 0, path, &size)) { const size_t hash = rstring (path).Hash (); if (applications.find (hash) == applications.end () && checker.find (hash) == checker.end ()) { checker[hash] = TRUE; if (!pvc) { if (_wcsnicmp (path, config.windows_dir, config.wd_length) != 0) _app_addapplication (hwnd, path, FALSE); } else { ITEM_PROCESS item; SecureZeroMemory (&item, sizeof (item)); StringCchCopy (item.file_path, _countof (item.file_path), path); SHFILEINFO shfi = {0}; SHGetFileInfo (item.file_path, 0, &shfi, sizeof (shfi), SHGFI_SMALLICON | SHGFI_ICON); RECT rc = {0}; rc.right = GetSystemMetrics (SM_CXSMICON); rc.bottom = GetSystemMetrics (SM_CYSMICON); HDC hdc = GetDC (nullptr); HDC hmemdc = CreateCompatibleDC (hdc); HBITMAP hbmp = CreateCompatibleBitmap (hdc, rc.right, rc.bottom); ReleaseDC (nullptr, hdc); HGDIOBJ old_bmp = SelectObject (hmemdc, hbmp); _r_wnd_fillrect (hmemdc, &rc, GetSysColor (COLOR_MENU)); DrawIconEx (hmemdc, 0, 0, shfi.hIcon, rc.right, rc.bottom, 0, nullptr, DI_NORMAL); SelectObject (hmemdc, old_bmp); DeleteDC (hmemdc); DestroyIcon (shfi.hIcon); item.hbmp = hbmp; PathCompactPathEx (item.display_path, item.file_path, _countof (item.display_path), 0); pvc->push_back (item); } } } else { WDBG (L"QueryFullProcessImageName failed: %s", spi->ImageName.Buffer); } NtClose (hprocess); } else { //WDBG (L"NtOpenProcess failed: %s", spi->ImageName.Buffer); } } while ((spi = ((spi->NextEntryOffset ? (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(spi)+(spi)->NextEntryOffset) : nullptr))) != nullptr); } else { WDBG (L"NtQuerySystemInformation failed."); } free (buffer); // free the allocated buffer. } VOID _app_profileload (HWND hwnd) { _R_SPINLOCK (config.lock_profile); // clear all applications.clear (); colors.clear (); rules.clear (); _r_listview_deleteallitems (hwnd, IDC_LISTVIEW); // load applications pugi::xml_document doc; if (doc.load_file (config.config_path, pugi::parse_escapes, pugi::encoding_utf16_le)) { pugi::xml_node root = doc.child (L"root"); if (root) { for (pugi::xml_node item = root.child (L"item"); item; item = item.next_sibling (L"item")) _app_addapplication (hwnd, item.attribute (L"path").as_string (), item.attribute (L"is_enabled").as_bool ()); } } else { _app_getprocesslist (hwnd, nullptr); } _R_SPINUNLOCK (config.lock_profile); // load default rules addrule (L"IDS_RULE_DHCP", IDS_RULE_DHCP, L"AllowDhcpService", TRUE, 0); addrule (L"IDS_RULE_DNS", IDS_RULE_DNS, L"AllowDnsService", TRUE, 0); addrule (L"IDS_RULE_NETWORKDISCOVERY", IDS_RULE_NETWORKDISCOVERY, L"AllowNetworkDiscoveryService", TRUE, 0); addrule (L"IDS_RULE_NTP", IDS_RULE_NTP, L"AllowNtpService", TRUE, 0); addrule (L"IDS_RULE_SNMP", IDS_RULE_SNMP, L"AllowSnmpService", FALSE, 0); addrule (L"IDS_RULE_SSDP", IDS_RULE_SSDP, L"AllowSsdpService", TRUE, 0); addrule (L"IDS_RULE_WUAUSERV", IDS_RULE_WUAUSERV, L"AllowWindowUpdateService", FALSE, 0); addrule (L"IDS_RULE_OUTBOUND_ICMP", IDS_RULE_OUTBOUND_ICMP, L"AllowOutboundIcmp", TRUE, 1); addrule (L"IDS_RULE_INBOUND_ICMP", IDS_RULE_INBOUND_ICMP, L"AllowInboundIcmp", FALSE, 1); addrule (L"IDS_RULE_INBOUND", IDS_RULE_INBOUND, L"AllowInboundConnections", FALSE, 1); addcolor (L"IDS_HIGHLIGHT_SYSTEM", IDS_HIGHLIGHT_SYSTEM, L"IsHighlightSystem", TRUE, L"ColorSystem", COLOR_SYSTEM); addcolor (L"IDS_HIGHLIGHT_INVALID", IDS_HIGHLIGHT_INVALID, L"IsHighlightInvalid", TRUE, L"ColorInvalid", COLOR_INVALID); } BOOL initializer_callback (HWND hwnd, DWORD msg, LPVOID, LPVOID) { switch (msg) { case _RM_INITIALIZE: { // set window icon indicator app.SetIcon (app.ConfigGet (L"IsFiltersEnabled", TRUE).AsBool () ? IDI_MAIN : IDI_INACTIVE); // init tray icon app.TrayCreate (UID, WM_TRAYICON, _r_loadicon (app.GetHINSTANCE (), MAKEINTRESOURCE (app.ConfigGet (L"IsFiltersEnabled", TRUE).AsBool () ? IDI_MAIN : IDI_INACTIVE), GetSystemMetrics (SM_CXSMICON))); if (!config.hengine && app.ConfigGet (L"IsFiltersEnabled", TRUE).AsBool ()) { _wfp_start (); // start firewall } else { SetEvent (config.apply2_evt); // apply filters } CheckMenuItem (GetMenu (hwnd), IDM_ALWAYSONTOP_CHK, MF_BYCOMMAND | (app.ConfigGet (L"AlwaysOnTop", FALSE).AsBool () ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem (GetMenu (hwnd), IDM_CHECKUPDATES_CHK, MF_BYCOMMAND | (app.ConfigGet (L"CheckUpdates", TRUE).AsBool () ? MF_CHECKED : MF_UNCHECKED)); break; } case _RM_LOCALIZE: { HMENU menu = GetMenu (hwnd); app.LocaleMenu (menu, I18N (&app, IDS_FILE, 0), 0, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_SETTINGS, 0), IDM_SETTINGS, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_EXIT, 0), IDM_EXIT, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_EDIT, 0), 1, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_FIND, 0), IDM_FIND, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_FINDNEXT, 0), IDM_FINDNEXT, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_REFRESH, 0), IDM_REFRESH, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_SETTINGS, 0), 2, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_ALWAYSONTOP_CHK, 0), IDM_ALWAYSONTOP_CHK, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_CHECKUPDATES_CHK, 0), IDM_CHECKUPDATES_CHK, FALSE); app.LocaleMenu (GetSubMenu (menu, 2), I18N (&app, IDS_ICONS, 0), 3, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_ICONSSMALL, 0), IDM_ICONSSMALL, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_ICONSLARGE, 0), IDM_ICONSLARGE, FALSE); app.LocaleMenu (GetSubMenu (menu, 2), I18N (&app, IDS_SORT, 0), 4, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_SORTBYFNAME, 0), IDM_SORTBYFNAME, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_SORTBYFDIR, 0), IDM_SORTBYFDIR, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_SORTISDESCEND, 0), IDM_SORTISDESCEND, FALSE); app.LocaleMenu (GetSubMenu (menu, 2), I18N (&app, IDS_LANGUAGE, 0), 6, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_HELP, 0), 3, TRUE); app.LocaleMenu (menu, I18N (&app, IDS_WEBSITE, 0), IDM_WEBSITE, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_DONATE, 0), IDM_DONATE, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_CHECKUPDATES, 0), IDM_CHECKUPDATES, FALSE); app.LocaleMenu (menu, I18N (&app, IDS_ABOUT, 0), IDM_ABOUT, FALSE); app.LocaleEnum ((HWND)GetSubMenu (menu, 2), 6, TRUE, IDM_DEFAULT); // enum localizations _app_refreshstatus (hwnd); // refresh statusbar break; } case _RM_UNINITIALIZE: { app.TrayDestroy (UID); break; } } return FALSE; } INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static ITEM_RULE_EXT* ptr = nullptr; switch (msg) { case WM_INITDIALOG: { ptr = (ITEM_RULE_EXT*)lparam; // configure window _r_wnd_center (hwnd); // localize window SetWindowText (hwnd, I18N (&app, IDS_EDITOR, 0)); SetDlgItemText (hwnd, IDC_NAME, I18N (&app, IDS_NAME, 0)); SetDlgItemText (hwnd, IDC_DIRECTION, I18N (&app, IDS_DIRECTION, 0)); SetDlgItemText (hwnd, IDC_ACTION, I18N (&app, IDS_ACTION, 0)); SetDlgItemText (hwnd, IDC_RULES, I18N (&app, IDS_RULE, 0)); SetDlgItemText (hwnd, IDC_APPLY, I18N (&app, IDS_APPLY, 0)); SetDlgItemText (hwnd, IDC_CLOSE, I18N (&app, IDS_CLOSE, 0)); _r_wnd_addstyle (hwnd, IDC_APPLY, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); _r_wnd_addstyle (hwnd, IDC_CLOSE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); // set data SetDlgItemText (hwnd, IDC_NAME_EDIT, ptr->name); SetDlgItemText (hwnd, IDC_RULES_EDIT, ptr->rule); SendDlgItemMessage (hwnd, IDC_DIRECTION_EDIT, CB_INSERTSTRING, 0, (LPARAM)I18N (&app, IDS_DIRECTION_1, 0).GetString ()); SendDlgItemMessage (hwnd, IDC_DIRECTION_EDIT, CB_INSERTSTRING, 1, (LPARAM)I18N (&app, IDS_DIRECTION_2, 0).GetString ()); SendDlgItemMessage (hwnd, IDC_DIRECTION_EDIT, CB_INSERTSTRING, 2, (LPARAM)I18N (&app, IDS_DIRECTION_3, 0).GetString ()); SendDlgItemMessage (hwnd, IDC_DIRECTION_EDIT, CB_SETCURSEL, (WPARAM)ptr->direction, 0); SendDlgItemMessage (hwnd, IDC_ACTION_EDIT, CB_INSERTSTRING, 0, (LPARAM)I18N (&app, IDS_ACTION_1, 0).GetString ()); SendDlgItemMessage (hwnd, IDC_ACTION_EDIT, CB_INSERTSTRING, 1, (LPARAM)I18N (&app, IDS_ACTION_2, 0).GetString ()); SendDlgItemMessage (hwnd, IDC_ACTION_EDIT, CB_SETCURSEL, ptr->is_block, 0); // set limitation SendDlgItemMessage (hwnd, IDC_NAME_EDIT, EM_LIMITTEXT, _countof (ptr->name) - 1, 0); SendDlgItemMessage (hwnd, IDC_RULES_EDIT, EM_LIMITTEXT, _countof (ptr->rule) - 1, 0); _r_ctrl_enable (hwnd, IDC_APPLY, FALSE); // disable apply button break; } case WM_COMMAND: { if (HIWORD (wparam) == EN_CHANGE || HIWORD (wparam) == CBN_SELENDOK) { BOOL is_enable = SendDlgItemMessage (hwnd, IDC_NAME_EDIT, WM_GETTEXTLENGTH, 0, 0) > 0 && SendDlgItemMessage (hwnd, IDC_RULES_EDIT, WM_GETTEXTLENGTH, 0, 0); _r_ctrl_enable (hwnd, IDC_APPLY, is_enable); // enable apply button return FALSE; } switch (LOWORD (wparam)) { case IDOK: // process Enter key case IDC_APPLY: { StringCchCopy (ptr->name, _countof (ptr->name), _r_ctrl_gettext (hwnd, IDC_NAME_EDIT)); StringCchCopy (ptr->rule, _countof (ptr->rule), _r_ctrl_gettext (hwnd, IDC_RULES_EDIT)); ptr->direction = (EnumDirection)SendDlgItemMessage (hwnd, IDC_DIRECTION_EDIT, CB_GETCURSEL, 0, 0); ptr->is_block = (BOOL)SendDlgItemMessage (hwnd, IDC_ACTION_EDIT, CB_GETCURSEL, 0, 0); EndDialog (hwnd, 1); break; } case IDCANCEL: // process Esc key case IDC_CLOSE: { EndDialog (hwnd, 0); break; } } break; } } return FALSE; } VOID SetIconsSize (HWND hwnd) { HIMAGELIST h = nullptr; RECT rc = {0}; BOOL is_large = app.ConfigGet (L"IsLargeIcons", TRUE).AsBool (); if (SUCCEEDED (SHGetImageList (is_large ? SHIL_LARGE : SHIL_SMALL, IID_IImageList, (LPVOID*)&h))) { SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)h); SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)h); } SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_SCROLL, 0, GetScrollPos (hwnd, SB_VERT)); // scroll-resize-HACK!!! CheckMenuRadioItem (GetMenu (hwnd), IDM_ICONSSMALL, IDM_ICONSLARGE, (is_large ? IDM_ICONSLARGE : IDM_ICONSSMALL), MF_BYCOMMAND); _r_listview_resizeonecolumn (hwnd, IDC_LISTVIEW); } VOID ShowItem (HWND hwnd, UINT ctrl_id, size_t item) { ListView_SetItemState (GetDlgItem (hwnd, ctrl_id), -1, 0, LVIS_SELECTED); // deselect all ListView_SetItemState (GetDlgItem (hwnd, ctrl_id), item, LVIS_SELECTED, LVIS_SELECTED); // select item SendDlgItemMessage (hwnd, ctrl_id, LVM_ENSUREVISIBLE, item, TRUE); // ensure him visible } VOID ResizeWindow (HWND hwnd, INT width, INT height) { SetWindowPos (GetDlgItem (hwnd, IDC_LISTVIEW), nullptr, 0, 0, width, height - config.sb_height - 1, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION); // resize statusbar parts INT parts[] = {_R_PERCENT_VAL (50, width), -1}; SendDlgItemMessage (hwnd, IDC_STATUSBAR, SB_SETPARTS, 2, (LPARAM)parts); // resize column width _r_listview_resizeonecolumn (hwnd, IDC_LISTVIEW); // resize statusbar SendDlgItemMessage (hwnd, IDC_STATUSBAR, WM_SIZE, 0, 0); } BOOL settings_callback (HWND hwnd, DWORD msg, LPVOID lpdata1, LPVOID lpdata2) { PAPPLICATION_PAGE page = (PAPPLICATION_PAGE)lpdata2; switch (msg) { case _RM_INITIALIZE: { switch (page->dlg_id) { case IDD_SETTINGS_1: { // localize SetDlgItemText (hwnd, IDC_TITLE_1, I18N (&app, IDS_TITLE_1, 0)); SetDlgItemText (hwnd, IDC_TITLE_2, I18N (&app, IDS_TITLE_2, 0)); SetDlgItemText (hwnd, IDC_ALWAYSONTOP_CHK, I18N (&app, IDS_ALWAYSONTOP_CHK, 0)); SetDlgItemText (hwnd, IDC_LOADONSTARTUP_CHK, I18N (&app, IDS_LOADONSTARTUP_CHK, 0)); SetDlgItemText (hwnd, IDC_STARTMINIMIZED_CHK, I18N (&app, IDS_STARTMINIMIZED_CHK, 0)); SetDlgItemText (hwnd, IDC_SKIPUACWARNING_CHK, I18N (&app, IDS_SKIPUACWARNING_CHK, 0)); SetDlgItemText (hwnd, IDC_CHECKUPDATES_CHK, I18N (&app, IDS_CHECKUPDATES_CHK, 0)); SetDlgItemText (hwnd, IDC_LANGUAGE_HINT, I18N (&app, IDS_LANGUAGE_HINT, 0)); if (!config.is_admin) _r_ctrl_enable (hwnd, IDC_SKIPUACWARNING_CHK, FALSE); CheckDlgButton (hwnd, IDC_ALWAYSONTOP_CHK, app.ConfigGet (L"AlwaysOnTop", FALSE).AsBool () ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton (hwnd, IDC_LOADONSTARTUP_CHK, app.AutorunIsPresent () ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton (hwnd, IDC_STARTMINIMIZED_CHK, app.ConfigGet (L"StartMinimized", TRUE).AsBool () ? BST_CHECKED : BST_UNCHECKED); #ifdef _APP_HAVE_SKIPUAC if (config.is_admin) CheckDlgButton (hwnd, IDC_SKIPUACWARNING_CHK, app.SkipUacIsPresent (FALSE) ? BST_CHECKED : BST_UNCHECKED); #endif // _APP_HAVE_SKIPUAC CheckDlgButton (hwnd, IDC_CHECKUPDATES_CHK, app.ConfigGet (L"CheckUpdates", TRUE).AsBool () ? BST_CHECKED : BST_UNCHECKED); app.LocaleEnum (hwnd, IDC_LANGUAGE, FALSE, 0); SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR)SendDlgItemMessage (hwnd, IDC_LANGUAGE, CB_GETCURSEL, 0, 0)); // check on save break; } case IDD_SETTINGS_2: { // localize SetDlgItemText (hwnd, IDC_TITLE_1, I18N (&app, IDS_TITLE_1, 0)); SetDlgItemText (hwnd, IDC_TITLE_3, I18N (&app, IDS_TITLE_3, 0)); SetDlgItemText (hwnd, IDC_USEBLOCKLIST_CHK, I18N (&app, IDS_USEBLOCKLIST_CHK, 0)); SetDlgItemText (hwnd, IDC_DONOTBLOCKMAINEXECUTABLE_CHK, I18N (&app, IDS_DONOTBLOCKMAINEXECUTABLE_CHK, 0)); SetDlgItemText (hwnd, IDC_DISABLEWINDOWSFIREWALL_CHK, I18N (&app, IDS_DISABLEWINDOWSFIREWALL_CHK, 0)); if (!config.is_admin) _r_ctrl_enable (hwnd, IDC_DISABLEWINDOWSFIREWALL_CHK, FALSE); CheckDlgButton (hwnd, IDC_USEBLOCKLIST_CHK, app.ConfigGet (L"UseBlocklist", TRUE).AsBool () ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton (hwnd, IDC_DONOTBLOCKMAINEXECUTABLE_CHK, app.ConfigGet (L"DoNotBlockMainExecutable", TRUE).AsBool () ? BST_CHECKED : BST_UNCHECKED); if (config.is_admin) CheckDlgButton (hwnd, IDC_DISABLEWINDOWSFIREWALL_CHK, (changeservicestate (MPS_SERVICE1, FALSE, 0) == SERVICE_DISABLED && changeservicestate (MPS_SERVICE2, FALSE, 0) == SERVICE_DISABLED) ? BST_CHECKED : BST_UNCHECKED); break; } case IDD_SETTINGS_3: { // localize SetDlgItemText (hwnd, IDC_TITLE_4, I18N (&app, IDS_TITLE_4, 0)); SetDlgItemText (hwnd, IDC_TITLE_5, I18N (&app, IDS_TITLE_5, 0)); SetDlgItemText (hwnd, IDC_SHOWBALLOONTIPS_CHK, I18N (&app, IDS_SHOWBALLOONTIPS_CHK, 0)); _r_listview_setstyle (hwnd, IDC_COLORS, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP | LVS_EX_CHECKBOXES); _r_listview_deleteallitems (hwnd, IDC_COLORS); _r_listview_deleteallcolumns (hwnd, IDC_COLORS); _r_listview_addcolumn (hwnd, IDC_COLORS, nullptr, 95, 0, LVCFMT_LEFT); for (size_t i = 0; i < colors.size (); i++) { colors.at (i).clr = app.ConfigGet (colors.at (i).config_color, colors.at (i).default_clr).AsUlong (); _r_listview_additem (hwnd, IDC_COLORS, I18N (&app, colors.at (i).locale_id, colors.at (i).locale_sid), LAST_VALUE, 0, LAST_VALUE, LAST_VALUE, i); if (app.ConfigGet (colors.at (i).config, colors.at (i).is_enabled).AsBool ()) _r_listview_setcheckstate (hwnd, IDC_COLORS, LAST_VALUE, TRUE); } _r_listview_resizeonecolumn (hwnd, IDC_COLORS); CheckDlgButton (hwnd, IDC_SHOWBALLOONTIPS_CHK, app.ConfigGet (L"ShowBalloonTips", TRUE).AsBool () ? BST_CHECKED : BST_UNCHECKED); break; } case IDD_SETTINGS_4: { // configure listview _r_listview_setstyle (hwnd, IDC_COMMON, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP | LVS_EX_CHECKBOXES); _r_listview_deleteallgroups (hwnd, IDC_COMMON); _r_listview_deleteallitems (hwnd, IDC_COMMON); _r_listview_deleteallcolumns (hwnd, IDC_COMMON); _r_listview_addcolumn (hwnd, IDC_COMMON, nullptr, 95, 0, LVCFMT_LEFT); _r_listview_addgroup (hwnd, IDC_COMMON, 0, I18N (&app, IDS_GROUP_1, 0)); _r_listview_addgroup (hwnd, IDC_COMMON, 1, I18N (&app, IDS_GROUP_2, 0)); for (size_t i = 0; i < rules.size (); i++) { _r_listview_additem (hwnd, IDC_COMMON, I18N (&app, rules.at (i).locale_id, rules.at (i).locale_sid), i, 0, LAST_VALUE, rules.at (i).group_id, i); _r_listview_setcheckstate (hwnd, IDC_COMMON, i, app.ConfigGet (rules.at (i).config, rules.at (i).is_enabled).AsBool ()); } _r_listview_resizeonecolumn (hwnd, IDC_COMMON); break; } case IDD_SETTINGS_5: case IDD_SETTINGS_6: { // configure listview _r_listview_setstyle (hwnd, IDC_EDITOR, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP | LVS_EX_CHECKBOXES); size_t item = (size_t)SendDlgItemMessage (hwnd, IDC_EDITOR, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED); _r_listview_deleteallitems (hwnd, IDC_EDITOR); _r_listview_deleteallcolumns (hwnd, IDC_EDITOR); _r_listview_addcolumn (hwnd, IDC_EDITOR, I18N (&app, IDS_NAME, 0), 35, 0, LVCFMT_LEFT); _r_listview_addcolumn (hwnd, IDC_EDITOR, I18N (&app, IDS_RULE, 0), 40, 1, LVCFMT_LEFT); _r_listview_addcolumn (hwnd, IDC_EDITOR, I18N (&app, IDS_ACTION, 0), 20, 2, LVCFMT_LEFT); for (size_t i = 0, j = 0; i < rules_ext.size (); i++) { if ( rules_ext.at (i).is_default || (page->dlg_id == IDD_SETTINGS_5 && rules_ext.at (i).is_port == FALSE) || (page->dlg_id == IDD_SETTINGS_6 && rules_ext.at (i).is_port == TRUE) ) continue; _r_listview_additem (hwnd, IDC_EDITOR, rules_ext.at (i).name, j, 0, LAST_VALUE, LAST_VALUE, i); _r_listview_additem (hwnd, IDC_EDITOR, rules_ext.at (i).rule, j, 1, LAST_VALUE, LAST_VALUE, i); if (rules_ext.at (i).is_block) _r_listview_additem (hwnd, IDC_EDITOR, I18N (&app, IDS_ACTION_2, 0), j, 2, LAST_VALUE, LAST_VALUE, i); else _r_listview_additem (hwnd, IDC_EDITOR, I18N (&app, IDS_ACTION_1, 0), j, 2, LAST_VALUE, LAST_VALUE, i); _r_listview_setcheckstate (hwnd, IDC_EDITOR, j, rules_ext.at (i).is_enabled); j += 1; } if (item != LAST_VALUE) ShowItem (hwnd, IDC_EDITOR, item); break; } } break; } case _RM_MESSAGE: { LPMSG pmsg = (LPMSG)lpdata1; switch (pmsg->message) { case WM_NOTIFY: { LPNMHDR nmlp = (LPNMHDR)pmsg->lParam; switch (nmlp->code) { case NM_CUSTOMDRAW: { LONG result = CDRF_DODEFAULT; LPNMLVCUSTOMDRAW lpnmlv = (LPNMLVCUSTOMDRAW)pmsg->lParam; switch (lpnmlv->nmcd.dwDrawStage) { case CDDS_PREPAINT: { result = CDRF_NOTIFYITEMDRAW; break; } case CDDS_ITEMPREPAINT: { if (nmlp->idFrom == IDC_COLORS) { size_t idx = lpnmlv->nmcd.lItemlParam; _r_wnd_fillrect (lpnmlv->nmcd.hdc, &lpnmlv->nmcd.rc, colors.at (idx).clr); lpnmlv->clrTextBk = colors.at (idx).clr; result = CDRF_NEWFONT; } break; } } SetWindowLongPtr (hwnd, DWLP_MSGRESULT, result); return TRUE; } case NM_DBLCLK: { LPNMITEMACTIVATE lpnmlv = (LPNMITEMACTIVATE)pmsg->lParam; if (lpnmlv->iItem != -1) { if (nmlp->idFrom == IDC_COLORS) { size_t idx = _r_listview_getlparam (hwnd, IDC_COLORS, lpnmlv->iItem); CHOOSECOLOR cc = {0}; COLORREF cust[16] = {COLOR_SYSTEM, COLOR_INVALID}; cc.lStructSize = sizeof (cc); cc.Flags = CC_RGBINIT | CC_FULLOPEN; cc.hwndOwner = hwnd; cc.lpCustColors = cust; cc.rgbResult = colors.at (idx).clr; if (ChooseColor (&cc)) { colors.at (idx).clr = cc.rgbResult; // send notify for apply button (required!) BOOL prev_state = _r_listview_getcheckstate (hwnd, IDC_COLORS, lpnmlv->iItem); _r_listview_setcheckstate (hwnd, IDC_COLORS, lpnmlv->iItem, !prev_state); _r_listview_setcheckstate (hwnd, IDC_COLORS, lpnmlv->iItem, prev_state); } } else if (nmlp->idFrom == IDC_EDITOR) { SendMessage (hwnd, WM_COMMAND, MAKELPARAM (IDM_EDIT, 0), 0); } } break; } } break; } case WM_CONTEXTMENU: { UINT ctrl_id = GetDlgCtrlID ((HWND)pmsg->wParam); if (ctrl_id == IDC_EDITOR) { HMENU menu = LoadMenu (nullptr, MAKEINTRESOURCE (IDM_EDITOR)), submenu = GetSubMenu (menu, 0); // localize app.LocaleMenu (submenu, I18N (&app, IDS_ADD, 0), IDM_ADD, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_EDIT2, 0), IDM_EDIT, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_DELETE, 0), IDM_DELETE, FALSE); if (!SendDlgItemMessage (hwnd, ctrl_id, LVM_GETSELECTEDCOUNT, 0, 0)) { EnableMenuItem (submenu, IDM_EDIT, MF_BYCOMMAND | MF_DISABLED); EnableMenuItem (submenu, IDM_DELETE, MF_BYCOMMAND | MF_DISABLED); } POINT pt = {0}; GetCursorPos (&pt); TrackPopupMenuEx (submenu, TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwnd, nullptr); DestroyMenu (menu); DestroyMenu (submenu); } } case WM_COMMAND: { switch (LOWORD (pmsg->wParam)) { case IDM_ADD: { ITEM_RULE_EXT* ptr = nullptr; ptr = new ITEM_RULE_EXT; SecureZeroMemory (ptr, sizeof (ITEM_RULE_EXT)); if (page->dlg_id == IDD_SETTINGS_5) ptr->is_port = TRUE; if (DialogBoxParam (nullptr, MAKEINTRESOURCE (IDD_EDITOR), hwnd, &EditorProc, (LPARAM)ptr)) { rules_ext.push_back (*ptr); settings_callback (page->hwnd, _RM_INITIALIZE, nullptr, page); // re-inititalize page } delete ptr; break; } case IDM_EDIT: { size_t item = (size_t)SendDlgItemMessage (hwnd, IDC_EDITOR, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED); if (item == LAST_VALUE) break; ITEM_RULE_EXT* ptr = &rules_ext.at ((size_t)_r_listview_getlparam (hwnd, IDC_EDITOR, item)); if (DialogBoxParam (nullptr, MAKEINTRESOURCE (IDD_EDITOR), hwnd, &EditorProc, (LPARAM)ptr)) { settings_callback (page->hwnd, _RM_INITIALIZE, nullptr, page); // re-inititalize page } break; } case IDM_DELETE: { if (_r_msg (hwnd, MB_YESNO | MB_ICONQUESTION, APP_NAME, nullptr, I18N (&app, IDS_QUESTION, 0)) == IDYES) { size_t count = _r_listview_getitemcount (hwnd, IDC_EDITOR) - 1; for (size_t i = count; i != LAST_VALUE; i--) { if (ListView_GetItemState (GetDlgItem (hwnd, IDC_EDITOR), i, LVNI_SELECTED)) { size_t idx = _r_listview_getlparam (hwnd, IDC_EDITOR, i); rules_ext.erase (rules_ext.begin () + idx); SendDlgItemMessage (hwnd, IDC_EDITOR, LVM_DELETEITEM, i, 0); } } } break; } } break; } } break; } case _RM_SAVE: { switch (page->dlg_id) { case IDD_SETTINGS_1: { app.ConfigSet (L"AlwaysOnTop", DWORD ((IsDlgButtonChecked (hwnd, IDC_ALWAYSONTOP_CHK) == BST_CHECKED) ? TRUE : FALSE)); app.AutorunCreate (IsDlgButtonChecked (hwnd, IDC_LOADONSTARTUP_CHK) == BST_UNCHECKED); app.ConfigSet (L"StartMinimized", DWORD ((IsDlgButtonChecked (hwnd, IDC_STARTMINIMIZED_CHK) == BST_CHECKED) ? TRUE : FALSE)); #ifdef _APP_HAVE_SKIPUAC if (!_r_sys_uacstate ()) app.SkipUacCreate (IsDlgButtonChecked (hwnd, IDC_SKIPUACWARNING_CHK) == BST_UNCHECKED); #endif // _APP_HAVE_SKIPUAC app.ConfigSet (L"CheckUpdates", ((IsDlgButtonChecked (hwnd, IDC_CHECKUPDATES_CHK) == BST_CHECKED) ? TRUE : FALSE)); // set language rstring buffer; if (SendDlgItemMessage (hwnd, IDC_LANGUAGE, CB_GETCURSEL, 0, 0) >= 1) buffer = _r_ctrl_gettext (hwnd, IDC_LANGUAGE); app.ConfigSet (L"Language", buffer); if (GetWindowLongPtr (hwnd, GWLP_USERDATA) != (INT)SendDlgItemMessage (hwnd, IDC_LANGUAGE, CB_GETCURSEL, 0, 0)) return TRUE; // for restart break; } case IDD_SETTINGS_2: { app.ConfigSet (L"UseBlocklist", DWORD ((IsDlgButtonChecked (hwnd, IDC_USEBLOCKLIST_CHK) == BST_CHECKED) ? TRUE : FALSE)); app.ConfigSet (L"DoNotBlockMainExecutable", DWORD ((IsDlgButtonChecked (hwnd, IDC_DONOTBLOCKMAINEXECUTABLE_CHK) == BST_CHECKED) ? TRUE : FALSE)); if (config.is_admin) { changeservicestate (MPS_SERVICE1, TRUE, IsDlgButtonChecked (hwnd, IDC_DISABLEWINDOWSFIREWALL_CHK)); changeservicestate (MPS_SERVICE2, TRUE, IsDlgButtonChecked (hwnd, IDC_DISABLEWINDOWSFIREWALL_CHK)); } break; } case IDD_SETTINGS_3: { for (size_t i = 0; i < colors.size (); i++) { app.ConfigSet (colors.at (i).config, _r_listview_getcheckstate (hwnd, IDC_COLORS, i)); app.ConfigSet (colors.at (i).config_color, colors.at (i).clr); } app.ConfigSet (L"ShowBalloonTips", DWORD ((IsDlgButtonChecked (hwnd, IDC_SHOWBALLOONTIPS_CHK) == BST_CHECKED) ? TRUE : FALSE)); break; } case IDD_SETTINGS_4: { for (size_t i = 0; i < _r_listview_getitemcount (hwnd, IDC_COMMON); i++) { size_t idx = _r_listview_getlparam (hwnd, IDC_COMMON, i); app.ConfigSet (rules.at (idx).config, _r_listview_getcheckstate (hwnd, IDC_COMMON, i)); } break; } case IDD_SETTINGS_5: case IDD_SETTINGS_6: { for (size_t i = 0; i < _r_listview_getitemcount (hwnd, IDC_EDITOR); i++) { size_t idx = _r_listview_getlparam (hwnd, IDC_EDITOR, i); rules_ext.at (idx).is_enabled = _r_listview_getcheckstate (hwnd, IDC_EDITOR, i); } _app_profilesave (app.GetHWND ()); break; } } break; } } return FALSE; } INT_PTR CALLBACK DlgProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == WM_FINDMSGSTRING) { LPFINDREPLACE lpfr = (LPFINDREPLACE)lparam; if ((lpfr->Flags & FR_DIALOGTERM) != 0) { config.hfind = nullptr; } else if ((lpfr->Flags & FR_FINDNEXT) != 0) { size_t total = _r_listview_getitemcount (hwnd, IDC_LISTVIEW); INT start = (INT)SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_GETNEXTITEM, (WPARAM)total - 1, LVNI_SELECTED | LVNI_DIRECTIONMASK | LVNI_BELOW) + 1; for (size_t i = start; i < total; i++) { const size_t hash = _r_listview_getlparam (hwnd, IDC_LISTVIEW, i); ITEM_APPLICATION* ptr = &applications[hash]; if (StrStrI (ptr->full_path, lpfr->lpstrFindWhat) != nullptr) { ShowItem (hwnd, IDC_LISTVIEW, i); break; } } } return FALSE; } switch (msg) { case WM_INITDIALOG: { RECT rc = {0}; #ifndef _WIN64 if (_r_sys_iswow64 ()) { BOOL old = 0; Wow64DisableWow64FsRedirection ((PVOID*)&old); } #endif // _WIN64 // static initializer config.is_admin = _r_sys_adminstate (); config.apply_evt = CreateEvent (nullptr, FALSE, FALSE, nullptr); config.apply2_evt = CreateEvent (nullptr, FALSE, FALSE, nullptr); config.stop_evt = CreateEvent (nullptr, FALSE, FALSE, nullptr); config.wd_length = GetWindowsDirectory (config.windows_dir, _countof (config.windows_dir)); StringCchPrintf (config.config_path, _countof (config.config_path), L"%s\\config.xml", app.GetProfileDirectory ()); StringCchPrintf (config.profile_path, _countof (config.profile_path), L"%s\\profile.xml", app.GetProfileDirectory ()); StringCchPrintf (config.rules_path, _countof (config.rules_path), L"%s\\rules.xml", app.GetProfileDirectory ()); StringCchPrintf (config.svchost_path, _countof (config.svchost_path), L"%s\\system32\\svchost.exe", config.windows_dir); config.svchost_hash = rstring (config.svchost_path).Hash (); GetModuleFileName (app.GetHINSTANCE (), config.myself_path, _countof (config.myself_path)); config.myself_hash = rstring (config.myself_path).Hash (); // set privileges if (config.is_admin) { _r_sys_setprivilege (SE_DEBUG_NAME, TRUE); _r_sys_setprivilege (SE_BACKUP_NAME, TRUE); _r_sys_setprivilege (SE_RESTORE_NAME, TRUE); } // configure listview _r_listview_setstyle (hwnd, IDC_LISTVIEW, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP | LVS_EX_CHECKBOXES); _r_listview_addcolumn (hwnd, IDC_LISTVIEW, nullptr, 95, 0, LVCFMT_LEFT); SetIconsSize (hwnd); // drag & drop support DragAcceptFiles (hwnd, TRUE); // resize support GetClientRect (GetDlgItem (hwnd, IDC_STATUSBAR), &rc); config.sb_height = rc.bottom; GetClientRect (hwnd, &rc); SendMessage (hwnd, WM_SIZE, 0, MAKELPARAM ((rc.right - rc.left), (rc.bottom - rc.top))); // load xml _app_profileload (hwnd); _app_listviewsort (hwnd); // settings app.AddSettingsPage (nullptr, IDD_SETTINGS_1, IDS_SETTINGS_1, L"IDS_SETTINGS_1", &settings_callback); app.AddSettingsPage (nullptr, IDD_SETTINGS_2, IDS_SETTINGS_2, L"IDS_SETTINGS_2", &settings_callback); app.AddSettingsPage (nullptr, IDD_SETTINGS_3, IDS_SETTINGS_3, L"IDS_SETTINGS_3", &settings_callback); size_t rules_page = app.AddSettingsPage (nullptr, IDD_SETTINGS_4, IDS_SETTINGS_4, L"IDS_SETTINGS_4", &settings_callback); app.AddSettingsPage (nullptr, IDD_SETTINGS_5, IDS_SETTINGS_5, L"IDS_SETTINGS_5", &settings_callback, rules_page); app.AddSettingsPage (nullptr, IDD_SETTINGS_6, IDS_SETTINGS_6, L"IDS_SETTINGS_6", &settings_callback, rules_page); // startup parameters if (!wcsstr (GetCommandLine (), L"/minimized") && !app.ConfigGet (L"StartMinimized", TRUE).AsBool ()) _r_wnd_toggle (hwnd, TRUE); break; } case WM_DROPFILES: { UINT numfiles = DragQueryFile ((HDROP)wparam, 0xFFFFFFFF, nullptr, 0); size_t item = 0; for (UINT i = 0; i < numfiles; i++) { UINT lenname = DragQueryFile ((HDROP)wparam, i, nullptr, 0); LPWSTR file = new WCHAR[(lenname + 1) * sizeof (WCHAR)]; DragQueryFile ((HDROP)wparam, i, file, lenname + 1); item = _app_addapplication (hwnd, file, FALSE); delete[] file; } _app_listviewsort (hwnd); ShowItem (hwnd, IDC_LISTVIEW, _app_getposition (hwnd, item)); DragFinish ((HDROP)wparam); break; } case WM_DESTROY: { SetEvent (config.stop_evt); // stop thread config.hthread = nullptr; PostQuitMessage (0); break; } case WM_NOTIFY: { LPNMHDR nmlp = (LPNMHDR)lparam; switch (nmlp->code) { case NM_CUSTOMDRAW: { if (nmlp->idFrom == IDC_LISTVIEW) { LONG result = CDRF_DODEFAULT; LPNMLVCUSTOMDRAW lpnmlv = (LPNMLVCUSTOMDRAW)lparam; switch (lpnmlv->nmcd.dwDrawStage) { case CDDS_PREPAINT: { result = CDRF_NOTIFYITEMDRAW; break; } case CDDS_ITEMPREPAINT: { const size_t hash = lpnmlv->nmcd.lItemlParam; if (hash) { ITEM_APPLICATION const * ptr = &applications[hash]; COLORREF new_clr = 0; if (ptr->is_system && app.ConfigGet (L"IsHighlightSystem", TRUE).AsBool ()) { new_clr = app.ConfigGet (L"ColorSystem", COLOR_SYSTEM).AsUlong (); } else if (app.ConfigGet (L"IsHighlightInvalid", TRUE).AsBool () && !_r_fs_exists (ptr->full_path)) { new_clr = app.ConfigGet (L"ColorInvalid", COLOR_INVALID).AsUlong (); } if (new_clr) { _r_wnd_fillrect (lpnmlv->nmcd.hdc, &lpnmlv->nmcd.rc, new_clr); lpnmlv->clrTextBk = new_clr; result = CDRF_NEWFONT; } } break; } } SetWindowLongPtr (hwnd, DWLP_MSGRESULT, result); return TRUE; } break; } case LVN_GETINFOTIP: { LPNMLVGETINFOTIP lpnmlv = (LPNMLVGETINFOTIP)lparam; const size_t hash = (size_t)_r_listview_getlparam (hwnd, IDC_LISTVIEW, lpnmlv->iItem); if (hash) { ITEM_APPLICATION* ptr = &applications[hash]; rstring tmp; if (ptr->description[0]) { tmp.Append (ptr->description); tmp.Append (L"\r\n"); } if (ptr->author[0]) { tmp.Append (ptr->author); tmp.Append (L"\r\n"); } if (ptr->version[0]) { tmp.Append (ptr->version); tmp.Append (L"\r\n"); } if (tmp.IsEmpty ()) tmp = L"n/a"; StringCchCopy (lpnmlv->pszText, lpnmlv->cchTextMax, tmp); } break; } case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv = reinterpret_cast(nmlp); if (lpnmlv->uNewState == 8192 || lpnmlv->uNewState == 4096) { const size_t hash = lpnmlv->lParam; if (!hash || !config.is_firstapply || applications.find (hash) == applications.end ()) return FALSE; ITEM_APPLICATION* ptr = &applications[hash]; ptr->is_checked = (lpnmlv->uNewState == 8192) ? TRUE : FALSE; if ((EnumMode)app.ConfigGet (L"Mode", Whitelist).AsUint () != TrustNoOne) SetEvent (config.apply_evt); // apply filters else _app_listviewsort (hwnd); } break; } case LVN_DELETEALLITEMS: case LVN_INSERTITEM: case LVN_DELETEITEM: { _r_listview_resizeonecolumn (hwnd, IDC_LISTVIEW); _app_refreshstatus (hwnd); break; } case NM_DBLCLK: { LPNMITEMACTIVATE lpnmlv = (LPNMITEMACTIVATE)lparam; if (lpnmlv->iItem != -1) SendMessage (hwnd, WM_COMMAND, MAKELPARAM (IDM_EXPLORE, 0), 0); break; } } break; } case WM_CONTEXTMENU: { if (GetDlgCtrlID ((HWND)wparam) == IDC_LISTVIEW) { HMENU menu = LoadMenu (nullptr, MAKEINTRESOURCE (IDM_LISTVIEW)), submenu = GetSubMenu (menu, 0); HMENU submenu1 = GetSubMenu (submenu, 1); // localize app.LocaleMenu (submenu, I18N (&app, IDS_ADD, 0), 0, TRUE); app.LocaleMenu (submenu, I18N (&app, IDS_ADD_FILE, 0), IDM_ADD_FILE, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_ADD_PROCESS, 0), 1, TRUE); app.LocaleMenu (submenu, I18N (&app, IDS_ALL, 0), IDM_ALL, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_REFRESH, 0), IDM_REFRESH2, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_EXPLORE, 0), IDM_EXPLORE, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_COPY, 0), IDM_COPY, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_DELETE, 0), IDM_DELETE, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_CHECK, 0), IDM_CHECK, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_UNCHECK, 0), IDM_UNCHECK, FALSE); if (!SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_GETSELECTEDCOUNT, 0, 0)) { EnableMenuItem (submenu, IDM_EXPLORE, MF_BYCOMMAND | MF_DISABLED); EnableMenuItem (submenu, IDM_COPY, MF_BYCOMMAND | MF_DISABLED); EnableMenuItem (submenu, IDM_DELETE, MF_BYCOMMAND | MF_DISABLED); EnableMenuItem (submenu, IDM_CHECK, MF_BYCOMMAND | MF_DISABLED); EnableMenuItem (submenu, IDM_UNCHECK, MF_BYCOMMAND | MF_DISABLED); } // generate processes popup menu { _app_getprocesslist (nullptr, &processes); for (size_t i = 0; i < processes.size (); i++) { MENUITEMINFO mii = {0}; mii.cbSize = sizeof (mii); mii.fMask = MIIM_ID | MIIM_CHECKMARKS | MIIM_STRING; mii.dwTypeData = processes.at (i).display_path; mii.hbmpChecked = processes.at (i).hbmp; mii.hbmpUnchecked = processes.at (i).hbmp; mii.wID = IDM_ADD_PROCESS + UINT (i); InsertMenuItem (submenu1, IDM_ADD_PROCESS + UINT (i), FALSE, &mii); } if (!processes.size ()) EnableMenuItem (submenu1, IDM_ALL, MF_BYCOMMAND | MF_DISABLED); } POINT pt = {0}; GetCursorPos (&pt); TrackPopupMenuEx (submenu, TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwnd, nullptr); DestroyMenu (menu); DestroyMenu (submenu); } break; } case WM_SIZE: { if (wparam == SIZE_MINIMIZED) { _r_wnd_toggle (hwnd, FALSE); return FALSE; } ResizeWindow (hwnd, LOWORD (lparam), HIWORD (lparam)); RedrawWindow (hwnd, nullptr, nullptr, RDW_ALLCHILDREN | RDW_ERASE | RDW_INVALIDATE); break; } case WM_SYSCOMMAND: { if (wparam == SC_CLOSE) { _r_wnd_toggle (hwnd, FALSE); return TRUE; } break; } case WM_TRAYICON: { switch (LOWORD (lparam)) { case WM_LBUTTONUP: { SetForegroundWindow (hwnd); break; } case WM_LBUTTONDBLCLK: case WM_MBUTTONDOWN: { _r_wnd_toggle (hwnd, FALSE); break; } case WM_RBUTTONUP: { SetForegroundWindow (hwnd); // don't touch HMENU menu = LoadMenu (nullptr, MAKEINTRESOURCE (IDM_TRAY)), submenu = GetSubMenu (menu, 0); HMENU submenu1 = GetSubMenu (submenu, 5); // localize app.LocaleMenu (submenu, I18N (&app, IDS_TRAY_SHOW, 0), IDM_TRAY_SHOW, FALSE); app.LocaleMenu (submenu, I18N (&app, (config.hengine ? IDS_TRAY_STOP : IDS_TRAY_START), config.hengine ? L"IDS_TRAY_STOP" : L"IDS_TRAY_START"), IDM_TRAY_START, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_TRAY_MODE, 0), 3, TRUE); app.LocaleMenu (submenu, I18N (&app, IDS_MODE_WHITELIST, 0), IDM_TRAY_MODEWHITELIST, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_MODE_BLACKLIST, 0), IDM_TRAY_MODEBLACKLIST, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_MODE_TRUSTNOONE, 0), IDM_TRAY_MODETRUSTNOONE, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_SETTINGS, 0), 5, TRUE); app.LocaleMenu (submenu, I18N (&app, IDS_SETTINGS, 0), IDM_TRAY_SETTINGS, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_WEBSITE, 0), IDM_TRAY_WEBSITE, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_ABOUT, 0), IDM_TRAY_ABOUT, FALSE); app.LocaleMenu (submenu, I18N (&app, IDS_EXIT, 0), IDM_TRAY_EXIT, FALSE); if (!config.is_admin) EnableMenuItem (submenu, 3, MF_BYPOSITION | MF_DISABLED); CheckMenuRadioItem (submenu, IDM_TRAY_MODEWHITELIST, IDM_TRAY_MODETRUSTNOONE, IDM_TRAY_MODEWHITELIST + app.ConfigGet (L"Mode", Whitelist).AsUint (), MF_BYCOMMAND); // append rules { DeleteMenu (submenu1, 0, MF_BYPOSITION); size_t prev_id = 0; for (size_t i = 0; i < rules.size (); i++) { if (rules.at (i).group_id != prev_id) AppendMenu (submenu1, MF_SEPARATOR, 0, nullptr); AppendMenu (submenu1, MF_STRING, IDM_RULES + i, I18N (&app, rules.at (i).locale_id, rules.at (i).locale_sid)); if (app.ConfigGet (rules.at (i).config, rules.at (i).is_enabled).AsBool ()) CheckMenuItem (submenu1, IDM_RULES + UINT (i), MF_BYCOMMAND | MF_CHECKED); prev_id = rules.at (i).group_id; } AppendMenu (submenu1, MF_SEPARATOR, 0, 0); AppendMenu (submenu1, MF_STRING, IDM_TRAY_SETTINGS, I18N (&app, IDS_SETTINGS, 0)); } POINT pt = {0}; GetCursorPos (&pt); TrackPopupMenuEx (submenu, TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwnd, nullptr); DestroyMenu (submenu); DestroyMenu (menu); break; } } break; } case WM_DEVICECHANGE: { if ((wparam == DBT_DEVICEARRIVAL) || (wparam == DBT_DEVICEREMOVECOMPLETE)) { DEV_BROADCAST_HDR* header = (PDEV_BROADCAST_HDR)lparam; if (header->dbch_devicetype == DBT_DEVTYP_VOLUME) SetEvent (config.apply2_evt); // apply filters } break; } case WM_COMMAND: { if (HIWORD (wparam) == 0 && LOWORD (wparam) >= IDM_DEFAULT && LOWORD (wparam) <= IDM_DEFAULT + app.LocaleGetCount ()) { app.LocaleApplyFromMenu (GetSubMenu (GetSubMenu (GetMenu (hwnd), 2), 6), LOWORD (wparam), IDM_DEFAULT); return FALSE; } else if ((LOWORD (wparam) >= IDM_ADD_PROCESS && LOWORD (wparam) <= IDM_ADD_PROCESS + processes.size ())) { ITEM_PROCESS const * ptr = &processes.at (LOWORD (wparam) - IDM_ADD_PROCESS); const size_t hash = _app_addapplication (hwnd, ptr->file_path, FALSE); _app_listviewsort (hwnd); ShowItem (hwnd, IDC_LISTVIEW, _app_getposition (hwnd, hash)); return FALSE; } else if ((LOWORD (wparam) >= IDM_RULES && LOWORD (wparam) <= IDM_RULES + rules.size ())) { ITEM_RULE const * ptr = &rules.at (LOWORD (wparam) - IDM_RULES); app.ConfigSet (ptr->config, !app.ConfigGet (ptr->config, ptr->is_enabled).AsBool ()); SetEvent (config.apply2_evt); // apply filters return FALSE; } switch (LOWORD (wparam)) { case IDCANCEL: // process Esc key case IDM_TRAY_SHOW: { _r_wnd_toggle (hwnd, FALSE); break; } case IDM_SETTINGS: case IDM_TRAY_SETTINGS: { app.CreateSettingsWindow (); break; } case IDM_EXIT: case IDM_TRAY_EXIT: { DestroyWindow (hwnd); break; } case IDM_WEBSITE: case IDM_TRAY_WEBSITE: { ShellExecute (hwnd, nullptr, _APP_WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT); break; } case IDM_DONATE: { ShellExecute (hwnd, nullptr, _APP_DONATION_URL, nullptr, nullptr, SW_SHOWDEFAULT); break; } case IDM_CHECKUPDATES: { app.CheckForUpdates (FALSE); break; } case IDM_ABOUT: case IDM_TRAY_ABOUT: { app.CreateAboutWindow (); break; } case IDM_ALWAYSONTOP_CHK: { BOOL val = app.ConfigGet (L"AlwaysOnTop", FALSE).AsBool (); CheckMenuItem (GetMenu (hwnd), IDM_ALWAYSONTOP_CHK, MF_BYCOMMAND | (!val ? MF_CHECKED : MF_UNCHECKED)); app.ConfigSet (L"AlwaysOnTop", !val); _r_wnd_top (hwnd, !val); break; } case IDM_CHECKUPDATES_CHK: { BOOL val = app.ConfigGet (L"CheckUpdates", TRUE).AsBool (); CheckMenuItem (GetMenu (hwnd), IDM_CHECKUPDATES_CHK, MF_BYCOMMAND | (!val ? MF_CHECKED : MF_UNCHECKED)); app.ConfigSet (L"CheckUpdates", !val); break; } case IDM_SORTBYFNAME: case IDM_SORTBYFDIR: { app.ConfigSet (L"SortMode", LOWORD (wparam) == IDM_SORTBYFNAME ? 1 : 0); _app_listviewsort (hwnd); break; } case IDM_SORTISDESCEND: { app.ConfigSet (L"IsSortDescending", !app.ConfigGet (L"IsSortDescending", FALSE).AsBool ()); _app_listviewsort (hwnd); break; } case IDM_ICONSSMALL: case IDM_ICONSLARGE: { app.ConfigSet (L"IsLargeIcons", LOWORD (wparam) == IDM_ICONSLARGE); SetIconsSize (hwnd); break; } case IDM_REFRESH: case IDM_REFRESH2: { size_t item = (size_t)SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED); _app_profileload (hwnd); SetEvent (config.apply2_evt); // apply filters if (item != LAST_VALUE) ShowItem (hwnd, IDC_LISTVIEW, item); break; } case IDM_TRAY_MODEWHITELIST: case IDM_TRAY_MODEBLACKLIST: case IDM_TRAY_MODETRUSTNOONE: { EnumMode curr = Whitelist; if (LOWORD (wparam) == IDM_TRAY_MODEBLACKLIST) curr = Blacklist; else if (LOWORD (wparam) == IDM_TRAY_MODETRUSTNOONE) curr = TrustNoOne; app.ConfigSet (L"Mode", curr); _app_refreshstatus (hwnd); SetEvent (config.apply_evt); // apply filters break; } case IDM_FIND: { if (!config.hfind) { FINDREPLACE fr = {0}; fr.lStructSize = sizeof (fr); fr.hwndOwner = hwnd; fr.lpstrFindWhat = config.search_string; fr.wFindWhatLen = _countof (config.search_string) - 1; fr.Flags = FR_HIDEWHOLEWORD | FR_HIDEMATCHCASE | FR_HIDEUPDOWN; config.hfind = FindText (&fr); } else { SetFocus (config.hfind); } break; } case IDM_FINDNEXT: { if (!config.search_string[0]) { SendMessage (hwnd, WM_COMMAND, MAKEWPARAM (IDM_FIND, 0), 0); } else { FINDREPLACE fr = {0}; fr.Flags = FR_FINDNEXT; fr.lpstrFindWhat = config.search_string; SendMessage (hwnd, WM_FINDMSGSTRING, 0, (LPARAM)&fr); } break; } case IDM_TRAY_START: { if (!config.is_admin) { if (app.SkipUacRun ()) DestroyWindow (hwnd); app.TrayPopup (NIIF_ERROR, APP_NAME, I18N (&app, IDS_STATUS_NOPRIVILEGES, 0)); } else { BOOL status = app.ConfigGet (L"IsFiltersEnabled", TRUE).AsBool (); if (status && _r_msg (hwnd, MB_YESNO | MB_ICONQUESTION, APP_NAME, nullptr, I18N (&app, IDS_QUESTION_DISABLE, 0)) != IDYES) break; if (!status && !config.hengine) { _wfp_start (); } else if (status && config.hengine) { _wfp_stop (); } app.ConfigSet (L"IsFiltersEnabled", !status); } break; } case IDM_ADD_FILE: { WCHAR files[_R_BUFFER_LENGTH] = {0}; size_t item = 0; OPENFILENAME ofn = {0}; ofn.lStructSize = sizeof (ofn); ofn.hwndOwner = hwnd; ofn.lpstrFile = files; ofn.nMaxFile = _countof (files); ofn.lpstrFilter = L"*.exe\0*.exe\0*.*\0*.*\0\0"; ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FORCESHOWHIDDEN; if (GetOpenFileName (&ofn)) { if (files[ofn.nFileOffset - 1] != 0) { item = _app_addapplication (hwnd, files, FALSE); } else { LPWSTR p = files; WCHAR dir[MAX_PATH] = {0}; GetCurrentDirectory (MAX_PATH, dir); while (*p) { p += wcslen (p) + 1; if (*p) item = _app_addapplication (hwnd, _r_fmt (L"%s\\%s", dir, p), FALSE); } } _app_listviewsort (hwnd); ShowItem (hwnd, IDC_LISTVIEW, _app_getposition (hwnd, _app_getposition (hwnd, item))); } break; } case IDM_ALL: { for (size_t i = 0; i < processes.size (); i++) _app_addapplication (hwnd, processes.at (i).file_path, FALSE); _app_listviewsort (hwnd); break; } case IDM_EXPLORE: case IDM_COPY: case IDM_UNCHECK: case IDM_CHECK: { INT item = -1; rstring buffer; while ((item = (INT)SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_GETNEXTITEM, item, LVNI_SELECTED)) != -1) { const size_t hash = (size_t)_r_listview_getlparam (hwnd, IDC_LISTVIEW, item); if (applications.find (hash) == applications.end ()) continue; ITEM_APPLICATION* ptr = &applications[hash]; if (LOWORD (wparam) == IDM_EXPLORE) { if (_r_fs_exists (ptr->full_path)) _r_run (_r_fmt (L"\"explorer.exe\" /select,\"%s\"", ptr->full_path)); else ShellExecute (hwnd, nullptr, ptr->file_dir, nullptr, nullptr, SW_SHOWDEFAULT); } else if (LOWORD (wparam) == IDM_COPY) { buffer.Append (ptr->full_path).Append (L"\r\n"); } else if (LOWORD (wparam) == IDM_CHECK || LOWORD (wparam) == IDM_UNCHECK) { ptr->is_checked = LOWORD (wparam) == IDM_CHECK ? TRUE : FALSE; _r_listview_setcheckstate (hwnd, IDC_LISTVIEW, item, LOWORD (wparam) == IDM_CHECK ? TRUE : FALSE); } } if (LOWORD (wparam) == IDM_COPY) { buffer.Trim (L"\r\n"); _r_clipboard_set (hwnd, buffer, buffer.GetLength ()); } break; } case IDM_DELETE: { if (SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_GETSELECTEDCOUNT, 0, 0) && _r_msg (hwnd, MB_YESNO | MB_ICONQUESTION, APP_NAME, nullptr, I18N (&app, IDS_QUESTION, 0)) == IDYES) { size_t count = _r_listview_getitemcount (hwnd, IDC_LISTVIEW) - 1; BOOL is_checked = FALSE; for (size_t i = count; i != LAST_VALUE; i--) { if (ListView_GetItemState (GetDlgItem (hwnd, IDC_LISTVIEW), i, LVNI_SELECTED)) { const size_t hash = (size_t)_r_listview_getlparam (hwnd, IDC_LISTVIEW, i); ITEM_APPLICATION* ptr = &applications[hash]; if (ptr->is_checked) is_checked = TRUE; ptr = nullptr; applications.erase (hash); SendDlgItemMessage (hwnd, IDC_LISTVIEW, LVM_DELETEITEM, i, 0); } } if (is_checked) SetEvent (config.apply_evt); // apply filters else _app_profilesave (hwnd); } break; } case IDM_SELECT_ALL: { ListView_SetItemState (GetDlgItem (hwnd, IDC_LISTVIEW), -1, LVIS_SELECTED, LVIS_SELECTED); break; } } break; } } return FALSE; } INT APIENTRY wWinMain (HINSTANCE, HINSTANCE, LPWSTR, INT) { if (app.CreateMainWindow (&DlgProc, &initializer_callback)) { MSG msg = {0}; HACCEL haccel = LoadAccelerators (app.GetHINSTANCE (), MAKEINTRESOURCE (IDA_MAIN)); while (GetMessage (&msg, nullptr, 0, 0) > 0) { if ((haccel && !TranslateAccelerator (app.GetHWND (), haccel, &msg)) && !IsDialogMessage (app.GetHWND (), &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } if (haccel) DestroyAcceleratorTable (haccel); } return ERROR_SUCCESS; }