SHGetFileInfo调用N次后罢工,救命!

longgang521125 2012-10-24 10:00:31
如上:代码如下,看了内存会增长很快,真心找不到问题所在,感觉是SHGetFileInfo是它调用很多次后,把内存弄得很高,结果后面图标就不见了!什么情况啊。
while(hfile!= INVALID_HANDLE_VALUE )
{
strTemp = fileDate.cFileName;
if(!SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON)&& strTemp != "." && strTemp != "..")
{
if(SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_PIDL))
goto line;
break;
}
line:
if((fileDate.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strTemp != "." && strTemp != ".."){

//posFile=imageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
posFile=imageList.Add(shFi.hIcon);
root=treeCtrl.InsertItem(strTemp,posFile,posFile,TVI_ROOT,root);
DestroyIcon(shFi.hIcon);
//MessageBox(_T("dgd"));
}
if(!(fileDate.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strTemp != "." && strTemp != ".."){
pos=imageList.Add(shFi.hIcon);
DestroyIcon(shFi.hIcon);
item=treeCtrl.InsertItem(strTemp,pos,pos,TVI_ROOT,item);

}
bool isNextFile = FindNextFile(hfile,&fileDate);//判断该目录下是否还有文件
if(isNextFile == 0)
{
break;
}
}
...全文
242 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2012-10-24
  • 打赏
  • 举报
回复
提出几个问题:
1. 你的文件查找与判断的循环不太恰当。通常都是这么写的:
HANDLE hFindFile;
WIN32_FIND_DATA w32fd;
hFindFile = FindFirstFile(szWildcard, &w32fd);
if (hFindFile != INVALID_HANDLE_VALUE) {
do {
if (w32fd.cFileName == _T(".") || w32fd.cFileName != _T("..")) {
continue;
}
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
//
} else {
//
}
} while (FindNextFile(hFindFile, &w32fd));
FindClose(hFindFile);
}

2. 重复的部分最好独立成函数,或者先赋值给变量。像你这里两次 start + _T("\\") + strTemp 为何不先赋值再调用呢?
3. 这里调用不正确,另外 SHGetFileInfo 返回非零,goto 也完全可以不用:
if (SHGetFileInfo(start + _T("\\") + strTemp, 0, &shFi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_PIDL))
goto line;
break;

SHGFI_PIDL 表示第一个参数是 PIDL,你传的依然是路径,这里绝对不正确。
你只需要在 SHGetFileInfo 前加一个 !,即可省去 goto,一行:
if (!SHGetFileInfo(start + _T("\\") + strTemp, 0, &shFi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_PIDL))
break;

另外,我不知道你里这么调用 SHGetFileInfo 两次有何用意?

通常情况下,都是先用 SHGetFileInfo 去返回一个系统的 ImageList 句柄,然后到具体的项目时,获取它的 iIcon 即系统 ImageList 的索引,也就是二楼所说的用 iIcon。当然,还有最后一个建议:通常对于 Treeview 或 Listview 控件做文件管理器都是处理 TVN_GETDISPINFO 或 LVN_GETDISPINFO 来处理的,这样对于文件数量过多的文件夹能明显提高效率,采用文件查找的方式,效率很低,只能算是笨办法。我在这方面也不是很懂,但是我看过类似的源码,调用 IShellFolder::EnumObjects 来实现的。
shen_wei 2012-10-24
  • 打赏
  • 举报
回复
图标没有了。。单步看看有没有添加图标。。。
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
1.imageList有必要循环Add么?放全局吧。加载一次就可以了。
反正图标一直要显示的。

