Jump to content

Recommended Posts

Posted (edited)
#include <WinAPIMisc.au3>
#include <ApiErrorsConstants.au3>

Exit ConsoleWrite(@CRLF & _GetWindowsNotepadPath() & @CRLF & @CRLF)
Func _GetWindowsNotepadPath()
    Local $asPackageNames = _WinAPI_GetPackagesByPackageFamily("Microsoft.WindowsNotepad_8wekyb3d8bbwe")
    If @error Then Return SetError(1, 0, @WindowsDir & "\notepad.exe")
    Local $sPathByFullName = _WinAPI_GetPackagePathByFullName($asPackageNames[1])
    If @error Then Return SetError(2, 0, @WindowsDir & "\notepad.exe")
    Return $sPathByFullName & "\Notepad\notepad.exe"
EndFunc   ;==>_GetWindowsNotepadPath

Func _WinAPI_GetPackagesByPackageFamily($sFamilyName)
    Local $aCall = DllCall("kernel32.dll", "long", "GetPackagesByPackageFamily", "wstr", $sFamilyName, "uint*", 0, "ptr", 0, "uint*", 0, "ptr", 0)
    If @error Or ($aCall[0] <> $ERROR_INSUFFICIENT_BUFFER) Then Return SetError(1) ;Bad call or unexpected error
    Local $iCount = $aCall[2], $iBuffSize = $aCall[4]
    If (Not $iCount) Or (Not $iBuffSize) Then Return SetError(2) ;No retrievable data

    Local $tNameLocations = DllStructCreate("ptr Address[" & $iCount & "]")
    Local $tBuffer = DllStructCreate("wchar[" & $iBuffSize & "]")

    $aCall = DllCall("kernel32.dll", "long", "GetPackagesByPackageFamily", _
            "wstr", $sFamilyName, "uint*", $iCount, "struct*", $tNameLocations, "uint*", $iBuffSize, "struct*", $tBuffer)
    If @error Or $aCall[0] Then Return SetError(3) ;Bad Call of $aCall[0] <> ERROR_SUCCESS

    Local $asNames[$iCount + 1] = [$iCount], $tPackageName, $iNameLen, $pNameAddress
    For $i = 1 To $iCount
        $pNameAddress = $tNameLocations.Address(($i))
        $iNameLen = _WinAPI_StringLenW($pNameAddress)
        $tPackageName = DllStructCreate("wchar Name[" & $iNameLen & "]", $pNameAddress)
        $asNames[$i] = $tPackageName.Name
    Next

    Return $asNames
EndFunc   ;==>_WinAPI_GetPackagesByPackageFamily

Func _WinAPI_GetPackagePathByFullName($sPackageName)
    Local $aCall = DllCall("kernel32.dll", "long", "GetPackagePathByFullName", "wstr", $sPackageName, "uint*", 0, "ptr", 0)
    If @error Or ($aCall[0] <> $ERROR_INSUFFICIENT_BUFFER) Then Return SetError(1)
    Local $iBuffSize = $aCall[2]
    If Not $iBuffSize Then Return SetError(2) ;No retrievable data

    Local $tPath = DllStructCreate("wchar Path[" & $iBuffSize & "]")
    $aCall = DllCall("kernel32.dll", "long", "GetPackagePathByFullName", "wstr", $sPackageName, "uint*", $iBuffSize, "struct*", $tPath)
    If @error Or $aCall[0] Then Return SetError(3)

    Return $tPath.Path
EndFunc   ;==>_WinAPI_GetPackagePathByFullName

Maybe it should be 2 functions, one for GetPackagesByPackageFamily and one for GetPackagePathByFullName ?.
In any case, I don't see a reason to separate them. What would be the use
 🤔
Thanks to @MattyD we now have proper code :) 

With this you can get the path to: "Microsoft.WindowsNotepad_8wekyb3d8bbwe" or "Microsoft.WindowsTerminal_8wekyb3d8bbwe" or anything else from the windows store.

If you feel this should be different, say it. Am not a magician ( well, maybe flowers out of a stick but that's unrelated to the topic :P ).

 

Edited by argumentum
better code

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

  • Solution
Posted (edited)

Good stuff :)

Small nitpick - $tFullNames contains pointers within the allocated buffer.

23 hours ago, argumentum said:
    Local $sFullName = DllStructGetData(DllStructCreate("wchar[" & DllStructGetData($tBufferLen, 1) & "]", DllStructGetData($tFullNames, 1, 1)), 1)

Using the full buffer size here as your "size" param is only valid for the first name location DllStructGetData($tFullNames, 1, 1). (If you use this size on a second location, you'll be running past the end of the allocated buffer)

So, for the same effect you might as well just do this:

Local $sFullName = DllStructGetData($tBuffer, 1)

But to take things a step further -  we can use _WinAPI_StringLenW to separate out the strings because they're null-terminated .

Apologies if this example fails for some - I'm using "Microsoft.WindowsAppRuntime.1.8_8wekyb3d8bbwe" to test because I have both the x86 and x64 versions installed. I'm aware not everyone will have this package! 

#include <WinAPIMisc.au3>
#include <ApiErrorsConstants.au3>

Local $asPackageNames = _WinAPI_GetPackagesByPackageFamily("Microsoft.WindowsAppRuntime.1.8_8wekyb3d8bbwe")
If Not @error Then
    For $i =  1 To $asPackageNames[0]
        ConsoleWrite(_WinAPI_GetPackagePathByFullName($asPackageNames[$i]) & @CRLF)
    Next
EndIf

Func _WinAPI_GetPackagesByPackageFamily($sFamilyName)
    Local $aCall = DllCall("kernel32.dll", "long", "GetPackagesByPackageFamily", "wstr", $sFamilyName, "uint*", 0, "ptr", 0, "uint*", 0, "ptr", 0)
    If @error Or ($aCall[0] <> $ERROR_INSUFFICIENT_BUFFER) Then Return SetError(1) ;Bad call or unexpected error
    Local $iCount = $aCall[2], $iBuffSize = $aCall[4]
    If (Not $iCount) Or (Not $iBuffSize) Then Return SetError(2) ;No retrievable data

    Local $tNameLocations = DllStructCreate("ptr Address[" & $iCount & "]")
    Local $tBuffer = DllStructCreate("wchar[" & $iBuffSize & "]")

    $aCall = DllCall("kernel32.dll", "long", "GetPackagesByPackageFamily", _
            "wstr", $sFamilyName, "uint*", $iCount, "struct*", $tNameLocations, "uint*", $iBuffSize, "struct*", $tBuffer)
    If @error Or $aCall[0] Then Return SetError(3) ;Bad Call of $aCall[0] <> ERROR_SUCCESS

    Local $asNames[$iCount + 1] = [$iCount], $tPackageName, $iNameLen, $pNameAddress
    For $i = 1 To $iCount
        $pNameAddress = $tNameLocations.Address(($i))
        $iNameLen = _WinAPI_StringLenW($pNameAddress)
        $tPackageName = DllStructCreate("wchar Name[" & $iNameLen & "]", $pNameAddress)
        $asNames[$i] = $tPackageName.Name
    Next

    Return $asNames
EndFunc   ;==>_WinAPI_GetPackagesByPackageFamily


Func _WinAPI_GetPackagePathByFullName($sPackageName)
    Local $aCall = DllCall("kernel32.dll", "long", "GetPackagePathByFullName", "wstr", $sPackageName, "uint*", 0, "ptr", 0)
    If @error Or ($aCall[0] <> $ERROR_INSUFFICIENT_BUFFER) Then Return SetError(1)
    Local $iBuffSize = $aCall[2]
    If Not $iBuffSize Then Return SetError(2) ;No retrievable data

    Local $tPath = DllStructCreate("wchar Path[" & $iBuffSize & "]")
    $aCall = DllCall("kernel32.dll", "long", "GetPackagePathByFullName", "wstr", $sPackageName, "uint*", $iBuffSize, "struct*", $tPath)
    If @error Or $aCall[0] Then Return SetError(3)

    Return $tPath.Path
EndFunc
Edited by MattyD

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...