【问题标题】:change the use of SHBrowseForFolder and struct BROWSEINFO TO - IFileOpenDialog将 SHBrowseForFolder 和 struct BROWSEINFO 的使用更改为 - IFileOpenDialog
【发布时间】:2020-08-31 17:08:13
【问题描述】:

直到现在——为了打开一个对话框,我使用了SHBrowseForFolder 函数。它会导致一些错误,我被告知使用IFileOpenDialog。 这是我需要替换的代码:

bool wvFM::SelectFileSystemObjectDialogTree(const WCDialogCreationOptions& in_options,
                                            WCDialogReply& out_Reply)
{
    AUTO_FUNC_DEBUG;

    DWORD osErr = NO_ERROR;
    WTErr wtErr = eNoErr;

    out_Reply.accept = false;

    if(in_options.m_flags[WCDialogCreationOptions::eSelectFolder]) {
        BROWSEINFO bi = {0};
        bi.hwndOwner = (HWND)in_options.m_owner;
        bi.pidlRoot = NULL; // TBD by callback BrowseCallbackProc
        bi.lpszTitle = in_options.m_windowTitle.c_str();
        bi.ulFlags = BIF_USENEWUI;    // to enable pasting path
        bi.lpfn = BrowseCallbackProc; // for initial dir option
        WTPathString initialLocationPathString(
            in_options.m_InitialDir.GetNativePathString());
        bi.lParam = in_options.m_InitialDir.IsValid()
                        ? (LPARAM)initialLocationPathString.c_str()
                        : NULL;

        LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

        // returns focus to the internal window of the plug
        ::SetFocus((HWND)in_options.m_owner);

        if(pidl != NULL) {
            TCHAR szPath[MAX_PATH];
            SHGetPathFromIDList(pidl, szPath);
            out_Reply.m_filePathRef = wvFM::WCStPath((char*)szPath);
            out_Reply.accept = true;
            IMalloc* imalloc = 0;
            if(SUCCEEDED(SHGetMalloc(&imalloc))) {
                imalloc->Free(pidl);
                imalloc->Release();
            }
        }
        return true;
    }

我不太确定如何进行这种转换。 感谢任何愿意提供帮助的人!

【问题讨论】:

  • 您似乎缺少函数的结尾。左大括号比右大括号多一个。
  • @danieloren 在尝试将此代码从 SHBrowseForFolder() 转换为 IFileOpenDialog 时,您到底遇到了什么问题?到目前为止,您尝试过哪些不适合您的方法?
  • @TedLyngmo 因为有问题的代码侧重于设置了 eSelectFolder 标志的情况,因此您所指的“缺失”代码包含更多代码来处理以下情况eSelectFolder 未设置。
  • @RemyLebeau 可能是。原来的缩进让它看起来好像真的不见了。
  • @danieloren "[SHBrowseForFolder] 导致一些错误" - 究竟是什么错误?

标签: c++ c windows function interface


【解决方案1】:

您显然正在使用具有某种自定义字符串类型的 3rd 方库,但您没有提供有关该字符串类型实际是什么的任何详细信息。我猜测字符串类型是基于char 的,因为您在将SHGetPathFromIDList() 的结果分配给out_Reply.m_filePathRef 时将其类型转换为char*,所以您很可能使用UNICODE undefined 编译您的项目,以便TCHAR 映射到char 而不是wchar_t。在这种情况下,SHBrowseForFolder() 将调用SHBrowseForFolderA() 而不是SHBrowseForFolderW()

IFileOpenDialog 根本不处理 ANSI 字符串,只处理 UNICODE 字符串,因此您必须根据需要在 3rd 方字符串类型和 Windows UTF-16 字符串之间来回转换。

SHBrowseForFolder()IFileOpenDialog 的转换大致如下所示(其中 toWString() 中的 YourStringType 是第 3 方字符串类型 - 在指示的地方进行所需的任何调整) :

std::wstring toWString(const YourStringType &str)
{
    const char pStr = ... pointer to str's characters ...;
    int sLen = ... length of str in chars, not counting the null terminator ...;

    std::wstring ws;

    int wLen = MultiByteToWideChar(CP_ACP, 0, pStr, slen, NULL, 0);
    if (wLen > 0)
    {
        ws.resize(wLen);
        MultiByteToWideChar(CP_ACP, 0, pStr, sLen, ws.data(), wLen);
    }

    return ws;
}

std::string toString(const wchar_t *ws)
{
    std::string s;

    int wLen = lstrlenW(s);
    int sLen = WideCharToMultiByte(CP_ACP, 0, ws, wLen, NULL, 0, NULL, NULL);
    if (sLen > 0)
    {
        s.resize(sLen);
        WideCharToMultiByte(CP_ACP, 0, ws, wLen, s.data(), sLen, NULL, NULL);
    }

    return s;
}

IShellItem* toShellItem(const YourStringType &path)
{
    IShellItem *pItem = NULL;
    if (FAILED(SHCreateItemFromParsingName(toWString(path).c_str(), NULL, IID_PPV_ARGS(&pItem))))
        pItem = NULL;
    return pItem;
}

bool wvFM::SelectFileSystemObjectDialogTree(const WCDialogCreationOptions& in_options,
                                            WCDialogReply& out_Reply)
{
    AUTO_FUNC_DEBUG;

    out_Reply.accept = false;

    if (in_options.m_flags[WCDialogCreationOptions::eSelectFolder]) {

        IFileOpenDialog *pFileOpen = NULL;
        if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOpen))))
            return false;

        FILEOPENDIALOGOPTIONS opts = 0;
        pFileOpen->GetOptions(&opts);
        
        pFileOpen->SetTitle(toWString(in_options.m_windowTitle).c_str());
        pFileOpen->SetOptions(opts | FOS_PICKFOLDERS);

        IShellItem *pItem = toShellItem(in_options.m_InitialDir);
        if (pItem)
        {
            pFileOpen->SetFolder(pItem);
            pItem->Release();
        }

        HWND hwndOwner = (HWND) in_options.m_owner;

        HRESULT hr = pFileOpen->Show(hwndOwner);
        ::SetFocus(hwndOwner);

        if (SUCCEEDED(hr))
        {
            if (SUCCEEDED(pFileOpen->GetResult(&pItem)))
            {
                PWSTR pszFilePath;
                if (SUCCEEDED(pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath)))
                {
                    out_Reply.m_filePathRef = wvFM::WCStPath(toString(pszFilePath).c_str());
                    out_Reply.accept = true;
                    CoTaskMemFree(pszFilePath);
                }
                pItem->Release();
            }
        }

        pFileOpen->Release();
        return true;
    }

    ...
}

【讨论】:

    猜你喜欢
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2018-04-23
    • 2011-02-08
    • 2013-02-01
    相关资源
    最近更新 更多