[python-win32] Context menu troubles
disclaimer: I have only the faintest idea what I'm doing! I'm trying to get a windows explorer context menu in my app. I can get the menu to show, but it does not execute any commands (e.g. 'copy') my code is based on http://bcbjournal.org/articles/vol4/0006/Using_the_shell_context_menu.htm and partly on http://netez.com/2xExplorer/shellFAQ/bas_context.html I'm new to both win32 and pywin32. Any help or advice will be readily accepted! Cheers! Chris. DesktopFolder = shell.SHGetDesktopFolder() if not DesktopFolder: raise Exception("Failed to get Desktop folder.") # Get a pidl for the folder the file # is located in. FilePath = 'J:\\' FileName = 'tree.xml' Eaten, ParentPidl, attr = DesktopFolder.ParseDisplayName(Handle, None, FilePath) # Get an IShellFolder for the folder # the file is located in. ParentFolder = DesktopFolder.BindToObject(ParentPidl, None, shell.IID_IShellFolder) CM_plus = None # Get a pidl for the file itself. Eaten, Pidl, attr = ParentFolder.ParseDisplayName(Handle, None, FileName) # Get the IContextMenu for the file. i, CM = ParentFolder.GetUIObjectOf(Handle, [Pidl], shell.IID_IContextMenu, 0) #else: # Get the IContextMenu for the folder. #i, CM = ParentFolder.GetUIObjectOf(Handle, [ParentPidl], shell.IID_IContextMenu, 0) if not CM: raise Exception("Unable to get context menu interface.") else: # try to obtain a higher level pointer, first 3 then 2 try: CM_plus = CM.QueryInterface(shell.IID_IContextMenu3, None) pcmType = 3 except Exception: try: CM_plus = CM.QueryInterface(shell.IID_IContextMenu2, None) pcmType = 2 except Exception: pass if CM_plus: CM.Release() # free initial "v1.0" interface CM = CM_plus else: # no higher version supported pcmType = 1 hMenu = win32gui.CreatePopupMenu() Flags = CMF_EXPLORE # Optionally the shell will show the extended # context menu on some operating systems when # the shift key is held down at the time the # context menu is invoked. The following is # commented out but you can uncommnent this # line to show the extended context menu. # Flags |= 0x0080; CM.QueryContextMenu(hMenu, 0, 1, 0x7FFF, Flags) # Show the menu. x, y = win32gui.GetCursorPos() flags = ( win32gui.TPM_LEFTALIGN | win32gui.TPM_LEFTBUTTON | win32gui.TPM_RIGHTBUTTON #| win32gui.TPM_RETURNCMD, ) hr = win32gui.TrackPopupMenu(hMenu, flags, x, y, 0, Handle, None) if hr != 1: e = win32api.GetLastError() s = win32api.FormatMessage(e) ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Context menu troubles
Thanks for reply Tim. I had decided not to use the command ID technique until I got things working, so TPM_RETURNCMD was commented out when I defines flags. From my understanding of MSDN and pywin32, this should make commands immediately execute and cause TrackPopupMenu to return an HRESULT? Also forgot to mention, using python3.2 32bit, pywon32 build 217 on windows 7 I've simplified/condensed it a bit, stripped comments and changed TrackPopupMenu return variable to something more appropriate. Chris. DesktopFolder = shell.SHGetDesktopFolder() if not DesktopFolder: raise Exception("Failed to get Desktop folder.") FilePath = 'J:\\' FileName = 'tree.xml' Eaten, ParentPidl, attr = DesktopFolder.ParseDisplayName(Handle, None, FilePath) ParentFolder = DesktopFolder.BindToObject(ParentPidl, None, shell.IID_IShellFolder) CM_plus = None Eaten, Pidl, attr = ParentFolder.ParseDisplayName(Handle, None, FileName) i, CM = ParentFolder.GetUIObjectOf(Handle, [Pidl], shell.IID_IContextMenu, 0) hMenu = win32gui.CreatePopupMenu() Flags = CMF_EXPLORE CM.QueryContextMenu(hMenu, 0, 1, 0x7FFF, Flags) x, y = win32gui.GetCursorPos() flags = win32gui.TPM_LEFTALIGN hr = win32gui.TrackPopupMenu(hMenu, flags, x, y, 0, Handle, None) if hr != 1: e = win32api.GetLastError() s = win32api.FormatMessage(e) #< "command completed successfully" On 02/03/2012 18:42, Tim Roberts wrote: Chris Ness wrote: disclaimer: I have only the faintest idea what I'm doing! I'm trying to get a windows explorer context menu in my app. I can get the menu to show, but it does not execute any commands (e.g. 'copy') Right, because you haven't told it to. You implemented the stuff form the articles pretty closely until the call to TrackPopupMenu, then you went awry. TrackPopupMenu does not actually return a boolean. It returns 0 if the call fails, but if the call succeeds, it returns the command ID of the menu item that was selected, and you have to tell the shell to go invoke that command. So, if it returns a value other than 0, you need to create a CMINVOKECOMMANDINFO structure, fill it in, and pass it to CM.InvokeCommand. That will trigger the real action. ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Context menu troubles
Also, the first article mentions OleInitialise(), which I tried but pythoncom.OleInitialise() does not exist in the module (AttributeError), despite what the docs say? Chris. ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Context menu troubles
Aah. It makes sense now. messages and such like. my lack of knowledge of win32 shows. I'll let you know how I get on. Am I right in thinking the win32 api is awfull? Chris. On 02/03/2012 20:16, Tim Roberts wrote: Chris Ness wrote: I had decided not to use the command ID technique until I got things working, so TPM_RETURNCMD was commented out when I defines flags. From my understanding of MSDN and pywin32, this should make commands immediately execute and cause TrackPopupMenu to return an HRESULT? Hmm, I should have read the doc more closely before I replied. My fault. I doesn't work quite that automatically. TrackPopupMenu is a general-purpose Windows API -- it doesn't have any connection to or knowledge of Windows Explorer, so it cannot force Explorer to take actions. If you don't specify TPM_RETURNCMD, then the final result of selecting a menu item will be that a WM_COMMAND message sent to your window. Your window doesn't know what to do with those command codes, so nothing useful will happen. In this particular case, I think you HAVE to use TPM_RETURNCMD. ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Context menu troubles
On 02/03/2012 20:16, Tim Roberts wrote: Chris Ness wrote: I had decided not to use the command ID technique until I got things working, so TPM_RETURNCMD was commented out when I defines flags. From my understanding of MSDN and pywin32, this should make commands immediately execute and cause TrackPopupMenu to return an HRESULT? Hmm, I should have read the doc more closely before I replied. My fault. I doesn't work quite that automatically. TrackPopupMenu is a general-purpose Windows API -- it doesn't have any connection to or knowledge of Windows Explorer, so it cannot force Explorer to take actions. If you don't specify TPM_RETURNCMD, then the final result of selecting a menu item will be that a WM_COMMAND message sent to your window. Your window doesn't know what to do with those command codes, so nothing useful will happen. In this particular case, I think you HAVE to use TPM_RETURNCMD. All seems to be working fine now. Thanks Tim. Learning a lot here. Having a spot of bother with the context menu for a drive though (e.g."C:"). I'm getting a very minimal menu with Open, Manage, Include in Library, Copy and Properties. Choosing proprties brings up Control Panel->System. Chris. def getContextMenu(filePath = 'J:', fileName = ''): hwnd = win32gui.GetForegroundWindow() # Get an IShellFolder for the desktop. desktopFolder = shell.SHGetDesktopFolder() if not desktopFolder: raise Exception("Failed to get Desktop folder.") # Get a pidl for the folder the file is located in. eaten, parentPidl, attr = desktopFolder.ParseDisplayName(hwnd, None, filePath) # Get an IShellFolder for the folder the file is located in. parentFolder = desktopFolder.BindToObject(parentPidl, None, shell.IID_IShellFolder) if fileName: # Get a pidl for the file itself. eaten, pidl, attr = parentFolder.ParseDisplayName(hwnd, None, fileName) # Get the IContextMenu for the file. i, contextMenu = parentFolder.GetUIObjectOf(hwnd, [pidl], shell.IID_IContextMenu, 0) else: i, contextMenu = desktopFolder.GetUIObjectOf(hwnd, [parentPidl], shell.IID_IContextMenu, 0) #<- where i attempt to get menu for a drive. contextMenu_plus = None if contextMenu: # try to obtain a higher level pointer, first 3 then 2 try: contextMenu_plus = contextMenu.QueryInterface(shell.IID_IContextMenu3, None) pcmType = 3 except Exception: try: contextMenu_plus = contextMenu.QueryInterface(shell.IID_IContextMenu2, None) pcmType = 2 except Exception: pass else: raise Exception("Unable to get context menu interface.") if contextMenu_plus: contextMenu.Release() # free initial "v1.0" interface contextMenu = contextMenu_plus else: # no higher version supported pcmType = 1 hMenu = win32gui.CreatePopupMenu() MIN_SHELL_ID = 1 MAX_SHELL_ID = 3 # Flags |= 0x0080; #to show the extended context menu. contextMenu.QueryContextMenu(hMenu, 0, MIN_SHELL_ID, MAX_SHELL_ID, CMF_EXPLORE) x, y = win32gui.GetCursorPos() flags = win32gui.TPM_LEFTALIGN | win32gui.TPM_RETURNCMD #| win32gui.TPM_LEFTBUTTON | win32gui.TPM_RIGHTBUTTON cmd = win32gui.TrackPopupMenu(hMenu, flags, x, y, 0, hwnd, None) if not cmd: e = win32api.GetLastError() if e: s = win32api.FormatMessage(e) raise Exception(s) CI = ( 0, #Mask hwnd, #hwnd cmd - MIN_SHELL_ID, #Verb '', #Parameters '', #Directory SW_SHOWNORMAL, #Show 0, #HotKey None#Icon ) contextMenu.InvokeCommand(CI) ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
[python-win32] Win7 explorer "include in library" submenu
I'm trying to replicate the win 7 explorer context menu on the fly. All works well apart from the "Include in Library" submenu, which shows one greyed out entry: "retrieving libraries...". Well it's not retrieving anything because the code to read the menus has returned! Here is my code that reads the menu entries... def __getMenuItems(hMenu, contextMenu): num_items = win32gui.GetMenuItemCount(hMenu) rval = [] for i in range(num_items): mi = EmptyMENUITEMINFO() win32gui.GetMenuItemInfo(hMenu, i, True, mi[0]) item = UnpackMENUITEMINFO(mi[0]) fType, fState, wID, hSubMenu, hbmpChecked, hbmpUnchecked, dwItemData, text, hbmpItem = item if hSubMenu: hSubMenu = win32gui.GetSubMenu(hMenu, i) rval.append((__getMenuItems(hSubMenu, contextMenu), text)) else: rval.append((wID, text)) return rval I have no idea what to do and google is no help. Do I need to initiate something? Wait for something? Any help much appreciated! chris ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32