Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
512 views
in Technique[技术] by (71.8m points)

virtual machine - How can my AutoHotKey script launch batch scripts accordingly?

This script is supposed to switch me from Windows to Linux(VM) and vice versa:

Pause::vmStart()
return

runVM := false
linux := false

vmStart()
{
    If (!runVM and !linux) {
        Run, C:Userspatrickdev-vmPS.cmd
        runVM := true
        sleep, 18000
    }
    If (!linux and !WinExist("DevVM - 127.0.0.1:23389 - RDP")) {
        Run, C:Userspatrickdev-vmRDP.cmd
    }
    if (!linux) {
        WinShow, DevVM - 127.0.0.1:23389 - RDP
        WinActivate, DevVM - 127.0.0.1:23389 - RDP
    }
    Send ^!{CtrlBreak}
    linux := !linux
}
  • When I am in Windows, it needs to activate my RDP window first (what works fine).
  • When I am in Windows and the VM was not started with PS.cmd, then it should launch it (what also works and takes about 18 sec)
  • Using ^!{CtrlBreak} is the normal switch that also works.

I think that there is something wrong with my brackets/function/boolean definition. Do you find the mistake?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Has a few problems, but just one that matters.
Firstly, your variable definitions are unreachable code.

Pause::vmStart()
return

runVM := false
linux := false

Code execution stops at the first hotkey that is met.
In addition you also have a Return in there, which would also stop code execution. So you really are making sure code execution will never reach the variable definitions haha.
Luckily AHK is super forgiving and if you reference any variable that hasn't been declared yet, it's created with the default value of nothing, which also evaluates to false.

So that wasn't the actual problem, but still something that needs fixing. Move the definitions to be above your hotkey, or just remove them, they're not needed due to how forgiving AHK is, as explained above.
Then onto the next problem, variable scope.

In that function's scope the variables you reference don't exist, and they're created and freed every time you run the function.
You have a few options you can do. You can either define the variables as global, static, or super global (super global is bad practice and not recommended).

Defining them as global means you reference a variable that's found outside of the function's scope and its value will be stored there. To define the variables as global, you'd make the first line(s) of your function do that like this:

vmStart()
{
    global runVM, linux
    ...

Or you could just make the first line of function be nothing but the keyword global, and that means the function assumes all variables are global.

To define the variables as static, you'd do the same as for global (with the keyword static). Defining them as static basically means they aren't freed after the function completes its execution. So next time you call the function their value is what you last set it to be in the function.

To define them as super global, you'd define the variables outside of the function (at the very top of your script) with the keyword global like this:

global runVM := false
global linux := false
Pause::vmStart()
...

This would mean any scope anywhere that tried to reference a variable by that name would use your super global variable. This is bad practice and can be dangerous to do, especially if you use external libraries. Wouldn't be too hard to accidentally break something.

Of course when you have a little script like that, is makes no difference whatsoever what method you use. Even I confess to sometimes using super global on my personal scripts, just because it's quite convenient to not have to worry about scopes.

If you'd like to hear my recommendation, I'd say go for static variables.
It's pretty much exactly intended for what you're doing here.

Here's your finished product (with some miscellaneous changes) in case I didn't explain something well enough:

Pause::vmStart()
;the 'return' here did nothing for us, removed

vmStart()
{
    ;using the static keyword to make the function assume
    ;all variables are static, and also skipped even 
    ;declaring the variables, not needed due to how forgiving AHK is
    static

    ;got rid of the 'and' keyword in your if statements
    ;that's legacy syntax, big ew, it's not 2005
    If (!runVM && !linux) {
        Run, C:Userspatrickdev-vmPS.cmd
        runVM := true
        sleep, 18000
    }
    ;removed braces, one-liner statments don't need them
    ;just personal preference though, of course
    If (!linux && !WinExist("DevVM - 127.0.0.1:23389 - RDP")) 
        Run, C:Userspatrickdev-vmRDP.cmd
    if (!linux) {
        WinShow, DevVM - 127.0.0.1:23389 - RDP
        WinActivate, DevVM - 127.0.0.1:23389 - RDP
    }
    ;switched to SendInput, it's faster and more reliable
    SendInput, ^!{CtrlBreak}
    linux := !linux
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...