1

Тема: AHK: как узнать путь к иконке используемой файлом?

У файлов есть иконки: иногда свои, а иногда им прописываются системные, соответствующие их расширению.

Как получить ссылку на 16x16 иконку используемую файлом?
[мне это необходимо для добавления иконки menuitem'у]

2

Re: AHK: как узнать путь к иконке используемой файлом?

Что Вы называете файлом? Программу (то бишь .exe), скомпилированный AutoHotkey скрипт, или может ярлык? Или иконка из сторонних файлов, на которую ссылается скомпилированный AutoHotkey скрипт?

Нужен конкретный пример.

3 (изменено: Alectric, 2014-05-22 22:18:00)

Re: AHK: как узнать путь к иконке используемой файлом?

Для этого нужно считать с реестра ассоциацию файла и определить "иконку по умолчанию" для этого файла, также из реестра.

FileExt=txt
RegRead,exts,HKCR,.%FileExt%,,
RegRead,ico,HKCR,%exts%\Defaulticon,,
msgbox,% ico

Для исполняемых файлов (exe например) этот скрипт не подойдет.
Некоторые файлы может отобразить как: "%SystemRoot%\system32\...", SystemRoot - это "C:\Windows".

Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

4

Re: AHK: как узнать путь к иконке используемой файлом?

Если нужно именно для меню, то для любых файлов (и даже папок) примерно так:

FilePath1 := A_ScriptDir  ; указать пути к нужным файлам
FilePath2 := A_AhkPath

Loop 2
{
   Menu, MyMenu, Add, MyFileIcon%A_Index%, MenuHandler
   Menu, MyMenu, Icon, MyFileIcon%A_Index%, % ImageFile := CreateImageFromFileIcon(FilePath%A_Index%),, 0
   FileDelete, % ImageFile
}
Menu, MyMenu, Show
MenuHandler:
Return

CreateImageFromFileIcon(sFile)
{
   DestFile := A_Temp "\AHK_" A_TickCount "Temp.png"   ; допустимые расширения: BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
   
   hIcon := GetFileIcon(sFile), pToken := GdipStartup()
   DllCall("gdiplus\GdipCreateBitmapFromHICON", "ptr", hIcon, "ptr*", pBitmap)
   GdipSaveBitmapToFile(pBitmap, DestFile)
   
   DllCall("DestroyIcon", Ptr, hIcon)
   DllCall("gdiplus\GdipDisposeImage", "ptr", pBitmap)
   GdipShutdown(pToken)
   Return DestFile
}

GetFileIcon(sFile)
{
   sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
   VarSetCapacity(sfi, sfi_size)
   
   DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), Str, sFile
      , UInt, 0, Ptr, &sfi, UInt, sfi_size, UInt, 0x101)  ; SHGFI_ICON | SHGFI_SMALLICON = 0x101
   return NumGet(sfi, 0)   ; hIcon
}

GdipStartup()
{
   if !DllCall("GetModuleHandle", "str", "gdiplus", "ptr")
      DllCall("LoadLibrary", "str", "gdiplus")
   VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
   DllCall("gdiplus\GdiplusStartup", "uptr*", pToken, "ptr", &si, "ptr", 0)
   return pToken
}

GdipSaveBitmapToFile(pBitmap, sOutput)
{
   SplitPath, sOutput,,, Extension
   if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
      return -1
   Extension := "." Extension

   DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
   VarSetCapacity(ci, nSize)
   DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, "ptr", &ci)
   if !(nCount && nSize)
      return -2
   
   Loop, %nCount%
   {
      sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
      if !InStr(sString, "*" Extension)
         continue
      
      pCodec := &ci+idx
      break
   }
   if !pCodec
      return -3
   
   E := DllCall("gdiplus\GdipSaveImageToFile", "ptr", pBitmap, "wstr", sOutput, "ptr", pCodec, "ptr", p ? p : 0)
   return E ? -5 : 0
}

GdipShutdown(pToken)
{
   DllCall("gdiplus\GdiplusShutdown", "uptr", pToken)
   if hModule := DllCall("GetModuleHandle", "str", "gdiplus", "ptr")
      DllCall("FreeLibrary", "ptr", hModule)
   return 0
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: как узнать путь к иконке используемой файлом?

ypppu пишет:

Что Вы называете файлом? Программу (то бишь .exe), скомпилированный AutoHotkey скрипт, или может ярлык? Или иконка из сторонних файлов, на которую ссылается скомпилированный AutoHotkey скрипт?

Нужен конкретный пример.

Всё из перечисленного вами является файлами. Скомпилированный AutoHotkey скрипт является уже обычным .exe со своей иконкой (стандартной белой [Н] на зелёном фоне или же какой-то не стандартной иконкой из внешнего файла).

Alectric пишет:

Для этого нужно считать с реестра ассоциацию файла и определить "иконку по умолчанию" для этого файла, также из реестра.

FileExt=txt
RegRead,exts,HKCR,.%FileExt%,,
RegRead,ico,HKCR,%exts%\Defaulticon,,
msgbox,% ico

Для исполняемых файлов (exe например) этот скрипт не подойдет.
Некоторые файлы может отобразить как: "%SystemRoot%\system32\...", SystemRoot - это "C:\Windows".

Спасибо, годный подход с коротким кодом. Я сейчас на этапе пересмотра возможного функционала своего скрипта и пока не принял решение стоит ли упираться и добавлять поддержку иконок .exe файлов или нет (код предложенный teadrinker'ом [ещё не пробовал, но верю, что он рабочий] довольно большой и имеет зависимость от ещё более толстого скрипта [gdip.ahk]).

teadrinker
спасибо за код. Почитал его чтобы понять как он работает и понял, что для меня это overkill: он будет сохранять иконки каждого файла в отдельные файлы, а для моих целей это уже слишком.
Но код годный, может когда и пригодится, не хороните его.

Наверно, остановлюсь на коде от Alectric а поддержку папок и .exe прикручу статичными иконками из shell32.dll (как я это уже сделал для *.URL файлов).
Всем спасибо.

6 (изменено: Alectric, 2014-05-24 07:52:07)

Re: AHK: как узнать путь к иконке используемой файлом?

Drugoy пишет:

поддержку папок и .exe прикручу статичными иконками из shell32.dll (как я это уже сделал для *.URL файлов).

Для *.url файлов можно также, через мой код. Точнее для любых файлов с расширением (конечно, если он ассоциирован с программой) кроме *.exe.

Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

7

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker
А как сохранить в файл одну из иконок в dll. Например Shell32.dll, 131

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

8

Re: AHK: как узнать путь к иконке используемой файлом?

Как говорится, спасибо за интересный вопрос. Пришлось покурить эту тему, и родился такой код:

SetBatchLines, -1
source := "Shell32.dll"
idx := 305  ; порядковый номер от 1
dest := A_Desktop "\test.ico"

GetIconFromResource(dest, source, idx)
Return

GetIconFromResource(dest, source, idx)
{
   SplitPath, source,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      ExitApp
   }
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      ExitApp
   }

   hRes := FindGroup(hModule, idx)
   pGroupIcons := GetResData(hModule, hRes)

   DataArray := CreateDataArray(hModule, pGroupIcons, CountIcons, size)
   pData := CreateDataBuff(size, pGroupIcons, CountIcons, DataArray)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Data2icoFile(pData, dest, size)
}

FindGroup(hModule, idx)
{
   RT_GROUP_ICON := 14, GroupIdx := 0
   
   Loop % idx
      while !hRes := DllCall("FindResource", Ptr, hModule, UInt, ++GroupIdx, UInt, RT_GROUP_ICON, Ptr)
         if (A_Index = 100000 && Error := 1)
            break 2
         
   if Error
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, Индекс не найден
      ExitApp
   }
   Return hRes
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(size, pIconGroup, CountIcons, DataArray)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlCopyMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlCopyMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlCopyMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size)
{
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      ExitApp
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker Шикарно! Теперь можно "воровать" понравившиеся иконки.
Под х64 полёт нормальный, под х32 Unicode неработает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

10

Re: AHK: как узнать путь к иконке используемой файлом?

Да, действительно, под х32 не работает почему-то, кроме того на х64 не загружает 32-битные модули. Надо разбираться.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: как узнать путь к иконке используемой файлом?

Вот вариант для любой битности:

SetBatchLines, -1
source := "Shell32.dll"
idx := 45  ; порядковый номер от 1
dest := A_Desktop "\test.ico"

GetIconFromResource(dest, source, idx)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   hModule := Validation(source)
   
   hGroupInfo := FindGroup(hModule, idx)
   pGroupInfo := GetResData(hModule, hGroupInfo)

   DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
   pData := CreateDataBuff(size, pGroupInfo, CountIcons, DataArray)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Data2icoFile(pData, dest, size)
}

Validation(source)
{
   if !FileExist(source)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
      {
         if FileExist(s := RTrim(A_LoopField, "\") . "\" . source)
         {
            source := s, found := 1
            break
         }
      }
      if !found
      {
         MsgBox, Файл %source% не найден
         ExitApp
      }
   }
   
   SplitPath, source,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      ExitApp
   }
   if !IsObject(File := FileOpen(source, "r"))
   {
      MsgBox, Невозможно открыть файл %source% для чтения.`nОшибка %A_LastError%
      ExitApp
   }
   
   File.Seek(0x3C)
   File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort()
   File.Close()
   
   if (res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4)   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
   {
      v := res = 0x10B
      if A_IsCompiled
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
         ExitApp
      }
      
      SplitPath, A_AhkPath,, AhkDir
      if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
      {
         Run, "%AhkModule%" "%A_ScriptFullPath%"
         ExitApp
      }
      else
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
            . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
         ExitApp
      }
   }
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      ExitApp
   }
   Return hModule
}

FindGroup(hModule, idx)
{
   RT_GROUP_ICON := 14, GroupIdx := 0
   
   VarSetCapacity(Name, 8, 0), NumPut(idx, Name, "UInt"), NumPut(0xFFFFFFFF, Name, 4, "UInt")
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON, Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, &Name)
   if ((n := NumGet(Name, 4, "UInt")) = 0xFFFFFFFF)
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, Индекс не найден
      ExitApp
   }

   Return DllCall("FindResource", Ptr, hModule, UInt, n, UInt, RT_GROUP_ICON, Ptr)
}

EnumGroupIconResource(hModule, Type, Name, lp)
{
   static i = 0
   if NumGet(lp+0, "UInt") = ++i
   {
      NumPut(Name, lp+4, "UInt")
      Return
   }
   Return Name != "" ? 1 : 0
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(size, pIconGroup, CountIcons, DataArray)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size)
{
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      ExitApp
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: как узнать путь к иконке используемой файлом?

В коллекцию!?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

13

Re: AHK: как узнать путь к иконке используемой файлом?

Надо ещё посмотреть, какие недостатки.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: как узнать путь к иконке используемой файлом?

Исправил поиск имени группы иконок по порядковому номеру.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

15 (изменено: Alectric, 2014-05-25 21:39:10)

Re: AHK: как узнать путь к иконке используемой файлом?

Можно ли обойтись без перезапуска скрипта? Это слишком неудобно, потому-что тогда невозможно использовать FileSelectFile, разве что использовать временный файл для сохранения пути на случай перезапуска.

Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

16

Re: AHK: как узнать путь к иконке используемой файлом?

Думал об этом, можно просто поиск отдельным процессом осуществлять, если битность не соответствует, по-другому, вроде, никак. Сделаю такой вариант позже.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17

Re: AHK: как узнать путь к иконке используемой файлом?

Такой вариант работает без перезагрузки:

SetBatchLines, -1
source := "Shell32.dll"
idx := 45  ; порядковый номер от 1
dest := A_Desktop "\test.ico"

GetIconFromResource(dest, source, idx)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   if !hModule := Validation(dest, source, idx)
      Return
   
   hGroupInfo := FindGroup(hModule, idx)
   pGroupInfo := GetResData(hModule, hGroupInfo)

   DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
   pData := CreateDataBuff(size, pGroupInfo, CountIcons, DataArray)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Data2icoFile(pData, dest, size)
}

Validation(dest, source, idx)
{
   if !FileExist(source)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
      {
         if FileExist(s := RTrim(A_LoopField, "\") . "\" . source)
         {
            source := s, found := 1
            break
         }
      }
      if !found
      {
         MsgBox, Файл %source% не найден
         Return
      }
   }
   
   SplitPath, source,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      Return
   }
   if !IsObject(File := FileOpen(source, "r"))
   {
      MsgBox, Невозможно открыть файл %source% для чтения.`nОшибка %A_LastError%
      Return
   }
   
   File.Seek(0x3C)
   File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort()
   File.Close()
   
   if (res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4)   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
   {
      v := res = 0x10B
      if A_IsCompiled
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
         Return
      }
      
      SplitPath, A_AhkPath,, AhkDir
      if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
      {
         VarSetCapacity(TmpFilePath, MAX_PATH := 260)
         DllCall("GetTempFileName", Str, A_Temp, Str, "ICN", UInt, 0, Ptr, &TmpFilePath)
         VarSetCapacity(TmpFilePath, -1)
         FileAppend, % GetScript(source, dest, idx), % TmpFilePath
         RunWait, "%AhkModule%" "%TmpFilePath%"
         FileDelete, % TmpFilePath
         Return
      }
      else
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
            . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
         Return
      }
   }
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      Return
   }
   Return hModule
}

