Page 2 of 2

Re: GeekDude's tips and tricks

Posted: 23 Oct 2017, 11:48
by geek
For the first one, Dummy is static (a type of local where the value isn't erased when the function ends) to the MyFunction function, so you can only access it from inside MyFunction's body. From my tests, the behavior of static which is being used here for auto-run doesn't apply to global, so you'd need to trick it a bit if you want to set a global value in your function.

Code: Select all

MyFunction()
{
	global MyGlobal ; Makes MyGlobal global
	static Dummy := MyGlobal := MyFunction() ; Makes Dummy static, and sets both it and MyGlobal to the result of MyFunction
	MsgBox, I see you %A_UserName%
	wow := "oops " A_Now
	return wow
}

MsgBox, % MyGlobal

For the second one, you need to use the new Q/Quotes option on the continuation section, to disable automatic quote escaping.
Quotes (or Q): Restores the ability to terminate quoted strings when an expression is used in a continuation section.
Right now, it's treating your expression as if you put this:

Code: Select all

MyObject := {math: `"fun`",english: `"boring`",coding: `"exciting`"}
You'll need to do this to make it work:

Code: Select all

MyObject := 
( LTrim Quotes Join
{
	math: "fun",
	english: "boring",
 	coding: "exciting"
}
)

Re: GeekDude's tips and tricks

Posted: 23 Oct 2017, 12:57
by derz00
Sure enough that new option is mentioned on this page: https://autohotkey.com/v2/v2-changes.htm

Thank you for your very helpful (as usual) explanations. You've got a good handle on the language. I didn't know you even do much with v2?!

Re: GeekDude's tips and tricks

Posted: 23 Oct 2017, 14:12
by derz00
Uhhh yes RUNIE? :P

Re: GeekDude's tips and tricks

Posted: 23 Oct 2017, 14:46
by runie
I answered your question but didn't notice there was a page 2 haha smh

Re: GeekDude's tips and tricks

Posted: 23 Oct 2017, 15:13
by HotKeyIt
1. because it is a static and not a global variable:

Code: Select all

MyFunction()
{
    Static Dummy := MyFunction()
    MsgBox, %Dummy% I see you %A_UserName%
	wow:="oops " A_Now
	return wow
}
MsgBox % MyFunction()
2.

Code: Select all

MyObject := {math: "fun"
			,english: "boring"
			,coding: "exciting"}

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 08 Jun 2018, 15:43
by geek
This post has been updated! Two new sections, GUIs and Regular Expressions!

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 08 Jun 2018, 19:01
by derz00
GeekDude wrote:Find, and optionally replace, all matches of regular expression efficiently using a custom enumerator.

Code: Select all

Haystack =
(
abc123|

abc456|

abc789|
)

for Match, Ctx in new RegExMatchAll(Haystack, "O)abc(\d+)")
{
	if (Match[1] == "456")
		Ctx.Replacement := "Replaced"
}

MsgBox, % Ctx.Haystack


class RegExMatchAll
{
	__New(ByRef Haystack, ByRef Needle)
	{
		this.Haystack := Haystack
		this.Needle := Needle
	}
	
	_NewEnum()
	{
		this.Pos := 0
		return this
	}
	
	Next(ByRef Match, ByRef Context)
	{
		if this.HasKey("Replacement")
		{
			Len := StrLen(IsObject(this.Match) ? this.Match.Value : this.Match)
			this.Haystack := SubStr(this.Haystack, 1, this.Pos-1)
			. this.Replacement
			. SubStr(this.Haystack, this.Pos + Len)
			this.Delete("Replacement")
		}
		Context := this
		this.Pos := RegExMatch(this.Haystack, this.Needle, Match, this.Pos+1)
		this.Match := Match
		return !!this.Pos
	}
}
Thanks for sharing. I like your object-oriented coding styles :). This is very nicely done, as always

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 08 Jul 2018, 11:03
by geek
This post has been updated! Two new sections, Networking and Web and Files and Folders!

The DllCall section has been updated to include a new tip to "Run command line tools without having a command prompt pop."

You can see the exact changes from the revision history at the bottom of the original post.

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 09 Jul 2018, 06:53
by SpeedMaster
GeekDude wrote:Download a file from the web and use its contents without having to save to a temporary file.
It works fine as long as you stay connected :thumbup: but when you are not more connected, the script displays a really ugly warning. :sick:

I found a solution here : https://autohotkey.com/board/topic/1110 ... -internet/

Code: Select all

Address := "https://example.com/"

ConnectedToInternet(flag=0x40) { 
Return DllCall("Wininet.dll\InternetGetConnectedState", "Str", flag,"Int",0) 
}

If ConnectedToInternet() {
  ; Send a request for the resource we want using an HTTP Request object
  Request := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  Request.Open("GET", Address)
  Request.Send()
}
else {
  msgbox, 48,, You are not connected 
  exitapp
}

; capture some text
Haystack:=Request.responseText
Haystack:= RegExReplace(Haystack, "`n")
Haystack:= RegExReplace(Haystack, "` +", a_space)
Haystack:= RegExReplace(Haystack, ".*This domain", "This domain")
Haystack:= RegExReplace(Haystack, "ssion.*", "ssion.")

msgbox, % Haystack

Maybe there is a request that checks connection ? :think:


there is also a ready to use function on this page UrlDownloadToVar() :D

Code: Select all

Address := "https://example.com/"

haystack:=UrlDownloadToVar("https://example.com/")

if !(haystack) {
    msgbox, 48,, You are not connected 
    exitapp
 }

; capture some text

Haystack:= RegExReplace(Haystack, "`n")
Haystack:= RegExReplace(Haystack, "` +", a_space)
Haystack:= RegExReplace(Haystack, ".*This domain", "This domain")
Haystack:= RegExReplace(Haystack, "ssion.*", "ssion.")

