[c++] 获取可执行文件的路径



7 Answers

这种方式使用boost + argv。 您提到这可能不是跨平台的,因为它可能包含或不包含可执行文件的名称。 那么下面的代码应该可以解决这个问题。

#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;
}

下面的代码获取当前的工作目录,它可以做你需要的

#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;
}

注意刚刚意识到basename( )已被弃用,所以必须切换到.stem()

Question

我知道这个问题之前已经被问过了,但我还没有看到满意的答案,或者是一个明确的“不,这不能做”,所以我会再问一次!

我想要做的就是以独立于平台的方式获取当前正在运行的可执行文件的路径,作为绝对路径或相对于调用可执行文件的位置。 我虽然boost :: filesystem :: initial_path是我的麻烦的答案,但似乎只处理问题的“平台无关”部分 - 它仍然返回从中调用应用程序的路径。

对于一些背景,这是一个使用Ogre的游戏,我试图使用Very Sleepy进行配置文件,它从它自己的目录运行目标可执行文件,所以当然加载游戏时发现没有配置文件等,并立即崩溃。 我希望能够将它传递给配置文件的绝对路径,我知道它们将永远与可执行文件并存。 在Visual Studio中调试同样如此 - 我希望能够运行$(TargetPath)而不必设置工作目录。




以下是一个快速和肮脏的解决方案,但请注意,它远非万无一失:

#include <iostream>

using namespace std ;

int main( int argc, char** argv)
{
    cout << argv[0] << endl ;
    return 0;
}



对于Windows,您有如何从GetModuleFileName()的结果中GetModuleFileName()可执行文件的问题。 Nate用于此目的的Windows API调用PathRemoveFileSpec()在他的回答中在Windows 8和其前任之间发生了变化。那么,如何保持兼容性和安全性? 幸运的是,有C ++ 17(或Boost,如果您使用的是较旧的编译器)。 我这样做:

#include <windows.h>
#include <string>
#include <filesystem>
namespace fs = std::experimental::filesystem;

// We could use fs::path as return type, but if you're not aware of
// std::experimental::filesystem, you probably handle filenames
// as strings anyway in the remainder of your code.  I'm on Japanese
// Windows, so wide chars are a must.
std::wstring getDirectoryWithCurrentExecutable()
{
    int size = 256;
    std::vector<wchar_t> charBuffer;
    // Let's be safe, and find the right buffer size programmatically.
    do {
        size *= 2;
        charBuffer.resize(size);
        // Resize until filename fits.  GetModuleFileNameW returns the
        // number of characters written to the buffer, so if the
        // return value is smaller than the size of the buffer, it was
        // large enough.
    } while (GetModuleFileNameW(NULL, charBuffer.data(), size) == size);
    // Typically: c:/program files (x86)/something/foo/bar/exe/files/win64/baz.exe
    // (Note that windows supports forward and backward slashes as path
    // separators, so you have to be careful when searching through a path
    // manually.)

    // Let's extract the interesting part:
    fs::path path(charBuffer.data());  // Contains the full path including .exe
    return path.remove_filename()  // Extract the directory ...
               .w_str();           // ... and convert to a string.
}



如果您需要处理Windows的unicode路径:

#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;
}



我不确定关于Linux,但在Windows上尝试:

#include <windows.h>
#include <iostream>

using namespace std ;

int main()
{
     char ownPth[MAX_PATH]; 

     // When NULL is passed to GetModuleHandle, the handle of the exe itself is returned
     HMODULE hModule = GetModuleHandle(NULL);
     if (hModule != NULL)
     {
         // Use GetModuleFileName() with module handle to get the path
         GetModuleFileName(hModule, ownPth, (sizeof(ownPth))); 
         cout << ownPth << endl ;
         system("PAUSE");
         return 0;
     }
     else
     {
         cout << "Module handle is NULL" << endl ;
         system("PAUSE");
         return 0;
     }
}



这是Windows特有的方式,但至少有一半是你的答案。

GetThisPath.h

/// dest is expected to be MAX_PATH in length.
/// returns dest
///     TCHAR dest[MAX_PATH];
///     GetThisPath(dest, MAX_PATH);
TCHAR* GetThisPath(TCHAR* dest, size_t destSize);

GetThisPath.cpp

#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

TCHAR* GetThisPath(TCHAR* dest, size_t destSize)
{
    if (!dest) return NULL;
    if (MAX_PATH > destSize) return NULL;

    DWORD length = GetModuleFileName( NULL, dest, destSize );
    PathRemoveFileSpec(dest);
    return dest;
}

mainProgram.cpp

TCHAR dest[MAX_PATH];
GetThisPath(dest, MAX_PATH);

我建议使用平台检测作为预处理器指令来更改为每个平台调用GetThisPath的包装函数的实现。




char exePath[512];
CString strexePath;
GetModuleFileName(NULL,exePath,512);
strexePath.Format("%s",exePath);
strexePath = strexePath.Mid(0,strexePath.ReverseFind('\\'));



对于Windows,您可以使用GetModuleFilename()。
对于Linux,请参阅BinReloc




Related