Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Why use AutoHotkey_L? Ask Questions Here...


  • Please log in to reply
128 replies to this topic
jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
http://tinyurl.com/8ja76he

AutoHotkey_L Download Page

... I'm grateful that Lexikos, fincs, Sean, jackieku, Micha and others consider AutoHotkey worthwhile enough to provide it with major new functionality. In keeping with this, and as something long overdue, I've altered the website to give AutoHotkey_L more of the attention it deserves ...

... you can choose to use the outdated version of AHK, and that would be the same as choosing to use outdated computer, phone, or car. ... [AutoHotkey_L is] superior in any aspect - be it the short code fetish or the complex applications.

AutoHotkey_L is recommended because you have [everything AutoHotkey (Basic) has plus]:[*:4pf0h865]Native Unicode support.
[*:4pf0h865]Native 64-bit support.
[*:4pf0h865]Native COM support.
[*:4pf0h865]Native Array/associative array/OOP support.
[*:4pf0h865]Native variadic function support.
[*:4pf0h865]for key,val in object and until Expression.

[*:4pf0h865]More GUI Options (ActiveX, Link, etc.)
[*:4pf0h865]#if expression - Similar to #IfWinActive, but for arbitrary expressions.
[*:4pf0h865]Interactive debugging features (see SciTE4AutoHotkey)
[*:4pf0h865]Support for various text encodings.
[*:4pf0h865]New DllCall arg types for portability.
[*:4pf0h865]Object-oriented file I/O.

Here is a list of AHK Basic bugs that have been fixed in AHK_L ... This is why I recommend a switch to AHK_L today. Not because you'll be able to use many powerful new features, not because you can run a huge number of awesome AHK_L only scripts, but because you can avoid spending hours debugging a script only to find that it was an AHK Basic bug all along, or to find that you simply can't do something the way you want to at all, and have to settle for less.

If you are still using Autohotkey Basic, then you are using a Dead Project.

