Jump to content
genius257

AutoItObject Pure AutoIt

Recommended Posts

genius257

I've made a library, based on AutoItObject UDF with the goal of implementing getter and setter functionality and make it possible to define new object properties in as few steps as possible.

Thank you to @trancexx for getting me on the right track, and all users in Hooking into the IDispatch interface for the code to get me going.

If I've forgotten to add credit, please let me know :)

Example:

#include "AutoItObject_Internal.au3"
$myCar = IDispatch()
$myCar.make = 'Ford'
$myCar.model = 'Mustang'
$myCar.year = 1969
$myCar.__defineGetter('DisplayCar', DisplayCar)

Func DisplayCar($oThis)
    Return 'A Beautiful ' & $oThis.parent.year & ' ' & $oThis.parent.make & ' ' & $oThis.parent.model
EndFunc

MsgBox(0, "", $myCar.DisplayCar)

More examples: https://github.com/genius257/AutoIt-projects/tree/master/AutoItObject Internal/Examples

Version: 1.0.3

AutoItObject_Internal.au3

Documentation:

 

README.md3.png

Edit2 (19th March 2017):

First of all, sorry about the lack of updates on this project. I always start too many projects and end up ignoring old projects, if I run into problems ^^'.

So I've started moving my AutoIt scripts to GitHub. I will still post the most recent script version here.

Edited by genius257
  • Like 4

Share this post


Link to post
Share on other sites
Chimp

This seems something very interesting.... and even more when support for adding methods will be ready.
...worth stay tuned.... :)
Thanks for sharing.

p.s.
this line in AutoItObject_Internal.au3 raises an error:

If $iID==-1 Then Return Return $DISP_E_UNKNOWNNAME

 

Edited by Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites
genius257
7 hours ago, Chimp said:

This seems something very interesting.... and even more when support for adding methods will be ready.
...worth stay tuned.... :)
Thanks for sharing.

p.s.
this line in AutoItObject_Internal.au3 raises an error:

If $iID==-1 Then Return Return $DISP_E_UNKNOWNNAME

 

Glad you like it ;)

Sorry about the error. My SciTE did not warn me, but after installing "SciTE4AutoIt3.exe" i now see what you mean ^^

I'll fix and re-upload immediately

Share this post


Link to post
Share on other sites
genius257

version: 0.1.2

added basic support for methods via "__defineMethod" will update example.

 

Edit:

I been spending all this time looking into function reference, but it might be impossible, without knowing the structure Autoit uses. I feel like i got as close as i could, without just poking the bytes and hoping to get lucky. So I've added the above to try and get somewhat the same result.

Please inform me, if someone can help me with this.

Edited by genius257

Share this post


Link to post
Share on other sites
genius257

version: 1.0.0

Every type should now be supported with ease.

"__defineMethod" is now deprecated

"__unset" added

"__lock" added

Documentation will be above for most recent release, or on GitHub for older releases.

Edited by genius257
  • Like 1

Share this post


Link to post
Share on other sites
junkew

Nice. Some suggestions to join knowledge

Check also clr thread where we are working on c# clr solution for .net objects integrating into autoit..

Check oope.au3

Search for running object table in forums by trancex as it registers object on the fly so you can reach it from for example vbscript or other com languages.

 

Share this post


Link to post
Share on other sites
genius257

version: 1.0.2

"__keys" added

"arguments" property added to AccessorObject.

see documentation above for more info.

 

Example to show one way to use the arguments property and to show it works with things such as ScriptControl:

#include "AutoItObject_Internal.au3"

#AutoIt3Wrapper_Run_Au3Check=N

$AutoItError = ObjEvent("AutoIt.Error", "ErrFunc") ; Install a custom error handler
Func ErrFunc($oError)
    ConsoleWrite("!>COM Error !"&@CRLF&"!>"&@TAB&"Number: "&Hex($oError.Number,8)&@CRLF&"!>"&@TAB&"Windescription: "&StringRegExpReplace($oError.windescription,"\R$","")&@CRLF&"!>"&@TAB&"Source: "&$oError.source&@CRLF&"!>"&@TAB&"Description: "&$oError.description&@CRLF&"!>"&@TAB&"Helpfile: "&$oError.helpfile&@CRLF&"!>"&@TAB&"Helpcontext: "&$oError.helpcontext&@CRLF&"!>"&@TAB&"Lastdllerror: "&$oError.lastdllerror&@CRLF&"!>"&@TAB&"Scriptline: "&$oError.scriptline&@CRLF)
EndFunc ;==>ErrFunc

Example01()
Example02()

Func Example01()
    Local $o=IDispatch()
    $o.__defineGetter("a", _MsgBox)
    Local $oSC=ObjCreate("ScriptControl")
    $oSC.language = "JScript"
    ($oSC.Eval("Function('e','return e.a;')"))($o)
EndFunc

Func Example02()
    Local $oWindow = IDispatch()
    $oWindow.hwnd = GUICreate("title", 700, 320)
    $oWindow.__defineGetter("Show", Wnd_Show)
    $oWindow.__defineGetter("Hide", Wnd_Hide)
    $oWindow.__defineGetter("bkColor", Wnd_bkColor)
    $oWindow.__defineGetter("width", Wnd_width)
    $oWindow.__defineGetter("height", Wnd_height)
    $oWindow.__defineGetter("title", Wnd_title)
    $oWindow.__defineGetter("onExit", Wnd_onExit)

    $oWindow.Show.width(300).bkColor(0xC2E34E).height(300).title("Example 2").onExit(_MyExit)

    While 1
        Sleep(10)
    WEnd
