如何优雅的在资源管理器显示软件目录

未修改前为默认的文件夹图标,只能依靠名字检索


根据目录内主程序图标修改后,一目了然 :shushing_face:


留问:除了手动修改,有没有更优雅的方式呢

倒是有修改文件夹图标的工具,但是调用的是它自带的一些图标库,完全不想用 :sweat_smile:

对我来说,仅用来修改文件夹的颜色,使其容易区分


1 个赞

我用ahk写过给图库各个文件夹生成图标的,改一改就能用来给软件文件夹生成图标了。
自动提取文件夹内部exe图标,不过要是有多个exe怎么办?

1 个赞

:ok_hand:t2:,看起来不错,等会看看。
至于文件夹内检索出有多个exe,弹窗手动选择

我待会贴一下代码,你改一改试试,我觉得不难,会ahk基础的话

推荐2个软件:

  1. 使用 文件夹 图标 替换 软件. 我测试过很多类似软件, 最终选择的 CustomFolder3

这个软件可以自定义文件夹图标, 并给这些文件夹贴上徽章. 所以比起同类软件来说, 自定义程度和图标的丰富程度会高很多. 徽章的位置大小也是可以自由调节的.

而且我已经做了官方中文版, 官网直接下载即可.

https://www.gdzsoft.com/

  1. 我自己写过一个. 利用的是win7大文件夹预览能力.

小众有介绍

2 个赞

题外话,平时启动开始菜单搜索/各种启动器启动已经很方便了。另外开始菜单中的快捷方式够用了,快捷方式右键可以随时打开原文件位置

目前在用Claunch,有时候手动进入program files目录添加软件,看到文件夹都是一样的图标不舒服 :joy:

强迫症懂的,不过这种东西可能重装系统,或者是引用的图片位置更改了,就全空了…就容易没有耐心去搞了。

不会的,原理是在这个文件夹内存入一个desktop.ini文件,如图:

只要目录内有此ini文件,exe软件存在就不会导致图标消失,换了系统一样显示。

关于 Windows 的文件夹图标和名称都是 desktop.ini 决定的这个我是知道的,不过这个 A: 盘是什么我就不清楚了。是上述的软件的效果吗?

1 个赞

A盘是我软件安装目录

1 个赞

原来如此,这种指向确实没有什么问题

印象中是 Windows 10 还是 11 某个版本开始可以把盘修改为 A 盘

我改了一个用来给软件文件夹做图标的版本,不过没有添加多个exe选择的功能,而且还有bug。
有空我可能改一改?(不过我八成不会动弹了,因为已经够我用了,多个exe选择还挺烦)

你研究研究吧,因为有现成的库,代码很简单,十来行一眼就看明白了,现在逻辑上有一点问题,如果下一个文件夹的第一层没有exe,使用的是上一个文件夹的图标

效果

使用前的软件文件夹,眼花缭乱

使用后的软件文件夹(貌似有些个看上去是错的,还得改代码,代码有问题)

代码ahk v1.几

#SingleInstance

FileselectFolder, path, , , 请选择根目录
FilesetAttrib +S,%path%\*, 2 ,1

loop Files, %path%\* , D R ;递归子文件夹
{
	loop, Files, %A_LoopFileLongPath%\* , F
	{
		if (A_LoopFileExt = "exe")
		{
			exe_path := A_LoopFileLongPath
			break ,1
		}
	}

	ini=%A_LoopFileLongPath%\desktop.ini
	icofullpath=%A_LoopFileLongPath%\folder.ico
	Png2Icon(exe_path, icofullpath)


	IniWrite folder.ico, %ini%, .ShellClassInfo, IconFile
	IniWrite 0          , %ini%, .ShellClassInfo, IconIndex
	IniWrite 0          , %ini%, .ShellClassInfo, ConfirmFileOp


}
MsgBox everything is Ok
return



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
               ;以下是png转ico库
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Png2Icon(sourcePng, destIco) {
   hBitmap := LoadPicture(sourcePng, "GDI+")
   hIcon := HIconFromHBitmap(hBitmap)
   HiconToFile(hIcon, destIco)
   DllCall("DestroyIcon", "Ptr", hIcon), DllCall("DeleteObject", hBitmap)
}

HIconFromHBitmap(hBitmap) {
   VarSetCapacity(BITMAP, size := 4*4 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "Int", size, "Ptr", &BITMAP)
   width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
   hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
   hCBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", width, "Int", height, "Ptr")
   VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
   NumPut(1, ICONINFO)
   NumPut(hCBM, ICONINFO, 4*2 + A_PtrSize)
   NumPut(hBitmap, ICONINFO, 4*2 + A_PtrSize*2)
   hIcon := DllCall("CreateIconIndirect", "Ptr", &ICONINFO, "Ptr")
   DllCall("DeleteObject", "Ptr", hCBM), DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
   Return hIcon
}

