 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Guest
|
Posted: Tue May 26, 2009 1:34 pm Post subject: |
|
|
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. |
|
| Back to top |
|
 |
Eucaly61
Joined: 16 May 2009 Posts: 18 Location: TW
|
Posted: Tue May 26, 2009 1:53 pm Post subject: |
|
|
| 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 |
|
| Back to top |
|
 |
Eucaly61
Joined: 16 May 2009 Posts: 18 Location: TW
|
Posted: Tue May 26, 2009 2:38 pm Post subject: |
|
|
.
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_folders.htm#Directories
.
.
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,
or
| Quote: | | http://www.koders.com/noncode/fid66A0E1FAB1C94FB665CFA5236DA4CDAEA22742CE.aspx#L1051 |
_________________ Eucaly61's DIY World (Mainly in Chinese)
http://eucaly61.blogspot.com/search/label/AutoHotKey |
|
| Back to top |
|
 |
Eucaly61
Joined: 16 May 2009 Posts: 18 Location: TW
|
Posted: Tue May 26, 2009 2:47 pm Post subject: |
|
|
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 |
|
| Back to top |
|
 |
Guest
|
Posted: Tue May 26, 2009 10:12 pm Post subject: |
|
|
@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 |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Wed May 27, 2009 4:42 am Post subject: |
|
|
| 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. |
|
| Back to top |
|
 |
joebodo
Joined: 28 Apr 2008 Posts: 48
|
Posted: Fri May 29, 2009 7:24 pm Post subject: |
|
|
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)
}
}
} |
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Fri May 29, 2009 11:33 pm Post subject: |
|
|
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
|
|
|
| Back to top |
|
 |
skrommel
Joined: 30 Jul 2004 Posts: 190
|
Posted: Sun Jun 21, 2009 10:24 am Post subject: Multiple files |
|
|
| 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 |
|
| Back to top |
|
 |
skwire
Joined: 18 Jan 2006 Posts: 273 Location: Conway, Arkansas
|
Posted: Sat Aug 01, 2009 11:02 pm Post subject: |
|
|
| Sean, would it be possible to provide an example showing how to make this work with with a multiple file selection, please? |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sun Aug 02, 2009 1:27 am Post subject: |
|
|
| 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. |
|
| Back to top |
|
 |
temp01
Joined: 09 Jul 2009 Posts: 120
|
Posted: Fri Sep 25, 2009 9:35 am Post subject: |
|
|
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)
} |
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Fri Sep 25, 2009 3:53 pm Post subject: |
|
|
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") |
|
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4653 Location: AHK Forum
|
Posted: Mon Nov 30, 2009 12:20 pm Post subject: |
|
|
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 
Last edited by HotKeyIt on Mon Nov 30, 2009 6:10 pm; edited 1 time in total |
|
| Back to top |
|
 |
Gauss
Joined: 10 Sep 2009 Posts: 203
|
Posted: Mon Nov 30, 2009 1:39 pm Post subject: |
|
|
| The link for CoHelper.ahk is dead |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|