根据一个字符串(如“aaa.doc”)获得windows内与之相对应的图标的问题!超级疑难,非高手莫入! (200分)

  • 主题发起人 chemstar
  • 开始时间
实不相瞒,我现在正编一个realplay播放器,所以我们可以共同探讨这个问题。<br>一个文件的图标除了windows找不到其关联程序时用缺省图标外,不会再在什<br>么地方存放图标。我的机器就是装了realplayer和超级解霸的,在<br>注册表中HKEY_CLASSES_ROOT/.rm下就同时有realpler 的键值:<br>application/vnd.rn-realmedia和超级解霸的,一般好像是默认第一个键值,<br>你卸了realplayer,打开方式自然就用超级解霸的,我的程序不是加上第三个键值,而是<br>将HKEY_CLASSES_ROOT/RealPlayer.RM.6/shell/open/command/下的键值改为我的播放器的路径,<br>图标也改了,如果让RealPlayer它又运行的话,它又会将它改回来的。所以不会在什么地方存<br>图标了。<br>&nbsp; &nbsp;共同探讨,200分大家平分就行了。
 
to 我爱PASCAL:<br>&nbsp; &nbsp;哈哈!这个问题我终于搞明白了,你的观点尽管也对,不过并不一个好的方法。<br>其实,windows本身也有一个imagelist,当启动的时候就从相关联的程序中将相应的<br>图标读到了它的imagelist中(就是你用的那个方法),以后直接从imagelist中加载<br>就可以了。<br>  我们要做的只要用个winapi函数取得该扩展名的文件的图标在imagelist中的索引,<br>然后直接调用就可以了。根本不用自己读注册表。这样岂不是快的多?<br>  等我整理好了代码后帖上来。
 
to book523, <br>&nbsp; &nbsp;我按你给出的代码运行了一下,在win98下面没什么问题,但在win2000下怎么什么也显示不出来呀?<br>(注意:SmallImages.ShareImages:=True后面掉了一个分号)。
 
ShGetFileInfo('*.*',0,SHFileInfo...)<br>改成<br>ShGetFileInfo('',0,SHFileInfo...)
 
//----------------[创建 ListView 图标]------------------------------------<br>FUNCTION FkListViewImageInit(vListView:TListView):BOOL;<br>VAR &nbsp;SysImageList: UINT; &nbsp;SFI: TSHFileInfo;<br>BEGIN<br>&nbsp; vListView.LargeImages:=TImageList.Create(vListView);<br>&nbsp; vListView.SmallImages:=TImageList.Create(vListView);<br>&nbsp; //vListView.PopupMenu:=TPopupMenu.Create(vListView);<br>&nbsp; WITH vListView DO<br>&nbsp; &nbsp; BEGIN<br>&nbsp; &nbsp; //[BIG]<br>&nbsp; &nbsp; SysImageList := SHGetFileInfo('',0,SFI,SizeOf(SFI),SHGFI_SYSICONINDEX OR SHGFI_LARGEICON);<br>&nbsp; &nbsp; IF SysImageList &lt;&gt; 0 THEN<br>&nbsp; &nbsp; &nbsp; BEGIN<br>&nbsp; &nbsp; &nbsp; LargeImages.Handle := SysImageList;<br>&nbsp; &nbsp; &nbsp; Largeimages.ShareImages := TRUE;<br>&nbsp; &nbsp; &nbsp; END;<br>&nbsp; &nbsp; //[SMALL]<br>&nbsp; &nbsp; SysImageList := SHGetFileInfo('',0,SFI,SizeOf(SFI),SHGFI_SYSICONINDEX OR SHGFI_SMALLICON);<br>&nbsp; &nbsp; IF SysImageList &lt;&gt; 0 THEN<br>&nbsp; &nbsp; &nbsp; BEGIN<br>&nbsp; &nbsp; &nbsp; SmallImages.Handle := SysImageList;<br>&nbsp; &nbsp; &nbsp; SmallImages.ShareImages := TRUE;<br>&nbsp; &nbsp; &nbsp; END;<br>&nbsp; &nbsp; //[END OF WITH]<br>&nbsp; &nbsp; END;<br>END;<br>//-----------------------------------------------------------------------------------<br>//用他对ListView图标出使化.保证不出问题.<br>用的时侯用SHGetFileInfo获得索引号就可以了.
 