HiconToFile(hIcon, destFile) {
   static szICONHEADER := 6, szICONDIRENTRY := 16, szBITMAP := 16 + A_PtrSize*2, szBITMAPINFOHEADER := 40
        , IMAGE_BITMAP := 0, flags := (LR_COPYDELETEORG := 0x8) | (LR_CREATEDIBSECTION := 0x2000)
        , szDIBSECTION := szBITMAP + szBITMAPINFOHEADER + 8 + A_PtrSize*3
        , copyImageParams := ["UInt", IMAGE_BITMAP, "Int", 0, "Int", 0, "UInt", flags, "Ptr"]

   VarSetCapacity(ICONINFO, 8 + A_PtrSize*3, 0)
   DllCall("GetIconInfo", "Ptr", hIcon, "Ptr", &ICONINFO)
   if !hbmMask  := DllCall("CopyImage", "Ptr", NumGet(ICONINFO, 8 + A_PtrSize), copyImageParams*) {
      MsgBox, % "CopyImage failed. LastError: " . A_LastError
      Return
   }
   hbmColor := DllCall("CopyImage", "Ptr", NumGet(ICONINFO, 8 + A_PtrSize*2), copyImageParams*)
   VarSetCapacity(mskDIBSECTION, szDIBSECTION, 0)
   VarSetCapacity(clrDIBSECTION, szDIBSECTION, 0)
   DllCall("GetObject", "Ptr", hbmMask , "Int", szDIBSECTION, "Ptr", &mskDIBSECTION)
   DllCall("GetObject", "Ptr", hbmColor, "Int", szDIBSECTION, "Ptr", &clrDIBSECTION)

   clrWidth        := NumGet(clrDIBSECTION,  4, "UInt")
   clrHeight       := NumGet(clrDIBSECTION,  8, "UInt")
   clrBmWidthBytes := NumGet(clrDIBSECTION, 12, "UInt")
   clrBmPlanes     := NumGet(clrDIBSECTION, 16, "UShort")
   clrBmBitsPixel  := NumGet(clrDIBSECTION, 18, "UShort")
   clrBits         := NumGet(clrDIBSECTION, 16 + A_PtrSize)
   colorCount := clrBmBitsPixel >= 8 ? 0 : 1 << (clrBmBitsPixel * clrBmPlanes)
   clrDataSize := clrBmWidthBytes * clrHeight

   mskHeight       := NumGet(mskDIBSECTION,  8, "UInt")
   mskBmWidthBytes := NumGet(mskDIBSECTION, 12, "UInt")
   mskBits         := NumGet(mskDIBSECTION, 16 + A_PtrSize)
   mskDataSize := mskBmWidthBytes * mskHeight

   iconDataSize := clrDataSize + mskDataSize
   dwBytesInRes := szBITMAPINFOHEADER + iconDataSize
   dwImageOffset := szICONHEADER + szICONDIRENTRY

   VarSetCapacity(ICONHEADER, szICONHEADER, 0)
   NumPut(1, ICONHEADER, 2, "UShort")
   NumPut(1, ICONHEADER, 4, "UShort")

   VarSetCapacity(ICONDIRENTRY, szICONDIRENTRY, 0)
   NumPut(clrWidth      , ICONDIRENTRY,  0, "UChar")
   NumPut(clrHeight     , ICONDIRENTRY,  1, "UChar")
   NumPut(colorCount    , ICONDIRENTRY,  2, "UChar")
   NumPut(clrBmPlanes   , ICONDIRENTRY,  4, "UShort")
   NumPut(clrBmBitsPixel, ICONDIRENTRY,  6, "UShort")
   NumPut(dwBytesInRes  , ICONDIRENTRY,  8, "UInt")
   NumPut(dwImageOffset , ICONDIRENTRY, 12, "UInt")

   NumPut(clrHeight*2 , clrDIBSECTION, szBITMAP +  8, "UInt")
   NumPut(iconDataSize, clrDIBSECTION, szBITMAP + 20, "UInt")
   
   File := FileOpen(destFile, "w", "cp0")
   File.RawWrite(ICONHEADER, szICONHEADER)
   File.RawWrite(ICONDIRENTRY, szICONDIRENTRY)
   File.RawWrite(&clrDIBSECTION + szBITMAP, szBITMAPINFOHEADER)
   File.RawWrite(clrBits + 0, clrDataSize)
   File.RawWrite(mskBits + 0, mskDataSize)
   File.Close()

   DllCall("DeleteObject", "Ptr", hbmColor)
   DllCall("DeleteObject", "Ptr", hbmMask)
}

