Jump to content

Command line argument management.


Mat
 Share

Recommended Posts

For ages I've been reusing the same old code to parse command line parameters. So I figured I'd change it slightly and make it into a UDF. The result is pretty good IMHO. To make it look nice, the main function is called 'CmdLine'. Usage is almost $_GET: CmdLine("arg") returns the value of "arg" :x

What it does is put all the command line arguments in a global array ($CmdLine_Cache) in the form: [*][0] => Argument name, [*][1] => Value. The array is populated on either the first call to CmdLine or explicitly calling _CmdLine_Parse. The latter has several advantages that I will discuss later. CmdLine() is the 'unnamed' parameter. This is the one without an argument, so "program 'file.ext'" would set this to 'file.ext'. It can be set in the command line by using just the prefix (e.g. "program -- 'test'" will set it to 'test')

Using _CmdLine_Parse has several added parameters that let you set the prefix and even say what arguments can be used. By default '--' is used (as per the GNU standard), but this is simple to change to '-' or '/' or anything else. The second argument is a zero based array of allowed arguments OR a '|' split list. This should not include prefixes! If a parameter is found that does not appear in the list then the error function specified in the third parameter is called. This should take a single argument which is given an error message from the function.

Examples:

  • --foo="This is the value of FOO"

    Foo = "This is the value of FOO"

  • --foo "This is also the value of FOO"

    Foo = "This is also the value of FOO"

  • --foo

    Foo = True

  • --Test=123

    Foo = False

$foo = CmdLine("foo")
If Not $foo Then
    MsgBox(0, "Hmm...", "Foo was not defined")
Else
    MsgBox(0, "Foo Found", "Foo = " & $foo)
EndIf

  • --Error 123

    Command line Error: Unrecognized parameter: Error

    Foo was not defined

    Test was not defined

  • --foo="This is FOO" --test="This is TEST"

    Foo = This is FOO

    test = This is TEST

_CmdLine_Parse("-", "foo|test", "_CmdLine_Error")

$foo = CmdLine("foo")
If Not $foo Then
    MsgBox(0, "Hmm...", "Foo was not defined")
Else
    MsgBox(0, "Foo Found", "Foo = " & $foo)
EndIf

$test = CmdLine("test")
If Not $test Then
    MsgBox(0, "Hmm...", "Test was not defined")
Else
    MsgBox(0, "Test Found", "Test = " & $test)
EndIf

Func _CmdLine_Error($sError)
    MsgBox(16, "Error", "Command line Error: " & $sError)
EndFunc

There is more info in the function headers.

CmdLine.au3:

Global $CmdLine_Cache[1][2] = [[0, False]]

; #FUNCTION# ====================================================================================================================
; Name ..........: CmdLine
; Description ...: Returns the value of the command line parameter.
; Syntax ........: CmdLine( [ $sParam ] )
; Parameters ....: $sParam          - [optional] A string specifying the command line parameter to retrieve. Default is a blank
;                                     string, which is the parameter that does not have a named flag first.
; Return values .: Success          - If the parameter has a value, then that is returned. If not then True is.
;                  Failure          - False. Usually means that the parameter wasn't in the command line.
; Author(s) .....: Matt Diesel (Mat)
; Modified ......:
; Remarks .......:
; Related .......: _CmdLine_Parse
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func CmdLine($sParam = "")
    If $CmdLine_Cache[0][0] = 0 And $CmdLine[0] > 0 Then _CmdLine_Parse()

    If $sParam = "" Then
        Return $CmdLine_Cache[0][1]
    Else
        For $i = 1 To UBound($CmdLine_Cache) - 1
            If $CmdLine_Cache[$i][0] = $sParam Then Return $CmdLine_Cache[$i][1]
        Next
        Return False
    EndIf
EndFunc   ;==>CmdLine

