387 lines
13 KiB
Python
387 lines
13 KiB
Python
# Regedit - a Registry Editor for Python
|
|
|
|
import commctrl
|
|
import regutil
|
|
import win32api
|
|
import win32con
|
|
import win32ui
|
|
from pywin.mfc import dialog, docview, window
|
|
|
|
from . import hierlist
|
|
|
|
|
|
def SafeApply(fn, args, err_desc=""):
|
|
try:
|
|
fn(*args)
|
|
return 1
|
|
except win32api.error as exc:
|
|
msg = "Error " + err_desc + "\r\n\r\n" + exc.strerror
|
|
win32ui.MessageBox(msg)
|
|
return 0
|
|
|
|
|
|
class SplitterFrame(window.MDIChildWnd):
|
|
def __init__(self):
|
|
# call base CreateFrame
|
|
self.images = None
|
|
window.MDIChildWnd.__init__(self)
|
|
|
|
def OnCreateClient(self, cp, context):
|
|
splitter = win32ui.CreateSplitter()
|
|
doc = context.doc
|
|
frame_rect = self.GetWindowRect()
|
|
size = ((frame_rect[2] - frame_rect[0]), (frame_rect[3] - frame_rect[1]) // 2)
|
|
sub_size = (size[0] // 3, size[1])
|
|
splitter.CreateStatic(self, 1, 2)
|
|
# CTreeControl view
|
|
self.keysview = RegistryTreeView(doc)
|
|
# CListControl view
|
|
self.valuesview = RegistryValueView(doc)
|
|
|
|
splitter.CreatePane(self.keysview, 0, 0, (sub_size))
|
|
splitter.CreatePane(self.valuesview, 0, 1, (0, 0)) # size ignored.
|
|
splitter.SetRowInfo(0, size[1], 0)
|
|
# Setup items in the imagelist
|
|
|
|
return 1
|
|
|
|
def OnItemDoubleClick(self, info, extra):
|
|
(hwndFrom, idFrom, code) = info
|
|
if idFrom == win32ui.AFX_IDW_PANE_FIRST:
|
|
# Tree control
|
|
return None
|
|
elif idFrom == win32ui.AFX_IDW_PANE_FIRST + 1:
|
|
item = self.keysview.SelectedItem()
|
|
self.valuesview.EditValue(item)
|
|
return 0
|
|
# List control
|
|
else:
|
|
return None # Pass it on
|
|
|
|
def PerformItemSelected(self, item):
|
|
return self.valuesview.UpdateForRegItem(item)
|
|
|
|
def OnDestroy(self, msg):
|
|
window.MDIChildWnd.OnDestroy(self, msg)
|
|
if self.images:
|
|
self.images.DeleteImageList()
|
|
self.images = None
|
|
|
|
|
|
class RegistryTreeView(docview.TreeView):
|
|
def OnInitialUpdate(self):
|
|
rc = self._obj_.OnInitialUpdate()
|
|
self.frame = self.GetParent().GetParent()
|
|
self.hierList = hierlist.HierListWithItems(
|
|
self.GetHLIRoot(), win32ui.IDB_HIERFOLDERS, win32ui.AFX_IDW_PANE_FIRST
|
|
)
|
|
self.hierList.HierInit(self.frame, self.GetTreeCtrl())
|
|
self.hierList.SetStyle(
|
|
commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS
|
|
)
|
|
self.hierList.PerformItemSelected = self.PerformItemSelected
|
|
|
|
self.frame.HookNotify(self.frame.OnItemDoubleClick, commctrl.NM_DBLCLK)
|
|
self.frame.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK)
|
|
|
|
# self.HookMessage(self.OnItemRightClick, win32con.WM_RBUTTONUP)
|
|
|
|
def GetHLIRoot(self):
|
|
doc = self.GetDocument()
|
|
regroot = doc.root
|
|
subkey = doc.subkey
|
|
return HLIRegistryKey(regroot, subkey, "Root")
|
|
|
|
def OnItemRightClick(self, notify_data, extra):
|
|
# First select the item we right-clicked on.
|
|
pt = self.ScreenToClient(win32api.GetCursorPos())
|
|
flags, hItem = self.HitTest(pt)
|
|
if hItem == 0 or commctrl.TVHT_ONITEM & flags == 0:
|
|
return None
|
|
self.Select(hItem, commctrl.TVGN_CARET)
|
|
|
|
menu = win32ui.CreatePopupMenu()
|
|
menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1000, "Add Key")
|
|
menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1001, "Add Value")
|
|
menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1002, "Delete Key")
|
|
self.HookCommand(self.OnAddKey, 1000)
|
|
self.HookCommand(self.OnAddValue, 1001)
|
|
self.HookCommand(self.OnDeleteKey, 1002)
|
|
menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position.
|
|
return None
|
|
|
|
def OnDeleteKey(self, command, code):
|
|
hitem = self.hierList.GetSelectedItem()
|
|
item = self.hierList.ItemFromHandle(hitem)
|
|
msg = "Are you sure you wish to delete the key '%s'?" % (item.keyName,)
|
|
id = win32ui.MessageBox(msg, None, win32con.MB_YESNO)
|
|
if id != win32con.IDYES:
|
|
return
|
|
if SafeApply(
|
|
win32api.RegDeleteKey, (item.keyRoot, item.keyName), "deleting registry key"
|
|
):
|
|
# Get the items parent.
|
|
try:
|
|
hparent = self.GetParentItem(hitem)
|
|
except win32ui.error:
|
|
hparent = None
|
|
self.hierList.Refresh(hparent)
|
|
|
|
def OnAddKey(self, command, code):
|
|
from pywin.mfc import dialog
|
|
|
|
val = dialog.GetSimpleInput("New key name", "", "Add new key")
|
|
if val is None:
|
|
return # cancelled.
|
|
hitem = self.hierList.GetSelectedItem()
|
|
item = self.hierList.ItemFromHandle(hitem)
|
|
if SafeApply(win32api.RegCreateKey, (item.keyRoot, item.keyName + "\\" + val)):
|
|
self.hierList.Refresh(hitem)
|
|
|
|
def OnAddValue(self, command, code):
|
|
from pywin.mfc import dialog
|
|
|
|
val = dialog.GetSimpleInput("New value", "", "Add new value")
|
|
if val is None:
|
|
return # cancelled.
|
|
hitem = self.hierList.GetSelectedItem()
|
|
item = self.hierList.ItemFromHandle(hitem)
|
|
if SafeApply(
|
|
win32api.RegSetValue, (item.keyRoot, item.keyName, win32con.REG_SZ, val)
|
|
):
|
|
# Simply re-select the current item to refresh the right spitter.
|
|
self.PerformItemSelected(item)
|
|
|
|
# self.Select(hitem, commctrl.TVGN_CARET)
|
|
|
|
def PerformItemSelected(self, item):
|
|
return self.frame.PerformItemSelected(item)
|
|
|
|
def SelectedItem(self):
|
|
return self.hierList.ItemFromHandle(self.hierList.GetSelectedItem())
|
|
|
|
def SearchSelectedItem(self):
|
|
handle = self.hierList.GetChildItem(0)
|
|
while 1:
|
|
# print "State is", self.hierList.GetItemState(handle, -1)
|
|
if self.hierList.GetItemState(handle, commctrl.TVIS_SELECTED):
|
|
# print "Item is ", self.hierList.ItemFromHandle(handle)
|
|
return self.hierList.ItemFromHandle(handle)
|
|
handle = self.hierList.GetNextSiblingItem(handle)
|
|
|
|
|
|
class RegistryValueView(docview.ListView):
|
|
def OnInitialUpdate(self):
|
|
hwnd = self._obj_.GetSafeHwnd()
|
|
style = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
|
|
win32api.SetWindowLong(
|
|
hwnd,
|
|
win32con.GWL_STYLE,
|
|
(style & ~commctrl.LVS_TYPEMASK) | commctrl.LVS_REPORT,
|
|
)
|
|
|
|
itemDetails = (commctrl.LVCFMT_LEFT, 100, "Name", 0)
|
|
self.InsertColumn(0, itemDetails)
|
|
itemDetails = (commctrl.LVCFMT_LEFT, 500, "Data", 0)
|
|
self.InsertColumn(1, itemDetails)
|
|
|
|
def UpdateForRegItem(self, item):
|
|
self.DeleteAllItems()
|
|
hkey = win32api.RegOpenKey(item.keyRoot, item.keyName)
|
|
try:
|
|
valNum = 0
|
|
ret = []
|
|
while 1:
|
|
try:
|
|
res = win32api.RegEnumValue(hkey, valNum)
|
|
except win32api.error:
|
|
break
|
|
name = res[0]
|
|
if not name:
|
|
name = "(Default)"
|
|
self.InsertItem(valNum, name)
|
|
self.SetItemText(valNum, 1, str(res[1]))
|
|
valNum = valNum + 1
|
|
finally:
|
|
win32api.RegCloseKey(hkey)
|
|
|
|
def EditValue(self, item):
|
|
# Edit the current value
|
|
class EditDialog(dialog.Dialog):
|
|
def __init__(self, item):
|
|
self.item = item
|
|
dialog.Dialog.__init__(self, win32ui.IDD_LARGE_EDIT)
|
|
|
|
def OnInitDialog(self):
|
|
self.SetWindowText("Enter new value")
|
|
self.GetDlgItem(win32con.IDCANCEL).ShowWindow(win32con.SW_SHOW)
|
|
self.edit = self.GetDlgItem(win32ui.IDC_EDIT1)
|
|
# Modify the edit windows style
|
|
style = win32api.GetWindowLong(
|
|
self.edit.GetSafeHwnd(), win32con.GWL_STYLE
|
|
)
|
|
style = style & (~win32con.ES_WANTRETURN)
|
|
win32api.SetWindowLong(
|
|
self.edit.GetSafeHwnd(), win32con.GWL_STYLE, style
|
|
)
|
|
self.edit.SetWindowText(str(self.item))
|
|
self.edit.SetSel(-1)
|
|
return dialog.Dialog.OnInitDialog(self)
|
|
|
|
def OnDestroy(self, msg):
|
|
self.newvalue = self.edit.GetWindowText()
|
|
|
|
try:
|
|
index = self.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
except win32ui.error:
|
|
return # No item selected.
|
|
|
|
if index == 0:
|
|
keyVal = ""
|
|
else:
|
|
keyVal = self.GetItemText(index, 0)
|
|
# Query for a new value.
|
|
try:
|
|
newVal = self.GetItemsCurrentValue(item, keyVal)
|
|
except TypeError as details:
|
|
win32ui.MessageBox(details)
|
|
return
|
|
|
|
d = EditDialog(newVal)
|
|
if d.DoModal() == win32con.IDOK:
|
|
try:
|
|
self.SetItemsCurrentValue(item, keyVal, d.newvalue)
|
|
except win32api.error as exc:
|
|
win32ui.MessageBox("Error setting value\r\n\n%s" % exc.strerror)
|
|
self.UpdateForRegItem(item)
|
|
|
|
def GetItemsCurrentValue(self, item, valueName):
|
|
hkey = win32api.RegOpenKey(item.keyRoot, item.keyName)
|
|
try:
|
|
val, type = win32api.RegQueryValueEx(hkey, valueName)
|
|
if type != win32con.REG_SZ:
|
|
raise TypeError("Only strings can be edited")
|
|
return val
|
|
finally:
|
|
win32api.RegCloseKey(hkey)
|
|
|
|
def SetItemsCurrentValue(self, item, valueName, value):
|
|
# ** Assumes already checked is a string.
|
|
hkey = win32api.RegOpenKey(
|
|
item.keyRoot, item.keyName, 0, win32con.KEY_SET_VALUE
|
|
)
|
|
try:
|
|
win32api.RegSetValueEx(hkey, valueName, 0, win32con.REG_SZ, value)
|
|
finally:
|
|
win32api.RegCloseKey(hkey)
|
|
|
|
|
|
class RegTemplate(docview.DocTemplate):
|
|
def __init__(self):
|
|
docview.DocTemplate.__init__(
|
|
self, win32ui.IDR_PYTHONTYPE, None, SplitterFrame, None
|
|
)
|
|
|
|
# def InitialUpdateFrame(self, frame, doc, makeVisible=1):
|
|
# self._obj_.InitialUpdateFrame(frame, doc, makeVisible) # call default handler.
|
|
# frame.InitialUpdateFrame(doc, makeVisible)
|
|
|
|
def OpenRegistryKey(
|
|
self, root=None, subkey=None
|
|
): # Use this instead of OpenDocumentFile.
|
|
# Look for existing open document
|
|
if root is None:
|
|
root = regutil.GetRootKey()
|
|
if subkey is None:
|
|
subkey = regutil.BuildDefaultPythonKey()
|
|
for doc in self.GetDocumentList():
|
|
if doc.root == root and doc.subkey == subkey:
|
|
doc.GetFirstView().ActivateFrame()
|
|
return doc
|
|
# not found - new one.
|
|
doc = RegDocument(self, root, subkey)
|
|
frame = self.CreateNewFrame(doc)
|
|
doc.OnNewDocument()
|
|
self.InitialUpdateFrame(frame, doc, 1)
|
|
return doc
|
|
|
|
|
|
class RegDocument(docview.Document):
|
|
def __init__(self, template, root, subkey):
|
|
docview.Document.__init__(self, template)
|
|
self.root = root
|
|
self.subkey = subkey
|
|
self.SetTitle("Registry Editor: " + subkey)
|
|
|
|
def OnOpenDocument(self, name):
|
|
raise TypeError("This template can not open files")
|
|
return 0
|
|
|
|
|
|
class HLIRegistryKey(hierlist.HierListItem):
|
|
def __init__(self, keyRoot, keyName, userName):
|
|
self.keyRoot = keyRoot
|
|
self.keyName = keyName
|
|
self.userName = userName
|
|
hierlist.HierListItem.__init__(self)
|
|
|
|
def __lt__(self, other):
|
|
return self.name < other.name
|
|
|
|
def __eq__(self, other):
|
|
return (
|
|
self.keyRoot == other.keyRoot
|
|
and self.keyName == other.keyName
|
|
and self.userName == other.userName
|
|
)
|
|
|
|
def __repr__(self):
|
|
return "<%s with root=%s, key=%s>" % (
|
|
self.__class__.__name__,
|
|
self.keyRoot,
|
|
self.keyName,
|
|
)
|
|
|
|
def GetText(self):
|
|
return self.userName
|
|
|
|
def IsExpandable(self):
|
|
# All keys are expandable, even if they currently have zero children.
|
|
return 1
|
|
|
|
## hkey = win32api.RegOpenKey(self.keyRoot, self.keyName)
|
|
## try:
|
|
## keys, vals, dt = win32api.RegQueryInfoKey(hkey)
|
|
## return (keys>0)
|
|
## finally:
|
|
## win32api.RegCloseKey(hkey)
|
|
|
|
def GetSubList(self):
|
|
hkey = win32api.RegOpenKey(self.keyRoot, self.keyName)
|
|
win32ui.DoWaitCursor(1)
|
|
try:
|
|
keyNum = 0
|
|
ret = []
|
|
while 1:
|
|
try:
|
|
key = win32api.RegEnumKey(hkey, keyNum)
|
|
except win32api.error:
|
|
break
|
|
ret.append(HLIRegistryKey(self.keyRoot, self.keyName + "\\" + key, key))
|
|
keyNum = keyNum + 1
|
|
finally:
|
|
win32api.RegCloseKey(hkey)
|
|
win32ui.DoWaitCursor(0)
|
|
return ret
|
|
|
|
|
|
template = RegTemplate()
|
|
|
|
|
|
def EditRegistry(root=None, key=None):
|
|
doc = template.OpenRegistryKey(root, key)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
EditRegistry()
|