17

Creating a Windows Shell context menu item that takes a single file as an argument is easy. See this question for an example.

However, how do you create a context menu item that takes multiple files as arguments? Say, for a diff-merge tool (in my case P4Merge), although the same technique would no doubt be applicable for other applications as well.

I've installed P4Merge but it does not add an item to the context menu automatically so I will have to do it manually.

When I tried using:

"C:\Program Files\Perforce\p4merge.exe" %1 %2

as the command line I got an error:

Errors: At least two files are needed. Cannot open only one file. P4Merge needs 0, 2, or 3 files.

When I tried using:

"C:\Program Files\Perforce\p4merge.exe" %0 %1

as the command line it opened two instances of P4Merge, one for each file.

It appears the correct file names are being passed through to %0 and %1 but a different instance of the P4Merge application is being executed for each one.

I currently have SourceGear's DiffMerge tool which has an item on the Shell context menu and that works beautifully, as I am able to select two files and use the context menu item to run a diff on them. I've trying searching the registry to see what arguments DiffMerge uses but I could not find a DiffMerge commandline that included arguments.

Simon Elms
  • 1,025

4 Answers4

28

You can also try adding the program to the SendTo menu.

surfasb
  • 22,896
7

Browsing for the answer it seems that there is no simple fix and that a shell extension is needed. Looking again at the registry entries for DiffMerge, it appears to use a shell extension: DiffMergeShellExtension64.dll. If P4Merge does not have such a shell extension then it looks like the only way I could get it working correctly in the Windows Explorer context menu would be to write one myself.

The Complete Idiot's Guide to Writing Shell Extensions series in Code Project is a useful guide to writing shell extensions. Part II of the series is about writing an extension that handles multiple files at once (exactly what I need).

Warning: The Complete Idiot's Guide to Writing Shell Extensions uses C and COM, ATL (Active Template Library) and MFC (Microsoft Foundation Classes). So writing a shell extension, if you're not familiar with those technologies, is going to be a long and potentially difficult process; it's definitely not something you can do in an hour.

Simon Elms
  • 1,025
6

You can do it with my program context-menu-launcher (singleinstance):

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\SystemFileAssociations\.txt\Shell\p4merge]
"MultiSelectModel"="Player"

[HKEY_CLASSES_ROOT\SystemFileAssociations\.txt\Shell\p4merge\Command]
@="\"d:\\singleinstance.exe\" %1 \"C:\\Program Files\\Perforce\\p4merge.exe\" $files --si-timeout 400"
zenden2k
  • 160
0

SUMMARY

  1. In Registry put the target program as Context Menu Create File.exe which writes reg.txt file.

  2. In your main program loop every 1 second to check if reg.txt exists. If it exists, kill the Context Menu Create File.exe and delete the reg.txt file. Then copy the selected file paths and manipulate with them.

  3. If your program loops to check for reg.txt, then you need to start the program before executing context menu either on startup or manually.

I did this with AutoHotkey.

These 2 AutoHotkey scripts below allow you to add a P4 Merge Compare context menu item in Windows Explorer to open multiple selected files.

You can leave all variable values as they are, but if you want to change the contextMenu value and program name then see 3.1.

INSTRUCTIONS:

Create 2 files in the same directory:

  1. Create 1st program Add To Context Menu And Create Startup Shortcut.ahk

    1. RunAsAdmin Label ensures that the script runs as admin (fixes adding Registry values).

      1. The If (!A_IsAdmin) checks if current user is NOT admin, A_IsAdmin is a built in AutoHotkey variable that returns 1 if user is admin, 0 otherwise.
      2. Run, \*RunAs "%A_ScriptFullPath%" *RunAs parameter runs the script as admin, "%A_ScriptFullPath%" gets the full path of the current executing script.
      3. ExitApp exits the current script instance running without admin privileges.
      4. Because the Run command runs the script again with admin privileges it will skip the IF condition and continue executing code below.
    2. ContextMenuCreateFile: Label creates a Context Menu Create File.exe which creates a file reg.txt and exits Context Menu Create File.exe after it has written the file reg.txt. Make sure you specify where your Ahk2Exe.exe path is in the RunWait command.

    3. Add To Context Menu: Label adds the Registry entry which runs Context Menu Create File.exe.

      1. Set the contextMenu variable to what needs to be displayed in the Context Menu. (The program name is set to contextMenu)
      2. Set the regPath to your desired Registry path.
      3. When it executes the MsgBox, check if the command is added to the Registry in the address bar.
    4. CreateStartupShortcut: Label creates the shortcut of the main program P4 Merge Compare.exe in Startup folder.

