如何让特定格式的文件在Windows下显示缩略图及预览.docx
- 文档编号:30771137
- 上传时间:2023-08-23
- 格式:DOCX
- 页数:16
- 大小:340.34KB
如何让特定格式的文件在Windows下显示缩略图及预览.docx
《如何让特定格式的文件在Windows下显示缩略图及预览.docx》由会员分享,可在线阅读,更多相关《如何让特定格式的文件在Windows下显示缩略图及预览.docx(16页珍藏版)》请在冰豆网上搜索。
如何让特定格式的文件在Windows下显示缩略图及预览
如何让特定格式的文件在Windows下显示缩略图及预览
深圳市中科数码技术有限公司–研发部余浩2011-10-23yh@
概述:
在Windows中系统默认提供了对很多常见格式的文件的缩略图或预览,最典型的就是如jpg、bmp等格式的文件,让我们不用其他工具打开文件就可以知道文件的内容。
对于其他特定格式的文件是不是也可以让其有这样的缩略图或预览功能呢,答案当然是肯定的。
本文描述了在WindowXP下和Windows7下实现缩略图或预览功能的方法。
下图为在Windows7下实现缩略图和预览功能的效果图:
一、WindowsXP下实现缩略图功能
1.实现的原理
在WindowsXP下实现缩略图功能根本上就是实现IExtractImage、IExtractImage2和IPersistFile中的各种方法。
上述接口中的各种方法都必须有相应的实现函数,函数如果没有具体内容可以返回E_NOTIMPL,代码如下:
//IExtractImage
STDMETHOD(GetLocation)(LPWSTRpszPathBuffer,
DWORDcchMax,
DWORD*pdwPriority,
constSIZE*prgSize,
DWORDdwRecClrDepth,
DWORD*pdwFlags);
STDMETHOD(Extract)(HBITMAP*);
//IExtractImage2
STDMETHOD(GetDateStamp)(FILETIME*pDateStamp);
//IPersistFile
STDMETHOD(Load)(LPCOLESTRwszFile,DWORDdwMode);
STDMETHOD(GetClassID)(LPCLSIDclsid){returnE_NOTIMPL;}
STDMETHOD(IsDirty)(VOID){returnE_NOTIMPL;}
STDMETHOD(Save)(LPCOLESTR,BOOL){returnE_NOTIMPL;}
STDMETHOD(SaveCompleted)(LPCOLESTR){returnE_NOTIMPL;}
STDMETHOD(GetCurFile)(LPOLESTRFAR*){returnE_NOTIMPL;}
上述即只实现了四个方法GetLocation、Extract、GetDateStamp和Load,其他方法均返回E_NOTIMPL。
2.实现的方法
在codeproject网上有一个例子,而且有一个VC6的工程向导。
利用该向导并添加适当的代码就可以显示特定格式文件的缩略图。
上文是对该例子的简化,原例子在Load方法中先在DC上绘图然后在保存HBITMAP,本文直接用GDI+的方法生成了一个HBITMAP(主要不同请查看Load方法具体实现的不同之处)。
各方法的具体实现如下:
HRESULTCGydTydPreviewExtractor:
:
GetLocation(LPWSTRpszPathBuffer,
DWORDcchMax,DWORD*pdwPriority,
constSIZE*prgSize,DWORDdwRecClrDepth,
DWORD*pdwFlags)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
m_bmSize=*prgSize;
if(*pdwFlags&IEIFLAG_ASYNC)returnE_PENDING;
returnNOERROR;
}
HRESULTCGydTydPreviewExtractor:
:
Load(LPCOLESTRwszFile,DWORDdwMode)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
USES_CONVERSION;
_tcscpy(m_szFile,OLE2T((WCHAR*)wszFile));
BOOLbLoad=FALSE;
GdiplusStartupInputstartupInput;
ULONG_PTRgdiplusToken;
Statusret=GdiplusStartup(&gdiplusToken,&startupInput,NULL);
CFilefile;
if(file.Open(m_szFile,CFile:
:
modeRead))
{
file.Seek(26,CFile:
:
begin);
WORDwBitCounts;
DWORDdwVersion;
file.Read(&dwVersion,4);
if(dwVersion>=20090612)
{
file.Read(&wBitCounts,2);
BYTE*pBits=(BYTE*)GlobalAlloc(GMEM_ZEROINIT,450000);
BYTE*pt=(BYTE*)GlobalAlloc(GMEM_ZEROINIT,wBitCounts+5000);
file.Read(pt,wBitCounts);
shortnWidth=100;
longlen=uncode_expand(pt,pBits,wBitCounts);
GlobalFree(pt);
if(len==40000)
nWidth=100;
else
nWidth=256;
Bitmap*pBitmap=newBitmap(nWidth,nWidth,nWidth*4,PixelFormat32bppRGB,pBits);
if(pBitmap)
{
bLoad=TRUE;
ret=pBitmap->GetHBITMAP(Color(0,0,0),&m_hPreview);
ASSERT(ret==Ok);
deletepBitmap;
}
GlobalFree(pBits);
}
file.Close();
}
if(!
bLoad)
{
Bitmap*pBitmap=Bitmap:
:
FromResource(AfxGetInstanceHandle(),A2OLE(MAKEINTRESOURCE(IDB_DEMO)));
if(pBitmap)
{
ret=pBitmap->GetHBITMAP(Color(0,0,0),&m_hPreview);
ASSERT(ret==Ok);
deletepBitmap;
}
}
returnS_OK;
};
上述Load函数是实现对特定文件进行缩略图的关键,在这里你可以对特定格式的文件进行解析,然后生成HBITMAP保存为成员变量。
本示例中的*.GYD或*.TYD文件在文件头部保存有一个BMP格式缩略图文件,在Load中将其读取,用GDI+的Bitmap生成HBITMAP。
//IExtractImage:
:
Extract
HRESULTCGydTydPreviewExtractor:
:
Extract(HBITMAP*phBmpThumbnail)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(m_hPreview!
=NULL)
{
*phBmpThumbnail=m_hPreview;
returnNOERROR;
}
else
returnE_FAIL;
}
上述Extract函数是缩略图的实现,它告诉系统用你所生成的HBITMAP去显示缩略图。
HRESULTCGydTydPreviewExtractor:
:
GetDateStamp(FILETIME*pDateStamp)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
FILETIMEftCreationTime,ftLastAccessTime,ftLastWriteTime;
//openthefileandgetlastwritetime
HANDLEhFile=CreateFile(m_szFile,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(!
hFile)returnE_FAIL;
GetFileTime(hFile,&ftCreationTime,&ftLastAccessTime,&ftLastWriteTime);
CloseHandle(hFile);
*pDateStamp=ftLastWriteTime;
returnNOERROR;
}
3.如何调试
codeproject网上的例子提供了一个vb编写的测试程序TestThumbExtract.exe,使用该程序可以对使用向导生成的VC6工程进行调试。
二、Windows7下实现缩略图功能
1.实现原理
在Vista、Win7下MS提供了新的接口来显示缩略图,尽管MS宣称旧的IExtractImage、IExtractImage2接口依然支持,但是我的缩略图程序在WindowsXP下运行良好而在Windows7上却没有什么反应。
新的接口名字为:
IThumbnailProvider,在该接口中只有一个方法需要实现,实现该方法便可以显示特定文件的缩略图,该方法定义如下:
//IThumbnailProvider
IFACEMETHODIMPGetThumbnail(UINTcx,HBITMAP*phbmp,WTS_ALPHATYPE*pdwAlpha);
2.实现方法
在SDK中有例子RecipeThumbnailProvider,照本宣科修改为我所用即可。
SDK的例子中使用了WIC的CODEC中imagefactory和decoder的接口及方法实现缩略图,本文使用GDI+的方法实现,对其进行了简化。
同在WindowsXP下一样在该方法中加载并解析特定的文件即可,本文是在IStream中解析文件的。
如果使用IInitializeWithFile,则可以直接获取文件路径,然后对文件进行解析。
在MSDN中说明如果没有什么特殊情况,最好使用IInitializeWithStream接口。
GetThumbnail的具体内容如下:
//IThumbnailProvider
IFACEMETHODIMPCGydTydThumbProvider:
:
GetThumbnail(UINTcx,HBITMAP*phbmp,WTS_ALPHATYPE*pdwAlpha)
{
*pdwAlpha=WTSAT_ARGB;
LARGE_INTEGERliSeek;
liSeek.HighPart=0;
liSeek.LowPart=26;
HRESULThr=_pStream->Seek(liSeek,STREAM_SEEK_SET,NULL);
if(SUCCEEDED(hr))
{
DWORDdwVersion=0;
ULONGdwReaded=0;
hr=_pStream->Read(&dwVersion,4,&dwReaded);
if(SUCCEEDED(hr)&&dwVersion>=20090612)
{
DWORDdwLen=0;
hr=_pStream->Read(&dwLen,2,&dwReaded);
if(SUCCEEDED(hr))
{
BYTE*bits=(BYTE*)GlobalAlloc(GMEM_ZEROINIT,450000);//最大*256*4
BYTE*pt=(BYTE*)GlobalAlloc(GMEM_ZEROINIT,dwLen+5000);
hr=_pStream->Read(pt,dwLen,&dwReaded);
intlen=uncode_expand(pt,bits,dwLen);
GlobalFree(pt);
WORDwWid=100;//每个像素用4个字节存储
if(len!
=40000)//旧版本的缩略图为100*100,新版为256*256
wWid=256;
GdiplusStartupInputstartupInput;
ULONG_PTRgdiplusToken;
Statusret=GdiplusStartup(&gdiplusToken,&startupInput,NULL);
Bitmap*pBitmap=newBitmap(wWid,wWid,wWid*4,PixelFormat32bppRGB,bits);
if(pBitmap)
{
ret=pBitmap->GetHBITMAP(Color(0,0,0),phbmp);
if(ret==Ok)
hr=S_OK;
else
hr=S_FALSE;
deletepBitmap;
pBitmap=NULL;
}
GdiplusShutdown(gdiplusToken);//shutdownGDIPlus
GlobalFree(bits);
}
}
}
returnhr;
}
3.如何调试
SDK中UsingThumbnailProviders工程可以对你的工程进行调试,该工程的路径一般在X:
\ProgramFiles\MicrosoftSDKs\Windows\v7.1\Samples\winui\shell\appplatform\UsingThumbnailProviders,readme.txt中有详细的调试方法。
VS2008调试设置见下图:
三、Windows7下实现预览功能
1.实现原理
预览功能是WindowsVista和Windows7的新功能,实现预览功能的接口为IPreviewHandler,该接口有下列方法:
//IPreviewHandler
IFACEMETHODIMPSetWindow(HWNDhwnd,constRECT*prc);
IFACEMETHODIMPSetFocus();
IFACEMETHODIMPQueryFocus(HWND*phwnd);
IFACEMETHODIMPTranslateAccelerator(MSG*pmsg);
IFACEMETHODIMPSetRect(constRECT*prc);
IFACEMETHODIMPDoPreview();
IFACEMETHODIMPUnload();
上述方法都必须实现,其中DoPreview方法具体实现预览的功能。
2.实现方法
SDK中有例子RecipePreviewHandler,同样照本宣科改一改为我所用即可。
该例子中使用RichEdit进行预览,这里用一个现成的oxc预览*.GYD或*.TYD文件。
要实现ocx控件显示预览有如下步骤:
I.添加头文件及库
Ocx也是一种COM组件,要使用COM的接口和方法必须添加下来头文件和库文件。
//atl的头文件,调用ocx需要用
#include
CComModule_Module;
#include
#include
#pragmacomment(lib,"atl")
II.添加OCX类型库信息(typeinformation)
添加OCX的tlb文件有两种方法:
第一种使用improt导入OCX类型库:
#import"..\\..\\bin\\GYardControlVC90.ocx"\
raw_interfaces_only,/*Don'taddraw_tomethodnames*/\
raw_native_types,/*Don'tmaptoDTCsmarttypes*/\
named_guids,/*Namedguidsanddeclspecs*/\
no_namespace/*Don'twrapwithC++namespace*/
使用这种方法在Debug或Release目录会自动生成OCX同名的tlh文件,工程中不把再添加什么头文件或者库文件。
第二中是使用OLE/COMObjectViewer导出的类型库,步骤如下:
首先使用OLE/COMObjectViewer来找到GYardControl,点击右键“ViewTypeInformation”,在弹出的界面中,点击“saveas”将信息保存为gctrl.IDL文件。
然后在打开VS提供的工具:
“VisualStudio2008命令提示”,进入DOS界面,切换到gctrl.IDL所在的目录,执行如下命令:
MIDLgctrl.IDL/tlbgctrl.tlb,即可生成tlb文件。
如果生成过程有错,提示“errorMIDL2110:
endoffilefoundinstring”,可以这样做:
将前面打开的界面中(“ViewTypeInformation”)的内容拷贝,然后手动新建一个gctrl.IDL的文件,将拷贝的内容粘贴入,再次执行MIDL命令。
接下来在你的VC++项目中:
#import"gctrl.tlb",编译之,即会在debug或者release目录下面生成tlh(头文件,header)和tli文件(实现文件,implementation)。
注意,在tlh文件的末尾处已经包含了tli文件。
注意:
如果你的OCX中有Release方法,在VS2008下编译可能报告方法与COM里面的方法有重定义的错误,这时可以先手工编辑一下gctrl.idl文件,删除其中关于Release的定义。
但是最好的解决办法是在你的OCX中尽量不用使用系统常使用的名称作为你的方法名,避免不必要的麻烦。
III.DoPreview方法的具体实现
定义如下私有成员变量:
_bstr_t_filePath;//文件路径
CAxWindowm_content_wnd;
_DGYardControl*m_gcl;
shortm_nFileType;//文件类型,0:
*.GYD;1:
*.TYD
DoPreview的具体实现如下:
//Themainmethodthatextractsrelevantinformationfromthefilestreamand
//drawscontenttothepreviewerwindow
HRESULTCGydTydPreviewHandler:
:
DoPreview()
{
HRESULThr=E_FAIL;
if(_hwndPreview==NULL)//cannotcallmorethanonce(UnloadshouldbecalledbeforeanotherDoPreview)
{
hr=_CreatePreviewWindow();
}
returnhr;
}
HRESULTCGydTydPreviewHandler:
:
_CreatePreviewWindow()
{
if(m_nFileType<0)returnE_FAIL;//文件类型不识别
assert(_hwndPreview==NULL);
HRESULThr=E_FAIL;
CoInitialize(NULL);
LPOLESTRpstocx;
CLSIDgocxCLSID;
CLSIDFromProgID(L"GYARDCONTROL.GYardControlCtrl.1",&gocxCLSID);
StringFromCLSID(gocxCLSID,&pstocx);
if(m_content_wnd.IsWindow())
m_content_wnd.DestroyWindow();
_hwndPreview=m_content_wnd.Create(_hwndParent,_rcParent,
LPCTSTR(pstocx),WS_CHILD|WS_VISIBLE);//createaGyardControl
if(_hwndPreview)
{
hr=m_content_wnd.QueryControl(&m_gcl);
if(SUCCEEDED(hr))
{
m_gcl->InstanceYard();
BOOLbLoad=FALSE;
if(m_nFileType==0)//*.gyd文件调用LoadFromGFile
bLoad=m_gcl->LoadFromGFile(_filePath);
else
bLoad=m_gcl->LoadFromTFile(_filePath);
if(bLoad)
hr=S_OK;
}
}
else
hr=HRESULT_FROM_WIN32(GetLastError());
CoTaskMemFree(pstocx);
CoUninitialize();
returnhr;
}
3.如何调试
这类程序进行调试可以参考RecipePreviewHandler工程的readme.txt中的描述。
具体设置如下:
首先,设置可以附加到现有进程中进行调试,prevhost.exe是Windows提供预览的服务进程,系统中可能同时有多个预览服务进程,因此可以在命令参数中添加如下语句进行识别:
{540D08F0-C59A-4ca1-AC92-D6A7F6E14865}–Embedding
前面一个参数就是你预览程序的CLSID。
VS2008的调试设置见下图:
四、总结
首先,感谢各位专家提供的各种示例程序,我也只是在他们的基础上修修改
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 如何 特定 格式 文件 Windows 显示 缩略图 预览