Jump to content

UDF _StartRun()


lod3n
 Share

Recommended Posts

Sometimes, you just want to be able to run arbitrary commands, without worrying about which function you use to execute them.

Try Run("http://www.google.com"). Sorry, you have to use ShellExecute for that.

Try ShellExecute("winword c:\windows\win.ini"). Sorry, you have to use Run for that.

Bah! Windows lets you run either of these in the Run dialog, found under the Start Menu. So why can't we? It appears that Windows accomplishes this by cheating: It actually tries both methods! [Correction: No it doesn't!] So, that's easy enough...

; Example usages:

$cmd = "this will not work"
$result = _StartRun($cmd)
If $result <> 1 Then MsgBox(16,"_StartRun Error:",$cmd & @CRLF & @CRLF & $result)

$cmd = "http://www.google.com"
$result = _StartRun($cmd)
If $result <> 1 Then MsgBox(16,"_StartRun Error:",$cmd & @CRLF & @CRLF & $result)

$cmd = "notepad c:\windows\win.ini"
$result = _StartRun($cmd)
If $result <> 1 Then MsgBox(16,"_StartRun Error:",$cmd & @CRLF & @CRLF & $result)


; #FUNCTION  _StartRun # ========================================
; Description ...: Tries to execute command with Run, and then ShellExec. Not the same as Start/Run, but similar effect
; Parameters ....: $sCmd        - The command string to execute with parameters, as you might type into the real Start/Run
;                  $sFolder     - The default folder to run in, defaults to @DesktopDir to match the real Start/Run
;                  $rState      - The application visiblity flag, defaults to @SW_SHOWNORMAL - not sure if Start/Run does the same
; Return values .: Success      - Bool, 1 = success, 0 = failure
; Author(s) .....: lod3n, SlimShady
; Remarks .......: 
; Related .......: Run, ShellExec, and SlimShady's _ShellExec upon which this is partially based
; ===============================================================
    

Func _StartRun($sCmd, $sFolder = @DesktopDir, $rState = @SW_SHOWNORMAL)
    Local $prevRunFatal = Opt("RunErrorsFatal", 0) ;1=fatal, 0=silent set @error
    
    Local $pid = Run($sCmd, $sFolder, $rState)
    
    If $pid = 0 Then
        ; AutoIt's built in ShellExecute abstracts this DllCall. Let's just call it directly. Not working in without MSLU installed
        Local $aRet = DllCall("shell32.dll", "long", "ShellExecute", _
                "hwnd", 0, _
                "string", "", _ ; would be the verb. it defaults to OPEN, or whatever verb is default for the file you specified
                "string", $sCmd, _
                "string", "", _ ; would be a command argument, but we don't need this as we try Run first, above
                "string", $sFolder, _
                "int", $rState)
        Local $errorText = _GetLastErrorMessage()

        If $aRet[0] > 32 Then
            Opt("RunErrorsFatal", $prevRunFatal)
            Return 1 ; ShellExecute Success!
        Else
            Opt("RunErrorsFatal", $prevRunFatal)
            Return $errorText ; Run failed, and so did ShellExecute
        EndIf
    Else
        Opt("RunErrorsFatal", $prevRunFatal)
        Return 1 ; Run Success!
    EndIf

EndFunc   ;==>_StartRun


Func _GetLastErrorMessage()
    Local $ret, $s
    Local $p = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000

    If @error Then Return ""

    $ret = DllCall("Kernel32.dll", "int", "GetLastError")

    $ret = DllCall("kernel32.dll", "int", "FormatMessage", _
            "int", $FORMAT_MESSAGE_FROM_SYSTEM, _
            "ptr", 0, _
            "int", $ret[0], _
            "int", 0, _
            "ptr", DllStructGetPtr($p), _
            "int", 4096, _
            "ptr", 0)
    $s = DllStructGetData($p, 1)
    Return $s
EndFunc  ;==>_GetLastErrorMessage

This function should work with Windows 98 if MSLU (Microsoft Layer for Unicode) is installed:

http://msdn2.microsoft.com/en-us/library/ms812865.aspx

Edited by lod3n

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

First of all, no, Windows does not try both. Microsoft has a parser to read the filename and determines whether it is registered as an executable or a data file. If it is an executable, a new process is started. If it is not an executable, the registry is checked to see if a new process should be started, or if a DDE message should be sent to an already existing process.

Second, it's not bad as far as functions go. I can see this getting a lot of use.

Edited by Mr Icekirby
Link to comment
Share on other sites

Mr Icekerby,

I appreciate that information. My source was wrong it seems (thanks again, Internet!). I'd like to replicate that same process. Before coming up with this, I'd played around with writing my own parser, and was never happy with the limitations - it was hard to predict all of the possible usages. Do you know of a reference that I could look at to improve this?

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

I remember an old environment variable that used to exist. It had to do with executable extensions. They were .exe, .pif, and .bat. I'm sure that no one uses pif files anymore. Batch files have to be executed through a command interpretter. Exe files are easy enough to the check the extension of.

As for the registry configurations for the opening of data files, I don't quite understand it. I've looked at the entries in my registry to learn how they work, but I never had an official documentation.

Link to comment
Share on other sites

I'm sorry, I don't have a floppy drive with which to install my copy of Windows 1998 in order to test and find a solution for you. Maybe this?

Func _StartRun98($sCmd, $sFolder = @DesktopDir, $rState = @SW_SHOWNORMAL)
    Local $prevRunFatal = Opt("RunErrorsFatal", 0)        ;1=fatal, 0=silent set @error
    Local $pid = Run($sCmd, $sFolder, $rState)
    Opt("RunErrorsFatal", $prevRunFatal) ; this is just so it plays nice with everybody else

    If $pid = 0 Then
        $RetVal = ShellExecute($sCmd,"",$sFolder,"",$rState)
        Return $RetVal ; ShellExecute Success!
    Else
        Return 1 ; Run Success!
    EndIf

EndFunc   ;==>_StartRun98

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

I'll try it out. Actually I don't own 98, I was asking a friend of mine to test my script..and she said it only works with programs. Will set it up to detect OS and let you know. :rolleyes: Thanks

[font="Impact"]Cats rule, humans drool.[/font]
Link to comment
Share on other sites

I remember an old environment variable that used to exist. It had to do with executable extensions. They were .exe, .pif, and .bat. I'm sure that no one uses pif files anymore. Batch files have to be executed through a command interpretter. Exe files are easy enough to the check the extension of.

As for the registry configurations for the opening of data files, I don't quite understand it. I've looked at the entries in my registry to learn how they work, but I never had an official documentation.

Wonder if that was a result of parsing output from ftype and assoc in @comspec?

Open a command shell and type help assoc, help ftype. Or just assoc && ftype

EDIT:Typo's

Edited by Uten
Link to comment
Share on other sites

assoc and fftype are simply looking up values in HKCR in the registry. There's been some work done with this kind of thing:

http://www.autoitscript.com/forum/index.php?showtopic=47845

The problem is making a flexible enough parser to handle all of the potential command someone might try and enter. It's about handling spaces, slashes and quotes well enough to find and execute the correct command, with the correct parameters, OR opening the correct file with the correct application, OR detecting the requested protocol (http://, ftp://, res://, etc.) and correctly opening the associated application. Any one of these items is simple enough on it's own, but to make something smart enough to tell what kind of random command you've specified and correctly executing it is tricky.

[font="Fixedsys"][list][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...