zoukankan      html  css  js  c++  java
  • C++获取系统图标方法

    原作者:James Brown
    Original Author: James Brown
    原文链接:http://www.catch22.net/tuts/sysimg.asp
    Original Link: http://www.catch22.net/tuts/sysimg.asp
    点这里下载示例程序及其源码
    注意:本文的中文翻译工作已得到了原文作者 James Brown 的邮件授权,如果您需要转载,请联系 James 本人。   
     系统图像列表(有时亦被称作 Shell 图标缓存)是一个由 Windows Shell 维护的图标资源,资源管理器和其它应用程序使用这个列表来显示系统对象、程序和文件类型的图标。其实就是一个简单的 HIMAGELIST(可以用图像列表 API 存取的标准图像列表),一些应用程序可能会发现显示系统提供的图标更好一些,而不是自己内部存储这些图标的副本。所以,本教程的目的就是解说如何存取系统的图像列表,并在你的应用程序里使用它。
    简单的方法
    如果你先前从未花时间浏览过 MSDN 的话,你可能就会调用 SHGetFileInfo API(由 shell32.dll 导出,Win9x/WinNT4/2000/XP 都可使用)。这个函数看起来是这样的:
    DWORD_PTR SHGetFileInfo(
        LPCTSTR     pszPath,              
        DWORD       dwFileAttributes,
        SHFILEINFO *psfi,
        UINT        cbFileInfo,
        UINT        uFlags
    );
    复制代码
    此函数可被用来获得指定文件的信息,uFlags 参数则指定了要获取的具体哪些信息。对于这个参数来说,有两个非常有趣的取值: SHGFI_ICON 和 SHGFI_SYSICONINDEX 。当指定了这两个值之后,SHGetFileInfo 会返回系统图像列表的句柄,并将相应的图标类型索引保存到 SHFILEINFO 结构中。
    下面的调用示范了可能的使用方法:
    SHFILEINFO shfi;
    HIMAGELIST hSysImgList;
    ...
    hSysImgList = (HIMAGELIST)SHGetFileInfo(
           "C:", 
           0, 
           &shfi, 
           sizeof(SHFILEINFO), 
           SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ICON);
    复制代码
    平台差异
    在 Windows 9x 和 Windows NT 系列的操作系统之间,存在一个很微小但又十分重要的区别。在 Windows 9x 下,SHGetFileInfo 返回系统图像列表的句柄,这个句柄是被所有进程共享的。这个图像列表与资源管理器所使用的以及 Shell 用来显示系统图标的图像列表是同一个图像列表,这就意味着如果一个进程对这个图像列表进行了任何的误操作,那么所有的进程(包括资源管理器)都会受到影响。
    在 Windows NT (以及 2000/XP )之下,就会略有不同。由于系统架构的不同,亦为保持一个稳定的操作环境,SHGetFileInfo 会为每个请求系统图像列表的进程返回一份单独的拷贝。详而述之,SHGetFileInfo 并不会像 Windows 9x 那样返回一个完整的系统图像列表——只有在 SHGetFileInfo 调用中所请求的图标会出现在返回的图像列表中。对于 99% 的情况来说并没有什么关系,但是由于我们要制作一个浏览整个图像列表的应用程序,这就向我们提出了一个问题。
    在所有的 Windows 版本中定位系统图像列表
    闲话休叙,在 shell32.dll 中有一个名为 Shell_GetImageLists 的未公开 API ,——你可能猜到了,它会返回系统图像列表的句柄(注意函数名的复数形式,有大图标和小图标的版本)。这个 shell32.dll 中未公开的 API 适用于所有的 Windows 版本。
    BOOL WINAPI Shell_GetImageLists(HIMAGELIST *lphimlLarge, HIMAGELIST *lphimlSmall);
    我们需要的另一个 API 是 FileIconInit, 它只适用于 Windows NT/2000/XP 。这不是问题,因为我们只需要在 Windows NT 下调用它。
    BOOL WINAPI FileIconInit(BOOL bFullInit);
    这些 API 并未用函数名导出,而只有序号:
    // shell32 未公开的函数
    Shell_GetImageLists @71
    FileIconInit        @660
    复制代码
    获得了这一信息后,我们现在可以编写一个函数来返回系统图像列表的句柄了。第一步是定义两个 typedef ,以使我们的工作更容易些。
    typedef BOOL (WINAPI * SH_GIL_PROC)(HIMAGELIST *phLarge, HIMAGELIST *phSmall);
    typedef BOOL (WINAPI * FII_PROC)   (BOOL fFullInit);
    复制代码
    SH_GIL_PROC 是 Shell_GetIconLists_Procecedure 简写,同理 FII_PROC 是 FileIconInit_Procedure 的简写。现在我们可以定位这些 shell32.dll 未公开的的函数了,以便调用。
    HMODULE      hShell32;
    SH_GIL_PROC  Shell_GetImageLists;
    FII_PROC     FileIconInit;    


    // 装载 shell32.dll ,如果它尚未装载的话
    hShell32 = LoadLibrary("shell32.dll");


    if(hShell32 == 0)
        return FALSE;


    //
    // 从 shell32.dll 中获取未公开的 API
    //
    Shell_GetImageLists  = (SH_GIL_PROC) GetProcAddress(hShell32, (LPCSTR)71);
    FileIconInit         = (FII_PROC)    GetProcAddress(hShell32, (LPCSTR)660);
    复制代码
    请注意我们是如何把序号参数传给 GetProcAddress 的。OK ,现在我们已经获得了所需的函数指针,可以进行处理了。
    // 初始化本进程的图像列表——在 Win95/98 下函数是不可用的
    if(FileIconInit != 0)
        FileIconInit(TRUE);


    // 获得大图标和小图标的系统图像列表句柄
    Shell_GetImageLists(phLarge, phSmall);


    // 不要卸载 shell32.dll !
    复制代码
    上面代码段最后的注释指出“不要卸载 shell32.dll ”,这是非常重要的。因为只要 shell32.dll 被卸载,系统图像列表就会被销毁,这样一来我们是前的所有工作都会付之东流。
    永远不要修改或删除系统图像列表!
    在我们往下进行之前,你应该了解另外一条重要的信息。你永远不要去尝试在系统图像列表中添加、删除图标,也不要删除系统图像列表。这一点在 SHGetFileInfo 的文档中已经解释得很清楚了,而且这也是个很好的意见。但是,仍然有一个很简单的方法会将系统图像列表误删。
    现在来说这个问题。在默认情况下,当一个列表视图(ListView)控件被销毁后,它会自动调用 ImageList_Destroy API 来删除与之关联的图像列表。也就是说,在默认的情况下你甚至要求你的程序删除系统图像列表!——是的,当时就是这样。所幸,列表视图控件有一个 LVS_SHAREIMAGELISTS 样式可以防止它删除它的图像列表。(在这种情况下,请确认你设置了这个样式!)
    十分诡异,树型视图(TreeView)控件却不会引起这一问题—— MSDN 指出树型视图不会销毁与之关联的图像列表,所以只有列表视图控件需要特别注意。
    显然,如果你的程序运行在 Windows NT/2000/XP 下,那么误删系统图像列表并不会有很严重的后果,因为你只是删除了自己进程中图像列表的拷贝。但是,在 Windows 95/98/ME 下,删除这个图像列表会产生灾难性的后果。不信就试试!
    结论
    获取完整的系统图像列表本是一件非常棘手的事,尤其是如果我们不得不从缓存图标的文件中提取图标的话。所幸,这一对未公开的 API 函数可以帮我们做这些事情。当然,我不能把发现这些的功劳记在自己身上——我是在 James Holderness 优秀的网站上发现的,那里关于系统图像列表的信息比我这里提到的更多,另外还有更多的未公开的好东西,现在就过去看看吧!
    祝你们用得开心!
    如果有任何的评论和建议,请给我发邮件:james@catch22.net
    www.likebeta.com
  • 相关阅读:
    读取Java文件到byte数组的三种方式
    https://blog.csdn.net/eguid_1/article/category/6270094
    JavaCV 学习(一):JavaCV 初体验
    WebService服务发布与使用(JDK自带WebService)
    SourceTree 免登录跳过初始设置
    Owin password
    IIS并发
    压力测试
    nginx
    消息队列MSMQ
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318845.html
Copyright © 2011-2022 走看看