2.
MSDN:
Do not use this function to destroy a shared icon. A shared icon is valid as long as the module from which it was loaded remains in memor……
[/Quote]
imagelist我是放在全局的,是这个add导致的内存增长的嘛?感觉不是,我测试过,2次add一样的内存一样大,图标一样没了!
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]
为什么要N次呢,用到N次的,就让它只1次
[/Quote]
因为我想动态获得图标
换了下代码还是有内存增加,最后还是没图标了!
while(hfile!= INVALID_HANDLE_VALUE )
{
strTemp = fileDate.cFileName;
if(strTemp != "." && strTemp != "..")
{
if(!SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON)){
if(SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_PIDL))
goto line;
break;
}
line:
if((fileDate.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strTemp != "." && strTemp != ".."){

//posFile=imageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
posFile=imageList.Add(shFi.hIcon);
root=treeCtrl.InsertItem(strTemp,posFile,posFile,TVI_ROOT,root);
if(shFi.hIcon)
DestroyIcon(shFi.hIcon);
}
if(!(fileDate.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strTemp != "." && strTemp != ".."){
pos=imageList.Add(shFi.hIcon);
DestroyIcon(shFi.hIcon);
item=treeCtrl.InsertItem(strTemp,pos,pos,TVI_ROOT,item);

}
}
/*if(!(fileDate.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strTemp != "." && strTemp != ".."){
pos=imageList.Add(shFi.hIcon);
DestroyIcon(shFi.hIcon);
item=treeCtrl.InsertItem(strTemp,pos,pos,TVI_ROOT,item);

}*/
bool isNextFile = FindNextFile(hfile,&fileDate);//判断该目录下是否还有文件
if(isNextFile == 0)
{
break;
}
}
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
觉得你这个遍历逻辑上有些问题?一般的先得到文件路径,先过滤.和..,SHGetFileInfo得到文件图标,Add到CImageList中,然后DestroyIcon()删除,然后再去判断是否是目录还是文件,如果是目录的话,再递归
[/Quote]
好照你方法试试,看看
lgstudyvc 2012-10-24
  • 打赏
  • 举报
回复
为什么要N次呢,用到N次的,就让它只1次
傻X 2012-10-24
  • 打赏
  • 举报
回复
1.imageList有必要循环Add么?放全局吧。加载一次就可以了。
反正图标一直要显示的。

2.
MSDN:
Do not use this function to destroy a shared icon. A shared icon is valid as long as the module from which it was loaded remains in memory. The following functions obtain a shared icon.

不要删除一个共享的图标,
只要这个图标任然在内存中使用,就被定义为一个共享图标

CreateIconFromResourceEx CreateIconIndirect and CopyIcon.
才用DestroyIcon

Eleven 2012-10-24
  • 打赏
  • 举报
回复
觉得你这个遍历逻辑上有些问题?一般的先得到文件路径,先过滤.和..,SHGetFileInfo得到文件图标,Add到CImageList中,然后DestroyIcon()删除,然后再去判断是否是目录还是文件,如果是目录的话,再递归
BombZhang 2012-10-24
  • 打赏
  • 举报
回复

if(strTemp != "." && strTemp != "..")
{
if(!SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON))
{
if(SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_PIDL))
goto line;
else
break;
}
}
else
{
bool isNextFile = FindNextFile(hfile,&fileDate);//判断该目录下是否还有文件
if(isNextFile == 0)
{
break;
}

continue;
}
BombZhang 2012-10-24
  • 打赏
  • 举报
回复
不好意思,上面的有问题,再改改


if(strTemp != "." && strTemp != ".." && !SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON))
{
if(SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_PIDL))
goto line;
break;
}
else
{
bool isNextFile = FindNextFile(hfile,&fileDate);//判断该目录下是否还有文件
if(isNextFile == 0)
{
break;
}

continue;
}
BombZhang 2012-10-24
  • 打赏
  • 举报
回复
下面这行是不是不太合适?
if(!SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON)&& strTemp != "." && strTemp != "..")

这么写应该好点儿,strTemp是.和..的时候就不会再执行SHGetFileInfo了:

if(strTemp != "." && strTemp != ".." && !SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON))
{
if(SHGetFileInfo(start+_T("\\")+strTemp,0,&shFi,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_PIDL))
goto line;
break;
}
else
continue;
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
参考下面文章,试试直接用iIcon,不用hIcon
http://www.cnblogs.com/jianu/archive/2011/05/12/2044885.html
[/Quote]
看了下,和我的写法差不多额!感觉上面我的代码,没有泄露啊,都destroyicon啦,为什么还是增了!头疼
BombZhang 2012-10-24
  • 打赏
  • 举报
回复
参考下面文章,试试直接用iIcon,不用hIcon
http://www.cnblogs.com/jianu/archive/2011/05/12/2044885.html
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
网上的很多方法我都试过,就是不行!希望高手能帮帮,这里谢谢啦!
longgang521125 2012-10-24
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
提出几个问题:
1. 你的文件查找与判断的循环不太恰当。通常都是这么写的:

C/C++ code
HANDLE hFindFile;
WIN32_FIND_DATA w32fd;
hFindFile = FindFirstFile(szWildcard, &w32fd);
if (hFindFile != INVALID_HANDLE_VALUE) {
do {
……
[/Quote]
嗯嗯,说的蛮好的!我改改,其实这个我写的逻辑上有点问题。
给分啦!

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