to ligia, zw84611:<br>&nbsp; 太对了!果然如此,非常感谢!!!<br> 但还有一个小问题:<br> 1、怎样才能得到像windows文件夹那样的图标呢?也是从系统图标列表内!<br> 2、将listview的samllimages和largeimages指向系统图标列表后,怎样再将其断开,重新<br>  赋给另外一个imagelist?<br>回答后立即给分!!<br> 
 
VAR icoTemp:TIcon; imgList:TImageList; tshIcon: TSHFileInfo;<br>BEGIN<br>&nbsp; &nbsp; ...........<br>&nbsp; &nbsp; icoTemp:=TIcon.Create;<br>&nbsp; &nbsp; imgList:=TImageList.Create(vForm);//<br>&nbsp; &nbsp; imgList.Handle:=SHGetFileInfo(PCHAR(vFile),0, tshIcon,SizeOf(tshIcon),SHGFI_SYSICONINDEX+SHGFI_SMALLICON);<br>&nbsp; &nbsp; imgList.ShareImages:=TRUE;<br>&nbsp; &nbsp; imgList.GetIcon(tshIcon.iIcon,icoTemp);<br>&nbsp; &nbsp;..................<br>END;<br><br>用GetIcon 输出到 TIcon<br>然后将 TIcon 添加到新的 TImageList.<br><br>你的第一个问题,不明白?
 
to ligia, <br>&nbsp; 第一个问题的意思是,windows的文件夹的图标序号是怎样获得的?我也想从windows中动态获得。<br>再比如windwos的一些虚拟文件夹如“我的电脑”等的图标是怎样得到的?
 
那如果能得到 左下角有个箭头的图标呀,就是快捷方式的图标
 
to ligia,<br>&nbsp;第二个问题还是不太明白, 请详细些,最好来段完整的代码。谢谢!
 
1.可以直接使用SHGetFileInfo获得文件夹,将文件处换成路经即可.<br>SHGetFileInfo(PCHAR(vPath),0, tshIcon,SizeOf(tshIcon),SHGFI_SYSICONINDEX+SHGFI_SMALLICON);<br>2.用文件处换成 PIDL 即可获得特殊的文件夹图标(包括我的电脑).<br>SHGetFileInfo(PCHAR(PIDL),0, tshIcon,SizeOf(tshIcon),SHGFI_SYSICONINDEX+SHGFI_SMALLICON);<br>具体的PIDL值,明天找一下再说.<br>SHGetDesktopFolder(vPIDL);可以获得桌面的PIDL.<br><br>关于第二个问题,明天写个给你.<br>
 
to ligia<br>如何能得到 左下角有个箭头的图标呀,就是快捷方式的图标,我也另送给你,就是给一个<br>后辍,比如(doc),得到有箭头的图标
 
to zjfeng, <br>  那个箭头是叠加上去的,根本不是一个整个的图标。找找以前的帖子,有这个答案的。
 