FindGroup(hModule, idx)
{
   RT_GROUP_ICON := 14, GroupIdx := 0
   
   VarSetCapacity(Name, 8, 0), NumPut(idx, Name, "UInt"), NumPut(0xFFFFFFFF, Name, 4, "UInt")
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON, Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, &Name)
   if ((n := NumGet(Name, 4, "UInt")) = 0xFFFFFFFF)
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, Индекс не найден
      Return
   }

   Return DllCall("FindResource", Ptr, hModule, UInt, n, UInt, RT_GROUP_ICON, Ptr)
}

EnumGroupIconResource(hModule, Type, Name, lp)
{
   static i = 0
   if NumGet(lp+0, "UInt") = ++i
   {
      NumPut(Name, lp+4, "UInt")
      Return
   }
   Return Name != "" ? 1 : 0
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(size, pIconGroup, CountIcons, DataArray)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size)
{
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      Return
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}

GetScript(source, dest, idx)
{
   Script =
   (
      #NoTrayIcon
      SetBatchLines, -1
      GetIconFromResource("%dest%", "%source%", "%idx%")
      ExitApp

      GetIconFromResource(dest, source, idx)
      {
         if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
         {
            MsgBox, Невозможно загрузить указанный модуль!``nОшибка `%A_LastError`%
            ExitApp
         }

         hGroupInfo := FindGroup(hModule, idx)
         pGroupInfo := GetResData(hModule, hGroupInfo)

         DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
         pData := CreateDataBuff(size, pGroupInfo, CountIcons, DataArray)
         DllCall("FreeLibrary", Ptr, hModule)
         
         Data2icoFile(pData, dest, size)
      }
      
      FindGroup(hModule, idx)
      {
         RT_GROUP_ICON := 14, GroupIdx := 0
         
         VarSetCapacity(Name, 8, 0), NumPut(idx, Name, "UInt"), NumPut(0xFFFFFFFF, Name, 4, "UInt")
         DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON, Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, &Name)
         if ((n := NumGet(Name, 4, "UInt")) = 0xFFFFFFFF)
         {
            DllCall("FreeLibrary", Ptr, hModule)
            MsgBox, Индекс не найден
            ExitApp
         }

         Return DllCall("FindResource", Ptr, hModule, UInt, n, UInt, RT_GROUP_ICON, Ptr)
      }

      EnumGroupIconResource(hModule, Type, Name, lp)
      {
         static i = 0
         if NumGet(lp+0, "UInt") = ++i
         {
            NumPut(Name, lp+4, "UInt")
            Return
         }
         Return Name != "" ? 1 : 0
      }
      
      GetResData(hModule, hRes)
      {
         hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
         Return DllCall("LockResource", Ptr, hData, Ptr)
      }

      CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
      {
         static DataArray := [], RT_ICON := 3
         
         CountIcons := NumGet(pIconGroup+0, 4, "UShort")
         offset := 6 + CountIcons*16
         
         Loop `% CountIcons
         {
            id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
            hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
            pIcon := GetResData(hModule, hRes)
            DataArray[A_Index] := {ptr: pIcon
                                 , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                                 , offset: offset}
            offset += s
         }
         Return DataArray
      }

      CreateDataBuff(size, pIconGroup, CountIcons, DataArray)
      {
         static IconData
         VarSetCapacity(IconData, size)
         DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

         offset := 6
         Loop `% CountIcons
         {
            DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
            NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
            DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
         }
         Return &IconData
      }

      Data2icoFile(pData, Dest, size)
      {
         if !(File := FileOpen(Dest, "w"))
         {
            MsgBox, Невозможно открыть файл `%Dest`% на запись``nОшибка `%A_LastError`%
            ExitApp 
         }
         File.Seek(0)
         File.RawWrite(pData+0, size)
         File.Close()
      }
   )
   Return Script
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: как узнать путь к иконке используемой файлом?

Почему-то у меня для любого валидного source и idx выдает одну и ту же иконку test. Win 8.1 x86

+ открыть спойлер

http://savepic.net/5573011.jpg

19 (изменено: serzh82saratov, 2014-05-26 10:44:19)

Re: AHK: как узнать путь к иконке используемой файлом?

Возможно что появляясь на раб столе с одинаковым именем её вид не обновляется, попробуй для каждого индекса использовать разное имя файла.

idx := 45  ; порядковый номер от 1
dest := A_Desktop "\icon" idx ".ico"
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

20

Re: AHK: как узнать путь к иконке используемой файлом?

Такой вариант работает без перезагрузки:

Почему то правильно создаёт только первую иконку:


loop 10 
    GetIconFromResource(A_Desktop "\icons\icon" A_Index + 200 ".ico", source, A_Index  + 200)
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

21

Re: AHK: как узнать путь к иконке используемой файлом?

Вот так, вроде, правильно:

SetBatchLines, -1

Loop 200
   GetIconFromResource(A_Desktop "\Icons\test" A_Index ".ico", "Shell32.dll", A_Index)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   if !hModule := Validation(dest, source, idx)
      Return
   
   GetIt(dest, source, idx, hModule)
}
   
GetIt(dest, source, idx, hModule)
{
   if !hGroupInfo := FindGroup(source, idx, hModule)
      Return
   
   pGroupInfo := GetResData(hModule, hGroupInfo)
   DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
   pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Data2icoFile(pData, dest, size)
}

Validation(dest, source, idx)
{
   if !(source := ValidateName(source)) || !ValidateCapasity(dest, source, idx)
      Return
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      Return
   }
   Return hModule
}

ValidateName(FilePath)
{
   if !FileExist(FilePath)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
      {
         if FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath)
         {
            FilePath := p, found := 1
            break
         }
      }
      if !found
      {
         MsgBox, Файл %FilePath% не найден
         Return
      }
   }
   
   SplitPath, FilePath,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      Return
   }
   Return FilePath
}

ValidateCapasity(dest, source, idx)
{
   if !IsObject(File := FileOpen(source, "r"))
   {
      MsgBox, Невозможно открыть файл %source% для чтения.`nОшибка %A_LastError%
      Return
   }
   File.Seek(0x3C), File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort(), File.Close()
   
   if !((res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4))   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
      Return 1
   Else
   {
      v := res = 0x10B
      if A_IsCompiled
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
         Return
      }
      
      SplitPath, A_AhkPath,, AhkDir
      if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
         RunScript(dest, source, idx, AhkModule)
      else
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
            . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
      }
   }
}

RunScript(dest, source, idx, AhkModule)
{
   VarSetCapacity(TmpFilePath, MAX_PATH := 260)
   DllCall("GetTempFileName", Str, A_Temp, Str, "ICN", UInt, 0, Ptr, &TmpFilePath)
   VarSetCapacity(TmpFilePath, -1)
   FileAppend, % GetScript(dest, source, idx), % TmpFilePath
   RunWait, "%AhkModule%" "%TmpFilePath%"
   FileDelete, % TmpFilePath
}

FindGroup(source, idx, hModule)
{
   VarSetCapacity(Name, 8, 0), NumPut(idx, Name, "UShort"), NumPut(0xFFFFFFFF, Name, 2, "UInt")
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON := 14, Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, &Name)
   if ((n := NumGet(Name, 2, "UInt")) = 0xFFFFFFFF)
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, Индекс %idx% в файле %source% не найден
      Return
   }
   Return DllCall("FindResource", Ptr, hModule, UInt, n, UInt, RT_GROUP_ICON, Ptr)
}

EnumGroupIconResource(hModule, Type, Name, lp)
{
   static i
   (!NumGet(lp+6, "UShort")) ? (NumPut(1, lp+6, "UShort"), i := 0)
   if NumGet(lp+0, "UShort") = ++i && NumPut(Name, lp+2, "UInt") && !i := 0
      Return
   
   Return Name != "" ? 1 : 0
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size)
{
   SplitPath, Dest,, Dir
   If !FileExist(Dir)
      FileCreateDir, % Dir
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      Return
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}

GetScript(dest, source, idx)
{
   Script =
   (
      #NoTrayIcon
      SetBatchLines, -1
      GetIcon("%dest%", "%source%", "%idx%")
      ExitApp

      GetIcon(dest, source, idx)
      {
         if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
         {
            MsgBox, Невозможно загрузить указанный модуль!``nОшибка `%A_LastError`%
            ExitApp
         }
         GetIt(dest, source, idx, hModule)
      }
      #Include %A_ScriptFullPath%
   )
   Return Script
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK: как узнать путь к иконке используемой файлом?

А точнее, вот так:

SetBatchLines, -1

Loop 300
   GetIconFromResource(A_Desktop "\Icons\test" A_Index ".ico", "Shell32.dll", A_Index)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   if !hModule := Validation(dest, source, idx)
      Return
   
   GetIt(dest, source, idx, hModule)
}
   
GetIt(dest, source, idx, hModule)
{
   if !hGroupInfo := FindGroup(source, idx, hModule)
      Return
   
   pGroupInfo := GetResData(hModule, hGroupInfo)
   DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
   pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Data2icoFile(pData, dest, size)
}

Validation(dest, source, idx)
{
   if !(source := ValidateName(source)) || !ValidateCapasity(dest, source, idx)
      Return
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      Return
   }
   Return hModule
}

ValidateName(FilePath)
{
   if !FileExist(FilePath)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
      {
         if FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath)
         {
            FilePath := p, found := 1
            break
         }
      }
      if !found
      {
         MsgBox, Файл %FilePath% не найден
         Return
      }
   }
   
   SplitPath, FilePath,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      Return
   }
   Return FilePath
}

ValidateCapasity(dest, source, idx)
{
   if !IsObject(File := FileOpen(source, "r"))
   {
      MsgBox, Невозможно открыть файл %source% для чтения.`nОшибка %A_LastError%
      Return
   }
   File.Seek(0x3C), File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort(), File.Close()
   
   if !((res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4))   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
      Return 1
   Else
   {
      v := res = 0x10B
      if A_IsCompiled
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
         Return
      }
      
      SplitPath, A_AhkPath,, AhkDir
      if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
         RunScript(dest, source, idx, AhkModule)
      else
      {
         MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
            . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
            . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
      }
   }
}

RunScript(dest, source, idx, AhkModule)
{
   VarSetCapacity(TmpFilePath, MAX_PATH := 260)
   DllCall("GetTempFileName", Str, A_Temp, Str, "ICN", UInt, 0, Ptr, &TmpFilePath)
   VarSetCapacity(TmpFilePath, -1)
   FileAppend, % GetScript(dest, source, idx), % TmpFilePath
   RunWait, "%AhkModule%" "%TmpFilePath%"
   FileDelete, % TmpFilePath
}

FindGroup(source, idx, hModule)
{
   VarSetCapacity(Name, 8, 0), NumPut(idx, Name, "UShort"), NumPut(0xFFFFFFFF, Name, 2, "UInt")
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON := 14, Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, &Name)
   if ((n := NumGet(Name, 2, "UInt")) = 0xFFFFFFFF)
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, Индекс %idx% в файле %source% не найден
      Return
   }
   Return DllCall("FindResource", Ptr, hModule, UInt, n, UInt, RT_GROUP_ICON, Ptr)
}