所以为什么会有人想把盘符改成A开始……我觉得好不习惯诶(((

请教一下,我自己研究写了一个AHK脚本,按下快捷键时捕获选中文件的路径,再生成desktop.ini,但遇到了一个小问题,就是不起作用。通过右键属性来更改,查看desktop.ini,里面内容与我用AHK生成的一模一样,但是用AHK生成的ini没能改掉图标是什么情况?

通过AHK生成的desktop.ini文件:

[.ShellClassInfo]
IconResource=A:\Program Files\AutoOff\AutoOff_4.21.exe,0

AHK代码:

F3::
    sel := Explorer_GetSelected()
	str1 := sel ",0"
    inipath := Explorer_GetPath() "\desktop.ini"
    IniWrite, %str1%, %inipath%, .ShellClassInfo, IconResource
	FileSetAttrib, +HS-A, %inipath%
    return

;以下内容为获取选中文件路径
Explorer_GetPath(hwnd="")
{
    if !(window := Explorer_GetWindow(hwnd))
        return ErrorLevel := "ERROR"
    if (window="desktop")
        return A_Desktop
    path := window.LocationURL
    path := RegExReplace(path, "ftp://.*@","ftp://")
    path := RegExReplace(path, "%20"," ") ;替换空格,否则显示%20
    StringReplace, path, path, file:///
    StringReplace, path, path, /, \, All
    ; thanks to polyethene
    Loop
        If RegExMatch(path, "i)(?<=%)[da-f]{1,2}", hex)
            StringReplace, path, path, `%%hex%, % Chr("0x" . hex), All
        Else Break
    return path
}
 
Explorer_GetAll(hwnd="")
{
    return Explorer_Get(hwnd)
}
 
Explorer_GetSelected(hwnd="")
{
    return Explorer_Get(hwnd,true)
}
 
Explorer_GetWindow(hwnd="")
{
    ; thanks to jethrow for some pointers here
    WinGet, process, processName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A")
    WinGetClass class, ahk_id %hwnd%
 
    if (process!="explorer.exe")
        return
    if (class ~= "(Cabinet|Explore)WClass")
    {
        for window in ComObjCreate("Shell.Application").Windows
            if (window.hwnd==hwnd)
                return window
    }
    else if (class ~= "Progman|WorkerW")
        return "desktop" ; desktop found
}
 
Explorer_Get(hwnd="",selection=false)
{
    if !(window := Explorer_GetWindow(hwnd))
        return ErrorLevel := "ERROR"
    if (window="desktop")
    {
        ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
        if !hwWindow ; #D mode
            ControlGet, hwWindow, HWND,, SysListView321, A
        ControlGet, files, List, % ( selection ? "Selected":"") "Col1",,ahk_id %hwWindow%
        base := SubStr(A_Desktop,0,1)=="" ? SubStr(A_Desktop,1,-1) : A_Desktop
        Loop, Parse, files, `n, `r
        {
            path := base "" A_LoopField
            IfExist %path% ; ignore special icons like Computer (at least for now)
                ret .= path "`n"
        }
    }
    else
    {
        if selection
            collection := window.document.SelectedItems
        else
            collection := window.document.Folder.Items
        for item in collection
            ret .= item.path "`n"
    }
    return Trim(ret,"`n")
}

[quote=“dog, post:14, topic:35094”]
FilesetAttrib +S,%path%\*, 2 ,1
[/quote]

是需要设置attrib的,你查一下这个函数有说明

我看看哈

可以用啊,刷新一下图标就出来了,你这个方法好,不用转ico图标出来了。
刷新图标缓存的代码,可能有用,可能没用你试试

RefreshExplorer() { ; by teadrinker on D437 @ tiny.cc/refreshexplorer
   local Windows := ComObjCreate("Shell.Application").Windows
   Windows.Item(ComObject(0x13, 8)).Refresh()
   for Window in Windows
      if (Window.Name != "Internet Explorer")
         Window.Refresh()
}

实测有效,把这段代码加上就好了,然后每次执行后加一句RefreshExplorer() 就好了。

如果不是历史遗留问题,A 盘本来应该就是系统盘的,除非是某些软件是把路径相关的写死了,不然手动改成 A 盘问题不大。尊重个性化需求(虽然我不改

3 个赞

我当年大概是windows vista 的时候改过,然后windows不能索引 :sweat_smile: