引子
首先,什么是Preview和Thumbnail?
简单理解,Windows下Preview就是预览,Thumbnail就是缩略图。
一图以蔽之。
其次,如何开发自己格式文件的Preview、Thumbnail?
使用Windows Shell中的IPreviewHandler、IThumbnailProvider
微软官方示例
-
Windows Shell preview handler(CppShellExtPreviewHandler)
https://code.msdn.microsoft.com/CppShellExtPreviewHandler-58db53b8
-
Windows Shell thumbnail handler(CppShellExtThumbnailHandler)
https://code.msdn.microsoft.com/CppShellExtThumbnailHandler-32399b35
Preview
Preview开发主要步骤:
-
新建RobotArtExtPreviewHandler工程
-
加入Art自己的处理逻辑(读取相关信息)
-
编译出dll
-
安装包将dll打包至指定目录,并注册
1、新建Win32 dll Empty项目
2、借鉴官方示例,添加dll注册处理模块
-
Shell extension handlers are COM objects implemented as DLLs.官方说明preview的shell扩展是一个作为dll实现的com对象。需要为其指定一个CLSID。
// {E46116A3-24EF-4525-8131-96C4E74F6FBE}
const CLSID CLSID_RobotArtPreviewHandler =
{ 0xe46116a3, 0x24ef, 0x4525, { 0x81, 0x31, 0x96, 0xc4, 0xe7, 0x4f, 0x6f, 0xbe } };
注:IPreviewHandler的GUID为8895b1c6-b41f-4c1c-a562-0d564250836f,所有自定义开发的preview组件均需挂在其下。
// Remove the registry key:
// HKCR\<File Type>\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
L"%s\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}", pszFileType);
if (SUCCEEDED(hr))
{
hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, szSubkey));
}
可以参考word文档.doc在注册表中的数据,如下图所示。
- DllRegisterServer函数中绑定自定义格式文件与新建组件
// Register the component.
hr = RegisterInprocServer(szModule, CLSID_RobotArtPreviewHandler,
L"RobotArtExtPreviewHandler.RobotArtPreviewHandler Class",
L"Apartment", APPID_RobotArtPreviewHandler);
if (SUCCEEDED(hr))
{
// Register the preview handler. The preview handler is associated
// with the .recipe file class.
hr = RegisterShellExtPreviewHandler(L".robx", CLSID_RobotArtPreviewHandler,
L"RobotArtPreviewHandler");
}
3、创建COM类,实现IPreviewHandler相关接口
class RobotArtPreviewHandler :
//public IInitializeWithStream,
public IInitializeWithFile,
public IPreviewHandler,
public IPreviewHandlerVisuals,
public IOleWindow,
public IObjectWithSite
注意这里面继承的接口,
IInitializeWithStream 重载函数获得文件流
// IInitializeWithStream
IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
对于较小的或者xml格式的自定义文件,可以采取文件流方式;微软官方的示例就是重载的IInitializeWithStream。
IInitializeWithFile 重载函数获得文件路径
// IInitializeWithFile
IFACEMETHODIMP Initialize(LPCWSTR pfilePath, DWORD grfMode);
这种方式,拿到的是文件路径,后续可以用自己的方式去解析文件。
IPreviewHandler 主要用到DoPreview,在其中实现自定义文件解析及PreviewWindow(就是资源管理器中右边预览窗格中你看到的)的Create 。
// IPreviewHandler
IFACEMETHODIMP SetWindow(HWND hwnd, const RECT *prc);
IFACEMETHODIMP SetFocus();
IFACEMETHODIMP QueryFocus(HWND *phwnd);
IFACEMETHODIMP TranslateAccelerator(MSG *pmsg);
IFACEMETHODIMP SetRect(const RECT *prc);
IFACEMETHODIMP DoPreview();
IFACEMETHODIMP Unload();
4、添加对话框资源,用来显示预览图片以及你想要显示的自定义信息。
这里需要注意一点是,如果你需要在预览窗口里进行单击操作之类,比如单击操作者就跳转到他的主页的话,就需要在DoPreview中CreateDialog时一定要注意为其指定回调函数,否则对话框内的消息com组件中响应不到。
INT_PTR CALLBACK DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
//HWND m_hwndPreview;头文件中定义的
m_hwndPreview = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_MAINDIALOG),
m_hwndParent, (DLGPROC)DlgProc);
INT_PTR CALLBACK DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch(msg)
{
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE)
{
// 如果执行了关闭
// 销毁对话框,将收到WM_DESTROY消息
DestroyWindow(hdlg);
}
return 0;
/*case WM_COMMAND:
{
if(LOWORD(wParam) == IDC_BUTTON_CREATOR)
{
}
}
return 0;*/
case WM_NOTIFY:
{
PNMLINK pNmlink = (PNMLINK)lParam;
if(pNmlink->hdr.code == NM_CLICK)
{
if((LOWORD(wParam) == IDC_SYSLINK_CREATOR) ||
(LOWORD(wParam) == IDC_SYSLINK_EDITOR))
{
{
HINSTANCE result = ShellExecute(NULL, _T("runas"), _T("iexplore.exe"), _T("http://www.robotart.com/WorksWall/Index"), NULL, SW_SHOWNORMAL);
}
}
}
}
return 0;
}
return (INT_PTR)FALSE;
}
还需要注意一点是在点击创建者Syslink响应中需要注意,shell扩展的用户权限可能不是很高,上述代码中ShellExecute启动浏览器未必会成功,需要加上runas予以提权。
5、注册与卸载
Regsvr32.exe CppShellExtThumbnailHandler.dll
Regsvr32.exe /u CppShellExtThumbnailHandler.dll
Thumbnail
Thumbnail开发主要步骤:
-
新建RobotArtThumbnailHandler 工程
-
加入Art自己的处理逻辑
-
编译出dll
-
安装包将dll打包至指定目录,并注册
主要步骤与Preview大致相同,也需要新建Win32 dll Empty项目、添加dll注册处理模块 ,只不过是实现的接口不一样而已。
class RobotArtThumbnailHandler :
//public IInitializeWithStream,
public IInitializeWithFile,
public IThumbnailProvider
// IThumbnailProvider
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
注:IThumbnailProvider的GUID为e357fccd-a995-4576-b01f-234630154e96,所有自定义开发的thumbnail组件均需挂在其下。
有关Preview、Thumbnail中图片的处理
Preview、Thumbnail中都需要用到图像,如果每次都将图片解到磁盘后再用势必不如将图片解到内存中快捷安全。所以在DocMeta Cfg中存了缩略图的base64字符串,shell扩展程序中使用时再由base64字符串转为img。你可以考虑在你的文件格式中将图片存成base64字符串。
有关Preview、Thumbnail的调试
Preview调试,attach prevhost进程即可。
Thumbnail调试,暂不知。thumbnail的调用进程在explore.exe中,不知道该attach谁。
敲重点:
一定要看官方示例,微软的例子写的很清楚明白。