# help.py - help utilities for PythonWin. import os import regutil import win32api import win32con import win32ui htmlhelp_handle = None html_help_command_translators = { win32con.HELP_CONTENTS: 1, # HH_DISPLAY_TOC win32con.HELP_CONTEXT: 15, # HH_HELP_CONTEXT win32con.HELP_FINDER: 1, # HH_DISPLAY_TOC } def FinalizeHelp(): global htmlhelp_handle if htmlhelp_handle is not None: import win32help try: # frame = win32ui.GetMainFrame().GetSafeHwnd() frame = 0 win32help.HtmlHelp(frame, None, win32help.HH_UNINITIALIZE, htmlhelp_handle) except win32help.error: print("Failed to finalize htmlhelp!") htmlhelp_handle = None def OpenHelpFile(fileName, helpCmd=None, helpArg=None): "Open a help file, given a full path" # default help arg. win32ui.DoWaitCursor(1) try: if helpCmd is None: helpCmd = win32con.HELP_CONTENTS ext = os.path.splitext(fileName)[1].lower() if ext == ".hlp": win32api.WinHelp( win32ui.GetMainFrame().GetSafeHwnd(), fileName, helpCmd, helpArg ) # XXX - using the htmlhelp API wreaks havoc with keyboard shortcuts # so we disable it, forcing ShellExecute, which works fine (but # doesn't close the help file when Pythonwin is closed. # Tom Heller also points out http://www.microsoft.com/mind/0499/faq/faq0499.asp, # which may or may not be related. elif 0 and ext == ".chm": import win32help global htmlhelp_handle helpCmd = html_help_command_translators.get(helpCmd, helpCmd) # frame = win32ui.GetMainFrame().GetSafeHwnd() frame = 0 # Dont want it overlapping ours! if htmlhelp_handle is None: htmlhelp_hwnd, htmlhelp_handle = win32help.HtmlHelp( frame, None, win32help.HH_INITIALIZE ) win32help.HtmlHelp(frame, fileName, helpCmd, helpArg) else: # Hope that the extension is registered, and we know what to do! win32api.ShellExecute(0, "open", fileName, None, "", win32con.SW_SHOW) return fileName finally: win32ui.DoWaitCursor(-1) def ListAllHelpFiles(): ret = [] ret = _ListAllHelpFilesInRoot(win32con.HKEY_LOCAL_MACHINE) # Ensure we don't get dups. for item in _ListAllHelpFilesInRoot(win32con.HKEY_CURRENT_USER): if item not in ret: ret.append(item) return ret def _ListAllHelpFilesInRoot(root): """Returns a list of (helpDesc, helpFname) for all registered help files""" import regutil retList = [] try: key = win32api.RegOpenKey( root, regutil.BuildDefaultPythonKey() + "\\Help", 0, win32con.KEY_READ ) except win32api.error as exc: import winerror if exc.winerror != winerror.ERROR_FILE_NOT_FOUND: raise return retList try: keyNo = 0 while 1: try: helpDesc = win32api.RegEnumKey(key, keyNo) helpFile = win32api.RegQueryValue(key, helpDesc) retList.append((helpDesc, helpFile)) keyNo = keyNo + 1 except win32api.error as exc: import winerror if exc.winerror != winerror.ERROR_NO_MORE_ITEMS: raise break finally: win32api.RegCloseKey(key) return retList def SelectAndRunHelpFile(): from pywin.dialogs import list helpFiles = ListAllHelpFiles() if len(helpFiles) == 1: # only 1 help file registered - probably ours - no point asking index = 0 else: index = list.SelectFromLists("Select Help file", helpFiles, ["Title"]) if index is not None: OpenHelpFile(helpFiles[index][1]) helpIDMap = None def SetHelpMenuOtherHelp(mainMenu): """Modifies the main Help Menu to handle all registered help files. mainMenu -- The main menu to modify - usually from docTemplate.GetSharedMenu() """ # Load all help files from the registry. global helpIDMap if helpIDMap is None: helpIDMap = {} cmdID = win32ui.ID_HELP_OTHER excludeList = ["Main Python Documentation", "Pythonwin Reference"] firstList = ListAllHelpFiles() # We actually want to not only exclude these entries, but # their help file names (as many entries may share the same name) excludeFnames = [] for desc, fname in firstList: if desc in excludeList: excludeFnames.append(fname) helpDescs = [] for desc, fname in firstList: if fname not in excludeFnames: helpIDMap[cmdID] = (desc, fname) win32ui.GetMainFrame().HookCommand(HandleHelpOtherCommand, cmdID) cmdID = cmdID + 1 helpMenu = mainMenu.GetSubMenu( mainMenu.GetMenuItemCount() - 1 ) # Help menu always last. otherHelpMenuPos = 2 # cant search for ID, as sub-menu has no ID. otherMenu = helpMenu.GetSubMenu(otherHelpMenuPos) while otherMenu.GetMenuItemCount(): otherMenu.DeleteMenu(0, win32con.MF_BYPOSITION) if helpIDMap: for id, (desc, fname) in helpIDMap.items(): otherMenu.AppendMenu(win32con.MF_ENABLED | win32con.MF_STRING, id, desc) else: helpMenu.EnableMenuItem( otherHelpMenuPos, win32con.MF_BYPOSITION | win32con.MF_GRAYED ) def HandleHelpOtherCommand(cmd, code): OpenHelpFile(helpIDMap[cmd][1])