Spaces:
Sleeping
Sleeping
# 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() | |