EndFunc

Func _MsgBox()
    Return MsgBox(0, "_MsgBox", "test")
EndFunc

Func Wnd_Show($oSelf)
    GUISetState(@SW_SHOW, $oSelf.parent.hwnd)
    Return $oSelf.parent
EndFunc

Func Wnd_Hide($oSelf)
    GUISetState(@SW_HIDE, $oSelf.parent.hwnd)
    Return $oSelf.parent
EndFunc

Func Wnd_bkColor($oSelf)
    If Not ($oSelf.arguments.length==1) Then Return SetError(1, 1, $oSelf.parent
    GUISetBkColor($oSelf.arguments.values[0], $oSelf.parent.hwnd)
    Return $oSelf.parent
EndFunc

Func Wnd_width($oSelf)
    If Not ($oSelf.arguments.length==1) Then Return SetError(1, 1, $oSelf.parent
    Local $aPos = WinGetPos(ptr($oSelf.parent.hwnd), "")
    WinMove(ptr($oSelf.parent.hwnd), "", $aPos[0], $aPos[1], $oSelf.arguments.values[0], $aPos[3], 0)
    Return $oSelf.parent
EndFunc

Func Wnd_height($oSelf)
    If Not ($oSelf.arguments.length==1) Then Return SetError(1, 1, $oSelf.parent
    Local $aPos = WinGetPos(ptr($oSelf.parent.hwnd))
    WinMove(ptr($oSelf.parent.hwnd), "", $aPos[0], $aPos[1], $aPos[2], $oSelf.arguments.values[0], 0)
    Return $oSelf.parent
EndFunc

Func Wnd_title($oSelf)
    If Not ($oSelf.arguments.length==1) Then Return SetError(1, 1, $oSelf.parent)
    WinSetTitle(ptr($oSelf.parent.hwnd), "", $oSelf.arguments.values[0])
    Return $oSelf.parent
EndFunc

Func Wnd_onExit($oSelf)
    If Not ($oSelf.arguments.length==1) Then Return SetError(1, 1, $oSelf.parent)
    opt("GuiOnEventMode", 1)
    GUISetOnEvent(-3, $oSelf.arguments.values[0], ptr($oSelf.parent.hwnd))
EndFunc

Func _MyExit()
    Exit
EndFunc

 

Edited by genius257
Example added
  • Like 1

Share this post


Link to post
Share on other sites
junkew

Q1. How would I do this when I want both parameters to come from a string

$methodName="onJump"
$newMethod="myClass_onJump"

$myObject=iDispatch()
$myObject.__defineGetter($methodName, $newMethod)

func myClass_onJump()
  consolewrite("jump")
endfunc

So i do not want this I want a more dynamic way 

$myObject.__defineGetter("onJump",  myClass_OnJump)

Q2. How would I clone an object that is created?

 

Edited by junkew

Share this post


Link to post
Share on other sites
genius257
On 31/5/2018 at 1:51 AM, junkew said:

Q1. How would I do this when I want both parameters to come from a string

$methodName="onJump"
$newMethod="myClass_onJump"

$myObject=iDispatch()
$myObject.__defineGetter($methodName, $newMethod)

func myClass_onJump()
  consolewrite("jump")
endfunc

So i do not want this I want a more dynamic way 

$myObject.__defineGetter("onJump",  myClass_OnJump)

Q2. How would I clone an object that is created?

 

Hi @junkew, I'm glad to know there still is interest for my project ;)

A1. Hmmmm. currently, you would need to check for that yourself. See the code below for an example :) If you want, you are more than welcome to create an issue on github for it, and i will implement it :)

#include "AutoItObject_Internal.au3"

#AutoIt3Wrapper_Run_Au3Check=N

if Not IsDeclared("E_HANDLE") Then Global Const $E_HANDLE = 0x80070006
if Not IsDeclared("E_POINTER") Then Global Const $E_POINTER = 0x80004003
if Not IsDeclared("E_NOINTERFACE") Then Global Const $E_NOINTERFACE = 0x80004002
if Not IsDeclared("S_OK") Then Global Const $S_OK = 0x00000000
if Not IsDeclared("E_INVALIDARG") Then Global Const $E_INVALIDARG = 0x80070057
if Not IsDeclared("E_NOTIMPL") Then Global Const $E_NOTIMPL = 0x80004001

$methodName="onJump"
$newMethod="myClass_onJump"

$myObject=MyObject($methodName, $newMethod)

$myObject.onJump

func myClass_onJump()
  consolewrite("jump"&@CRLF)
endfunc

Func MyObject($methodName, $newMethod)
    Local $myObject = IDispatch()

    $newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)
    If Not IsFunc($newMethod) Then Return SetError(1, 0, 0)

    $myObject.__defineGetter($methodName, $newMethod)

    Return SetError(0, 0, $myObject)
EndFunc

A2. The current public version does not support cloning. It is a feature i have planned :) It will come out with the next version, where i also will take big inspiration from JS Object methods, such as freezevalues and for your interest assign. Currently the way to clone an objects property/properties would be to create a new empty object and fetch the desired properties from the structure of the original object, call VariantCopy on each and and assign them to the new object's Properties element in the $tagObject struct. They are in a linked list, so extending the list is easy enough :) Let me know if you want some code to illustrate this :)

I hope my answer will satisfy your questions, and sorry for the delay with the answer :)

  • Like 1

Share this post


Link to post
Share on other sites
junkew