>> Want to test your version of AutoHotkey? Run the following script:
If A_AhkVersion >= 1.1
	MsgBox, 262208, AutoHotkey Version Notification, You are using AutoHotkey Version %A_AhkVersion%.`n(also know as AutoHotkey_L)
Else
    MsgBox, 262212, AutoHotkey Version Notification, You are using AutoHotkey Version %A_AhkVersion%
	. A newer version of AutoHotkey has been released. (also know as AutoHotkey_L)`n`nWould you like to download the newest version?
IfMsgBox Yes
    Run "http://l.autohotkey.net/AutoHotkey_L_Install.exe"

IMPORTANT: If you are using the Unicode build (recommended), save your script with File-Encoding: UTF-8
Posted Image*Image of saving your script in Notepad

Concerned your script may have compatibility issues? See Script Compatibility.

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
Frequently Asked Questions:
[*:1c30z4tg]Automatic hierarchy creation using dot syntax

Beta:=Object()

Beta.gamma.test := "ouga" ; doesn't work, however this syntax is more readable with string name
msgbox % Beta.gamma.test

Beta["gamma","test"]:="ouga" ; it works with normal way
msgbox % Beta.gamma.test

It was asked here before, a possible solution was provided here, and here is the official documentation ... Alternately, you could manually create the object (this will be simpler with JSON):

Beta[[color=#666666]"gamma"[/color]] := [color=#107095]object[/color]([color=#666666]"test"[/color],[color=#666666]"ouga"[/color])
; ~OR~
Beta.Insert([color=#666666]"gamma"[/color], [color=#107095]object[/color]([color=#666666]"test"[/color],[color=#666666]"ouga"[/color]))

[*:1c30z4tg]Assignment Fail When Object Declared In One Line

... value assignments to object keys misbehave when the object is declared in a single line.

ObjA := ObjB := [color=#107095]Object[/color]()
ObjA[[color=#666666]"Fruit"[/color]] := [color=#666666]"This is an apple."[/color]
ObjB[[color=#666666]"Fruit"[/color]] := [color=#666666]"This is a banana."[/color]
[color=#107095]msgbox[/color] % ObjA.Fruit		;returns "This is a banana."
[color=#107095]msgbox[/color] % ObjB.Fruit		;returns "This is a banana."

When you assign an object you're assigning a reference to that object, so when you assign to an object in that manner you're assigning two variable names to reference the same object ... When you break it up into two lines and assign an object to each you're assigning two unique object references to two unique variable names.

ObjA := [color=darkred]Object(),[/color] ObjB := Object()

Additionally, Lexikos explained this here.

[*:1c30z4tg]Winsock2.ahk

Using Winsock2.ahk for sending email. It was working. Upgraded to Autohotkey_L and it's not working.

See: Converting Script to AHK_L - specifically AHKsock - A simple AHK implementation of Winsock (TCP/IP)


[*:1c30z4tg]General discussion: AutoHotkey_L Objects

I also have some troubles understanding the AHK implementation of objects and would like some info as well...



majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I salut your efforts jethrow. I'll also try to answer all questions asked here.
One of those things that are problematic about AHKL is lack of examples and if more people are interested, there will be more examples to learn from.
Posted Image

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
I don't know if it possible but I have some question about AHKL, and I want to know how AHKL can simplify my life.

Alpha:=Object()
Alpha["p1","x"]:="p1x" , Alpha["p1","y"]:="p1y" , Alpha["p1","r"]:="p1r"
Alpha["p2","x"]:="p2x" , Alpha["p2","y"]:="p2y" , Alpha["p2","r"]:="p2r"
Beta:=Object()



; -- 1 -- Table Array

Beta.gamma.test := "ouga" ; doesn't work, however this syntax is more readable with string name
msgbox % Beta.gamma.test
; Beta["gamma","test"]:="ouga" ; it works with normal way
; msgbox % Beta.gamma.test



; -- 2 -- Double Array

Gamma:=Object()

Beta["gamma"]["test"]:="ouga"
msgbox % Beta["gamma"]["test"]
; I have do a lot of test but I don't know how to create and use table and array with the second method of the help file



; -- 3 -- Loop, Table

;for k1, v in Alpha
;  for k2, v in Alpha[k1]
;    msgbox % k1 "," k2 "=" v ; it's work but:
;they are a "for k1, k2, v in Object" ? how retrieve the creation order or reverse alphabetic order or other in this loop ?



; -- 4 -- Object GetName

func(Alpha, Beta)
; Not func("Alpha", "Beta") who is easy to use and get, like a string.
; For performance reason ( %obj% is half slower than obj ) I try to get the object name.

func(obj1, obj2) {
global ; or not
; if (obj1="beta") ; ObjGetName(&obj1) or Address.GetName(Object(obj1)) features ? or to write a string name at the same adress when created object ?
  msgbox % obj1 "," obj2
}



; -- 5 -- Operator Object

; always for performance reason:
; something like Object[1]+= or Object[1]*= is possible ? like a variable ?


jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
[*:1mdriaey]Automatic hierarchy creation using dot syntax - good question. It was asked here before, a possible solution was provided here, and here is the official documentation.

[*:1mdriaey]Your second question seems similar to the first. You need to use [key1, key2] to auto-create a value that is an object:
Beta[[color=#666666]"gamma"[/color],[color=#666666]"test"[/color]]:=[color=#666666]"ouga"[/color]
[color=#107095]msgbox[/color] % Beta[[color=#666666]"gamma"[/color]][[color=#666666]"test"[/color]]
Alternately, you could manually create the object (this will be simpler with JSON):
Beta[[color=#666666]"gamma"[/color]] := [color=#107095]object[/color]([color=#666666]"test"[/color],[color=#666666]"ouga"[/color])
; ~OR~
Beta.Insert([color=#666666]"gamma"[/color], [color=#107095]object[/color]([color=#666666]"test"[/color],[color=#666666]"ouga"[/color]))
[*:1mdriaey]

... how retrieve the creation order ...

Lexikos wrote it somewhere - keys are stored in the object in Numeric/Alphabetic order (Note - numbers [1] & strings ["1"] are NOT the same for keys). For instance, take the following:
obj := [color=#107095]object[/color](	[color=#666666]"A"[/color]  ,   [color=#666666]"1st letter"[/color]	; show as 3rd key
				,	 [color=#666666]"key"[/color],   [color=#666666]"value"[/color]			; show as 4th key
				,	 [color=#666666]"1"[/color]  ,   [color=#666666]"One (Str)"[/color]		; show as 2nd key
				,	  1   ,   [color=#666666]"One (Num)"[/color]	)	; show as 1st key
[color=#107095]For[/color] k,v in obj
	text .= k [color=#666666]" = "[/color] v [color=#666666]"`n"[/color]