EnumGroupIconResource(hModule, Type, Name, lp)
{
   static i
   (!NumGet(lp+6, "UShort")) ? (NumPut(1, lp+6, "UShort"), i := 0)
   if NumGet(lp+0, "UShort") = ++i && NumPut(Name, lp+2, "UInt")
      Return
   
   Return Name != "" ? 1 : 0
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size)
{
   SplitPath, Dest,, Dir
   if !FileExist(Dir)
   {
      FileCreateDir, % Dir
      if ErrorLevel
      {
         MsgBox, Невозможно создать папку %Dir%.`nОшибка %A_LastError%
         Return
      }
   }
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      Return
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}

GetScript(dest, source, idx)
{
   Script =
   (
      #NoTrayIcon
      SetBatchLines, -1
      GetIcon("%dest%", "%source%", "%idx%")
      ExitApp

      GetIcon(dest, source, idx)
      {
         if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
         {
            MsgBox, Невозможно загрузить указанный модуль!``nОшибка `%A_LastError`%
            ExitApp
         }
         GetIt(dest, source, idx, hModule)
      }
      #Include %A_ScriptFullPath%
   )
   Return Script
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

23

Re: AHK: как узнать путь к иконке используемой файлом?

Я подумал — а чего мелочиться? В таком варианте считываются из ресурса все иконки за раз, если в качестве индекса отправить 0.

SetBatchLines, -1
GetIconFromResource(A_Desktop "\Icons\test.ico", "Shell32.dll", 0)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   if !hModule := Validation(dest, source, idx)
      Return
   
   GetIt(dest, source, idx, hModule)
}
   
GetIt(dest, source, idx, hModule)
{
   if !oHandles := FindGroup(source, idx, hModule)
      Return
   
   for key, handle in oHandles
   {
      pGroupInfo := GetResData(hModule, handle)
      DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size)
      pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
      Data2icoFile(pData, dest, size, (key = oHandles.MaxIndex() && key > 1) ? -1 : idx)
   }
   DllCall("FreeLibrary", Ptr, hModule)
}

Validation(dest, source, idx)
{
   if !(source := ValidateName(source)) || !ValidateCapasity(dest, source, idx)
      Return
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
   {
      MsgBox, Невозможно загрузить указанный модуль!`nОшибка %A_LastError%
      Return
   }
   Return hModule
}

ValidateName(FilePath)
{
   if !FileExist(FilePath)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
      {
         if FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath)
         {
            FilePath := p, found := 1
            break
         }
      }
      if !found
      {
         MsgBox, Файл %FilePath% не найден
         Return
      }
   }
   
   SplitPath, FilePath,,, ext
   if !(ext ~= "exe|dll")
   {
      MsgBox, Допустимы только dll и exe файлы
      Return
   }
   Return FilePath
}

ValidateCapasity(dest, source, idx)
{
   if !IsObject(File := FileOpen(source, "r"))
   {
      MsgBox, Невозможно открыть файл %source% для чтения.`nОшибка %A_LastError%
      Return
   }
   File.Seek(0x3C), File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort(), File.Close()
   
   if !((res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4))   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
      Return 1

   v := res = 0x10B
   if A_IsCompiled
   {
      MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
         . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
      Return
   }
   
   SplitPath, A_AhkPath,, AhkDir
   if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
      Return RunScript(dest, source, idx, AhkModule)
   
   MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
      . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
      . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
}

RunScript(dest, source, idx, AhkModule)
{
   VarSetCapacity(TmpFilePath, MAX_PATH := 260)
   DllCall("GetTempFileName", Str, A_Temp, Str, "ICN", UInt, 0, Ptr, &TmpFilePath)
   VarSetCapacity(TmpFilePath, -1)
   FileAppend, % GetScript(dest, source, idx), % TmpFilePath
   RunWait, "%AhkModule%" "%TmpFilePath%"
   FileDelete, % TmpFilePath
}

FindGroup(source, idx, hModule)
{
   static RT_GROUP_ICON := 14
   
   Names := [idx, 0]
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON
      , Ptr, RegisterCallback("EnumGroupIconResource", "Fast", 4), Ptr, pNames := Object(Names))
   ObjRelease(pNames)
   if (Names.3 = "")
   {
      DllCall("FreeLibrary", Ptr, hModule)
      MsgBox, % idx ? "Иконка " . idx . " в файле " . source . " не найдена" : "Иконки в файле " . source . " не найдены"
      Return
   }
   Names.Remove(1, 2)
   for k, v in Names
      Names[k] := DllCall("FindResource", Ptr, hModule, UInt, v, UInt, RT_GROUP_ICON, Ptr)
   Return Names
}

EnumGroupIconResource(hModule, Type, Name, lp)
{
   obj := Object(lp)
   if !obj.1
      obj.Insert(Name)
   else
   {
      obj.2 += 1
      if (obj.2 = obj.1)
      {
         obj.3 := Name
         Return
      }
   }
   Return 1
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset)
{
   static DataArray := [], RT_ICON := 3
   
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UShort")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size, idx)
{
   static i = 0
   SplitPath, Dest,, Dir, Ext, OutNameNoExt
   If !FileExist(Dir)
   {
      FileCreateDir, % Dir
      if ErrorLevel
      {
         MsgBox, Невозможно создать папку %Dir%.`nОшибка %A_LastError%
         Return
      }
   }
   if (idx <= 0)
      Dest := (Ext ? SubStr(Dest, 1, -(StrLen(Ext) + 1)) : Dest) . "(" . ++i . ")" . (Ext ? "." . Ext : "")
   (idx = -1) ? i := 0
   
   if !(File := FileOpen(Dest, "w"))
   {
      MsgBox, Невозможно открыть файл %Dest% на запись`nОшибка %A_LastError%
      Return
   }
   File.Seek(0)
   File.RawWrite(pData+0, size)
   File.Close()
}

GetScript(dest, source, idx)
{
   Script =
   (
      #NoTrayIcon
      SetBatchLines, -1
      GetIcon("%dest%", "%source%", "%idx%")
      ExitApp

      GetIcon(dest, source, idx)
      {
         if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
         {
            MsgBox, Невозможно загрузить указанный модуль!``nОшибка `%A_LastError`%
            ExitApp
         }
         GetIt(dest, source, idx, hModule)
      }
      #Include %A_ScriptFullPath%
   )
   Return Script
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

24

Re: AHK: как узнать путь к иконке используемой файлом?

Последний (подсокращённый) вариант. Добавлен в Коллекцию, сообщайте о недостатках, если заметите.

GetIconFromResource(A_Desktop "\Icons\test.ico", "Shell32.dll", 0)        ; извлекаем все иконки из Shell32.dll
GetIconFromResource(A_Desktop "\Icons2\test.ico", "Shell32.dll", 45)      ; извлекаем иконку с порядковым индексом 45 (счёт от 1)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   if !hModule := Validation(dest, source, idx)
      Return
   
   GetIt(dest, source, idx, hModule)
}
   
GetIt(dest, source, idx, hModule)
{
   SetBatchLines, -1
   for key, handle in FindGroup(source, idx, hModule)
   {
      pGroupInfo := GetResData(hModule, handle)
      if !IsObject(DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size, idx ? idx : A_Index))
      {
         if (DataArray = 6)
            continue
         else
            break
      }
      pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
      res := Data2icoFile(pData, dest, size, idx)
   } until !res
   
   DllCall("FreeLibrary", Ptr, hModule)
}

Validation(dest, source, idx)
{
   if !((idx + 1) > 0 && (source := ValidateName(source)) && ValidateCapasity(dest, source, idx))
      Return
   
   if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
      && Error := "Невозможно загрузить указанный модуль!`nОшибка " A_LastError
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
         
   Return hModule
}

ValidateName(FilePath)
{
   if !FileExist(FilePath)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
         continue
      until FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath) && (FilePath := p) && found := 1
      
      if !found && Text := "Файл " FilePath " не найден"
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   }
   
   SplitPath, FilePath,,, ext
   if !(ext ~= "i)exe|dll") && Error := "Допустимы только dll и exe файлы"
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
   
   Return FilePath
}

ValidateCapasity(dest, source, idx)
{
   if !IsObject(File := FileOpen(source, "r")) && Text := "Невозможно открыть файл " source "для чтения`nОшибка " A_LastError
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   
   File.Seek(0x3C), File.Seek(File.ReadUInt() + 0x18)
   res := File.ReadUShort(), File.Close()
   
   if !((res = 0x10B && A_PtrSize = 8) || (res = 0x20B && A_PtrSize = 4))   ; 0x10B — 32-битный модуль, 0x20B — 64-битный
      Return 1

   v := res = 0x10B
   if A_IsCompiled && Text := "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
      . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Запустите скрипт в нескомпилированном виде."
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   
   SplitPath, A_AhkPath,, AhkDir
   if FileExist(AhkModule := AhkDir . "\AutoHotkeyU" . (v ? "32" : "64") . ".exe")
      Return RunScript(dest, source, idx, AhkModule)
   
   MsgBox, % "Вы пытаетесь загрузить " . (v ? "32" : "64") . "-битный модуль на "
      . (v ? "64" : "32") . "-битной версии AHK!`nПрограмма не будет работать. Установите AHK с помощью инсталлятора с оф. сайта."
      . "`nВ папке, куда установлена AHK, должны быть файлы AutoHotkeyU32.exe и AutoHotkeyU64.exe"
}

RunScript(dest, source, idx, AhkModule)
{
   VarSetCapacity(TmpFilePath, MAX_PATH := 260)
   DllCall("GetTempFileName", Str, A_Temp, Str, "ICN", UInt, 0, Ptr, &TmpFilePath)
   VarSetCapacity(TmpFilePath, -1)
   FileAppend, % GetScript(dest, source, idx), % TmpFilePath
   RunWait, "%AhkModule%" "%TmpFilePath%"
   FileDelete, % TmpFilePath
}

FindGroup(source, idx, hModule)
{
   Names := [idx, 0]
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON := 14
      , Ptr, RegisterCallback("EnumGroupIconProc", "Fast", 4), Ptr, pNames := Object(Names))
   ObjRelease(pNames)
   
   if (Names.3 = "") && Text := idx ? "Иконка " . idx . " в файле " . source . " не найдена"
                                    : "Иконки в файле " . source . " не найдены"
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   
   Names.Remove(1, 2)
   for i, Name in Names
      Names[i] := DllCall("FindResource", Ptr, hModule, Name + 1 ? "UInt" : "Str", Name, UInt, RT_GROUP_ICON, Ptr)
   Return Names
}

EnumGroupIconProc(hModule, Type, Name, lp)
{
   (Name>>16) ? Name := LTrim(StrGet(Name+0), "#")
   obj := Object(lp)
   if !obj.1
      obj.Insert(Name)
   else if ((obj.2 += 1) = obj.1)
      Return, 0, obj.3 := Name
   Return 1
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset, idx)
{
   if NumGet(pIconGroup+0, 2, "UShort") != 1 && Text := "Ресурс " Idx " неправильного типа. Возможно, файл сжат или зашифрован`nПродолжить?"
      Return DllCall("MessageBox", Ptr, 0, Str, Text, Str, "Неправильный ресурс", UInt, 4)
   
   DataArray := [], RT_ICON := 3
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UInt")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size, idx)
{
   static i = 0
   SplitPath, Dest,, Dir, Ext, OutNameNoExt
   if !FileExist(Dir)
   {
      FileCreateDir, % Dir
      if ErrorLevel && Text := "Невозможно создать папку " Dir "`nОшибка " A_LastError
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   }
   
   (!idx) ? Dest := (Ext ? SubStr(Dest, 1, -(StrLen(Ext) + 1)) : Dest) . "(" . ++i . ")" . (Ext ? "." . Ext : "")
   
   if !(File := FileOpen(Dest, "w")) && Text := "Невозможно открыть файл " Dest "на запись`nОшибка " A_LastError
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
         
   File.Seek(0), File.RawWrite(pData+0, size), File.Close()
   Return 1
}

GetScript(dest, source, idx)
{
   Script =
   (
      #NoTrayIcon
      SetBatchLines, -1
      GetIcon("%dest%", "%source%", "%idx%")
      ExitApp

      GetIcon(dest, source, idx)
      {
         if !(hModule := DllCall("LoadLibrary", Str, source, Ptr))
            && Text := "Невозможно загрузить указанный модуль!``nОшибка " A_LastError
               ExitApp, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
         
         GetIt(dest, source, idx, hModule)
      }
      #Include %A_ScriptFullPath%
   )
   Return Script
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25

Re: AHK: как узнать путь к иконке используемой файлом?

Исправлено несколько ошибок.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

26

Re: AHK: как узнать путь к иконке используемой файлом?

Убрал:

Исправлено несколько ошибок.

из темы в Коллекции.

27

Re: AHK: как узнать путь к иконке используемой файлом?

Оказывается, в адресное пространство процесса можно загрузить модуль несоответствующей битности, если указать, что он загружается, как источник ресурсов. Так что вспомогательный процесс не нужен. Новый вариант:

GetIconFromResource(A_Desktop "\Icons\test.ico", "Shell32.dll", 0)  ; извлекаем все иконки из ресурса
GetIconFromResource(A_Desktop "\Icons2\test.ico", "Shell32.dll", 45)  ; извлекаем конку с порядковым индексом 45 (счёт от 1)
Return

GetIconFromResource(dest, source, idx)
{
   ; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
   SetBatchLines, -1
   if !hModule := Validation(dest, source, idx)
      Return
   
   for key, handle in FindGroup(source, idx, hModule)
   {
      pGroupInfo := GetResData(hModule, handle)
      if !IsObject(DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size, idx ? idx : A_Index))
      {
         if (DataArray = 6)
            continue
         else
            break
      }
      pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
      res := Data2icoFile(pData, dest, size, idx)
   } until !res
   
   DllCall("FreeLibrary", Ptr, hModule)
}

Validation(dest, source, idx)
{
   if !((idx + 1) > 0 && source := ValidateName(source))
      Return
   
   static dwFlags := (LOAD_LIBRARY_AS_DATAFILE := 0x2 | LOAD_LIBRARY_AS_IMAGE_RESOURCE := 0x20)
   if !hModule := DllCall("LoadLibraryEx", Str, source, Ptr, 0, UInt, dwFlags, Ptr)
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Невозможно загрузить указанный модуль!`nОшибка " A_LastError, Str, "", UInt, 0)
         
   Return hModule
}

ValidateName(FilePath)
{
   SplitPath, FilePath,,, ext
   if !(ext ~= "i)exe|dll") && Error := "Допустимы только dll и exe файлы"
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
   
   if !FileExist(FilePath)
   {
      EnvGet, PathVar, Path
      Loop, parse, PathVar, `;
         continue
      until FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath) && (FilePath := p) && found := 1
      
      if !found && Text := "Файл " FilePath " не найден"
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   }
   
   Return FilePath
}

