我正在尝试在对话框中托管文件预览处理程序。我已经为资源管理器中的选择更改设置了一个事件接收器。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
在不同的地方放置,但没有锁。
此外,对话框资源如下所示: