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