Jump to content

Recommended Posts

(The title of this example was originally "The Shell/Custom Favorites/Programs Menus".)

TheFavoritesMenu_zps2e52cc56.jpg

This is an implementation of the Shell Favorites and Programs menus with the IShellMenu interface.

The purpose of this menu system is to create a popup menu from a directory structure consisting of subfolders and internet or program links. The menu will look like the Favorites menu in Internet or Windows Explorer (as it looked when XP SP2 was released in August 2004).

The IShellMenu interface can generally be used to create a menu from a directory structure. The menu items will be supplied with the same icons as the link files and they will be supplied with tooltips too. When you click a menu item the command associated with the internet or program link will be executed.

The Favorites and Programs menus will create popup menus from the directory structures given by $CSIDL_FAVORITES, $CSIDL_PROGRAMS, $CSIDL_STARTMENU, $CSIDL_COMMON_PROGRAMS, $CSIDL_COMMON_STARTMENU.

The Custom Favorites and Custom Programs menus can be used to create custom popup menus from custom directory structures.

Note that the context (right click) menu is working in the Favorites menu.

Update #4 2014-05-03: AutoIt 3.3.10

This example was created under 3.3.8 and based on APIConstants.au3 and WinAPIEx.au3 by Yashied.

The original example runs under 3.3.10 without any changes at all. But a lot of unused constants and functions are included.

In 3.3.10 the two UDFs are divided into several smaller UDFs. This makes it much easier to just include, what is needed. This update only includes the necessary UDFs. You find the new and old zip in bottom of the post.

Update #3 2012-11-06: Programs menus

Added the Programs menus from the directory structures given by $CSIDL_PROGRAMS, $CSIDL_STARTMENU, $CSIDL_COMMON_PROGRAMS, $CSIDL_COMMON_STARTMENU.

To create a menu like the "All Programs" menu copy the two "Start Menu" folders (your own + "All Users") to the "Custom Programs 1" folder and overwrite the existing "Start Menu" folder. Then select the menu item "Custom Programs | Custom Programs 1".

Update #2 2012-11-03: Custom Favorites menus

If you are creating an AutoIt program and want to add a custom Favorites menu with relevant internet links all you have to do is to create a directory structure, add the subfolders (optional) and links and call the ShowFavsProgsMenu() function with a path to the directory. And you will get a menu that looks like and works like the Favorites menu in Internet Explorer.

You can see two custom Favorites menus in the examples.

Added two small directory structures to the zip to be used for the custom Favorites menus.

Fixed an error: OleInitialize() is used to initialize COM in stead of CoInitialize() (necessary to make the Copy command in the context menu work).

Update #1 2012-11-01: Window procedure

Because a popup menu like the Favorites menu is modal, it's necessary to use some kind of a window procedure to catch the menu messages. When it's a popup menu it should be enough to have the window procedure running while the popup menu is displayed.

In the original scripts the window procedure was created with these commands:

$hNewWinProc = DllCallbackRegister( "NewWindowProc", "int", "hwnd;uint;wparam;lparam" )        ; New window procedure
$hOldWinProc = _WinAPI_SetWindowLong( $hGui, $GWL_WNDPROC, DllCallbackGetPtr( $hNewWinProc ) ) ; Old window procedure
The procedure was started in the main script in the example and was running as long as the script was running.

In this update the menu messages is catched with a hook procedure:

$hFavMenuMsg = DllCallbackRegister( "FavMenuMsg", "long", "int;wparam;lparam" )
$hFavMenuMsgHook = _WinAPI_SetWindowsHookEx( $WH_MSGFILTER, DllCallbackGetPtr( $hFavMenuMsg ), 0, _WinAPI_GetCurrentThreadId() )
; $WH_MSGFILTER installs a hook procedure that monitors messages generated as a
; result of an input event in a dialog box, message box, menu, or scroll bar.
The procedure is started in the bottom of the ShowFavoritesMenu() function immediately after the Favorites menu is displayed on the screen, and the procedure is stopped when the menu disappears from the screen. Either because the menu is cancelled or a selection is made.

(If you comment out these commands in ShellFavoritesMenu.au3 the Favorites menu will still show up. But the submenus will not be expanded if you keep the mouse steady over a submenu or use the arrow keys.)

This hook procedure is much better than the original window procedure. It's much easier to integrate the Favorites menu in other programs when it isn't depending on a "global" window procedure.

A "global" window procedure can also have some influence on the GUI (at least on XP, I think it's better on 7). In the original example you saw it clearly when the GUI lost focus. When the GUI got focus back the upper line of the edit box could be behind the toolbar. This is not a problem with a hook procedure only running when the Favorites menu is displayed.

Added an example with a menu. Zip updated.

First post 2012-10-30

This is an implementation of the Favorites menu primary with the IShellMenu interface but several other interfaces are used as well.

The main function:

Func ShowFavoritesMenu( $hWnd, $hMenu, $xCoord, $yCoord )

; --- Create a menu band object and the IShellMenu interface ---

Local $oIShellMenu, $pIShellMenu
; Create a menu band object and get a pointer to the IShellMenu interface
CoCreateInstance( $tCLSID_MenuBand, $NULL, $CLSCTX_INPROC_SERVER, $tRIID_IShellMenu, $pIShellMenu )
$oIShellMenu = ObjCreateInterface( $pIShellMenu, $sIID_IShellMenu, $dtag_IShellMenu )
If Not IsObj( $oIShellMenu ) Then Return SetError(1,0,0)

; --- Initialize the interface ---

If $oIShellMenu.Initialize( $NULL, -1, $ANCESTORDEFAULT, BitOR( $SMINIT_TOPLEVEL, $SMINIT_VERTICAL ) ) <> $S_OK Then Return SetError(2,0,0)

; --- Specify the folder for the menu band to browse ---

; Get a pointer to the IShellFolder interface for the desktop
Local $pIShellFolder = $NULL, $oIShellFolderDesktop, $pIShellFolderDesktop, $pidlRel
SHGetDesktopFolder( $pIShellFolderDesktop )
SHGetSpecialFolderLocation( $NULL, $CSIDL_FAVORITES, $pidlRel )
$oIShellFolderDesktop = ObjCreateInterface( $pIShellFolderDesktop, $sIID_IShellFolder, $dtag_IShellFolder )
$oIShellFolderDesktop.BindToObject( $pidlRel, $NULL, $tRIID_IShellFolder, $pIShellFolder )
If $pIShellFolder = $NULL Then Return SetError(3,0,0)

; Get the registry key with the "Order" value of the Favorites folder
Local $hRegOrder = _WinAPI_RegOpenKey( $HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites", $KEY_READ )
If $hRegOrder = 0 Then Return SetError(4,0,0)

; Specify the folder for the menu band to browse
If $oIShellMenu.SetShellFolder( $pIShellFolder, $pidlRel, $hRegOrder, BitOR( $SMSET_BOTTOM, $SMSET_USEBKICONEXTRACTION ) ) <> $S_OK Then Return SetError(5,0,0)
_WinAPI_CoTaskMemFree( $pidlRel )
_WinAPI_RegCloseKey( $hRegOrder )

; --- Append a static menu to the menu band ---

If $oIShellMenu.SetMenu( $hMenu, $hWnd, $SMSET_TOP ) <> $S_OK Then Return SetError(6,0,0)

; --- Get access to IMenuPopup, IDeskBar and IDeskBand interfaces ---

Local $pIMenuPopup, $pIDeskBar, $pIDeskBand

; The IMenuPopup interface
If $pIShellMenu Then
If $oIShellMenu.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup ) <> $S_OK Then Return SetError(7,0,0)
EndIf

; The IDeskBar interface
If $pIMenuPopup Then
Local $oIMenuPopup = ObjCreateInterface( $pIMenuPopup, $sIID_IMenuPopup, $dtag_IMenuPopup )
If $oIMenuPopup.QueryInterface( $tRIID_IDeskBar, $pIDeskBar ) <> $S_OK Then Return SetError(8,0,0)
EndIf

; The IDeskBand interface
If $pIDeskBar Then
Local $oIDeskBar = ObjCreateInterface( $pIDeskBar, $sIID_IDeskBar, $dtag_IDeskBar )
If $oIDeskBar.QueryInterface( $tRIID_IDeskBand, $pIDeskBand ) <> $S_OK Then Return SetError(9,0,0)
EndIf

; --- Create a menu desk bar object and the IMenuPopup interface ---

Local $oIUnknown, $pIUnknown, $oIMenuPopup, $pIMenuPopup

; Create a menu desk bar object and get a pointer to the IUnknown interface
CoCreateInstance( $tCLSID_MenuDeskBar, $NULL, $CLSCTX_INPROC_SERVER, $tRIID_IUnknown, $pIUnknown )
$oIUnknown = ObjCreateInterface( $pIUnknown, $sIID_IUnknown, $dtag_IUnknown )

; Create the IMenuPopup interface
$oIUnknown.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup )
$oIMenuPopup = ObjCreateInterface( $pIMenuPopup, $sIID_IMenuPopup, $dtag_IMenuPopup )
If Not IsObj( $oIMenuPopup ) Then Return SetError(10,0,0)

