GeekDude's Tips, Tricks, and Standalones

Put simple Tips and Tricks that are not entire Tutorials in this forum
geek
Posts: 1068
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: GeekDude's tips and tricks

Post by geek » 23 Oct 2017, 11:48

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"
}
)

User avatar
derz00
Posts: 497
Joined: 02 Feb 2016, 17:54
Location: Middle of the round cube
Contact:

Re: GeekDude's tips and tricks

Post by derz00 » 23 Oct 2017, 12:57

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?!
try it and see
...

User avatar
derz00
Posts: 497
Joined: 02 Feb 2016, 17:54
Location: Middle of the round cube
Contact:

Re: GeekDude's tips and tricks

Post by derz00 » 23 Oct 2017, 14:12

Uhhh yes RUNIE? :P
try it and see
...

User avatar
runie
Posts: 305
Joined: 03 May 2014, 14:50
Contact:

Re: GeekDude's tips and tricks

Post by runie » 23 Oct 2017, 14:46

I answered your question but didn't notice there was a page 2 haha smh

HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: GeekDude's tips and tricks

Post by HotKeyIt » 23 Oct 2017, 15:13

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"}

geek
Posts: 1068
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: GeekDude's Tips, Tricks, and Standalones

Post by geek » 08 Jun 2018, 15:43

This post has been updated! Two new sections, GUIs and Regular Expressions!

User avatar
derz00
Posts: 497
Joined: 02 Feb 2016, 17:54
Location: Middle of the round cube
Contact:

Re: GeekDude's Tips, Tricks, and Standalones

Post by derz00 » 08 Jun 2018, 19:01

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
try it and see
...

geek
Posts: 1068
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: GeekDude's Tips, Tricks, and Standalones

Post by geek » 08 Jul 2018, 11:03

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.

User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: GeekDude's Tips, Tricks, and Standalones

Post by SpeedMaster » 09 Jul 2018, 06:53

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
}



geek
Posts: 1068
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: GeekDude's Tips, Tricks, and Standalones

Post by geek » 09 Jul 2018, 08:40

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! :)

User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: GeekDude's Tips, Tricks, and Standalones

Post by SpeedMaster » 09 Jul 2018, 13:50

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

User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: GeekDude's Tips, Tricks, and Standalones

Post by SpeedMaster » 11 Jul 2018, 14:09

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,

geek
Posts: 1068
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: GeekDude's Tips, Tricks, and Standalones

Post by geek » 13 Jul 2018, 09:57

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.

User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: GeekDude's Tips, Tricks, and Standalones

Post by SpeedMaster » 13 Jul 2018, 19:33

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

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: GeekDude's Tips, Tricks, and Standalones

Post by jeeswg » 28 Jul 2018, 17:18

- 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")
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Post Reply

Return to “Tips and Tricks (v1)”