Get path of executable

前端 未结 23 1533
清歌不尽
清歌不尽 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:35

    This way uses boost + argv. You mentioned this may not be cross platform because it may or may not include the executable name. Well the following code should work around that.

    #include <boost/filesystem/operations.hpp>
    
    #include <boost/filesystem/path.hpp>
    
    #include <iostream>
    
    namespace fs = boost::filesystem;
    
    
    int main(int argc,char** argv)
    {
        fs::path full_path( fs::initial_path<fs::path>() );
    
        full_path = fs::system_complete( fs::path( argv[0] ) );
    
        std::cout << full_path << std::endl;
    
        //Without file name
        std::cout << full_path.stem() << std::endl;
        //std::cout << fs::basename(full_path) << std::endl;
    
        return 0;
    }
    

    The following code gets the current working directory which may do what you need

    #include <boost/filesystem/operations.hpp>
    #include <boost/filesystem/path.hpp>
    
    #include <iostream>
    
    namespace fs = boost::filesystem;
    
    
    int main(int argc,char** argv)
    {
        //current working directory
        fs::path full_path( fs::current_path<fs::path>() );
    
        std::cout << full_path << std::endl;
    
        std::cout << full_path.stem() << std::endl;
        //std::cout << fs::basepath(full_path) << std::endl;
    
        return 0;
    }
    

    Note Just realized that basename() was deprecated so had to switch to .stem()

    0 讨论(0)
  • 2020-11-22 07:36

    There is no cross platform way that I know.

    For Linux: readlink /proc/self/exe

    Windows: GetModuleFileName

    0 讨论(0)
  • 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 <windows.h>
    #include <tlhelp32.h>
    #include <cstddef>
    #include <vector>
    #include <cwchar>
    
    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<char> 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 <libproc.h>
    
    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 <cstdlib>
    
    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 <sys/sysctl.h>
    #include <cstddef>
    
    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 <process.h>
    #endif
    #include <unistd.h>
    #include <cstddef>
    
    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 <windows.h>
    typedef DWORD process_t;
    #else
    #include <sys/types.h>
    typedef pid_t process_t;
    #endif
    #include <string>
    
    /* 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 <iostream>
    
    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.

    0 讨论(0)
  • 2020-11-22 07:41

    This is what I ended up with

    The header file looks like this:

    #pragma once
    
    #include <string>
    namespace MyPaths {
    
      std::string getExecutablePath();
      std::string getExecutableDir();
      std::string mergePaths(std::string pathA, std::string pathB);
      bool checkIfFileExists (const std::string& filePath);
    
    }
    
    

    Implementation

    
    #if defined(_WIN32)
        #include <windows.h>
        #include <Shlwapi.h>
        #include <io.h> 
    
        #define access _access_s
    #endif
    
    #ifdef __APPLE__
        #include <libgen.h>
        #include <limits.h>
        #include <mach-o/dyld.h>
        #include <unistd.h>
    #endif
    
    #ifdef __linux__
        #include <limits.h>
        #include <libgen.h>
        #include <unistd.h>
    
        #if defined(__sun)
            #define PROC_SELF_EXE "/proc/self/path/a.out"
        #else
            #define PROC_SELF_EXE "/proc/self/exe"
        #endif
    
    #endif
    
    namespace MyPaths {
    
    #if defined(_WIN32)
    
    std::string getExecutablePath() {
       char rawPathName[MAX_PATH];
       GetModuleFileNameA(NULL, rawPathName, MAX_PATH);
       return std::string(rawPathName);
    }
    
    std::string getExecutableDir() {
        std::string executablePath = getExecutablePath();
        char* exePath = new char[executablePath.length()];
        strcpy(exePath, executablePath.c_str());
        PathRemoveFileSpecA(exePath);
        std::string directory = std::string(exePath);
        delete[] exePath;
        return directory;
    }
    
    std::string mergePaths(std::string pathA, std::string pathB) {
      char combined[MAX_PATH];
      PathCombineA(combined, pathA.c_str(), pathB.c_str());
      std::string mergedPath(combined);
      return mergedPath;
    }
    
    #endif
    
    #ifdef __linux__
    
    std::string getExecutablePath() {
       char rawPathName[PATH_MAX];
       realpath(PROC_SELF_EXE, rawPathName);
       return  std::string(rawPathName);
    }
    
    std::string getExecutableDir() {
        std::string executablePath = getExecutablePath();
        char *executablePathStr = new char[executablePath.length() + 1];
        strcpy(executablePathStr, executablePath.c_str());
        char* executableDir = dirname(executablePathStr);
        delete [] executablePathStr;
        return std::string(executableDir);
    }
    
    std::string mergePaths(std::string pathA, std::string pathB) {
      return pathA+"/"+pathB;
    }
    
    #endif
    
    #ifdef __APPLE__
        std::string getExecutablePath() {
            char rawPathName[PATH_MAX];
            char realPathName[PATH_MAX];
            uint32_t rawPathSize = (uint32_t)sizeof(rawPathName);
    
            if(!_NSGetExecutablePath(rawPathName, &rawPathSize)) {
                realpath(rawPathName, realPathName);
            }
            return  std::string(realPathName);
        }
    
        std::string getExecutableDir() {
            std::string executablePath = getExecutablePath();
            char *executablePathStr = new char[executablePath.length() + 1];
            strcpy(executablePathStr, executablePath.c_str());
            char* executableDir = dirname(executablePathStr);
            delete [] executablePathStr;
            return std::string(executableDir);
        }
    
        std::string mergePaths(std::string pathA, std::string pathB) {
            return pathA+"/"+pathB;
        }
    #endif
    
    
    bool checkIfFileExists (const std::string& filePath) {
       return access( filePath.c_str(), 0 ) == 0;
    }
    
    }
    
    
    0 讨论(0)
  • 2020-11-22 07:41

    As of C++17:

    Make sure you include std filesystem.

    #include <filesystem>
    

    and now you can do this.

    std::filesystem::current_path().string()
    

    boost filesystem became part of the standard lib.

    if you can't find it try to look under:

    std::experimental::filesystem
    
    0 讨论(0)
  • 2020-11-22 07:42

    In case you need to handle unicode paths for Windows:

    #include <Windows.h>
    #include <iostream>
    
    int wmain(int argc, wchar_t * argv[])
    {
        HMODULE this_process_handle = GetModuleHandle(NULL);
        wchar_t this_process_path[MAX_PATH];
    
        GetModuleFileNameW(NULL, this_process_path, sizeof(this_process_path));
    
        std::wcout << "Unicode path of this app: " << this_process_path << std::endl;
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题