; --- Create a menu band site object and the IBandSite interface ---

Local $oIBandSite, $pIBandSite
; Create a menu band site object and get a pointer to the IBandSite interface
CoCreateInstance( $tCLSID_MenuBandSite, $NULL, $CLSCTX_INPROC_SERVER, $tRIID_IBandSite, $pIBandSite )
$oIBandSite = ObjCreateInterface( $pIBandSite, $sIID_IBandSite, $dtag_IBandSite )
If Not IsObj( $oIBandSite ) Then Return SetError(11,0,0)

; --- Set the band site object as client for the desk bar object ---

If $oIMenuPopup.SetClient( $pIBandSite ) <> $S_OK Then Return SetError(12,0,0)

; --- Add the desk band object to the band site object ---

If $oIBandSite.AddBand( $pIDeskBand ) <> $S_OK Then Return SetError(13,0,0)

; --- Show the Favorites menu ---

Local $tPOINT = DllStructCreate( $tagPOINT )
DllStructSetData( $tPOINT, "X", $xCoord )
DllStructSetData( $tPOINT, "Y", $yCoord )

Local $tRECT = DllStructCreate( $tagRECT )
DllStructSetData( $tRECT, "Left", $xCoord )
DllStructSetData( $tRECT, "Top", $yCoord+1 )
DllStructSetData( $tRECT, "Right", $xCoord )
DllStructSetData( $tRECT, "Bottom", $yCoord+1 )

$oIMenuPopup.Popup( $tPOINT, $tRECT, $MPPF_ALIGN_RIGHT )

; --- Create the IMenuBand interface ---

Local $oIDeskBand
$oIDeskBand = ObjCreateInterface( $pIDeskBand, $sIID_IDeskBand, $dtag_IDeskBand )
$oIDeskBand.QueryInterface( $tRIID_IMenuBand, $pIMenuBand )
$oIMenuBand = ObjCreateInterface( $pIMenuBand, $sIID_IMenuBand, $dtag_IMenuBand )
If Not IsObj( $oIMenuBand ) Then Return SetError(14,0,0)

; $oIMenuBand and $pIMenuBand are global variables
; $oIMenuBand is used to handle the messages from the Favorites menu in the function below
; $pIMenuBand is used to test if the Favorites menu is open ($pIMenuBand <> $NULL)

Return 0

EndFunc

Example

The zip contains the example as you can see in the picture. There are two versions of the example: A version based on a toolbar (ExShellFavsProgsMenus.au3), and a version based on a menu bar (ExShellFavsProgsMenus2.au3). The purpose of the text box is just to have something to put in the window.

The zip contains also the ShellFavsProgsMenus.au3 UDF.

This zip contains the original scripts for 3.3.8. You need APIConstants.au3 and WinAPIEx.au3 by Yashied. The UDFs are not included in the zip. The zip can be opened with 7-Zip.

ShellFavsProgsMenus.zip

This zip contains the updated scripts for 3.3.10. Only a matter of UDFs. These scripts will not run under 3.3.8.

TheFavoritesMenu.7z

Testet on XP 32 bit and Win 7 32/64 bit.

Edited by LarsJ
Link to comment
Share on other sites

JScript, Added an example with a menu. Thank you for the stars.

The "global" window procedure that runs all the time is replaced with a hook procedure that only runs when the Favorites menu is displayed.

Lars.

Edited by LarsJ
Link to comment
Share on other sites

Added support for custom Favorites menus.

Link to comment
Share on other sites

Added support for Programs menus.

Link to comment
Share on other sites

  • 1 year later...

This is fantastic :thumbsup: , I searched for such a menu for years and and always planned to programm my own

I have some questions for a bit more of control:

- Is it possible to better control the menu, like selecting items programmaticly and determine the current path ( especially when entering submenus... )

- It it possible to add own entrys directly in such a menu ( for example a recent folders entry or favourites )

 

Thanks in advance

Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Bluesmaster, The purpose of this menu system is to create a popup menu from a directory structure consisting of subfolders and internet or program links. The menu will look like the Favorites menu in Internet or Windows Explorer (as they looked when XP SP2 was released in August 2004).

To control the menu you need menu handles. But menu handles are generated internally and you get new handles every time the menu is shown. So there is no easy way to control the menu.

If you add new links and subfolders to the directory structure they will be shown as new menu items and submenus. Because the entire directory structure is read each time the menu is shown you can do it dynamically.

This menu cannot replace an entire menu system. But it can be used as a part of a menu system to create a menu similar to the Favorites menu or Programs menu.

I'm using the code in this OpenGL example to create a Links menu with links to information.

Lars.

Link to comment
Share on other sites

Hello Lars,

I am glad you care for this after one year has passed. I am planning to transform this into a more general menu for moving and browsing files fast and efficent.

Just started, and its quite promising. Main hurdle is to know, the path corresponding to the object currently selected by the user.

Figured out, that the menu is represented by a "toolbar32" but I failed to get the handles :ermm: .

And even if I could get them, the other task is to get the full path of the item and not just its name in one of the submenus.

Here some attempts to get infos from the menu ( all failed )

    local $hPopupWin
    $oIMenuPopup.GetWindow( $hPopupWin )

or

$oIShellMenu.GetShellFolder( $hMenu, $hWnd, $SMSET_TOP )

or

$hToolbar = ControlGetHandle(  WinGetHandle( "[CLASS:BaseBar" ) , "" , "[CLASS:ToolbarWindow32; INSTANCE:1]" )

Can you please give me  some small tips I really got stuck for a  day now.

 

