UEZ Posted July 4, 2023 Posted July 4, 2023 I'm trying to run a #.LNK file on my desktop as administrator. This is what I mixed together from several resources: expandcollapse popup#AutoIt3Wrapper_Version=p #include <GUIConstantsEx.au3> #include <WinAPICom.au3> #include <WinAPIConv.au3> #include <WinAPIShellEx.au3> Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc") Const $CLSCTX_INPROC_SERVER = 1, $STGM_READ = 0, $SLR_NOUPDATE = 8, $SLR_NO_UI = 1, $SLGP_UNCPRIORITY = 2, $MAX_PATH = 260, $SW_SHOWDEFAULT = 10 Const $sCLSID_ShellLink = "{00021401-0000-0000-C000-000000000046}", _ $sCLSID_IID_IShellLinkW = "{000214F9-0000-0000-C000-000000000046}", _ $sCLSID_IID_IPersistFile = "{0000010b-0000-0000-C000-000000000046}" Const $dtagIUnknown = "QueryInterface hresult(ptr;ptr*);AddRef dword();Release dword();", _ $tag_IPersist = "GetClassID hresult(long);", _ $tag_IPersistFile = $tag_IPersist & _ ; Inherits from IPersist "IsDirty hresult();" & _ "Load hresult(wstr;dword);" & _ "Save hresult(wstr;bool);" & _ "SaveCompleted hresult(long);" & _ "GetCurFile hresult(long);" Const $tagIShellLinkW = _ "GetPath hresult(wstr;int;ptr*;dword);" & _ "GetIDList hresult(ptr*);" & _ "SetIDList hresult(ptr);" & _ "GetDescription hresult(wstr;int);" & _ "SetDescription hresult(wstr);" & _ "GetWorkingDirectory hresult(wstr;int);" & _ "SetWorkingDirectory hresult(wstr);" & _ "GetArguments hresult(wstr;int);" & _ "SetArguments hresult(wstr);" & _ "GetHotkey hresult(word*);" & _ "SetHotkey hresult(word);" & _ "GetShowCmd hresult(int*);" & _ "SetShowCmd hresult(int);" & _ "GetIconLocation hresult(wstr;int;ptr*);" & _ "SetIconLocation hresult(wstr;int);" & _ "SetRelativePath hresult(wstr);" & _ "Resolve hresult(hwnd;dword);" & _ "SetPath hresult(wstr);" Func RunAsAdmin($sFilename) Local $sTargetPath = "" If StringRight($sFilename, 4) = ".lnk" Then Local $tCLSID_IID_IPersistFile = _WinAPI_GUIDFromString($sCLSID_IID_IPersistFile) Local $oShellLink = ObjCreateInterface($sCLSID_ShellLink, $sCLSID_IID_IShellLinkW, $tagIShellLinkW) If Not IsObj($oShellLink) Then ConsoleWrite("Error creating ShellLink object" & @CRLF) Return SetError(1, 0, False) EndIf Local $pIPersistFile = 0 $oShellLink.QueryInterface($tCLSID_IID_IPersistFile, $pIPersistFile) If $pIPersistFile = 0 Then ConsoleWrite("Error creating $pIPersistFile pointer" & @CRLF) Return SetError(2, 0, False) EndIf Local $oIPersistFile = ObjCreateInterface($pIPersistFile, $sCLSID_IID_IPersistFile, $tag_IPersistFile) If Not IsObj($oIPersistFile) Then ConsoleWrite("Error creating IPersistFile object" & @CRLF) Return SetError(2, 0, False) EndIf $oIPersistFile.Load($sFilename, $STGM_READ) $oShellLink.Resolve(Null, BitOR($SLR_NO_UI, $SLR_NOUPDATE)) $oShellLink.GetPath($sTargetPath, $MAX_PATH, Null, $SLGP_UNCPRIORITY) ;~ $oIPersistFile.Release() ;~ $oShellLink.Release() If $sTargetPath = "" Then Return SetError(3, 0, False) EndIf Else $sTargetPath = $sFilename EndIf Local $tSHELLEXECUTEINFO = DllStructCreate($tagSHELLEXECUTEINFO), $tFileBuff = DllStructCreate("wchar file[256]"), $tProperty = DllStructCreate("wchar verb[256]") DllStructSetData($tFileBuff, 1, $sTargetPath) DllStructSetData($tProperty, 1, "runas") With $tSHELLEXECUTEINFO ;https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa .Size = DllStructGetSize($tSHELLEXECUTEINFO) .Mask = BitOR($SEE_MASK_FLAG_DDEWAIT, $SEE_MASK_INVOKEIDLIST, $SEE_MASK_FLAG_LOG_USAGE) .File = $tFileBuff.file .Verb = $tProperty.verb .Show = $SW_SHOWDEFAULT EndWith If _WinAPI_ShellExecuteEx($tSHELLEXECUTEINFO) = 0 Or @error Then Return SetError(4, 0, False) Return True EndFunc Func _ErrFunc() ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF) EndFunc ;==>_ErrFunc ConsoleWrite(RunAsAdmin(@DesktopDir & "\CMD.lnk") & " / " & @error & @CRLF) Just create a shortcut on your desktop from C:\Windows\System32\cmd.exe and rename it to CMD. My problem is that the script works sometimes and sometime not, getting the em: "C:\...\test18.au3" (63) : ==> Error in expression.: $oShellLink.GetPath($sTargetPath, $MAX_PATH, Null, $SLGP_UNCPRIORITY) ^ ERROR This stuff is new to me and any help is appreciated. Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Andreik Posted July 4, 2023 Posted July 4, 2023 (edited) If it's not a requirement to use the code above, for LNK files it's enough to set bit 6 in byte 22. You can use the code below as an example. RunLNKAsAdmin(@ScriptDir & '\cmd.lnk') Func RunLNKAsAdmin($sPath, $bRestore = True) Local $hFile = FileOpen($sPath, 16) Local $dData = FileRead($hFile) FileClose($hFile) Local $dLinkFlags = Hex(BitOR(BinaryMid($dData, 22, 1), 0x20), 2) $hFile = FileOpen($sPath, 18) FileWrite($hFile, BinaryMid($dData, 1, 21) & $dLinkFlags & StringTrimLeft(BinaryMid($dData, 23), 2)) FileClose($hFile) ShellExecute($sPath) If $bRestore Then $hFile = FileOpen($sPath, 18) FileWrite($hFile, $dData) FileClose($hFile) EndIf EndFunc If you don't like that the LinkFlag has been changed in the original file, you already have the previous value so it's just another overwrite with initial value and the file it's back in its original state. Edited July 4, 2023 by Andreik Restore flag
UEZ Posted July 4, 2023 Author Posted July 4, 2023 Thanks @Andreik but the solution is a little too hacky. 😉 For learning purposes I want find the solution for the code in post#1. It seems that $oIPersistFile.Load($sFilename, $STGM_READ) isn't working as expected. Returns -2147024809 (0x80070057). Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Solution Andreik Posted July 4, 2023 Solution Posted July 4, 2023 (edited) I will investigate the code from first post but what about this less hacky way: ShellExecute(@DesktopDir & "\CMD.lnk", '', @DesktopDir, 'runas') Edit: well you were almost there, I edited just 3 lines (see the comments in code). expandcollapse popup#AutoIt3Wrapper_Version=p #include <GUIConstantsEx.au3> #include <WinAPICom.au3> #include <WinAPIConv.au3> #include <WinAPIShellEx.au3> Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc") Const $CLSCTX_INPROC_SERVER = 1, $STGM_READ = 0, $SLR_NOUPDATE = 8, $SLR_NO_UI = 1, $SLGP_UNCPRIORITY = 2, $MAX_PATH = 260, $SW_SHOWDEFAULT = 10 Const $sCLSID_ShellLink = "{00021401-0000-0000-C000-000000000046}", _ $sCLSID_IID_IShellLinkW = "{000214F9-0000-0000-C000-000000000046}", _ $sCLSID_IID_IPersistFile = "{0000010b-0000-0000-C000-000000000046}" Const $dtagIUnknown = "QueryInterface hresult(ptr;ptr*);AddRef dword();Release dword();", _ $tag_IPersist = "GetClassID hresult(long);", _ $tag_IPersistFile = $tag_IPersist & _ ; Inherits from IPersist "IsDirty hresult();" & _ "Load hresult(wstr;dword);" & _ "Save hresult(wstr;bool);" & _ "SaveCompleted hresult(long);" & _ "GetCurFile hresult(long);" Const $tagIShellLinkW = _ "GetPath hresult(wstr;int;ptr;dword);" & _ ; << ------- WIN32_FIND_DATAW should be ptr "GetIDList hresult(ptr*);" & _ "SetIDList hresult(ptr);" & _ "GetDescription hresult(wstr;int);" & _ "SetDescription hresult(wstr);" & _ "GetWorkingDirectory hresult(wstr;int);" & _ "SetWorkingDirectory hresult(wstr);" & _ "GetArguments hresult(wstr;int);" & _ "SetArguments hresult(wstr);" & _ "GetHotkey hresult(word*);" & _ "SetHotkey hresult(word);" & _ "GetShowCmd hresult(int*);" & _ "SetShowCmd hresult(int);" & _ "GetIconLocation hresult(wstr;int;ptr*);" & _ "SetIconLocation hresult(wstr;int);" & _ "SetRelativePath hresult(wstr);" & _ "Resolve hresult(hwnd;dword);" & _ "SetPath hresult(wstr);" Func RunAsAdmin($sFilename) Local $sTargetPath = "" If StringRight($sFilename, 4) = ".lnk" Then Local $tCLSID_IID_IPersistFile = _WinAPI_GUIDFromString($sCLSID_IID_IPersistFile) Local $oShellLink = ObjCreateInterface($sCLSID_ShellLink, $sCLSID_IID_IShellLinkW, $tagIShellLinkW) If Not IsObj($oShellLink) Then ConsoleWrite("Error creating ShellLink object" & @CRLF) Return SetError(1, 0, False) EndIf Local $pIPersistFile = 0 $oShellLink.QueryInterface($tCLSID_IID_IPersistFile, $pIPersistFile) If $pIPersistFile = 0 Then ConsoleWrite("Error creating $pIPersistFile pointer" & @CRLF) Return SetError(2, 0, False) EndIf Local $oIPersistFile = ObjCreateInterface($pIPersistFile, $sCLSID_IID_IPersistFile, $tag_IPersistFile) If Not IsObj($oIPersistFile) Then ConsoleWrite("Error creating IPersistFile object" & @CRLF) Return SetError(2, 0, False) EndIf $oIPersistFile.Load($sFilename, $STGM_READ) $oShellLink.Resolve(Null, BitOR($SLR_NO_UI, $SLR_NOUPDATE)) $oShellLink.GetPath($sTargetPath, $MAX_PATH, Null, $SLGP_UNCPRIORITY) ;~ $oIPersistFile.Release() ;~ $oShellLink.Release() If $sTargetPath = "" Then Return SetError(3, 0, False) EndIf Else $sTargetPath = $sFilename EndIf Local $tSHELLEXECUTEINFO = DllStructCreate($tagSHELLEXECUTEINFO), $tFileBuff = DllStructCreate("wchar file[256]"), $tProperty = DllStructCreate("wchar verb[256]") DllStructSetData($tFileBuff, 1, $sTargetPath) DllStructSetData($tProperty, 1, "runas") With $tSHELLEXECUTEINFO ;https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa .Size = DllStructGetSize($tSHELLEXECUTEINFO) .Mask = BitOR($SEE_MASK_FLAG_DDEWAIT, $SEE_MASK_INVOKEIDLIST, $SEE_MASK_FLAG_LOG_USAGE) .File = DllStructGetPtr($tFileBuff) ; << ----- here we need a pointer not the value .Verb = DllStructGetPtr($tProperty) ; << ----- here we need a pointer not the value .Show = $SW_SHOWDEFAULT EndWith If _WinAPI_ShellExecuteEx($tSHELLEXECUTEINFO) = 0 Or @error Then Return SetError(4, 0, False) Return True EndFunc Func _ErrFunc() ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF) EndFunc ;==>_ErrFunc ConsoleWrite(RunAsAdmin(@DesktopDir & "\CMD.lnk") & " / " & @error & @CRLF) Anyway, IMO it doesn't worth to write like 40 lines of code vs one line ShellExecute(), maybe just for educational purpose. Edited July 5, 2023 by Andreik UEZ 1
UEZ Posted July 5, 2023 Author Posted July 5, 2023 @Andreik thanks, seems to work properly. Quote Anyway, IMO it doesn't worth to write like 40 lines of code vs one line ShellExecute(), maybe just for educational purpose. For me using the Winapi object classes is new and I wanted to understand and learn it. Seems to be very powerful... Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Andreik Posted July 5, 2023 Posted July 5, 2023 Probably there are others things to be fixed in the script above, especially data types for some methods. For example $tag_IPersist = "GetClassID hresult(long);" Technically CLSID *pClassID it's not a long. Even if might work as long data type, ptr* it would be more appropriate in this case. I didn't go through all methods to check data types since you used just few of them.
UEZ Posted July 5, 2023 Author Posted July 5, 2023 To be honest, I did not research for it, used it from other resources (copy / paste 😋). I assumed that they are correct. Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
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