以缩略图的形式在Windows资源浏览器中显示自定义格式图片

本文主要是介绍以缩略图的形式在Windows资源浏览器中显示自定义格式图片,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

在公司培训有一段时间了,终于接到了部门任务,需求很简单,就是先Windows Explorer中以缩略图的形式显示自定义的图片,部门提供图片解码代码,我和我的同事实现需求,在实现的过程中走了很多的弯路,犯了不少错误,不过最终我们还是完成了,通过这次实践我相信的能力又提高了很多,本文不阐述开发过程中遇到了什么问题,只是说明如何实现这个需求的步骤。

   开发语言是C++,工具VC6,需要有COM的知识以及ATL的使用,当然COM和ATL我基本不会,都是在这次任务中学习的,如果跟我一样没有学过COM的,建议先看看《COM本质论》至少把什么是COM以及简单实现原理搞清楚,否则就算实现了,意义也不大。

  其实实现非常简单,只需要3个接口就可以搞定,分别是IPersistFile, IExtractImage和IExtractImage2,每个接口的作用可以查MSDN得到,描述的很清楚,这里就不说了,简单说下原理,假设你的图片后缀名为.tp,那么当你在资源浏览器中点到.tp的文件,或者使用缩略图显示图片的时候当前文件夹中有.tp的文件,那么系统会请求IPersistFile接口的Load方法,这里可以得到选择或浏览到的文件名(包括路径),然后请求IExtractImage接口的GetLocation方法,最后请求IExtractImage的Extract方法,你只需要返回你图片的HBITMAP就可以了,大小都不需要你自己改变,系统会帮你缩小在显示在资源浏览器上。

  下边是详细的实现步骤:

  1。打开VC6建立一个ATL工程,名字为TPThumbnail,OK and Finish。

  2。选择Insert->New ATL Object。然后选择Simple Object,Next,ShortName写TPeExtract其他的也就会自动填写上了,点OK。

  这里牢骚2句,IExtractImage和IExtractImage2接口在MSDN中说只在VISTA中提供,所以你要想实现这2个接口,必须从VISTA的SDK中把这2个接口的声明弄出来,这点不明白MS怎么想的,为什么不在XP中直接提供。

  3。此时TPeExtract.h是实现IDispatchImpl接口的,这个对我们没什么用处,所以我们把他去掉(CComObjectRootEx和CComCoClass接口不要删除), COM_INTERFACE_ENTRY(IDispatch)和COM_INTERFACE_ENTRY(ITPeExtract)这个也要删除,然后#include "IExtractImage.h" 头文件,并把这2个实现加上去,然后实现这3个接口的方法就可以了。最后的TPeExtract.h如下:

 

//  TPeExtract.h : Declaration of the CTPeExtract

#ifndef __TPEEXTRACT_H_
#define  __TPEEXTRACT_H_

#include 
" resource.h "         //  main symbols
#include  " IExtractImage.h "

/////
//  CTPeExtract
class  ATL_NO_VTABLE CTPeExtract : 
    
public  CComObjectRootEx < CComSingleThreadModel > ,
    
public  CComCoClass < CTPeExtract,  & CLSID_TPeExtract > ,
    
public  IPersistFile,
    
public  IExtractImage2
{
public:
    CTPeExtract();


DECLARE_REGISTRY_RESOURCEID(IDR_TPEEXTRACT)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CTPeExtract)
    COM_INTERFACE_ENTRY(IPersistFile)
    COM_INTERFACE_ENTRY(IExtractImage)
    COM_INTERFACE_ENTRY(IExtractImage2)
END_COM_MAP()

// IExtractImage
public:
    
    STDMETHOD(GetLocation)(LPWSTR pszPathBuffer,
        DWORD cchMax,
        DWORD 
*pdwPriority,
        
const SIZE *prgSize,
        DWORD dwRecClrDepth,
        DWORD 
*pdwFlags);
    STDMETHOD(Extract)(HBITMAP
*);
    
// IExtractImage2
    STDMETHOD(GetDateStamp)(FILETIME *pDateStamp);
    
    
// IPersistFile
    STDMETHOD(Load)(LPCOLESTR wszFile, DWORD dwMode);
    
    STDMETHOD(GetClassID)(LPCLSID clsid)
    
return E_NOTIMPL;    }
    
    STDMETHOD(IsDirty)(VOID)
    
return E_NOTIMPL; }
    
    STDMETHOD(Save)(LPCOLESTR, BOOL)
    
return E_NOTIMPL; }
    
    STDMETHOD(SaveCompleted)(LPCOLESTR)
    
return E_NOTIMPL; }
    
    STDMETHOD(GetCurFile)(LPOLESTR FAR
*)
    
return E_NOTIMPL; }
}
;

#endif   // __TPEEXTRACT_H_

  当然现在是编译不通过的,因为有些方法没实现,其中象Save, GetCurFile等等在本例中没有用到。所以直接返回E_NOTIMPL就可以了。

  4。然后增加1个成员变量TCHAR m_szFileName[MAX_PATH]; 这个是保存文件名用的。

  5。在构造函数中初始化szFileName。

CTPeExtract::CTPeExtract()
{
    ZeroMemory(m_szFileName, MAX_PATH);
}

  6。现在实现Load方法,这个方法只保存传入的文件名,代码如下:

HRESULT CTPeExtract::Load(LPCOLESTR wszFile, DWORD dwMode)
{
    USES_CONVERSION;
    _tcscpy(m_szFileName, OLE2T((WCHAR
*)wszFile)); 

    
return S_OK;    
}
;

   7。实现GetLocation。