Here is a first snippet showing the direction of my attempt ( please ignore the missing error-handling for now )
ContextBrowser.au3

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Bluesmaster, I'm pretty sure you can get the path of the selected item if you implement the IShellMenuCallback interface and look for SMC_SFSELECTITEM notifications. From the documentation of SMC_SFSELECTITEM notifications: "The user has selected the item specified by the accompanying SMDATA structure." From this SMDATA structure you can get all the information you need.

I have not looked at your code yet, but the project seems to be quite interesting.

Regards Lars.

Link to comment
Share on other sites

Thanks for your answer. I will try. But I really struggle with those IInterfaces... I never really understood the difference to the "objectCreate"-method and it seems nobody can really explain it to me.

I can get the "$IID_IShellMenuCallback =  "{4CA300A1-9B8D-11d1-8B22-00C04FD918D0}"  but how to get those mysterious vTables. For me it seems like google fortune and I had no in this case.

There seem to be professional solutions like TypeLibInspector ( '?do=embed' frameborder='0' data-embedContent> title=""> ) but I never get that to run, and my question was never answerd.

Where do you get your vTables and clsids from?

 

regards Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Microsoft provides info. It's documented on MSDN. If web page lacks info about v-table order or identifiers it wouldn't miss to tell you in which file those definitions are. The files are part of Microsoft SDKs.

In case you don't program for Windows and don't use Visual Studio and don't have SDK then you can allways google, for example IShellMenuCallback ReactOS or maybe IShellMenuCallback Wine and get definition from there. Former will very quickly lead you to http://doxygen.reactos.org/d4/d3f/shobjidl_8idl_source.html where you can see definition for your interface and list of functions in, of course, v-table order together with parameters definitions.

Edited by trancexx
Link to comment
Share on other sites

Bluesmaster, Here is an implementation of IShellMenuCallback. It's not completely trivial. It'll write the paths in Scite console.

Download IShellMenuCallback.au3 below.

Edit ShellFavsProgsMenus.au3 from the the zip in the first post.

Include IShellMenuCallback.au3:

; Dynamic Link Libraries
Global Const $dllOle32    = DllOpen( "ole32.dll" )
Global Const $dllShell32  = DllOpen( "shell32.dll" )
Global Const $dllUser32   = DllOpen( "user32.dll" )

#include "IShellMenuCallback.au3" ; <<<<<<<<<<<<<<<<

Comment out this line:

;Global Const $NULL = 0x0000

Comment out this section:

#cs
; IShellFolder Interface
Global Const $sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
Global Const $tRIID_IShellFolder = CLSIDFromString( $sIID_IShellFolder )
Global Const $dtag_IShellFolder = _
    "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
    "EnumObjects hresult(hwnd;dword;ptr*);" & _
    "BindToObject hresult(ptr;ptr;struct*;ptr*);" & _
    "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
    "CompareIDs hresult(lparam;ptr;ptr);" & _
    "CreateViewObject hresult(hwnd;struct*;ptr*);" & _
    "GetAttributesOf hresult(uint;struct*;ulong*);" & _
    "GetUIObjectOf hresult(hwnd;uint;struct*;struct*;uint*;ptr*);" & _
    "GetDisplayNameOf hresult(ptr;uint;struct*);" & _
    "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
#ce

Comment out a line and add a line:

;If $oIShellMenu.Initialize( $NULL, -1, $ANCESTORDEFAULT, BitOR( $SMINIT_TOPLEVEL, $SMINIT_VERTICAL ) ) <> $S_OK Then Return SetError(2,0,0)
If $oIShellMenu.Initialize( $pIShellMenuCallback, -1, $ANCESTORDEFAULT, BitOR( $SMINIT_TOPLEVEL, $SMINIT_VERTICAL ) ) <> $S_OK Then Return SetError(2,0,0)

Open and run one of the examples in Scite and you'll see the paths in the console.

V-table: I get the information from the same sources as trancexx.

Regards Lars.

IShellMenuCallback.au3

Edit: See next post.

Edited by LarsJ
Link to comment
Share on other sites

You can replace oIShellMenuCallback_CallbackSM in IShellMenuCallback.au3 with this:

Func oIShellMenuCallback_CallbackSM( $pSelf, $psmd, $uMsg, $wParam, $lParam )
    ;ConsoleWrite( "oIShellMenuCallback_CallbackSM" & @CRLF )
    Switch $uMsg
        Case $SMC_SFSELECTITEM
            Local $tSMDATA = DllStructCreate( $tagSMDATA, $psmd ), $sPath
            Local $pPidl = ILClone( DllStructGetData( $tSMDATA, "pidlFolder" ) )
            $pPidl = ILCombine( $pPidl, DllStructGetData( $tSMDATA, "pidlItem" ) )
            SHGetPathFromIDList( $pPidl, $sPath )
            _WinAPI_CoTaskMemFree( $pPidl )
            ConsoleWrite( $sPath & @CRLF )
            Return $S_FALSE
        Case Else
            Return $S_FALSE
    EndSwitch
EndFunc

Add these two functions to the bottom of the file:

Func ILClone( $pidl )
    Local $aRet = DllCall( $dllShell32, "ptr", "ILClone", "ptr", $pidl )
    If @error Then Return SetError(1, 0, 0)
    Return $aRet[0]
EndFunc

Func ILCombine( $pidlAbs, $pidlRel )
    Local $aRet = DllCall( $dllShell32, "ptr", "ILCombine", "ptr", $pidlAbs, "ptr", $pidlRel )
    If @error Then Return SetError(1, 0, 0)
    Return $aRet[0]
EndFunc

Then you can delete the following:

Global Const $dllShlwapi = DllOpen( "shlwapi.dll" )

Global $iIShellFolder = 0, $apIShellFolder[1], $aoIShellFolder[1]

Func StrRetToBuf( $pSTRRET, $pidl, ByRef $sBuf, $iBuf = 512 )
    Local $aRet = DllCall( $dllShlwapi, "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sBuf, "uint", $iBuf )
    If @error Then Return SetError(1, 0, 0)
    $sBuf = $aRet[3]
    Return $aRet[0]
EndFunc
Link to comment
Share on other sites

Hello Lars,

Sorry for my late respose. Its very hard to find time at the moment. Your code is amazing. And it works :)

Honestly I would never had been able to implement this. I will need some time to develop the full context-menu-explorer.

I will post the result here. And again: Thank you so much

Bluesmaster

Edited by Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Hi Lars,

I found some time to continue working on the "context-menu-explorer" based on your "ShowFavsProgsMenu". And...I am desperate.

My purpose is to merge 2 of those menus in 1 menu to augment the first menu with some "most recent folders" ... and so  on.
I build an example that should merge "c:" and "c:users" but they popup separatly, or alone or do not even popup whatever I try.

The code is extra unreadable :sweating:  because I condensed it a lot for overview reasons. But its more a  question of basic understanding.

In Point 1 ( line 90 ) I create a menu. In Point 2 ( line 120 ) I create a second one...I could write a thousand words, I think you know what I mean.

Can you please give me  some small advice again?

#include-once
#include <GuiMenu.au3>
#include "APIConstants.au3"
#include "WinAPIEx.au3"


HotKeySet( "{ESC}" , "_exit" )
Func _exit()
    Exit
EndFunc