msgbox, % Haystack


UrlDownloadToVar(URL) {
 ComObjError(false)
 WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
 WebRequest.Open("GET", URL)
 WebRequest.Send()
 Return WebRequest.ResponseText
}



Re: GeekDude's Tips, Tricks, and Standalones

Posted: 09 Jul 2018, 08:40
by geek
The recommended way of handling that issue is to put the code which triggers the error into a try/catch block. This allows you to run an alternate set of code in the case that the first set of code fails. Checking if you have an Internet connection before trying to make a request can work but it is probably not a good way to make your code more robust. Instead of handling a single point of failure in the code it creates two points of failure: one for the Internet check and one for the web request.

By instead using try/catch you can handle the case that there's no net connection, or the case that the particular website was unreachable, or the case that the server didn't respond/timed out, and many other cases all in one go. It's less code and easier to read/write :) .

Finally, that URLDownloadToVar function you shared suppresses COM related errors without ever re-enabling them or doing anything to handle them. This can break other code in a script that has been written to handle errors correctly. I have never seen a case where calling ComObjError(false) has been beneficial rather than subtly detrimental. The way to handle errors is not to disable the errors, but like I said above to use try/catch blocks to specify what should happen (instead of a warning dialog).

Code: Select all

try
{
	Value := UrlDownloadToVar("https://not.a.real.website.com/")
}
catch
{
	Value := "Couldn't load!"
}

MsgBox, %Value%

UrlDownloadToVar(URL) {
	WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	WebRequest.Open("GET", URL)
	WebRequest.Send()
	Return WebRequest.ResponseText
}t
Thanks for your input on this topic! :)

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 09 Jul 2018, 13:50
by SpeedMaster
GeekDude wrote:By using try/catch you can handle the case that there's no net connection, or the case that the particular website was unreachable...
Thanks for your explanation.
I didn't know about try-catch statement. :roll:
This works very well. :thumbup:

Cheers

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 11 Jul 2018, 14:09
by SpeedMaster
GeekDude wrote:GUIs : Create a menu bar for your GUI using a well formatted object instead of a long list of menu commands.
Help wrote: Check, MenuItemName: Adds a visible checkmark in the menu next to MenuItemName (if there isn't one already).
Hello,
How do you "check/Uncheck" an item in the custom menu bar ? :think:

for example:

Code: Select all

Menu MyMenu, Check, &Find
Thanks,

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 13 Jul 2018, 09:57
by geek
SpeedMaster wrote:How do you "check/Uncheck" an item in the custom menu bar ? :think:
When the function builds your menu out of your array structure, it creates an array and places the name of each menu into it. The indices of the array are in linear order according to where your sub-menus are placed into the array.

Code: Select all

Menu :=
( LTrim Join Comments
[                                       ; 1
	["Branch 1", [                      ; ; 2
		["Item 1", "return"],           ; ;
		["Item 2", [                    ; ; ; 3
			["Sub-Item 1", "subitem1"], ; ; ;
			["Sub-Item 2", "return"]    ; ; ;
		]],                             ; ;
		["Item 3", [                    ; ; ; 4
			["Sub-Item 1", "subitem1"], ; ; ;
			["Sub-Item 2", "return"]    ; ; ;
		]]                              ; ;
	]],                                 ;
	["Branch 2", [                      ; ; 5
		["Item 1", "return"],           ; ;
		["Item 2", "return"]            ; ;
	]]                                  ;
]
)

MenuArray := CreateMenus(Menu)
So, then, to add a check to Menu -> Branch 1 -> Item 2 -> Sub-Item 2 you would call Menu, % MenuArray[3], Check, Sub-Item 2. Similarly, for Menu -> Branch 2 -> Item 1 you would call Menu, % MenuArray[5], Check, Item 1.

It's not the most user friendly of methods but it works. I suppose it could be possible to modify the menu creation function to return a more usable array (so that you could say MenuArray["Branch 1>Item 3"] instead of MenuArray[3] but the separator would need to be well chosen to avoid confusion if the menu name has that character in it. Alternately, it could be something like MenuArray["1:2"] for Branch 1 -> Item 3 but, while it does avoid shifting the index of later top-level menus when a sub-menu is added, it's not very useful for when you reorder the menu/add or remove top level menu items.

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 13 Jul 2018, 19:33
by SpeedMaster
Tanks !
It works now ;)

I made a simple mistake of syntax

Menu, % A_ThisMenu, Check, %A_ThisMenuItem%
Menu, % Menu_2, UnCheck, &Item2
Menu, Menu_2, UnCheck, &Item2 ; ---> The fix


Cheers

Re: GeekDude's Tips, Tricks, and Standalones

Posted: 28 Jul 2018, 17:18
by jeeswg
- Thanks so much for this tutorial, especially the 'Initialize()' and 'Download a file' examples.
- Btw notice the difference with StrRepeat, when using spaces or zeros as the fill character and specifying 0 characters. I also provide my StrRept function as an example, where I added negative number handling.

Code: Select all

vText := "a"
vNum := 0
MsgBox, % StrReplace(Format("{:" vNum "}", ""), " ", vText) ;(blank)
MsgBox, % StrReplace(Format("{:0" vNum "}", 0), 0, vText) ;a
MsgBox, % JEE_StrRept("a", 5)

JEE_StrRept(vText, vNum)
{
	if (vNum <= 0)
		return
	return StrReplace(Format("{:" vNum "}", ""), " ", vText)
	;return StrReplace(Format("{:0" vNum "}", 0), 0, vText)
}
- Should this be "Ptr" instead of "UInt"?
pData := NumGet(ComObjValue(Request.responseBody)+8+A_PtrSize, "UInt")