C++ [Windows] 可执行文件所在文件夹的路径

42

我需要在Windows上的C++应用程序中使用fstream访问一些文件。这些文件都位于包含我的可执行文件的文件夹的子文件夹中。

  • 获取当前可执行文件所在文件夹的路径,最简单且更加重要的是安全的方式是什么?

有比使用argv [0]更复杂的东西,它是int main(int argc,char * argv [])的参数并进行解析的吗? - Minok
3个回答

59

使用 GetModuleFileName 函数可以找到你的exe文件运行的位置。

WCHAR path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);

然后从路径中去除exe文件名。


2
有没有不使用Win32 API的方法来实现这个? - asas
3
@asas:没有简单且安全的方法。 - Adrian McCarthy
2
@asas:不使用Win32 API来编写C++ Windows应用程序?像使用Qt一样? - sean e
1
是的,没有Win32 API。它不是一个GUI应用程序 - 它是一个解释器。我目前在MSVC中编写它,这应该不难移植 - Win32 API使其难以移植。 - asas
3
我知道这很老了,但是GetModuleFileNameW(NULL, path, MAX_PATH)不就足够了吗? - Mukesh Sai Kumar
显示剩余3条评论

33

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);
更新:在Windows 8中,PathRemoveFileSpec已经被弃用了。 然而,替代函数PathCchRemoveFileSpec仅适用于Windows 8+。 (感谢@askalee的评论)
我认为下面的代码可能有效,但在下面的代码得到验证之前,我会保留上面的代码。我目前没有设置编译器来测试这个代码。如果您有机会测试此代码,请发表评论,说明此下方代码是否有效以及您测试的操作系统是什么。谢谢! 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;

    DWORD length = GetModuleFileName( NULL, dest, destSize );
#if (NTDDI_VERSION >= NTDDI_WIN8)
    PathCchRemoveFileSpec(dest, destSize);
#else
    if (MAX_PATH > destSize) return NULL;
    PathRemoveFileSpec(dest);
#endif
    return dest;
}

mainProgram.cpp

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

8
+1 代表对 PathRemoveFileSpec 的赞同,不知道这个函数之前。 - lambdas
3
似乎 PathRemoveFileSpec 已经被弃用,请使用 PathCchRemoveFileSpec 替代。参考链接:http://msdn.microsoft.com/zh-cn/library/windows/desktop/bb773748(v=vs.85).aspx。 - askalee
2
@askalee 值得注意的是,它只支持Win8(及以上版本)桌面应用程序。 - wonko realtime
当我准备实现它时,我意识到这将不适用于Windows 8以上的版本。例如,Windows 8.1是“NTDDI_WINBLUE”,而不是“NTDDI_WIN8”。您需要使用类似于#if (NTDDI_VERSION >= NTDDI_WIN8)的内容。 - Warpspace
@SomethingSomething 谢谢。 - Nate
显示剩余5条评论

-1

默认情况下,exe所在的目录应该是起始位置。因此,在子文件夹中打开文件应该像这样简单:

fstream infile; 
infile.open(".\\subfolder\\filename.ext");

从您的程序内部。

然而,除非您使用包装所需功能的框架(我建议使用boost),或直接使用Windows API,例如GetModuleFileName(如sean e所建议的那样),否则无法保证始终有效。


3
什么?你听说过“运行路径”吗?你不必告诉我exe文件运行的默认路径... - asas
3
如果你有误解:每个进程都有一个代表当前目录的值。 默认情况下,该值应设置为可执行文件所在的目录。 您可以使用GetCurrentDirectory() API调用来检查此目录,或使用SetCurrentDirectory()设置它。 尽管我意识到这不是您问题的确切解决方案(如原始文本所述),但这些信息是正确的 http://msdn.microsoft.com/en-us/library/aa363806.aspx。如果您认为这值得投反对票,我不确定您是否理解此处投票系统的预期用途。 - KevenK
2
他可能指的是“开始于”选项,在Windows开始菜单程序链接中可以指定起始工作目录。 - sean e
3
除了有明确指定工作目录的快捷方式外,例如从cmd启动程序时,当前工作目录将会继承自父进程。你不能假设当前工作目录与可执行文件的位置有任何关系。 - bcrist
1
Windows程序有“当前目录”的概念,它不一定与它们物理上所在的文件夹相同。两个目录不匹配的情况很少见(例如在Visual Studio中运行时),但当你遇到这种情况时,你会感到非常困惑。而且,“运行它”只会导致“在我的机器上可以运行”(当我以使物理位置与当前目录匹配的方式运行它时)。因此,是的,这个答案正确地指出了在Windows中事情要复杂一些。 - Max Lybbert
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接