ShowFavsProgsMenu( "C:\" )

While 1
    Sleep( 1000 )
WEnd


Func ShowFavsProgsMenu( $targetFolder , $xCoord  = "" , $yCoord  = "" , $pasteAndLeaveMode = 0 , $nFavouritesToShow = 1 )



    ; 0 - PREPARE - ( define constants and vTables )
    #region PREPARE
    Global $NULL  = 0x0000, $S_FALSE = 0x00000001, $MAX_PATH = 260, $iIShellFolder = 0, $apIShellFolder[1], $aoIShellFolder[1]
    Global $hFavsProgsMenu , $oIMenuBand, $pIMenuBand = 0x0000, $S_OK = 0, $hFavsProgsMenuMsg = 0x0000, $tFavsProgsMenuMsg, $hFavsProgsMenuMsgHook, $idFavsProgsMenuMsgUnHook = 0
    Global Const $dllOle32    = DllOpen( "ole32.dll"   )
    DllCall( $dllOle32 , "long", "OleInitialize", "ptr", 0)
    Global $tagMSG = "hwnd hwnd;uint message;wparam wParam;lparam lParam;dword time;int X;int Y"
    $IID_IShellMenuCallback =  "{4CA300A1-9B8D-11d1-8B22-00C04FD918D0}"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; CLSID_MenuBand
    Global Const $tCLSID_MenuBand = $tCLSID
    Global Const $sCLSID_MenuBand = "{5B4DAE26-B807-11D0-9815-00C04FD91972}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sCLSID_MenuBand, "ptr", DllStructGetPtr($tCLSID))
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; CLSID_MenuDeskBar
    Global Const $sCLSID_MenuDeskBar = "{ECD4FC4F-521C-11D0-B792-00A0C90312E1}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sCLSID_MenuDeskBar, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tCLSID_MenuDeskBar = $tCLSID
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; CLSID_MenuBandSite
    Global Const $sCLSID_MenuBandSite = "{E13EF4E4-D2F2-11D0-9816-00C04FD91972}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sCLSID_MenuBandSite, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tCLSID_MenuBandSite = $tCLSID
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IShellMenu
    Global Const $sIID_IShellMenu = "{EE1F7637-E138-11d1-8379-00C04FD918D0}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IShellMenu, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IShellMenu = $tCLSID
    Global Const $dtag_IShellMenu = "Initialize hresult(ptr;uint;uint;dword);GetMenuInfo hresult(ptr*;uint*;uint*;dword*);SetShellFolder hresult(ptr;ptr;handle;dword);GetShellFolder hresult(ptr*;ptr*;struct*;ptr*);" & _
    "Setmenu hresult(handle;hwnd;dword);GetMenu hresult(handle*;hwnd*;dword*);InvalidateItem hresult(ptr;dword);GetState hresult(ptr);SetMenuToolbar hresult(ptr*;dword);"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IShellFolder
    Global Const $sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IShellFolder, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IShellFolder = $tCLSID
    Global Const $dtag_IShellFolder = "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);EnumObjects hresult(hwnd;dword;ptr*);BindToObject hresult(ptr;ptr;struct*;ptr*);BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
    "CompareIDs hresult(lparam;ptr;ptr);CreateViewObject hresult(hwnd;struct*;ptr*);GetAttributesOf hresult(uint;struct*;ulong*);GetUIObjectOf hresult(hwnd;uint;struct*;struct*;uint*;ptr*);GetDisplayNameOf hresult(ptr;uint;struct*);SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IMenuPopup
    Global Const $sIID_IMenuPopup = "{D1E7AFEB-6A2E-11d0-8C78-00C04FD918B4}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IMenuPopup, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IMenuPopup = $tCLSID
    Global Const $dtag_IMenuPopup =     "GetWindow hresult(hwnd);ContextSensitiveHelp hresult(bool);SetClient hresult(ptr);GetClient hresult(ptr*);OnPosRectChangeDB hresult(struct*);Popup hresult(struct*;struct*;dword);OnSelect hresult(dword);SetSubMenu hresult(ptr;bool);"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IDeskBar
    Global Const $sIID_IDeskBar = "{EB0FE173-1A3A-11D0-89B3-00A0C90A90AC}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IDeskBar, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IDeskBar = $tCLSID
    Global Const $dtag_IDeskBar = "SetClient hresult(ptr);GetClient hresult(ptr*);OnPosRectChangeDB hresult(struct*);"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IDeskBand
    Global Const $sIID_IDeskBand = "{EB0FE172-1A3A-11D0-89B3-00A0C90A90AC}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IDeskBand, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IDeskBand = $tCLSID
    Global Const $dtag_IDeskBand ="GetBandInfo hresult(dword;dword;struct*);"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IUnknown
    Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IUnknown, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IUnknown = $tCLSID
    Global Const $dtag_IUnknown = "QueryInterface hresult(struct*;ptr*);AddRef ulong();Release ulong();"
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IBandSite
    Global Const $sIID_IBandSite = "{4CF504B0-DE96-11D0-8B3F-00A0C911E8E5}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IBandSite, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IBandSite = $tCLSID
    Global Const $dtag_IBandSite =  "AddBand hresult(ptr);EnumBands hresult(uint;dword*);QueryBand hresult(dword;ptr*;dword*;wstr;int);SetBandState hresult(dword;dword;dword);RemoveBand hresult(dword);GetBandObject hresult(dword;struct*;ptr*);SetBandSiteInfo hresult(ptr);GetBandSiteInfo hresult(ptr*);"                                         ; BANDSITEINFO* pbsinfo
    $tCLSID = DllStructCreate("dword;word;word;byte[8]")    ; IMenuBand
    Global Const $sIID_IMenuBand = "{568804CD-CBD7-11d0-9816-00C04FD91972}"
    DllCall( $dllOle32 , "long", "CLSIDFromString", "wstr", $sIID_IMenuBand, "ptr", DllStructGetPtr($tCLSID))
    Global Const $tRIID_IMenuBand = $tCLSID
    Global Const $dtag_IMenuBand = "IsMenuMessage hresult(struct*);TranslateMenuMessage hresult(struct*;lresult*);"
    #endregion PREPARE



    ; 1 - MENU 1  ( "c:\" )
    Local $oMainFolderMenu, $pIShellMenu , $CLSCTX_INPROC_SERVER = 0x1
    $pIShellMenu = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuBand), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IShellMenu), "ptr*", 0 )
    $oMainFolderMenu = ObjCreateInterface( $pIShellMenu[5] , $sIID_IShellMenu, $dtag_IShellMenu )
    ;~  $SMINIT_RESTRICT_DRAGDROP  = 0x00000002  ; Don't allow Drag and Drop  | $SMINIT_TOPLEVEL = 0x00000004  ; This is the top band. | $SMSET_DONTOWN   = 0x00000001  ; The Menuband doesn't own the non-ref counted object
    Local $SMINIT_VERTICAL = 0x10000000, $ANCESTORDEFAULT  = 0xFFFFFFFF, $SMSET_USEBKICONEXTRACTION = 0x00000008 , $SMSET_TOP = 0x10000000 ,$SMINIT_TOPLEVEL  = 0x00000004  ,$SMSET_BOTTOM  = 0x20000000  ; Bias this namespace to the bottom of the menu
    $oMainFolderMenu.Initialize(  ObjCreateInterfaceEx( "oIShellMenuCallback_", "CallbackSM hresult(ptr;uint;wparam;lparam);", True ) , -1, $ANCESTORDEFAULT, BitOR( $SMINIT_TOPLEVEL, $SMINIT_VERTICAL ) ) ; Callback installieren
    $r = DllCall( "shell32.dll" , "uint", "SHILCreateFromPath", "wstr",   $targetFolder  , "ptr*", 0, "dword*", 0 ) ; set Folder
    $oMainFolderMenu.SetShellFolder( $NULL , $r[2] , $NULL , BitOR( $SMSET_BOTTOM, $SMSET_USEBKICONEXTRACTION ) )

    ;  IMenuPopup  >>  IDeskBar  >> IDeskBand  >>  IShellMenu )
    Local $pIMenuPopup, $pIDeskBar, $pIDeskBand
    $oMainFolderMenu.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup )               ; IShellMenu  >> ... >>  IMenuPopup ???
    $oIMenuPopup = ObjCreateInterface( $pIMenuPopup, $sIID_IMenuPopup, $dtag_IMenuPopup )
    $oIMenuPopup.QueryInterface( $tRIID_IDeskBar, $pIDeskBar )
    $oIDeskBar   = ObjCreateInterface( $pIDeskBar, $sIID_IDeskBar, $dtag_IDeskBar )
    $oIDeskBar.QueryInterface( $tRIID_IDeskBand, $pIDeskBand )                       ; IBandSite  >>  IDeskbar
    $pIUnknown   = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuDeskBar), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IUnknown), "ptr*", 0 )
    $oIUnknown   = ObjCreateInterface( $pIUnknown[5] , $sIID_IUnknown, $dtag_IUnknown )
    $oIUnknown.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup )
    $oIMenuPopup = ObjCreateInterface( $pIMenuPopup, $sIID_IMenuPopup, $dtag_IMenuPopup )
    $pIBandSite  = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuBandSite), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IBandSite), "ptr*", 0 )
    $oIBandSite  = ObjCreateInterface( $pIBandSite[5] , $sIID_IBandSite, $dtag_IBandSite )
    $oIMenuPopup.SetClient( $pIBandSite[5] ) ;                IBandSite  >>  IMenuPopup
    $oIBandSite.AddBand( $pIDeskBand )       ; IDeskBand  >>  IBandSite





    ; 2 - MENU 2 ( "C:\Users" )
    Local $oAppendixMenu, $pIShellMenu2 , $CLSCTX_INPROC_SERVER = 0x1
    $pIShellMenu2  = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuBand), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IShellMenu), "ptr*", 0 )
    $oAppendixMenu = ObjCreateInterface( $pIShellMenu2[5] , $sIID_IShellMenu, $dtag_IShellMenu )
    ;~  $SMINIT_RESTRICT_DRAGDROP  = 0x00000002  ; Don't allow Drag and Drop  | $SMINIT_TOPLEVEL = 0x00000004  ; This is the top band. | $SMSET_DONTOWN   = 0x00000001  ; The Menuband doesn't own the non-ref counted object
    Local $SMINIT_VERTICAL = 0x10000000, $ANCESTORDEFAULT  = 0xFFFFFFFF, $SMSET_USEBKICONEXTRACTION = 0x00000008 , $SMSET_TOP = 0x10000000 ,$SMINIT_TOPLEVEL  = 0x00000004  ,$SMSET_BOTTOM  = 0x20000000  ; Bias this namespace to the bottom of the menu
    $oAppendixMenu.Initialize(  ObjCreateInterfaceEx( "oIShellMenuCallback2_", "CallbackSM hresult(ptr;uint;wparam;lparam);", True ) , -1, $ANCESTORDEFAULT, BitOR( $SMINIT_TOPLEVEL, $SMINIT_VERTICAL ) ) ; Callback installieren
    $r = DllCall( "shell32.dll" , "uint", "SHILCreateFromPath", "wstr",     "C:\Users"    , "ptr*", 0, "dword*", 0 ) ; set Folder
    $oAppendixMenu.SetShellFolder( $NULL , $r[2] , $NULL , BitOR( $SMSET_BOTTOM, $SMSET_USEBKICONEXTRACTION ) )

    ; IMenuPopup  >>  IDeskBar  >> IDeskBand  >>  IShellMenu )
    Local $pIMenuPopup2, $pIDeskBar2, $pIDeskBand2
    $oAppendixMenu.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup2 )
    $oIMenuPopup2 = ObjCreateInterface( $pIMenuPopup2, $sIID_IMenuPopup, $dtag_IMenuPopup )
    $oIMenuPopup2.QueryInterface( $tRIID_IDeskBar, $pIDeskBar2 )
    $oIDeskBar2 = ObjCreateInterface( $pIDeskBar2, $sIID_IDeskBar, $dtag_IDeskBar )
    $oIDeskBar2.QueryInterface( $tRIID_IDeskBand, $pIDeskBand2 )
    $pIUnknown2 = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuDeskBar), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IUnknown), "ptr*", 0 )
    $oIUnknown2 = ObjCreateInterface( $pIUnknown2[5] , $sIID_IUnknown, $dtag_IUnknown )
    $oIUnknown2.QueryInterface( $tRIID_IMenuPopup, $pIMenuPopup2 )
    $oIMenuPopup2 = ObjCreateInterface( $pIMenuPopup2, $sIID_IMenuPopup, $dtag_IMenuPopup )
    $pIBandSite2 = DllCall( $dllOle32, "long_ptr", "CoCreateInstance", "ptr", DllStructGetPtr($tCLSID_MenuBandSite), "ptr", $NULL, "dword", $CLSCTX_INPROC_SERVER, "ptr", DllStructGetPtr($tRIID_IBandSite), "ptr*", 0 )
    $oIBandSite2 = ObjCreateInterface( $pIBandSite2[5] , $sIID_IBandSite, $dtag_IBandSite )
    $oIMenuPopup2.SetClient( $pIBandSite2[5] ) ; IBandSite  >>  IMenuPopup
    $oIBandSite2.AddBand( $pIDeskBand2 )       ; IDeskBand  >>  IBandSite
