Get Windows UWP icons Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Get Windows UWP icons

23 Mar 2024, 16:12

Any ideas how could one get the 256px icon from UWP apps? Settings, Calculator, Store, etc.

I've been reading that SHLoadIndirectString could retrieve the icon. This script by @just me uses it to get the icon.

Can someone help me? Here's what I have so far:

Code: Select all

#Requires AutoHotkey v2.0
User32Path := A_WinDir "\System32\user32.dll"
pIconCount := 0

MyGui := Gui()
ProgramsLV := MyGui.Add("ListView", "+Icon w640 h640 r1", ["hWnd"])
; Create ImageList
pIL := DllCall("comctl32.dll\ImageList_Create", "int", 100, "int", 100, "uint", 0x20, "int", 10, "int", 10)
ProgramsLV.SetImageList(pIL)

AllWins := WinGetList()
for hWnd in AllWins
    {   IconImg := 0
        Path := WinGetProcessPath(hWnd)
        Name := WinGetTitle(hWnd)
        ; Get Icon
        DllCall("PrivateExtractIcons","str",Path,"int",0,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")
        if !(IconImg) ; If no Icon, get system one
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",5,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")

        DllCall("comctl32.dll\ImageList_ReplaceIcon", "uint", pIL, "int", -1, "uint", IconImg) 
        pIconCount += 1
        ProgramsLV.Add("Icon" pIconCount, Name)
    }
    MyGui.Show()

#s::Reload
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons  Topic is solved

24 Mar 2024, 23:25

a_bolog wrote:
23 Mar 2024, 16:12
Any ideas how could one get the 256px icon from UWP apps? Settings, Calculator, Store, etc.
You can't - by design. Windows 10 apps don't have their icons stored as a resource in their executable. Their icons reside in resource files that make up the package for the app. For example, Calculator has an image file by the name "CalculatorStoreLogo.scale-200.png" in its directory. It's a 100x100 image. You can use the function below to get the path of the largest "Logo" file in the package directory and convert it into an icon using the LoadPicture function.

Code: Select all

GetLargestUWPLogoPath(hwnd) {
   Address := CallbackCreate(EnumChildProc.Bind(WinGetPID(hwnd)), 'Fast', 2)
   DllCall('User32.dll\EnumChildWindows', 'Ptr', hwnd, 'Ptr', Address, 'UInt*', &ChildPID := 0, 'Int'), CallbackFree(Address)
   return ChildPID && AppHasPackage(ChildPID) ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : ''
   
   EnumChildProc(PID, hwnd, lParam) {
      ChildPID := WinGetPID(hwnd)
      if ChildPID != PID {
         NumPut 'UInt', ChildPID, lParam
         return false
      }
      return true
   }
   
   AppHasPackage(ChildPID) {
      static PROCESS_QUERY_LIMITED_INFORMATION := 0x1000, APPMODEL_ERROR_NO_PACKAGE := 15700
      ProcessHandle := DllCall('Kernel32.dll\OpenProcess', 'UInt', PROCESS_QUERY_LIMITED_INFORMATION, 'Int', false, 'UInt', ChildPID, 'Ptr')
      IsUWP := DllCall('Kernel32.dll\GetPackageId', 'Ptr', ProcessHandle, 'UInt*', &BufferLength := 0, 'Ptr', 0, 'Int') != APPMODEL_ERROR_NO_PACKAGE
      DllCall('Kernel32.dll\CloseHandle', 'Ptr', ProcessHandle, 'Int')
      return IsUWP
   }
   
   GetDefaultLogoPath(Path) {
      SplitPath Path, , &Dir
      if !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
         throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
      return Dir '\' Match[1]
   }
   
   GetLargestLogoPath(Path) {
      LoopFileSize := 0
      SplitPath Path, , &Dir, &Extension, &NameNoExt
      Loop Files Dir '\' NameNoExt '.scale-*.' Extension
         if A_LoopFileSize > LoopFileSize && RegExMatch(A_LoopFileName, '\d+\.' Extension '$')  ; Avoid contrast files.
            LoopFilePath := A_LoopFilePath, LoopFileSize := A_LoopFileSize
      return LoopFilePath
   }
}
Thus, your code would become

