AutoHotkey Community

It is currently May 26th, 2012, 9:51 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 62 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
 Post subject:
PostPosted: May 26th, 2009, 2:34 pm 
sorry for a no0b question
I know this script is useful but how exactly do I use it?
I mean I know extract the file and run it,
but it shows the context menu only once, per time I launch the script?

is there any key to launch the context menu?
and how is this better than the regular context menu?

please reply.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: May 26th, 2009, 2:53 pm 
Offline

Joined: May 16th, 2009, 4:15 pm
Posts: 18
Location: TW
Anonymous wrote:
... how exactly do I use it? ...

Trigger from hotkey, or as a portion of a large script ....
Do not limit your imagination (and also innovation)

Anonymous wrote:
...how is this better than the regular context menu?

the ContextMenu is registed under your AutoHotKey thread, thus you can do some pre-process and/or post-process as you like.

inspired from this, I make a varient that get and invoke menu items without bring up popup menu

I will show that in next post

_________________
Eucaly61's DIY World (Mainly in Chinese)
http://eucaly61.blogspot.com/search/label/AutoHotKey


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 26th, 2009, 3:38 pm 
Offline

Joined: May 16th, 2009, 4:15 pm
Posts: 18
Location: TW
.
below is the demo code to get and invoke ContextMenu (ShellEx) items without bring up popup menu

(dependency: CoHelper.ahk)

Code:
#SingleInstance Force
SetBatchLines,-1

#Include CoHelper.ahk

; FileName : ShellExt-Demo-008.ahk

sIId = {000214E4-0000-0000-C000-000000000046}   ; IContextMenu

;sDll := "igfxpph.dll"
sClsId1 = {3AB1675A-CCFF-11D2-8B20-00A0C93CB1F4} igfx Shellext

;sDll := "wmpshell.dll"
sClsId2 = {F1B9284F-E9DC-4e68-9D7E-42362A59F0FD} add to playlist
; => could see menu, but did not try more details

;sDll := "shdocvw.dll"
sClsId3 = {2559a1f0-21d7-11d4-bdaf-00c04f60b9f0} findfiles

;sDll := "shdocvw.dll"
sClsId4 = {2559a1f1-21d7-11d4-bdaf-00c04f60b9f0} help

;sDll := "SHELL32.dll"
sClsId5 = {D969A300-E7FF-11d0-A93B-00A0C90F2719} New ...
; => not able to explore 2nd level, maybe it's context sensitive

sClsId6 = {7BA4C740-9E81-11CF-99D3-00AA004AE837} send-to
; => not able to explore 2nd level, maybe it's context sensitive

; You could add more CLSID (clsid7, 8, 9 and so on),
   ; only those enclosed by {...} are recognized as CLSID

Gui, Font, S12
Gui, Add, ListBox, w500 r10 vClsIdList
Gui, Add, Button, ,Go

lst=
Loop
{
   if !sClsId%A_index%
      break
   lst .= "|" . sClsId%A_index%
}

GuiControl,, ClsIdList, %lst%
Gui, SHow
return

GuiClose:
   ExitApp

ButtonGo:
   Gui, Submit, noHide
   p1 := RegExMatch(ClsIdList,"(?P<ClsId>\{[^\}]*\})",s)

   if !p1
      return

   Critical
   CoInitialize()

   pcm := CreateObject(sClsId,sIId)
   if !pcm
      return

l := ClsIdList . "`n`n"

   hMenu := DllCall("CreatePopupMenu")
   DllCall(VTable(pcm,3), "Uint", pcm
         ,"Uint", hMenu, "Uint", 0
         , "Uint", 3, "Uint", 0x7FFF, "Uint", 0)   ; QueryContextMenu

l .= "idx / idn / MenuItem / hSubMenu`n"
l .= "========================================`n"

   Loop, % DllCall( "GetMenuItemCount", UInt,hMenu ) {
      idx := A_Index-1
      idn := DllCall( "GetMenuItemID", UInt,hMenu, Int,idx )
      nSize := DllCall( "GetMenuString"
            , UInt,hMenu, Int,idx, Int,0, Int,0, UInt,0x400 ) + 1
      VarSetCapacity( mStr,nSize )
      DllCall( "GetMenuString"
             , UInt,hMenu, Int,idx, Str,mStr, Int,nSize, UInt,0x400 )

      hSub := DllCall("GetSubMenu",Uint,hMenu,int,idx)

l .= idx . " / " . idn . " / " . mstr . " / " . hSub . "`n"

      if hSub
      {
l .= "--------------------`n"
         Loop, % DllCall( "GetMenuItemCount", UInt,hSub ) {
            idx := A_Index-1
            idn := DllCall( "GetMenuItemID", UInt,hSub, Int,idx )
            nSize := DllCall( "GetMenuString"
                  , UInt,hSub, Int,idx, Int,0, Int,0, UInt,0x400 ) + 1
            VarSetCapacity( mStr1,nSize )
            DllCall( "GetMenuString"
                , UInt,hSub, Int,idx, Str,mStr1, Int,nSize, UInt,0x400 )

            hSub1 := DllCall("GetSubMenu",Uint,hSub,int,idx)
      
l .= "[" . idx . "] / " . idn . " / " . mstr . " -- " . mstr1 . " / " . hSub1 . "`n"
         }
l .= "--------------------`n"
      }
   }

msgbox, % l


; implement below to invoke menu command with given idn
if (0) {
   DetectHiddenWindows, On
   Process, Exist
   WinGet, hAHK, ID, ahk_pid %ErrorLevel%

;   idn := .....

   DllCall("GetCursorPos", "int64P", pt)

   NumPut(VarSetCapacity(ici,64,0),ici), NumPut(0x4000|0x20000000,ici,4), NumPut(1,NumPut(hAHK,ici,8),12), NumPut(idn-3,NumPut(idn-3,ici,12),24), NumPut(pt,ici,56,"int64")

   DllCall(VTable(pcm,4), "Uint", pcm, "Uint", &ici)   ; InvokeCommand
}

   DllCall("DestroyMenu", "Uint", hMenu)
   Release(pcm)
   CoUninitialize()
   Critical, Off
   return


Thanks for the suggestion from Sean, now DllGetClassObject (the first two lines)
Eucaly61 wrote:
Code:
* DllGetClassObject with IID_IClassFactory
* pcm := CreateInstance with "{000214E4-0000-0000-C000-000000000046}"   ; IContextMenu

* hMenu := DllCall("CreatePopupMenu")

are replaced by
Code:
pcm := CreateObject(CLSID,IID)


more shellex (or contextmenu) related CLSID and DLL could be found under below registry key
Code:
HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers
HKEY_CLASSES_ROOT\{file type or CLSID}\shellex\ContextMenuHandlers
HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers
HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers

or even more in http://windowsxp.mvps.org/context_folde ... irectories
.
.
as for the magic number
Code:
DllCall(NumGet(NumGet(1*psf)+32) ...
DllCall(NumGet(NumGet(1*psf)+40) ...

Sean wrote:
... have to refer to header files for that. In this case of IShellFolder, for example, the infos are contained in ShObjIdl.h and/or ShObjIdl.idl.

There are on-line document to refer (for example,
Quote:
CreateViewObject and GetUIObjectOf under interface IShellFolder : IUnknown
or QueryContextMenu under interface IContextMenu : IUnknown

or
Quote:
http://www.koders.com/noncode/fid66A0E1FAB1C94FB665CFA5236DA4CDAEA22742CE.aspx#L1051

_________________
Eucaly61's DIY World (Mainly in Chinese)
http://eucaly61.blogspot.com/search/label/AutoHotKey


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 26th, 2009, 3:47 pm 
Offline

Joined: May 16th, 2009, 4:15 pm
Posts: 18
Location: TW
I don't do further study, but I guess this would be helpful if some CLSID / DLL are not registed in registry key

that is, directly DllGetClassObject from DLL,

you could replace
Code:
   pcm := CreateObject(sClsId,sIId)

with
Code:
sDll := "some.dll"
If (GUID4String(sbinClassId, sClsId) And GUID4String(sbinIId, sIId))
   pcm := COM_CreateInstanceFromDll(sDll,sbinClassId,sbinIId)
else
   return

and, add below function define (a subset modified from ws4ahk.ahk)
Code:
COM_CreateInstanceFromDll(sDll, ByRef sbinClassId, ByRef sbinIId)
{
   static IID_IClassFactory := "{00000001-0000-0000-C000-000000000046}"

   if (!GUID4String(sbinIID_IClassFactory, IID_IClassFactory))
      return
   
   If (!Unicode4Ansi(wsDll, sDll))
      return       

   hDll := DllCall("ole32\CoLoadLibrary", "Str", wsDll, "Int", 1, "UInt")

   If (ErrorLevel <> 0) or (hDll = 0)
      Return

   iErr := DllCall(sDll . "\DllGetClassObject"
               ,"Str" , sbinClassId
               ,"Str" , sbinIID_IClassFactory
               ,"UInt*", pIFactory
               ,"Int")
   If iErr
      Return
   
   iObjPtr := COM_IClassFactory_CreateInstance(pIFactory, 0, sbinIId)
   
   Release (pIFactory)
   
   Return iObjPtr
}


COM_IClassFactory_CreateInstance(ppvIClassFactory, pUnkOuter, ByRef riid)
{
   iErr := DllCall(VTable(ppvIClassFactory, 3), "UInt", ppvIClassFactory
               , "UInt",  pUnkOuter
               , "Str",   riid
               , "Uint*", ppvObject
               , "Int")
   
   If iErr
      Return
   
   Return ppvObject
}

_________________
Eucaly61's DIY World (Mainly in Chinese)
http://eucaly61.blogspot.com/search/label/AutoHotKey


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 26th, 2009, 11:12 pm 
@Eucaly61

I really appriciate that you cared to reply.
however I'm yet confused,
I tried to add ^1:: as hotkey but it gives me error. that { is not complete.

all I want is
say when my mouse has selected a file / folder
and I press something like tilde key or Insert key then
it launches this Sean's Context Menu for that file/folder
how do I do it?

Thanks in Advance


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: May 27th, 2009, 5:42 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Eucaly61 wrote:
below is the demo code to get and invoke ContextMenu (ShellEx) items without bring up popup menu
Nice. Although I suppose it still may not be able to retrieve all the items of some submenus without bring up the pop-up menu, it can be used as an extension of InvokeVerb through COM. BTW, the GetMenu routine is familiar to me.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 29th, 2009, 8:24 pm 
Offline

Joined: April 28th, 2008, 2:55 pm
Posts: 48
Thanks for the information on getting and executing menu selections. I have been looking for this for awhile.

I am able to bring up the shell context menu for a file or a folder and execute the command with just a few problems.

I am unable to iterate through the "Send To" or the "Open With" submenus. I can get a handle to the submenu, but they don't appear to be populated.

When I select copy, the file is not being copied into the clipboard (appears that nothing happens as the clipboard has the text from before selecting that option).

I'm going to post my code as a reference for others:

The "menu" variable that I am using is for my own menu handling - hope it is not too confusing.

Code:
ShellContextMenu(menu, fileName) {

   CoInitialize()

   DllCall("shell32\SHParseDisplayName", "Uint", Unicode4Ansi(wPath,fileName)
      , "Uint", 0, "UintP", pidl, "Uint", 0, "Uint", 0)

   DllCall("shell32\SHBindToParent", "Uint", pidl
      , "Uint", GUID4String(IID_IShellFolder,"{000214E6-0000-0000-C000-000000000046}")
      , "UintP", psf, "UintP", pidlChild)
   DllCall(NumGet(NumGet(1*psf)+40), "Uint", psf
      , "Uint", 0, "Uint", 1, "UintP", pidlChild
      , "Uint", GUID4String(IID_IContextMenu,"{000214E4-0000-0000-C000-000000000046}")
      , "Uint", 0, "UintP", pcm)

   Release(psf)
   CoTaskMemFree(pidl)

   ; Create a stub menu
   hMenu := DllCall("CreatePopupMenu")

   ; Get the context menu
   DllCall(NumGet(NumGet(1*pcm)+12), "Uint", pcm, "Uint", hMenu, "Uint", menuNo, "Uint", 3, "Uint", 0x7FFF, "Uint", 0)

   menuAddSeparator(menu)
   addMenuEntries(hMenu, menu, fileName)
}

addMenuEntries(hMenu, menu, fileName) {

   Loop, % DllCall( "GetMenuItemCount", UInt,hMenu ) {
   
      idx := A_Index-1
      idn := DllCall( "GetMenuItemID", UInt,hMenu, Int,idx )
      nSize := DllCall( "GetMenuString"
              , UInt,hMenu, Int,idx, Int,0, Int,0, UInt,0x400 ) + 1
      VarSetCapacity( mStr,nSize )
      DllCall( "GetMenuString"
               , UInt,hMenu, Int,idx, Str,mStr, Int,nSize, UInt,0x400 )
      
      if (mstr <> "" AND idn = -1) {
         ; logA("submenu:" . hSub)
         ; hSub := DllCall("GetSubMenu",Uint,hMenu,int,idx)

; Not functioning properly...
         ; addMenuEntries(hSub, A_Args, mstr, idx, pcm)
      } else if (mstr = "") {
         menuAddSeparator(menu)
      } else if (idn != -1) {
         command := commandCreate("ContextMenu Run", "/file:" . fileName . " /idn:" . idn)
         menuAdd(menu, "/item:" . mstr, command)
      } else {
         menuAddSeparator(menu)
      }
   }
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: May 30th, 2009, 12:33 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
As I said before, if the menu item appears in the main menu, not in the submenu, InvokeVerb is simpler to use.
Code:
sPath := A_ScriptFullPath ; path of the target file

SplitPath, sPath, sName, sDir
COM_Init()
psh := COM_CreateObject("Shell.Application")
COM_Invoke(psh, "NameSpace[" sDir "].ParseName[" sName "].InvokeVerb", "Copy")
COM_Release(psh)
COM_Term()
MsgBox, DONE


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Multiple files
PostPosted: June 21st, 2009, 11:24 am 
Offline

Joined: July 30th, 2004, 8:50 pm
Posts: 192
Sean wrote:
LBJ wrote:
Has anyone managed to expand on this to work with a set of files? If so, how did you mange it?
How do you think Explorer does it? You can exactly do the same with the script.


:( I'm having the same problem... Anyone know how to get this working with multiple files?

Skrommel

_________________
www.1HourSoftware.com


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 2nd, 2009, 12:02 am 
Offline

Joined: January 18th, 2006, 7:39 am
Posts: 274
Location: Conway, Arkansas
Sean, would it be possible to provide an example showing how to make this work with with a multiple file selection, please?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 2nd, 2009, 2:27 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
All are described here. Notice that the function accepts an array of (child) pidls, meaning that you can pass an array of multiple child pidls instead of (an array of) single child pidl. That's what explorer does.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 25th, 2009, 10:35 am 
Offline

Joined: July 9th, 2009, 9:25 pm
Posts: 120
Context menu for multiple items (files/folders):
Code:
#Persistent

ShellContextMenu("", "0x000D; 0x0027")   ; CSIDL_MYMUSIC; CSIDL_MYPICTURES
ShellContextMenu("C:\Windows\Media", "notify.wav; flourish.mid")
;ShellContextMenu("C:\Windows", "system32\; Cursors\; Media\")
Return

ShellContextMenu(parentDir, files){
   COM_CoInitialize()
   COM_GUID4String(IID_IShellFolder,"{000214E6-0000-0000-C000-000000000046}"), COM_GUID4String(IID_IContextMenu,"{000214E4-0000-0000-C000-000000000046}")
   
   parentDir := RegExReplace(parentDir, "\\$"), i:=0
   Loop, Parse, files, `;, %A_Space%%A_Tab%
   {
      If A_LoopField is Integer
         i++, DllCall("shell32\SHGetFolderLocation", "Uint", 0, "int", A_LoopField, "Uint", 0, "Uint", 0, "UintP", pidl%i%)
      Else IfNotExist, %parentDir%\%A_LoopField%
         Continue
      Else
         i++, DllCall("shell32\SHParseDisplayName", "Uint", COM_Unicode4Ansi(wPath,parentDir "\" A_LoopField), "Uint", 0, "UintP", pidl%i%, "Uint", 0, "Uint", 0)
      DllCall("shell32\SHBindToParent", "Uint", pidl%i%, "Uint", &IID_IShellFolder, "UintP", psf%i%, "UintP", pidlChild%i%)
   }
   IfEqual,i,0, return
   
   VarSetCapacity(apidl, i * 4, 0)
   Loop, %i%
      NumPut(pidlChild%A_Index%, apidl, (A_Index-1)*4, "UInt")
   
   DllCall(NumGet(NumGet(1*psf1)+40), "Uint", psf1, "Uint", 0, "Uint", i, "Uint", &apidl, "Uint", &IID_IContextMenu, "Uint", 0, "UintP", pcm)
   Loop, %i%
      COM_Release(psf%A_Index%), COM_CoTaskMemFree(pidl%A_Index%)
   
   hMenu := DllCall("CreatePopupMenu")
   DllCall(NumGet(NumGet(1*pcm)+12), "Uint", pcm, "Uint", hMenu, "Uint", 0, "Uint", 3, "Uint", 0x7FFF, "Uint", 0)   ; QueryContextMenu
   DetectHiddenWindows, On
   Process, Exist
   WinGet, hAHK, ID, ahk_pid %ErrorLevel%
   WinActivate, ahk_id %hAHK%
   Global   pcm2 := COM_QueryInterface(pcm,IID_IContextMenu2:="{000214F4-0000-0000-C000-000000000046}")
   Global   pcm3 := COM_QueryInterface(pcm,IID_IContextMenu3:="{BCFCE0A0-EC17-11D0-8D10-00A0C90F2719}")
   Global   WPOld:= DllCall("SetWindowLong", "Uint", hAHK, "int",-4, "int",RegisterCallback("WindowProc"))
   DllCall("GetCursorPos", "int64P", pt)
   DllCall("InsertMenu", "Uint", hMenu, "Uint", 0, "Uint", 0x0400|0x800, "Uint", 2, "Uint", 0)
   DllCall("InsertMenu", "Uint", hMenu, "Uint", 0, "Uint", 0x0400|0x002, "Uint", 1, "Uint", &parentDir)
   idn := DllCall("TrackPopupMenu", "Uint", hMenu, "Uint", 0x0100, "int", pt << 32 >> 32, "int", pt >> 32, "Uint", 0, "Uint", hAHK, "Uint", 0)
   NumPut(VarSetCapacity(ici,64,0),ici), NumPut(0x4000|0x20000000,ici,4), NumPut(1,NumPut(hAHK,ici,8),12), NumPut(idn-3,NumPut(idn-3,ici,12),24), NumPut(pt,ici,56,"int64")
   DllCall(NumGet(NumGet(1*pcm)+16), "Uint", pcm, "Uint", &ici)   ; InvokeCommand
   ;   VarSetCapacity(sName,259), DllCall(NumGet(NumGet(1*pcm)+20), "Uint", pcm, "Uint", idn-3, "Uint", 1, "Uint", 0, "str", sName, "Uint", 260)   ; GetCommandString
   DllCall("GlobalFree", "Uint", DllCall("SetWindowLong", "Uint", hAHK, "int", -4, "int", WPOld))
   DllCall("DestroyMenu", "Uint", hMenu)
   COM_Release(pcm3)
   COM_Release(pcm2)
   COM_Release(pcm)
   COM_CoUninitialize()
   pcm2:=pcm3:=WPOld:=0
}

WindowProc(hWnd, nMsg, wParam, lParam)
{
   Critical
   Global   pcm2, pcm3, WPOld
   If   pcm3
   {
      If   !DllCall(NumGet(NumGet(1*pcm3)+28), "Uint", pcm3, "Uint", nMsg, "Uint", wParam, "Uint", lParam, "UintP", lResult)
         Return   lResult
   }
   Else If   pcm2
   {
      If   !DllCall(NumGet(NumGet(1*pcm2)+24), "Uint", pcm2, "Uint", nMsg, "Uint", wParam, "Uint", lParam)
         Return   0
   }
   Return   DllCall("user32.dll\CallWindowProcA", "Uint", WPOld, "Uint", hWnd, "Uint", nMsg, "Uint", wParam, "Uint", lParam)
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 25th, 2009, 4:53 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Nice try, but too much redundancy here, dig a little further. And ; as the delimiter is not a good choice as ; is a valid character in a file name. What I'm using, for example, is like this.
Code:
ShellContextMenu("C:\Windows\test1.txt|test2.txt|test3.txt")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 30th, 2009, 1:20 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Really great function, however it looks like "Copy" does not work, possibly due to absence of Explorer and marked file :(
Could we redirect the function to script, to do the job?

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Last edited by HotKeyIt on November 30th, 2009, 7:10 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 30th, 2009, 2:39 pm 
Offline

Joined: September 10th, 2009, 5:54 pm
Posts: 203
The link for CoHelper.ahk is dead


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 62 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Apollo, JamixZol, Yahoo [Bot] and 5 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group