0

I'm writing myself a GUI utility for use in a CMD window to navigate between folders, rather in the style of the old Norton Change Directory utility for DOS.

When run, the app pops up a folder tree to allow the user to select a folder to which to navigate and then closes and returns to the CMD prompt. At the moment, the way it works is that it is run as the first command in a "main" batch file. It writes a secondary batch file, in my app's folder under AppData, containing the commands to change drive and directory to the folder the user selected, and the main batch file then invokes this second batch file using CALL.

It works fine, but this way of actually changing the CMD window's current directory strikes me as inelegant both from the point of view of needing to be run from a batch file (so that the user's selection can be acted upon after my app has closed) and of needing the secondary batch file to do the actual navigation.

So, my question is, how can my app send the instructions to the instance of CMD that owns the window in which the app is run to the folder the user selected? I've tried doing a ShellExecute of "CMD /K ..." but although that does indeed navigate to the selected folder, it does so in a new CMD window, not the one my app is run in. The conceptual gap I have is how to get the current CMD to act on my app's instructions after my app has terminated.

Fwiw, I thought of trying to write the user's folder selection into an environment variable in the CMD window's environment for the CMD processor to act upon from there, but this seems to require that the CMD window be opened via "Run as Administrator", which I definitely don't want.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • I can't get what you mean with "how to get the current CMD to act on my app's instructions **after** my app has terminated". How should it act? – fantaghirocco Nov 12 '15 at 15:45
  • why not simply output to the cmd `WriteLn(Format('cd "%s"', [the_selected_directory]))` when your app closes? ` – fantaghirocco Nov 12 '15 at 15:53
  • Well, if I try to change the current directory from within my app, it seems to have no effect on the current directory of the CMD window after my app has terminated -it's as if the "current directory" in the CMD window reverts to whatever it was before my app ran. So it seems to me that I need to get the CMD instance which is "hosting" the window to change directory – MartynA Nov 12 '15 at 15:53
  • "why not simply output to the cmd" because that has no effect whatever in or on the CMD window the app is run in. – MartynA Nov 12 '15 at 15:57
  • @MartynA Is you program opening the console window or is it started from within the console window by specific command? – SilverWarior Nov 12 '15 at 16:08
  • You could send keystrokes to the CMD window. I just made a small test with a timer of 5000 ms. the CMD window was the active one. and I used: `v := CreateOleObject('WScript.Shell'); v.SendKeys('Hello!');` (Tested on XP) – kobik Nov 12 '15 at 16:08
  • @SilverWarior: It runs in an already-open CMD window, by entring the name of the "main" batch file I mention in the q. – MartynA Nov 12 '15 at 16:09
  • this should give some oxigen: http://stackoverflow.com/questions/18159741/how-do-i-write-to-stdout-from-a-gui-app-started-from-the-command-line – fantaghirocco Nov 12 '15 at 16:11
  • @kobik Thanks, I'll maybe try that, but tbh I was hoping for something a bit more, err, ... – MartynA Nov 12 '15 at 16:12
  • I'm curious about the down-vote. A heads-up from the voter to say what's wrong with the q would be good. – MartynA Nov 13 '15 at 10:36
  • Thanks for asking the question! This has puzzled me every time I need to use the cmd and 'cd' through paths I never remember. With Robs answer I now have a much simpler way of wading through the paths. – Tom Brunberg Nov 14 '15 at 19:32
  • Thanks @TomBrunberg. What prompted me to do try this is that I prefer cruising around from the CMD prompt but it would drive me nuts having to surround paths with embedded spaces with dbl-quote marks, though they seem to have fixed that in Win10. I assume it's your +1 which offset the down-vote, thanks. Still no heads-up from the downvoter needless to say. – MartynA Nov 14 '15 at 19:46

1 Answers1

2

Your program cannot influence the environment variables of the command interpreter because they're separate processes. Your program cannot change the directory of the command interpreter directly, either, because, again, they're separate processes.

You need to use a batch file because the command interpreter executes batch files internally. Since it's all the same process, the batch file has the power to change the current directory, and for that change to remain in effect after the batch file finishes running.

Therefore, you need some way for your interactive program to communicate the directory selection back to the batch file so that it can act on it.

Instead of writing the instructions to another batch file, you could write the result to standard output. Have the batch file capture that output into a variable, and then execute cd on that variable. The batch code would look something like this:

for /f "tokens=*" %%a in ('[select_dir.exe]') do (
  set DIRSELECTION=%%a
)
cd /d %DIRSELECTION%

Your Delphi code would look like this:

writeln(selected_dir);

To allow that command to work, you'll need to make sure your program is marked as a console program, as with {$APPTYPE CONSOLE}. If it's not, then the batch file won't receive any output, and probably won't even wait for your program to finish running before proceeding. It's OK for a console program to display a TForm, just like a GUI program.

Community
  • 1
  • 1
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Thanks for that, I'll give it a whirl. I must admit, I've never had occasion to use "for /f tokens ..." except maybe messing around with the examples in Neil Rubenking's marvellous "DOS Batch File Lab Notes" book. – MartynA Nov 12 '15 at 16:22