Get path of executable

前端 未结 23 1567
清歌不尽
清歌不尽 2020-11-22 07:04

I know this question has been asked before but I still haven\'t seen a satisfactory answer, or a definitive \"no, this cannot be done\", so I\'ll ask again!

All I wa

23条回答
  •  情话喂你
    2020-11-22 07:39

    This is probably the most natural way to do it, while covering most major desktop platforms. I am not certain, but I believe this should work with all the BSD's, not just FreeBSD, if you change the platform macro check to cover all of them. If I ever get around to installing Solaris, I'll be sure to add that platform to the supported list.

    Features full UTF-8 support on Windows, which not everyone cares enough to go that far.

    procinfo/win32/procinfo.cpp

    #ifdef _WIN32
    #include "../procinfo.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using std::string;
    using std::wstring;
    using std::vector;
    using std::size_t;
    
    static inline string narrow(wstring wstr) {
      int nbytes = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
      vector buf(nbytes);
      return string{ buf.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), buf.data(), nbytes, NULL, NULL) };
    }
    
    process_t ppid_from_pid(process_t pid) {        
      process_t ppid;       
      HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);      
      PROCESSENTRY32 pe = { 0 };        
      pe.dwSize = sizeof(PROCESSENTRY32);       
      if (Process32First(hp, &pe)) {        
        do {        
          if (pe.th32ProcessID == pid) {        
            ppid = pe.th32ParentProcessID;      
            break;      
          }     
        } while (Process32Next(hp, &pe));       
      }     
      CloseHandle(hp);      
      return ppid;      
    }
    
    string path_from_pid(process_t pid) {
      string path;
      HANDLE hm = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
      MODULEENTRY32W me = { 0 };
      me.dwSize = sizeof(MODULEENTRY32W);
      if (Module32FirstW(hm, &me)) {
        do {
          if (me.th32ProcessID == pid) {
            path = narrow(me.szExePath);
            break;
          }
        } while (Module32NextW(hm, &me));
      }
      CloseHandle(hm);
      return path;
    }
    #endif
    

    procinfo/macosx/procinfo.cpp

    #if defined(__APPLE__) && defined(__MACH__)
    #include "../procinfo.h"
    #include 
    
    using std::string;
    
    string path_from_pid(process_t pid) {
      string path;
      char buffer[PROC_PIDPATHINFO_MAXSIZE];
      if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0) {
        path = string(buffer) + "\0";
      }
      return path;
    }
    #endif
    

    procinfo/linux/procinfo.cpp

    #ifdef __linux__
    #include "../procinfo.h"
    #include 
    
    using std::string;
    using std::to_string;
    
    string path_from_pid(process_t pid) {
      string path;
      string link = string("/proc/") + to_string(pid) + string("/exe");
      char *buffer = realpath(link.c_str(), NULL);
      path = buffer ? : "";
      free(buffer);
      return path;
    }
    #endif
    

    procinfo/freebsd/procinfo.cpp

    #ifdef __FreeBSD__
    #include "../procinfo.h"
    #include 
    #include 
    
    using std::string;
    using std::size_t;
    
    string path_from_pid(process_t pid) {
      string path;
      size_t length;
      // CTL_KERN::KERN_PROC::KERN_PROC_PATHNAME(pid)
      int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid };
      if (sysctl(mib, 4, NULL, &length, NULL, 0) == 0) {
        path.resize(length, '\0');
        char *buffer = path.data();
        if (sysctl(mib, 4, buffer, &length, NULL, 0) == 0) {
          path = string(buffer) + "\0";
        }
      }
      return path;
    }
    #endif
    

    procinfo/procinfo.cpp

    #include "procinfo.h"
    #ifdef _WiN32
    #include 
    #endif
    #include 
    #include 
    
    using std::string;
    using std::size_t;
    
    process_t pid_from_self() {
      #ifdef _WIN32
      return _getpid();
      #else
      return getpid();
      #endif
    }
    
    process_t ppid_from_self() {
      #ifdef _WIN32
      return ppid_from_pid(pid_from_self());
      #else
      return getppid();
      #endif
    }
    
    string dir_from_pid(process_t pid) {
      string fname = path_from_pid(pid);
      size_t fp = fname.find_last_of("/\\");
      return fname.substr(0, fp + 1);
    }
    
    string name_from_pid(process_t pid) {
      string fname = path_from_pid(pid);
      size_t fp = fname.find_last_of("/\\");
      return fname.substr(fp + 1);
    }
    

    procinfo/procinfo.h

    #ifdef _WiN32
    #include 
    typedef DWORD process_t;
    #else
    #include 
    typedef pid_t process_t;
    #endif
    #include 
    
    /* windows-only helper function */
    process_t ppid_from_pid(process_t pid);
    
    /* get current process process id */
    process_t pid_from_self();
    
    /* get parent process process id */
    process_t ppid_from_self();
    
    /* std::string possible_result = "C:\\path\\to\\file.exe"; */
    std::string path_from_pid(process_t pid);
    
    /* std::string possible_result = "C:\\path\\to\\"; */
    std::string dir_from_pid(process_t pid);
    
    /* std::string possible_result = "file.exe"; */
    std::string name_from_pid(process_t pid);
    

    This allows getting the full path to the executable of pretty much any process id, except on Windows there are some process's with security attributes which simply will not allow it, so wysiwyg, this solution is not perfect.

    To address what the question was asking more precisely, you may do this:

    procinfo.cpp

    #include "procinfo/procinfo.h"
    #include 
    
    using std::string;
    using std::cout;
    using std::endl;
    
    int main() {
      cout << dir_from_pid(pid_from_self()) << endl;
      return 0;
    }
    

    Build the above file structure with this command:

    procinfo.sh

    cd "${0%/*}"
    g++ procinfo.cpp procinfo/procinfo.cpp procinfo/win32/procinfo.cpp procinfo/macosx/procinfo.cpp procinfo/linux/procinfo.cpp procinfo/freebsd/procinfo.cpp -o procinfo.exe
    

    For downloading a copy of the files listed above:

    git clone git://github.com/time-killer-games/procinfo.git
    

    For more cross-platform process-related goodness:

    https://github.com/time-killer-games/enigma-dev

    See the readme for a list of most of the functions included.

提交回复
热议问题