Как разместить обработчик предварительного просмотра в диалоговом окне

Я пытаюсь разместить обработчик предварительного просмотра файла в диалоговом окне. Я установил приемник событий для изменений выбора в проводнике. Когда выбор изменяется, я передаю выбранный элемент оболочки в диалоговое окно, которое, в свою очередь, передает его функции, которая подготавливает кадр предварительного просмотра.

Как правило, он успешно загружает правильный обработчик и отображает содержимое файла, но для определенных типов файлов (а именно файлов 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);
}

А теперь вот функция в моем диалоге, которая подготавливает предварительный просмотр, учитывая элемент оболочки (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 в разных местах, но без блокировки.

Кроме того, так выглядит ресурс диалога:

0 ответов

Другие вопросы по тегам