FindGroup(source, idx, hModule)
{
   Names := [idx, 0]
   DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON := 14
      , Ptr, RegisterCallback("EnumGroupIconProc", "Fast", 4), Ptr, pNames := Object(Names))
   ObjRelease(pNames)
   
   if (Names.3 = "") && Text := idx ? "Иконка " . idx . " в файле " . source . " не найдена"
                                    : "Иконки в файле " . source . " не найдены"
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   
   Names.Remove(1, 2)
   for i, Name in Names
      Names[i] := DllCall("FindResource", Ptr, hModule, Name + 1 ? "UInt" : "Str", Name, UInt, RT_GROUP_ICON, Ptr)
   Return Names
}

EnumGroupIconProc(hModule, Type, Name, lp)
{
   (Name>>16) ? Name := LTrim(StrGet(Name+0), "#")
   obj := Object(lp)
   if !obj.1
      obj.Insert(Name)
   else if ((obj.2 += 1) = obj.1)
      Return, 0, obj.3 := Name
   Return 1
}

GetResData(hModule, hRes)
{
   hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
   Return DllCall("LockResource", Ptr, hData, Ptr)
}

CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset, idx)
{
   if NumGet(pIconGroup+0, 2, "UShort") != 1 && Text := "Ресурс " Idx " неправильного типа. Возможно, файл сжат или зашифрован`nПродолжить?"
      Return DllCall("MessageBox", Ptr, 0, Str, Text, Str, "Неправильный ресурс", UInt, 4)
   
   DataArray := [], RT_ICON := 3
   CountIcons := NumGet(pIconGroup+0, 4, "UShort")
   offset := 6 + CountIcons*16
   
   Loop % CountIcons
   {
      id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
      hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
      pIcon := GetResData(hModule, hRes)
      DataArray[A_Index] := {ptr: pIcon
                           , size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UInt")
                           , offset: offset}
      offset += s
   }
   Return DataArray
}

CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
   static IconData
   VarSetCapacity(IconData, size)
   DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)

   offset := 6
   Loop % CountIcons
   {
      DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
      NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
      DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
   }
   Return &IconData
}

