【问题标题】:Get all files listed inside .exe directory not knowing location获取.exe目录中列出的所有文件不知道位置
【发布时间】:2014-03-13 08:25:46
【问题描述】:

我想我的问题是 - 我如何将 exe 位置的目录作为 LPCWSTR 获取,以便我可以将其输入到我的代码中

#include <iostream>
#include <Windows.h>
int main(int argc, char **argv)
{
WIN32_FIND_DATA a;
HANDLE swap = FindFirstFile(/*(LPCWSTR)__exe_directory__*/,&a);
if (swap!=INVALID_HANDLE_VALUE)
{
    do
    {
        char *sptn = new char [lstrlen(a.cFileName)+1];
        for (int c=0;c<lstrlen(a.cFileName);c++)
        {
            sptn[c]=char(a.cFileName[c]);
        }
        sptn[lstrlen(a.cFileName)]='\0';
        std::cout<<sptn<<std::endl;
    }
    while (FindNextFile(swap,&a));
}
else std::cout<<"undetected file\n";
FindClose(swap);
system("pause");
}

它会返回目录中列出的文件而不会出错。我知道我的代码在给定目录的情况下已经可以工作,我已经对其进行了测试。

【问题讨论】:

  • 我想使用GetModuleFileNameW 并且稍微修剪一下是不可能的?
  • 我试过getmodulefilenamew ...你说的稍微修剪一下是什么意思,请详细说明?当我把它放在那里GetModuleFileNameW(NULL,sptn,MAX_PATH)——首先,它不是一个LPCWSTR,当我输入cast它时,它会返回数字78作为输出?
  • 你不能使用 argv[0] 和 PATH 创建它吗?
  • @Jim 我只是在这个 int main(...) 环境中工作以测试我正在创建的函数,然后我只需将其复制并粘贴到我的主项目中。鉴于我的主项目中的函数是 void(),我将如何使用 argv[0]?即使那样,如果您无法在主函数中指定参数, __argv[0] 与 argv[0] 相同,但无论如何类型转换再次返回相同的数字 78,并且它首先不是 LPCWSTR。
  • 将窄字符串转换为宽字符串:stackoverflow.com/questions/19715144/…

标签: c++ winapi directory


【解决方案1】:

关键是使用GetModuleFileName()(传递nullptr作为模块句柄,引用当前进程EXE),然后调用PathRemoveFileSpec()(或PathCchRemoveFileSpec(),如果你不关心之前的Windows版本到 Windows 8) 从路径中删除文件规范。

要使用PathRemoveFileSpec(),您必须与Shlwapi.lib 链接,如MSDN documentation 中所述。

以这个可编译的代码为例:

#include <iostream>     // For console output
#include <exception>    // For std::exception
#include <stdexcept>    // For std::runtime_error
#include <string>       // For std::wstring
#include <Windows.h>    // For Win32 SDK
#include <Shlwapi.h>    // For PathRemoveFileSpec()

#pragma comment(lib, "Shlwapi.lib")

// Represents an error in a call to a Win32 API.
class win32_error : public std::runtime_error 
{
public:
    win32_error(const char * msg, DWORD error) 
        : std::runtime_error(msg)
        , _error(error)
    { }

    DWORD error() const 
    {
        return _error;
    }

private:
    DWORD _error;
};

// Returns the path without the filename for current process EXE.
std::wstring GetPathOfExe() 
{
    // Get filename with full path for current process EXE
    wchar_t filename[MAX_PATH];
    DWORD result = ::GetModuleFileName(
        nullptr,    // retrieve path of current process .EXE
        filename,
        _countof(filename)
    );
    if (result == 0) 
    {
        // Error
        const DWORD error = ::GetLastError();
        throw win32_error("Error in getting module filename.", 
                          error);
    }

    // Remove the file spec from the full path
    ::PathRemoveFileSpec(filename);

    return filename;
}

