4

我正在尝试在对话框中托管文件预览处理程序。我已经为资源管理器中的选择更改设置了一个事件接收器。When the selection changes, I feed the selected shell item to the dialog, which in turn feeds it to a function that prepares the preview frame.

一般来说,它会成功加载正确的处理程序并显示文件的内容,但对于某些文件类型(即 Excel 和 Word 文件),它会遇到诸如焦点丢失或闪烁等各种问题。这是一个 Excel 预览处理程序弄乱焦点的演示(我的意思是弄乱,我的意思是它错误地从资源管理器中窃取了焦点,我想保持焦点):

在此处输入图像描述

Word 文件可能会成功加载一次,但随后会失败,尤其是在打开 Word 的情况下。

至于代码:

对于初学者,这是我从文件扩展名中获取预览处理程序的函数。这似乎工作正常:

HRESULT PreviewHandlerFromExt(LPCWSTR pszExt, IPreviewHandler** ppph)
{
    WCHAR szCLSID[CLSID_LEN] = { 0 };
    DWORD cchOut = CLSID_LEN;
    HRESULT hr = AssocQueryString(  ASSOCF_INIT_DEFAULTTOSTAR,
                                    ASSOCSTR_SHELLEXTENSION,
                                    pszExt,
                                    L"{8895b1c6-b41f-4c1c-a562-0d564250836f}",
                                    szCLSID,
                                    &cchOut );
    if (FAILED(hr))
    {
        return hr;
    }

    CLSID clsid;
    hr = CLSIDFromString(szCLSID, &clsid);
    if (FAILED(hr))
    {
        return hr;
    }

    CComPtr<IUnknown> punk;
    hr = punk.CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER);
    if (FAILED(hr))
    {
        return hr;
    }

    CComPtr<IPreviewHandler> pPrevHandler;
    hr = punk->QueryInterface(&pPrevHandler);
    if (FAILED(hr) || !pPrevHandler)
    {
        return hr;
    }

    return pPrevHandler.CopyTo(ppph);
}

现在这是我的对话框中准备预览的函数,给定一个 shell 项 (m_pPreviewHandler是活动的预览处理程序,IDC_PREVIEWFRAME是对话框中预览窗格的占位符,并且m_mapExtsToPreviewHandlers只是一个用于在用户遇到预览处理程序时存储它们的映射):

void CMyDialog::ShowPreview(IShellItem* pShItem)
{
    HRESULT hr;

    if (m_pPreviewHandler)
    {
        m_pPreviewHandler->Unload();
        m_pPreviewHandler.Release();
    }

    CComHeapPtr<WCHAR> pszPath;
    hr = pShItem->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
    if (FAILED(hr))
    {
        return;
    }

    LPWSTR pszExt = CharLower(PathFindExtension(pszPath));

    auto it = m_mapExtsToPreviewHandlers.find(pszExt);
    if (it == m_mapExtsToPreviewHandlers.end())
    {
        hr = PreviewHandlerFromExt(pszExt, &m_pPreviewHandler);
        if (FAILED(hr) || !m_pPreviewHandler)
        {
            return;
        }

        m_mapExtsToPreviewHandlers[pszExt] = m_pPreviewHandler;
    }

    else
    {
        m_pPreviewHandler = m_mapExtsToPreviewHandlers[pszExt];
    }

    CComPtr<IInitializeWithFile> pInitWithFile;
    hr = m_pPreviewHandler->QueryInterface(&pInitWithFile);
    if (SUCCEEDED(hr))
    {
        hr = pInitWithFile->Initialize(pszPath, STGM_READ);
        if (FAILED(hr))
        {
            return;
        }
    }

    else
    {
        CComPtr<IInitializeWithStream> pInitWithStream;
        hr = m_pPreviewHandler->QueryInterface(&pInitWithStream);
        if (SUCCEEDED(hr))
        {
            CComPtr<IStream> pStream;
            hr = SHCreateStreamOnFile(pszPath, STGM_READ, &pStream);
            if (FAILED(hr) || !pStream)
            {
                return;
            }

            hr = pInitWithStream->Initialize(pStream, STGM_READ);
            if (FAILED(hr))
            {
                return;
            }
        }
    }

    CWindow wndPreviewFrame( GetDlgItem(IDC_PREVIEWFRAME) );
    CRect rectPreviewFrame;
    wndPreviewFrame.GetClientRect(&rectPreviewFrame);

    hr = m_pPreviewHandler->SetWindow(wndPreviewFrame, &rectPreviewFrame);
    if (FAILED(hr))
    {
        return;
    }

    hr = m_pPreviewHandler->DoPreview();
    if (FAILED(hr))
    {
        return;
    }

    hr = m_pPreviewHandler->SetRect(&rectPreviewFrame);
    if (FAILED(hr))
    {
        return;
    }
}

有谁知道我做错了什么或者什么可以解决这些焦点问题?

我也试过LockSetForegroundWindow在不同的地方放置,但没有锁。

此外,对话框资源如下所示:

在此处输入图像描述

4

0 回答 0