I think in this forum are about a dozen people that understand the power of your library and only a handfull that can write it :). With your library and some others as mentioned before we could write in a more oo syntax then currently is possible. So keep up the great piece of work you made and offcourse credits to all people involved in AIO and objcreateinterface.

  • Like 2

Share this post


Link to post
Share on other sites
xroot

Junkew is right about "AutoItObject_Internal.au3" way over my head but very cool.
I like Pure AutoIt stuff, keep it simple and use as much AutoIt internal as possible.
I see JScript was used in an example which got me thinking about OBJECTS.
JScript can create the objects, properties, methods in Au3.

JScript Example 1

Func ObjErrFunc()
    Msgbox(0,"*COM ERROR*",$ObjErr.windescription & @lf & $ObjErr.description & @LF & "Line=" & $ObjErr.scriptline)
EndFunc

Func jsc($IO)
    $jsCode &= $IO & @CRLF
EndFunc

global $ObjErr = ObjEvent("AutoIt.Error","ObjErrFunc")
global $sc     = ObjCreate("ScriptControl")
global $jsCode = ""
$sc.Language   = "JScript"

jsc('function myCar(){')
    jsc('this.make       = "";')
    jsc('this.model      = "";')
    jsc('this.year       = 0;')
    jsc('this.DisplayCar = function(){return "A Beautiful "+this.year+" "+this.make+" "+this.model;}};')

; MsgBox(0,"jScript",$jsCode)
$sc.AddCode($jsCode)

local $myCar = $sc.Eval("new myCar")
$myCar.make  = "Ford"
$myCar.model = "Mustang"
$myCar.year  = 1969

MsgBox(64,"JS Returns",$myCar.DisplayCar())

The second example was very interesting.
To keep it Au3 pure, I used "AutoItX3.Control" and AutoIt3.exe /AutoIt3ExecuteLine.

JScript Example 2

Func ObjErrFunc()
    Msgbox(0,"*COM ERROR*",$ObjErr.windescription & @lf & $ObjErr.description & @LF & "Line=" & $ObjErr.scriptline)
EndFunc

Func jsc($IO)
    $jsCode &= $IO & @CRLF
EndFunc

Func bkColor($hWnd,$iMsg,$wParam,$lParam)
    GUISetBkColor($wParam,$hWnd)
EndFunc

Func GuiLoop()
    While GUIGetMsg() <> -3
        Sleep(10)
    WEnd
EndFunc

global $ObjErr = ObjEvent("AutoIt.Error","ObjErrFunc")
global $sc     = ObjCreate("ScriptControl")
global $jsCode = ""
$sc.Language   = "JScript"

jsc('var au3x   = new ActiveXObject("AutoItX3.Control");')
jsc('var au3exe = "c:/Program Files (x86)/AutoIt3/AutoIt3.exe /AutoIt3ExecuteLine ";')
jsc('var width = 0,height = 0;')

jsc('function Au3_Objects(){')
    jsc('this.hWnd    = 0;')
    jsc('this.Title   = function(t){au3x.WinSetTitle("","",t);return this;}')
    jsc('this.bkColor = function(c){au3x.Run(au3exe+"\"DllCall(''user32'',''lresult'',''SendMessage'',''hwnd'',"+this.hWnd+",''uint'',1024,''wparam'',"+c+",''lparam'',0)\"");return this;}')
    jsc('this.Width   = function(w){au3x.WinMove("","",('&@desktopwidth&'-w)/2,('&@desktopheight&'-height)/2,w,height);width = w;return this;}')
    jsc('this.Height  = function(h){au3x.WinMove("","",('&@desktopwidth&'-width)/2,('&@desktopheight&'-h)/2,width,h);height = h;return this;}')
    jsc('this.Show    = function(){au3x.Run(au3exe+"\"GUISetState()\"");return this;}}')

; MsgBox(0,"jScript",$jsCode)
$sc.AddCode($jsCode)

local $gui = $sc.eval("new Au3_Objects")

$gui.hWnd = GUICreate("Normal Au3 Gui 1")
GUISetBkColor(0xffff00)
GUIRegisterMsg(1024,"bkColor")
GUISetState()
GuiLoop()

$gui.Title("Objects Au3 Gui 2").bkColor(0xff00ff).Width(400).Height(600).Show()
GuiLoop()

With $gui
    .Title("Objects Au3 Gui 3")
    .bkColor(0x00ff00)
    .Width(800)
    .Height(300)
    .Show()
EndWith
GuiLoop()

 

Share this post


Link to post
Share on other sites
Earthshine

how did i miss this? thank you guys. I am so playing around with this on Monday morning

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
junkew

@genius257 

  • Any more magic in this Execute("string")?

so this Execute($newMethod) seems to do the trick but reading help and manual I am surprised on this (powerfull) behavior

$newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)

As above does not trigger the jump function to execute that happens later when you

$myObject.onJump

 

 

Some code

I played around with referencing variables to functions ($class, $endclass etc)  to see if with some syntactic sugar we could make it more OO syntax

  • using $<some oo syntax> looks nice to my feeling as some kind of annotator tags before method/property definition
  • No additional scanning of coding needed
  • Makes life a little easier then the initial syntax of iDispatch()
  • TODO:
    • Manage the objects/classes  (I feel with assign/eval/execute or in an overall array of class/objects)
    • get some feedback if people like below OO-syntax
    • no workaround I feel for Classname_methodName syntax with underscores

 

#include <AutoItConstants.au3>
#include <AutoItObject_Internal.au3>

if Not IsDeclared("E_HANDLE") Then Global Const $E_HANDLE = 0x80070006
if Not IsDeclared("E_POINTER") Then Global Const $E_POINTER = 0x80004003
if Not IsDeclared("E_NOINTERFACE") Then Global Const $E_NOINTERFACE = 0x80004002
if Not IsDeclared("S_OK") Then Global Const $S_OK = 0x00000000
if Not IsDeclared("E_INVALIDARG") Then Global Const $E_INVALIDARG = 0x80070057
if Not IsDeclared("E_NOTIMPL") Then Global Const $E_NOTIMPL = 0x80004001
    
;~ #AutoIt3Wrapper_Run_Au3Check=N

#REGION putInIncludeLater

;~ Create some function variables to create a nicer class syntax
global $g_lastClassReferenced
$class=createClass
$property=createProperty
$method=createMethod
$endClass=endClass

;~ Some initial implementations behind the nice function variables
func createClass($className)
    consolewrite("Creating class " & $className & @CRLF)
    $g_lastClassReferenced=IDispatch()
    $g_lastClassReferenced.className=$className
    consolewrite("Created class  " & $g_lastClassReferenced.className & @CRLF)
    $result=assign($className,$g_lastClassReferenced, $ASSIGN_FORCEGLOBAL)
EndFunc

func endClass($dummy=0)
    consolewrite("Ending class definition " & $g_lastClassReferenced.className & @CRLF)
EndFunc

func createProperty($propName)
    $newMethod=$g_lastClassReferenced.className & "_set_" & $propName
    $newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)
;~     'If there is a setter function defined
    If IsFunc($newMethod) Then 
        $g_lastClassReferenced.__defineSetter($propName, $newMethod)
    EndIf

    $newMethod=$g_lastClassReferenced.className & "_get_" & $propName
    $newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)
;~     'If there is a setter function defined
    If IsFunc($newMethod) Then 
        $g_lastClassReferenced.__defineGetter($propName, $newMethod)
    EndIf
    
;~  assign($newProp,"",$ASSIGN_FORCEGLOBAL)
    consolewrite("This could work " & $propName & @CRLF)
EndFunc

func defaultGet($oSelf)
    consolewrite("Default get with paramcount "& $oSelf.arguments.length & @CRLF)
EndFunc

func createMethod($methodName)
    $newMethod=$g_lastClassReferenced.className & "_" & $methodName
    $newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)
    If Not IsFunc($newMethod) Then Return SetError(1, 0, 0)

    $g_lastClassReferenced.__defineGetter($methodName, $newMethod)

;~  assign($newMethod,"",$ASSIGN_FORCEGLOBAL)
    consolewrite("This could work " & $newMethod & @CRLF)
EndFunc

func new($className)
    consolewrite("Instantiate object " & $className & @CRLF)
;~ TODO: Now we get the classObject whereas we should actually make a clone
    return eval($className)
EndFunc
#EndRegion
;~ Each class could be in its own include file, REGION there only for testing 
#REGION class Foo
$class("Foo")
    $property("Property1")
    func Foo_set_Property1()
        consolewrite("Hmmm, looks funny Foo_set_Property1" & @CRLF)
    EndFunc
    func Foo_get_Property1()
        consolewrite("Hmmm, looks funny Foo_get_Property1" & @CRLF)
    EndFunc 

    $property("Property2")
    func Foo_set_Property2()
        consolewrite("Hmmm, looks funny Foo_get_Property2" & @CRLF)
    EndFunc
    func Foo_get_Property2()
        consolewrite("Hmmm, looks funny Foo_get_Property2" & @CRLF)
    EndFunc 
    $method("method1")
    func Foo_method1()
        consolewrite("Hmmm, looks funny Foo_method1" & @CRLF)
    EndFunc
    $method("method2")
    func Foo_method2()
        consolewrite("Hmmm, looks funny Foo_method2" & @CRLF)
    EndFunc
    $method("method3")
    func Foo_method3()
        consolewrite("Hmmm, looks funny 3" & @CRLF)
    EndFunc
$endClass("Foo")
#EndRegion

#REGION class bar
$class("Bar")
    $property("Property1")
    func Bar_set_Property1()
        consolewrite("Hmmm, looks funny Bar_set_Property1" & @CRLF)
    EndFunc
    func Bar_get_Property1()
        consolewrite("Hmmm, looks funny Bar_get_Property1" & @CRLF)
    EndFunc 

    $property("Property2")
    func Bar_set_Property2()
        consolewrite("Hmmm, looks funny Bar_get_Property2" & @CRLF)
    EndFunc
    func Bar_get_Property2()
        consolewrite("Hmmm, looks funny Bar_get_Property2" & @CRLF)
    EndFunc 
    $method("method1")
    func Bar_method1()
        consolewrite("Hmmm, looks funny Bar_method1" & @CRLF)
    EndFunc
    $method("method2")
    func Bar_method2()
        consolewrite("Hmmm, looks funny Bar_method2" & @CRLF)
    EndFunc
    $method("method3")
    func Bar_method3()
        consolewrite("Hmmm, looks funny 3" & @CRLF)
    EndFunc
$endClass("Bar")
#EndRegion

;~ ##### Actual program ######
Consolewrite ("##### Actual program ######")
$oFoo1=new("Foo")
$oFoo2=new("Foo")
$oBar1=new("BAR")
$oBar2=new("BAR")

consolewrite("is object " & isobj($oFoo1) & @CRLF)
consolewrite("is object " & $oFoo1.Property1 & @CRLF)
$oFoo1.method1()
$oFoo2.method1()
$oBar1.method1()
$oBar2.method1()

 

