Получить путь к исполняемому файлу - PullRequest
101 голосов
/ 07 октября 2009

Я знаю, что этот вопрос задавался ранее, но я все еще не видел удовлетворительного ответа или окончательного ответа "нет, этого нельзя сделать", поэтому я спрошу снова!

Все, что я хочу сделать, - это получить путь к исполняемому в данный момент исполняемому файлу, либо в виде абсолютного пути, либо относительно того, откуда исполняемый файл вызывается, независимо от платформы. Я, хотя boost :: filesystem :: initial_path был ответом на мои проблемы, но, похоже, он обрабатывает только «независимую от платформы» часть вопроса - он по-прежнему возвращает путь, из которого было вызвано приложение.

Для справки: это игра с использованием Ogre, которую я пытаюсь профилировать с помощью Very Sleepy, которая запускает целевой исполняемый файл из своего собственного каталога, поэтому, конечно, при загрузке игра не находит конфигурационные файлы и т. Д. и быстро вылетает. Я хочу иметь возможность передать ему абсолютный путь к файлам конфигурации, которые, как я знаю, всегда будут жить рядом с исполняемым файлом. То же самое касается отладки в Visual Studio - я хотел бы иметь возможность запускать $ (TargetPath) без необходимости устанавливать рабочий каталог.

Ответы [ 19 ]

1 голос
/ 07 октября 2009

Следующее работает как быстрое и грязное решение, но учтите, что оно далеко не надежно:

#include <iostream>

using namespace std ;

int main( int argc, char** argv)
{
    cout << argv[0] << endl ;
    return 0;
}
0 голосов
/ 18 июня 2019

Начиная с C ++ 17:

Убедитесь, что вы включили файловую систему std.

#include <filesystem>

и теперь вы можете сделать это.

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

Файловая система boost стала частью стандартной библиотеки lib.

если вы не можете найти его, попробуйте заглянуть в:

std::experimental::filesystem
0 голосов
/ 07 марта 2019

Как уже упоминалось, argv[0] является довольно хорошим решением, при условии, что платформа фактически передает путь к исполняемому файлу, что, безусловно, не менее вероятно, чем ОС, являющаяся Windows (где WinAPI может помочь найти путь к исполняемому файлу). Если вы хотите удалить строку, включив в нее только путь к каталогу, в котором находится исполняемый файл, то использовать этот путь для поиска других файлов приложения (например, игровых ресурсов, если ваша программа - игра) совершенно нормально, поскольку открытие файлов относительно рабочий каталог или, если он указан, корневой каталог.

0 голосов
/ 20 февраля 2014
char exePath[512];
CString strexePath;
GetModuleFileName(NULL,exePath,512);
strexePath.Format("%s",exePath);
strexePath = strexePath.Mid(0,strexePath.ReverseFind('\\'));
0 голосов
/ 07 июня 2018

В случае, если вам нужно обработать Unicode-пути для 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 голосов
/ 05 февраля 2018

Это было мое решение в Windows. Это называется так:

std::wstring sResult = GetPathOfEXE(64);

Где 64 - минимальный размер, который, по вашему мнению, будет иметь путь. GetPathOfEXE рекурсивно вызывает себя, удваивая размер буфера каждый раз, пока не получит достаточно большой буфер, чтобы получить весь путь без усечения.

std::wstring GetPathOfEXE(DWORD dwSize)
{
    WCHAR* pwcharFileNamePath;
    DWORD dwLastError;
    HRESULT hrError;
    std::wstring wsResult;
    DWORD dwCount;

    pwcharFileNamePath = new WCHAR[dwSize];

    dwCount = GetModuleFileNameW(
        NULL,
        pwcharFileNamePath,
        dwSize
    );

    dwLastError = GetLastError();

    if (ERROR_SUCCESS == dwLastError)
    {
        hrError = PathCchRemoveFileSpec(
            pwcharFileNamePath,
            dwCount
        );

        if (S_OK == hrError)
        {
            wsResult = pwcharFileNamePath;

            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            return wsResult;
        }
        else if(S_FALSE == hrError)
        {
            wsResult = pwcharFileNamePath;

            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            //there was nothing to truncate off the end of the path
            //returning something better than nothing in this case for the user
            return wsResult;
        }
        else
        {
            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            std::ostringstream oss;
            oss << "could not get file name and path of executing process. error truncating file name off path. last error : " << hrError;
            throw std::runtime_error(oss.str().c_str());
        }
    }
    else if (ERROR_INSUFFICIENT_BUFFER == dwLastError)
    {
        if (pwcharFileNamePath)
        {
            delete pwcharFileNamePath;
        }

        return GetPathOfEXE(
            dwSize * 2
        );
    }
    else
    {
        if (pwcharFileNamePath)
        {
            delete pwcharFileNamePath;
        }

        std::ostringstream oss;
        oss << "could not get file name and path of executing process. last error : " << dwLastError;
        throw std::runtime_error(oss.str().c_str());
    }
}
0 голосов
/ 26 января 2018

Для Windows у вас есть проблема, как убрать исполняемый файл из результата GetModuleFileName(). Вызов API Windows 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.
}
0 голосов
/ 20 ноября 2017

Этот метод работает как для Windows, так и для Linux:

#include <stdio.h>
#include <string>
#ifdef _WIN32
#include <direct.h>
#define GetCurrentDir _getcwd
#elif __linux__
#include <unistd.h>
#define GetCurrentDir getcwd
#endif

std::string GetCurrentWorkingDir() 
{
    char buff[FILENAME_MAX];
    GetCurrentDir(buff, FILENAME_MAX);
    std::string current_working_dir(buff);
    return current_working_dir;
}
0 голосов
/ 19 марта 2014

в Unix (включая Linux) попробуйте 'which', в Windows попробуйте 'where'.

#include <stdio.h>

#define _UNIX

int main(int argc, char** argv)
{
        char cmd[128];
        char buf[128];
        FILE* fp = NULL;
#if defined(_UNIX)
        sprintf(cmd, "which %s > my.path", argv[0]);
#else
        sprintf(cmd, "where %s > my.path", argv[0]);
#endif
        system(cmd);
        fp = fopen("my.path", "r");
        fgets(buf, sizeof(buf), fp);
        fclose(fp);

        printf("full path: %s\n", buf);
        unlink("my.path");

        return 0;
}
...