Files
BeneficialCode-WinArk/WinArk/View.cpp
T

1581 lines
44 KiB
C++

#include "stdafx.h"
#include "resource.h"
#include "View.h"
#include "Internals.h"
#include "SortHelper.h"
#include "NumberValueDlg.h"
#include "ChangeValueCommand.h"
#include "StringValueDlg.h"
#include "MultiStringValueDlg.h"
#include "BinaryValueDlg.h"
#include "ExportDlg.h"
#include "RenameValueCommand.h"
#include "ClipboardHelper.h"
#include "TreeHelper.h"
#include "ListViewHelper.h"
#include "RegHelpers.h"
#include "CreateKeyCommand.h"
#include "RenameKeyCommand.h"
#include "CreateValueCommand.h"
#include "CopyKeyCommand.h"
#include "CopyValueCommand.h"
#include "SecurityHelper.h"
#include "RegExportImport.h"
#include "GotoKeyDlg.h"
HWND CRegistryManagerView::GetHwnd() const {
return m_hWnd;
}
AppSettings& CRegistryManagerView::GetSettings() {
return m_Settings;
}
void CRegistryManagerView::RunOnUiThread(std::function<void()> f) {
SendMessage(WM_RUN, 0, reinterpret_cast<LPARAM>(&f));
}
LRESULT CRegistryManagerView::OnFindUpdate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) {
TreeHelper th(m_Tree);
HTREEITEM hItem;
auto fd = reinterpret_cast<FindData*>(lParam);
if (fd->Path[0] != L'\\') {
hItem = th.FindItem(m_hStdReg, fd->Path);
}
else {
hItem = th.FindItem(m_hRealReg, fd->Path);
}
ATLASSERT(hItem);
m_Tree.SelectItem(hItem);
m_Tree.EnsureVisible(hItem);
if ((fd->Name == nullptr || *fd->Name == 0) && (fd->Data == nullptr || *fd->Data == 0)) {
m_Tree.SetFocus();
}
else {
UpdateList(true);
int index = ListViewHelper::FindItem(m_List, fd->Data ? fd->Data : fd->Name, true);
ATLASSERT(index >= 0);
m_List.EnsureVisible(index, FALSE);
m_List.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED);
m_List.SetSelectionMark(index);
m_List.SetFocus();
}
return 0;
}
void CRegistryManagerView::OnFindNext(PCWSTR path, PCWSTR name, PCWSTR data) {
ATLTRACE(L"Found: %s, %s, %s\n", path, name, data);
FindData fd{ path,name,data };
SendMessage(WM_FIND_UPDATE, 0, reinterpret_cast<LPARAM>(&fd));
}
void CRegistryManagerView::OnFindStart() {
::SetCursor(AtlLoadSysCursor(IDC_APPSTARTING));
}
void CRegistryManagerView::OnFindEnd(bool cancelled) {
if (!cancelled) {
RunOnUiThread([this]() {
AtlMessageBox(m_hWnd, L"Finished searching the Registry.", IDS_TITLE, MB_ICONINFORMATION);
});
}
}
bool CRegistryManagerView::GoToItem(PCWSTR path, PCWSTR name, PCWSTR data) {
TreeHelper th(m_Tree);
auto hItem = th.FindItem(path[0] == L'\\' ? m_hRealReg : m_hStdReg, path);
if (!hItem)
return false;
SetActiveWindow();
m_UpdateNoDelay = true;
m_Tree.SelectItem(hItem);
UpdateList();
if (name && *name) {
int index = m_List.FindItem(name, false);
if (index >= 0) {
m_List.SetSelectionMark(index);
m_List.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED);
m_List.SetFocus();
}
}
else {
m_Tree.SetFocus();
}
return true;
}
LRESULT CRegistryManagerView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) {
::RegDeleteTree(HKEY_CURRENT_USER, DeletedPathBackup.Left(DeletedPathBackup.GetLength() - 1));
::ChangeWindowMessageFilterEx(m_hWnd, WM_COPYDATA, MSGFLT_ALLOW, nullptr);
if (m_Settings.Load(L"Software\\ScorpioSoftware\\RegExp"))
m_ReadOnly = m_Settings.ReadOnly();
m_Locations.Load(L"Software\\ScorpioSoftware\\RegExp");
CComPtr<IAutoComplete> spAC;
auto hr = spAC.CoCreateInstance(CLSID_AutoComplete);
if (SUCCEEDED(hr)) {
m_AutoCompleteStrings->CreateInstance(&m_AutoCompleteStrings);
CRect r(0, 0, 800, 20);
CEdit edit;
auto hEdit = edit.Create(m_hWnd, &r, nullptr, WS_CHILD | WS_VISIBLE |
ES_AUTOHSCROLL | ES_WANTRETURN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
hr = spAC->Init(hEdit, m_AutoCompleteStrings->GetUnknown(), nullptr, nullptr);
if (SUCCEEDED(hr)) {
spAC->Enable(TRUE);
CComQIPtr<IAutoComplete2> spAC2(spAC);
if (spAC2) {
spAC2->SetOptions(ACO_AUTOSUGGEST | ACO_USETAB | ACO_AUTOAPPEND);
}
ATLVERIFY(m_AddressBar.SubclassWindow(hEdit));
}
else {
m_AddressBar.DestroyWindow();
}
}
m_MainSplitter.Create(m_hWnd, rcDefault, nullptr,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);
m_Tree.Create(m_MainSplitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_EDITLABELS, WS_EX_CLIENTEDGE, TreeId);
m_Tree.SetExtendedStyle(TVS_EX_DOUBLEBUFFER | TVS_EX_RICHTOOLTIP, 0);
m_List.Create(m_MainSplitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
| LVS_OWNERDATA | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_EDITLABELS, WS_EX_CLIENTEDGE);
m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP);
auto cm = GetColumnManager(m_List);
cm->AddColumn(L"Name", LVCFMT_LEFT, 220, ColumnType::Name);
cm->AddColumn(L"Type", LVCFMT_LEFT, 110, ColumnType::Type);
cm->AddColumn(L"Size", LVCFMT_RIGHT, 70, ColumnType::Size);
cm->AddColumn(L"Value", LVCFMT_LEFT, 250, ColumnType::Value);
cm->AddColumn(L"Last Write", LVCFMT_LEFT, 120, ColumnType::TimeStamp);
cm->AddColumn(L"Details", LVCFMT_LEFT, 250, ColumnType::Details);
cm->UpdateColumns();
m_MainSplitter.SetSplitterPanes(m_Tree, m_List);
m_MainSplitter.SetSplitterPosPct(25);
m_MainSplitter.UpdateSplitterLayout();
m_AddressBar.SetFont(m_Tree.GetFont());
PostMessage(WM_BUILD_TREE);
return 0;
}
void CRegistryManagerView::SetStartKey(const CString& key) {
m_StartKey = key;
}
CString CRegistryManagerView::GetCurrentKeyPath() {
return GetFullNodePath(m_Tree.GetSelectedItem());
}
void CRegistryManagerView::DisplayError(PCWSTR msg, HWND hWnd, DWORD error) const {
CString text;
text.Format(L"%s (%s)", msg, (PCWSTR)RegHelpers::GetErrorText(error));
AtlMessageBox(hWnd ? hWnd : m_hWnd, (PCWSTR)text, IDS_TITLE, MB_ICONERROR);
}
CString CRegistryManagerView::GetColumnText(HWND h, int row, int col) const {
auto& item = m_Items[row];
CString text;
switch (static_cast<ColumnType>(GetColumnManager(h)->GetColumnTag(col)))
{
case ColumnType::Name:
return item.Name.IsEmpty() ? CString(RegHelpers::DefaultValueName) : item.Name;
case ColumnType::Type:
return Registry::GetRegTypeAsString(item.Type);
case ColumnType::Value:
if (!item.Key) {
if (item.Value.IsEmpty())
item.Value = Registry::GetDataAsString(m_CurrentKey, item);
return item.Value;
}
break;
case ColumnType::Size:
if (!item.Key) {
// recalculate
item.Size;
m_CurrentKey.QueryValue(item.Name, nullptr, nullptr, &item.Size);
}
text.Format(L"%u", item.Size);
break;
case ColumnType::TimeStamp:
if (item.TimeStamp.dwHighDateTime + item.TimeStamp.dwLowDateTime)
return CTime(item.TimeStamp).Format(L"%x %X");
break;
case ColumnType::Details:
return item.Key ? GetKeyDetails(item) : GetValueDetails(item);
}
return text;
}
void CRegistryManagerView::DoSort(const SortInfo* si) {
if (si == nullptr || si->SortColumn < 0 || m_Items.empty())
return;
auto col = GetColumnManager(m_List)->GetColumnTag<ColumnType>(si->SortColumn);
auto asc = si->SortAscending;
auto compare = [&](auto& d1, auto& d2) {
switch (col)
{
case ColumnType::Name:
return SortHelper::SortStrings(d1.Name, d2.Name, asc);
case ColumnType::Type:
return SortHelper::SortNumbers(d1.Type, d2.Type, asc);
case ColumnType::Size:
return SortHelper::SortNumbers(d1.Size, d2.Size, asc);
case ColumnType::TimeStamp:
return SortHelper::SortNumbers(*(ULONGLONG*)&d1.TimeStamp, *(ULONGLONG*)&d2.TimeStamp, asc);
}
return false;
};
std::sort(m_Items.begin() + (m_Settings.ShowKeysInList() ? 1 : 0), m_Items.end(), compare);
}
bool CRegistryManagerView::IsSortable(HWND h, int col) const {
auto tag = GetColumnManager(h)->GetColumnTag<ColumnType>(col);
return tag == ColumnType::Name || tag == ColumnType::Size || tag == ColumnType::Type || tag == ColumnType::TimeStamp;
}
BOOL CRegistryManagerView::OnRightClickList(HWND h, int row, int col, const POINT& pt) {
CMenu menu;
menu.LoadMenu(IDR_CONTEXT);
int index = 3;
if (row >= 0) {
index = m_Items[row].Key ? 1 : 2;
if (m_Items[row].Type == REG_KEY_UP)
return FALSE;
}
return TrackPopupMenu(menu.GetSubMenu(index), TPM_LEFTALIGN, pt.x, pt.y, 0, m_hWnd, nullptr);
}
BOOL CRegistryManagerView::OnDoubleClickList(HWND, int row, int col, const POINT& pt) {
if (row < 0)
return FALSE;
auto& item = m_Items[row];
if (item.Key) {
if (item.Type == REG_KEY_UP) {
m_UpdateNoDelay = true;
m_Tree.SelectItem(m_Tree.GetParentItem(m_Tree.GetSelectedItem()));
m_Tree.EnsureVisible(m_Tree.GetSelectedItem());
m_List.SetSelectionMark(0);
return TRUE;
}
ATLASSERT(item.Type == REG_KEY);
m_Tree.Expand(m_Tree.GetSelectedItem(), TVE_EXPAND);
TreeHelper th(m_Tree);
auto hItem = th.FindChild(m_Tree.GetSelectedItem(), item.Name);
ATLASSERT(hItem);
m_UpdateNoDelay = true;
m_Tree.SelectItem(hItem);
m_Tree.EnsureVisible(hItem);
return TRUE;
}
else {
}
return FALSE;
}
LRESULT CRegistryManagerView::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {
m_Items.clear();
bHandled = FALSE;
return 1;
}
LRESULT CRegistryManagerView::OnTimer(UINT, WPARAM id, LPARAM, BOOL&) {
if (id == 2) {
KillTimer(2);
UpdateList();
}
return 0;
}
LRESULT CRegistryManagerView::OnEditPaint(UINT, WPARAM wp, LPARAM, BOOL& handled) {
CDCHandle dc((HDC)wp);
CRect rc;
GetClientRect(&rc);
dc.FillSolidRect(&rc, 255);
return 1;
}
LRESULT CRegistryManagerView::OnGoToKeyExternal(UINT, WPARAM, LPARAM lp, BOOL&) {
auto cds = reinterpret_cast<COPYDATASTRUCT*>(lp);
if (cds->dwData == 0x1000) {
SetActiveWindow();
if (cds->lpData)
GotoKey((PCWSTR)cds->lpData);
return 1;
}
return 0;
}
void CRegistryManagerView::InitTree() {
WCHAR name[32];
DWORD len = _countof(name);
::GetComputerName(name, &len);
m_hLocalRoot = m_Tree.InsertItem(name + CString(L" (Local)"), 1, 1, TVI_ROOT, TVI_LAST);
m_hLocalRoot.SetData(static_cast<DWORD_PTR>(NodeType::Machine));
m_hStdReg = m_Tree.InsertItem(L"Standard Registry", 0, 0, m_hLocalRoot, TVI_LAST);
SetNodeData(m_hStdReg, NodeType::StandardRoot);
m_hRealReg = m_Tree.InsertItem(L"REGISTRY", 11, 11, m_hLocalRoot, TVI_LAST);
SetNodeData(m_hRealReg, NodeType::RegistryRoot | NodeType::Predefined | NodeType::Key);
m_hLocalRoot.Expand(TVE_EXPAND);
m_Tree.SelectItem(m_hStdReg);
}
NodeType CRegistryManagerView::GetNodeData(HTREEITEM hItem) const {
return static_cast<NodeType>(m_Tree.GetItemData(hItem));
}
void CRegistryManagerView::SetNodeData(HTREEITEM hItem, NodeType type) {
m_Tree.SetItemData(hItem, static_cast<DWORD_PTR>(type));
}
HTREEITEM CRegistryManagerView::BuildTree(HTREEITEM hRoot, HKEY hKey, PCWSTR name) {
if (name) {
hRoot = m_Tree.InsertItem(name, 3, 2, hRoot, TVI_LAST);
auto path = GetFullNodePath(hRoot);
if (Registry::IsHiveKey(path)) {
SetNodeData(hRoot, GetNodeData(hRoot) | NodeType::Hive);
}
auto subkeys = Registry::GetSubKeyCount(hKey);
if (subkeys) {
m_Tree.InsertItem(L"\\\\", hRoot, TVI_LAST);
}
}
else {
CRegKey key(hKey);
Registry::EnumSubKeys(key, [&](auto name, const auto& ft) {
auto hItem = m_Tree.InsertItem(name, 3, 2, hRoot, TVI_LAST);
SetNodeData(hItem, NodeType::Key);
CRegKey subKey;
auto error = subKey.Open(hKey, name, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
if (error == ERROR_SUCCESS) {
DWORD subkeys = Registry::GetSubKeyCount(subKey);
if (subkeys)
m_Tree.InsertItem(L"\\\\", hItem, TVI_LAST);
subKey.Close();
CString linkPath;
if (Registry::IsKeyLink(key, name, linkPath)) {
// m_Tree.SetItemImage(hItem, 4, 4);
}
}
else if (error == ERROR_ACCESS_DENIED) {
SetNodeData(hItem, GetNodeData(hItem) | NodeType::AccessDenied);
}
auto path = GetFullNodePath(hItem);
if (Registry::IsHiveKey(path)) {
SetNodeData(hItem, GetNodeData(hItem) | NodeType::Hive);
}
return true;
});
m_Tree.SortChildren(hRoot);
key.Detach();
}
return hRoot;
}
LRESULT CRegistryManagerView::OnBuildTree(UINT, WPARAM, LPARAM, BOOL&) {
InitTree();
auto showExtra = m_Settings.ShowExtraHive();
m_Tree.LockWindowUpdate();
int i = 0;
for (auto& k : Registry::Keys) {
if (!showExtra && ++i == 6)
break;
auto hItem = BuildTree(m_hStdReg, k.hKey, k.text);
SetNodeData(hItem, NodeType::Key | NodeType::Predefined);
}
m_Tree.Expand(m_hStdReg, TVE_EXPAND);
auto hKey = Registry::OpenRealRegistryKey();
if (hKey) {
CRegKey key(hKey);
BuildTree(m_hRealReg, key);
m_Tree.Expand(m_hRealReg, TVE_EXPAND);
}
m_Tree.LockWindowUpdate(FALSE);
if (!m_StartKey.IsEmpty()) {
auto hItem = GotoKey(m_StartKey);
if (!hItem) {
AtlMessageBox(m_hWnd, (PCWSTR)(L"Failed to locate key " + m_StartKey), IDS_TITLE, MB_ICONWARNING);
}
}
m_Tree.SetFocus();
return 0;
}
CString CRegistryManagerView::GetFullNodePath(HTREEITEM hItem) const {
CString path;
auto hPrev = hItem;
CString text;
while (hItem && ((GetNodeData(hItem) & (NodeType::Predefined | NodeType::Key)) != NodeType::None)) {
ATLVERIFY(m_Tree.GetItemText(hItem, text));
path = text + L"\\" + path;
hPrev = hItem;
hItem = m_Tree.GetParentItem(hItem);
}
path.TrimRight(L"\\");
if (path.Left(8) == L"REGISTRY")
path = L"\\" + path;
if ((GetNodeData(hItem) & NodeType::RemoteRegistry) == NodeType::RemoteRegistry) {
CString name;
m_Tree.GetItemText(hItem, name);
path = L"\\\\" + name + (path.IsEmpty() ? L"" : L"\\") + path;
}
return path;
}
CString CRegistryManagerView::GetFullParentNodePath(HTREEITEM hItem) const {
auto path = GetFullNodePath(hItem);
auto index = path.ReverseFind(L'\\');
if (index < 0)
return L"";
return path.Left(index);
}
CString CRegistryManagerView::GetKeyDetails(const RegistryItem& item) const {
if (item.Type == REG_KEY_UP)
return L"";
RegistryKey key;
if (!m_CurrentKey)
key = Registry::OpenKey(m_CurrentPath + (m_CurrentPath.IsEmpty() ? L"" : L"\\") + item.Name, KEY_QUERY_VALUE);
else
key.Open(m_CurrentKey.Get(), item.Name, KEY_QUERY_VALUE);
CString text;
if (key) {
DWORD values = 0;
auto subkeys = Registry::GetSubKeyCount(key, &values);
text.Format(L"Subkeys: %u, Values: %u", subkeys, values);
}
return text;
}
CString CRegistryManagerView::GetValueDetails(const RegistryItem& item) const {
ATLASSERT(!item.Key);
CString text;
if (item.Value.IsEmpty())
item.Value = Registry::GetDataAsString(m_CurrentKey, item);
switch (item.Type)
{
case REG_EXPAND_SZ:
if (item.Value.Find(L"%") >= 0) {
text = Registry::ExpandStrings(item.Value);
}
break;
case REG_SZ:
if (item.Value[0] == L'@') {
static const CString paths[] = {
L"",
RegHelpers::GetSystemDir(),
RegHelpers::GetSystemDir() + CString(L"\\Drivers"),
RegHelpers::GetWindowsDir(),
};
for (auto& path : paths) {
if (ERROR_FILE_NOT_FOUND != ::RegLoadMUIString(m_CurrentKey.Get(),
item.Name, text.GetBufferSetLength(512), 512,
nullptr, REG_MUI_STRING_TRUNCATE, path.IsEmpty() ? nullptr : (PCWSTR)path))
break;
}
}
break;
}
return text;
}
CTreeItem CRegistryManagerView::InsertKeyItem(HTREEITEM hParent, PCWSTR name, NodeType type) {
bool accessDenied = (type & NodeType::AccessDenied) == NodeType::AccessDenied;
auto item = m_Tree.InsertItem(name, hParent, TVI_LAST);
SetNodeData(item, type);
if ((type & NodeType::Key) == NodeType::Key) {
auto key = Registry::OpenKey(GetFullNodePath(item), KEY_QUERY_VALUE);
if (key) {
if (Registry::GetSubKeyCount(key.Get()) > 0)
m_Tree.InsertItem(L"\\\\", item, TVI_LAST);
}
}
return item;
}
HTREEITEM CRegistryManagerView::BuildKeyPath(const CString& path, bool accessible) {
auto hItem = path[0] == L'\\' ? m_hRealReg : m_hStdReg;
CString name;
int start = path[0] == L'\\' ? 10 : 0;
TreeHelper th(m_Tree);
while (!(name = path.Tokenize(L"\\", start)).IsEmpty()) {
auto hChild = th.FindChild(hItem, name);
if (hChild) {
hItem = hChild;
continue;
}
hItem = InsertKeyItem(hItem, name, NodeType::Key | (accessible ? NodeType::None : NodeType::AccessDenied));
}
return hItem;
}
HTREEITEM CRegistryManagerView::GotoKey(const CString& path, bool knownToExist) {
CString spath(path);
spath.MakeUpper();
if (spath != L'\\') {
if (spath.Find(L'\\') < 0)
spath += L"\\";
spath.Replace(L"HKLM\\", L"HKEY_LOCAL_MACHINE\\");
spath.Replace(L"HKCU\\", L"HKEY_CURRENT_USER\\");
spath.Replace(L"HKCR\\", L"HKEY_CLASSES_ROOT\\");
spath.Replace(L"HKU\\", L"HKEY_USERS\\");
spath.Replace(L"HKCC\\", L"HKEY_CURRENT_CONFIG\\");
}
auto hItem = TreeHelper(m_Tree).FindItem(spath[0] == L'\\' ? m_hRealReg : m_hStdReg, spath);
if (!hItem || knownToExist) {
auto key = Registry::OpenKey(path, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE);
hItem = BuildKeyPath(path, key.Get() != nullptr);
}
if (hItem) {
m_Tree.SelectItem(hItem);
m_Tree.EnsureVisible(hItem);
m_Tree.SetFocus();
}
return hItem;
}
void CRegistryManagerView::UpdateList(bool force) {
m_Items.clear();
m_List.SetItemCount(0);
auto hItem = m_Tree.GetSelectedItem();
m_CurrentPath = GetFullNodePath(hItem);
auto& path = m_CurrentPath;
m_AddressBar.SetWindowText(path);
m_CurrentKey.Close();
if (hItem == m_hLocalRoot)
return;
if (hItem == m_hRealReg)
m_CurrentKey.Attach(Registry::OpenRealRegistryKey());
if (m_Settings.ShowKeysInList() && (hItem == m_hStdReg || hItem == m_hRealReg ||
(GetNodeData(hItem) & NodeType::RemoteRegistry) == NodeType::RemoteRegistry)) {
// special case for root of registry
for (hItem = m_Tree.GetChildItem(hItem); hItem; hItem = m_Tree.GetNextSiblingItem(hItem)) {
RegistryItem item;
CString name;
m_Tree.GetItemText(hItem, name);
item.Name = name;
if (m_CurrentPath[0] == L'\\')
name = m_CurrentPath + L"\\" + name;
auto key = Registry::OpenKey(name, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
if (key) {
Registry::GetSubKeyCount(key.Get(), nullptr, &item.TimeStamp);
}
item.Key = true;
item.Type = REG_KEY;
m_Items.push_back(std::move(item));
}
m_List.SetItemCount(static_cast<int>(m_Items.size()));
DoSort(GetSortInfo(m_List));
return;
}
if (!m_CurrentPath.IsEmpty()) {
m_CurrentKey = Registry::OpenKey(m_CurrentPath,
KEY_QUERY_VALUE | (m_Settings.ShowKeysInList() ? KEY_ENUMERATE_SUB_KEYS : 0));
ATLASSERT(m_CurrentKey.IsValid());
}
if (m_Settings.ShowKeysInList()) {
// insert up directory
RegistryItem up;
up.Name = L"..";
up.Type = REG_KEY_UP;
up.Key = true;
m_Items.push_back(up);
if (m_CurrentKey) {
Registry::EnumSubKeys(m_CurrentKey.Get(), [&](auto name, const auto& ft) {
RegistryItem item;
item.Name = name;
item.TimeStamp = ft;
item.Key = true;
item.Type = REG_KEY;
m_Items.push_back(std::move(item));
return true;
});
}
}
if (m_CurrentKey) {
Registry::EnumKeyValues(m_CurrentKey.Get(), [&](auto type, auto name, auto size) {
RegistryItem item;
item.Name = name;
item.Type = type;
item.Size = size;
m_Items.push_back(item);
return true;
});
}
auto parentPath = GetFullParentNodePath(hItem);
if (!parentPath.IsEmpty()) {
auto temp = Registry::OpenKey(parentPath, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
if (temp) {
CString name, linkPath;
m_Tree.GetItemText(hItem, name);
if (Registry::IsKeyLink(temp.Get(), name, linkPath)) {
RegistryItem item;
item.Name = L"SymbolicLinkName";
item.Type = REG_LINK;
item.Size = (linkPath.GetLength() + 1) * sizeof(WCHAR);
item.Value = linkPath;
m_Items.push_back(item);
}
}
}
m_List.SetItemCount(static_cast<int>(m_Items.size()));
DoSort(GetSortInfo(m_List));
m_List.RedrawItems(m_List.GetTopIndex(), m_List.GetTopIndex() + m_List.GetCountPerPage());
}
LRESULT CRegistryManagerView::OnTreeItemExpanding(int, LPNMHDR hdr, BOOL&) {
auto tv = (NMTREEVIEW*)hdr;
CString text;
auto h = tv->itemNew.hItem;
m_Tree.GetItemText(m_Tree.GetChildItem(h), text);
if (text == L"\\\\") {
m_Tree.DeleteItem(m_Tree.GetChildItem(h));
CWaitCursor wait;
ExpandItem(h);
}
return FALSE;
}
void CRegistryManagerView::ExpandItem(HTREEITEM hItem) {
auto path = GetFullNodePath(hItem);
auto key = Registry::OpenKey(path, KEY_ENUMERATE_SUB_KEYS);
if (key) {
m_Tree.SetRedraw(FALSE);
BuildTree(hItem, key.Get());
m_Tree.SetRedraw(TRUE);
}
}
LRESULT CRegistryManagerView::OnTreeSelChanged(int, LPNMHDR, BOOL&) {
if (m_UpdateNoDelay) {
m_UpdateNoDelay = false;
UpdateList();
}
else {
// short delay in case the user is scrolling fast
SetTimer(2, 200, nullptr);
}
return 0;
}
HTREEITEM CRegistryManagerView::FindItemByPath(PCWSTR path) const {
CTreeItem item;
if (path[0] == L'\\') {
// real registry
item = m_hRealReg;
}
else {
// standard registry
item = m_hStdReg;
}
CString spath(path);
int start = 0;
while (true) {
auto token = spath.Tokenize(L"\\", start);
if (token.IsEmpty())
break;
TreeHelper th(m_Tree);
item = th.FindChild(item, token);
}
return item;
}
LRESULT CRegistryManagerView::OnTreeEndEdit(int /*idCtrl*/, LPNMHDR hdr, BOOL& /*bHandled*/) {
auto& item = ((NMTVDISPINFO*)hdr)->item;
if (item.pszText == nullptr) {
// cancelled
if (m_CurrentOperation == Operation::CreateKey)
m_Tree.DeleteItem(item.hItem);
return FALSE;
}
switch (m_CurrentOperation)
{
case CRegistryManagerView::Operation::RenameKey:
{
CString name;
m_Tree.GetItemText(item.hItem, name);
auto cb = [this](auto& cmd, bool) {
auto hParent = FindItemByPath(cmd.GetPath());
ATLASSERT(hParent);
TreeHelper th(m_Tree);
auto hItem = th.FindChild(hParent, cmd.GetName());
ATLASSERT(hItem);
m_Tree.SetItemText(hItem, cmd.GetNewName());
return true;
};
auto hParent = m_Tree.GetParentItem(item.hItem);
auto cmd = std::make_shared<RenameKeyCommand>(GetFullNodePath(hParent), name, item.pszText);
if (!m_CmdMgr.AddCommand(cmd)) {
DisplayError(L"Failed to rename key");
return FALSE;
}
cmd->SetCallback(cb);
return TRUE;
}
case CRegistryManagerView::Operation::CreateKey:
{
auto hItem = item.hItem;
auto hParent = m_Tree.GetParentItem(hItem);
auto cmd = std::make_shared<CreateKeyCommand>(GetFullNodePath(hParent), item.pszText);
if (!m_CmdMgr.AddCommand(cmd)) {
m_Tree.DeleteItem(hItem);
DisplayError(L"Failed to create key");
return FALSE;
}
auto cb = [this](auto& cmd, bool execute) {
if (execute) {
auto hParent = FindItemByPath(cmd.GetPath());
ATLASSERT(hParent);
auto hItem = InsertKeyItem(hParent, cmd.GetName());
m_Tree.EnsureVisible(hItem);
}
else {
auto hItem = FindItemByPath(cmd.GetPath() + L"\\" + cmd.GetName());
ATLASSERT(hItem);
m_Tree.DeleteItem(hItem);
}
return true;
};
cmd->SetCallback(cb);
if (AppSettings::Get().ShowKeysInList())
UpdateList();
return TRUE;
}
}
return FALSE;
}
LRESULT CRegistryManagerView::OnTreeBeginEdit(int, LPNMHDR hdr, BOOL&) {
auto tv = (NMTVDISPINFO*)hdr;
auto prevent = m_ReadOnly || (GetNodeData(tv->item.hItem) & (NodeType::Key | NodeType::Predefined)) != NodeType::Key;
if (!prevent && m_CurrentOperation == Operation::None)
m_CurrentOperation = Operation::RenameKey;
return prevent;
}
LRESULT CRegistryManagerView::OnListItemChanged(int, LPNMHDR, BOOL&)
{
int selected = m_List.GetSelectionMark();
if (selected != m_CurrentSelectedItem) {
m_CurrentSelectedItem = selected;
}
return 0;
}
LRESULT CRegistryManagerView::OnListEndEdit(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {
auto lv = (NMLVDISPINFO*)pnmh;
if (lv->item.pszText == nullptr) {
// cancelled
return FALSE;
}
std::shared_ptr<AppCommand> cmd;
auto hItem = m_Tree.GetSelectedItem();
auto index = lv->item.iItem;
auto& item = m_Items[index];
auto path = GetFullNodePath(hItem);
switch (m_CurrentOperation)
{
case Operation::RenameKey:
cmd = std::make_shared<RenameKeyCommand>(path, item.Name, lv->item.pszText);
break;
case Operation::CreateKey:
cmd = std::make_shared<CreateKeyCommand>(path, lv->item.pszText);
break;
case Operation::CreateValue:
{
CString text(lv->item.pszText);
if (text.IsEmpty()) {
// default value
}
auto cb = [this](auto cmd, auto) {
if (m_CurrentOperation == Operation::None && cmd.GetPath() == GetFullNodePath(m_Tree.GetSelectedItem())) {
UpdateList(true);
}
return true;
};
cmd = std::make_shared<CreateValueCommand>(path, text, item.Type, cb);
break;
}
case Operation::RenameValue:
cmd = std::make_shared<RenameValueCommand>(GetFullNodePath(hItem), item.Name, lv->item.pszText);
break;
}
LRESULT rv = FALSE;
ATLASSERT(cmd);
if (cmd) {
auto op = m_CurrentOperation;
m_CurrentOperation = Operation::None;
if (!m_CmdMgr.AddCommand(cmd)) {
DisplayError(L"Failed to " + cmd->GetCommandName());
}
else {
switch (op) {
case Operation::CreateValue:
// ����ָ��֮����ת��
item.Size = std::static_pointer_cast<CreateValueCommand>(cmd)->GetSize();
break;
case Operation::RenameKey:
case Operation::RenameValue:
item.Name = lv->item.pszText;
break;
}
m_List.RedrawItems(index, index);
m_List.SetSelectionMark(index);
m_List.EnsureVisible(index, FALSE);
rv = TRUE;
}
}
return rv;
}
LRESULT CRegistryManagerView::OnListBeginEdit(int, LPNMHDR pnmh, BOOL&) {
if (m_ReadOnly)
return TRUE;
if (m_CurrentOperation != Operation::None)
return FALSE;
auto lv = (NMLVDISPINFO*)pnmh;
auto& item = m_Items[lv->item.iItem];
m_CurrentOperation = item.Key ? Operation::RenameKey : Operation::RenameValue;
return FALSE;
}
void CRegistryManagerView::InvokeTreeContextMenu(const CPoint& pt) {
CPoint pt2(pt);
m_Tree.ClientToScreen(&pt2);
CMenu menu;
menu.LoadMenu(IDR_CONTEXT);
TrackPopupMenu(menu.GetSubMenu(5), 0, pt2.x, pt2.y, 0, m_hWnd, nullptr);
}
LRESULT CRegistryManagerView::OnTreeKeyDown(int, LPNMHDR hdr, BOOL&) {
auto tv = (NMTVKEYDOWN*)hdr;
switch (tv->wVKey)
{
case VK_TAB:
m_List.SetFocus();
if (m_List.GetSelectedCount() == 0)
m_List.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
return TRUE;
case VK_APPS:
CRect rc;
if (m_Tree.GetItemRect(m_Tree.GetSelectedItem(), &rc, TRUE)) {
InvokeTreeContextMenu(rc.CenterPoint());
return TRUE;
}
break;
}
return 0;
}
LRESULT CRegistryManagerView::OnEditKeyDown(UINT, WPARAM wp, LPARAM, BOOL& handled) {
if (wp == VK_RETURN) {
CString path;
m_AddressBar.GetWindowText(path);
static const std::wstring computer(L"Computer\\");
static const std::wstring computerName(L"������\\");
std::wstring regPath(path);
if (regPath.find(computer) == 0) {
regPath = regPath.substr(computer.size());
}
else if (regPath.find(computerName) == 0) {
regPath = regPath.substr(computerName.size());
}
GotoKey(regPath.c_str());
}
else if (wp == VK_ESCAPE) {
m_List.SetFocus();
}
else {
handled = FALSE;
}
return 0;
}
LRESULT CRegistryManagerView::OnRunOnUIThread(UINT, WPARAM, LPARAM lp, BOOL&) {
auto f = reinterpret_cast<std::function<void()>*>(lp);
(*f)();
return 0;
}
LRESULT CRegistryManagerView::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) {
if (m_AddressBar.IsWindow()) {
int cx = GET_X_LPARAM(lParam), cy = GET_Y_LPARAM(lParam);
CRect rc;
m_AddressBar.GetClientRect(&rc);
m_AddressBar.MoveWindow(0, 0, rc.right, rc.bottom);
m_MainSplitter.MoveWindow(0, rc.bottom, cx, cy - rc.bottom);
}
return 0;
}
LRESULT CRegistryManagerView::OnListKeyDown(int /*idCtrl*/, LPNMHDR hdr, BOOL& /*bHandled*/) {
auto lv = (NMLVKEYDOWN*)hdr;
switch (lv->wVKey)
{
case VK_TAB:
m_Tree.SetFocus();
break;
case VK_RETURN:
OnDoubleClickList(m_List, m_List.GetSelectionMark(), 0, POINT());
break;
}
return 0;
}
LRESULT CRegistryManagerView::OnTreeContextMenu(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) {
CPoint pt;
::GetCursorPos(&pt);
CPoint pt2(pt);
m_Tree.ScreenToClient(&pt);
UINT flags;
auto hItem = m_Tree.HitTest(pt, &flags);
if (hItem) {
m_Tree.SelectItem(hItem);
if (hItem == m_hStdReg || hItem == m_hLocalRoot)
return 0;
CMenu menu;
menu.LoadMenu(IDR_CONTEXT);
auto type = GetNodeData(hItem);
auto hMenu = menu.GetSubMenu((type & NodeType::RemoteRegistry) == NodeType::RemoteRegistry ? 6 : 5);
if ((type & NodeType::Hive) == NodeType::Hive) {
// add jump to hive file
//hMenu.InsertMenu(0, MF_BYPOSITION, ID_KEY_JUMPTOHIVEFILE, L"Jump &Hive File...");
}
TrackPopupMenu(hMenu, 0, pt2.x, pt2.y, 0, m_hWnd, nullptr);
}
return 0;
}
void CRegistryManagerView::RefreshFull(HTREEITEM hItem) {
hItem = m_Tree.GetChildItem(hItem);
TreeHelper th(m_Tree);
while (hItem) {
auto state = m_Tree.GetItemState(hItem, TVIS_EXPANDED | TVIS_EXPANDEDONCE);
if (state) {
if (state == TVIS_EXPANDEDONCE) {
CString text;
if (m_Tree.GetChildItem(hItem) && m_Tree.GetItemText(m_Tree.GetChildItem(hItem), text) && text != L"\\\\") {
// not expanded now,delete all items and insert a dummy item
th.DeleteChildren(hItem);
m_Tree.InsertItem(L"\\\\", hItem, TVI_LAST);
}
}
else {
// really expanded
RefreshFull(hItem);
auto key = Registry::OpenKey(GetFullNodePath(hItem), KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
if (key) {
auto keys = th.GetChildItems(hItem);
Registry::EnumSubKeys(key.Get(), [&](auto name, const auto&) {
if (!th.FindChild(hItem, name)) {
// new sub key
auto hChild = InsertKeyItem(hItem, name);
}
else {
keys.erase(name);
}
return true;
});
for (auto& [name, h] : keys)
m_Tree.DeleteItem(h);
if (m_Tree.GetChildItem(hItem) == nullptr) {
// remove children indicator
TVITEM tvi;
tvi.hItem = hItem;
tvi.mask = TVIF_CHILDREN;
tvi.cChildren = 0;
m_Tree.SetItem(&tvi);
}
else {
m_Tree.SortChildren(hItem);
}
}
}
}
else if (m_Tree.GetChildItem(hItem) == nullptr && (GetNodeData(hItem) & NodeType::AccessDenied) == NodeType::None) {
// no children - check if new exist
auto key = Registry::OpenKey(GetFullNodePath(hItem), KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
if (Registry::GetSubKeyCount(key.Get()) > 0) {
m_Tree.InsertItem(L"\\\\", hItem, TVI_LAST);
TVITEM tvi;
tvi.hItem = hItem;
tvi.mask = TVIF_CHILDREN;
tvi.cChildren = 1;
m_Tree.SetItem(&tvi);
}
}
hItem = m_Tree.GetNextSiblingItem(hItem);
}
}
LRESULT CRegistryManagerView::OnViewRefresh(WORD, WORD, HWND, BOOL&) {
RefreshFull(m_hStdReg);
RefreshFull(m_hRealReg);
UpdateList();
return 0;
}
LRESULT CRegistryManagerView::OnNewKey(WORD, WORD, HWND, BOOL&) {
m_Tree.GetSelectedItem().Expand(TVE_EXPAND);
auto hItem = InsertKeyItem(m_Tree.GetSelectedItem(), L"(NewKey)");
hItem.EnsureVisible();
m_CurrentOperation = Operation::CreateKey;
m_Tree.EditLabel(hItem);
return 0;
}
bool CRegistryManagerView::RefreshItem(HTREEITEM hItem) {
auto expanded = m_Tree.GetItemState(hItem, TVIS_EXPANDED);
m_Tree.LockWindowUpdate();
m_Tree.Expand(hItem, TVE_COLLAPSE | TVE_COLLAPSERESET);
TreeHelper th(m_Tree);
th.DeleteChildren(hItem);
m_Tree.InsertItem(L"\\\\", hItem, TVI_LAST);
if (expanded)
m_Tree.Expand(hItem, TVE_EXPAND);
m_Tree.LockWindowUpdate(FALSE);
UpdateList(true);
return true;
}
LRESULT CRegistryManagerView::OnTreeRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
RefreshItem(m_Tree.GetSelectedItem());
return 0;
}
LRESULT CRegistryManagerView::OnNewValue(WORD /*wNotifyCode*/, WORD id, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
DWORD type = REG_NONE;
switch (id)
{
case ID_NEW_BINARYVALUE:
type = REG_BINARY;
break;
case ID_NEW_DWORDVALUE:
type = REG_DWORD;
break;
case ID_NEW_QWORDVALUE:
type = REG_QWORD;
break;
case ID_NEW_STRINGVALUE:
type = REG_SZ;
break;
case ID_NEW_MULTIPLESTRINGVALUE:
type = REG_MULTI_SZ;
break;
case ID_NEW_EXPANDSTRINGVALUE:
type = REG_EXPAND_SZ;
break;
}
RegistryItem item;
item.Name = L"NewValue";
item.Type = type;
item.Key = false;
m_Items.push_back(item);
m_List.SetItemCountEx(m_List.GetItemCount() + 1, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
m_CurrentOperation = Operation::CreateValue;
m_List.EditLabel((int)m_Items.size() - 1);
return 0;
}
LRESULT CRegistryManagerView::OnEditCopy(WORD, WORD, HWND, BOOL&){
if (::GetFocus() == m_Tree) {
ClipboardItem item;
item.Key = true;
item.Path = GetFullParentNodePath(m_Tree.GetSelectedItem());
m_Tree.GetItemText(m_Tree.GetSelectedItem(), item.Name);
m_Clipboard.Items.clear();
m_Clipboard.Items.push_back(item);
m_Clipboard.Operation = ClipboardOperation::Copy;
}
else {
ATLASSERT(::GetFocus() == m_List);
auto count = m_List.GetSelectedCount();
ATLASSERT(count >= 1);
int index = -1;
auto path = GetFullNodePath(m_Tree.GetSelectedItem());
m_Clipboard.Items.clear();
CString text;
for (UINT i = 0; i < count; i++) {
index = m_List.GetNextItem(index, LVIS_SELECTED);
ATLASSERT(index >= 0);
text += ListViewHelper::GetRowAsString(m_List, index, L'\t') + L"\n";
ClipboardItem ci;
ci.Path = path;
auto& item = m_Items[index];
ci.Key = item.Key;
ci.Name = item.Name;
m_Clipboard.Items.push_back(ci);
}
ClipboardHelper::CopyText(m_hWnd, text);
m_Clipboard.Operation = ClipboardOperation::Copy;
}
return 0;
}
LRESULT CRegistryManagerView::OnEditCut(WORD code, WORD id, HWND hWndCtl, BOOL& bHandled) {
OnEditCopy(code, id, hWndCtl, bHandled);
if (m_Clipboard.Operation == ClipboardOperation::Copy)
m_Clipboard.Operation = ClipboardOperation::Cut;
return 0;
}
AppCommandCallback<DeleteKeyCommand> CRegistryManagerView::GetDeleteKeyCommandCallback() {
static const auto cb = [this](auto& cmd, bool execute) {
TreeHelper th(m_Tree);
auto real = cmd.GetPath()[0] == L'\\';
auto hParent = th.FindItem(real ? m_hRealReg : m_hStdReg, cmd.GetPath());
ATLASSERT(hParent);
if (execute) {
auto hItem = th.FindChild(hParent, cmd.GetName());
ATLASSERT(hItem);
m_Tree.DeleteItem(hItem);
}
else {
// create the item
auto hItem = InsertKeyItem(hParent, cmd.GetName());
}
return true;
};
return cb;
}
LRESULT CRegistryManagerView::OnEditPaste(WORD, WORD, HWND, BOOL&){
if (m_Clipboard.Items.empty()) {
return 0;
}
ATLASSERT(!m_Clipboard.Items.empty());
auto cb = [this](auto& cmd, bool) {
RefreshItem(m_Tree.GetSelectedItem());
UpdateList();
return TRUE;
};
auto list = std::make_shared<AppCommandList>(nullptr, cb);
auto path = GetFullNodePath(m_Tree.GetSelectedItem());
for (auto& item : m_Clipboard.Items) {
std::shared_ptr<AppCommand> cmd;
if (item.Key)
cmd = std::make_shared<CopyKeyCommand>(item.Path, item.Name, path);
else
cmd = std::make_shared<CopyValueCommand>(item.Path, item.Name, path);
list->AddCommand(cmd);
if (m_Clipboard.Operation == ClipboardOperation::Cut) {
if (item.Key)
cmd = std::make_shared<DeleteKeyCommand>(item.Path, item.Name, GetDeleteKeyCommandCallback());
else
cmd = std::make_shared<DeleteValueCommand>(item.Path, item.Name);
list->AddCommand(cmd);
}
}
if (list->GetCount() == 1)
list->SetCommandName(list->GetCommand(0)->GetCommandName());
else
list->SetCommandName(L"Paste");
if (!m_CmdMgr.AddCommand(list))
DisplayError(L"Paste failed");
return 0;
}
LRESULT CRegistryManagerView::OnEditRename(WORD, WORD, HWND, BOOL&){
if (::GetFocus() == m_Tree) {
m_CurrentOperation = Operation::RenameKey;
m_Tree.EditLabel(m_Tree.GetSelectedItem());
}
else if (::GetFocus() == m_List) {
auto index = m_List.GetSelectionMark();
if (index >= 0) {
m_CurrentOperation = m_Items[index].Key ? Operation::RenameKey : Operation::RenameValue;
m_List.EditLabel(index);
}
}
return 0;
}
LRESULT CRegistryManagerView::OnEditDelete(WORD, WORD, HWND, BOOL&){
if (::GetFocus() == m_Tree) {
auto hItem = m_Tree.GetSelectedItem();
auto path = GetFullParentNodePath(hItem);
CString name;
m_Tree.GetItemText(hItem, name);
auto cmd = std::make_shared<DeleteKeyCommand>(path, name, GetDeleteKeyCommandCallback());
if (!m_CmdMgr.AddCommand(cmd))
DisplayError(L"Failed to delete key");
}
else if (::GetFocus() == m_List) {
auto count = m_List.GetSelectedCount();
ATLASSERT(count >= 1);
int index = -1;
auto cb = [this](auto& cmd, auto) {
auto cmd0 = std::static_pointer_cast<DeleteValueCommand>(cmd.GetCommand(0));
if (GetFullNodePath(m_Tree.GetSelectedItem()) == cmd0->GetPath()) {
RefreshItem(m_Tree.GetSelectedItem());
UpdateList();
}
return true;
};
auto list = std::make_shared<AppCommandList>(L"", cb);
auto path = GetFullNodePath(m_Tree.GetSelectedItem());
for (UINT i = 0; i < count; i++) {
index = m_List.GetNextItem(index, LVIS_SELECTED);
ATLASSERT(index >= 0);
auto& item = m_Items[index];
if (item.Type == REG_KEY_UP) {
count--;
continue;
}
std::shared_ptr<AppCommand> cmd;
if (item.Key) {
cmd = std::make_shared<DeleteKeyCommand>(path, item.Name);
}
else {
cmd = std::make_shared<DeleteValueCommand>(path, item.Name);
}
list->AddCommand(cmd);
}
if (count == 1) // only up key selected
return 0;
if (count == 1)
list->SetCommandName(list->GetCommand(0)->GetCommandName());
else
list->SetCommandName(L"Delete");
if (!m_CmdMgr.AddCommand(list))
DisplayError(L"Delete failed.");
}
return 0;
}
LRESULT CRegistryManagerView::OnCopyFullKeyName(WORD, WORD, HWND, BOOL&){
ClipboardHelper::CopyText(m_hWnd, GetFullNodePath(m_Tree.GetSelectedItem()));
return 0;
}
LRESULT CRegistryManagerView::OnCopyKeyName(WORD, WORD, HWND, BOOL&){
CString text;
m_Tree.GetItemText(m_Tree.GetSelectedItem(), text);
ClipboardHelper::CopyText(m_hWnd, text);
return 0;
}
LRESULT CRegistryManagerView::OnKeyPermissions(WORD, WORD, HWND, BOOL&){
auto path = GetFullNodePath(m_Tree.GetSelectedItem());
SecurityHelper::EnablePrivilege(SE_TAKE_OWNERSHIP_NAME, true);
if (::GetFocus() == m_List) {
auto& item = m_Items[m_List.GetSelectionMark()];
ATLASSERT(item.Key);
path += L"\\" + item.Name;
}
auto readonly = m_ReadOnly;
auto key = Registry::OpenKey(path, READ_CONTROL | (readonly ? 0 : (WRITE_DAC | WRITE_OWNER)));
if (!key && ::GetLastError() == ERROR_ACCESS_DENIED) {
key = Registry::OpenKey(path, READ_CONTROL);
readonly = true;
}
if (!key && ::GetLastError() == ERROR_ACCESS_DENIED) {
key = Registry::OpenKey(path, MAXIMUM_ALLOWED);
}
if (!key) {
DisplayError(L"Failed to open key");
}
else {
CSecurityInformation si(key, path, readonly);
::EditSecurity(m_hWnd, &si);
}
SecurityHelper::EnablePrivilege(SE_TAKE_OWNERSHIP_NAME, false);
return 0;
}
LRESULT CRegistryManagerView::OnProperties(WORD, WORD, HWND, BOOL&){
if (::GetFocus() == m_List) {
auto index = m_List.GetSelectionMark();
if (index >= 0 && !m_Items[index].Key)
return (LRESULT)ShowValueProperties(m_Items[index], index);
}
return 0;
}
INT_PTR CRegistryManagerView::ShowValueProperties(RegistryItem& item, int index) {
auto cb = [this](auto& cmd, bool) {
if (GetFullNodePath(m_Tree.GetSelectedItem()) == cmd.GetPath()) {
int index = m_List.FindItem(cmd.GetName(), false);
ATLASSERT(index >= 0);
if (index >= 0) {
m_Items[index].Value.Empty();
m_Items[index].Size -= 1;
m_List.RedrawItems(index, index);
m_List.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED);
}
}
return true;
};
bool success = false;
bool result = false;
switch (item.Type)
{
case REG_LINK:
AtlMessageBox(m_hWnd, L"No special properties available for a symbolic link", IDS_TITLE, MB_ICONINFORMATION);
return 0;
case REG_SZ:
case REG_EXPAND_SZ:
{
CStringValueDlg dlg(m_CurrentKey, item.Name, m_ReadOnly);
result = dlg.DoModal() == IDOK && dlg.IsModified();
if (result) {
auto hItem = m_Tree.GetSelectedItem();
DWORD type = dlg.GetType();
CString value = dlg.GetValue();
LONG size = (1 + value.GetLength()) * sizeof(WCHAR);
auto cmd = std::make_shared<ChangeValueCommand>(GetFullNodePath(hItem),
item.Name, type, (PVOID)(PCWSTR)value,size);
success = m_CmdMgr.AddCommand(cmd);
if (success) {
cmd->SetCallback(cb);
item.Value.Empty();
item.Size -= 1;
m_List.RedrawItems(index, index);
}
}
break;
}
case REG_MULTI_SZ:
{
CMultiStringValueDlg dlg(m_CurrentKey, item.Name, m_ReadOnly);
result = dlg.DoModal() == IDOK && dlg.IsModified();
if (result) {
auto hItem = m_Tree.GetSelectedItem();
auto value = dlg.GetValue();
// ������Ŀ���ַ������е���һ�ַ���ֱ��������һ��������Ŀ���ַ����Ӽ����ַ�Ϊֹ
value.TrimRight(L"\r\n");
value.Replace(L"\r\n", L"\n");
auto len = value.GetLength();
for (int i = 0; i < len; i++) {
if (value[i] == L'\n')
value.SetAt(i, 0);
}
auto cmd = std::make_shared<ChangeValueCommand>(
GetFullNodePath(hItem),item.Name,REG_MULTI_SZ,
(PVOID)(PCWSTR)value,
(1+len)*(LONG)sizeof(WCHAR));
success = m_CmdMgr.AddCommand(cmd);
if (success)
cmd->SetCallback(cb);
}
break;
}
case REG_DWORD:
case REG_QWORD:
{
CNumberValueDlg dlg(m_CurrentKey, item.Name, item.Type, m_ReadOnly);
result = dlg.DoModal() == IDOK && dlg.IsModified();
if (result) {
auto hItem = m_Tree.GetSelectedItem();
auto value = dlg.GetValue();
auto cmd = std::make_shared<ChangeValueCommand>(
GetFullNodePath(hItem), item.Name, item.Type, &value,
dlg.GetType() == REG_DWORD ? 4 : 8);
success = m_CmdMgr.AddCommand(cmd);
if (success)
cmd->SetCallback(cb);
}
break;
}
case REG_BINARY:
case REG_FULL_RESOURCE_DESCRIPTOR:
case REG_RESOURCE_REQUIREMENTS_LIST:
case REG_RESOURCE_LIST:
{
CBinaryValueDlg dlg(m_CurrentKey, item.Name, m_ReadOnly, this);
result = dlg.DoModal() == IDOK && dlg.IsModified();
if (result) {
auto hItem = m_Tree.GetSelectedItem();
auto cmd = std::make_shared<ChangeValueCommand>(
GetFullNodePath(hItem), item.Name, item.Type, (const PVOID)dlg.GetValue().data(),
(LONG)dlg.GetValue().size());
success = m_CmdMgr.AddCommand(cmd);
if (success) {
cmd->SetCallback(cb);
item.Size = (DWORD)dlg.GetValue().size();
}
}
break;
}
}
if (!result)
return 0;
if (!success)
DisplayError(L"Failed to changed value");
else {
item.Value.Empty();
auto index = m_List.GetSelectionMark();
m_List.RedrawItems(index, index);
}
return 0;
}
LRESULT CRegistryManagerView::OnImport(WORD, WORD, HWND, BOOL&) {
if (!SecurityHelper::EnablePrivilege(SE_BACKUP_NAME, true) ||
!SecurityHelper::EnablePrivilege(SE_RESTORE_NAME, true)) {
AtlMessageBox(m_hWnd, L"Exporting, importing, and loading hives require the Backup/Restore privileges. \
Running elevated will allow it.", IDS_TITLE, MB_ICONERROR);
return 0;
}
CSimpleFileDialog dlg(TRUE, L"dat", nullptr, OFN_FILEMUSTEXIST | OFN_ENABLESIZING | OFN_EXPLORER,
L"All Files\0*.*\0", m_hWnd);
if (dlg.DoModal() == IDOK) {
auto error = ::RegRestoreKey(m_CurrentKey.Get(), dlg.m_szFileName, REG_FORCE_RESTORE);
if (ERROR_SUCCESS != error) {
DisplayError(L"Failed to import file", nullptr, error);
}
else {
RefreshItem(m_Tree.GetSelectedItem());
}
}
SecurityHelper::EnablePrivilege(SE_BACKUP_NAME, false);
SecurityHelper::EnablePrivilege(SE_RESTORE_NAME, false);
return 0;
}
LRESULT CRegistryManagerView::OnExport(WORD, WORD, HWND, BOOL&) {
CExportDlg dlg;
dlg.SetKeyPath(GetFullNodePath(m_Tree.GetSelectedItem()));
if (dlg.DoModal() == IDOK) {
auto filename = dlg.GetFileName();
const auto& path = dlg.GetSelectedKey();
if (filename.Right(4).CompareNoCase(L".reg") == 0) {
CWaitCursor wait;
RegExportImport reg;
if (reg.Export(path, filename))
AtlMessageBox(m_hWnd, L"Export successful.", IDS_TITLE, MB_ICONINFORMATION);
else
AtlMessageBox(m_hWnd, L"Export failed.", IDS_TITLE, MB_ICONERROR);
return 0;
}
if (!SecurityHelper::EnablePrivilege(SE_BACKUP_NAME, true)) {
AtlMessageBox(m_hWnd, L"Exporting, importing, and loading hives require the Backup/Restore privileges. \
Running elevated will allow it.", IDS_TITLE, MB_ICONERROR);
return 0;
}
HKEY hKey;
if (path.IsEmpty())
hKey = Registry::OpenRealRegistryKey();
else {
auto key = Registry::OpenKey(path, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS);
hKey = key.Detach();
}
if (!hKey)
DisplayError(L"Failed to open key to export");
else {
LSTATUS error;
CWaitCursor wait;
::DeleteFile(dlg.GetFileName());
if (path == "HKEY_CLASSES_ROOT")
error = ::RegSaveKey(hKey, filename, nullptr);
else
error = ::RegSaveKeyEx(hKey, filename, nullptr, REG_LATEST_FORMAT);
::SetLastError(error);
if (error != ERROR_SUCCESS)
DisplayError(L"Failed to export key");
else
AtlMessageBox(m_hWnd, L"Export successful.", IDS_TITLE, MB_ICONINFORMATION);
SecurityHelper::EnablePrivilege(SE_BACKUP_NAME, false);
::RegCloseKey(hKey);
}
}
return 0;
}
LRESULT CRegistryManagerView::OnGotoKey(WORD, WORD, HWND, BOOL&) {
CGotoKeyDlg dlg;
dlg.SetKey(GetFullNodePath(m_Tree.GetSelectedItem()));
if (dlg.DoModal() == IDOK) {
CWaitCursor wait;
auto hItem = GotoKey(dlg.GetKey());
if(!hItem)
AtlMessageBox(m_hWnd, L"Failed to locate key", IDS_TITLE, MB_ICONERROR);
}
return 0;
}