3

Has anyone ever written some delphi code that does what REGJUMP does?

Specifically, REGJUMP is a MS app that lets you open regedit to a specified path of values/keys (ready for viewing or editing in regedit). For example: regjump HKLM\Software\Microsoft\Windows will open regedit at the path HKLM\Software\Microsoft\Windows.

I tried:

ShellExecute(handle,'Open','C:\WINDOWS\regedit.exe', nil, nil, SW_SHOW);

Which of course only opens regedit to the last path you were looking at.

I tried:

ShellExecute(handle,'Open','C:\WINDOWS\regedit.exe', '[HKLM\Software\Microsoft\Windows]', nil, SW_SHOW);

but that attempts to import values to the path - and for various reasons fails miserably - and is not what I'm wanting to do anyway.

  • Doesn't look like there are command line options to do this. It looks to me as though this sysinternals tool automates the UI. You could do the same no doubt. But the question is off topic because it is a recommendation question. – David Heffernan Jan 13 '17 at 08:50
  • 1
    From Troubleshooting with the Windows Sysinternals Tools: *Window messages can be used to simulate mouse or keyboard activity.RegJump and the Jump To feature in Process Monitor and Autoruns do exactly this to navigate to a key in Regedit.* – Lieven Keersmaekers Jan 13 '17 at 09:31

2 Answers2

10

I think you will find the last registry key visited in Regedit is saved in the registry in the LastKey value under

HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\RegEdit

in Windows10 at least.

So, what I would try would be to write the value I want to visit to there before calling ShellExecute or whatever.

Sample code:

program RegJumpTest;

{$APPTYPE CONSOLE}

uses
  SysUtils, Registry;
var
  Reg : TRegistry;
  LastKey,
  KeyToFind,
  ValueToWrite : String;
begin
  ValueToWrite := ParamStr(1);
  KeyToFind := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Regedit';
  Reg := TRegistry.Create;
  if Reg.KeyExists(KeyToFind) then
    writeln('found ', KeyToFind)
  else
    writeln('not found ', KeyToFind);

  if Reg.OpenKey(KeyToFind, False) then
    writeln(KeyToFind, ' opened ok')
  else begin
    writeln('failed to open key: ', KeyToFind);
    Halt(1);
  end;
  LastKey := Reg.ReadString('LastKey');
  writeln('Last key: >', LastKey, '<');

  Reg.WriteString('LastKey', ValueToWrite);
  readln;
end.
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Now that's thinking outside the box! – MikeD Jan 13 '17 at 09:40
  • 1
    This works on Win7 also. but only for the first time if REGEDIT is not currently running, since REGEDIT runs single instance. maybe it needs to be close first. +1 – kobik Jan 13 '17 at 10:17
  • @kobik: Thanks for confirmation about Win7. Yes, I meant to mention to the OP not to expect this to necessarily work if Regedit is already running. – MartynA Jan 13 '17 at 10:38
  • This works perfectly (assuming regedit is not already running) - Thank you. For those searching for the code it basically means writing your needed path to LastKey as follows: if not Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Applets\RegEdit', True) then RaiseLastOSError; Reg.WriteString('LastKey', 'Computer\HKEY_CURRENT_USER\Software\MyCompany\MyApp\Settings'); – Owen Winter Jan 13 '17 at 10:57
0

Here is the code that does what you wanted. I have used it a long time ago and it is sitting in my helper units. Can't remember if I wrote it or reused it from somewhere else.

What it does it to search for Regedit's window, launch it if it is not running, and automate it by sending messages to simulate key presses for navigating the required key. Not a native solution as passing a command line param, but is working pretty well.

// Open Registry editor and go to the specified key
procedure JumpToRegKey(const aKey: string);
var
   I, J: Integer;
   hWin: HWND;
   ExecInfo: TShellExecuteInfo;
begin
   // Check if regedit is running and launch it if not
   // All the code below depends on specific window titles and classes, so it will fail if MS changes the Regedit app
   hWin := FindWindow(PChar('RegEdit_RegEdit'), nil);
   if hWin = 0 then
   begin
     ZeroMemory(@ExecInfo, sizeof(ExecInfo));
     with ExecInfo do
     begin
       cbSize := SizeOf(TShellExecuteInfo);
       fMask  := SEE_MASK_NOCLOSEPROCESS;
       Wnd := Application.Handle;
       lpVerb := PChar('open');
       lpFile := PChar('regedit.exe');
       nShow  := SW_SHOWMAXIMIZED;
     end;
     ShellExecuteEx(@ExecInfo);
     WaitForInputIdle(ExecInfo.hProcess, 200);
     hWin := FindWindow(PChar('RegEdit_RegEdit'), nil);
   end;

   if hWin <> 0 then
   begin
     ShowWindow(hWin, SW_SHOWMAXIMIZED);
     hWin := FindWindowEx(hWin, 0, PChar('SysTreeView32'), nil);
     SetForegroundWindow(hWin);
     // Collapse the tree first by sending a large number of Left arrow keys
     I := 30;
     repeat
       SendMessage(hWin, WM_KEYDOWN, VK_LEFT, 0);
       Dec(I);
     until I = 0;
     Sleep(100);
     SendMessage(hWin, WM_KEYDOWN, VK_RIGHT, 0);
     Sleep(100);
     I := 1;
     J := Length(aKey);
     repeat
       if aKey[I] = '\' then
       begin
         SendMessage(hWin, WM_KEYDOWN, VK_RIGHT, 0);
         Sleep(50);
       end
       else
         SendMessage(hWin, WM_CHAR, Integer(aKey[I]), 0);
       I := I + 1;
     until I = J;
   end;
end;

There is a limitation for the usage of this code, as kobik reminded. A non-elevated app can not send messages to an elevated one. Regedit is elevated, so the code can be used either if your app has elevated privileges, or if the UAC is turned off.
Otherwise it will launch the process(which will ask for approval) and find its window, but PostMessage will not work.

VGeorgiev
  • 491
  • 5
  • 16
  • 1
    You can't send messages to elevated process such RegEdit. have you tested this on Win7? – kobik Jan 13 '17 at 13:23
  • Yup, this is a limitation. For the code to work the caller has to be elevated, or UAC has to be turned off. It should not work if called from a non-elevated app. I'll add a note to the answer, thanks. – VGeorgiev Jan 13 '17 at 13:38