Mike Torrettinni 198 Posted August 31, 2021 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: Looking at Task manager I see this about the Parent process (19916): 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
David Heffernan 2345 Posted August 31, 2021 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
Fr0sT.Brutal 900 Posted August 31, 2021 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 1 Share this post Link to post
Mike Torrettinni 198 Posted August 31, 2021 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
SwiftExpat 65 Posted August 31, 2021 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 Share this post Link to post
Mike Torrettinni 198 Posted August 31, 2021 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
Lars Fosdal 1792 Posted August 31, 2021 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. 1 Share this post Link to post
David Heffernan 2345 Posted August 31, 2021 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
Mike Torrettinni 198 Posted August 31, 2021 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
Mike Torrettinni 198 Posted August 31, 2021 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
David Heffernan 2345 Posted August 31, 2021 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? 1 Share this post Link to post
Mike Torrettinni 198 Posted August 31, 2021 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 Posted August 31, 2021 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
Mike Torrettinni 198 Posted August 31, 2021 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
Mike Torrettinni 198 Posted August 31, 2021 (edited) 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 August 31, 2021 by Mike Torrettinni Share this post Link to post
Fr0sT.Brutal 900 Posted August 31, 2021 I still can't realize what exactly you're trying to achieve Share this post Link to post
Mike Torrettinni 198 Posted August 31, 2021 (edited) 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 August 31, 2021 by Mike Torrettinni Share this post Link to post
David Heffernan 2345 Posted August 31, 2021 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
Remy Lebeau 1392 Posted August 31, 2021 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
SwiftExpat 65 Posted September 1, 2021 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 1 Share this post Link to post
Fr0sT.Brutal 900 Posted September 1, 2021 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
Mike Torrettinni 198 Posted September 1, 2021 10 hours ago, Remy Lebeau said: https://devblogs.microsoft.com/oldnewthing/20091125-00/?p=15923 https://devblogs.microsoft.com/oldnewthing/20090223-00/?p=19063 https://stackoverflow.com/a/14018468/65863 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
Mike Torrettinni 198 Posted September 1, 2021 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
Fr0sT.Brutal 900 Posted September 1, 2021 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
Mike Torrettinni 198 Posted September 1, 2021 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