;~  $oIBandSite.AddBand( $pIDeskBand2 )       ; IDeskBand  >>  IBandSite



    ; 3 - APPEND  -   ( ...to exsiting menu = optional )
    $hWnd   = GUICreate( "" )
    $hMenu  = _GUICtrlMenu_CreatePopup()
    _GUICtrlMenu_InsertMenuItem( $hMenu , 0 , "&custom command 2" , 55 )
    _GUICtrlMenu_InsertMenuItem( $hMenu , 0 , "&custom command 1" , 55 )
    _GUICtrlMenu_AddMenuItem(  $hMenu  , ""  ) ; Separator
    _GUICtrlMenu_AddMenuItem(  $hMenu  , ""  )
    $oMainFolderMenu.SetMenu( $hMenu, $hWnd, $SMSET_TOP )
    $oAppendixMenu.SetMenu(   $hMenu, $hWnd, $SMSET_TOP )



    ; 4 - SHOW    -  ( position )
    ; Flags > IMenuPopup::Popup method
    Global Enum _
        $MPPF_SETFOCUS          = 0x1, _        ; The menu should have focus when it appears.
        $MPPF_INITIALSELECT     = 0x2, _        ; The first item in the menu should be selected.
        $MPPF_NOANIMATE         = 0x4, _        ; Do not animate this show.
        $MPPF_KEYBOARD          = 0x10, _       ; The menu is activated by the keyboard.
        $MPPF_REPOSITION        = 0x20, _       ; Reposition the displayed bar.
        $MPPF_FORCEZORDER       = 0x40, _       ; The menu bar should ignore submenu positions.
        $MPPF_FINALSELECT       = 0x80, _       ; The last item in the menu should be selected.
        $MPPF_TOP               = 0x20000000, _ ; Display the pop-up menu above the point specified in ppt.
        $MPPF_LEFT              = 0x40000000, _ ; Display the pop-up menu to the left of the point specified in ppt.
        $MPPF_RIGHT             = 0x60000000, _ ; Display the pop-up menu to the right of the point specified in ppt.
        $MPPF_BOTTOM            = 0x80000000, _ ; Display the pop-up menu below the point specified in ppt.
        $MPPF_POS_MASK          = 0xE0000000, _ ; Mask for position values MPPF_TOP, MPPF_LEFT, and MPPF_RIGHT.
        $MPPF_ALIGN_LEFT        = 0x2000000, _  ; Default alignment.
        $MPPF_ALIGN_RIGHT       = 0x4000000     ; The pop-up menu should be aligned to the right of the excluded rectangle specified by prcExclude.

    if $xCoord  = "" Then    ; falls keine Position gegeben > am Mauszeiger erstellen
        $xCoord = MouseGetPos( 0 )
        $yCoord = MouseGetPos( 1 )
    EndIf
    Local $tPOINT = DllStructCreate( $tagPOINT )
    DllStructSetData( $tPOINT, "X", $xCoord )
    DllStructSetData( $tPOINT, "Y", $yCoord )
    Local $tRECT = DllStructCreate( $tagRECT )
    DllStructSetData( $tRECT, "Left", $xCoord )
    DllStructSetData( $tRECT, "Top", $yCoord+1 )
    DllStructSetData( $tRECT, "Right", $xCoord )
    DllStructSetData( $tRECT, "Bottom", $yCoord+1 )
    $oIMenuPopup.Popup( $tPOINT, $tRECT, $MPPF_ALIGN_RIGHT )
    $oIMenuPopup2.Popup( $tPOINT, $tRECT, $MPPF_ALIGN_RIGHT )
