Forum > Windows

Cmd annoyance and a solution

(1/6) > >>

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

Go to full version