Shell_GetImageLists使GetOpenFileName/SHBrowseForFolder导致程序崩溃(Crash)

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

最近在用C/C++开发一个小项目,文章好久没更新,跟大家打个招呼。今天要介绍的是Win32桌面程序开发的问题,当然我的博客关于Windows程序开发介绍得还是比较少的,主要因为我做Windows开发的时候由于博客不稳定,一直没有更新这类文章,当博客稳定下来后又主打脚本或者Web编程,所以相关内容比较少,以后慢慢增加丰富吧。

今天的问题是一个我遇到的程序Bug,我设计的某程序,其中用到了系统的文件图标,查阅Win32 API后得知可以使用Shell_GetImageLists这个API获取,比如说获取16*16大小的系统图标组可以如下编写:

HIMAGELIST himl;
Shell_GetImageLists(NULL, &himl);

其中himl就是包含系统图标组的ImageList,MSDN的介绍中强调了不可以使用ImageList_Destroy销毁这个ImageList:

Important The image lists retrieved through this function are global system image lists; do not call ImageList_Destroy using them.

好吧,我们就不Destroy这个ImageList,那么我要将其关联到ListView控件上,那么代码很简单,如下即可(其中hwndListView为ListView的句柄):

HIMAGELIST himl;
Shell_GetImageLists(NULL, &himl);
ListView_SetImageList(hwndListView, himl, LVSIL_SMALL);

似乎这样很完美了,也许今天的工作可以很好的收尾,但是事实却不是这样,自从加上上述代码后,程序变得极其不稳定,特别是当调用GetOpenFileName或者SHBrowseForFolder等Shell API时,程序会出现异常,要么闪退,要么是没有响应,于是我把注意力放在上面这三段代码上。依次注释排除Shell_GetImageLists和ListView_SetImageList这两个调用。

我特地查阅了ListView_SetImageListAPI说明(准确的说这不是API,只是个SendMessage的包装宏),出现了这么一段话:

The current image list will be destroyed when the list-view control is destroyed unless the LVS_SHAREIMAGELISTS style is set. If you use this message to replace one image list with another, your application must explicitly destroy all image lists other than the current one.

也就是说如果你不为ListView设置LVS_SHAREIMAGELISTS这个样式的话,当你销毁对话框时,指定的ListView也将被销毁,但是ListView在寿终正寝前会随手帮你做件“好事”——那就是Destroy关联其上的ImageList,好吧,这个才是问题的关键,当我为ListView设置了LVS_SHAREIMAGELISTS样式后问题才算解决。看来什么问题都不能想当然,最终代码如下:

HIMAGELIST himl;
Shell_GetImageLists(NULL, &himl);
SetWindowLongPtr(hwndListView, GWL_STYLE,
    LVS_SHAREIMAGELISTS | GetWindowLongPtr(hwndListView, GWL_STYLE));
ListView_SetImageList(hwndListView, himl, LVSIL_SMALL);
若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!
请稍后...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*