mirror of
https://github.com/BeneficialCode/WinArk
synced 2026-08-09 12:00:31 +00:00
572 lines
16 KiB
C++
572 lines
16 KiB
C++
#include "stdafx.h"
|
|
#include "KernelPoolView.h"
|
|
#include <unordered_set>
|
|
|
|
#pragma comment(lib,"ntdll")
|
|
|
|
void CKernelPoolView::LoadPoolTagText() {
|
|
auto hModule = _Module.GetResourceInstance();
|
|
auto hResource = ::FindResource(hModule, MAKEINTRESOURCE(IDR_POOLTAG), L"TXT");
|
|
ATLASSERT(hResource);
|
|
|
|
auto hGlobal = ::LoadResource(hModule, hResource);
|
|
ATLASSERT(hGlobal);
|
|
|
|
auto data = static_cast<const char*>(::LockResource(hGlobal));
|
|
auto next = strchr(data, '\n');
|
|
for (; next; data = next + 1) {
|
|
if (strncmp(data, "//", 2) == 0 || _strnicmp(data, "rem", 3) == 0
|
|
|| strncmp(data, "\r\n", 2) == 0 || strncmp(data, "\n", 1) == 0) {
|
|
next = strchr(data, '\n');
|
|
continue;
|
|
}
|
|
|
|
next = strchr(data, '\n');
|
|
|
|
// read the tag
|
|
std::string tag(data, data + 4);
|
|
|
|
// locate the first dash
|
|
auto dash1 = strchr(data, '-');
|
|
if (dash1 == nullptr)
|
|
continue;
|
|
|
|
// locate second dash
|
|
auto dash2 = strchr(dash1 + 1, '-');
|
|
if (dash2 == nullptr)
|
|
continue;
|
|
|
|
if (dash2 > next) {
|
|
dash2 = dash1;
|
|
dash1 = nullptr;
|
|
}
|
|
|
|
CStringA trimmedTag(tag.c_str());
|
|
trimmedTag.TrimLeft();
|
|
trimmedTag += L" ";
|
|
if (trimmedTag.GetLength() > 4)
|
|
trimmedTag = trimmedTag.Mid(0, 4);
|
|
CStringW trimmedDriverName(L"");
|
|
if (dash1) {
|
|
std::string driverName(dash1 + 1, dash2);
|
|
trimmedDriverName = driverName.c_str();
|
|
trimmedDriverName.Trim();
|
|
}
|
|
|
|
std::string driverDesc(dash2 + 1, next - 1);
|
|
CStringW trimmedDriverDesc(driverDesc.c_str());
|
|
trimmedDriverDesc.Trim();
|
|
|
|
m_TagSource.insert({ trimmedTag, std::make_pair(CString(trimmedDriverName), CString(trimmedDriverDesc)) });
|
|
}
|
|
}
|
|
|
|
ULONG CKernelPoolView::UpdateSystemPoolTags() {
|
|
ULONG size = 1 << 22;
|
|
if (m_PoolTags == nullptr) {
|
|
LoadPoolTagText();
|
|
m_PoolTags = static_cast<SYSTEM_POOLTAG_INFORMATION*>(::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
|
if (m_PoolTags == nullptr) {
|
|
AtlMessageBox(m_hWnd, L"Not enough memory", IDR_MAINFRAME, MB_ICONERROR);
|
|
return 0;
|
|
}
|
|
}
|
|
ULONG len;
|
|
|
|
auto status = NtQuerySystemInformation(SystemPoolTagInformation,
|
|
m_PoolTags,
|
|
size, &len
|
|
);
|
|
|
|
if (status) {
|
|
AtlMessageBox(m_hWnd, L"Failed in getting pool information", IDR_MAINFRAME, MB_ICONERROR);
|
|
return 0;
|
|
}
|
|
|
|
auto count = m_PoolTags->Count;
|
|
m_Tags.reserve(count + 16);
|
|
m_TagsMap.reserve(count + 16);
|
|
|
|
for (decltype(count) i = 0; i < count; i++) {
|
|
const auto& info = m_PoolTags->TagInfo[i];
|
|
m_TotalPaged += info.PagedUsed;
|
|
m_TotalNonPaged += info.NonPagedUsed;
|
|
AddTag(info, i);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
ULONG CKernelPoolView::UpdateSessionPoolTags(ULONG sessionId) {
|
|
ULONG count = 0;
|
|
ULONG size = 1 << 22;
|
|
if (m_SessionPoolTags == nullptr) {
|
|
LoadPoolTagText();
|
|
m_SessionPoolTags = static_cast<SYSTEM_SESSION_POOLTAG_INFORMATION*>(::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
|
if (m_SessionPoolTags == nullptr) {
|
|
AtlMessageBox(m_hWnd, L"Not enough memory", IDR_MAINFRAME, MB_ICONERROR);
|
|
return 0;
|
|
}
|
|
}
|
|
ULONG len;
|
|
SYSTEM_SESSION_PROCESS_INFORMATION procInfo;
|
|
procInfo.SessionId = sessionId;
|
|
procInfo.Buffer = m_SessionPoolTags;
|
|
procInfo.SizeOfBuf = size;
|
|
auto status = NtQuerySystemInformation(SystemSessionPoolTagInformation,
|
|
&procInfo,
|
|
sizeof(SYSTEM_SESSION_PROCESS_INFORMATION), &len
|
|
);
|
|
|
|
if (status) {
|
|
AtlMessageBox(m_hWnd, L"Failed in getting pool information", IDR_MAINFRAME, MB_ICONERROR);
|
|
return 0;
|
|
}
|
|
|
|
count = m_SessionPoolTags->Count;
|
|
for (decltype(count) i = 0; i < count; i++) {
|
|
const auto& info = m_SessionPoolTags->TagInfo[i];
|
|
m_TotalPaged += info.PagedUsed;
|
|
m_TotalNonPaged += info.NonPagedUsed;
|
|
AddTag(info, i);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void CKernelPoolView::UpdatePoolTags() {
|
|
ULONG count = 0;
|
|
m_Tags.clear();
|
|
m_TagsMap.clear();
|
|
m_TotalPaged = m_TotalNonPaged = 0;
|
|
count = UpdateSystemPoolTags();
|
|
count += UpdateSessionPoolTags(0);
|
|
count += UpdateSessionPoolTags(1);
|
|
if (m_Tags.empty()) {
|
|
SetItemCount(count);
|
|
}
|
|
else {
|
|
SetItemCountEx(count, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
|
|
UpdateVisible();
|
|
}
|
|
UpdatePaneText();
|
|
}
|
|
|
|
void CKernelPoolView::AddTag(const SYSTEM_POOLTAG& info, int index) {
|
|
char tag[5] = { 0 };
|
|
::CopyMemory(tag, &info.Tag, 4);
|
|
auto item = std::make_shared<TagItem>();
|
|
item->Tag = CStringA(tag);
|
|
|
|
item->TagInfo = info;
|
|
item->Index = index;
|
|
|
|
if (auto it = m_TagSource.find(item->Tag); it != m_TagSource.end()) {
|
|
item->SourceName = it->second.first;
|
|
item->SourceDesc = it->second.second;
|
|
}
|
|
|
|
m_Tags.push_back(item);
|
|
m_TagsMap.insert({ info.TagUlong, item });
|
|
}
|
|
|
|
void CKernelPoolView::UpdateVisible() {
|
|
int page = GetCountPerPage();
|
|
int start = GetTopIndex();
|
|
RedrawItems(start, start + page);
|
|
}
|
|
|
|
BOOL CKernelPoolView::PreTranslateMessage(MSG* pMsg) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD CKernelPoolView::OnPrePaint(int id, LPNMCUSTOMDRAW cd) {
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
}
|
|
|
|
DWORD CKernelPoolView::OnItemPrePaint(int id, LPNMCUSTOMDRAW cd) {
|
|
return CDRF_NOTIFYSUBITEMDRAW;
|
|
}
|
|
|
|
DWORD CKernelPoolView::OnSubItemPrePaint(int id, LPNMCUSTOMDRAW cd) {
|
|
auto lcd = (LPNMLVCUSTOMDRAW)cd;
|
|
int row = static_cast<int>(cd->dwItemSpec);
|
|
int col = lcd->iSubItem;
|
|
lcd->clrTextBk = CLR_INVALID;
|
|
|
|
const auto& item = m_Tags[row];
|
|
CellColorKey key(item->TagInfo.TagUlong, col);
|
|
if (auto it = m_CellColors.find(key); it != m_CellColors.end()) {
|
|
auto& cc = it->second;
|
|
if (cc.TargetTime > 0 && cc.TargetTime < ::GetTickCount64())
|
|
m_CellColors.erase(key);
|
|
else
|
|
lcd->clrTextBk = it->second.BackColor;
|
|
}
|
|
|
|
return CDRF_DODEFAULT;
|
|
}
|
|
|
|
BOOL CKernelPoolView::OnIdle() {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
|
|
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
|
|
|
|
SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_HEADERINALLVIEWS | LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER);
|
|
|
|
InsertColumn(ColumnType::TagName, L"Tag", LVCFMT_CENTER, 80);
|
|
InsertColumn(ColumnType::PagedAllocs, L"Paged Allocs", LVCFMT_RIGHT, 100);
|
|
InsertColumn(ColumnType::PagedFrees, L"Paged Frees", LVCFMT_RIGHT, 100);
|
|
InsertColumn(ColumnType::PagedDiff, L"Paged Diff", LVCFMT_RIGHT, 80);
|
|
InsertColumn(ColumnType::PagedUsage, L"Paged Usage", LVCFMT_RIGHT, 100);
|
|
|
|
InsertColumn(ColumnType::NonPagedAllocs, L"NPaged Allocs", LVCFMT_RIGHT, 120);
|
|
InsertColumn(ColumnType::NonPagedFrees, L"NPaged Frees", LVCFMT_RIGHT, 120);
|
|
InsertColumn(ColumnType::NonPagedDiff, L"NPaged Diff", LVCFMT_RIGHT, 100);
|
|
InsertColumn(ColumnType::NonPagedUsage, L"NPaged Usage", LVCFMT_RIGHT, 100);
|
|
|
|
InsertColumn(ColumnType::SourceName, L"Source", LVCFMT_LEFT, 150);
|
|
InsertColumn(ColumnType::SourceDescription, L"Source Description", LVCFMT_LEFT, 350);
|
|
|
|
UpdatePoolTags();
|
|
|
|
SetTimer(1, m_UpdateInterval, nullptr);
|
|
|
|
auto pLoop = _Module.GetMessageLoop();
|
|
pLoop->AddIdleHandler(this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CKernelPoolView::UpdatePaneText() {
|
|
if (IsWindowVisible()) {
|
|
CString text;
|
|
text.Format(L"%d Tags", GetItemCount());
|
|
m_pFrame->SetPaneText(2, text);
|
|
text.Format(L"Paged: %u MB", (unsigned)(m_TotalPaged >> 20));
|
|
m_pFrame->SetPaneText(3, text);
|
|
text.Format(L"Non Paged: %u MB", (unsigned)(m_TotalNonPaged >> 20));
|
|
m_pFrame->SetPaneText(4, text);
|
|
}
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnTimer(UINT, WPARAM wParam, LPARAM, BOOL&) {
|
|
if (wParam == 1) {
|
|
// UpdatePoolTags();
|
|
UpdatePaneText();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
|
|
if (m_PoolTags)
|
|
::VirtualFree(m_PoolTags, 0, MEM_RELEASE);
|
|
|
|
CMessageLoop* pLoop = _Module.GetMessageLoop();
|
|
ATLASSERT(pLoop);
|
|
pLoop->RemoveIdleHandler(this);
|
|
bHandled = FALSE;
|
|
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnGetDisplayInfo(int, LPNMHDR nmhdr, BOOL&) {
|
|
auto disp = (NMLVDISPINFO*)nmhdr;
|
|
auto& item = disp->item;
|
|
auto index = item.iItem;
|
|
auto& info = *m_Tags[index];
|
|
|
|
if (disp->item.mask & LVIF_TEXT) {
|
|
switch (disp->item.iSubItem) {
|
|
case ColumnType::TagName:
|
|
StringCchCopyW(item.pszText, item.cchTextMax, CString(info.Tag));
|
|
break;
|
|
|
|
case ColumnType::PagedAllocs:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.PagedAllocs);
|
|
break;
|
|
|
|
case ColumnType::PagedFrees:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.PagedFrees);
|
|
break;
|
|
|
|
case ColumnType::PagedDiff:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.PagedAllocs - info.TagInfo.PagedFrees);
|
|
break;
|
|
|
|
case ColumnType::PagedUsage:
|
|
{
|
|
auto value = info.TagInfo.PagedUsed;
|
|
if (value < 1 << 12)
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%ld B", value);
|
|
else
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%ld KB", value >> 10);
|
|
|
|
break;
|
|
}
|
|
|
|
case ColumnType::NonPagedAllocs:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.NonPagedAllocs);
|
|
break;
|
|
|
|
case ColumnType::NonPagedFrees:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.NonPagedFrees);
|
|
break;
|
|
|
|
case ColumnType::NonPagedDiff:
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%u", info.TagInfo.NonPagedAllocs - info.TagInfo.NonPagedFrees);
|
|
break;
|
|
|
|
case ColumnType::NonPagedUsage:
|
|
{
|
|
auto value = info.TagInfo.NonPagedUsed;
|
|
if (value < 1 << 12)
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%ld B", value);
|
|
else
|
|
StringCchPrintf(item.pszText, item.cchTextMax, L"%ld KB", value >> 10);
|
|
break;
|
|
}
|
|
|
|
case ColumnType::SourceName:
|
|
item.pszText = (PWSTR)info.SourceName;
|
|
break;
|
|
|
|
case ColumnType::SourceDescription:
|
|
item.pszText = (PWSTR)info.SourceDesc;
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnColumnClick(int, LPNMHDR nmhdr, BOOL&) {
|
|
auto lv = (NMLISTVIEW*)nmhdr;
|
|
int column = lv->iSubItem;
|
|
int oldSortColumn = m_SortColumn;
|
|
if (column == m_SortColumn)
|
|
m_Ascending = !m_Ascending;
|
|
else {
|
|
m_SortColumn = column;
|
|
m_Ascending = true;
|
|
}
|
|
|
|
HDITEM h;
|
|
h.mask = HDI_FORMAT;
|
|
auto header = GetHeader();
|
|
header.GetItem(m_SortColumn, &h);
|
|
h.fmt = (h.fmt & HDF_JUSTIFYMASK) | HDF_STRING | (m_Ascending ? HDF_SORTUP : HDF_SORTDOWN);
|
|
header.SetItem(m_SortColumn, &h);
|
|
|
|
if (oldSortColumn >= 0 && oldSortColumn != m_SortColumn) {
|
|
h.mask = HDI_FORMAT;
|
|
header.GetItem(oldSortColumn, &h);
|
|
h.fmt = (h.fmt & HDF_JUSTIFYMASK) | HDF_STRING;
|
|
header.SetItem(oldSortColumn, &h);
|
|
}
|
|
|
|
DoSort();
|
|
UpdateVisible();
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnItemChanged(int, LPNMHDR, BOOL&) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnFindItem(int, LPNMHDR nmhdr, BOOL&) {
|
|
auto fi = (NMLVFINDITEM*)nmhdr;
|
|
auto start = GetSelectedIndex() + 1;
|
|
auto count = GetItemCount();
|
|
CString text(fi->lvfi.psz);
|
|
|
|
if (fi->lvfi.flags & LVFI_STRING) {
|
|
for (int i = start; i < start + count; i++) {
|
|
if (CString(m_Tags[i % count]->Tag).Mid(0, text.GetLength()).CompareNoCase(text) == 0) {
|
|
return i % count;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool CKernelPoolView::CompareItems(const TagItem& item1, const TagItem& item2) {
|
|
int result;
|
|
switch (m_SortColumn) {
|
|
case ColumnType::TagName:
|
|
result = item2.Tag.CompareNoCase(item1.Tag);
|
|
return m_Ascending ? (result > 0) : (result < 0);
|
|
|
|
case ColumnType::SourceName:
|
|
result = ::_wcsicmp(item2.SourceName, item1.SourceName);
|
|
return m_Ascending ? (result > 0) : (result < 0);
|
|
|
|
case ColumnType::SourceDescription:
|
|
result = ::_wcsicmp(item2.SourceDesc, item1.SourceDesc);
|
|
return m_Ascending ? (result > 0) : (result < 0);
|
|
|
|
case ColumnType::PagedAllocs:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.PagedAllocs < item2.TagInfo.PagedAllocs;
|
|
else
|
|
return item1.TagInfo.PagedAllocs > item2.TagInfo.PagedAllocs;
|
|
|
|
case ColumnType::PagedFrees:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.PagedFrees < item2.TagInfo.PagedFrees;
|
|
else
|
|
return item1.TagInfo.PagedFrees > item2.TagInfo.PagedFrees;
|
|
|
|
case ColumnType::PagedUsage:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.PagedUsed < item2.TagInfo.PagedUsed;
|
|
else
|
|
return item1.TagInfo.PagedUsed > item2.TagInfo.PagedUsed;
|
|
|
|
case ColumnType::PagedDiff:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.PagedAllocs - item1.TagInfo.PagedFrees < item2.TagInfo.PagedAllocs - item2.TagInfo.PagedFrees;
|
|
else
|
|
return item1.TagInfo.PagedAllocs - item1.TagInfo.PagedFrees > item2.TagInfo.PagedAllocs - item2.TagInfo.PagedFrees;
|
|
|
|
case ColumnType::NonPagedAllocs:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.NonPagedAllocs < item2.TagInfo.NonPagedAllocs;
|
|
else
|
|
return item1.TagInfo.NonPagedAllocs > item2.TagInfo.NonPagedAllocs;
|
|
|
|
case ColumnType::NonPagedFrees:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.NonPagedFrees < item2.TagInfo.NonPagedFrees;
|
|
else
|
|
return item1.TagInfo.NonPagedFrees > item2.TagInfo.NonPagedFrees;
|
|
|
|
case ColumnType::NonPagedDiff:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.NonPagedAllocs - item1.TagInfo.NonPagedFrees < item2.TagInfo.NonPagedAllocs - item2.TagInfo.NonPagedFrees;
|
|
else
|
|
return item1.TagInfo.NonPagedAllocs - item1.TagInfo.NonPagedFrees > item2.TagInfo.NonPagedAllocs - item2.TagInfo.NonPagedFrees;
|
|
|
|
case ColumnType::NonPagedUsage:
|
|
if (m_Ascending)
|
|
return item1.TagInfo.NonPagedUsed < item2.TagInfo.NonPagedUsed;
|
|
else
|
|
return item1.TagInfo.NonPagedUsed > item2.TagInfo.NonPagedUsed;
|
|
|
|
}
|
|
|
|
ATLASSERT(false);
|
|
return false;
|
|
}
|
|
|
|
void CKernelPoolView::DoSort() {
|
|
std::sort(m_Tags.begin(), m_Tags.end(), [this](const auto& i1, const auto& i2) {
|
|
return CompareItems(*i1, *i2);
|
|
});
|
|
}
|
|
|
|
void CKernelPoolView::SetToolBar(HWND hWnd) {
|
|
|
|
}
|
|
|
|
void CKernelPoolView::AddCellColor(CellColor& cell, DWORD64 targetTime) {
|
|
cell.TargetTime = targetTime;
|
|
m_CellColors.insert({ cell, cell });
|
|
}
|
|
|
|
void CKernelPoolView::RemoveCellColor(const CellColorKey& key) {
|
|
m_CellColors.erase(key);
|
|
}
|
|
|
|
int CKernelPoolView::GetChange(const SYSTEM_POOLTAG& info, const SYSTEM_POOLTAG& newinfo, ColumnType type) const {
|
|
static const auto compare = [](const auto v1, const auto v2) -> int {
|
|
if (v1 > v2)
|
|
return -1;
|
|
if (v2 > v1)
|
|
return 1;
|
|
return 0;
|
|
};
|
|
|
|
switch (type) {
|
|
case ColumnType::NonPagedAllocs: return compare(info.NonPagedAllocs, newinfo.NonPagedAllocs);
|
|
case ColumnType::NonPagedFrees: return compare(info.NonPagedFrees, newinfo.NonPagedFrees);
|
|
case ColumnType::NonPagedDiff: return compare(info.NonPagedAllocs - info.NonPagedFrees, newinfo.NonPagedAllocs - newinfo.NonPagedFrees);
|
|
case ColumnType::NonPagedUsage: return compare(info.NonPagedUsed, newinfo.NonPagedUsed);
|
|
|
|
case ColumnType::PagedAllocs: return compare(info.PagedAllocs, newinfo.PagedAllocs);
|
|
case ColumnType::PagedFrees: return compare(info.PagedFrees, newinfo.PagedFrees);
|
|
case ColumnType::PagedDiff: return compare(info.PagedAllocs - info.PagedFrees, newinfo.PagedAllocs - newinfo.PagedFrees);
|
|
case ColumnType::PagedUsage: return compare(info.PagedUsed, newinfo.PagedUsed);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
|
|
UpdatePoolTags();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CKernelPoolView::OnRBtnDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {
|
|
CMenu menu;
|
|
CMenuHandle hSubMenu;
|
|
menu.LoadMenu(IDR_KERNEL_CONTEXT);
|
|
hSubMenu = menu.GetSubMenu(2);
|
|
POINT pt;
|
|
::GetCursorPos(&pt);
|
|
|
|
auto id = (UINT)TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hWnd, nullptr);
|
|
if (id) {
|
|
PostMessage(WM_COMMAND, id);
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CKernelPoolView::DoFind(const CString& text, DWORD flags) {
|
|
auto searchDown = flags & FR_DOWN;
|
|
|
|
int start = GetSelectedIndex();
|
|
CString find(text);
|
|
auto ignoreCase = !(flags & FR_MATCHCASE);
|
|
if (ignoreCase)
|
|
find.MakeLower();
|
|
|
|
int from = searchDown ? start + 1 : start - 1 + GetItemCount();
|
|
int to = searchDown ? GetItemCount() + start : start + 1;
|
|
int step = searchDown ? 1 : -1;
|
|
|
|
int findIndex = -1;
|
|
for (int i = from; i != to; i += step) {
|
|
int index = i % GetItemCount();
|
|
const auto& item = m_Tags[index];
|
|
CString text(item->Tag);
|
|
if (ignoreCase)
|
|
text.MakeLower();
|
|
if (text.Find(find) >= 0) {
|
|
findIndex = index;
|
|
break;
|
|
}
|
|
text = item->SourceName;
|
|
if (ignoreCase)
|
|
text.MakeLower();
|
|
if (text.Find(find) >= 0) {
|
|
findIndex = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (findIndex >= 0) {
|
|
SelectItem(findIndex);
|
|
}
|
|
else
|
|
AtlMessageBox(m_hWnd, L"Not found");
|
|
}
|
|
|
|
|