在应用程序的编写中,组合框(ComboBox)、列表框(ListBox)、等常见的部件,通常不仅要用于显示文字,而且还要显示其与文字相关的图标。在一般的Windows应用程序中,这些图标的显示都要随列出的显示文本的变化而变化,例如在组合框中列出当前目录下的所有文件时,在组合框左边就显示与文件名相关联的图标,这就是所谓的动态图标。在Delphi中使用动态图标的步骤如下:<br>  一、图标的获取<br>  要使用动态图标,首先要解决的是如何获得显示文本和与其相关联的图标句柄。该图标通过文件关联由系统注册表决定,并且在Windows编程中同一文件(或子目录,或文件夹)在桌面上也可能有两种显示结果,这就是DOS文件名与显示名(Display Name)。如果我们的应用程序不需要有像Windows资源浏览器那样的效果,则可以使用FindFirst()和FindNext()二个函数以及FindClose()过程来获得DOS文件名,否则我们就应当使用WindowsAPI来获得显示名。在获得文件名的同时可通过使用ShellAPI.pas中的SHGetFileInfo()函数来获得其图标句柄HICON,说明如下:<br>  function SHGetFileInfo(pszPath: PAnsiChar; dwFileAttributes: DWORD;var psfi: TSHFileInfo; cbFileInfo,uFlags: UINT): DWORDl;<br>  pszPath 参数:指定的文件名。当uFlags的取值中不包含 SHGFI_PIDL时,可直接指定;否则pszPath要通过计算获得,不能直接指定;<br>   dwFileAttributes参数:文件属性,仅当uFlags的取值中包含SHGFI_USEFILEATTRIBUTES时有效,一般不用此参数;<br>  psfi 参数:返回获得的文件信息,是一个记录类型,有以下字段:<br>  hIcon: HICON; //文件的图标句柄<br>  iIcon: Integer; //图标的系统索引号<br>  dwAttributes: DWORD; //文件的属性值<br>  szDisplayName: array [0..MAX_PATH-1] of AnsiChar; //文件的显示名<br>  szTypeName: array [0..79] of AnsiChar; //文件的类型名<br>  cbFileInfo 参数:psfi的比特值;<br>  uFlags 参数:指明需要返回的文件信息标识符,常用的有以下常数:<br>  SHGFI_ICON; //获得图标<br>  SHGFI_DISPLAYNAME; //获得显示名<br>  SHGFI_TYPENAME; //获得类型名<br>  SHGFI_ATTRIBUTES;//获得属性<br>  SHGFI_LARGEICON; //获得大图标<br>  SHGFI_SMALLICON; //获得小图标<br>  SHGFI_PIDL;// pszPath是一个标识符<br>  函数SHGetFileInfo()的返回值也随uFlags的取值变化而有所不同。通过调用SHGetFileInfo()可以由psfi参数得到文件的图标句柄,但要注意在uFlags参数中不使用SHGFI_PIDL时,SHGetFileInfo()不能获得"我的电脑"等虚似文件夹的信息。<br>  二、图标的加载<br>  使用Delphi提供的TImageList组件,通过调用CommCtrl .pas中的函数ImageList_AddIcon()来加载得到的图标,并要保证其索引号与显示文本相对应。说明如下:<br>  function ImageList_AddIcon(ImageList: HIMAGELIST; //加载图标的ImageList句柄<br>  Icon: Hicon //加载的图标句柄 ): Integer; //返回图标在ImageList中的索引号<br>  在需要指明图标索引号时可使用ImageList_AddIcon()的返回值。<br>  三、图标和文本的绘图式输出<br>  对于组合框、列表框等不能直接显示图标的组件,由于要求显示图标的同时又要同时显示文本,可通过设置其相应的Style属性达到目的,示例如下:<br>  组合框:ComboBox1.Style:=csOwnerDrawVariable根据实际使用经验最好不要在ObjectInspector窗体中直接设置,而应将代码添加在程序的适当位置,否则可能出现绘图区域高度不规则变化<br>  列表框:ListBox1.Style:=lbOwnerDrawVariable <br>  状态栏:StatusBar1.Panels.Style:= psOwnerDraw 不能使用简单状态栏,i是状态栏中要绘制图标的某一窗格索引号,图形输出可使用TImageList的ImageList1.Draw()方法,而文本输出则可使用TCanvas的TextOut()方法,它由组件的Canvas属性继承得到,显然没有Canvas属性的组件不能使用此方法显示图标。<br>  对于可直接显示图标的组件,直接指定其Images、StateImages等需要的图标属性为相应的TimageList组件名,并通过指定图标的索引号则可显示图标。需要注意的是:在使用大图标时,必须先调用TImageList的CreateSize()方法指定可加载图标的尺寸,并且在每次调用TImageList的Clear方法后都要重新调用CreateSize()。<br>  使用TImageList的ImageList1.Clear方法清除已加载的图标,常在需要刷新时使用。<br>
 
to ligia:<br>  真是高手!果然如此!谢谢!等着第二个问题的代码!<br>  另外既然你对图标的处理如此在行,索性好人做到底,将下面这个问题也一并回答了吧!(另送分给你)<br>  问:怎样将取得的图标(我是用ExtractAssociatedIcon从盘上的一个文件提取的)存入一个数据库,如aaa.mdb?<br>  而后又怎样从库中取出来然后将它加到一个imagelist里面?<br>  其实不用数据库也行,只要能把很多的图标存入一个文件就行。<br>
 
//我根据一个字符串如‘aaa.doc’(这个文件并不实际存在),通过调用函数<br>//来取得doc文件在系统内的图标索引,进而显示在一个listview内<br>大家注意:是aaa.doc 这个文件并不实际存在<br>如果文件存在用这个shgetfileinfo函数可以得到,如果不存在我是怎么也没有得到。<br>我的操作系统是NT,我没有安装98,不知道在98下可不可以。<br>to chemstar<br>&nbsp; &nbsp;你现在知道了吗,如果知道了请告之。<br>&nbsp; &nbsp;我爱PASCAL 的方法可行,但是我担心执行速度会很慢。
 
to &nbsp;yanghai0437:<br>  函数没错,但声明不对。对照上面看看。
 
顶部