Share this post


Link to post
Share on other sites
genius257

@junkew

On 2/6/2018 at 11:49 PM, junkew said:

I think in this forum are about a dozen people that understand the power of your library and only a handfull that can write it :). With your library and some others as mentioned before we could write in a more oo syntax then currently is possible. So keep up the great piece of work you made and offcourse credits to all people involved in AIO and objcreateinterface.

Thank you for the kind words.

 

22 hours ago, junkew said:

Any more magic in this Execute("string")?

Lots, i would say :)

22 hours ago, junkew said:

so this Execute($newMethod) seems to do the trick but reading help and manual I am surprised on this (powerfull) behavior

$newMethod = IsFunc($newMethod) ? $newMethod : Execute($newMethod)

As above does not trigger the jump function to execute that happens later when you

$myObject.onJump

 

Yeah Execute runs the litteral string as AutoIt script, so if it's a function name, we get a UserFunction or Function type variable returned.

$myObject.jump triggers the getter accessor (if it is exists) and within your getter function, you can return computed values.

 

22 hours ago, junkew said:

Some code

I do like your idea, but i try to use as few global variables as possible on purpose :)

The less chance to confict with other user functions/variables the better :)

This could be a nice fork of my project, giving people even more choices :)

 

I do understand the issue you have with the IDispatch approach. The truth is this library is more akin to JS objects, as to classes.

My personal approach to classes so far have been like this:

#Region Actual script
#include <Array.au3>
#include "AutoItObject_Internal.au3"

if Not IsDeclared("E_HANDLE") Then Global Const $E_HANDLE = 0x80070006
if Not IsDeclared("E_POINTER") Then Global Const $E_POINTER = 0x80004003
if Not IsDeclared("E_NOINTERFACE") Then Global Const $E_NOINTERFACE = 0x80004002
if Not IsDeclared("S_OK") Then Global Const $S_OK = 0x00000000
if Not IsDeclared("E_INVALIDARG") Then Global Const $E_INVALIDARG = 0x80070057
if Not IsDeclared("E_NOTIMPL") Then Global Const $E_NOTIMPL = 0x80004001

#AutoIt3Wrapper_Run_Au3Check=N

$oFoo = Foo()

$oFoo.Property1 = "I love AutoIt"
$oFoo.Property2 = "I love AutoIt"
$oFoo.Property3 = "I love AutoIt"
$oFoo.Property4 = "really"

For $i=0 To 9
    ConsoleWrite( _
        $oFoo.Property1 & @CRLF & _
        $oFoo.Property2 & @CRLF & _
        $oFoo.Property3 & @CRLF & _
        $oFoo.Property4 & @CRLF & _
        @CRLF _
    )
Next

#cs
# Chained calls
#ce
$oFoo.Write($oFoo.Property1).Write($oFoo.Property2).Write($oFoo.Property3).Write($oFoo.Property4)

#cs
# Dynamic number of parameters
#ce
$oFoo.Write($oFoo.Property1, $oFoo.Property2, $oFoo.Property3, $oFoo.Property4)
#EndRegion Actual script

#Region Foo.au3
    Func Foo()
        Local $fooClassInstance = IDispatch()

        $fooClassInstance.Property1 = "string value";normal variable

        $fooClassInstance.Property2 = "";"computed" variable out
        $fooClassInstance.__defineGetter("Property2", Foo_Property2_Get)

        $fooClassInstance.Property3 = "";"computed" variable in
        $fooClassInstance.__defineSetter("Property3", Foo_Property3_Set)

        $fooClassInstance.Property4 = "";"computed" variable in & out
        $fooClassInstance.__defineGetter("Property4", Foo_Property4_Get)
        $fooClassInstance.__defineSetter("Property4", Foo_Property4_Set)

        $fooClassInstance.Write = ConsoleWrite;internal property used as a setter that returns relf for continues calls
        $fooClassInstance.__defineGetter("Write", Foo_Write_Get)

        $fooClassInstance.__lock();prevent additional properties to be created

        Return $fooClassInstance
    EndFunc

    #cs
    # Reverses the value of Property2 and returns it.
    # @param $oThis - IDispatch internal accessor object
    #ce
    Func Foo_Property2_Get($oThis)
        Local $value = $oThis.val
        If Not IsString($value) Then Return $value
        $value = StringReverse($value)
        $oThis.val = $value
        Return $value
    EndFunc

    #cs
    # Shuffles the provided string value and sets it as
    # @param $oThis - IDispatch internal accessor object
    #ce
    Func Foo_Property3_Set($oThis)
        Local $value = $oThis.ret
        If Not IsString($value) Then Return SetError(2, 0, 0)
        $value = StringSplit($value, "", 2)
        _ArrayShuffle($value)
        $oThis.val = _ArrayToString($value, "")
    EndFunc

    #cs
    # Randomly sets each char in Property4 value to upper or lower case and returns it
    # @param $oThis - IDispatch internal accessor object
    #ce
    Func Foo_Property4_Get($oThis)
        Local $value = $oThis.val
        $value = StringSplit($value, "", 2)
        For $i=0 To UBound($value)-1
            $value[$i] = Random(0, 1, 1) ? StringUpper($value[$i]) : StringLower($value[$i])
        Next
        $value = _ArrayToString($value, "")
        Return $value
    EndFunc

    #cs
    # Adds provided string as an adverb in a proclamation for AutoIt love and sets it as Property4 value
    #ce
    Func Foo_Property4_Set($oThis)
        $oThis.val = StringFormat("I %s love AutoIt", $oThis.ret)
    EndFunc

    Func Foo_Write_Get($oThis)
        Local $i
        Local $self = $oThis.parent
        Local $length = $oThis.arguments.length
        Local $values = $oThis.arguments.values
        For $i=0 To $length-1
            ConsoleWrite($values[$i] & @CRLF)
        Next
        ConsoleWrite(@CRLF)
        Return $self
    EndFunc
