topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Sunday December 15, 2024, 2:49 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: Is it possible to change to working directory within the running programm?  (Read 10082 times)

crono

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 179
    • View Profile
    • Donate to Member
Hi all,

I have to write a tool which starts and runs on the shell (cmd.exe). It does some logic, takes some input from the user and finishes. Right before it finishes it should change the directory from which it was called. I have no clue if this is even possible. I tried to get the parent process and alter it this way, which results in crashes... 


C:\Home>my_tool.exe 
   ...doing some stuff...
   ...doing some stuff...
   ...doing some stuff...
   ...some user input....
   ...doing some stuff...
   ...finishing...
D:\Data\Documents>


Any Idea how to do this?

f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,153
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
What you want to do is change the working directory of the calling program, yes?

I dunno if this is possible to do in any clean way. Thing is, Current Working Directory is managed per-thread, not per-process. So the solution hack I'm thinking of would require finding your parent process (requires undocumented calls, iirc), locating the "correct thread", injecting code in the parent process to SetCurrentDirectory where you want, temporarily redirect the "correct thread" to this injected code, and then back to where it originally was.

Perhaps there's a cleaner way. A less hackish method would probably be running your tool from a batch file, and having the batch file CHDIR to the new folder.
- carpe noctem

crono

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 179
    • View Profile
    • Donate to Member
What you want to do is change the working directory of the calling program, yes?
Yes, this is what I would like to do.

I dunno if this is possible to do in any clean way.
I fear it is not :(, at least not in a clean way...

Thing is, Current Working Directory is managed per-thread, not per-process. So the solution hack I'm thinking of would require finding your parent process (requires undocumented calls, iirc)
I tried something in that way. It is very very very slow  :down:
Code: C# [Select]
  1. string pName = Process.GetCurrentProcess().ProcessName.ToString();
  2. Process[] pList = Process.GetProcessesByName(pName);
  3. // Getting the Process ID
  4. PerformanceCounter PID = new PerformanceCounter("Process", "ID Process", pName);
  5.  
  6. // Getting the Parent Process ID
  7. PerformanceCounter PPID = new PerformanceCounter("Process", "Creating Process ID", pName);
  8.  
  9. // Getting the Precess
  10. Process p = Process.GetProcessById(int.Parse(PPID.NextValue().ToString()));
  11.  
  12. //trying to change the Dir... - which results in a Crash...
  13. p.StandardInput.WriteLine("CD {0}",path);


A less hackish method would probably be running your tool from a batch file, and having the batch file CHDIR to the new folder.
This is a really good Idea and would be perfect if the Directory after finishing would be always the same (it is not), but how can I redirect only the last program Output to the Batchfile instead of all Output. The tool needs some (interactive) Userinput, so I can't capture all of the output...?

Thanks for the input f0dder :)


//edit: Idea:
The Batch have to look like this:
Code: C [Select]
  1. call my_tool.exe
  2. call my_temp.bat

The my_temp.bat have to be created by my_tool.exe on the fly before finishing... I believe this will work...
Code: C [Select]
  1. cd _DIR_


f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,153
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
Well, your code to get parent id does look extraordinarily slow - the performance counter API is pretty slow to deal with, especially the first call you make in a program. It'd probably be faster to use toolhelp32 and enumerate the processes until you find your own pid, and then check the th32ParentProcessID member... or use the undocumented NtQueryInformationProcess() function, which is pretty much instantaneous.

But even with the parent process PID, there isn't much you can do, without resorting to the hackhackhack I outlined in the previous post :)

Doing the multiple-batchfile approach is probably the cleanest.
- carpe noctem

hwtan

  • Charter Member
  • Joined in 2005
  • ***
  • Posts: 73
    • View Profile
    • Donate to Member
Alternative solution: write to the keyboard buffer.

Code: C++ [Select]
  1. #include <Windows.h>
  2.  
  3. void writeKeyboardBuffer(const char* str)
  4. {
  5.         INPUT in;
  6.  
  7.         in.type = INPUT_KEYBOARD;
  8.         in.ki.dwFlags = 0;
  9.         in.ki.time = 0;
  10.         in.ki.wScan = 0;
  11.         in.ki.dwExtraInfo = 0;
  12.  
  13.         for (const char* ptr = str; *ptr != '\0'; ++ptr)
  14.         {              
  15.                 SHORT key = VkKeyScan(*ptr);
  16.                 if (key & 0x0100)
  17.                 {
  18.                         in.ki.dwFlags = 0;
  19.                         in.ki.wVk = VK_SHIFT;
  20.                         SendInput(1, &in, sizeof(INPUT));      
  21.                 }
  22.  
  23.                 in.ki.dwFlags = 0;
  24.                 in.ki.wVk = key & 0xFF;
  25.                 SendInput(1, &in, sizeof(INPUT));      
  26.  
  27.                 if (key & 0x0100)
  28.                 {
  29.                         in.ki.dwFlags = KEYEVENTF_KEYUP;
  30.                         in.ki.wVk = VK_SHIFT;
  31.                         SendInput(1, &in, sizeof(INPUT));      
  32.                 }
  33.  
  34.                 in.ki.dwFlags = KEYEVENTF_KEYUP;
  35.                 in.ki.wVk = key & 0xFF;
  36.                 SendInput(1, &in, sizeof(INPUT));      
  37.         }
  38. }
  39.  
  40. int main(int argc, char* argv[])
  41. {
  42.         const char* cmd = "cd D:\\TEMP\r";
  43.         writeKeyboardBuffer(cmd);
  44. }

f0dder

  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 9,153
  • [Well, THAT escalated quickly!]
    • View Profile
    • f0dder's place
    • Read more about this member.
    • Donate to Member
Alternative solution: write to the keyboard buffer.
Baaad idea :)

One thing is that it will obviously fail if the console window loses focus (and it might, for a zillion different reasons). Another potential problem the following blurb:
Microsoft Windows Vista. This function fails when it is blocked by User Interface Privilege Isolation (UIPI). Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.
(obviously that would also block the other various hacks, but not the batchfile thingy).
- carpe noctem