Add To Context Menu And Create Startup Shortcut.ahk

; =============Recommended Settings=============
#NoEnv
SetWorkingDir %A_ScriptDir%
#Warn
CoordMode, Mouse, Window
SendMode Input
#SingleInstance Force
SetTitleMatchMode 2
SetTitleMatchMode Fast
DetectHiddenWindows Off
DetectHiddenText On
#WinActivateForce
#NoTrayIcon
SetControlDelay 1
SetWinDelay 0
SetKeyDelay -1
SetMouseDelay -1
SetBatchLines -1
#Persistent
#MaxThreadsPerHotkey 2
; =============Recommended Settings=============

AddToContextMenuAndCreateStartupShortcut: RunAsAdmin: ; =============RunAsAdmin============= If (!A_IsAdmin) ; IF NOT Admin { Run, *RunAs "%A_ScriptFullPath%" ; Run script as admin ExitApp ; Exit the current instance running without admin privileges } ContextMenuCreateFile: ; =============ContextMenuCreateFile============= contextMenuCreateFileAhk := (LTrim "#NoEnv #NoTrayIcon #SingleInstance Force SetWorkingDir %A_ScriptDir% SetBatchLines -1

ContextMenuCreateFile: FileDelete, reg.txt FileAppend, , reg.txt ExitApp Return" ) ; contextMenuCreateFileAhk FileDelete, Context Menu Create File.exe ; DEL Context Menu Create File.exe FileDelete, Context Menu Create File.ahk ; DEL Context Menu Create File.ahk FileAppend, %contextMenuCreateFileAhk%, Context Menu Create File.ahk ; MAKE Context Menu Create File.ahk RunWait, C:\Program Files\AutoHotkey\Compiler\Ahk2Exe.exe /in "Context Menu Create File.ahk" /out "Context Menu Create File.exe" ; Convert AHK to EXE FileDelete, Context Menu Create File.ahk ; DEL Context Menu Create File.ahk AddToContextMenu: ; =============AddToContextMenu============= path := "" ; path program := "Context Menu Create File" ; program contextMenu := "P4 Merge Compare" ; contextMenu regPath := "HKCR*\shell" ; regPath StringReplace, regKey, contextMenu, %A_Space%, , A ; regKey regKey := 0 regKey ; regKey Loop, Files, %program%.exe, F ; Find Program.exe In Current Dir { path := A_LoopFileLongPath ; Set Program Path } cmd := (LTrim "reg add """ regPath "" regKey """ /ve /t REG_SZ /d """ contextMenu """ /f reg add """ regPath "" regKey "\command"" /ve /t REG_SZ /d """"" path """`"" /f" ) ; Registry FileDelete, Add To Context Menu.bat ; CREATE Add To Context Menu.bat FileAppend, %cmd%, Add To Context Menu.bat ; CREATE Add To Context Menu.bat RunWait, Add To Context Menu.bat, , Hide ; RUN Add To Context Menu.bat (*RunAs ADMIN) FileDelete, Add To Context Menu.bat ; DEL Add To Context Menu.bat Run, regedit ; regedit WinWait, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; Registry Sleep, 333 ControlSetText, Edit1, %regPath%%regKey%\command, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; regPath ControlFocus, Edit1, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; regPath ControlSend, Edit1, {Enter}, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; regPath ControlSend, SysListView321, {Control Down}{NumpadAdd}{Control Up}, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; regPath ControlSend, SysListView321, {F5}, Registry Editor ahk_class RegEdit_RegEdit ahk_exe regedit.exe ; regPath MsgBox, 262192, CHECK, Check If Added %contextMenu% To Registry ; CHECK CreateStartupShortcut: ; =============CreateStartupShortcut============= path := "" ; path program := contextMenu ; program Loop, Files, %program%.exe, F ; Find Program.exe In Current Dir { path := A_LoopFileLongPath ; Set Program Path } FileCreateShortcut, %path%, %A_Startup%%program%.lnk ; Create Startup Shortcut Run, %A_Startup%, , Max ; Check If Shortcut Created Run, "%program%.exe" ; Run Program MsgBox, 262144, CHECK, Check If Shortcut Created ; CHECK ExitApp ; ExitApp Return

  1. Create 2nd program P4 Merge Compare.ahk which is the main program.
    1. Here a Loop is created and checks every 1 second if reg.txt exists.
    2. IfExist, reg.txt it kills the Context Menu Create File.exe and deletes the reg.txt.
    3. Then it activates explorer.exe window and copies all selected file paths to CLIPBOARD.
    4. If CLIPBOARD contains .,\ to make sure CLIPBOARD contains path "\" with extension ".".
    5. The list of selected files is saved in selectedFiles variable.
    6. The Loop below p4Params := "" loops through selected files, gets the filePaths.
    7. Then the filePath is concatenated to p4Params.
    8. StringTrimRight removes the last space from p4Params string.
    9. Then Run, C:\Program Files\Perforce\p4merge.exe %p4Params% is executed with %p4Params% (list of selected files).

P4 Merge Compare.ahk

; =============Recommended Settings=============
#NoEnv
SetWorkingDir %A_ScriptDir%
#Warn
CoordMode, Mouse, Window
SendMode Input
#SingleInstance Force
SetTitleMatchMode 2
SetTitleMatchMode Fast
DetectHiddenWindows Off
DetectHiddenText On
#WinActivateForce
#NoTrayIcon
SetControlDelay 1
SetWinDelay 0
SetKeyDelay -1
SetMouseDelay -1
SetBatchLines -1
#Persistent
#MaxThreadsPerHotkey 2
; =============Recommended Settings=============

P4MergeCompare: Loop ; Loop Start { Sleep, 1000 ; Fix High CPU IfExist, reg.txt ; IF reg.txt EXIST { RunWait, cmd /c taskkill /im "Context Menu Create File.exe" /f, , Hide ; Fix Opening 2 Compose Windows FileDelete, reg.txt ; DEL reg.txt WinActivate, ahk_class CabinetWClass ahk_exe explorer.exe ; Explorer CLIPBOARD := "" ; Clear Clipboard Send, {Control Down}{c}{Control Up} ; Copy File Paths ClipWait, 0 ; Clip Wait If CLIPBOARD contains .,\ ; IF CLIPBOARD contains .,
{ selectedFiles := CLIPBOARD ; selectedFiles p4Params := "" ; p4Params Loop, Parse, selectedFiles, n,r ; Loop Start selectedFiles { filePath := """" A_LoopField """" ; filePath p4Params .= filePath . " " ; p4Params .= %filePath%, } StringTrimRight, p4Params, p4Params, 1 ; Remove Last Space Run, C:\Program Files\Perforce\p4merge.exe %p4Params% ; Open Files In P4Merge } } } Return

  1. Convert both Add To Context Menu And Create Startup Shortcut.ahk and P4 Merge Compare.ahk to EXE files in the same directory using Ahk2Exe.exe --> (find in Start Menu, just browse file and hit convert)

  2. Execute the Add To Context Menu And Create Startup Shortcut.exe

  3. Select files, right click and the P4 Merge Compare context menu item should appear.