Jump to content

Recommended Posts

Posted

I'm trying to run a #.LNK file on my desktop as administrator.

This is what I mixed together from several resources:

#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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (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 by Andreik
Restore flag
Posted

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
Posted (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).

#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 by Andreik
Posted

@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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted

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.

Posted

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

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...