Forum > Windows
Cmd annoyance and a solution
GetMem:
When I open cmd(command promt) it's defaulting to the user(or system32) folder, which is fine, but then I have to use the cd command to go to a particular folder. Typing a folder path or even copy pasting takes time and it's annoying. Some linux distroes solved this issue by adding the "Open in terminal" item to the context menu, which opens the current folder from the file explorer. Very nicely done penguin!
The attached project, a shell extension dll, will do the same for windows:
- download, extract attachment
- build the dll, make sure Lazarus/FPC bitness is the same as your windows bitness
- run cmd "As admin", cd to the dll folder, then type: "Regsvr32 OpenFolderInCmdShell.dll" without quotes
- if the registration was successfull, go to a random folder with file explorer, right click the empty space or a subfolder. The following menu item should be visible in the context menu: "Open folder in cmd"(see attached image)
Tested with Lazarus trunk/FPC 3.2.2(64 bit) on windows 10. To unregister the dll, type: "Regsvr32 /u OpenFolderInCmdShell.dll" in the command prompt, then press enter.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit OpenFolderInCmd; interface uses Windows, ActiveX, ComObj, ShlObj, ShellApi; type TOpenFolderInCmd = class(TComObject, IUnknown, IContextMenu, IShellExtInit) private FPath: WideString; function ShellGetPathFromIdListW(APItemIdList: PItemIdList): WideString; protected function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall; function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall; function GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; stdcall; function IShellExtInit.Initialize = InitShellExt; function InitShellExt (pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; stdcall; end; TOpenFolderInCmdFactory = class(TComObjectFactory) public procedure UpdateRegistry (Register: Boolean); override; end; const cName = 'OpenFolderInCmd'; cMenuCaption = 'Open folder in cmd'; cMenuHelp = 'Open current folder in command prompt'; cGUID: TGUID = '{55639E10-A032-4E22-B039-882E3BCCA67C}'; implementation uses ComServ, SysUtils, Registry; function TOpenFolderInCmd.InitShellExt(pidlFolder: PItemIDList; lpdobj: IDataObject; hKeyProgID: HKEY): HResult; stdcall;var medium: TStgMedium; fe: TFormatEtc;begin Result := NOERROR; if lpdobj <> nil then begin with fe do begin cfFormat := CF_HDROP; ptd := nil; dwAspect := DVASPECT_CONTENT; lindex := -1; tymed := TYMED_HGLOBAL; end; Result := lpdobj.GetData(fe, medium); if not Failed (Result) then begin if DragQueryFileW(medium.hGlobal, $FFFFFFFF, nil, 0) = 1 then begin SetLength(FPath, 1000); DragQueryFileW(medium.hGlobal, 0, PWideChar(FPath), 1000); FPath := PWideChar(FPath); if not DirectoryExists(FPath) then Result := E_FAIL end else Result := E_FAIL; end; ReleaseStgMedium(medium); end else FPath := ShellGetPathFromIdListW(pidlFolder);end; function TOpenFolderInCmd.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; stdcall;begin InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst, cMenuCaption); Result := 1;end; function TOpenFolderInCmd.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;var Drv: WideString; Cmd: WideString;begin Result := NOERROR; if HiWord(LongInt(lpici.lpVerb)) <> 0 then begin Result := E_FAIL; Exit; end; if LoWord(LongInt(lpici.lpVerb)) > 0 then begin Result := E_INVALIDARG; Exit; end; if LoWord(LongInt(lpici.lpVerb)) = 0 then begin FPath := IncludeTrailingBackslash(FPath); Drv := ExtractFileDrive(FPath); FPath := '"' + FPath + '"'; Cmd := '/K ' + Drv + ' && CD ' + FPath; ShellExecuteW(0, 'runas', 'cmd.exe', PWideChar(Cmd), PWideChar(FPath), SW_SHOWNORMAL); end;end; function TOpenFolderInCmd.GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; stdcall;begin if (idCmd = 0) and (uFlags = GCS_HELPTEXT) then begin StrLCopy(pszName, cMenuHelp, cchMax); Result := NOERROR; end else Result := E_INVALIDARG;end; function TOpenFolderInCmd.ShellGetPathFromIdListW(APItemIdList: PItemIdList): WideString;var sz: array[ 0..MAX_PATH ] of WideChar; w: Word;begin if (APItemIdList = nil) then begin w := 0; APItemIdList := Pointer(@w); end; if SHGetPathFromIdListW(APItemIdList, @sz[0]) then SetString(Result, sz, Strlen(sz)) else Result := '';end; procedure TOpenFolderInCmdFactory.UpdateRegistry(Register: Boolean);var Reg: TRegistry;begin inherited UpdateRegistry (Register); Reg := TRegistry.Create; Reg.RootKey := HKEY_CLASSES_ROOT; try if Register then begin if Reg.OpenKey('\*\ShellEx\ContextMenuHandlers\' + cName, True) then Reg.WriteString('', GUIDToString(cGUID)); if Reg.OpenKey('\Directory\Background\ShellEx\ContextMenuHandlers\' + cName, True) then Reg.WriteString('', GUIDToString(cGUID)); if Reg.OpenKey('\Directory\shellex\ContextMenuHandlers\' + cName, True) then Reg.WriteString('', GUIDToString(cGUID)); if Reg.OpenKey('\Drive\shellex\ContextMenuHandlers\' + cName, True) then Reg.WriteString('', GUIDToString(cGUID)); end else begin if Reg.OpenKey('\*\ShellEx\ContextMenuHandlers\' + cName, False) then Reg.DeleteKey ('\*\ShellEx\ContextMenuHandlers\' + cName); if Reg.OpenKey('\Directory\Background\shellex\ContextMenuHandlers\' + cName, False) then Reg.DeleteKey ('\Directory\Background\shellex\ContextMenuHandlers\' + cName); if Reg.OpenKey('\Directory\shellex\ContextMenuHandlers\' + cName, False) then Reg.DeleteKey ('\Directory\shellex\ContextMenuHandlers\' + cName); if Reg.OpenKey('\Drive\shellex\ContextMenuHandlers\' + cName, False) then Reg.DeleteKey ('\Drive\shellex\ContextMenuHandlers\' + cName); end; finally Reg.CloseKey; Reg.Free; end;end; initialization TOpenFolderInCmdFactory.Create (ComServer, TOpenFolderInCmd, cGUID, cName, cMenuCaption, ciMultiInstance, tmApartment); end.
dseligo:
Nice example, I have to try it.
But: don't you already have 'Open in terminal' when you right click (or Shift + Right click) in empty space in Windows explorer?
GetMem:
@dseligo
--- Quote ---But: don't you already have 'Open in terminal' when you right click (or Shift + Right click) in empty space in Windows explorer?
--- End quote ---
I don't have any command prompt related item(s) in the context menu, only "Open PowerShell window here" (Shift + Right click), but PowerShell it's a different beast.
domasz:
--- Quote from: dseligo on February 09, 2023, 12:18:49 pm ---Nice example, I have to try it.
But: don't you already have 'Open in terminal' when you right click (or Shift + Right click) in empty space in Windows explorer?
--- End quote ---
You must have installed something. Win 7 and Win 10 do not come with such an option out of the box.
dseligo:
--- Quote from: GetMem on February 09, 2023, 01:28:16 pm ---@dseligo
--- Quote ---But: don't you already have 'Open in terminal' when you right click (or Shift + Right click) in empty space in Windows explorer?
--- End quote ---
I don't have any command prompt related item(s) in the context menu, only "Open PowerShell window here" (Shift + Right click), but PowerShell it's a different beast.
--- End quote ---
I think you can change somewhere (maybe in registry) to open cmd instead of Powershell (I have both on right click in one W10 installation).
In W11 this got improved. It is very customizable, you can have more sessions in one tabbed window, more profiles in context menu...
Navigation
[0] Message Index
[#] Next page