#EndRegion Foo.au3

 

Edit:

Here is an example for nested objects used with accessors

Edited by genius257

Share this post


Link to post
Share on other sites
genius257
On 3/6/2018 at 4:12 PM, xroot said:

Junkew is right about "AutoItObject_Internal.au3" way over my head but very cool.
I like Pure AutoIt stuff, keep it simple and use as much AutoIt internal as possible.
I see JScript was used in an example which got me thinking about OBJECTS.
JScript can create the objects, properties, methods in Au3.

JScript Example 1

Func ObjErrFunc()
    Msgbox(0,"*COM ERROR*",$ObjErr.windescription & @lf & $ObjErr.description & @LF & "Line=" & $ObjErr.scriptline)
EndFunc

Func jsc($IO)
    $jsCode &= $IO & @CRLF
EndFunc

global $ObjErr = ObjEvent("AutoIt.Error","ObjErrFunc")
global $sc     = ObjCreate("ScriptControl")
global $jsCode = ""
$sc.Language   = "JScript"

jsc('function myCar(){')
    jsc('this.make       = "";')
    jsc('this.model      = "";')
    jsc('this.year       = 0;')
    jsc('this.DisplayCar = function(){return "A Beautiful "+this.year+" "+this.make+" "+this.model;}};')

; MsgBox(0,"jScript",$jsCode)
$sc.AddCode($jsCode)

local $myCar = $sc.Eval("new myCar")
$myCar.make  = "Ford"
$myCar.model = "Mustang"
$myCar.year  = 1969

MsgBox(64,"JS Returns",$myCar.DisplayCar())

The second example was very interesting.
To keep it Au3 pure, I used "AutoItX3.Control" and AutoIt3.exe /AutoIt3ExecuteLine.

JScript Example 2

Func ObjErrFunc()
    Msgbox(0,"*COM ERROR*",$ObjErr.windescription & @lf & $ObjErr.description & @LF & "Line=" & $ObjErr.scriptline)
EndFunc

Func jsc($IO)
    $jsCode &= $IO & @CRLF
EndFunc

Func bkColor($hWnd,$iMsg,$wParam,$lParam)
    GUISetBkColor($wParam,$hWnd)
EndFunc

Func GuiLoop()
    While GUIGetMsg() <> -3
        Sleep(10)
    WEnd
EndFunc

global $ObjErr = ObjEvent("AutoIt.Error","ObjErrFunc")
global $sc     = ObjCreate("ScriptControl")
global $jsCode = ""
$sc.Language   = "JScript"

jsc('var au3x   = new ActiveXObject("AutoItX3.Control");')
jsc('var au3exe = "c:/Program Files (x86)/AutoIt3/AutoIt3.exe /AutoIt3ExecuteLine ";')
jsc('var width = 0,height = 0;')

jsc('function Au3_Objects(){')
    jsc('this.hWnd    = 0;')
    jsc('this.Title   = function(t){au3x.WinSetTitle("","",t);return this;}')
    jsc('this.bkColor = function(c){au3x.Run(au3exe+"\"DllCall(''user32'',''lresult'',''SendMessage'',''hwnd'',"+this.hWnd+",''uint'',1024,''wparam'',"+c+",''lparam'',0)\"");return this;}')
    jsc('this.Width   = function(w){au3x.WinMove("","",('&@desktopwidth&'-w)/2,('&@desktopheight&'-height)/2,w,height);width = w;return this;}')
    jsc('this.Height  = function(h){au3x.WinMove("","",('&@desktopwidth&'-width)/2,('&@desktopheight&'-h)/2,width,h);height = h;return this;}')
    jsc('this.Show    = function(){au3x.Run(au3exe+"\"GUISetState()\"");return this;}}')

; MsgBox(0,"jScript",$jsCode)
$sc.AddCode($jsCode)

local $gui = $sc.eval("new Au3_Objects")

$gui.hWnd = GUICreate("Normal Au3 Gui 1")
GUISetBkColor(0xffff00)
GUIRegisterMsg(1024,"bkColor")
GUISetState()
GuiLoop()

$gui.Title("Objects Au3 Gui 2").bkColor(0xff00ff).Width(400).Height(600).Show()
GuiLoop()

With $gui
    .Title("Objects Au3 Gui 3")
    .bkColor(0x00ff00)
    .Width(800)
    .Height(300)
    .Show()
EndWith
GuiLoop()

 

Hi @xroot

Yeah i used to do a lot of JS objects with AutoIt, however there are problems, sutch as trying to execute AutoIt methods in JS or vice versa with internal variable types, or nasty memory leaks, that resulted in my script crashing after 2 minutes.

But yeah it depends on preference :) Everything has its strengths and weaknesses i guess ^^

Share this post


Link to post
Share on other sites
junkew
  • Whats the idea (naming thoughts) of parent property when you are in the setter/getter?
    I expected more like $This.string2 without .parent. in front of it
  • Offcourse I made already a mistake on infinite recursing with using $this.parent.string ;-)

Example I played with

#include <AutoItObject_Internal.au3>

$o=idispatch()
$o.string = "123";optional to define property first
$o.string2 ="just another string"