int main() 
{
    try 
    {
        std::wcout << "Path for current EXE:\n"
                   << GetPathOfExe() 
                   << std::endl;
    } 
    catch (const win32_error & e) 
    {
        std::cerr << "\n*** ERROR: " << e.what()
                  << " (error code: " << e.error() << ")" 
                  << std::endl;
    } 
    catch (const std::exception& e) 
    {
        std::cerr << "\n*** ERROR: " << e.what() << std::endl;
    }
}

在控制台中:

C:\Temp\CppTests>cl /EHsc /W4 /nologo /DUNICODE /D_UNICODE get_exe_path.cpp
get_exe_path.cpp

C:\Temp\CppTests>get_exe_path.exe
Path for current EXE:
C:\Temp\CppTests

PS
在您的代码中,您似乎指的是FindFirtFile() 的Unicode 版本(即FindFirstFileW(),因为在评论中您期望LPCWSTR,即const wchar_t*),但随后在以下代码中您使用ANSI/MBCS字符串(即char*)。

我建议您始终在现代 Windows C++ 代码中使用 Unicode UTF-16 wchar_t* 字符串:它更利于国际化,而现代 Win32 API 仅带有 Unicode 版本。

还要注意,由于您使用的是 C++,因此最好使用健壮方便的 字符串类(例如,std::wstring 用于 Microsoft Visual C++ 的 Unicode UTF-16 字符串),而不是 C-像原始字符指针。在 API 接口处使用原始指针(因为 Win32 API 具有 C 接口),然后安全地转换为 std::wstring

【讨论】:

  • 顺便问一下。我不熟悉c++,C++13的这个“时代”?当您引用 ::PathRemoveFileSpec(filename); 时——您将其指向哪个命名空间?你怎么能就这么写出来?对我来说没有意义。是不是默认只取标准?
  • PathRemoveFileSpec() 是一个纯 C 接口 Win32 API 函数。它属于“全局命名空间”,我习惯在 Win32 C API 前加上 ::(这可能很有用,例如,当你在一个 C++ 类中,它可能有一个名为 Win32 API 函数的方法,所以用::您清楚地识别出“全局”Win32 C 接口 API 函数)。
  • 啊,嗯,谢谢你的提示,我一定会把它应用到我的代码中。在旁注中,您声明 FindFirstFileW() 需要 wchar_t* 用于 LPCWSTR,但是当我将 GetPathOfExe() 函数添加为参数一时,它表示没有从 std::wstring 到 LPCWSTR 的合适转换。我有什么办法可以解决这个问题?
  • std::wstring 没有到LPCWSTR 的隐式转换运算符(与CString 不同)。另一种方法是调用std::wstring::c_str() 成员函数,该函数返回const wchar_t*(即LPCWSTR)。
  • 两件事,首先,我如何将 std::wstring::c_str() 放入 getpathofexe() 函数,因为这是导致类型转换错误的函数。此外,我觉得我对所有这些现代 C++ jibber jabber 都非常“过时”。我一生都在用 C 编程(只用了 6 年)。现在,当我来到这些新一代论坛时,我对人们向我抛出的所有这些我从未听说过的新功能感到非常难过。如果您可以向我推荐一本可以启发我的 C 程序员的 C++ 书籍,您认为有可能吗? :)
【解决方案2】:

在 UNICODE 构建中使用 GetModuleFileName 函数获取宽字符串中的可执行完整文件名。

然后,搜索最后一个 '\' 字符并将其替换为 0。

完成。

#include <Windows.h>
#include <stdio.h>

int main( void ) {
    wchar_t szExeFullPath[ MAX_PATH ];
    if ( GetModuleFileName( NULL, szExeFullPath, _countof( szExeFullPath ) ) ) {
        wchar_t * pszLastAntiSlash = wcsrchr( szExeFullPath, L'\\' );
        if ( pszLastAntiSlash ) {
            *pszLastAntiSlash = 0;
            wprintf( L"Exe full path is %s\n", szExeFullPath );
        }
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 2015-01-05
    • 2010-12-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 2017-02-16
    • 2011-06-13
    • 1970-01-01
    相关资源
    最近更新 更多