; #FUNCTION# ====================================================================================================================
; Name ..........: _CmdLine_Parse
; Description ...:
; Syntax ........: _CmdLine_Parse( [ $sPrefix [, $asAllowed [, $sOnErrFunc ]]] )
; Parameters ....: $sPrefix         - [optional] The prefix for command line arguments. Default is '--'. It is recommended that
;                                     it is one of the following standards (although it could be anything):
;                                   |GNU     - uses '--' to start arguments. <a href="http://www.gnu.org/prep/standards/
;                                              html_node/Command_002dLine-Interfaces.html">Page</a>. '--' on it's own sets the
;                                              unnamed argument but always uses the next parameter, even if prefixed by '--'.
;                                              E.g. '-- --file' will mean CmdLine() = '--file'.
;                                   |MS      - uses '-'. Arguments with values are seperated by a colon: ':'. <a
;                                              href="http://technet.microsoft.com/en-us/library/ee156811.aspx">Page</a>
;                                   |Slashes - Not sure where it's a standard, but using either backslash ( '\' ) or slash
;                                              ( '/' ) is fairly common. AutoIt uses it :) Just make sure the user knows which
;                                              one it is.
;                  $asAllowed       - [optional] A zero based array of possible command line arguments that can be used. When an
;                                     argument is found that does not match any of the values in the array, $sOnErrFunc is called
;                                     with the first parameter being "Unrecognized parameter: PARAM_NAME".
;                  $sOnErrFunc      - [optional] The function to call if an error occurs.
; Return values .: None
; Author(s) .....: Matt Diesel (Mat)
; Modified ......:
; Remarks .......:
; Related .......: This function must be called (rather than used in #OnAutoItStartRegister), as it uses a global array.
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _CmdLine_Parse($sPrefix = "--", $asAllowed = 0, $sOnErrFunc = "")
    If IsString($asAllowed) Then $asAllowed = StringSplit($asAllowed, "|", 3)

    For $i = 1 To $CmdLine[0]
        If $CmdLine[$i] = "--" Then
            If $i <> $CmdLine[0] Then
                $CmdLine_Cache[0][1] = $CmdLine[$i + 1]
                $i += 1
            Else
                $CmdLine_Cache[0][1] = True
            EndIf
        ElseIf StringLeft($CmdLine[$i], StringLen($sPrefix)) = $sPrefix Then
            $CmdLine_Cache[0][0] = UBound($CmdLine_Cache)
            ReDim $CmdLine_Cache[$CmdLine_Cache[0][0] + 1][2]

            If StringInStr($CmdLine[$i], "=") Then
                $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = StringLeft($CmdLine[$i], StringInStr($CmdLine[$i], "=", 2) - 1)
                $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = StringTrimLeft($CmdLine_Cache[$CmdLine_Cache[0][0]][0], StringLen($sPrefix))
                $CmdLine_Cache[$CmdLine_Cache[0][0]][1] = StringTrimLeft($CmdLine[$i], StringInStr($CmdLine[$i], "=", 2))
            ElseIf StringInStr($CmdLine[$i], ":") Then
                $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = StringLeft($CmdLine[$i], StringInStr($CmdLine[$i], ":", 2) - 1)
                $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = StringTrimLeft($CmdLine_Cache[$CmdLine_Cache[0][0]][0], StringLen($sPrefix))
                $CmdLine_Cache[$CmdLine_Cache[0][0]][1] = StringTrimLeft($CmdLine[$i], StringInStr($CmdLine[$i], ":", 2))
            Else
                $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = StringTrimLeft($CmdLine[$i], StringLen($sPrefix))
                If ($i <> $CmdLine[0]) And (StringLeft($CmdLine[$i + 1], StringLen($sPrefix)) <> $sPrefix) Then
                    $CmdLine_Cache[$CmdLine_Cache[0][0]][1] = $CmdLine[$i + 1]
                    $i += 1
                Else
                    $CmdLine_Cache[$CmdLine_Cache[0][0]][1] = True
                EndIf
            EndIf

            If $asAllowed <> 0 Then
                For $n = 0 To UBound($asAllowed) - 1
                    If $CmdLine_Cache[$CmdLine_Cache[0][0]][0] = $asAllowed[$n] Then ContinueLoop 2
                Next

                If $sOnErrFunc <> "" Then Call($sOnErrFunc, "Unrecognized parameter: " & $CmdLine_Cache[$CmdLine_Cache[0][0]][0])
            EndIf
        Else
            If Not $CmdLine_Cache[0][1] Then
                $CmdLine_Cache[0][1] = $CmdLine[$i]
            Else
                If $sOnErrFunc <> "" Then Call($sOnErrFunc, "Unrecognized parameter: " & $CmdLine[$i])
            EndIf
        EndIf
    Next
EndFunc   ;==>_CmdLine_Parse

Mat

Link to comment
Share on other sites

  • 3 weeks later...

No probs :x

If you want a simple one-line solution to the problem then you could just use:

If StringInStr($CmdLineRaw, " /install") Then
    ; Install
EndIf

or alternatively, there is a very nice (and unfortunately not advertised) collection of basic snippets in SciTE under abbreviations. Go to: Edit > Insert Abbreviation and type "cmdlineswitch" to get a template statement that you can then edit with your parameters. If you'd rather use mine after those tow suggestions then read on:

The easiest way to use my code is to save it as a file called "CmdLine.au3", and put it in the same directory as your script. You can then use this in your program:

; Leave these two lines at the top!!
#include "CmdLine.au3"
_CmdLine_Parse("/")

; Check command line parameters:
If CmdLine("install") Then
    MsgBox(0, "Test", "The installation would be running right now.")
ElseIf CmdLine("uninstall") Then
    MsgBox(0, "Test", "The UN-installation would be running right now.")
Else
    MsgBox(0, "Test", "Not much going on...")
EndIf

For information on include the helpfile has it all (as usual). Although it may sound counter-intuitive, learn the language, THEN write your programs. If you try and write a program while the gradient is still steep on the learning curve then you'll only end up re-writing it later.

Here's a sort of template based on the above:

MyScript.zip

Mat

Link to comment
Share on other sites

I have to clarify my request :x

I put an example about adobe flash player , but I need solution for any application may has switches

also I didn't understand where to insert the location of the app that I wanna use :P

thanks for the help and sorry for inconvenience :shifty:

Link to comment
Share on other sites

As said before, you must learn the language before trying to program... Me helping you know won't help you as much as you teaching yourself. Furthermore this thread is for an example, and as much as I am willing to help you, filling up pages of stuff that's only going to useful to you is what we have a pm system for. So here's what I'll do: Play around with the snippet I gave you, try to read it as though it was English (best way to deal with IF tests), and pm me tomorrow with what you know, and still need to know. Deal? Try it, you'll learn lot's :x

Link to comment
Share on other sites

  • 6 months later...
  • 1 year later...

Sorry to revive an old thread attack of the necro bump is back! But....possibly valid? 

I am attempting to use this to pass command line arguments to a wrapper script that I use to launch Notepad++. At the moment it is sh!tting me to tears that Notepad++ always launches in the same instance. I use Alt+Tab a LOT! So it is handy to Alt Tab between sessions...nope Notepad is always on the same tab and you have to pass it command line options of notepad++.exe -multiInst -nosession in order for it to launch as 1) In a new session 2) As full screen
That brings me to my next problem. If I click my compiled exe script to launch Notepad++ it always launches as a new session. But I use right click a hell of a lot too! Currently Notepad++ everytime I reboot my computer seems to reset its self when it right click a file and launch from the standard Edit with Notepad++ that sometimes when it launches it isn't exactly minimised it launches maximised however the expand Window button defaults to resize the Window and make it about the size of the 3 buttons...actually screw it a screen shot is in order here to prove my point! (click to see full size version and check out the top left corner)