$o.__defineSetter("string", setter1)
$o.__defineGetter("string", getter1)

$o.string = "456";so what happens if I set it again
func setter1($this) 
    consolewrite($this.parent.string2 & @CRLF)
    $this.val = $this.ret & $this.ret
EndFunc

func getter1($this)
;~  $this.ret=$this.val 'Does not make sense here
    return $this.val & $this.val
EndFunc

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • FrancescoDiMuro
      By FrancescoDiMuro
      Good evening everyone
      I'm working on a little project of mines, and I was trying to use WMI Object.
      The question which I don't find an answer is: 
      Once I do the query with WMI Object, something like "SELECT * FROM Win32_LogonSession", instead of specify the field of the collection returned, ( i.e. $colItems.Caption ), can I loop though each property and each value of the property, writing so one row of code only?
      Hope my question was clear enough.
      Thanks in advance.

      Best Regards.
    • Fenzik
      By Fenzik
       Hello all"
      I have curious problem with com object implementation of Sapi 5.1.
      In some cases }Some Voice engines] the metods for retrieve the voice parameters fails with error :Member not exists:.
      But the Retrieved Voice object can speak the given text, so It exists and work.
      Example of this type of Engine can be this one: http://download.kobavision.be/KobaSpeech3/KobaSpeech 3 With Vocalizer Serena - English (Great Britain).exe (can work as demo)
      So my question is> Is there some way to workaround or solve this issue?
      What i tryed:
      1. Typical use of Sapi.spvoice object:
      $oMyError = ObjEvent("AutoIt.Error","MyErrFunc"); Install a custom error handler
       
        $spvoice = ObjCreate("sapi.spvoice")
      for $voice in $spvoice.getvoices()
        msgbox(0, "Voice", $voice.getdescription())
      next
      Func MyErrFunc()
      $HexNumber = hex($oMyError.number, 8)
      Msgbox(0,"","We intercepted a COM Error !" & @CRLF &"Number is: " & $HexNumber & @CRLF &"Windescription is: " & $oMyError.windescription)
      SetError(1)
      Endfunc

      2. Implement workaround based on Nvda Screen reader sapi5 Library at https://github.com/nvaccess/nvda/blob/master/source/synthDrivers/sapi5.py
      Thys code in Pascal should work, so i tryed to reproduce it in Autoit.
      Pascal code just as example:
                   SOTokens:=SpVoice.GetVoices('','');
                   for i:=0 to SOTokens.Count-1 do
                   try
                        SOToken:=SOTokens.Item(I); s:=SOToken.GetDescription(0);
      end
      In Autoit I tryed it like this:
      $oMyError = ObjEvent("AutoIt.Error","MyErrFunc"); Install a custom error handler
        $spvoice = ObjCreate("sapi.spvoice")
      for $i = 0 to $spvoice.getvoices.count-1
      $name = $spvoice.getvoices.item($i).getdescription
      msgbox(0,"Voice", $name)
      next
      Func MyErrFunc()
      $HexNumber = hex($oMyError.number, 8)
      Msgbox(0,"","We intercepted a COM Error !" & @CRLF &"Number is: " & $HexNumber & @CRLF &"Windescription is: " & $oMyError.windescription)
      SetError(1)
      Endfunc
      Both of this methods returning same Error ("Member not exists.").
      Thanks a lot for help.
      Znefyg
    • SchneiMi
      By SchneiMi
      Hello,
      following my previous question, I have moved all potentially instable object interactions into Executes. But it Looks like "="-assignments to object Attributes cannot be done with Execute, only method calls. Using an "$obj = 1" construct, it compares (Eval) instead of sets (Execute) the value.
      I have tested multiple different combinations, using Execute and Assign, but it seems not to work with object Attributes. :-(
      Gives following Output:
      The assign Action using apply (a3) Fails, while assigning it directly, without Assign() works fine.
      The execute versions compare and do not assign, in both cases. Though, the "Execute" topic in the help file says it executes, not evaluates.
      I have found a similar, old thread, which explains this behavious but does not give a solution. https://www.autoitscript.com/forum/topic/110228-pass-object-property-as-a-variable/  
      Is there a way to assign to a com object's Attribute? Or is there anything new to this unexpected behaviour of Execute (at least compared to the help file description and Python's exec).
       
      Any help is appreciated, and thank you for all the help so far.
      Regards, Michael
       
    • Simpel
      By Simpel
      Hi,
      since some days I become this error message exiting my app:

      Eventviewer shows following data:
      Name der fehlerhaften Anwendung: autoit3.exe, Version: 3.3.14.2, Zeitstempel: 0x55fc1979 Name des fehlerhaften Moduls: ntdll.dll, Version: 6.1.7601.23864, Zeitstempel: 0x595fa490 Ausnahmecode: 0xc000000d Fehleroffset: 0x000987e0 I stripped my code from 1500 lines down to 70:
      #include <GUIConstants.au3> Global $g_sPathToPDF = ; path to some pdf file to show Opt("GUIOnEventMode", 1) ; default ist 0 ; 1 bedeutet, daß bei Klick direkt die darunterbeschriebene Funktion ausgeführt wird Global $g_hGUI_MAIN ; Haupt-GUI Global $g_hDummy_Main ; Dummy um Fokus in der Haupt-GUI unsichtbar zu setzen Global $g_hGUI_Pruefen ; GUI zum Prüfen aller PDF Global $g_hGUI_PDF ; GUI PDF-Ansicht der ausgewählten PDF Global $g_hPDF ; ActiveX control welches das PDF enthält Global $g_oAcrobatReader ; AcrobatReaderObjekt in dem die PDF gezeigt werden _GUI_Main() GUISetOnEvent ($GUI_EVENT_CLOSE, "_Exit_Main" , $g_hGUI_MAIN) While 1 Sleep(1) WEnd Exit Func _GUI_Main() ; GUI-MAIN $g_hGUI_MAIN = GUICreate("MAIN", 390, 390, 763, 372) GUISetFont(12) GUICtrlCreateButton("NEXT", 20, 20, 350, 55, $BS_DEFPUSHBUTTON) ; Default-Knopf GUICtrlSetOnEvent(-1, "_GUI_Pruefen") GUISetState(@SW_SHOW, $g_hGUI_MAIN) ; GUI anzeigen EndFunc Func _GUI_Pruefen() ; GUI zum Prüfen der PDF GUISetState(@SW_HIDE, $g_hGUI_MAIN) ; MAIN-GUI ausblenden Opt("GUIOnEventMode", 0) ; wieder auf Default gesetzt $g_hGUI_Pruefen = GUICreate("RIGHT", 490,950, 1057, 91, -1, $WS_EX_APPWINDOW, $g_hGUI_MAIN) _AcrobatShow($g_sPathToPDF, "", 367, 91, 674, 950, $g_hGUI_Pruefen) ; PDF-GUI erstellen GUISetState(@SW_SHOW, $g_hGUI_Pruefen) ; GUI-Prüfen anzeigen Local $msg While 1 $msg = GuiGetMsg() ; Aktion mit der GUI registrieren Switch $msg ; je nach Aktion mit der GUI Case $GUI_EVENT_CLOSE ; X gedrückt $g_oAcrobatReader = "" ; zerstöre das Objekt AcrobatReader GUIDelete($g_hGUI_PDF) ; lösche die GUI-PDF GUIDelete($g_hGUI_Pruefen) ; lösche die GUI-Prüfen Opt("GUIOnEventMode", 1) ; Default 0 GUISetState(@SW_SHOW, $g_hGUI_MAIN) ; MAIN-GUI wieder zeigen Return EndSwitch WEnd EndFunc Func _Exit_Main() ; ausführen, wenn die MAIN-GUI schließt ConsoleWrite("EXIT" & @CRLF) Exit EndFunc Func _AcrobatShow($sFile, $sTitle = "PDF ", $iLeft = 50, $iTop = 0, $iWidth = 1000, $iHeight = 700, $hWnd = "") ; GUI-PDF erstellen If FileExists($sFile) Then ; wenn das PDF existiert $g_oAcrobatReader = ObjCreate("AcroPDF.PDF.1") $g_oAcrobatReader.src = $sFile ; Quelle ist das File $g_oAcrobatReader.SetLayoutMode("SinglePage") ; default "SinglePage" $g_oAcrobatReader.SetPageMode("none") ; default "none" $g_oAcrobatReader.SetShowToolbar(0) ; Tool-Bar nicht zeigen 0 $g_oAcrobatReader.SetShowScrollbars(0) ; Scroll-Balken nicht zeigen 0 $g_oAcrobatReader.SetView("fit") ; "fit" falls wer eigene Einstellungen im Reader gespeichert hat $g_hGUI_PDF = GUICreate($sTitle, $iWidth, $iHeight, $iLeft, $iTop, -1, -1, $hWnd) ; GUI als Child zu GUI-PRUEFEN erstellen - es soll nicht aktiviert werden $g_hPDF = GUICtrlCreateObj($g_oAcrobatReader, 0, 0, $iWidth, $iHeight) ; Objekt für das PDF erstellen GUICtrlSetStyle($g_hPDF, $WS_VISIBLE) ; PDF anzeigen GUISetState(@SW_SHOW, $g_hGUI_PDF) ; GUI-PDF anzeigen Else MsgBox(0, 'ERROR', "No PDF found.") EndIf EndFunc Do following steps to prove:
      - start app
      - click "next" on main gui
      - wait minimum 5 seconds (until the arrows left and right on "gui left" disappear)
      - close gui left or right
      - close main gui
      - look on console written "EXIT" the last code line before exit
      - now windows error message above appears
      The funny thing is if I don't wait the 5 seconds (before the half transparent arrows disappear) closing the gui then I will get no win error message.
      If I comment _AcrobatShow() out then the error never appears. So it seemed to be an acrobat reader issue. Every week at work there are a lot of updates, but there is no chance to know which one. But since one update this error happens.
      Any solutions? Regards, Conrad
    • WoodGrain
      By WoodGrain
      Hi All,
      I've coded the small script below, but it can't seem to get the instance of Windows Media player as it keeps going to @error, I've not used com objects before so any assistance would be appreciate. I already have WMP open and minimised. I retrieved "WMPlayerApp" from the AutoIT info tool, I've included a copy below.
      I'm using these sources:
      https://msdn.microsoft.com/en-us/library/dd564085.aspx
      https://msdn.microsoft.com/en-us/library/dd564018.aspx
      $oWMP = ObjGet("", "WMPlayerApp") If @error Then MsgBox(0, "Can't get WMP", "Couldn't connect to the WMP instance") Exit EndIf $wmpPlayState = $oWMP.playState MsgBox(0, "Play State", $wmpPlayState) $wmpSongName = $oWMP.currentMedia.name MsgBox(0, "Play State", $wmpSongName) I've also seen references to the below, but I want to get an existing open WMP:
      ObjCreate("wmplayer.OCX") and have looked at the WMP.udf but can't see how it will do either of the functions I've coded above.
       
×