# Regedit - a Registry Editor for Python import win32api, win32ui, win32con, commctrl from pywin.mfc import window, docview, dialog from . import hierlist import regutil import string 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()