Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[SOLVED]get other process's working dir


  • Please log in to reply
61 replies to this topic
MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009

Not sure I can agree, I've written scripts that poll hardware in the 100ths of seconds and they seem to work just fine.
In the case of WMI, there are things you simply can't do without going 3rd party which probably use it anyway. I dont know.
What ever works I guess.


I have programs that monitor the active window to make an MRU list of Explorer folders. Just getting the folder name without relying on "show full path in address bar" is not possible except in the case where the one window is clicked on by the user. It just bogs.

Anyway, it would probably be worth it to run an au3 program in the background just to get the working directory of other processes and use message passing to communicate with your main ahk app. Since the mouse hotkey handling, and hotkey handling in general really, is superior in AHK I often use an AHK hotkey handler that sends a message to an au3 program. Sometimes functions in au3 make something easy to do. That's the reason to use more than one language. But in any case... :)

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


GodlyCheese
  • Members
  • 719 posts
  • Last active: Nov 11 2014 07:12 PM
  • Joined: 30 Aug 2012
Tyvm TLM, I have found this information very useful! Never knew it was that bloody simple. I don't suppose there's a way to get the directory of what the program's running, is there? I checked WinGet and it doesn't seem to be able to do this and did a search that came up with nada. For instance if I have a file open in notepad it would give me the file's directory or something of that nature.

amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
Thank you, everyone. However, I think what I need is what MilesAhead said.
The working dir of a process is neither the same as its executable file path nor its starting dir, though sometimes they are just identical.
A_WorkingDir is the woking dir of a script itself and we can change it easily.

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.


MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009
This post may be of interest. One of the functions is to get the command line of the target process.

<!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?t=9000">viewtopic.php?t=9000</a><!-- l -->

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
It seems like to get a process's command line rather than working dir. If do so, I prefer WMI:
for i in ComObjGet("winmgmts:\\.\root\CIMV2").ExecQuery("SELECT * FROM Win32_Process WHERE ProcessId = " Pid, "WQL",48) 
        Cmdl := i.CommandLine
It is very simple.

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.


TLM
  • Administrators
  • 3864 posts
  • Last active:
  • Joined: 21 Aug 2006
@amnesiac
It seems your 1st assertion of reading the process environment block was correct.

This may also reveal an API method ( albeit many functions ):
<!-- m -->http://www.codeproje... ... ionProcess<!-- m -->

Primary functions:

<!-- m -->http://msdn.microsof...y/ms684280.aspx<!-- m -->
<!-- m -->http://msdn.microsof...y/ms680553.aspx<!-- m -->

Posted Image

don't duplicate, iterate!


MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009

It seems like to get a process's command line rather than working dir. If do so, I prefer WMI:

for i in ComObjGet("winmgmts:\\.\root\CIMV2").ExecQuery("SELECT * FROM Win32_Process WHERE ProcessId = " Pid, "WQL",48) 
        Cmdl := i.CommandLine
It is very simple.


You asked about getting the file the process was "running" which was kind of vague. One way to do that, if launched via command line arg, is by getting the command line. If the program opened the file via menu then more sophisticated approach similar to handle monitoring would be required.

Seems like this thread goes all over. But anyway, I differentiate between "source code optimization" which many seem to like(I only have to type one line of code) and performance optimization(the one line of code might be 200 times slower than the 5 lines of code.)

(edit: The best optimization is often not wasting time optimizing something done only once. So in this case it may not matter. I like to put code into an include file for general reuse. I've gotten burned thinking I had a generally useful function for say getting the path of an Explorer window without relying on reading the text (path in address bar.) But although the function was fine as a one shot, in any kind of monitor loop it bogged to useless. Just wanted to make the point as it's easy to think it worked once so it's good to go in all situations. Also though I do use WMI stuff when it's the easiest way, it's not always the most portable. If all your stuff demands XP SP2 and later then it may not matter. It's probably there.)

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
@TLM
I checked the code and run it with AutoHotkey_L Unicode, but I got a failure.
Thank you for your material reference.
@MilesAhead
Working dir is easy to understand and very clear for me. A_WorkingDir is a working dir for a script itself.
Retrieving working dir of other process is a main component of my scripts (command line or starting dir is invaluable entirely). So what I do is not optimization. Thank you for your advice.
I have translated the au3 code you talked about to ahk and the debug is doing.

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.


TLM
  • Administrators
  • 3864 posts
  • Last active:
  • Joined: 21 Aug 2006

I checked the code and run it with AutoHotkey_L Unicode, but I got a failure.

When you say 'and run it', do you mean u tried running the code from the link(s) directly in AHk?
If so, it has to be translated to a format that AHk can handle, and would be an extremely advanced job.
It would make an very nice lib function though :).

Posted Image

don't duplicate, iterate!


amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
@TLM
Oh, sorry. I misunderstood you last time.
I know those code in the link you provided is c/c++. As you say, translating it is too difficult to do for me (Maybe I can comprehend a little thinking).
Now I find another way: Create remote thread to get current dir (i.e. working dir):
Process, Exist, notepad.exe
PID := ErrorLevel
If !pFunc
    pFunc := DllCall( "GetProcAddress", "UInt"
        , DllCall( "GetModuleHandle", "Str", "kernel32.dll"), "Str", "GetCurrentDirectory" )
nProc := DllCall( "OpenProcess", "UInt",0x43a,"Int",0,"UInt", PID)
hThrd := DllCall( "CreateRemoteThread", "UInt",nProc, "UInt",0, "UInt",0, "UInt",pFunc, "UInt",0
    , "UInt",0, "UInt",0 ),  DllCall( "WaitForSingleObject", "UInt",hThrd, "UInt",0xFFFFFFFF ) ; lpParameter error.