Data2icoFile(pData, Dest, size, idx)
{
   static i = 0
   SplitPath, Dest,, Dir, Ext, OutNameNoExt
   if !FileExist(Dir)
   {
      FileCreateDir, % Dir
      if ErrorLevel && Text := "Невозможно создать папку " Dir "`nОшибка " A_LastError
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
   }
   
   (!idx) ? Dest := (Ext ? SubStr(Dest, 1, -(StrLen(Ext) + 1)) : Dest) . "(" . ++i . ")" . (Ext ? "." . Ext : "")
   
   if !(File := FileOpen(Dest, "w")) && Text := "Невозможно открыть файл " Dest "на запись`nОшибка " A_LastError
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
         
   File.Seek(0), File.RawWrite(pData+0, size), File.Close()
   Return 1
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

28

Re: AHK: как узнать путь к иконке используемой файлом?

Ну и до кучи, создание dll с иконками и добавление иконок в существующие dll и exe файлы:

AddIconResourceToFile(SourceFolder, DestDllorExe)
{
   SetBatchLines, -1
   SetWorkingDir, % A_ScriptDir
   
   SplitPath, DestDllorExe,,, ext
   if (!(ext ~= "i)exe|dll") && (Error := "Допустимы только dll и exe файлы"))
      || (ext = "exe" && !FileExist(DestDllorExe) && Error := "Файл """ DestDllorExe """ не найден")
         Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
   
   FileArray := []
   Loop, % SourceFolder "\*.ico", 0, 0
      FileArray[A_Index] := A_LoopFileLongPath
   
   if (!FileArray.1 && Error := "Файлы с иконками в папке """ SourceFolder """ не найдены")
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
   
   if (ext = "dll" && !FileExist(DestDllorExe))
      CreateResourceDll(FileArray, DestDllorExe)
   else
      UpdateResource(FileArray, DestDllorExe)
   Return
}

CreateResourceDll(FileArray, Dest)
{
   if !CreateDummyDll(Dest)
      Return
   
   Update(FileArray, Dest, 1, 1)
}

UpdateResource(FileArray, Dest)
{
   if !hModule := DllCall("LoadLibraryEx", Str, Dest, Ptr, 0, UInt, LOAD_LIBRARY_AS_DATAFILE := 0x2, Ptr)
      Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Невозможно загрузить указанный модуль!`nОшибка " A_LastError, Str, "", UInt, 0)

   FirstGroupNumber := GetMaxNumber(hModule, RT_GROUP_ICON := 14)
   FirstIconIdx := GetMaxNumber(hModule, RT_ICON := 3)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Update(FileArray, Dest, FirstGroupNumber, FirstIconIdx)
}

Update(FileArray, Dest, FirstGroupNumber, FirstIconIdx)
{
   if !hUpdate := DllCall("BeginUpdateResource", Str, Dest, UInt, 0, Ptr)
      Return 0, DllCall("MessageBox", Ptr, 0
         , Str, "Не удаётся открыть файл """ Dest """ для обновленя ресурсов!`nОшибка " A_LastError, Str, "", UInt, 0)

   for idx, FilePath in FileArray
      if !AddIconGroup(FilePath, hUpdate, FirstGroupNumber + idx - 1, FirstIconIdx, idx = FileArray.MaxIndex() ? 1 : 0)
         break

   DllCall("EndUpdateResource", Ptr, hUpdate, UInt, 0)
}   

GetMaxNumber(hModule, ResourceType)
{
   Names := []
   DllCall("EnumResourceNames", Ptr, hModule, UInt, ResourceType
      , Ptr, RegisterCallback("EnumProc", "Fast", 4), Ptr, pNames := Object(Names))
   ObjRelease(pNames)
   
   MaxNumber := 1
   for i, Name in Names
   {
      if !(Name + 1)
         continue
      MaxNumber <= Name ? MaxNumber := Name + 1
   }
   Return MaxNumber
}

EnumProc(hModule, Type, Name, lp)
{
   (Name>>16) ? Name := LTrim(StrGet(Name+0), "#")
   Object(lp).Insert(Name)
   Return 1
}
      
AddIconGroup(source, hUpdate, GroupIdx, StartIconIdx, end)
{
   static IconIdx
   (IconIdx = "") ? IconIdx := StartIconIdx
   
   Loop 1
   {
      if (!File := FileOpen(source, "r"))
         && Error := "Не удалось открыть файл """ source """ для чтения.`nОшибка " A_LastError ". Продолжить?"
            break
      
      File.Seek(2)   
      if File.ReadUShort() != 1
         File.Close(), Error := "Файл """ source """ неправильного типа.`nПродолжить?"
   }
   
   if Error
      Return MessageBoxYesNo(Error) ? 1 : IconIdx := ""
   
   CountIcons := File.ReadUShort()
   VarSetCapacity(GroupBuff, GroupSize := 6 + 14*CountIcons, 0)
   File.Seek(0), File.RawRead(GroupBuff, 6)
   
   Loop % CountIcons
   {
      File.Seek(6 + 16*(A_Index - 1))
      File.RawRead(&GroupBuff + 6 + 14*(A_Index - 1), 12)
      NumPut(IconIdx, &GroupBuff + 6 + 14*A_Index - 2, "UShort")
      
      File.Seek(6 + 16*A_Index - 8), BytesInRes := File.ReadUInt()
      VarSetCapacity(IconBuff, BytesInRes, 0)
      File.Seek(6 + 16*A_Index - 4), File.Seek(File.ReadUInt())
      File.RawRead(IconBuff, BytesInRes)
      DllCall("UpdateResource", Ptr, hUpdate, UInt, RT_ICON := 3, UInt, IconIdx++, UInt, 0x409, Ptr, &IconBuff, UInt, BytesInRes)
   }
   DllCall("UpdateResource", Ptr, hUpdate, UInt, RT_GROUP_ICON := 14, UInt, GroupIdx, UInt, 0x409, Ptr, &GroupBuff, UInt, GroupSize)
   
   File.Close()
   end ? IconIdx := ""
   Return 1
}
   
MessageBoxYesNo(text, title = "")
{
   MsgBox, 4, % title, % text
   IfMsgBox, Yes
      Return 1
   else
      Return 0
}

CreateDummyDll(dest)
{
   DummyDll =
   (LTrim Join
      4D5A90000300000004000000FFFF0000B8000000000000004000000000000000000000000000000000000000000000000000000000
      00000000000000B00000000E1FBA0E00B409CD21B8014CCD21546869732069732033322D626974207265736F7572636520646C6C2E
      0D0D0A0000000000000000000000240000000000000029E701DB6D866F886D866F886D866F88AA8069886C866F8832A465886C866F
      88526963686D866F880000000000000000504500004C0101000CA3E83A0000000000000000E0000F010B0106000000000010000000
      0000000000000000000200000002000000004000100000001000000004000000000000000400000000000000100200000002000000
      0000000200000000001000001000000000100000100000000000001000000000000000000000000000000000000000000200001000
      0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
      2E72737263000000100000000002000010000000000200000000000000000000000000004000004000000000000000000000000000
      000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000
   )

   Hex2Bin(buff, DummyDll)
   if !IsObject(File := FileOpen(dest, "w"))
      Return, 0, DllCall("MessageBox", Ptr, 0
         , Str, "Не удалось открыть файл """ dest """ для записи.`nОшибка " A_LastError, Str, "", UInt, 0)

   Return File.RawWrite(&buff+0, StrLen(DummyDll)//2), File.Close()
}
   
Hex2Bin(ByRef buff, hex)
{
   VarSetCapacity(buff, len := StrLen(hex)//2)
   Loop % len
      NumPut("0x" . SubStr(hex, 1 + (A_Index - 1)*2, 2), buff, A_Index - 1, "UChar")
}

В качестве SourceFolder нужно указать путь к папке с иконками, которые требуется добавить. Если в DestDllorExe указан путь к dll, которая ещё не существует, будет создана новая dll с иконками из папки SourceFolder. Если в DestDllorExe будут указаны уже существующие файлы, в их ресурсы будут добавлены новые иконки, если это возможно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

29

Re: AHK: как узнать путь к иконке используемой файлом?

О, класс.
Ведь по идее можно скомпилировать скрипт, загрузить в него иконки, и им же из себя же использовать!?


#SingleInstance Force  

Menu, Tray, Icon, %A_ScriptFullPath%, 9 
Gui, Add, Picture, w128 h-1 Icon10, %A_ScriptFullPath%
Gui, Show 
Return
 
Esc::      
    ExitApp


Could not extract script from EXE.

Но из некомпилированного скрипта мы без труда можем использовать их из нашего компилированного файла:


#SingleInstance Force  

Menu, Tray, Icon, C:\Users\sergey\Desktop\=Test.exe, 9 
Gui, Add, Picture, w128 h-1 Icon10, C:\Users\sergey\Desktop\=Test.exe
Gui, Show 
Return
 
Esc::      
    ExitApp

В чём заключается наивность моих предположений?
Ну а за труды спасибо, теперь одним файлом можно рядом положить нужные иконки.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

30

Re: AHK: как узнать путь к иконке используемой файлом?

Resource hacker может добавлять в скомпилированный скрипт иконку, которая будет вида в скрите, если что:

Gui, Add, Picture, w128 h-1 Icon10, %A_ScriptFullPath%

31

Re: AHK: как узнать путь к иконке используемой файлом?

А Resource hacker может так добавить, чтобы в трее поменять?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

32

Re: AHK: как узнать путь к иконке используемой файлом?

serzh82saratov пишет:

В чём заключается наивность моих предположений?

Чтобы поменять в иконку в трее на одну из тех, что добавлены в скомпилированный файл скрипта, придётся получить и использовать хэндл иконки. А картинку можно так же:

Gui, Add, Picture, w128 h-1 Icon10, %A_ScriptFullPath%
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

33

Re: AHK: как узнать путь к иконке используемой файлом?

Почему то у меня и с Resource hacker, и с этим кодом, и без Menu, Tray - Could not extract script from EXE.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

34

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

Чтобы поменять в иконку в трее на одну из тех, что добавлены в скомпилированный файл скрипта, придётся получить и использовать хэндл иконки.

Я уже даже пример накатал:

nTrayIcon := 9   ; номер иконки для трея
nPicIcon := 10   ; номер иконки для картинки
nGuiIcon := 11   ; номер иконки для окна

if !A_IsCompiled
{
   MsgBox, это пример для скомпилированного скрипта, скомпилируйте!
   ExitApp
}

hTrayIcon := ExtractIcon(A_ScriptFullPath, nTrayIcon, 16)
hGuiIconSmall := ExtractIcon(A_ScriptFullPath, nGuiIcon, 16)
hGuiIconBig   := ExtractIcon(A_ScriptFullPath, nGuiIcon, 32)

ChangeTrayIcon(hTrayIcon)   ; меняем иконку в трее

Gui, +LastFound
Gui, Add, Picture, w32 h-1 Icon%nPicIcon%, % A_ScriptFullPath    ; с картинкой остаётся прежний вариант

SendMessage, WM_SETICON := 0x80, ICON_SMALL := 0, hGuiIconSmall  ; меняем иконку окна
SendMessage, WM_SETICON := 0x80, ICON_BIG := 1, hGuiIconBig      ; большая для Alt+Tab
Gui, Show, w200 h50
Return

GuiClose:
   DllCall("DestroyIcon", Ptr, hGuiIconSmall)  ; удаляем хэндлы перед уничтожением окна
   DllCall("DestroyIcon", Ptr, hGuiIconBig)
   Gui, Destroy
   ExitApp

ExtractIcon(sFile, IconNumber, IconSize)
{
   coding := A_IsUnicode ? "W" : "A"

   SplitPath, sFile,,, ext
   if (ext = "ico")
      IconNumber := 0

   if PrivateExtractIcons := DllCall("GetProcAddress"
                              , Ptr, DllCall("LoadLibrary", Str, "User32", Ptr)
                              , AStr, "PrivateExtractIcons" . coding, Ptr)
   {
      Result := DllCall(PrivateExtractIcons, Str, sFile, Int, IconNumber-1
                  , Int, IconSize, Int, IconSize, PtrP, hIcon, UIntP, 0, UInt, 1, UInt, 0)
      if !Result
         MsgBox, 16,, % "Не удалось извлечь иконку.`nОшибка " A_LastError "."
      else if (Result = 0xFFFFFFFF || Result = -1)
         MsgBox, 16,, Указанный файл не найден!
   }
   else
   {
      if !DllCall("Shell32\ExtractIconEx" . coding, Str, sFile, Int, IconNumber-1, PtrP, hIconLarge, PtrP, hIconSmall, UInt, 1)
      {
         MsgBox, 16,, % "Не удалось извлечь иконку.`nОшибка " A_LastError "."
         return
      }
      SysGet, SmallIconSize, % SM_CXSMICON
      if (IconSize <= SmallIconSize)
         DllCall("DestroyIcon", Ptr, hIconLarge)
         , hIcon := hIconSmall
      else
         DllCall("DestroyIcon", Ptr, hIconSmall)
         , hIcon := hIconLarge

      hIcon := DllCall("CopyImage", Ptr, hIcon, UInt, IMAGE_ICON
         , Int, IconSize, Int, IconSize, UInt, LR_COPYRETURNORG := 0x4|LR_COPYDELETEORG := 0x8, Ptr)
   }
   Return hIcon
}

ChangeTrayIcon(hIcon)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA, "UInt")
   NumPut(A_ScriptHwnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID := 0x404, NOTIFYICONDATA, 2*A_PtrSize)   ; у AHK-скриптов uID всегда 0x404
   NumPut(NIF_ICON := 2, NOTIFYICONDATA, 2*A_PtrSize + 4)
   NumPut(hIcon, NOTIFYICONDATA, 3*A_PtrSize+8)
   
   DllCall("shell32\Shell_NotifyIcon", UInt, NIM_MODIFY := 1, Ptr, &NOTIFYICONDATA)
   DllCall("DestroyIcon", Ptr, hIcon)
}

Компилируем скрипт, добавляем туда три иконки. Изначально в скрипте их восемь, значит номера будут 9, 10 и 11.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

35

Re: AHK: как узнать путь к иконке используемой файлом?

Разобрался, увы с

Use MPRESS (if present) to compress resulting exe

не работает.

Я уже даже пример накатал:

Для трэя и панели задач ведь можно использовать иконку заданную в компиляторе, но если её надо будет менять, то да.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

36

Re: AHK: как узнать путь к иконке используемой файлом?

nGuiIcon := 11   ; номер иконки для окна

Прикольно, не знал что у окна может быть иконка отличная от той которая у этой программы в трее.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

37

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

А Resource hacker может так добавить, чтобы в трее поменять?

Да, вроде без проблем должно получиться.

38

Re: AHK: как узнать путь к иконке используемой файлом?

Я имею в виду, чтобы несколько раз можно было поменять. Ну, и пример кода не помешает.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

39

Re: AHK: как узнать путь к иконке используемой файлом?

У меня так и не появились идеи почему это http://forum.script-coding.com/viewtopi … 434#p77434 не меняет иконку в стороннем приложении, может по случаю подскажешь.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

40

Re: AHK: как узнать путь к иконке используемой файлом?

У меня меняет, и в панели задач меняется.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

41

Re: AHK: как узнать путь к иконке используемой файлом?

Мистика.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

42

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

Я имею в виду, чтобы несколько раз можно было поменять. Ну, и пример кода не помешает.

Вот код скомпилированного скрипта, меняюего иконку в трее, взятую из собственного файла.

Loop, 8
{
GUI, Add, Picture, w64  h-1 Icon%A_Index%, %A_ScriptFullPath%
Menu, Tray, Icon, %A_ScriptFullPath%, %A_Index%
Gui, Show, h600
Sleep, 2000
}

43

Re: AHK: как узнать путь к иконке используемой файлом?

Хм, действительно, теперь работает. Но у меня работает и такой вариант:

Loop 3
{
   Menu, Tray, Icon, %A_ScriptFullPath%, % 8 + A_Index
   Sleep, 2000
}
Return

Компилируем, добавляем три иконки с помощью моего кода.
И теперь даже такой:

Menu, Tray, Icon, %A_ScriptFullPath%, 9
Sleep, 3000

В общем, пока непонятно, почему в некоторых случаях не работает. Может, зависит от того, какие иконки добавлены.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

44

Re: AHK: как узнать путь к иконке используемой файлом?

Насколько я знаю, в одном файле *.ico может находиться несколько разных по размеру изображений. В скомпилированном скрипте есть раздел, куда закинуты иконки и им присвоены номера. Есть ещё другой раздел, где перечисляются группы иконок: в каждой группе свой набор вышеупомянутых иконок.
А система уже сама решает, которая иконка из файла *.ico, либо из группы, хранящейся в *.exe (либо другом формате ресурсов) лучше подходит для конкретного случая. Так, например, для области уведомлений или ListView в режиме "список" берётся иконка 16x16. Если таковой нет, берётся ближайшая и сжимается/растягивается.

45

Re: AHK: как узнать путь к иконке используемой файлом?

А вывод какой?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

46

Re: AHK: как узнать путь к иконке используемой файлом?

Думал, поможет понять, почему в некоторых случаях не работает.

47

Re: AHK: как узнать путь к иконке используемой файлом?

Ясно, спасибо! Только, думаешь, можно написать функции извлекающие и добавляющие иконки в ресурсы, и не знать, как они устроены?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

48

Re: AHK: как узнать путь к иконке используемой файлом?

Сейчас попробовал добавить иконки, где нет 16х16 — всё равно работает.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

49

Re: AHK: как узнать путь к иконке используемой файлом?

Так это...

teadrinker пишет:

Хм, действительно, теперь работает.

...

В общем, пока непонятно, почему в некоторых случаях не работает. Может, зависит от того, какие иконки добавлены.

Каких-то знаний явно не хватает. Я только хотел помочь! (c) х/ф "Такси"

50

Re: AHK: как узнать путь к иконке используемой файлом?

Хочешь помочь — предлагай варианты. Но я теперь уже не могу воспроизвести ситуацию, когда с добавленными иконками не работает код

Menu, Tray, Icon, %A_ScriptFullPath%, 9
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

51 (изменено: serzh82saratov, 2014-10-31 01:10:50)

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker интересный код. Я так понял что мне нужна эта статья, но не смог осилить.
Меня интересует:

  • Как получить путь к используемой файлом (или папкой) иконке, и как быть если она в DLL или EXE.

  • Как получить файл иконки в его истинном (максимальном) размере (хотя если будет путь, то далее видимо - это).

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

52

Re: AHK: как узнать путь к иконке используемой файлом?

serzh82saratov пишет:

Как получить путь к используемой файлом (или папкой) иконке

Со всеми по-разному. Для отображения файлов с изображениями система берёт данные из них же (алгоритм знаю только для иконок), для exe — из их ресурсов, остальные имеют ассоциированные иконки, узнать можно из реестра:

MsgBox, % GetAssociatedIcon("ahk")

GetAssociatedIcon(ext)
{
   if (ext = "")
      RegRead, value, HKCR, Folder\DefaultIcon
   else
   {
      ext := "." . LTrim(ext, ".")
      RegRead, value, HKCR, %ext%
      RegRead, value, HKCR, %value%\DefaultIcon
   }
   Return value
}

Как получить файл иконки в его истинном (максимальном) размере (хотя если будет путь, то далее видимо - это).

Не очень понял вопрос. Представленный код извлекает иконки со всеми их размерами.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

53

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

Со всеми по-разному.

Вот по разному и не хочется. У тебя GetFileIcon всегда одинаково и правильно возвращает указатель на иконку.


GetFileIcon(sFile)
{
   sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
   VarSetCapacity(sfi, sfi_size)
   
   DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), Str, sFile
      , UInt, 0, Ptr, &sfi, UInt, sfi_size, UInt, 0x101)  ; SHGFI_ICON | SHGFI_SMALLICON = 0x101
   return NumGet(sfi, 0)   ; hIcon
}

Так может она сможет также возвращать и путь, ведь в SHGetFileInfo есть ещё и такая штука:

SHGFI_ICONLOCATION (0x000001000)

Retrieve the name of the file that contains the icon representing the file specified by pszPath, as returned by the IExtractIcon::GetIconLocation method of the file's icon handler. Also retrieve the icon index within that file. The name of the file containing the icon is copied to the szDisplayName member of the structure specified by psfi. The icon's index is copied to that structure's iIcon member.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

54

Re: AHK: как узнать путь к иконке используемой файлом?

Должно бы работать так:

FilePath := "C:\Windows\System32\shell32.dll"

SFI_SIZE := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
SHGFI_ICONLOCATION := 0x1000

VarSetCapacity(SHFILEINFO, SFI_SIZE, 0)
DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), Str, FilePath, UInt, 0
         , Ptr, &SHFILEINFO, UInt, SFI_SIZE, UInt, SHGFI_ICONLOCATION)
         
MsgBox, % StrGet(&SHFILEINFO + A_PtrSize + 8)

Но не работает. В сети информации не нашёл.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

55

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker
Это вроде работает:
http://www.autohotkey.com/board/topic/7 … icon-path/
Здесь:
http://www.autohotkey.com/board/topic/6 … ct-ahk-11/
Некая библиотека - <Class_DllStruct>
https://gist.githubusercontent.com/AHK- … Struct.ahk
Сможешь найти ошибку, и сократить код?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

56

Re: AHK: как узнать путь к иконке используемой файлом?

Поспешил, показывает не для всех файлов. Причём не понятно какие файлы не подходят.
Отсюда http://www.autohotkey.com/board/topic/7 … of-a-file/ код тоже не рабочий.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

57

Re: AHK: как узнать путь к иконке используемой файлом?

serzh82saratov пишет:

Поспешил, показывает не для всех файлов.

У меня вообще ни для каких не показывает, только для папок, как и мой код.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

58

Re: AHK: как узнать путь к иконке используемой файлом?

Да, правильно, это только для папок работает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

59

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

Должно бы работать так:

FilePath := "C:\Windows\System32\shell32.dll"

SFI_SIZE := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
SHGFI_ICONLOCATION := 0x1000

VarSetCapacity(SHFILEINFO, SFI_SIZE, 0)
DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), Str, FilePath, UInt, 0
         , Ptr, &SHFILEINFO, UInt, SFI_SIZE, UInt, SHGFI_ICONLOCATION)
         
MsgBox, % StrGet(&SHFILEINFO + A_PtrSize + 8)

Но не работает. В сети информации не нашёл.

Для ярлыков работает, но только если явно назначить ярлыку иконку.

60

Re: AHK: как узнать путь к иконке используемой файлом?

В нескольких местах ещё пишут, что можно через IExtractIcon. Сейчас пока времени нет, чтоб разобраться.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

61

Re: AHK: как узнать путь к иконке используемой файлом?

Попробовал, но какая-то хрень выходит:

obj := GetIconLocation(A_WinDir "\System32\notepad.exe")

MsgBox,, % A_WinDir "\System32\notepad.exe", % "IconPath = " . obj.IconPath
   . "`nindex = " . obj.index . "     `; странный индекс`nflags = " . obj.flags

obj := GetIconLocation(A_WinDir "\System32\shell32.dll")

MsgBox,, % A_WinDir "\System32\shell32.dll", % "IconPath = " . obj.IconPath
   . "    `; не показывает путь ко многим файлам`nindex = " . obj.index . "`nflags = " . obj.flags

GetIconLocation(sPath)
{
   DllCall("shell32\SHParseDisplayName", Str, sPath, Ptr, 0, PtrP, pidl, UInt, 0, UIntP, 0)
   DllCall("shell32\SHBindToParent", Ptr, pidl
         , Ptr, GUID4String(IID_IShellFolder,"{000214E6-0000-0000-C000-000000000046}"), PtrP, pIShellFolder, PtrP, pidlChild)

   ; IShellFolder -> GetUIObjectOf
   DllCall(VTable(pIShellFolder, 10), Ptr, pIShellFolder, Ptr, 0, UInt, 1, PtrP, pidlChild
         , Ptr, GUID4String(IID_IExtractIconW,"{000214FA-0000-0000-C000-000000000046}"), Ptr, 0, PtrP, pIExtractIconW)

   ObjRelease(pIShellFolder), CoTaskMemFree(pidl)

   MAX_PATH := 260
   VarSetCapacity(szIconFile, MAX_PATH * (A_IsUnicode ? 2 : 1))

   ; IExtractIcon -> GetIconLocation
   DllCall(VTable(pIExtractIconW, 3), Ptr, pIExtractIconW
         , UInt, GIL_FORSHELL := 0x2, Ptr, &szIconFile, UInt, MAX_PATH, IntP, iIndex, UIntP, wFlags)
         
   ObjRelease(pIExtractIconW)
   
   Return {IconPath: StrGet(&szIconFile), index: iIndex, flags: wFlags}
}

VTable(ppv, idx)
{
   Return   NumGet(NumGet(1*ppv)+A_PtrSize*idx)
}

GUID4String(ByRef CLSID, String)
{
   VarSetCapacity(CLSID, 16,0)
   return DllCall("ole32\CLSIDFromString", "wstr", String, Ptr, &CLSID) >= 0 ? &CLSID : ""
}

CoTaskMemFree(pv)
{
   Return   DllCall("ole32\CoTaskMemFree", Ptr, pv)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

62

Re: AHK: как узнать путь к иконке используемой файлом?

Alectric пишет:

Для этого нужно считать с реестра ассоциацию файла и определить "иконку по умолчанию" для этого файла, также из реестра.

FileExt=txt
RegRead,exts,HKCR,.%FileExt%,,
RegRead,ico,HKCR,%exts%\Defaulticon,,
msgbox,% ico

Для исполняемых файлов (exe например) этот скрипт не подойдет.
Некоторые файлы может отобразить как: "%SystemRoot%\system32\...", SystemRoot - это "C:\Windows".

Кстати, работает-то это очень странно: если вручную залезть в ту ветвь реестра, то там даже нет такой подветви, а код всё равно работает.
А вот для одной программы (sumatra pdf portable от portableapps.com) иконка почему-то не срабатывает.

63

Re: AHK: как узнать путь к иконке используемой файлом?

Drugoy пишет:

если вручную залезть в ту ветвь реестра, то там даже нет такой подветви, а код всё равно работает.

Мистика! Советую компьютер святой водой окропить!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

64 (изменено: Drugoy, 2014-11-04 20:38:22)

Re: AHK: как узнать путь к иконке используемой файлом?

Вовсе не мистика: видимо, в винде просто есть система fallback'ов: если в одном месте пусто, то использовать из другого места.
https://i.imgur.com/ZAWnxAd.png

65

Re: AHK: как узнать путь к иконке используемой файлом?

А о чём этот скриншот говорит?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

66 (изменено: Drugoy, 2014-11-04 20:38:00)

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

А о чём этот скриншот говорит?

Об отсутствии подраздела "Defaulticon" у раздела ".txt", и о том, что какая-то иконка при этом для .txt файла всё же используется.

67

Re: AHK: как узнать путь к иконке используемой файлом?

Раздел .txt ссылается на раздел txtfile. Там и DefaultIcon должна быть.

68

Re: AHK: как узнать путь к иконке используемой файлом?

Вы не разобрались, как работает код. Первая строка:

RegRead,exts,HKCR,.%FileExt%

Здесь считывается дефолтное значение ветки HKEY_CLASSES_ROOT\.txt. Его значение, как мы видим, txtfile, оно заносится в переменную exts.
Вторая строка:

RegRead,ico,HKCR,%exts%\Defaulticon

Здесь считывается, учитывая подстановку переменной exts, дефолтное значение ветки HKEY_CLASSES_ROOT\txtfile\DefaultIcon:

http://i.imgur.com/9Neoz2Q.jpg

Оно, как видно из скриншота, равно %SystemRoot%\system32\imageres.dll,-102

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

69

Re: AHK: как узнать путь к иконке используемой файлом?

Ок. Спасибо, и правда запутался. Но это не отменяет моего первого вопроса: почему у .pdf нет картинки?
Дефолтное значение у HKCR\.pdf = pdf_auto_file.
У HKCR\pdf_auto_file отсутствует подветка 'DefaultIcon', но при этом в проводнике-то .pdf файлы идут с иконкой от Sumatra PDF Portable.

70

Re: AHK: как узнать путь к иконке используемой файлом?

Ну а почему она там должна быть? Это ведь не виндосовский файл. Что в реестр записано при установке программы для их чтения, то и будет, я так думаю.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

71

Re: AHK: как узнать путь к иконке используемой файлом?

Куда записано? Откуда читать-то?

72

Re: AHK: как узнать путь к иконке используемой файлом?

Например, там есть команда открытия файла. Открывающая программа там ведь указана. Что мешает системе взять из неё иконку?

73

Re: AHK: как узнать путь к иконке используемой файлом?

Вопрос в том, как система определяет, из какого файла и с каким индексом иконку брать для ненативных для неё файлов. Если из какого файла — понятно, что из ассоциированного, то с каким индексом — неизвестно. Также неизвестно, какой конкретно механизм система использует для определения пути к иконке. Не факт, что это документировано.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

74

Re: AHK: как узнать путь к иконке используемой файлом?

Хотя, скорее всего, индекс записывается где-то при создании ассоциации для файла.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

75

Re: AHK: как узнать путь к иконке используемой файлом?

Может всё таки вопрос лежит в плоскости - Я, проводник, что мне делать при представлении файла в проводнике. В смысле, SHGetFileInfo это как то выдаёт... Или - проводник как решает что ему показать в своём SysListView32.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

76

Re: AHK: как узнать путь к иконке используемой файлом?

Так а я о чём?

teadrinker пишет:

Вопрос в том, как система определяет, из какого файла и с каким индексом иконку брать для ненативных для неё файлов.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

77

Re: AHK: как узнать путь к иконке используемой файлом?

Вот ведь мутняк.. А как же жить дальше? В полном непонимании как это сделано...

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

78

Re: AHK: как узнать путь к иконке используемой файлом?

Вот здесь описано, как это делает система.

1. Retrieves the class identifier of the handler.
2. Creates a handler object by calling the CoCreateInstance function with the CLSID.
3. Initializes the instance by calling the IPersistFile::Load member function.
4. Uses the QueryInterface member function to get to the IExtractIcon interface.
5. Calls the IExtractIcon::GetIconLocation and IExtractIcon::Extract member functions.

Вопрос упирается в то, где в общем случае брать этот самый "class identifier of the handler".

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

79

Re: AHK: как узнать путь к иконке используемой файлом?

И о чём думал создатель?

Кенни:
Видимо чтобы для нас это было непостижимо...

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

80

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

Вопрос упирается в то, где в общем случае брать этот самый "class identifier of the handler".

А что, он всегда есть, этот handler? По ссылке описано, как приложение может указать, какую иконку использовать. Но оно ведь не обязано это делать. Если handler есть, там сказано, где искать его класс.

81

Re: AHK: как узнать путь к иконке используемой файлом?

А этот код не прояснит ситуацию?
http://ahkscript.org/boards/viewtopic.p … amp;t=1004

82

Re: AHK: как узнать путь к иконке используемой файлом?

Не думаю.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

83

Re: AHK: как узнать путь к иконке используемой файлом?

Malcev пишет:

А этот код не прояснит ситуацию?
http://ahkscript.org/boards/viewtopic.p … amp;t=1004

А у вас он работает? У меня первый пример из темы выдаёт ошибку 'Error - %Size%, No icon found for path`r`n%Path%!' а второй показывает гуй с отсутствующими lv.

84

Re: AHK: как узнать путь к иконке используемой файлом?

Какой пример?
У меня так работает:

#NoEnv
SetBatchLines, -1
SHIL := {LARGE: 0x00, SMALL: 0x01, EXTRALARGE: 0x02, SYSSMALL: 0x03, JUMBO: 0x04}
SS_ICON := 0x03
STM_SETICON := 0x0170
Path := ".pdf"
For Size, Value In SHIL {
   If !IsObject(Icon := GetSysImgLstIcon(Path, Size)) {
      MsgBox, 16, Error - %Size%, No icon found for path`r`n%Path%!
      Continue
   }
   Gui, +LastFound
   Gui, Margin, 20, 20
   IW := Icon.W, IH := Icon.H
   Gui, Add, Text, xm, Path:`t%Path%`r`nSize;`t%Size%`r`nWidth:`t%IW%`r`nHeight:`t%IH%
   Gui, Add, Pic, w%IW% h%IH% +%SS_ICON% hwndHSTATIC
   SendMessage, %STM_SETICON%, % Icon.HICON, 0, , ahk_id %HSTATIC%
   Gui, Add, Button, Default gGuiClose, Exit
   Gui, Show, w296, ShellGetIcon
   WinWaitClose
}
ExitApp
GuiClose:
   Gui, Destroy
Return
GuiEscape:
ExitApp




GetSysImgLstIcon(Path, Size := "SYSSMALL", Overlay := "") {
   Static AW := A_IsUnicode ? "W" : "A"
   Static cbSFI := A_PtrSize + 8 + (340 << !!A_IsUnicode)
   Static FILE_ATTRIBUTE_NORMAL := 0x80
   Static IID_IIL_Str := "{46EB5926-582E-4017-9FDF-E8998DAA0950}"
   Static SHGFI := {SYSICONINDEX: 0x04000, USEFILEATTRIBUTES: 0x0010}
   Static SHGIOI := {SHARE: 0x0FFFFFFF, LINK: 0x0FFFFFFE, SLOWFILE: 0x0FFFFFFD, DEFAULT: 0x0FFFFFFC}
   Static SHIL := {LARGE: 0x00, SMALL: 0x01, EXTRALARGE: 0x02, SYSSMALL: 0x03, JUMBO: 0x04}
   If !SHIL.HasKey(Size)
      Return False
   VarSetCapacity(IID_IIL, 16, 0) ; IID
   If DllCall("Ole32.dll\IIDFromString", "WStr", IID_IIL_Str, "Ptr", &IID_IIL, "UInt")
      Return False
   HMOD := DllCall("Kernel32.dll\GetModuleHandle", "Str", "shell32.dll", "UPtr")
   FileIconInit := DllCall("Kernel32.dll\GetProcAddress", "Ptr", HMOD, "Ptr", 660, "UPtr")
   DllCall(FileIconInit, "UInt", True, "UInt")
   VarSetCapacity(SFI, cbSFI, 0) ; SHFILEINFO
   ; pure extensions need special handling
   Flags := SHGFI.SYSICONINDEX | (SubStr(Path, 1, 1) = "." ? SHGFI.USEFILEATTRIBUTES : 0x0)
   If !DllCall("Shell32.dll\SHGetFileInfo" . AW, "Str", Path, "UInt", 0x80, "Ptr", &SFI, "UInt", cbSFI, "UInt", Flags, "UPtr")
      Return False
   IconIndex := NumGet(SFI, A_PtrSize, "Int")
   If DllCall("Shell32.dll\SHGetImageList", "Int", SHIL[Size], "Ptr", &IID_IIL, "PtrP", IIL, "UInt")
      Return False
   Flags := 0x0020 ; ILD_IMAGE
   ; overlays need a special handling
   If SHGIOI.HasKey(Overlay)
   && (IOV := DllCall("Shell32.dll\SHGetIconOverlayIndex", "Ptr", 0, "UInt", SHGIOI[Overlay], "Int")) >= 0
      Flags |= IOV << 8
   DllCall("Comctl32.dll\ImageList_GetIconSize", "Ptr", IIL, "IntP", CX, "IntP", CY, "UInt")
   HICON := DllCall("Comctl32.dll\ImageList_GetIcon", "Ptr", IIL, "Int", IconIndex, "UInt", Flags, "UPtr")
   Return {HICON: HICON, W: CX, H: CY}
}

85

Re: AHK: как узнать путь к иконке используемой файлом?

У меня всё работает на x64. Конечно, пути к иконкам это не определяет, но даёт возможность получить иконки большого размера, если они есть в наличии.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

86

Re: AHK: как узнать путь к иконке используемой файлом?

Malcev пишет:

Какой пример?
У меня так работает:

Спасибо, так у меня тоже работает. Оказалось, что код скопировался как-то с потерями: все имена функций в dllcall'ах были слеплены вот так "Kernel32.dllGetModuleHandle", вместо "Kernel32.dll\GetModuleHandle".
Тогда, получается, что этим методом можно получать иконку.
Вот только разницы между SMALL и SYSSMALL я не понимаю: на вид они одинаковы.

87

Re: AHK: как узнать путь к иконке используемой файлом?

Ссылка с англоязычного форума на тему извлечения иконок:
IconEx v1.4b - Обозреватель / извлекатель иконок

88

Re: AHK: как узнать путь к иконке используемой файлом?

А на код ссылка есть?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

89

Re: AHK: как узнать путь к иконке используемой файлом?

teadrinker пишет:

А на код ссылка есть?

http://i.smiles2k.net/aiwan_smiles/no.gif

Есть сам код, еле нашёл здесь:

; IconEx v1.2b by SKAN ( arian.suresh@gmail.com )  ||   CD: 13-May-2008 |  LM: 27-Dec-2008
DllCall( "LoadLibrary", Str,"Shell32.dll")
#SingleInstance, Force
SetWorkingDir %A_ScriptDir% 
SetBatchLines, -1
Process, Priority,, High

SaveButton := 0x79 -1   ; ( VK code for F9 ) Note: modify -1 to -2 for F8 and so on...
KeyName := "F9"         ; depends on the VK code you use above
Deff    := A_ScriptDir  ; Default ICON save folder
CallB   := RegisterCallback( "EnumResNameProc" )
tFolder := A_WinDir "\SYSTEM32\SHELL32.DLL" ; default folder in address bar
IfExist, %A_Temp%\IconEx.tmp
 {
   FileRead, tFolder, %A_Temp%\IconEx.tmp
   FileDelete, %A_Temp%\IconEx.tmp   
 }
 
EnumResNameProc( hModule, lpszType, lpszName, lParam ) {
 Global IconGroups, IGCount
 IconGroups .= ( ( IconGroups!="" ) ? "|" : "" ) . lpszName , IGCount:=IGCount+1 
 Return True
}

Gui,Font, s10 Normal, Tahoma
; SHAutoComplete():  Sean - http://www.autohotkey.com/forum/viewtopic.php?p=121621#121621
; For constants : http://www.codeproject.com/KB/edit/autocomp.aspx
Gui, Add, Combobox, x7 y7 w550 h21 Choose1 -Theme hwndhSHAC vtFolder, %tFolder%
ControlGet, hMyEdit, hWnd,, Edit1, ahk_id %hSHAC%

DllCall( "ole32\CoInitialize", UInt,0 )
DllCall( "shlwapi\SHAutoComplete", UInt,hMyEdit, UInt,0x1|0x10000000 )
; DllCall( "ole32\CoUninitialize" ) ; In Vista: Crashes AHK On Exit
 
Gui,Font, s8 Normal, Tahoma
Gui, Add, Button, x+2 w33 h24 +Default gUpdateResourceList, &Go
Gui, Add, Button, x+2 w52 h24 gSelectFolder, &Browse
Gui, Add, ListView, x7 y+5 h280 w235 -Theme -E0x200 +0x4 +0x8 +Border vLVR gLVR 
                   +BackGroundFFFFFA c444466 AltSubmit, Resource File|Icons|IconGroup
LV_ModifyCol( 1 ,"170" ), LV_ModifyCol( 2, "42 Integer" ), LV_ModifyCol( 3, "0" )
Gui, Add, ListView, x+0 yp h280 w405 -Theme +Icon -E0x200 +0x100
                   +BackGroundFFFFFC cBB2222 Border AltSubmit vLVI gLVI hwndLVC2
Gui, Add, Hotkey, x2 y+79 w1 h1 +Disabled vHotkey gCreateSimpleIcon
Loop 8 {
   Ix += 1 
   Gui, Add, Text,x+10 yp-70 0x1203 w70 h70 vI%Ix% hWndIcon%Ix% gSelectSimpleIcon
   Gui, Add, Text, xp  yp+70 0x201  w70 h16 vIconT%Ix%, -
} 
Gui, Add, Text, x2 y+79 w1 h1
Loop 8 {
   Ix += 1 
   Gui, Add, Text,x+10 yp-70 0x1203 w70 h70 vI%Ix% hWndIcon%Ix% gSelectSimpleIcon
   Gui, Add, Text, xp  yp+70 0x201  w70 h16 vIconT%Ix%, -
} 

Gui, Add, Button, X7 y+30 gAccelerator, &File
Gui, Add, Button, x+5     gAccelerator, &Icon
Gui, Add, Button, x+5     gAccelerator, A&ddress Bar
Gui, Add, Button, x+5     gAccelerator, &Reload
Gui,Font
Gui, Add, StatusBar, vSB gFindTarget
SB_SetParts( 40,425 )
GoSub, UpdateResourceList
SB_SetText( "Type the path to a folder/file. Auto complete enabled", 2 )
Gui, Show, w655 h535 , IconEx - v1.0
Return                                                 ; // end of auto-execute section //

UpdateResourceList:
  SendInput, {Escape}
  ControlGetText,tFolder,, ahk_id %hSHAC%
  If ! InStr( FileExist( tFolder ), "D" ) 
    Folder := tFolder
  Else Folder := tFolder . "\*.*"
  GoSub, SetFolder
  Gui, ListView, LVI
  LV_Delete()
  Gui, ListView, LVR
  LV_Delete(), , SB_SetText( "  Loading files.. Please wait" , 2 ), FileCount := 0
  Loop, %Folder%  {
    If A_LoopFileExt Not in EXE,DLL,CPL,SCR
      Continue
    hModule := DllCall( "LoadLibraryEx", Str,A_LoopFileLongPath, UInt,0, UInt,0x2 )
    IfEqual,hModule,0,Continue
    IGCount:=0, IconGroups := ""
    DllCall("EnumResourceNamesA", UInt,hModule, UInt,14, UInt,CallB, UInt,0 )
    DllCall( "FreeLibrary", UInt,hModule )
    IfEqual,IGCount,0, Continue
    FileCount:=FileCount+1
    FileName := DllCall( "CharUpperA", Str,A_LoopFileName, Str )
    Gui, ListView, LVR
    LV_ADD( "", FileName, IGCount, IconGroups )
    SB_SetText( "`t" FileCount, 1 )
  }
  SB_SetText( "`t" FileCount, 1 ), SB_SetText( "  Done!" , 2 )
  GuiControl, Focus, LVR
  RowNo := 1
  GoSub, LVRSUB
  Gui, ListView, LVI
  LV_Modify( 1, "Select" )
  Gui, ListView, LVR
  GuiControl, Focus, LVR
  LV_Modify( 1, "Select" )
  GuiControl, Focus, tFolder
Return

LVR:
  If ( A_GuiEvent="k" and ( A_EventInfo=40 or A_EventInfo=38 ) ) {
       RowNo := LV_GetNext( 0, "Focused" )
       GoTo, LVRSUB
       Return
  }
 
  If ( A_GuiEvent="k" and A_EventInfo=SaveButton ) {
       RowNo := LV_GetNext( 0, "Focused" )
       IfNotEqual,RowNo,0, GoSub, ExtractIconRes
       Return
  }
  IfNotEqual, A_GuiEvent,Normal, Return
  RowNo := A_EventInfo
LVRSUB: 
  Gui, ListView, LVR
  LV_GetText( File, RowNo,1 ), LV_GetText( IGC, RowNo,2 ), LV_GetText( IG, RowNo,3 )
  SB_SetText( "Press <" KeyName "> to save all icons in " File , 2 ) 
  Gui, ListView, LVI
  LV_Delete()
  ImageListID ? IL_Destroy( ImageListID ) :
  ImageListID := IL_Create( 10,10,1 ), LV_SetImageList(ImageListID)
  Loop, %IGC%
        IL_Add(ImageListID, tFolder "\" File, A_Index )
  Loop, Parse, IG, |
       {
          Gui, ListView, LVI
          LV_Add("Icon" . A_Index, A_LoopField )
       }     
  RowNo := 1
  GoSub, LVISUB
  Gui, ListView, LVR
Return

LVI:
  Gui, ListView, LVI
  If ( A_GuiEvent="k" and ( A_EventInfo>=37 and A_EventInfo<=40 ) ) {
       RowNo := LV_GetNext( 0, "Focused" )
       LV_GetText( IconGroup, RowNo,1 ) 
       SB_SetText( "Press <" KeyName "> to save the Icon Group " IconGroup, 2 )
       GoTo, LVISUB
       Return
  }
  If ( A_GuiEvent="k" and A_EventInfo=SaveButton ) {
       RowNo := LV_GetNext( 0, "Focused" )
       IfNotEqual,RowNo,0,GoSub, ExtractIcon
       Return
  }

  If ( A_GuiEvent="k" and A_EventInfo=0x79 ) {
       GoSub, ApplyIconToFolder
       Return
  }
  IfNotEqual, A_GuiEvent,Normal, Return
  RowNo := A_EventInfo
  LV_GetText( IconGroup, RowNo,1 ) 
  SB_SetText( "Press <" KeyName "> to save the Icon Group " IconGroup, 2 )
LVISUB:
  Gui, ListView, LVI
  LV_GetText( IconGroup, RowNo,1 )
  hMod := DllCall( "LoadLibraryEx", Str,tFolder "\" File, UInt,0, UInt,0x2 )
  Buff := GetResource( hMod, IconGroup, (RT_GROUP_ICON:=14), nSize, hResData )
  Icos := NumGet( Buff+4, 0, "UShort" ), Buff:=Buff+6
  SB_SetText( "`t" Icos " Icons in < Group " IconGroup " >", 3 )
  Loop, %Icos% {
      W   := NumGet( Buff+0,0,"UChar" ),   H   := NumGet( Buff+0,1,"UChar" )
      BPP := NumGet( Buff+0,6,"UShort"),   nID := NumGet( Buff+0,12,"UShort")
      If ( W+H = 0 ) {
        SendMessage, ( STM_SETIMAGE:=0x172 ), 0x1, 0,, % "ahk_id " Icon%A_Index%       
        DllCall( "FreeResource", UInt,hResData )
        GuiControl,,IconT%A_Index%, - 
        Continue
      }
      Buff+=14
      IconD  := GetResource( hMod, nID, (RT_ICON:=3), nSize, hResData )
      Wi := ( W > 64 ) ? 64 : W , Hi := ( H > 64 ) ? 64 : H
      hIcon  := DllCall( "CreateIconFromResourceEx", UInt,IconD, UInt,BPP, Int,1
                        , UInt, 0x00030000, Int,Wi, Int,Hi, UInt,(LR_SHARED := 0x8000) )
      SendMessage, ( STM_SETIMAGE:=0x172 ), 0x1, 0,, % "ahk_id " Icon%A_Index%
      SendMessage, ( STM_SETIMAGE:=0x172 ), 0x1, hIcon,, % "ahk_id " Icon%A_Index%
      DllCall( "FreeResource", UInt,hResData )
      GuiControl,,IconT%A_Index%, % W "x" H "-" BPP "b" 
  }
  Loop % 16-Icos {
      Ix := Icos+A_Index
      GuiControl,,IconT%Ix%, -     
      SendMessage, ( STM_SETIMAGE:=0x172 ), 0x1, 0,, % "ahk_id " Icon%Ix%
  }
  DllCall( "FreeResource", UInt,hResData ), DllCall( "FreeLibrary", UInt,hModule )
Return

GetResource( hModule, rName, rType, ByRef nSize, ByRef hResData ) {
  hResource := DllCall( "FindResource", UInt,hModule, UInt,rName, UInt,rType )
  nSize     := DllCall( "SizeofResource", UInt,hModule, UInt,hResource )
  hResData  := DllCall( "LoadResource", UInt,hModule, UInt,hResource )
Return DllCall( "LockResource", UInt, hResData )
}

ExtractIconRes:
  FileSelectFolder, TargetFolder, *%DEFF%, 3, Extract Icons! Where to?
  IfEqual,TargetFolder,, Return
  GoSub, SetFolder
  hModule := DllCall( "LoadLibraryEx", Str,tFolder "\" File, UInt,0, UInt,0x2 )
  Loop, Parse, IG, |
    {
      FileN := SubStr( "000" A_Index, -3 ) "-" SubStr( "00000" A_LoopField, -4 ) ".ico"
      SB_SetText( (FileN := TargetFolder "\" FileN), 2 ), IconGroup := A_LoopField
      GoSub, WriteIcon
    }
  DllCall( "FreeLibrary", UInt,hModule ), SB_SetText( IGC " Icons extracted!", 2 )
  DllCall( "Sleep", UInt,1000 ), SB_SetText( TargetFolder, 2 )
Return

ExtractIcon:
  LV_GetText( IconGroup, RowNo,1 )
  FileN := SaveIcon( DEFF "\" File "-IG" SubStr( "-00000" IconGroup, -4 ) ".ico" )
  IfEqual,FileN,,Return   
  hModule := DllCall( "LoadLibraryEx", Str,tFolder "\" File, UInt,0, UInt,0x2 )
  GoSub, WriteIcon
  DllCall( "FreeLibrary", UInt,hModule ), SB_SetText( FileN, 2 )
Return

WriteIcon:
 hFile := DllCall( "_lcreat", Str,FileN, UInt,0 )
 sBuff := GetResource( hModule, IconGroup, (RT_GROUP_ICON:=14), nSize, hResData )
 Icons := NumGet( sBuff+0, 4, "UShort" )
 tSize := nSize+( Icons*2 ), VarSetCapacity( tmpBuff,tSize, 0 ), tBuff := &tmpBuff
 CopyData( sBuff, tBuff, 6  ),   sBuff:=sBuff+06,  tBuff:=tBuff+06
 Loop %Icons%
      CopyData( sBuff, tBuff, 14  ),  sBuff:=sBuff+14,  tBuff:=tBuff+16
 DllCall( "FreeResource", UInt,hResData )
 DllCall( "_lwrite", UInt,hFile, Str,tmpBuff, UInt,tSize )
 EOF := DllCall( "_llseek", UInt,hFile, UInt,-0, UInt,2 )
 VarSetCapacity( tmpBuff, 0 )
 DataOffset := DllCall( "_llseek", UInt,hFile, UInt,18, UInt,0 )

 Loop %Icons% {
      VarSetCapacity( Data,4,0 )
      DllCall( "_lread", UInt,hFile, Str,Data, UInt,2 ),
      nID := NumGet( Data, 0, "UShort" )
      DllCall( "_llseek", UInt,hFile, UInt,-2, UInt,1 )
      NumPut( EOF, Data ),  DllCall( "_lwrite", UInt,hFile, Str,Data, UInt,4 )
      DataOffset := DllCall( "_llseek", UInt,hFile, UInt,0, UInt,1 )
      sBuff := GetResource( hModule, nID, (RT_ICON:=3), nSize, hResData )   
      DllCall( "_llseek", UInt,hFile, UInt,0, UInt,2 )         
      DllCall( "_lwrite", UInt,hFile, UInt,sBuff, UInt,nSize )
      DllCall( "FreeResource", UInt,hResData )
      EOF := DllCall( "_llseek", UInt,hFile, UInt,-0, UInt,2 )
      DataOffset := DllCall( "_llseek", UInt,hFile, UInt,DataOffset+12, UInt,0 )
 } 
 DllCall( "_lclose", UInt,hFile )
Return

SelectSimpleIcon:
  StringTrimLeft,FNo,A_GuiControl,1
  GuiControlGet, IconT%fNo%
  If ( (IconT := IconT%fNo%) = "-" )
       Return
  SB_SetText("Press <" KeyName "> to save Icon " IconT  " from Icon Group " IconGroup ,2)
  GuiControl, Enable, Hotkey
  GuiControl, Focus,  Hotkey
  GuiControl,,Hotkey
  SetTimer, DisableHotkey, -5000
Return

DisableHotkey:
  GuiControlGet, Hotkey, Enabled
  If ( Hotkey ) {
  GuiControl,,Hotkey
  GuiControl, Disable, Hotkey
  GuiControl, Focus, LVI
  StatusBarGetText, SbTxt, 2, IconEx
  InStr( SbTxt, "to save Icon") ? SB_SetText( "", 2 ) :
  }   
Return 

CreateSimpleIcon:
  SB_SetText( "", 2 )
  GuiControlGet, Hotkey
  GuiControl, Disable, Hotkey
  IfNotEqual, Hotkey, %KeyName%, Return

  FileN := SaveIcon( Deff "\" File " [" SubStr("0000" IconGroup, -4 ) "-"
                    . SubStr( "0" FNo,-1) "][ " IconT "].ico" )           
  IfEqual,FileN,, Return     
  hModule := DllCall( "LoadLibraryEx", Str,tFolder "\" File, UInt,0, UInt,0x2 )
  Buffer := GetResource( hModule, IconGroup, (RT_GROUP_ICON:=14), nSize, hResData )
  tBuff := Buffer+6+((Fno-1)*14), nID := Numget( tBuff+0, 12, "Ushort" )
  VarSetCapacity(Z,10,0), NumPut(1,Z,2,"UChar"), NumPut(1,Z,4,"UChar" ),NumPut(22,Z,6)
  SBuff := GetResource( hModule, nID, (RT_ICON:=3), nSize, hResData )
  hFile := DllCall( "_lcreat", Str,FileN, UInt,0 )
  DllCall( "_lwrite", UInt,hFile, Str,Z, UInt,6 )
  DllCall( "_lwrite", UInt,hFile, UInt,tbuff, UInt,12 )
  DllCall( "_lwrite", UInt,hFile, UInt,&Z+6, UInt,4 )
  DllCall( "FreeResource", UInt,hResData )
  Buff := GetResource( hModule, nID, (RT_ICON:=3), nSize, hResData )
  DllCall( "_lwrite", UInt,hFile, UInt,Buff, UInt,nSize )
  DllCall( "_lclose", UInt,hFile )
  DllCall( "FreeResource", UInt,hResData ),  DllCall( "FreeLibrary", UInt,hModule )
  SB_SetText( FileN, 2 )
Return

FindTarget:
  StatusBarGetText, SB, 2, A
  IfExist, %SB%, Run, %COMSPEC% /c "Explorer /select`, %SB%",,Hide
Return

SetFolder:
  ControlGetText,tFolder,, ahk_id %hSHAC%
  If ! InStr( FileExist( tFolder ), "D" ) {
    SplitPath, tFolder,, tFolder
    ControlSetText,,% (tFolder:=DllCall("CharUpperA",Str,tFolder,Str )), ahk_id %hSHAC%
 }     
Return

SelectFolder:
  GoSub, SetFolder
  FileSelectFolder, nFolder, *%tFolder%, , Select a Resource Folder
  IfEqual,nFolder,,Return
  ControlSetText,,%nFolder%, ahk_id %hSHAC%
  GoSub, SetFolder
  GoSub, UpdateResourceList
Return

CopyData( SPtr, TPtr, nSize ) {
  Return DllCall( "RtlMoveMemory", UInt,TPtr, UInt,SPtr, UInt,nSize )
}

SaveIcon( Filename, Prompt="Save Icon As"  ) {
  FileSelectFile, File, 16, %Filename%, %Prompt%, Icon (*.ico)
Return ( File <> "" and SubStr( File, -3 ) <> ".ico" ) ? File ".ico" : File
}

Accelerator:
 IfEqual,A_GuiControl,&File, GuiControl,Focus,LVR
 IfEqual,A_GuiControl,&Icon, GuiControl,Focus,LVI
 IfEqual,A_GuiControl,A&ddress Bar, GuiControl,Focus,tFolder
 IfEqual,A_GuiControl,&Reload,IfExist,%tFolder%\%File%
    {
      FileAppend,%tFolder%\%File%,%A_Temp%\IconEx.tmp
      Reload     
    }
 
Return
 
GuiContextMenu:
  StatusBarGetText, SbTxt, 2, IconEx
  StringTrimLeft, SbTxt,SbTxt, 14
  If ( SubStr( SbTxt, 1,4) = "save" )
     SendInput {%KeyName%}
Return   

GuiClose:
  ExitApp
 
ApplyIconToFolder:
 FileSelectFolder, applyFolder,::{20d04fe0-3aea-1069-a2d8-08002b30309d},0, Apply Folder Icon
 If ( applyFolder="" OR ErrorLevel )
    Return
 dini := applyFolder "\Desktop.ini"
 IniRead, iconFile, %dini%, .ShellClassInfo, IconFile, %A_Space%
 If ( SubStr(iconFile,1,7 ) == "IconEx_" )
    FileDelete,%applyFolder%\%iconFile%
 iconFile := ( "IconEx_" HashStr( A_Now ) ".ico" ), FileN := applyFolder "\" iconFile
 hModule := DllCall( "LoadLibraryEx", Str,tFolder "\" File, UInt,0, UInt,0x2 )
 LV_GetText( IconGroup, RowNo,1 )
 GoSub, WriteIcon
 DllCall( "FreeLibrary", UInt,hModule ), SB_SetText( FileN, 2 )
 IniWrite, %IconFile%, %dini%, .ShellClassInfo, IconFile
 IniWrite, 0         , %dini%, .ShellClassInfo, IconIndex
 FileSetAttrib, +S, %applyFolder%
 FileSetAttrib, +SH, %dini%
 FileSetAttrib, +SH, %FileN%
 ; SHCNE_ASSOCCHANGED := 0x8000000
 DllCall( "Shell32\SHChangeNotify", UInt,0x8000000, UInt,0x0, UInt,0, UInt,0 )
 Run Properties "%applyFolder%"
Return

HashStr( sStr="" ) {
 Static hHash=12345678
 DllCall( "shlwapi\UrlHashA",  Str,sStr, UIntP,dHash, UInt,4 )
 DllCall( "msvcrt.dll\sprintf", Str,hHash, Str,"%08X", UInt,dHash )
 Return ( sStr<>"" ) ? hHash :
}

90

Re: AHK: как узнать путь к иконке используемой файлом?

Запускал?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

91

Re: AHK: как узнать путь к иконке используемой файлом?

Да.

92

Re: AHK: как узнать путь к иконке используемой файлом?

И?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

93

Re: AHK: как узнать путь к иконке используемой файлом?

Иконки отображаются, извлекаются.

94

Re: AHK: как узнать путь к иконке используемой файлом?

Только под 32-bit. Скорее всего, под AHK-basic написано.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

95

Re: AHK: как узнать путь к иконке используемой файлом?

У меня 32-bit, но версия 1.1.13.1 Unicode (XP SP3).

96

Re: AHK: как узнать путь к иконке используемой файлом?

SKAN пишет:
DllCall( "shlwapi\SHAutoComplete", UInt,hMyEdit, UInt,0x1|0x10000000 )

Здесь хэндл с типом "UInt", сработает только на 32-bit. На AHK_L это ошибка, принято писать "Ptr". То-есть, для практического использования подойдёт, а для примера кодинга — не очень.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder