argumentum Posted Monday at 02:35 PM Posted Monday at 02:35 PM (edited) expandcollapse popup#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 ). Edited 22 hours ago by argumentum better code WildByDesign and ioa747 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Monday at 03:48 PM Posted Monday at 03:48 PM Nice work! In one of my older projects, I used to call PowerShell commands from AutoIt and parse the results. So this is super helpful. argumentum 1
Solution MattyD Posted yesterday at 01:31 PM Solution Posted yesterday at 01:31 PM (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! expandcollapse popup#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 yesterday at 01:42 PM by MattyD argumentum 1
argumentum Posted 23 hours ago Author Posted 23 hours ago 1 hour ago, MattyD said: Good stuff Small nitpick That !, is exactly what I was looking for. I copy and paste until functional but, not necessarily "correct". Thanks for correcting the code MattyD 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now