I don't know how to make the parameters for GetCurrentDirectory in CreateRemoteThread.

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.


rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
This site gives a step-by-step procedure for injecting a thread into another process' address space and executing it. HTH

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009
For those who don't mind taking the easy way out by calling another program:

<!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?f=7&t=93277">viewtopic.php?f=7&t=93277</a><!-- l -->

I'm curious to see it done in ahk though. So I'll watch this thread. :)

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
@rbrtryn, Thank you.

I write some code. But I can't retrieve a function's address in AutoHotkey for calculating the ThreadProc's size.
Process, Exist, notepad.exe
PID := ErrorLevel

PROCESS_QUERY_INFORMATION := 0x0400
PROCESS_VM_OPERATION := 0x8
PROCESS_VM_READ := 0x10
PROCESS_VM_WRITE := 0x20
READ_WRITE_ACCESS := PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION
MEM_COMMIT := 0x1000
PAGE_READWRITE := 4

hProcess := DllCall("OpenProcess", "UInt", READ_WRITE_ACCESS, "Int",0, "UInt", PID)
nDirLength := VarSetCapacity(nDirLength, 512, 0)
cbThreadSize := &AfterThreadFunc() - &ThreadFunc()    ; Here is error.
pBufferRemote := DllCall("Kernel32.dll\VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "UPtr", nDirLength + 1, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE, "Ptr")
pThreadRemote := DllCall("Kernel32.dll\VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "UPtr", cbThreadSize + 1, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE, "Ptr")
DllCall("Kernel32.dll\WriteProcessMemory", "Ptr", hProcess, "Ptr", pThreadRemote, "Ptr", &ThreadFunc, "UPtr", cbThreadSize, "Ptr", 0)
hThread := DllCall("CreateRemoteThread", "UInt", hProcess, "UInt", 0, "UInt", 0, "UInt", pThreadRemote, "UInt", 0, "UInt", 0, "UInt", 0)
DllCall("WaitForSingleObject", "UInt", hThread, "UInt", 0xFFFFFFFF)
DllCall("GetExitCodeThread", "UInt", hThread, "UIntP", lpExitCode)
VarSetCapacity(sCmdLine, 512)
DllCall("ReadProcessMemory", "UInt", hProcess, "UInt", lpExitCode, "Str", sCmdLine, "UInt", 512, "UInt", 0)
if hThread
    DllCall("CloseHandle", "UInt", hThread)
if hProcess
    DllCall("CloseHandle", "UInt", hProcess)
ListVars
Pause

ThreadFunc() 
{
    DllCall("GetCurrentDirectoryW", "UInt", nDirLength, "UInt", pBufferRemote)
    return, pBufferRemote
}
AfterThreadFunc()
{}

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Try this :)
The MCode hex string is original 32-bit GetCurrentDirectoryW function with swapped parameters.
Process, Exist, notepad.exe
If !PID := ErrorLevel
  Run notepad.exe,,,PID

MsgBox % GetProcessWorkingDir(PID)

GetProcessWorkingDir(PID){
  static PROCESS_ALL_ACCESS:=0x1F0FFF,MEM_COMMIT := 0x1000,MEM_RELEASE:=0x8000,PAGE_EXECUTE_READWRITE:=64
        ,GetCurrentDirectoryW,init:=MCode(GetCurrentDirectoryW,"8BFF558BECFF750[color=#FF0000]8[/color]8B450803C050FF15A810807CD1E85DC20800")
  nDirLength := VarSetCapacity(nDir, 512, 0)
  hProcess := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID)
  if !hProcess 
    return
  pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", nDirLength + 1, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")

  pThreadRemote := DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "PTR", 31, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
  DllCall("WriteProcessMemory", "Ptr", hProcess, "Ptr", pThreadRemote, "Ptr", &GetCurrentDirectoryW, "PTR", 31, "Ptr", 0)

  If hThread := DllCall("CreateRemoteThread", "PTR", hProcess, "UInt", 0, "UInt", 0, "PTR", pThreadRemote, "PTR", pBufferRemote, "UInt", 0, "UInt", 0)
  {
    DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
    DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)
    If lpExitCode {
      DllCall("ReadProcessMemory", "PTR", hProcess, "PTR", pBufferRemote, "Str", nDir, "UInt", lpExitCode*2, "UInt", 0)
      VarSetCapacity(nDir,-1)
    }
    DllCall("CloseHandle", "PTR", hThread)
  }
  DllCall("VirtualFreeEx","PTR",hProcess,"PTR",pBufferRemote,"PTR",nDirLength + 1,MEM_RELEASE)
  DllCall("VirtualFreeEx","PTR",hProcess,"PTR",pThreadRemote,"PTR",31,MEM_RELEASE)
  DllCall("CloseHandle", "PTR", hProcess)

  return nDir
}


amnesiac
  • Members
  • 124 posts
  • Last active: May 01 2014 03:04 AM
  • Joined: 07 Nov 2010
@HotKeyIt, Thank you very much. You solve my immediate problem.

By the way, does you struct library support nested struct? e.g.
typedef struct
{
    ULONG               AllocationSize;
    ULONG               Unknown1;
    HINSTANCE           ProcessHinstance;
    PVOID               ListDlls;
    PPROCESS_PARAMETERS ProcessParameters;
    ULONG               Unknown2;
    HANDLE              Heap;
} PEB, *PPEB;

typedef struct
{
    DWORD ExitStatus;
    PPEB  PebBaseAddress;
    DWORD AffinityMask;
    DWORD BasePriority;
    ULONG UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
}   PROCESS_BASIC_INFORMATION;

Click to download Chinese resource for AutoHotkey.

Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.