Jump to content
Mike Torrettinni

Get Parent process Current directory

Recommended Posts

I'm experiment with some scripts and trying to get Parent info of the process.

 

This is my call:

I run a batch file, starting point: c:\Develop\ and batch file calls my Delphi's Project1.exe in Win32\Debug\ folder.

 

I see in Process Monitor (mouse hint) that it has a Current directory of a Parent that executes my Delphi Project1.exe:

image.thumb.png.27d17809d003568b114cb4138fd27820.png

 

 

Looking at Task manager I see this about the Parent process (19916):

image.thumb.png.5ad2bdcb8df84a5912456c16cfbd1a18.png

 

In Delphi I can get Parent PID, exe name and full path, so I can get Image path name, not sure how to get Command line info, but more important is Current directory (that is not in Task manager, but in Process Manager tool).

I use CreateToolhelp32Snapshot to get Parent process info, PID and full path name.

 

So, I want to find out what was the starting point or Current directory of the batch file that calls my Project1.exe.

Any idea how to get this Parent's Current directory info?

 

Share this post


Link to post

What problem are you trying to solve here, because what you are describing doesn't sound like a robust solution to any problem. 

Share this post


Link to post

Child process inherits current directory. I doubt it's possible to get parent's CDir with any API except by injecting and other hackish methods

  • Thanks 1

Share this post


Link to post

Yes, seems like could be tricky, not reliable. If I understand correctly this answer, then is not documented and I think translating this into possible Delphi code is out of my league:

https://stackoverflow.com/a/16142791

 

"As other pointed out, this is completely undocumented, but here is a piece of code that does it (as of today, it seems to work). Of course, it needs to run as admin. Note it can work for any process bitness, 32-bit or 64-bit (some processess may report an access denied, even running as admin), with any compilation target (x86 or x64). It also is capable of reading the command line. Use at your own risk!"

Share this post


Link to post
1 hour ago, SwiftExpat said:

If you are open to using WMI, check out https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process

 

You can see an example output running this at a command line:   wmic process

It has a lot of info, like ExecutablePath, but not Current directory. I already have a way to get Parent's executable path.

Unless, I'm not seeing something obvious, this can't help me.

Share this post


Link to post

If the parent process runs at a higher security level than your own, you will have a hard time gleaning info from the process without elevating your own process.

Since CreateProcess explicitly can specify a different working directory than the current (i.e. the parent) - there is no bullet-proof way of knowing the actual working directory of the parent process.

 

  • Thanks 1

Share this post


Link to post
4 hours ago, Fr0sT.Brutal said:

Child process inherits current directory

Not if the parent chooses to specify a different current directory. 

 

6 hours ago, Mike Torrettinni said:

I run a batch file, starting point: c:\Develop\ and batch file calls my Delphi's Project1.exe

The command interpreter process, which is the parent, might terminate before your process has a chance to inspect it. 

 

If you are in charge of creating the process, then pass in the information required as an argument. 

 

The more I read of thus the more it seems you are taking the wrong path. 

Share this post


Link to post
5 minutes ago, Lars Fosdal said:

If the parent process runs at a higher security level than your own, you will have a hard time gleaning info from the process without elevating your own process.

Ok, makes sense. I'm not against the need for my project to run as admin, if necessary.

 

But as I tested a script that might give the correct info, it fails to use ReadProcessMemory (after NtQueryInformationProcess(handle, ProcessBasicInformation...) ) on the selected parent process, with or without Delphi running as Admin.

For some other processes I can see PWD=c:\... info, which I think is what I'm looking for (but not 100%), just not for the processes I need.

 

Seems like I'm close, but I've never done anything like reading other processes memory, so it's a little of guesswork. I thought someone already has done something like this, in Delphi, of course.

Share this post


Link to post
1 minute ago, David Heffernan said:

The command interpreter process, which is the parent, might terminate before your process has a chance to inspect it.

It could be that will be the case in some situations, but currently the process waits until my project closes. And if it does, I believe the solution is to see if the process with same PID has been created after my process (so the original parent exited and same PID might be assigned to new process).

 

2 minutes ago, David Heffernan said:

If you are in charge of creating the process, then pass in the information required as an argument. 

Yes, in a way I am/can be in charge, but I'm trying to figure out a way to do this without this, so it's more general solution.

 

Last night I noticed that Process monitor can get the Current directory, so overnight I tried to find a way to do it on my own. So, as hours progressed I have more info, and now I see that this could be a tricky thing.

But I'm not done looking into it, yet.

 

 

Share this post


Link to post
45 minutes ago, Mike Torrettinni said:

Yes, in a way I am/can be in charge, but I'm trying to figure out a way to do this without this, so it's more general solution.

Then you are in trouble because there's really no way in general to be sure that the process which created your process still exists when your process executes. Windows has a very different model of parent/child process relationships from say Linux.

 

What problem are you trying to solve? 

  • Thanks 1

Share this post


Link to post
3 minutes ago, David Heffernan said:

Then you are in trouble because there's really no way in general to be sure that the process which created your process still exists when your process executes. Windows has a very different model of parent/child process relationships from say Linux.

 

What problem are you trying to solve? 

Right now I have a workaround, a solution that works, but it requires manual work by users and in some cases (big customers) they need to do this manual work multiple times a day - they know the 'current directory'.

 

I'm trying to avoid this and automate without their interaction. One way is to have that interceptor/bridge batch that can pass the parameter, or perhaps I can find by looking at Parent's info. Like I said, the process stays opened, until my process is done.

Share this post


Link to post
Guest
1 hour ago, Mike Torrettinni said:

it fails to use ReadProcessMemory (after NtQueryInformationProcess(handle, ProcessBasicInformation...) ) on the selected parent process, with or without Delphi running as Admin.

You might have your OpenHandle with wrong parameters, but it doesn't matter.

 

I would suggest more easier way to get the GetCurrentDirectory from within the target process, using DLL injection, this is the shortest way, i searched the internet, and there is many resources, one in particular is done by a black art hacker, visit his site on your own risk

https://www.ideasawakened.com/post/dll-injection-with-delphi

 

 

Share this post


Link to post
22 minutes ago, Kas Ob. said:

using DLL injection,

Thanks, I think I don't want to go near this. I have no idea how this affects the running process, if anti-malware could catch the action and alert users... I don't even want to think how to defend the action, this definitely feels like going rogue on my customers 🙂

Share this post


Link to post

So, long story short, David was right, I did find a tool that closes it's process right after it calls my project. So, if I want to have broad solution, I have to take this into account.

Even though this tool is rarely used, I can't rely on the fact other tools that keep the process open, will not change their implementation in the future.

 

OK, research done. This is not the way to do it: can't rely on Current directory of the Parent process.

Edited by Mike Torrettinni

Share this post


Link to post

OK, let me try to explain: I have a project that is run by different tools and it has limited info that it can receive (well, limited info/parameters are available from the calling tools - the tools I don't control), and those tools don't send their starting directory, although I need it in 100% cases. So, my project needs to have manually adjusted a setting that tells what the what the calling tool is and the starting point/directory. And based on that info my project behaves as it should. And users need to set this manually. In many cases they set it once and forget about it. But there are cases where they need to 'switch' between multiple start locations, multiple times a day - annoying, but necessary.

 

So I have 2 options to improve this, to some extent: there is limited option where I can have a batch to run between the tool and before my project gets called (so the tool actually run my the batch file), which in theory could be used to get the start directory and pass it to my project. But this is not 100% in all cases, well this is also still being researched and in testing mode, because not all tools call my project in the same way.

 

But when I was looking at how these tools behave with Process monitor, I saw that the Current directory info was available for every instance of a Parent process. Testing with a few most commonly used tools, the Parent task was always opened, while running my project. And I was hoping I can get the same info within my project. And here we are now, knowing that I can't rely on a fact that the parent process will always be opened, for my project to query it's info.

 

So, now back to trying to make it work with batch file in between and see what 'limited or unlimited' options I have there.

 

I thought it would be pointless to put all this into the original post.

 

Edited by Mike Torrettinni

Share this post


Link to post
2 hours ago, Mike Torrettinni said:

I thought it would be pointless to put all this into the original post

No. This missing context is the exact reason why this thread has been so long. It's invariably valuable to understand the motivation to a question.

 

It sounds like what you need is for you r the calling processes to provide extra information to your program. 

Share this post


Link to post
17 hours ago, Mike Torrettinni said:

In Delphi I can get Parent PID, exe name and full path, so I can get Image path name, not sure how to get Command line info

https://devblogs.microsoft.com/oldnewthing/20091125-00/?p=15923

https://devblogs.microsoft.com/oldnewthing/20090223-00/?p=19063

17 hours ago, Mike Torrettinni said:

but more important is Current directory (that is not in Task manager, but in Process Manager tool).

https://stackoverflow.com/a/14018468/65863

Share this post


Link to post
11 hours ago, Mike Torrettinni said:

 So, my project needs to have manually adjusted a setting that tells what the what the calling tool is and the starting point/directory.

 

One item you might try is to use TPath to get the full path of a file in your working directory (the file does not need to exist).  That would give you the working directory at that time.

 

program CheckWorkDir;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.IOUtils;

begin
  try
    writeln('Working Dir = ' +TPath.GetDirectoryName(TPath.GetFullPath('pid.txt')));
  except
    on E: Exception do
      writeln(E.ClassName, ': ', E.Message);
  end;

end.

output:

c:\Data>C:\Users\Coder\Documents\Embarcadero\Studio\Projects\OSUtils\TouchFile\Win32\Debug\checkworkdir.exe
Working Dir = c:\Data\

c:\Data>cd ibd

c:\Data\ibd>C:\Users\Coder\Documents\Embarcadero\Studio\Projects\OSUtils\TouchFile\Win32\Debug\checkworkdir.exe
Working Dir = c:\Data\ibd

  • Like 1

Share this post


Link to post
14 hours ago, Mike Torrettinni said:

OK, let me try to explain: I have a project that is run by different tools and it has limited info that it can receive (well, limited info/parameters are available from the calling tools - the tools I don't control), and those tools don't send their starting directory, although I need it in 100% cases. So, my project needs to have manually adjusted a setting that tells what the what the calling tool is and the starting point/directory. And based on that info my project behaves as it should. And users need to set this manually. In many cases they set it once and forget about it. But there are cases where they need to 'switch' between multiple start locations, multiple times a day - annoying, but necessary.

Don't CurrDir of your project that is by default inherited from launching process and path to launching process' image file satisfy your needs?

Btw, CurrDir is unreliable anyway. F.ex.:
 

>cmd

c:\users\user> d:\soft\that-tool-calling-my-project\tool.exe

 

Share this post


Link to post
10 hours ago, Remy Lebeau said:

Thanks, I did see similar scripts, some in Delphi already. Like Raymond says "Once the process can access its own command line, the kernel’s responsibilities are done. ", I guess is not completely true, since the command line is displayed in Task Manager.

Same for Parent process current directory, not easily accessible.

 

But if Parent process is not running anymore, then there is no info to get anyway.

Share this post


Link to post
2 hours ago, Fr0sT.Brutal said:

Don't CurrDir of your project that is by default inherited from launching process and path to launching process' image file satisfy your needs?

Btw, CurrDir is unreliable anyway. F.ex.:
 


>cmd

c:\users\user> d:\soft\that-tool-calling-my-project\tool.exe

  

Exactly, not reliable. I need to know where the the line was executed because this is current directory of the process that executes my project. And if Parent would always be persistent process, this would be Parent's current directory.

So, I was hoping for function GetProcessCurrentDirectoty(ParentPID): string; 😉

 

Now, I will have to use batch file to get the current directory and pass it to my project.

 

 

Share this post


Link to post
37 minutes ago, Mike Torrettinni said:

Now, I will have to use batch file to get the current directory and pass it to my project.

You mean, launching bat file instead of your project? How it could help? There's no principal difference between running cmd.exe and yourproject.exe

Share this post


Link to post
1 hour ago, Fr0sT.Brutal said:

You mean, launching bat file instead of your project? How it could help? There's no principal difference between running cmd.exe and yourproject.exe

Perhaps I don't know that it's possible, but can you identify what was the current directory that your project was called from? Please share the code.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×