Referencing a global variable (via its address as shown in my previous post) is unreliable. Assigning an object to the global variable changes its address, that is
this.__Ptr != &g_Variable, so there is no way to keep track of it. Might as well use a custom object that acts as a variable:
Code: Select all
g_Var := new Variable("Hello World") ; initialize, assign value
MsgBox % "Value: " . g_Var.Value . "`nType: " . g_Var.Type . "`nCapacity: " . g_Var.Capacity
g_Var.Value := 123 ; assign integer
MsgBox % "Value: " . g_Var.Value . "`nType: " . g_Var.Type . "`nCapacity: " . g_Var.Capacity
; use var as struct
g_Var.Capacity := 16 ; set capacity, RECT
DllCall("GetWindowRect", "Ptr", A_ScriptHwnd, "Ptr", g_Var[]) ; address of buffer
RECT := Format("
(Join`r`n
Script's Main Window RECT
Left: {}
Top: {}
Right: {}
Bottom: {}
)", NumGet(g_Var[], 0, "Int"), NumGet(g_Var[], 4, "Int"), NumGet(g_Var[], 8, "Int"), NumGet(g_Var[], 12, "Int"))
ListVars
ControlSetText, Edit1, %RECT%, ahk_id %A_ScriptHwnd%
WinWaitClose ahk_id %A_ScriptHwnd%
return
class Variable
{
__New(value)
{
this.__Value := value
}
__Get(key:="", args*)
{
if !key
return ObjGetAddress(this, "__Value") ; blank if there is no string buffer
}
Value {
get {
return this.__Value
}
set {
return this.__Value := value
}
}
Type {
get {
return IsObject(this.Value) ? "Object"
: this.Capacity != "" ? "String"
: InStr(this.Value, ".") ? "Float"
: "Integer"
}
}
Capacity[FillByte:=0] {
get {
return ObjGetCapacity(this, "__Value")
}
set { ; emulate VarSetCapacity(), that is to always clear the buffer
if (this.Type != "String")
this.__Value := "" ; assign string or else address is blank
ObjSetCapacity(this, "__Value", 0) ; free buffer first
ObjSetCapacity(this, "__Value", value) ; set new capacity
DllCall("RtlFillMemory", "Ptr", this[], "UPtr", value, "UChar", FillByte) ; fill memmory
}
}
}