Code: Select all

if (Path := GetLargestUWPLogoPath(hwnd))
   hIcon := LoadPicture(Path, 'Icon1', &IMAGE_ICON)
I hope this helps.
Last edited by iPhilip on 28 Mar 2024, 10:41, edited 2 times in total.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

25 Mar 2024, 00:36

I've just tried it and it's able to get the icon only for the Settings App for some reason?
image.png
image.png (15.99 KiB) Viewed 429 times

Code: Select all

#Requires AutoHotkey v2.0
User32Path := A_WinDir "\System32\imageres.dll"
pIconCount := 0

MyGui := Gui()
ProgramsLV := MyGui.Add("ListView", "+Icon w1640 h600 r1", ["hWnd"])
; Create ImageList
pIL := DllCall("comctl32.dll\ImageList_Create", "int", 256, "int", 256, "uint", 0x20, "int", 10, "int", 10)
ProgramsLV.SetImageList(pIL)

AllWins := WinGetList()
for hWnd in AllWins
    {   IconImg := 0
        Path := WinGetProcessPath(hWnd)
        Name := WinGetTitle(hWnd)
        ; Get Icon
        DllCall("PrivateExtractIcons","str",Path,"int",0,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")
        if !(IconImg) ; If no Icon, get UWP
        IconImg := LoadPicture(GetLargestUWPLogoPath(hWnd), 'Icon1', &IconImg)

        if !(IconImg) ; If no Icon, get system one
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",11,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")

        DllCall("comctl32.dll\ImageList_ReplaceIcon", "uint", pIL, "int", -1, "uint", IconImg) 
        pIconCount += 1
        ProgramsLV.Add("Icon" pIconCount, Name)
    }
    MyGui.Show()
GetLargestUWPLogoPath(hwnd, Default?) {
   Address := CallbackCreate(EnumChildProc.Bind(WinGetPID(hwnd)), 'Fast', 2)
   DllCall('User32.dll\EnumChildWindows', 'Ptr', hwnd, 'Ptr', Address, 'Ptr*', &ChildPID := 0, 'Int'), CallbackFree(Address)
   return ChildPID ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : Default ?? A_AhkPath
   
   EnumChildProc(PID, hwnd, lParam) {
      ChildPID := WinGetPID(hwnd)
      if ChildPID != PID {
         NumPut 'UInt', ChildPID, lParam
         return false
      }
      return true
   }
   
   GetDefaultLogoPath(Path) {
      SplitPath Path, , &Dir
      if !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
         throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
      return Dir '\' Match[1]
   }
   
   GetLargestLogoPath(Path) {
      Size := 0
      LoopFilePath := 0
      SplitPath Path, , &Dir, &Extension, &NameNoExt
      Loop Files Dir '\' NameNoExt '.scale-*.' Extension
         if A_LoopFileSize > Size && RegExMatch(A_LoopFileName, '\d+\.' Extension '$')  ; Avoid contrast files.
            LoopFilePath := A_LoopFilePath, Size := A_LoopFileSize
      return LoopFilePath
   }
}

#s::Reload
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

25 Mar 2024, 01:21

What you posted works for me. See the screenshot below.
Screenshot 2024-03-24 232018.png
Screenshot 2024-03-24 232018.png (164.71 KiB) Viewed 422 times
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

26 Mar 2024, 22:25

I updated the apps and it works now.
Many thanks for the help you the best
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

27 Mar 2024, 09:04

You are welcome. :)
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 01:49

@iPhilip What would be a good way to identify if the app is UWP?
To apply the code only to UWP apps

Code: Select all

if (UWPApp) 
   IconImg := LoadPicture(GetLargestUWPLogoPath(hWnd), 'Icon1', &IMAGE_ICON)
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 01:55