HRESULT CTPeExtract::GetLocation(LPWSTR pszPathBuffer,
                                        DWORD cchMax, DWORD 
* pdwPriority,
                                        
const  SIZE  * prgSize, DWORD dwRecClrDepth,
                                        DWORD 
* pdwFlags)
{
    
if (*pdwFlags & IEIFLAG_ASYNC)    
        
return E_PENDING; 

    
return NOERROR;
}

  有人会问为什么return E_PENDING;这个你看MSDN就知道,让是XP or later的系统,就必须这样做。

  8。重要的函数Extract的实现,这个函数是系统问你要你这个图片的HBITMAP,给他就是了,这里就写你图片的解码,由于是例子所以我直接加载个资源就可以了。

HRESULT CTPeExtract::Extract(HBITMAP *  phBmpThumbnail)

    HBITMAP hBM 
= 0;
    hBM 
= ::LoadBitmap(_Module.GetModuleInstance(),MAKEINTRESOURCE(IDB_BITMAP1)); 
    
if (0 != hBM)
        
*phBmpThumbnail = hBM;
    
return NOERROR; 
}

  9。最后是GetDateStamp函数的实现,这个是IExtractImage2的函数,具体作用看MSND。

HRESULT CTPeExtract::GetDateStamp(FILETIME  * pDateStamp)
{
        
    FILETIME ftCreationTime,ftLastAccessTime,ftLastWriteTime;

    HANDLE hFile 
= CreateFile(m_szFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
        OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    
if(!hFile)
        
return E_FAIL;
    GetFileTime(hFile,
&ftCreationTime,&ftLastAccessTime,&ftLastWriteTime);
    CloseHandle(hFile);
    
*pDateStamp = ftLastWriteTime;
    
return NOERROR; 
}

这个是编译就可以通过了。  TPThumbnail.dll - 0 error(s), 0 warning(s)

但是,光这样还不够,还需要最重要的一步,就是这个组件注册到合适的地方。这样修改Resource Files中的TPeExtract.rgs文件。修改后如下:

HKCR
{
    TPThumbnail.TPeExtract
.1   =  s 'TPeExtract Class'
    {
        CLSID 
=  s '{E45A903D-53AE-4A14-906E-0260D13FF77F}'
    }
    TPThumbnail.TPeExtract 
=  s 'TPeExtract Class'
    {
        CLSID 
=  s '{E45A903D-53AE-4A14-906E-0260D13FF77F}'
        CurVer 
=  s 'TPThumbnail.TPeExtract .1 '
    }
    NoRemove CLSID
    {
        ForceRemove {E45A903D-53AE-4A14-906E-0260D13FF77F} 
=  s 'TPeExtract Class'
        {
            ProgID 
=  s 'TPThumbnail.TPeExtract .1 '
            VersionIndependentProgID 
=  s 'TPThumbnail.TPeExtract'
            ForceRemove 'Programmable'
            InprocServer32 
=  s '%MODULE%'
            {
                val ThreadingModel 
=  s 'Apartment'
            }
            'TypeLib' 
=  s '{F473925C-FDEE-42AD-9FC2-C843DB7BA2B2}'
        }
    }

    NoRemove .tp
    {
        shellex
        {
            {BB2E617C-
0920 -11d1-9A0B-00C04FC2D6C1}  =  s '{E45A903D-53AE-4A14-906E-0260D13FF77F}'
        }
    }

    NoRemove 
.1
    {
        shellex
        {
            {BB2E617C-
0920 -11d1-9A0B-00C04FC2D6C1}  =  s '{E45A903D-53AE-4A14-906E-0260D13FF77F}'
        }
    }
}

  这里的 .tp 就是关联的文件后缀名,BB2E617C-0920-11d1-9A0B-00C04FC2D6C1是IUnknow接口的CLSID,E45A903D-53AE-4A14-906E-0260D13FF77F是本例的CLSID,如果你在开发中需要修改这个CLSID就可以了。

  编译, PASS~~~

  现在需要注册这个COM组件,方法很简单。开始-运行-cmd。

  注册: regsvr32 编译出来的DLL

  反注册,就是移除: regsvr32 /u 编译出来的DLL

  注册和反注册都会有提示的,这个时候你在任意文件夹下建一个后缀名为.tp的文件就可以看到效果了,再切换到缩略图看看。

  最后再次感谢帮助我的人,还有和我一起开发的同事,他在整个开发中给我提出了很多中肯的意见以及帮助。

  (本代码只是例子,并没有做详尽的测试)

因源码链接失败,在此不做转载!

文章转载至:https://blog.csdn.net/jlu3389/article/details/2207005

这篇关于以缩略图的形式在Windows资源浏览器中显示自定义格式图片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067913

相关文章

python运用requests模拟浏览器发送请求过程

《python运用requests模拟浏览器发送请求过程》模拟浏览器请求可选用requests处理静态内容,selenium应对动态页面,playwright支持高级自动化,设置代理和超时参数,根据需... 目录使用requests库模拟浏览器请求使用selenium自动化浏览器操作使用playwright

Python获取浏览器Cookies的四种方式小结

《Python获取浏览器Cookies的四种方式小结》在进行Web应用程序测试和开发时,获取浏览器Cookies是一项重要任务,本文我们介绍四种用Python获取浏览器Cookies的方式,具有一定的... 目录什么是 Cookie?1.使用Selenium库获取浏览器Cookies2.使用浏览器开发者工具

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

Mysql常见的SQL语句格式及实用技巧

《Mysql常见的SQL语句格式及实用技巧》本文系统梳理MySQL常见SQL语句格式,涵盖数据库与表的创建、删除、修改、查询操作,以及记录增删改查和多表关联等高级查询,同时提供索引优化、事务处理、临时... 目录一、常用语法汇总二、示例1.数据库操作2.表操作3.记录操作 4.高级查询三、实用技巧一、常用语

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码