【问题标题】:HRESULT to string (getting documents path) C++HRESULT 到字符串(获取文档路径)C++
【发布时间】:2014-09-02 14:02:14
【问题描述】:

我正在使用以下函数尝试获取文档文件夹的路径,然后将该路径转换为 ​​std::string:

std::string getpath() {
    TCHAR documents[MAX_PATH];
    HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
    std::stringstream pff;
    pff << result;
    return pff.str();
}

执行此操作时,我在尝试将“\filename”附加到字符串时收到“无效文件名错误”。

请帮忙!

编辑:这是我附加到路径的方式:

std::string folder = getpath() + "\\Folder";

我认为双转义符号仍然适用。

【问题讨论】:

    标签: c++ winapi directory stdstring


    【解决方案1】:

    您打印的不是documents,而是result

    试试这样的:

    std::string getpath() {
        TCHAR documents[MAX_PATH];
    
        HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
        if (result == S_OK) // SUCCEEDED(result) can be problematic
                            // since S_FALSE is a possible return value
        {
            std::stringstream pff;
            pff << documents;
            return pff.str();
        }
        // handle error somehow
        return "";
    }
    

    这是一个 Unicode 友好的版本:

    std::wstring getpath() {
        TCHAR documents[MAX_PATH];
    
        HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
        if (result == S_OK) // SUCCEEDED(result) can be problematic
            // since S_FALSE is a possible return value
        {
            std::wstringstream pff;
            pff << documents;
            return pff.str();
        }
        // handle error somehow
        return L"";
    }
    

    【讨论】:

    • 文件仍然是 TCHAR
    • +1 但您需要将字符串缓冲区的长度传递给 SHGetFolderPath:其中一个参数不应为 NULL。
    • @Bathsheba 应该是 MAX_PATH 缓冲区,见SHGetFolderPath
    • 我想我需要转换错误代码结果才能输出路径。
    • @user3295336 否 :)。但请注意TCHAR。如果您的项目使用 Unicode,您可能需要使用 wstringwstringstream
    【解决方案2】:

    您的代码失败了,因为您实际上是从SHGetFolderPath返回值(即错误代码)构造一个字符串。您应该改用返回的路径。

    由于SHGetFolderPath 已被弃用,您应该改用SHGetKnownFolderPath。除此之外,您不会意外地构造一个 MBCS 编码的路径名。并且没有任意的MAX_PATH (260) 个字符限制。

    以下代码检索当前用户的文档路径1

    #include <string>
    #include <ShlObj.h>
    #include <comdef.h>
    
    std::wstring GetDocumentPath() {
        wchar_t* pOut = nullptr;
        // Retrieve document path (CheckError throws a _com_error exception on failure)
        _com_util::CheckError( ::SHGetKnownFolderPath( FOLDERID_Documents, KF_FLAG_DEFAULT,
                                                       nullptr, &pOut ) );
        // Attach returned buffer to a smart pointer with custom deleter. This
        // is necessary, because the std::wstring c'tor throws on failure.
        // Without this smart pointer, any exception would leak memory.
        auto deleter = []( void* p ) { ::CoTaskMemFree( p ); };
        std::unique_ptr<wchar_t, decltype( deleter )> buffer{ pOut, deleter };
        return std::wstring{ buffer.get() };
        // Invisible: Run deleter for buffer, cleaning up allocated resources.
    }
    

    注意:_com_util::CheckError 没有正式记录,因此它可能在编译器的未来版本中变得不可用。具有类似功能的自定义实现可能如下所示:

    inline void CheckError( HRESULT hr ) {
        if ( FAILED( hr ) ) {
            _com_raise_error( hr );
        }
    }
    

    _com_raise_error 被记录为抛出 _com_error 异常。还记录了 FAILED 宏。


    1已知的文件夹路径是可自定义的(参见Folder Redirection Overview)。您不能简单地尝试自己构建它们。您必须向 Shell 询问此信息。

    【讨论】:

      【解决方案3】:

      我最终放弃了 SHGetFolderPath 并使用了更直接的 _dupenv_s:

      std::string getpath() {
          char* buf = 0;
          size_t sz = 0;
          if (_dupenv_s(&buf, &sz, "USERPROFILE") == 0) {
              std::string path(buf);
              path += "\\Documents\\Folder";
              return path;
          }
          return NULL;
      }
      

      【讨论】:

      • 这对于文档文件夹位于其他位置的系统失败。而且由于文档文件夹是可自定义的用户设置,因此您的代码失败不仅仅是理论上的可能性。内存泄漏和使用 MBCS 字符编码只会增加错误。请务必使用 tour 并访问 help center 以了解 Stack Overflow 是关于质量的答案。这个肯定不是。
      • 我想留下我的答案,因为它满足了问题的上下文。我没有具体说明解决方案是否应该是安全的。这是为了测试和概念目的,以便训练自己。尽管如此,我想我至少应该添加一个 try-catch 并明确声明:这不适合商业用途。因此,“-1”可能会稍微误导您。 SO 是关于学习。下次我会通过帮助中心回答。
      • “SO 是关于学习的。” - 这是错误的。 SO 是一个问答网站。它是关于解决 问题,用质量 解决方案。我不知道,try-catch 块会有什么好处。如果有的话,它会进一步恶化这个代码。由于很多原因,它是错误的,最重要的是,它没有解决所提出的问题(请参阅Folder Redirection Overview 以了解它为什么会失败并且将会失败)。有鉴于此,投反对票是合适的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-14
      • 1970-01-01
      • 2019-03-12
      • 1970-01-01
      相关资源
      最近更新 更多