Screenshot_notepad%2B%2B.png

So I figured that your script could be used to pass command arguments to my wrapper script from the right click context menu so that when I launch from right click and wondering where the f my window is I can pass it to my wrapper which should always allow it to be seen in full screen maximized instead of that cr@p you see in my screenshot.

Right click context menu accepts a command line of %1

For some reason this does not work when I load it in to my wrapper script? Nothing happens? It seems to ignore %1 as command line argument, actually nothing happens at all? It doesn't even launch the application?

Here is my script:
 

$Title = "NotepadNewInst"
#include <File.au3>
#NoTrayIcon

Func NotepadNewInst()
Local $path=(@ScriptDir &'\')
Run('notepad++.exe -multiInst -nosession ', $path, @SW_MAXIMIZE)
Exit
EndFunc   ;==>NotepadNewInst()
NotepadNewInst() 

Here it is modified:

Note: My CmdLine.au3 is in C:Program Files (x86)AutoIt3Include

$Title = "NotepadNewInst"
#include <File.au3>
#include <CmdLine.au3>
_CmdLine_Parse("%1")

Func NotepadNewInst()
Local $path=(@ScriptDir &'\')
If CmdLine("%1") Then
    Run('notepad++.exe -multiInst -nosession ' & '%1', $path, @SW_MAXIMIZE); Have tried all sorts of combinations of this none work?
;Run('notepad++.exe -multiInst -nosession ' & '%1', $path, @SW_MAXIMIZE)
;Run('notepad++.exe ' & '%1 ' &'-multiInst -nosession', $path, @SW_MAXIMIZE)
;Run('notepad++.exe %1 -multiInst -nosession', $path, @SW_MAXIMIZE)
;Run('notepad++.exe -multiInst -nosession %1', $path, @SW_MAXIMIZE)
;Run('notepad++.exe ' '%1', $path, @SW_MAXIMIZE)
;Run('notepad++.exe %1', $path, @SW_MAXIMIZE)
EndIf
Exit
EndFunc   ;==>NotepadNewInst()
NotepadNewInst() 

Any thoughts on why it won't pass the command line argument of %1?

Edited by DigitalFacade82
Link to comment
Share on other sites

So the issue is when you are right clicking, it going to notepad++ directly so it is not executing your program at all.  So you will need to modify the context menu to point to your program.

so I made a some changes to your program.  Compile it and place the exe wherever you want it.

Then open command prompt with admin rights

browse to where the exe location and run it with /install -- this modifies the context menu to point to your program.

Now when you right click edit with notepad++, it should open in new instance.

to set it back to default, use /uninstall switch

#NoTrayIcon
Global $path = RegRead('HKEY_LOCAL_MACHINE\SOFTWARE\Notepad++', '')
Global $context_reg = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\*\shellex\ContextMenuHandlers\', $guid
If $CmdLineRaw = "/install" Or  $CmdLineRaw = "/uninstall" Then
    If Not IsAdmin() Then
        MsgBox(0, 'error', 'Please re-run from command prompt with admin rights')
        Exit
    EndIf
    For $i = 1 To 10000
        Local $var = RegEnumKey($context_reg, $i)
        If @error <> 0 Then ExitLoop
        If StringInStr($var, 'Notepad++') Then $guid = RegRead($context_reg & $var, '')
    Next
    If $guid = '' Then
        MsgBox(0, 'error', 'could not find ContextMenuHandler for Notepad++')
        Exit
    EndIf
    If  $CmdLineRaw = "/install" Then
        RegWrite('HKEY_LOCAL_MACHINE64\SOFTWARE\Classes\CLSID\' & $guid & '\Settings', 'Path', 'REG_SZ', @ScriptFullPath)
    Else
        RegWrite('HKEY_LOCAL_MACHINE64\SOFTWARE\Classes\CLSID\' & $guid & '\Settings', 'Path', 'REG_SZ', $path & '\notepad++.exe')
    EndIf
    Exit
EndIf
Run($path & '\notepad++.exe -multiInst -nosession ' & $CmdLineRaw, $path, @SW_MAXIMIZE)
Link to comment
Share on other sites

Firstly, I recently rewrote this bit of code, you can find the new version >here.

You aren't really using this properly, you probably wanted something like this:

$Title = "NotepadNewInst"

#include <File.au3>

#include <CmdLine.au3>

_CmdLine_Parse()

NotepadNewInst()


Func NotepadNewInst()
    Local $path = (@ScriptDir & '\')
    
    If CmdLine("") Then
        ConsoleWrite('notepad++.exe -multiInst -nosession ' & CmdLine("") & @LF)
    EndIf
    
    Exit
EndFunc   ;==>NotepadNewInst

To be honest you are better off using the normal $CmdLine. This UDF was mostly designed to make more complicated command line applications.

Link to comment
Share on other sites

Damn I forgot to open my last post with  :x well that certainly broke the fun n games (old as they are.....2011 haha)

 

 

So the issue is when you are right clicking, it going to notepad++ directly so it is not executing your program at all.  So you will need to modify the context menu to point to your program.

so I made a some changes to your program.  Compile it and place the exe wherever you want it.

Then open command prompt with admin rights

browse to where the exe location and run it with /install -- this modifies the context menu to point to your program.

 

Not exactly. I am sorry the picture didn't come through before? It has now....and it seems to be rather large (sorry about that too), skydrive changed my share permissions? Looks like Microsoft have upped their security? 

As you will see in the screenshot it shrinks it to the very top left corner. No matter what you have its properties set as before executing, it ignores them every time and ends up shrunk.If I execute from my launcher script it always runs maximised. I just need my script to feed the variable %1 (the file I am right clicking) and parsing it to the main application executable. I am pretty familiar with Windows context menus. Mine is highly customised actually.

From a normal command line notepad++.exe -multiInst -nosession <filename.extension> works just as it should, however in Windows explorer Notepad++ executable doesn't seem to listen when it is passed commands from the context menu?  

 

Firstly, I recently rewrote this bit of code, you can find the new version >here.

You aren't really using this properly, you probably wanted something like this:

$Title = "NotepadNewInst"

#include <File.au3>

#include <CmdLine.au3>

_CmdLine_Parse()

NotepadNewInst()


Func NotepadNewInst()
    Local $path = (@ScriptDir & '\')
    
    If CmdLine("") Then
        ConsoleWrite('notepad++.exe -multiInst -nosession ' & CmdLine("") & @LF)
    EndIf
    
    Exit
EndFunc   ;==>NotepadNewInst

To be honest you are better off using the normal $CmdLine. This UDF was mostly designed to make more complicated command line applications.

 

 

Hi Mat,

Thanks for your response. Actually what you have posted makes perfect sense now. I guess I am used to Run and (@comspec, I have not used ConsoleWrite except for switching in a hidden command prompt window for some tray buttons I made. Other than that nothing so I should probably familiarise myself with the Console commands. I come from a very DOS/Windows background, so I still have the tendency of doing what is comfortable or habit at the moment, like writing small applications still in batch....when I have all the wealth of AutoIT at my fingertips. Sad I know.

You have made it so simplified; and I was making it damn complex by the look of things lol. Typical n00b that I am.

Thanks

will check out your thread when I have some time soon

Cheers  :x

Edited by DigitalFacade82
Link to comment
Share on other sites

I haven't looked at your code much at all, but it seems to me, that your issue may be Working Directory related?

Have you tried the same command string using a Shortcut file?

Often command strings that work fine from the Command Prompt, won't work with other implementations, until you pass the Working Directory properly, perhaps with a Directory Change even.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Link to comment
Share on other sites

I haven't looked at your code much at all, but it seems to me, that your issue may be Working Directory related?

Have you tried the same command string using a Shortcut file?

Often command strings that work fine from the Command Prompt, won't work with other implementations, until you pass the Working Directory properly, perhaps with a Directory Change even.

 

 
Hi TheSaint,
 
Um well that's the thing, the compiled script is actually run from the working directory. Notice the path is @Scriptdir that is basically the same as telling a batch file to cd "%~dp0" just before execution (my compiled script sits just inside Notepad++ directory next to notpad++.exe - note this is on Windows 7 not Windows 8, with Full Admin privileges....yes I probably should have with Req Admin rights but in all instances the execution DOES work). I don't believe it IS working directory related at all, I believe it is idiot related...meaning I got the syntax incorrect). But  I also think the root of the problem leading to all this is definitely a bug in Notepad++ and not with my script. My script works otherwise. Meaning when it is launched; the exe works.

Only when I compiled it to accept command line arguments it didn't. I now know why that is so and I can change it. Unfortunately launching from a shortcut is not going to fix my problem when it occurs at the right click context menu. Not being rude, but if you had read my post before responding you would know this. Also I have stated that Notepad++ works fine when it is fed command line arguments just not from the right click context menu.

But yes your suggestion could be implemented in a very messy way by having a script launch a shortcut, but 1) that is not good practice at all and 2) that would still leave me back at square one in that how would I program a shortcut to accept command line arguments? I mean wouldn't it be easier to make a compiled exe accept arguments instead?.......and that is what my whole question was about in the first place.
 
Apologies to the OP, I have not yet had the chance to implement what you have suggested, but thank you again.
Edited by DigitalFacade82
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...