[color=#107095]MsgBox[/color], %text%
That being said, you can create your own _NewEnum & Next methods to control the For-loop - Lexikos demonstrates here. So, you could enumerate an objects keys in reverse alphabetic order (possibly enumerate the keys & then return them in reverse order?).

[*:1mdriaey]

ObjGetName(&obj1) or Address.GetName(Object(obj1)) features ?

Like normal variables, object function parameters will not be able to access the passed object names. However, unlike normal variables, object function parameters will contain the same memory address as the passed function, to my understanding. This may not be technically what is happening (see Syntax), but here is an example:
Alpha := [color=#107095]object[/color]()
f(Alpha,&Alpha)

f(obj,Alpha_address) {
	obj_address := &obj
	[color=#107095]MsgBox[/color], 0, Alpha Address: %Alpha_address%, Obj Address: %obj_address%
}
[*:1mdriaey]

Object[1]+= or Object[1]*= is possible ? like a variable ?

I believe I was officially the first person to ask this ;) - see here. Lexikos' answer is about halfway down the page. Lexikos did mention later, however, that it's on his list.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

func(obj1, obj2) {
global ; or not
; if (obj1="beta") ; ObjGetName(&obj1) or Address.GetName(Object(obj1)) features ? or to write a string name at the same adress when created object ?
  msgbox % obj1 "," obj2
}


It doesn't work like that. The same way you can't know the name of the variable you passed. For that to work you need something called Reflection in the language and _LowLevel.ahk provides some form of it.
Anyway, you will probably be happy by standardizing some property of object that will let you examine its 'type' or 'name'. I for instance use _Name. So if you created objects in a manner Alpha:=Object("_Name", "Alpha") then you can do in your function

func(obj1, obj2) {
  ;global ; or not (majkinetor: definitely not)
; if (obj1._Name="beta") 
  msgbox % obj1._Name "," obj2._Name
}
... or you could use addresses as mentioned by jethrow altho using numbers for such purpose is IMO not adequate.

Now, the code that you wrote could be achieved if objects had default property (like in VBA for example). We already asked Lexikos to support something like this (and so far, it looks like its not going to happen), i.e. to give meaning to objects in usual mathematical and string operations, probably via metafunctions that would define object's behavior in specific context (i.e. __Add, __Concut, __Mul, __Str , etc. ). This is more then just a default property but its a complete solution for contextual problems (present in Lua language).
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
It may help to understand some basic concepts:

Variables have names.

Objects are values, like strings or numbers.

Like other values, objects can be stored in variables but variables are not objects and objects are not variables. Abusing the old adage, you could say that they're like apples and fruit baskets. (I wanted to say "apples and orange baskets" for familiarity, but my pedantic nature would not allow it.)

Objects are stored by reference. If x contains an object, y := x copies this reference so both refer to the same object. Another word for "reference" is "address"; x and y really just contain a number plus the special knowledge that it is the address of an object. When you do &x or &y, it returns this same value, but treats it as a plain old number.

When you pass a variable to a ByRef parameter, the address of the variable is copied into the target parameter. However, if the parameter is not ByRef, the contents of the variable are copied into the target parameter as if an ordinary assignment occurred. After this there is no connection between the target parameter and the original variable.

In addition to strings and numbers, AutoHotkey_L supports objects. Objects are treated as a distinct type of value which, like other types of values, can be stored in variables, passed to or returned from functions and stored in other objects.

Note that objects are "reference types" - after an assignment such as food := pizza, food will refer to the original pizza object. Similarly, Eat(pizza) will pass the original pizza object to the Eat() function, which is then able to modify the original object. If the parameter is declared ByRef, the function can also change the pizza variable to point to a different object.


Source: Objects

Like normal variables, object function parameters will not be able to access the passed object names.

Variables containing objects are normal variables. What you're referring to as "object names" are actually "variable names", which have no direct connection to the objects stored inside those variables. Accessing the name of the caller's variable is not possible unless the parameter is ByRef and you're willing to rely on undocumented features or wait for built-in functionality to be implemented.

However, unlike normal variables, object function parameters will contain the same memory address as the passed function, to my understanding.

The address-of operator can be a little confusing. If var contains an object, &var returns the object's address. An object doesn't "belong" to any one variable. On the other hand, if var contains a string, &var returns the address of var's buffer, which is where the string is stored. Expressions like &x == &y are only true when x and y refer to the same variable (via ByRef) or contain the same object; or both variables have zero capacity (i.e. no buffer).

The same way you can't know the name of the variable you passed.

I'd rather say it's exactly the same thing.

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009

... Eat(pizza) will pass the original pizza object to the Eat() function, which is then able to modify the original object.

I wanted to re-emphasize this because (to me anyways) it seems like this could cause confusion since ByRef isn't being used. However, this is the same in other languages as well. Here is the actual code for a visual:
pizza := [color=#107095]object[/color]([color=#666666]"slices"[/color], 10)
[color=#107095]MsgBox[/color], % pizza.slices ; 10 slices
Eat(pizza)
[color=#107095]MsgBox[/color], % pizza.slices ; 0 slices

Eat(p) { ; this will modify the passed object
	p.slices := 0
}
NOTE - if you want to alter an object in a function without modifying the passed object, you can use the Clone Method to create a copy of the object.

  • Guests
  • Last active:
  • Joined: --
unless this post is made a Sticky, wont it just slip off the first page?

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Not necessarily :)
Posted Image

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I wanted to re-emphasize this because (to me anyways) it seems like this could cause confusion since ByRef isn't being used.

Perhaps this will help anyone wishing to understand this behaviour (though some understanding of pointers may be required):
[color=#107095]SetFormat[/color] IntegerFast, H
pizzaObject := [color=#107095]Object[/color]([color=#666666]"slices"[/color], 8)  ; Create object.
pizzaAddress := [color=#107095]Object[/color](pizzaObject)  ; Retrieve object's address and ref count += 1.
[color=#107095]ListVars[/color]  ; Notice that both show the same value, but only one is an "object".
[color=#107095]MsgBox[/color] % pizzaAddress
Eat(pizzaAddress)  ; Eat the object by address (just a number).
[color=#107095]ObjRelease[/color](pizzaAddress)  ; Release the pizza (ref count -= 1).
[color=#107095]SetFormat[/color] IntegerFast, D
[color=#107095]MsgBox[/color] % pizzaObject.slices [color=#666666]" slices left."[/color]

Eat(foodAddress) {
    [color=#107095]MsgBox[/color] % [color=#666666]"Eat("[/color] foodAddress [color=#666666]")"[/color]
    foodObject := [color=#107095]Object[/color](foodAddress)  ; Convert the address back into an object reference.
    foodObject.slices := foodObject.slices - 1  ; Take a slice.
}
Non-sliced food handling excluded for brevity.

trock
  • Guests
  • Last active:
  • Joined: --
First of all, thank you all for the extra features in AutoHotkey_L.
Through the COM support I am now able to parse and write XML in an easy fast way. Great :D

Back to the topic:
A while ago I found this script stdio.ahk here in the forum.

I tried it in ansi build and it worked fine, but I couldn't get it run in unicode build.

The part I am using from this script is:
DllCall("AttachConsole", int, -1, int)

printf(str)
{
   str = [%str%] ;convert escape characters while preserving leading and trailing spaces and not changing AutoTrim
   StringTrimLeft, str, str, 1
   StringTrimRight, str, str, 1
   if (hStdout := DllCall("GetStdHandle", "int", -11))
      return DllCall("WriteFile", "uint", hStdout, "uint", &str, "uint", strlen(str), "uint", malloc(BytesWritten, 4), "uint", NULL)
}

I read the help and several threads in the forum, but I have no glue what to do, because DllCall is one of the things I am just a step to far away from as not being an developer.

What happens is that the output in a command prompt has as every second character a space.
Therefore I think this is somehow related to encoding.

Thanks in advance.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Therefore I think this is somehow related to encoding.

You are quite right. You are writing Unicode text into stdout, which is not what the console is expecting. Have you read Script Compatibility? In particular, note the example using "Ptr", which is usually equivalent to "UInt" (as noted below that) and note when "AStr" may be used in its place.

Alternatively, you can use FileAppend, text, * to write to stdout in both AutoHotkey Basic and AutoHotkey_L. You can use CONOUT$ in place of * to write to the console in cases where it's not the same as stdout. Since this topic is about AutoHotkey_L, I'm compelled to demonstrate the following: ;)
DllCall("AttachConsole", "int", -1, "int") || DllCall("AllocConsole")

conout := [color=#107095]FileOpen[/color]([color=#666666]"CONOUT$"[/color], [color=#666666]"w"[/color])
conout.[color=#107095]WriteLine[/color]([color=#666666]"Written with FileOpen CONOUT$"[/color])
stdout := [color=#107095]FileOpen[/color]([color=#107095]DllCall[/color]([color=#666666]"GetStdHandle"[/color], [color=#666666]"int"[/color], -11), [color=#666666]"h"[/color])
stdout.[color=#107095]WriteLine[/color]([color=#666666]"Written with FileOpen *"[/color])

MsgBox
See FileOpen and File Object.

trock
  • Guests
  • Last active:
  • Joined: --
Thank you for the fast answer.
I tried it and it works perfect.
I am happy, that you felt being compelled to demonstrate your example :wink:

I read the Script Compatibility, but I didn't understand anything around PTR and UInt and AStr and how and when to use it...
I love AutoHotkey, because it's so easy to use even if your not a developer like me.
I would not be able to transform the original code I posted into unicode code.

Even if I understand your example, I can't see the way to find it without your help.
With parsing a XML file I followed your link to the microsoft page, but I struggle to find this information by myself.

So thanks for your help.

Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
Thanks a lot for your time and your answers :)

I wonder if this script it's the good way for use an object like a table, without memory leak or other wrong effect... However an example script can be good into helpfile.chm for know how manage a simple table object ( for a noob like me )

MyTable:=Object()
MyTable["obj_name"]:="MyTable"

; R= Row , C= Column
MyTable["R1","C1"]:="R1C1" , MyTable["R1","C2"]:="R1C2" , MyTable["R1","C3"]:="R1C3"
MyTable["R2","C1"]:="R2C1" , MyTable["R2","C2"]:="R2C2" , MyTable["R2","C3"]:="R2C3"
MyTable["R3","C1"]:="R3C1" , MyTable["R3","C2"]:="R3C2" , MyTable["R3","C3"]:="R3C3"


; Delete a Row
MyTable.Remove("R2")

; Delete a Column
for k1, v1 in MyTable
  MyTable[k1].Remove("C2")


for k1, v1 in MyTable
{
;  if (k1="obj_name")
;    continue
;  msgbox % k1 "=" v1
  for k2, v2 in MyTable[k1]
    msgbox % k1 "=" v1 " | " k2 "=" v2
}

@jethrow:
don't quote me, it's not a good find name :X
<!-- m -->http://www.autohotke... ... 014#392014<!-- m -->
obj := Object() 
obj.test.var := "does not work" 
obj["test", "var"] := "works"