a_bolog wrote:
28 Mar 2024, 01:49
@iPhilip What would be a good way to identify if the app is UWP?
This conditional statement should work.

Code: Select all

if WinGetClass(hWnd) = 'ApplicationFrameWindow'
   IconImg := LoadPicture(GetLargestUWPLogoPath(hWnd), 'Icon1', &IMAGE_ICON)
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 03:14

I've tried that but apparently not all UWP are ApplicationFrameWindow.
Apps like Facebook Messenger, NVidia Control Panel, and other UWPs don't have this class.
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 10:46

Thank you for reporting the additional testing. I updated the above post to include a AppHasPackage function to check if the window is UWP.

Let me know if this works for you.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 11:17

Hmm it doesn't work it says it cant read the file.
Error: (2) The system cannot find the file specified.

056: {
057: SplitPath(Path, , &Dir)
▶ 058: If !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
059: Throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
060: Return Dir '\' Match[1]
I think this if (Path := GetLargestUWPLogoPath(hwnd)) is wrong

Code: Select all

#Requires AutoHotkey v2.0
User32Path := A_WinDir "\System32\imageres.dll"
pIconCount := 0

MyGui := Gui()
ProgramsLV := MyGui.Add("ListView", "+Icon w1640 h600 r1", ["hWnd"])
; Create ImageList
pIL := DllCall("comctl32.dll\ImageList_Create", "int", 256, "int", 256, "uint", 0x20, "int", 10, "int", 10)
ProgramsLV.SetImageList(pIL)

AllWins := WinGetList()
for hWnd in AllWins
    {   IconImg := 0
        Path := WinGetProcessPath(hWnd)
        Name := WinGetTitle(hWnd)

        ; Get Icon
        if (Path := GetLargestUWPLogoPath(hwnd)) ; if UWP
            IconImg := LoadPicture(Path, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
         else ; Get Normal Icon
            DllCall("PrivateExtractIcons","str",Path,"int",0,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")


        if !(IconImg) ; If no Icon, get system one
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",11,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")

        DllCall("comctl32.dll\ImageList_ReplaceIcon", "uint", pIL, "int", -1, "uint", IconImg) 
        pIconCount += 1
        ProgramsLV.Add("Icon" pIconCount, Name)
    }
    MyGui.Show()

    
GetLargestUWPLogoPath(hwnd, Default?) {
   Address := CallbackCreate(EnumChildProc.Bind(WinGetPID(hwnd)), 'Fast', 2)
   DllCall('User32.dll\EnumChildWindows', 'Ptr', hwnd, 'Ptr', Address, 'Ptr*', &ChildPID := 0, 'Int'), CallbackFree(Address)
   return ChildPID ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : Default ?? A_AhkPath
   
   EnumChildProc(PID, hwnd, lParam) {
      ChildPID := WinGetPID(hwnd)
      if ChildPID != PID {
         NumPut 'UInt', ChildPID, lParam
         return false
      }
      return true
   }

   AppHasPackage(ChildPID) {
      static PROCESS_QUERY_LIMITED_INFORMATION := 0x1000, APPMODEL_ERROR_NO_PACKAGE := 15700
      ProcessHandle := DllCall('Kernel32.dll\OpenProcess', 'UInt', PROCESS_QUERY_LIMITED_INFORMATION, 'Int', false, 'UInt', ChildPID, 'Ptr')
      IsUWP := DllCall('Kernel32.dll\GetPackageId', 'Ptr', ProcessHandle, 'UInt*', &BufferLength := 0, 'Ptr', 0, 'Int') != APPMODEL_ERROR_NO_PACKAGE
      DllCall('Kernel32.dll\CloseHandle', 'Ptr', ProcessHandle, 'Int')
      return IsUWP
   }
   
   GetDefaultLogoPath(Path) {
      SplitPath Path, , &Dir
      if !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
         throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
      return Dir '\' Match[1]
   }
   
   GetLargestLogoPath(Path) {
      Size := 0
      LoopFilePath := 0
      SplitPath Path, , &Dir, &Extension, &NameNoExt
      Loop Files Dir '\' NameNoExt '.scale-*.' Extension
         if A_LoopFileSize > Size && RegExMatch(A_LoopFileName, '\d+\.' Extension '$')  ; Avoid contrast files.
            LoopFilePath := A_LoopFilePath, Size := A_LoopFileSize
      return LoopFilePath
   }
}

#s::Reload
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 11:32

a_bolog wrote:
28 Mar 2024, 11:17
Hmm it doesn't work it says it cant read the file.
Error: (2) The system cannot find the file specified.

056: {
057: SplitPath(Path, , &Dir)
▶ 058: If !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
059: Throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
060: Return Dir '\' Match[1]
Please copy the entire function as in the updated post. You are missing some code. Specifically,

Code: Select all

return ChildPID ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : Default ?? A_AhkPath
should be

Code: Select all

return ChildPID && AppHasPackage(ChildPID) ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : ''

P.S.: Note that your Path variable is being overwritten by if (Path := GetLargestUWPLogoPath(hwnd)) ; if UWP. I don't think that's what you intended to do.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 12:07

My bad, I now copied it all, but now it shows icons only to same "ApplicationFrameWindow" apps. Messenger and Nvidia Control Panel don't get icons... hmm
image.png
image.png (45.78 KiB) Viewed 305 times

Code: Select all

#Requires AutoHotkey v2.0
User32Path := A_WinDir "\System32\imageres.dll"
pIconCount := 0

MyGui := Gui()
ProgramsLV := MyGui.Add("ListView", "+Icon w1640 h600 r1", ["hWnd"])
; Create ImageList
pIL := DllCall("comctl32.dll\ImageList_Create", "int", 256, "int", 256, "uint", 0x20, "int", 10, "int", 10)
ProgramsLV.SetImageList(pIL)

AllWins := WinGetList()
for hWnd in AllWins
    {   IconImg := 0
        Path := WinGetProcessPath(hWnd)
        Name := WinGetTitle(hWnd)

        ; Get Icon
        if (Path := GetLargestUWPLogoPath(hwnd)) ; if UWP
            IconImg := LoadPicture(Path, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
         else ; Get Normal Icon
            DllCall("PrivateExtractIcons","str",Path,"int",0,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")


        if !(IconImg) ; If no Icon, get system one
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",11,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")

        DllCall("comctl32.dll\ImageList_ReplaceIcon", "uint", pIL, "int", -1, "uint", IconImg) 
        pIconCount += 1
        ProgramsLV.Add("Icon" pIconCount, Name)
    }
    MyGui.Show()

    
GetLargestUWPLogoPath(hwnd, Default?) {
   Address := CallbackCreate(EnumChildProc.Bind(WinGetPID(hwnd)), 'Fast', 2)
   DllCall('User32.dll\EnumChildWindows', 'Ptr', hwnd, 'Ptr', Address, 'Ptr*', &ChildPID := 0, 'Int'), CallbackFree(Address)
   return ChildPID && AppHasPackage(ChildPID) ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : ''
   
   EnumChildProc(PID, hwnd, lParam) {
      ChildPID := WinGetPID(hwnd)
      if ChildPID != PID {
         NumPut 'UInt', ChildPID, lParam
         return false
      }
      return true
   }

   AppHasPackage(ChildPID) {
      static PROCESS_QUERY_LIMITED_INFORMATION := 0x1000, APPMODEL_ERROR_NO_PACKAGE := 15700
      ProcessHandle := DllCall('Kernel32.dll\OpenProcess', 'UInt', PROCESS_QUERY_LIMITED_INFORMATION, 'Int', false, 'UInt', ChildPID, 'Ptr')
      IsUWP := DllCall('Kernel32.dll\GetPackageId', 'Ptr', ProcessHandle, 'UInt*', &BufferLength := 0, 'Ptr', 0, 'Int') != APPMODEL_ERROR_NO_PACKAGE
      DllCall('Kernel32.dll\CloseHandle', 'Ptr', ProcessHandle, 'Int')
      return IsUWP
   }
   
   GetDefaultLogoPath(Path) {
      SplitPath Path, , &Dir
      if !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
         throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
      return Dir '\' Match[1]
   }
   
   GetLargestLogoPath(Path) {
      Size := 0
      LoopFilePath := 0
      SplitPath Path, , &Dir, &Extension, &NameNoExt
      Loop Files Dir '\' NameNoExt '.scale-*.' Extension
         if A_LoopFileSize > Size && RegExMatch(A_LoopFileName, '\d+\.' Extension '$')  ; Avoid contrast files.
            LoopFilePath := A_LoopFilePath, Size := A_LoopFileSize
      return LoopFilePath
   }
}

#s::Reload
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 12:11

See my P.S. above.

Changing

Code: Select all

if (Path := GetLargestUWPLogoPath(hwnd)) ; if UWP
   IconImg := LoadPicture(Path, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
to

Code: Select all

if (LogoPath := GetLargestUWPLogoPath(hwnd)) ; if UWP
   IconImg := LoadPicture(LogoPath, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
should fix it.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 12:19

Yes, what I mean is that the apps which are considered UWP by the AppHasPackage() function are the exact same ones as if WinClass(ApplicationFrameWindow).

Apps like "Facebook Messenger" and "NVIDIA Control Panel" don't get filtered through. You can test with Messenger app, install from store no login.
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 13:10

Can you post your latest code?
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 13:17

I've simplified it for testing, if UWP get uwp icon if not, get backup icon to see exactly what is considered UWP and not.

Code: Select all

#Requires AutoHotkey v2.0
User32Path := A_WinDir "\System32\imageres.dll"
pIconCount := 0

MyGui := Gui()
ProgramsLV := MyGui.Add("ListView", "+Icon w1640 h600 r1", ["hWnd"])
; Create ImageList
pIL := DllCall("comctl32.dll\ImageList_Create", "int", 256, "int", 256, "uint", 0x20, "int", 10, "int", 10)
ProgramsLV.SetImageList(pIL)

AllWins := WinGetList()
for hWnd in AllWins
    {   IconImg := 0
        Path := WinGetProcessPath(hWnd)
        Name := WinGetTitle(hWnd)

        ; Get Icon
        if (LogoPath := GetLargestUWPLogoPath(hwnd)) ; if UWP
            IconImg := LoadPicture(LogoPath, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
         else ; Get System Icon (just for testing)  
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",11,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")

        DllCall("comctl32.dll\ImageList_ReplaceIcon", "uint", pIL, "int", -1, "uint", IconImg) 
        pIconCount += 1
        ProgramsLV.Add("Icon" pIconCount, Name)
    }
    MyGui.Show()

    
GetLargestUWPLogoPath(hwnd, Default?) {
   Address := CallbackCreate(EnumChildProc.Bind(WinGetPID(hwnd)), 'Fast', 2)
   DllCall('User32.dll\EnumChildWindows', 'Ptr', hwnd, 'Ptr', Address, 'Ptr*', &ChildPID := 0, 'Int'), CallbackFree(Address)
   return ChildPID && AppHasPackage(ChildPID) ? GetLargestLogoPath(GetDefaultLogoPath(ProcessGetPath(ChildPID))) : ''
   
   EnumChildProc(PID, hwnd, lParam) {
      ChildPID := WinGetPID(hwnd)
      if ChildPID != PID {
         NumPut 'UInt', ChildPID, lParam
         return false
      }
      return true
   }

   AppHasPackage(ChildPID) {
      static PROCESS_QUERY_LIMITED_INFORMATION := 0x1000, APPMODEL_ERROR_NO_PACKAGE := 15700
      ProcessHandle := DllCall('Kernel32.dll\OpenProcess', 'UInt', PROCESS_QUERY_LIMITED_INFORMATION, 'Int', false, 'UInt', ChildPID, 'Ptr')
      IsUWP := DllCall('Kernel32.dll\GetPackageId', 'Ptr', ProcessHandle, 'UInt*', &BufferLength := 0, 'Ptr', 0, 'Int') != APPMODEL_ERROR_NO_PACKAGE
      DllCall('Kernel32.dll\CloseHandle', 'Ptr', ProcessHandle, 'Int')
      return IsUWP
   }
   
   GetDefaultLogoPath(Path) {
      SplitPath Path, , &Dir
      if !RegExMatch(FileRead(Dir '\AppxManifest.xml', 'UTF-8'), '<Logo>(.*)</Logo>', &Match)
         throw Error('Unable to read logo information from file.', -1, Dir '\AppxManifest.xml')
      return Dir '\' Match[1]
   }
   
   GetLargestLogoPath(Path) {
      Size := 0
      LoopFilePath := 0
      SplitPath Path, , &Dir, &Extension, &NameNoExt
      Loop Files Dir '\' NameNoExt '.scale-*.' Extension
         if A_LoopFileSize > Size && RegExMatch(A_LoopFileName, '\d+\.' Extension '$')  ; Avoid contrast files.
            LoopFilePath := A_LoopFilePath, Size := A_LoopFileSize
      return LoopFilePath
   }
}

#s::Reload
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 13:46

Thank you. There are a couple of issues you might want to look into:

1. The "Get Icon" logic doesn't seem right to me. In my opinion, this code

Code: Select all

        ; Get Icon
        if (LogoPath := GetLargestUWPLogoPath(hwnd)) ; if UWP
            IconImg := LoadPicture(LogoPath, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
         else ; Get System Icon (just for testing)  
        DllCall("PrivateExtractIcons" ,"str",User32Path,"int",11,"int",256,"int",256 ,"uint*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")
should be (note the change from 11 to 0 and uint to ptr for the IconImg parameter in the PrivateExtractIcons function)

Code: Select all

        ; Get Icon
        if (LogoPath := GetLargestUWPLogoPath(hwnd)) ; if UWP
            IconImg := LoadPicture(LogoPath, 'Icon1', &IMAGE_ICON) ; Get UWP Icon
         else ; Get App Icon
         {
            DllCall("PrivateExtractIcons" ,"str",Path,"int",0,"int",256,"int",256 ,"ptr*",&IconImg := 0,"uint*",0,"uint",1,"uint",0,"int")
            if !IconImg ; Get System Icon
               DllCall("PrivateExtractIcons" ,"str",User32Path,"int",0,"int",256,"int",256 ,"ptr*",&IconImg,"uint*",0,"uint",1,"uint",0,"int")
         }
2. The Default parameter in the GetLargestUWPLogoPath function is not being used and can be removed.

With the above changes, can you post your updated code and the resulting image showing the problem with the "Facebook Messenger" or the "NVidia Control Panel" apps?

Thank you.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
a_bolog
Posts: 31
Joined: 18 Apr 2022, 12:00

Re: Get Windows UWP icons

28 Mar 2024, 20:10

The "11" from PrivateExtract is to give me the 11th icon from the dll which looks like a blank window.

But the problem is not getting the icon, is the checking if an app is UWP or not. Because the AppHasPackage() function you provided doesn't recognize some apps as being UWP, namely Facebook Messenger and others.

Check to see if an app is UWP (not solved)
If yes -> LoadPicture (solved)
If not -> PrivateExtractIcons (solved)
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: Get Windows UWP icons

28 Mar 2024, 22:18

Thank you for your sticking with me on this. I don't have a way to test Facebook Messenger and the other apps you mentioned because of security restrictions on my laptop.
The AppHasPackage function was my best educated guess of how to check if an app is UWP or not. This guess was informed by this stackoverflow post and this Micosoft blog.
It's possible that using the GetPackageFullName WinAPI function would give you more accurate results than the GetPackageId function I used. Feel free to test that. I am curious what you learn.
It's also possible that there is something else going on with the other apps.

Good luck with your exploration.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: No registered users and 10 guests