;~  $oIMenuPopup2.SetSubMenu( $oIMenuPopup , 1 )



    ; 5 - MESSAGE HOOK  - ( messages to expand the submenus and other user interaction )
    Local $oIDeskBand
    $oIDeskBand = ObjCreateInterface( $pIDeskBand, $sIID_IDeskBand, $dtag_IDeskBand )
    $oIDeskBand.QueryInterface( $tRIID_IMenuBand, $pIMenuBand )
    $oIMenuBand = ObjCreateInterface( $pIMenuBand, $sIID_IMenuBand, $dtag_IMenuBand )
    If $idFavsProgsMenuMsgUnHook = 0 Then $idFavsProgsMenuMsgUnHook = GUICtrlCreateDummy()
    $hFavsProgsMenuMsg = DllCallbackRegister( "FavsProgsMenuMsg", "long", "int;wparam;lparam" )
    $hFavsProgsMenuMsgHook = _WinAPI_SetWindowsHookEx( $WH_MSGFILTER, DllCallbackGetPtr( $hFavsProgsMenuMsg ), 0, _WinAPI_GetCurrentThreadId() )

    Return 0

EndFunc




Func FavsProgsMenuMsg( $nCode, $wParam, $lParam )

;~  If $nCode <=  0 Then Return
;~  ConsoleWrite( $nCode & @CRLF )

    If $pIMenuBand Then  ; Falls das Menü noch existiert > Windowmessages auswerten

        $tFavsProgsMenuMsg = DllStructCreate( $tagMSG, $lParam )
        $msg = DllStructGetData( $tFavsProgsMenuMsg, "message" )
        if $msg = $WM_NULL OR $msg = $WM_PAINT OR $msg = $WM_TIMER  OR $msg = 0x0118 OR ( $msg > $WM_MOUSEFIRST AND $msg < $WM_XBUTTONDBLCLK ) Then  Return False   ; 0x0118 ~ WM_SYSTIMER

        ; TRANSLATE MESSAGE ( menü auffordern, die Nachricht auszuwerten )
        $i = $oIMenuBand.IsMenuMessage( $tFavsProgsMenuMsg )
        If $i >= 0 Then
            $tLRESULT = DllStructCreate( "lresult" )
            If $oIMenuBand.TranslateMenuMessage( $tFavsProgsMenuMsg, $tLRESULT ) = $S_OK Then Return True
        ElseIf $i = $E_FAIL Then
            ; The menu has exited the menu mode and can be destroyed
            $pIMenuBand = $NULL
            Return False
        EndIf
        Return False


    Else; Falls das Menü nicht mehr existiert

        If $hFavsProgsMenuMsg <> $NULL Then

        _GUICtrlMenu_DestroyMenu( $hFavsProgsMenu )
        _WinAPI_UnhookWindowsHookEx( $hFavsProgsMenuMsgHook )
;~      DllCallbackFree( $hFavsProgsMenuMsg )  ; Aufhänger, grund unbekannt

        EndIf

        Return False

    EndIf


EndFunc




    Func ObjCreateInterfaceEx( $sFunctionPrefix, $dtag_Interface, $fNoUnknown = False )
    ; ObjCreateInterfaceEx creates custom object defined with "dtag" interface description string.
    ; Main purpose of this function is to create custom objects that serve as event handlers for other objects.
    ; Registered callback functions (defined methods) are left for AutoIt to free at its convenience on exit.

        ; Original is _AutoItObject_ObjectFromDtag in AutoItObject.au3 by the AutoItObject-Team
        ; (http://www.autoitscript.com/forum/index.php?showtopic=110379, v1.2.8.3 in post 302)
        ; Modified by Ward (http://www.autoitscript.com/forum/index.php?showtopic=138372)

        If $fNoUnknown Then $dtag_Interface = "QueryInterface hresult(ptr;ptr*);AddRef ulong();Release ulong();" & $dtag_Interface ; Inherits from IUnknown
        Local $sMethods = StringTrimRight(StringReplace(StringRegExpReplace($dtag_Interface, "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1)
        If $sMethods = $dtag_Interface Then $sMethods = StringTrimRight(StringReplace(StringRegExpReplace($dtag_Interface, "\h*(\w+)\h*(;|;*\z)", "$1\|" & @LF), ";" & @LF, @LF), 1)
        $sMethods = StringReplace(StringReplace(StringReplace(StringReplace($sMethods, "object", "idispatch", 0, 1), "variant*", "ptr"), "hresult", "long"), "bstr", "ptr")

        Local $aMethods = StringSplit($sMethods, @LF, 3)
        Local $iUbound = UBound($aMethods)
        Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback

        Local $PtrSize = DllStructGetSize(DllStructCreate("ptr", 1))
        Local $AllocSize = $PtrSize * ($iUbound + 1)
        Local $AllocPtr = _WinAPI_CoTaskMemAlloc( $AllocSize )
        If @error Or $AllocPtr = 0 Then Return SetError(1, 0, 0)

        Local $tInterface = DllStructCreate("ptr[" & $iUbound + 1 & "]", $AllocPtr)
        If @error Then Return SetError(1, 0, 0)
        For $i = 0 To $iUbound - 1
            $aSplit = StringSplit($aMethods[$i], "|", 2)
            If UBound($aSplit) <> 2 Then ReDim $aSplit[2]
            $sNamePart = $aSplit[0]
            $sTagPart = $aSplit[1]
            $sMethod = $sFunctionPrefix & $sNamePart
            $aTagPart = StringSplit($sTagPart, ";", 2)
            $sRet = $aTagPart[0]
            $sParams = StringReplace($sTagPart, $sRet, "", 1)
            $sParams = "ptr" & $sParams
            $hCallback = Eval(":Callback:" & $sMethod)
            If Not $hCallback Then
                $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams)
                Assign(":Callback:" & $sMethod, $hCallback, 2)
            EndIf
            DllStructSetData($tInterface, 1, DllCallbackGetPtr($hCallback), $i + 2)
        Next
        DllStructSetData($tInterface, 1, $AllocPtr + $PtrSize) ; Interface method pointers are actually pointer size away
        Return $AllocPtr
    EndFunc



    Func SHGetPathFromIDList( $pidl, ByRef $sPath )
        Local $stPath = DllStructCreate( "wchar[" & $MAX_PATH & "]" )
        Local $aRet = DllCall( "shell32.dll", "int", "SHGetPathFromIDListW", "ptr", $pidl, "ptr", DllStructGetPtr( $stPath ) )
        If @error Then Return SetError(1, 0, 0)
        $sPath = DllStructGetData( $stPath, 1 )
        Return $aRet[0]
    EndFunc



    Func StrRetToBuf( $pSTRRET, $pidl, ByRef $sBuf, $iBuf = 512 )
        Local $aRet = DllCall( "shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sBuf, "uint", $iBuf )
        If @error Then Return SetError(1, 0, 0)
        $sBuf = $aRet[3]
        Return $aRet[0]
    EndFunc





#region CALLBACK


    Func oIShellMenuCallback_CallbackSM( $pSelf, $psmd, $uMsg, $wParam, $lParam )

        ;ConsoleWrite( "oIShellMenuCallback_CallbackSM" & @CRLF )
        Local $pIShellFolder, $oIShellFolder


        ; SMC_XXX messages and notifications
        ;~  $SMC_INITMENU                = 0x00000001
        ;~  $SMC_CREATE                  = 0x00000002
        ;~  $SMC_EXITMENU                = 0x00000003
        ;~  $SMC_GETINFO                 = 0x00000005
        ;~  $SMC_GETSFINFO               = 0x00000006
        ;~  $SMC_GETOBJECT               = 0x00000007
        ;~  $SMC_GETSFOBJECT             = 0x00000008
        ;~  $SMC_SFEXEC                  = 0x00000009
            $SMC_SFSELECTITEM            = 0x0000000A
        ;~  $SMC_REFRESH                 = 0x00000010
        ;~  $SMC_DEMOTE                  = 0x00000011
        ;~  $SMC_PROMOTE                 = 0x00000012
        ;~  $SMC_DEFAULTICON             = 0x00000016
        ;~  $SMC_NEWITEM                 = 0x00000017
        ;~  $SMC_CHEVRONEXPAND           = 0x00000019
        ;~  $SMC_DISPLAYCHEVRONTIP       = 0x0000002A
        ;~  $SMC_SETSFOBJECT             = 0x0000002D
        ;~  $SMC_SHCHANGENOTIFY          = 0x0000002E
        ;~  $SMC_CHEVRONGETTIP           = 0x0000002F
        ;~  $SMC_SFDDRESTRICTED          = 0x00000030
        ;~  $SMC_SFEXEC_MIDDLE           = 0x00000031
        ;~  $SMC_GETAUTOEXPANDSTATE      = 0x00000041
        ;~  $SMC_AUTOEXPANDCHANGE        = 0x00000042
        ;~  $SMC_GETCONTEXTMENUMODIFIER  = 0x00000043
        ;~  $SMC_GETBKCONTEXTMENU        = 0x00000044
        ;~  $SMC_OPEN                    = 0x00000045


            $SHGDN_NORMAL        = 0x0000
        ;~  $SHGDN_INFOLDER      = 0x0001
        ;~  $SHGDN_FOREDITING    = 0x1000
        ;~  $SHGDN_FORADDRESSBAR = 0x4000
        ;~  $SHGDN_FORPARSING    = 0x8000

        Switch $uMsg

                Case $SMC_SFSELECTITEM  ;SESESESESESESESESESESESESESESESESESE   SELECTED  SESESESESESESESESESESESESESESESESESESESESESE

                    $tagSMDATA = "dword dwMask;dword dwFlags;handle hmenu;hwnd hwnd;uint uId;uint UIDParent;uint uIdAncestor;ptr punk;ptr pidlFolder;ptr pidlItem;ptr psf;ptr pvUserData"   ; SMDATA struct
                    Local $tSMDATA = DllStructCreate( $tagSMDATA, $psmd )
                    ; New IShellFolder interface?
                    $pIShellFolder = DllStructGetData( $tSMDATA, "psf" )
                    For $i = 0 To $iIShellFolder - 1
                        If $pIShellFolder = $apIShellFolder[$i] Then ExitLoop
                    Next
                    If $i < $iIShellFolder Then
                        $oIShellFolder = $aoIShellFolder[$i]
                    Else
                        If Mod( $iIShellFolder, 10 ) = 0 Then
                            ReDim $apIShellFolder[$iIShellFolder+10]
                            ReDim $aoIShellFolder[$iIShellFolder+10]
                        EndIf
                        $apIShellFolder[$iIShellFolder] = $pIShellFolder
                        $oIShellFolder = ObjCreateInterface( $pIShellFolder, $sIID_IShellFolder, $dtag_IShellFolder )
                        $aoIShellFolder[$iIShellFolder] = $oIShellFolder
                        $iIShellFolder += 1
                    EndIf
                    ; Parent folder
                    Local $pParentFolder = DllStructGetData( $tSMDATA, "pidlFolder" ), $sPath
                    SHGetPathFromIDList( $pParentFolder, $sPath )
                    ; Current file or folder

                    Local $tSTRRET = DllStructCreate( "uint uType;ptr data;" ), $sName
                    $oIShellFolder.GetDisplayNameOf( DllStructGetData( $tSMDATA, "pidlItem" ), $SHGDN_NORMAL, $tSTRRET )
                    StrRetToBuf( DllStructGetPtr( $tSTRRET ), $NULL, $sName )

                    ; Full path

                    $fullPath = StringReplace(  $sPath & "\" & $sName , "\\" , "\"  )
                    ConsoleWrite( $fullPath & @CRLF )

                    Return $S_FALSE

            Case Else

                Return $S_FALSE
        EndSwitch

    EndFunc


    Func oIShellMenuCallback_QueryInterface( $pSelf, $pRIID, $pObj )
        Return $E_NOTIMPL
    EndFunc

    Func oIShellMenuCallback_AddRef( $pSelf )  ; neues Untermenü erstellen
        ConsoleWrite( "oIShellMenuCallback_AddRef" & @CRLF )
        $iIShellMenuCallback_Ref = 0
        $iIShellMenuCallback_Ref += 1
        Return $iIShellMenuCallback_Ref
    EndFunc

    Func oIShellMenuCallback_Release( $pSelf )
        ConsoleWrite( "oIShellMenuCallback_Release" & @CRLF )
        $iIShellMenuCallback_Ref = 0
        $iIShellMenuCallback_Ref -= 1
        Return $iIShellMenuCallback_Ref
    EndFunc


#endregion CALLBACK




#region CALLBACK 2


    Func oIShellMenuCallback2_CallbackSM( $pSelf, $psmd, $uMsg, $wParam, $lParam )

        ;ConsoleWrite( "oIShellMenuCallback_CallbackSM" & @CRLF )
        Local $pIShellFolder, $oIShellFolder


        ; SMC_XXX messages and notifications
        ;~  $SMC_INITMENU                = 0x00000001
        ;~  $SMC_CREATE                  = 0x00000002
        ;~  $SMC_EXITMENU                = 0x00000003
        ;~  $SMC_GETINFO                 = 0x00000005
        ;~  $SMC_GETSFINFO               = 0x00000006
        ;~  $SMC_GETOBJECT               = 0x00000007
        ;~  $SMC_GETSFOBJECT             = 0x00000008
        ;~  $SMC_SFEXEC                  = 0x00000009
            $SMC_SFSELECTITEM            = 0x0000000A
        ;~  $SMC_REFRESH                 = 0x00000010
        ;~  $SMC_DEMOTE                  = 0x00000011
        ;~  $SMC_PROMOTE                 = 0x00000012
        ;~  $SMC_DEFAULTICON             = 0x00000016
        ;~  $SMC_NEWITEM                 = 0x00000017
        ;~  $SMC_CHEVRONEXPAND           = 0x00000019
        ;~  $SMC_DISPLAYCHEVRONTIP       = 0x0000002A
        ;~  $SMC_SETSFOBJECT             = 0x0000002D
        ;~  $SMC_SHCHANGENOTIFY          = 0x0000002E
        ;~  $SMC_CHEVRONGETTIP           = 0x0000002F
        ;~  $SMC_SFDDRESTRICTED          = 0x00000030
        ;~  $SMC_SFEXEC_MIDDLE           = 0x00000031
        ;~  $SMC_GETAUTOEXPANDSTATE      = 0x00000041
        ;~  $SMC_AUTOEXPANDCHANGE        = 0x00000042
        ;~  $SMC_GETCONTEXTMENUMODIFIER  = 0x00000043
        ;~  $SMC_GETBKCONTEXTMENU        = 0x00000044
        ;~  $SMC_OPEN                    = 0x00000045


            $SHGDN_NORMAL        = 0x0000
        ;~  $SHGDN_INFOLDER      = 0x0001
        ;~  $SHGDN_FOREDITING    = 0x1000
        ;~  $SHGDN_FORADDRESSBAR = 0x4000
        ;~  $SHGDN_FORPARSING    = 0x8000

        Switch $uMsg

                Case $SMC_SFSELECTITEM  ;SESESESESESESESESESESESESESESESESESE   SELECTED  SESESESESESESESESESESESESESESESESESESESESESE

                    $tagSMDATA = "dword dwMask;dword dwFlags;handle hmenu;hwnd hwnd;uint uId;uint UIDParent;uint uIdAncestor;ptr punk;ptr pidlFolder;ptr pidlItem;ptr psf;ptr pvUserData"   ; SMDATA struct
                    Local $tSMDATA = DllStructCreate( $tagSMDATA, $psmd )
                    ; New IShellFolder interface?
                    $pIShellFolder = DllStructGetData( $tSMDATA, "psf" )
                    For $i = 0 To $iIShellFolder - 1
                        If $pIShellFolder = $apIShellFolder[$i] Then ExitLoop
                    Next
                    If $i < $iIShellFolder Then
                        $oIShellFolder = $aoIShellFolder[$i]
                    Else
                        If Mod( $iIShellFolder, 10 ) = 0 Then
                            ReDim $apIShellFolder[$iIShellFolder+10]
                            ReDim $aoIShellFolder[$iIShellFolder+10]
                        EndIf
                        $apIShellFolder[$iIShellFolder] = $pIShellFolder
                        $oIShellFolder = ObjCreateInterface( $pIShellFolder, $sIID_IShellFolder, $dtag_IShellFolder )
                        $aoIShellFolder[$iIShellFolder] = $oIShellFolder
                        $iIShellFolder += 1
                    EndIf
                    ; Parent folder
                    Local $pParentFolder = DllStructGetData( $tSMDATA, "pidlFolder" ), $sPath
                    SHGetPathFromIDList( $pParentFolder, $sPath )
                    ; Current file or folder

                    Local $tSTRRET = DllStructCreate( "uint uType;ptr data;" ), $sName
                    $oIShellFolder.GetDisplayNameOf( DllStructGetData( $tSMDATA, "pidlItem" ), $SHGDN_NORMAL, $tSTRRET )
                    StrRetToBuf( DllStructGetPtr( $tSTRRET ), $NULL, $sName )

                    ; Full path

                    $fullPath = StringReplace(  $sPath & "\" & $sName , "\\" , "\"  )
                    ConsoleWrite( $fullPath & @CRLF )

                    Return $S_FALSE

            Case Else

                Return $S_FALSE
        EndSwitch

    EndFunc


    Func oIShellMenuCallback2_QueryInterface( $pSelf, $pRIID, $pObj )
        Return $E_NOTIMPL
    EndFunc

    Func oIShellMenuCallback2_AddRef( $pSelf )  ; neues Untermenü erstellen
        ConsoleWrite( "oIShellMenuCallback2_AddRef" & @CRLF )
        $iIShellMenuCallback_Ref = 0
        $iIShellMenuCallback_Ref += 1
        Return $iIShellMenuCallback_Ref
    EndFunc

    Func oIShellMenuCallback2_Release( $pSelf )
        ConsoleWrite( "oIShellMenuCallback2_Release" & @CRLF )
        $iIShellMenuCallback_Ref = 0
        $iIShellMenuCallback_Ref -= 1
        Return $iIShellMenuCallback_Ref
    EndFunc


#endregion CALLBACK 2

ContexMenuBrowser.au3

Edited by Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

Why on earth do you think you can put menus together in that way? What you can do is to add a Recent Folders menu to the static part of the menu. The menu you are using in SetMenu. You can do this with the usual functions in GuiMenu.au3. Add the folders to the static menu before you call SetMenu.

Link to comment
Share on other sites

Sorry that was just a guess. I thought if one can append it to another menu, then the purpose of this must be to append multiple menus.

Are you absolutly sure this is not possible? If so I would have to find a workaround with the static part of the menu of course, but I see some disadvantages.

However you are the expert and I trust your word and start implementing the static solution.

Thanks.

Blues

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

  • 1 month later...

Hello LarsJ,

Do you think those menus will work for virtual folder too? ( like the control panel  = )

I cannot try because I dunno how to get the PIDL of such a folder as:

$r = DllCall( "shell32.dll" , "uint", "SHILCreateFromPath", "wstr",   $targetFolder  , "ptr*", 0, "dword*", 0 )

only works with paths. And virtual folders only got CLSIDS as far as I know.

Do you know a CLSID > PIDL method? Or any other suggestion?

Thank you

PS: CLSID for control panel:

ShellExecute( "explorer" , "shell:::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a}" )
Edited by Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

_WinAPI_ShellGetKnownFolderIDList will get the PIDL.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb762187(v=vs.85).aspx

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...