Jump to content

Recommended Posts

Posted

Oh my!

You know that game - show me yours, I'll show you mine? You saw mine, you turn now.

...go on, don't be shy.

It used to be private. Something that only me and my closest friends could comprehend. Then my forum-persona took over.

C:\Users\Admiral\autoitobject\trunk

:ph34r:

  • 1 month later...
  • 2 weeks later...
Posted

Hi,

I've made a little test if we can register AutoItObject into ROT. For in-process server it works fine, the AutoItObject returned by _GetActiveObject is the one registered via _RegisterActiveObject. But, invoked via out-of-process, it crash! :pirate:

If you compare the output of inProc vs outProc - with IUnknown debugger turned on - you can see the problem start when external process invoking QueryInterface for IDispatch. A pointer returned, but then it seems OLE stop working, cuz Release never arrived (though successfully invoked).

Ain't the default marshaler should handle IDispatch automatically? I hope we can do it proxy-stub-less, if the problem is TypeLib, well I can't find any TLB in AutoItObject.dll

Here's the test code, set $OutOfProcessTest and $IUnknownDebugger to alter the test. They are initially set for debugged in-process test:

Global Const $OutOfProcessTest = False ; TRUE = out-of-process, FALSE = in-process
Global Const $IUnknownDebugger = True ; TRUE = use IUnknown stub, FALSE = pass AutoItObject directly

#include "WinAPI.au3"
#include "AutoItObject.au3"
_AutoItObject_Startup()

Global  $_ActiveObject, $_pActiveObject, _
    $_tActiveObject_Factory = DllStructCreate("ptr;" & _
        "ptr QueryInterface;" & _
        "ptr AddRef;" & _
        "ptr Release" ), _
    $_ActiveObject_Factory = DllStructGetPtr($_tActiveObject_Factory), _
    $_ActiveObject_QueryInterface = DllCallbackRegister("_ActiveObject_QueryInterface", "INT", "ptr;ptr;ptr"), _
    $_ActiveObject_AddRef = DllCallbackRegister("_ActiveObject_AddRef", "ULONG", "ptr"), _
    $_ActiveObject_Release = DllCallbackRegister("_ActiveObject_Release", "ULONG", "ptr"), _
    $_SizeOfPtr = DllStructGetSize(DllStructCreate('ptr'))
    DllStructSetData($_tActiveObject_Factory, 1, $_ActiveObject_Factory + $_SizeOfPtr)
    DllStructSetData($_tActiveObject_Factory, 'QueryInterface', DllCallbackGetPtr($_ActiveObject_QueryInterface))
    DllStructSetData($_tActiveObject_Factory, 'AddRef', DllCallbackGetPtr($_ActiveObject_AddRef))
    DllStructSetData($_tActiveObject_Factory, 'Release', DllCallbackGetPtr($_ActiveObject_Release))

#Region    >>> Win32 ActiveObject API    

#cs HRESULT CoLockObjectExternal(
  _In_  LPUNKNOWN pUnk,
  _In_  BOOL fLock,
  _In_  BOOL fLastUnlockReleases
); Ole32.dll
#ce
Func _CoLockObjectExternal ( $pIUnknown, $fLock, $fLastUnlockReleases )
    $aCall = DllCall('Ole32.DLL', 'INT', 'CoLockObjectExternal', _
                'ptr', $pIUnknown, _
                'bool', $fLock, _
                'bool', $fLastUnlockReleases )
    If @error OR $aCall[0] Then Return SetError(1, $aCall[0], 0)
EndFunc

#cs HRESULT RegisterActiveObject(
  IUnknown *punk,
  REFCLSID rclsid,
  DWORD dwFlags,
  // ACTIVEOBJECT_STRONG 0 
  // ACTIVEOBJECT_WEAK 1
  DWORD *pdwRegister
); OleAut32.dll
#ce
Func _RegisterActiveObject ( ByRef $_IDispatch, $sGUID )
    $tGUID = _GuidFromString($sGUID)
    $tHandle = DllStructCreate('dword')
    If $IUnknownDebugger Then
        $pIUnknown = $_ActiveObject_Factory
    Else
        $pIUnknown = _AutoItObject_IDispatchToPtr($_IDispatch)
    EndIf

    $aCall = DllCall('OleAut32.DLL', 'INT', 'RegisterActiveObject', _
                'ptr', $pIUnknown, _
                'ptr', DllStructGetPtr($tGUID), _
                'dword', 0x0, _
                'ptr', DllStructGetPtr($tHandle) )
    If @error OR $aCall[0] Then Return SetError(1, $aCall[0], 0)

    If NOT $IUnknownDebugger Then
        _CoLockObjectExternal($pIUnknown, True, True)
        If @error Then Return SetError(2, @extended, 0)
    EndIf

    _Log( "_RegisterActiveObject: " & $pIUnknown & " " & $sGUID )
    Return DllStructGetData($tHandle, 1)
EndFunc

#cs HRESULT GetActiveObject(
  _In_        REFCLSID rclsid,
  _Reserved_  void *pvReserved,
  _Out_       IUnknown **ppunk
); OleAut32.dll
#ce
Func _GetActiveObject ( $sGUID )
    Static Local _
        $tagIUnknown = "ptr QueryInterface;" & _
                       "ptr AddRef;" & _
                       "ptr Release", _
        $IID_IDispatch = _GuidFromString("{00020400-0000-0000-C000-000000000046}"), _
        $pIID_IDispatch = DllStructGetPtr($IID_IDispatch), _
        $E_NOINTERFACE = 0x80004002, _
        $E_POINTER     = 0x80004003

    $tGUID = _GuidFromString($sGUID)
    $tIUnknown = DllStructCreate('ptr')
    $aCall = DllCall('OleAut32.DLL', 'INT', 'GetActiveObject', _
                'ptr', DllStructGetPtr($tGUID), _
                'ptr', 0, _
                'ptr', DllStructGetPtr($tIUnknown) )
    If @error OR $aCall[0] Then Return SetError(1, $aCall[0], 0)

    $pIUnknown = DllStructGetData($tIUnknown, 1)

    If $IUnknownDebugger Then
        ; Retreive IUnknown's VTable
        $tIUnknown = DllStructCreate('ptr', $pIUnknown)
        $vtIUnknown = DllStructCreate($tagIUnknown, DllStructGetData($tIUnknown, 1))

        ; Does MSDN mean the returned IUnknown is not our object because we need
        ; to QueryInterface for IDispatch?
        ; How To Attach to a Running Instance of an Office Application
        ; [http://support.microsoft.com/kb/238975/en-us]
        ; How to get IDispatch of an Excel or Word document from an OCX
        ; [http://support.microsoft.com/kb/190985]
        $aCall = DllCallAddress("INT", DllStructGetData($vtIUnknown, 'QueryInterface'), _
                        "ptr", $pIUnknown, _
                        "ptr", $pIID_IDispatch, _
                        "ptr", DllStructGetPtr($tIUnknown) )
        If @error OR $aCall[0] Then
            If @error Then Return SetError(2, @error, 0)
            If $aCall[0] = $E_POINTER Then Return SetError(2, 0, 0) ; Invalid IUnknown
            If $aCall[0] = $E_NOINTERFACE Then Return SetError(3, 0, 0) ; IID not recognized
            Return SetError(4, $aCall[0], 0)
        EndIf
        DllCallAddress("INT", DllStructGetData($vtIUnknown, 'Release'), "ptr", $pIUnknown)  ; This call never arrived in out-of-process case (watch the log)
                                                                                            ; which is weird because previous AddRef and QueryInterface call
                                                                                            ; are arrived safely. (Marshalling failure crash Ole handler?)
        ; Now we should have the IDispatch right?
        $pIUnknown = DllStructGetData($tIUnknown, 1)
        ; Below is required if registered with ACTIVEOBJECT_WEAK flag:
        ; _AutoItObject_IUnknownAddRef($pIUnknown)
    EndIf

    _Log("_GetActiveObject IDispatch acquired " & $pIUnknown & " " & $sGUID)
    Return _AutoItObject_PtrToIDispatch($pIUnknown) ; Nah, this will crash in out-of-process case
EndFunc

Func _PtrToIDispatch($pIDispatch)
    Static Local $PTR_SIZE = DllStructGetSize(DllStructCreate('ptr'))
Local $aCall = DllCall('Kernel32.DLL', "none", "RtlMoveMemory", "idispatch*", 0, "ptr*", $pIDispatch, "dword", $PTR_SIZE)
If @error Then Return SetError(1, 0, 0)
Return $aCall[1]
EndFunc

#cs HRESULT RevokeActiveObject(
  _In_        DWORD dwRegister,
  _Reserved_  void *pvReserved
); OleAut32.dll
#ce
Func _RevokeActiveObject ( ByRef $_IDispatch, $iHandle )
    If NOT $IUnknownDebugger Then
        $pIDispatch = _AutoItObject_IDispatchToPtr($_IDispatch)
        _CoLockObjectExternal($pIDispatch, False, True)
        If @error Then Return SetError(2, @extended, 0)
    EndIf

    $aCall = DllCall('OleAut32.DLL', 'INT', 'RevokeActiveObject', _
                'dword', $iHandle, _
                'ptr', 0 )
    If @error OR $aCall[0] Then Return SetError(1, $aCall[0], 0)
    Return 1
EndFunc

#EndRegion <<< Win32 ActiveObject API

#Region    >>> Win32 GUID API (CLSIDFromString may return E_CLASSNOTREG for unregistered ClsId)

Func _GuidFromString ( $sUUID, $ptGUID=0 )
    Static Local $RPC_S_INVALID_STRING_UUID = 0x6A9

    ; Use passed GUID struct by pointer or create new
    Local $tGUID
    If $ptGUID = 0 Then
        $tGUID = DllStructCreate($tagGUID)
    Else
        $tGUID = DllStructCreate($tagGUID, $ptGUID)
    EndIf

    ; Strip '{}'
    If StringLeft($sUUID, 1) = '{' Then $sUUID = StringMid($sUUID, 2, StringLen($sUUID) - 2)

Local $aCall = DllCall("Rpcrt4.DLL", 'INT', 'UuidFromStringW', 'wstr', $sUUID, 'ptr', DllStructGetPtr($tGUID))
If @error OR $aCall[0] Then
        If $aCall[0] = $RPC_S_INVALID_STRING_UUID Then Return SetError(2, 0, 0) ; Invalid Uuid String
        Return SetError(3, @error, 0) ; UuidFromString call failed
    EndIf

Return $tGUID
EndFunc ;==> _DllCOM_GuidFromString

Func _StringFromGuid ( $tGUID, $fCompat=1 )
    If IsPtr($tGUID) Then $tGUID = DllStructCreate($tagGUID, $tGUID)

Local $aCall = DllCall("Rpcrt4.DLL", 'INT', 'UuidToStringW', 'ptr', DllStructGetPtr($tGUID), 'wstr*', 0)
    If @error OR $aCall[0] Then Return SetError(2, $aCall[0], 0) ; UuidToString call failed

    If $fCompat Then Return "{" & StringUpper($aCall[2]) & "}"
    Return $aCall[2]
EndFunc ;==> _DllCOM_StringFromGuid

#EndRegion <<< Win32 GUID API

; AutoItObject test method
Func _ActiveObject_Hello ( $_Self, $msg )
    MsgBox(0, @AutoItPID, "After all that had happened: " & $msg)
EndFunc

; Server & Client Main
If $CmdLine[0] Then
    Opt('TrayIconHide', 1)
    $sGUID = $CmdLine[1]
    If $sGUID = EnvGet("ActiveObjectGUID") AND $sGUID = ConsoleRead() Then ; verify GUID
        _Log("Out-of-process fetching ActiveObject: " & $sGUID)
        MsgBox(0, @AutoItPID, "Fasten your seatbelt," & @CRLF & "we are going to CRASH!")
        $_out_proc_object = _Critical( _GetActiveObject($sGUID) )
        _Log("Out-of-process object test: " & $_out_proc_object.Data)
    Else
        _Log("ActiveObject GUID missmatch!")
    EndIf
    ; make sure stdout flushed
    Sleep(500)
Else
    $_ActiveObject = _AutoItObject_Create()
    _AutoItObject_AddProperty($_ActiveObject, "Data", $ELSCOPE_PUBLIC, "I'm alive!")
    _AutoItObject_AddMethod($_ActiveObject, "Hello", "_ActiveObject_Hello")
    If $IUnknownDebugger Then $_pActiveObject = _AutoItObject_IDispatchToPtr($_ActiveObject)

    $sGUID = ObjCreate("Scriptlet.TypeLib")
    $sGUID = $sGUID.GUID

    $hActiveObject = _Critical( _RegisterActiveObject($_ActiveObject, $sGUID) )

    If $OutOfProcessTest Then
        EnvSet("ActiveObjectGUID", $sGUID)
        $pid = Run('"' & @AutoItExe & '" "' & @ScriptFullPath & '" ' & $sGUID, @ScriptDir, @SW_HIDE, 0x3)
        StdInWrite($pid, $sGUID)
        While ProcessExists($pid)
            $log = StdoutRead($pid)
            If @extended Then 
                ConsoleWrite($log)
            Else
                Sleep(100)
            EndIf
        WEnd
    Else
        _Log("In-process fetching ActiveObject: " & $sGUID)
        $_in_proc_object = _Critical( _GetActiveObject($sGUID) )
        _Log("In-process object test: " & $_in_proc_object.Data)
    EndIf

    ; Prove that object still valid
    $_ActiveObject.Hello($_ActiveObject.Data)

    _Critical( _RevokeActiveObject($_ActiveObject, $hActiveObject) )
EndIf

#Region    >>> IUnknown Stub

Func _ActiveObject_AddRef ( $_Self )
    _Log("_ActiveObject_AddRef")
    Return 0;
EndFunc

Func _ActiveObject_Release ( $_Self )
    _Log("_ActiveObject_Release")
    Return 0;
EndFunc

; IID_IUnknown {00000000-0000-0000-C000-000000000046}
; IID_IMarshal {00000003-0000-0000-C000-000000000046}
; IID_IProxyManager {00000008-0000-0000-C000-000000000046}
; IID_IStdMarshalInfo {00000018-0000-0000-C000-000000000046}
; IID_IExternalConnection {00000019-0000-0000-C000-000000000046}
; ? {0000001B-0000-0000-C000-000000000046} <-- IdentityUnmarshal's GUID
; {4C1E39E1-E3E3-4296-AA86-EC938D896E92} <-- proxy-stub request, handled by default?
Func _ActiveObject_QueryInterface ( $_Self, $pIID, $ppObject )
    Static Local $E_NOTIMPL = 0x80004001
    $sIID = _StringFromGuid($pIID)
    If $sIID = "{00000000-0000-0000-C000-000000000046}" Then
        $tOut = DllStructCreate('ptr', $ppObject)
        DllStructSetData($tOut, 1, $_ActiveObject_Factory)
        _Log("_ActiveObject_QueryInterface IUnknown Requested")
        Return 0;
    ElseIf $sIID = "{00020400-0000-0000-C000-000000000046}" Then
        $tOut = DllStructCreate('ptr', $ppObject)
        DllStructSetData($tOut, 1, $_pActiveObject)
        _Log("_ActiveObject_QueryInterface IDispatch Requested")
        Return 0;
    Else
        _Log("_ActiveObject_QueryInterface Unhandled: " & _StringFromGuid($pIID))
        Return $E_NOTIMPL
    EndIf
EndFunc

#EndRegion <<< IUnknown Stub

#Region    >>> Debugging

Func _Log ( $msg )
    ConsoleWrite($msg & @CRLF)
EndFunc

Func _Error ( $msg )
    ConsoleWriteError($msg & @CRLF)
EndFunc

Func _Critical ($ret, $rel=0, $msg="Fatal Error", $err=@error, $ext=@extended, $ln = @ScriptLineNumber)
  If $err Then
    $ln += $rel
    Local $LastError = _WinAPI_GetLastError(), _
          $LastErrorMsg = _WinAPI_GetLastErrorMessage(), _
          $LastErrorHex = Hex($LastError)
    $LastErrorHex = "0x" & StringMid($LastErrorHex, StringInStr($LastErrorHex, "0", 1, -1)+1)
    $msg &= @CRLF & "at line " & $ln & @CRLF & @CRLF & "AutoIt Error: " & $err & " (0x" & Hex($err, 8)  & ") Extended: " & $ext & " (0x" & Hex($ext, 8)  & ")"
    If $LastError Then $msg &= @CRLF & "WinAPI Error: " & $LastError & " (" & $LastErrorHex & ")" & @CRLF & $LastErrorMsg
    _Error($msg)
    ClipPut($msg)
    MsgBox(270352, "Fatal Error - " & @ScriptName, $msg)
    Exit
  EndIf
  Return $ret
EndFunc

#EndRegion <<< Debugging

Please help to make it work, it would be cool if we can use AutoItObject for IPC! :robot:

Posted (edited)

Why can't you use _AutoItObject_RegisterObject() function?

Objects registered with that function are accessible throughout the system, not only inproc.

Whoa, silly me :sweating: totally miss that spot! Thank you trancexx!

Btw, is there any way to get the object outside autoit? cuz cbi: header is not known and guid not found using the regular GetActiveObject.

Edit:

OK, found nice example here and in Geez, only a handfull of them in google, these RegisterObject series should get more spotlight, cuz they are the star! :thumbsup:

Edited by eimhym
Posted (edited)

"cbi:" moniker is just for the AutoItObject's implementation of the calling function. You can use built-in ObjGet() to create the object from AutoIt scripts or GetObject() from VBS/JS, or System.Runtime.InteropServices.Marshal.BindToMoniker() from .NET based languages, or simple CoGetObject() WinAPI call for C/C++/... languages, or MkParseDisplayName(). All that without "cbi:" of course.

Edited by trancexx

♡♡♡

.

eMyvnE

  • 1 month later...
Posted

I spent some time looking on the forums for this, but didn't see where any one else was doing it. Is there a way, with this, to create COM Objects that respond to events? I was hoping to use trancexx's earlier example of how to create your own com server to make a plugin for a program, and just register for events that come from it so it can scan/do what it needs, and send back events when something interesting occurs, but I can't find any examples or hints as to how to do so with COM events (using ObjEvent() ).

  • 2 months later...
Posted (edited)

Hi guys,

 

First, you are stupendous. This object are wonderfull.

 

I'm start use AutoitObject and Koda at one script, and the situation is:

 

The next code works perfect and the window opens normaly.

 

--------------------------------------------------------------------------

;Includes das telas
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
Func _Telas_Analista_main()
   #Region ### START Koda GUI section ### 
   $AnalistaFormMain = GUICreate("Analista", 224, 438, 10, 10, BitOR($WS_SYSMENU, $WS_BORDER, $WS_CAPTION))
   GUISetState(@SW_SHOW)
   #EndRegion ### END Koda GUI section ###
   While 1
   $nMsg = GUIGetMsg()
   ConsoleWrite("!...Tela  travada'" & @CRLF)
   Switch $nMsg
   Case $GUI_EVENT_CLOSE
   Exit
 
   EndSwitch
   WEnd
EndFunc
 
_Telas_Analista_main()

--------------------------------------------------------------------------------------------------------------------------------------------------------

 

but, the next code are the up code with AutoitObject, and this, when I execute, his open the window but this stop!!

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

 

#comments-start
 AutoIt Version: 0.1
 Author:         Rafael Scolari Maciel
 Objetivo:       Gestão da execução das rotinas de analise
#comments-end
 
#include "AutoitObject.au3"
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
 
_AutoItObject_StartUp()
Global $C_Analista = _Analista_create();global detentora do objeto ANALISTA
 
Func _Analista_create()
Local $oClassObject = _AutoItObject_Class()
$oClassObject.Create()
$oClassObject.AddMethod("formMain", "_Analista_main")
$oClassObject.AddDestructor("_DestructorForAnalista")
Return $oClassObject.Object
EndFunc
 
Func _Analista_main($oSelf)
   #Region ### START Koda GUI section ### 
   $AnalistaFormMain = GUICreate("Analista", 224, 438, 10, 10, BitOR($WS_SYSMENU, $WS_BORDER, $WS_CAPTION))
   GUISetState(@SW_SHOW)
   #EndRegion ### END Koda GUI section ###
 
   While 1
 $nMsg = GUIGetMsg()
 ConsoleWrite("!...Tela  travada'" & @CRLF)
 Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
 EndSwitch
   WEnd
EndFunc
 
Func _DestructorForAnalista($oSelf)
ConsoleWrite("!...destructing... 'Analista'" & @CRLF)
 EndFunc
 
 $C_Analista.formMain

--------------------------------------------------------------------------------------------------------------------------------------------------------

At another post, Martin makes a great code to show this situation:

;Includes das telas
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include "C:\Program Files\Autoit3\include\AutoitObject.au3"

Dim $doexit

_AutoItObject_StartUp()

extern2("Window 1") ;create window without using objects


Global $C_Analista = _Analista_create();global detentora do objeto ANALISTA


$C_Analista.formMain

$C_Analista = 0;destroy th eobject

_AutoItObject_Shutdown();don't forget this line although the examples do


Func _Analista_create()
    Local $oClassObject = _AutoItObject_Class()
    $oClassObject.Create()
 
    $oClassObject.AddMethod("formMain", "_Analista_main")
    $oClassObject.AddDestructor("_DestructorForAnalista")
    Return $oClassObject.Object
EndFunc   ;==>_Analista_create

Func _Analista_main($oSelf)
    extern2("window from object")
EndFunc

func extern2($title)
    AutoItSetOption("guioneventmode",1)
    $doexit = 0
    #region ### START Koda GUI section ### 
    $AnalistaFormMain = GUICreate($title, 224, 438, 10, 10);, BitOR($WS_SYSMENU, $WS_BORDER, $WS_CAPTION))
    GUISetState(@SW_SHOW)
    #endregion ### END Koda GUI section ###
    ConsoleWrite("step 4" & @LF)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGui")
    While $doexit = 0
        sleep(30)
    WEnd
EndFunc   ;==>_Analista_main

Func CloseGui()
    ConsoleWrite("close gui?" & @LF)
    $doexit = 1
EndFunc


Func _DestructorForAnalista($oSelf)
    ConsoleWrite("!...destructing... 'Analista'" & @CRLF)
EndFunc   ;==>_DestructorForAnalista

()

More infos:

From the Windows Event Viewer the AutoIt register two events, first:

 
Fault bucket , type 0
Event Name: AppHangB1
Response: Not available
Cab Id: 0

Problem signature:
P1: AutoIt3.exe
P2: 3.3.8.1
P3: 4f25baec
P4: 1435
P5: 0
P6: 
P7: 
P8: 
P9: 
P10: 

Attached files:

These files may be available here:
C:\Users\<<<<<>>>>>>\AppData\Local\Microsoft\Windows\WER\ReportArchive\AppHang_AutoIt3.exe_8aa79b99642e5abe8fef93464a12724dbc1d31c_406e79d5

Analysis symbol: 
Rechecking for solution: 0
Report Id: cffc3b89-e378-11e2-83c1-0024e8b38737
Report Status: 0

Error event:

The program autoit3.exe version 3.3.8.1 stopped interacting with Windows and was closed. To see if more information about the problem is available, check the problem history in the Action Center control panel.
 Process ID: 5ca8
 Start Time: 01ce77858450d018
 Termination Time: 14
 Application Path: C:\Program Files (x86)\AutoIt3\autoit3.exe
 Report Id: cffc3b89-e378-11e2-83c1-0024e8b38737

Please, someone can help me?

Edited by RafaelMaciel
Posted

I love objects, but having to declare them like _SomeBulkyFunctionName(...) grates on my nerves (as I am used to C++ style classes), so I wrote a small function "_ObjCreate" to create objects for AutoItObject with somewhat cleaner syntax. Here it is for anybody else interested in using it.

Is something more native feeling a possibility for the future?

You give me bright ideas :bye: See what you think about this

Widget.au3...

#include-once
;this is your magic include, your mission is to design it
#include "ClassMaker.au3"

;This is the cache for the string that would be passed to your Func _ObjCreate($sText)
;Note: This could be encapsulated into ClassMaker as an associative array
Local $NewWidgetCache=''

;Here is the Constructor
Func NewWidget($p1,$p2)
  ;These Comments end up as properties (ie fields) for ClassMaker to read
  #cs
  Public
    publicField;
    publicFieldWithAssignment="String";
  Private
    privateField;
  ReadOnly
    readonlyField;
  #ce
  ;Call ClassMaker now...
  ;; begin packaging
  ;   Next set of statements could be packaged in ClassMaker, but are exposed here to demonstrate whats happening.
  ;   In packaged form the statements would be condensed in a call that would look like:
  ;     Local $me=ClassMaker($NewWidgetCache, <file>)
  ; which does...
  If $NewWidgetCache=='' Then
    ;ClassMaker now analyzes this file to compile the string for _ObjCreate()
    ; IMPORTANT: For compiled scripts, ClassMaker is creating/reading a <mainscript>Classes.ini to hold data for
    ; when script files are not present to analyze
    $NewWidgetCache=ClassMaker('C:\scripts\classes\Widget.au3');
  EndIf
  ; And here we call Create
  Local $me=_ObjCreate($NewWidgetCache)
  ;; end packaging
  ;
  ;All Done
  Return $me.Object
EndFunc

;Now we use comment decorations to indicate our functions to ClassMaker


Func _Widget__publicFn($me,$p1);PUBLIC
EndFunc
Func _Widget__privateFn($me,$p1);PRIVATE
EndFunc

What do you think?

Posted

Ok, I have been playing around with AutoItObject library a bit now. My experiments have been in the context of making user-defined classes (not messing with predefined COM or trying to inherit from them or what have you).

The docs on this are rather sparse, but what I have been able to determine is that AIO 'objects' are not objects that perform well as an OO design tool.
What I mean is that these objects appear to be flat when it comes to 'inheritance' -- they are like Xeroxed on top of each other and there is no way to get to members that have been masked by inheritance.
How can you have real OO without 'protected' and when 'private' really means 'protected' all down the tree?

I don't want to sound like a super-critic, I am just stating these things to make sure I understand the situation correctly.

For instance, I do not see a way to access 'this.base' in a single inheritance, or something akin to 'this.bases.classname.member' in the case of multiple inheritance. Is this correct?

Where can I get a list of this.__<special>__ members? I think I saw one a while back, I dont recall what it was though.

I am sure this package is exciting in accessing COM, but I feel I am missing out on something as far as using it for OO design, except in a very limited sense.


Nonetheless, I have built a helper for the AIO library called ClassMaker. It is a syntax cheat that will wire up an AIO object to its methods automtically by reading the script file.
This could be extended further but I am apprehensive now that I am discovering limitations that I described above.


The best way to explain it is to start with a AIO ClassMaker enabled file, first a comment-free base that we will inherit, WidgetBase.au3:

#include-once
; See Widget.au3 for explaination, barebones commenting here
Func NewWidgetBase()
  #cs
  Public
    publicFieldBase="This field has been set in WidgetBase Constructor";
  #ce
  Local $me=$ClassMaker.Produce('C:\batch\borg\WidgetBase.au3')
  Return $me
EndFunc

Func _WidgetBase__publicFn($me,$p1);PUBLIC
  Msg('_WidgetBase__publicFn')
  Msg('_WidgetBase__publicFn calling $me.privateFn...')
  $me.privateFn(1)
EndFunc
Func _WidgetBase__publicFn2Bases($me,$p1);PUBLIC
  Msg('_WidgetBase__publicFn2Bases')
  Msg('_WidgetBase__publicFn2Bases trying to call $me.publicFnVirt...')
  $me.publicFnVirt(1)
EndFunc
Func _WidgetBase__privateFn($me,$p1);PRIVATE
  Msg('_WidgetBase__privateFn')
EndFunc
Func _WidgetBase__privateFnBase($me,$p1);PRIVATE
  Msg('_WidgetBase__privateFnBase')
EndFunc
Func _WidgetBase__destructor($me)
  ;$me.___inheritor=0
  Msg('_WidgetBase__destructor');
EndFunc

Now a commented class that will explain the fundamentals of how ClassMaker works, Widget.au3

#include-once
; This is an example class file to be fed into ClassMaker
;
; No need for this include, Main.au3 will include and initiate ClassMaker
;#include "ClassMaker.au3"
;
; We will inherit
#include "WidgetBase.au3"
#include "WidgetBase2.au3"


; The Constructor for the Widget Class, must use New<classname> signature for ClassMaker to recognize
Func NewWidget($p1,$p2)
  ; The first #cs or #comments-start in a New<classname> constructor will be made into fields by ClassMaker
  #cs
  ;comments are allowed here, ignored by ClassMaker
  ; [<colon><baseclass>[,<baseclass>]...] declares our bases, applied in reverse order to handle overwrites logically
  ; this line can be omitted if not inheriting
  :WidgetBase,WidgetBase2
  ; declare public section, case insensitive, can also be Public:
  ; if left off, ClassMaker will start in public. Also, indentation ignored by ClassMaker
  Public
    ;name a field, semicolon optional
    publicField;
    ;name another field, with assignment. Right now only primitive assignments work, cannot access variables yet.
    publicFieldWithAssignment="This field has been assigned in Widget constructor";
  ;more of the same
  Private
    privateField;
  ReadOnly
    readonlyField;
  ; Can switch back or do classifiers in any order, or even leave one empty as below
  Public

  #ce
  ; Let ClassMaker do its magic now, pass in full path of file, classname derived from filename, but must be in synch
  ; with our constuctor and our method names
  ;
  ; IMPORTANT: Change this to reflect actual file location. Also do same with WidgetBase.au3, and WidgetBase2.au3
  Local $me=$ClassMaker.Produce('C:\batch\borg\Widget.au3')
  ;IMPORTANT: can still do specialty work here, set property values to variables or expressions,
  ; add new properties, or methods, or even further inheritance.
  ; Though further inheritance is not recommended since ClassMaker is trying to give helpers on inheritance, such as:
  ; THESE LIKELY WORK...
  ; $me.___type = <classname>
  ; $me.___basesnames = array of <baseclassnames>
  ; $base.___inheritor = <objthatinheritedme>
  ; $base.___final = <obj at end of inheritance tree>
  ;
  ; NOT SURE IF THESE WORK YET BUT...
  ; $me.___base = first base class
  ; $me.___bases.<baseclassname> = <baseclassobject>
  ; $me.___basesarray = array of <baseclassobjects>
  ;
  ;All Done
  Return $me
EndFunc

; ClassMaker will wire up any methods in the file with the proper signature to the object created
; Signatures by default are <prefix><classname><separator><functionname><suffix>
;   Where prefix    defaults to _
;         suffix    defaults to ""
;         separator defaults to __
;
; These defaults can be set in ClassMaker on a global level currently
;
; Storage Class For Methods: public, private
;  Determined by one of three things: Regions, Decorators, or Case of Method Name
;
; Regions lines look like "#region public" or ";public" (and "#endregion")
;
; Decorations are appended to right of function signatures and look like ";PUBLIC" (but are case insensitive)
;
; Method Names (see <functionname> above) are public if first letter is uppercase, else private
;
; Who wins? Regions override decorations which override Case Based determination
;
;
; Auto Property Backers...
;  Certain function signatures will trigger the creation of a private property backer
;  Any qualifiying (as above) function, should it also have a parameter declaration in the form of:
;   $value='PROPERTY'
;  will have a property backer field created for it with the name _<functionname>
;  Thus far, these created backers are only initialized to ""
;
; Destructors...
;  Any <functionname>=destructor will be registered as a destructor
;
; The following code has a bit of experimental twiddling going on in it, but you can get the idea


; A typical public function whose <functionname> is publicFn, it is public because of its decorator ;PUBLIC
; without the decoration it would be private due to the lowercase p as the first letter of its name
Func _Widget__publicFn($me,$p1);PUBLIC
  Msg('_Widget__publicFn')
  ;Msg('_Widget__publicFn trying to call $me.privateFnBase')
  ;$me.privateFnBase(1)
EndFunc

; This is something that is called from one of the bases, even though it is not declared in them. Cool.
Func _Widget__publicFnVirt($me,$p1);PUBLIC
  Msg('_Widget__publicFnVirt')
EndFunc

; This is how to declare an assignable property (not a field), and have its backer auto-created by ClassMaker
; due to the $value='PROPERTY' in the signature.
; The internal code shows how to handle the workings of an assignable property
; Leaving out the signature trigger will allow you to create assignables that don't need backers
Func _Widget__prop($me,$value='PROPERTY');PUBLIC
  If @NumParams = 2 Then
    $me._prop=$value
  Else
    return $me._prop
  EndIf
  ;Msg('_Widget__publicFn')
EndFunc

; An Example of a private region, comment form
;Private
; This decorator will be ignored since we are in a private region
Func _Widget__privateFn($me,$p1);PRIVATE
  Msg('_Widget__privateFn')
EndFunc
; We are still in private, there is no EndPrivate currently
; Another...
Func _Widget__privateFn2($me,$p1)
  Msg('_Widget__privateFn')
EndFunc

;Switch to public using other region form
#region public
; Decorator and case ignored in favor of region
Func _Widget__publicFn2($me,$p1);PRIVATE
  Msg('_Widget__publicFn')
  Msg('_Widget__publicFn trying to call $me.privateFnBase')
  $me.privateFnBase(1)
EndFunc
#endregion
; Still in public despite #endregion, since public is default


; The Destructor. Decorations, Regions and Case do not have any effect. This guy is always private
Func _Widget__destructor($me)
  Msg('_Widget__destructor');
EndFunc

Throw in the code for the other base we will inherit, WidgetBase2.au3:

#include-once
; See Widget.au3 for explaination, barebones commenting here
Func NewWidgetBase2()
  #cs
  Public
    publicFieldBase="pubBase2";
  #ce
  Local $me=$ClassMaker.Produce('C:\batch\borg\WidgetBase2.au3')
  ;All Done
  Return $me
EndFunc

Func _WidgetBase2__publicFn($me,$p1);PUBLIC
  Msg('_WidgetBase2__publicFn')
EndFunc
Func _WidgetBase2__publicFn2Bases($me,$p1);PUBLIC
  Msg('_WidgetBase2__publicFn2Bases')
EndFunc
Func _WidgetBase2__privateFn($me,$p1);PRIVATE
  Msg('_WidgetBase2__privateFn')
EndFunc
Func _WidgetBase2__destructor($me)
  ;$me.___inheritor=0
  ;Msg('_WidgetBase2__destructor');
EndFunc


Now a look at the Client:

Global $thisfile='C:\batch\borg\ClassMakerTester.au3'
#include <AutoItObject.au3>
; Include ClassMaker before any ClassFiles, ie Widget
#include "ClassMaker.au3"
; Include this because I want to make some Widget AutoItObjects via ClassMaker
#include "Widget.au3"

; Debug setup
Global $logg="C:\batch\borg\ClassMakerTester-log.txt";
;e C:\batch\borg\ClassMakerTester-log.txt
Global $timestamp=@YEAR&"."&@MON&"."&@MDAY&"."&@HOUR&"."&@MIN&"."&@SEC&"."&@MSEC
logclear()

; Do this for AutoItObject Lib
OnAutoItExitRegister("EvtScriptExit")
_AutoItObject_Startup()
Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc")

; Do once, before we make any ClassMaker dependent AutoItObjects
ClassMaker()

; Now we can make the ClassMaker dependent AutoItObject "Widget"
Global $widget1=NewWidget(1,2)

; STAND BACK!, WIDGET TEST AREA!!
;================================

If false Then
; Test: Call a Public Function
If false Then $widget1.publicFn(1)

; Test: Call a Private Function
If false Then $widget1.privateFn(1)
; Success, 2013.07.08.04.44.24.626:[COM Error]: ScriptLine(29) : Number 0x80020003 - Member not found.

; Test: Set A Public Field
If false Then $widget1.publicField='Assignment to public field ok'

; Test: Read A Public Field
If false Then Msg($widget1.publicField)

; Test: Read A Public Field Set in the Constuctor
If false Then Msg($widget1.publicFieldWithAssignment)

; Test: Set A Public Assignable Property with automatically created backer field
If false Then $widget1.prop="Assigning a assignable property"

; Test: Read a Public Assignable Property
If false Then Msg($widget1.prop)

; Test: Read a Base Public Field that has been assigned in constructor
If false Then Msg($widget1.publicFieldBase)

; Test: Set a Base Public Field that has been assigned in constructor
If false Then $widget1.publicFieldBase="$widget1.publicFieldBase has been reset"

; Test: Read a Base Public Field that has been assigned in constructor and reset
If false Then Msg($widget1.publicFieldBase)

; Test: Check the ___base.publicFieldBase to see if it has changed
If false Then Msg($widget1.___base.publicFieldBase)
; Fail, are objects disconnected? or am I just writing to this.
; Objects are disconnected, writing to .___base does not show up in this.

EndIf

If false Then
; We need more widgets
Global $widget2=NewWidget(1,2)

; Test: See the .___base.___type
If True Then Msg($widget2.___base.___type)


; Test: Set ___base.publicFieldBase and see if it shows up in this
$widget2.___base.publicFieldBase="$widget2.___base.publicFieldBase set from main"
If True Then Msg($widget2.publicFieldBase)
EndIf

;e C:\batch\borg\ClassMakerTester-log.txt


$widget1=0

Exit
; AutoItObject Exit Function
Func EvtScriptExit()
  ;Msg("EvtScriptExit")
  _AutoItObject_Shutdown()
EndFunc

; AutoItObject DEBUG FUNCTION
Func _ErrFunc()
    ;ConsoleWrite("COM Error, ScriptLine(" & $oError.scriptline & ") : Number 0x" & Hex($oError.number, 8) & " - " & $oError.windescription & @CRLF)
  Local $line="[COM Error]: ScriptLine(" & $oError.scriptline & ") : Number 0x" & Hex($oError.number, 8) & " - " & $oError.windescription
  Local $line2="" & $oError.scriptline & ":" & $oError.windescription
  logerr($line)
  ;Msg($line2)
  snarl(10,"COM ERROR"&":0x" & Hex($oError.number, 8),$line2)
EndFunc

; DEBUG FUNCTION BELOW
Func Msg($s)
  MsgBox(0,$thisfile,$s)
EndFunc
Func ts()
  Return @YEAR&"."&@MON&"."&@MDAY&"."&@HOUR&"."&@MIN&"."&@SEC&"."&@MSEC
EndFunc
Func logclear()
  FileDelete($logg)
EndFunc

Func logline($line)
  Local $fh1=FileOpen($logg,1);
  If $fh1<>-1 Then
    FileWriteLine($fh1,$line)
    FileClose($fh1)
  EndIf
EndFunc
Func logerr($line)
  Local $fh1=FileOpen($logg,1);
  Local $t=ts()
  If $fh1<>-1 Then
    FileWriteLine($fh1,$t&':'&$line)
    FileClose($fh1)
  EndIf
EndFunc

;If you have Snarl_CMD.exe, hook it up here for debugging
; I think the right source is
; http://sourceforge.net/projects/mozillasnarls/files/Snarl_CMD/
Func snarl($i,$t,$s)
  $snarl="C:\batch\Snarl_CMD.exe";
  If Not FileExists($snarl) Then Return
  $s1=StringReplace($s,'"',"'")
  $t1=StringReplace($t,'"',"'")
  $cmd=$snarl&' snShowMessage '&$i&' "'&$t1&'" "'&$s1&'"';
  Run($cmd)
EndFunc


And Finally the ClassMaker itself, ClassMaker.au3:

; #INDEX# =======================================================================================================================
; Title .........: ClassMaker v1.0.0.0
; AutoIt Version : 3.3
; Language ......: English (language independent)
; Description ...: Wires AutoItObjects by reading script files, attempts to make them more like true objects.
; Author(s) .....: MarkRobbins
; Copyright .....: Copyright (C) Mark C Robbins. All rights reserved.
; License .......: Artistic License 2.0, see Artistic.txt
;
; ClassMaker is free software; you can redistribute it and/or modify
; it under the terms of the Artistic License as published by Larry Wall,
; either version 2.0, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
; See the Artistic License for more details.
;
; You should have received a copy of the Artistic License with this Kit,
; in the file named "Artistic.txt".  If not, you can get a copy from
; <http://www.perlfoundation.org/artistic_license_2_0> OR
; <http://www.opensource.org/licenses/artistic-license-2.0.php>
;
; ===============================================================================================================================

; #OVERVIEW# ===========================================================================================================
 ; SOURCE_______________________________________________________________________________________________________________
  ; Organization ..: Mark Robbins and Associates
  ; Author ........: Mark Robbins
 ; LOG__________________________________________________________________________________________________________________
  ; Created .......: 2013.07.08
  ; Modified ......: 2013.07.08
  ; Entries........: yyyy.mm.dd.hh.mm.ss Comments
 ; HEADER_______________________________________________________________________________________________________________
  ; Type ..........: Class
  ; Subtype .......: Helper
  ; Name ..........: ClassMaker
  ; Summary .......: Class construction framework for AutoItObject Classes.
  ; Description ...: Provides formalized syntax for class declaration, uses that syntax in construction of the class by
  ;                  dynamically reading the script source file. Currently not to be used in compiled scripts.
  ; Remarks .......: This is a work in progress.
 ; DEVELOPMENT__________________________________________________________________________________________________________
  ; Issues ........: Need to implement mechanism for working with compiled scripts.
  ;                  Need Error handling.
  ;                  Need more investigation into how inheritance works and how to enhance it
  ; Status ........: [ ] New
  ;                  [ ] Open
  ;                  [X] InProgress
  ;                  [ ] Resolved
  ;                  [ ] Closed
 ; OTHER________________________________________________________________________________________________________________
  ; Related .......: AssocArrays.au3,
  ; Related Links .: http://www.autoitscript.com/forum/topic/110379-autoitobject-udf/
  ; Resources......:
 ; =====================================================================================================================


#include-once
#include <AssocArrays.au3>
#include <File.au3>
#include <Array.au3>


; #CURRENT# =====================================================================================================================
;NewClassMaker
;$ClassMaker.Produce
; ===============================================================================================================================

; #HELPERS# =====================================================================================================================
;ArrayDisp
; ===============================================================================================================================

; #INTERNAL# ====================================================================================================================
;$ClassMakerCache
;$ClassMaker.classfirst
;$ClassMaker.fields_a
;$ClassMaker.re_pfx
;$ClassMaker.re_sfx
;$ClassMaker.sep
;cacheGet__ClassMaker
;cacheHas__ClassMaker
;cachePut__ClassMaker
;cacheZap__ClassMaker
;Produce__ClassMaker
;collectFieldString__ClassMaker
;collectFunctionString__ClassMaker
;findNewLine__ClassMaker
;findNewLineCommentStart__ClassMaker
;findNewLineCommentEnd__ClassMaker
;make__ClassMaker
; ===============================================================================================================================


; Singleton Handle. Every Class File must include ClassMaker.au3 and Main must call ClassMaker()
Global $ClassMaker;=NewClassMaker()
; Data cache <classname>:<dataarrays>
Global $ClassMakerCache

; Initialize the singleton
Func ClassMaker()
  If Not IsObj($ClassMaker) Then
    $ClassMaker=NewClassMaker()
    If Not IsObj($ClassMaker) Then
      Msg('ClassMaker():forgot _AutoItObject_Startup() in Main?')
    EndIf
  EndIf
  Return $ClassMaker
EndFunc
; ClassMakers Constuctor
Func NewClassMaker()
  Local $me = _AutoItObject_Create()
  AssocArrayCreate($ClassMakerCache,1);
  ;do function signatures have classname first or last
  _AutoItObject_AddProperty($me,"classfirst",$ELSCOPE_PUBLIC,True)
  ;used as a temp cludge for now
  _AutoItObject_AddProperty($me,"fields_a",$ELSCOPE_PRIVATE,'')
  ;a non-capturing regex that will match fn sig prefix
  _AutoItObject_AddProperty($me,"re_pfx",$ELSCOPE_PUBLIC,'_')
  ;a non-capturing regex that will match fn sig suffix
  _AutoItObject_AddProperty($me,"re_sfx",$ELSCOPE_PUBLIC,'')
  ;a string literal that separates the classname from the function name in function signatures
  _AutoItObject_AddProperty($me,"sep",$ELSCOPE_PUBLIC,'__')
  ;Main Method, pass filepath and recieve new class instance
  _AutoItObject_AddMethod($me,"Produce","Produce__ClassMaker")
  ;cache utils
  _AutoItObject_AddMethod($me,"cacheHas","cacheHas__ClassMaker",True)
  _AutoItObject_AddMethod($me,"cachePut","cachePut__ClassMaker",True)
  _AutoItObject_AddMethod($me,"cacheGet","cacheGet__ClassMaker",True)
  _AutoItObject_AddMethod($me,"cacheZap","cacheZap__ClassMaker",True)
  ;get an array of fields to be created
  _AutoItObject_AddMethod($me,"collectFieldString","collectFieldString__ClassMaker",True)
  ;get an array of functions to be created
  _AutoItObject_AddMethod($me,"collectFunctionString","collectFunctionString__ClassMaker",True)
  ;discover location of New<classname> function in file
  _AutoItObject_AddMethod($me,"findNewLine","findNewLine__ClassMaker",True)
  ;discover location of #cs directive that is after New<classname> function in file
  _AutoItObject_AddMethod($me,"findNewLineCommentStart","findNewLineCommentStart__ClassMaker",True)
  ;discover location of #ce directive that is after New<classname> function in file
  _AutoItObject_AddMethod($me,"findNewLineCommentEnd","findNewLineCommentEnd__ClassMaker",True)
  ;make actual class from data arrays
  _AutoItObject_AddMethod($me,"make","make__ClassMaker",True)
  Return $me
EndFunc

;new class object instance is created, classname derived from filename of fullpath parameter $fn
Func Produce__ClassMaker($me,$fn);PUBLIC
  If Not FileExists($fn) Then
    MsgBox(0,'ClassMaker.Produce','File not found:'&$fn)
    Exit
  EndIf
  ;compute classname
  Local $szDrive, $szDir, $szFName, $szExt;
  _PathSplit($fn, $szDrive, $szDir, $szFName, $szExt)
  Local $n=$szFName;
  ;our data arrays
  Local $fields_a;
  Local $funs_a;
  ;maybe use cache
  If $me.cacheHas($n) Then
    Local $aaa=$me.cacheGet($n)
    $fields_a=$aaa[0]
    $funs_a=$aaa[1]
    ;make the instance
    Return $me.make($n,$fields_a,$funs_a)
  EndIf
  ;cache not present, read the script file
  Local $a
  ;TODO: fileexists
  _FileReadToArray($fn,$a)
  ;get field data
  $fields_a=$me.collectFieldString($n,$a)
  ;func data getter will need access, so cludge
  $me.fields_a=$fields_a
  ;get function data
  $funs_a=$me.collectFunctionString($n,$a)
  ;recieve the cludge
  $fields_a=$me.fields_a
  ;store in cache
  Local $bbb[2]
  $bbb[0]=$fields_a
  $bbb[1]=$funs_a
  $me.cachePut($n,$bbb)
  ;make the instance
  Return $me.make($n,$fields_a,$funs_a)
EndFunc
;cache utils
Func cacheHas__ClassMaker($me,$key);PRIVATE
  Return AssocArrayExists($ClassMakerCache,$key)
EndFunc
Func cachePut__ClassMaker($me,$key,$val);PRIVATE
  Return AssocArrayAssign($ClassMakerCache,$key,$val)
EndFunc
Func cacheGet__ClassMaker($me,$key);PRIVATE
  Return AssocArrayGet($ClassMakerCache,$key)
EndFunc
Func cacheZap__ClassMaker($me,$key);PRIVATE
  Return AssocArrayDelete($ClassMakerCache,$key)
EndFunc
;discover "Func New<classname> in file, ignore commented out lines via #cs etc
Func findNewLine__ClassMaker($me,$classname,$a)
  ;TODO:condense all finders into one function
  Local $to=UBound($a)-1
  Local $i
  Local $it
  Local $in_cs=False
  ;TODO: account for space before parens? or other space anomalies
  Local $tgt='func new'&StringLower($classname)&'('
  ;each line
  For $x=1 To $to
    $i=$a[$x]
    $it=StringStripWS($i,3);lead and trail
    $it=StringLower($it)
    ;filters...
    If StringMid($it,1,1)==';' Then ContinueLoop
    If $it=='' Then ContinueLoop
    ;in comment toggle
    If $in_cs Then
      If ($it=='#ce' Or $it=='#comments-end') Then
        $in_cs=False
      EndIf
      ContinueLoop
    EndIf
    If $it=='#cs' Or $it=='#comments-start' Then
      $in_cs=True
      ContinueLoop
    EndIf
    ;candidate line
    If StringMid($it,1,StringLen($tgt))==$tgt Then
      ;found!
      Return $x
    EndIf
  Next
  Return -1
EndFunc
;find first #cs or #comments-start after Func New<classname>
Func findNewLineCommentStart__ClassMaker($me,$classname,$a)
  Local $beg=$me.findNewLine($classname,$a)
  If $beg==-1 Then
    Return -1
  EndIf
  Local $to=UBound($a)-1
  Local $i
  Local $it
  Local $in_cs=False
  For $x=$beg To $to
    $i=$a[$x]
    $it=StringStripWS($i,3);lead and trail
    $it=StringLower($it)
    ;filter
    If StringMid($it,1,1)==';' Then ContinueLoop
    If $it=='' Then ContinueLoop
    ;candidate
    If $it=='#cs' Or $it=='#comments-start' Then
      ;found!
      Return $x
    EndIf
  Next
  Return -1
EndFunc
;find first #ce or #comments-end after #cs or #comments-start after Func New<classname>
Func findNewLineCommentEnd__ClassMaker($me,$classname,$a)
  Local $beg=$me.findNewLineCommentStart($classname,$a)
  If $beg==-1 Then
    Return -1
  EndIf
  Local $to=UBound($a)-1
  Local $i
  Local $it
  Local $in_cs=False
  For $x=$beg To $to
    $i=$a[$x]
    $it=StringStripWS($i,3);lead and trail
    $it=StringLower($it)
    ;filter
    If StringMid($it,1,1)==';' Then ContinueLoop
    If $it=='' Then ContinueLoop
    ;candidate
    If $it=='#ce' Or $it=='#comments-end' Then
      ;found!
      Return $x
    EndIf
  Next
  Return -1
EndFunc
;scan field section for declarations
Func collectFieldString__ClassMaker($me,$classname,$a)
  Local $ra[4]
  $ra[0]=''
  $ra[1]=''
  $ra[2]=''
  $ra[3]=''
  Local $d=Chr(9)
  ;Local $d='.';
  Local $s1=''
  Local $s2=''
  Local $s3=''
  Local $s4=''
  Local $beg=$me.findNewLineCommentStart($classname,$a)
  Local $end=$me.findNewLineCommentEnd($classname,$a)
  If $beg==-1 Then Return $ra
  If $end==-1 Then Return $ra
  Local $i,$it,$it2
  ;default to public storage
  Local $t='public'
  For $x=$beg+1 To $end-1
    $i=$a[$x]
    $it=StringStripWS($i,3);lead and trail
    $it2=$it
    ;filter...
    If StringMid($it,1,1)==';' Then ContinueLoop
    If $it=='' Then ContinueLoop
    ;handle base class list
    If StringMid($it,1,1)==':' Then
      $s4=StringMid($it,2)
      ContinueLoop
    EndIf
    ;handle storage declarations
    $it=StringLower($it)
    ;remove trailing colon if exists
    If StringMid($it,StringLen($it),1)==':' Then
      $it=StringMid($it,1,StringLen($it)-1)
    EndIf
    ;handle switch of storage declaration
    If $it=='public' Or $it=='private' Or $it=='readonly' Then
      $t=$it
      ContinueLoop
    EndIf
    ;revert to non-lowercase line
    $it=$it2
    ;slot and append declaration into proper delimited string based on storage declaration
    If $t=='public' Then
      If $s1=='' Then
        $s1=$it
      Else
        $s1&=$d&$it
      EndIf
    ElseIf $t=='private' Then
      If $s2=='' Then
        $s2=$it
      Else
        $s2&=$d&$it
      EndIf
    ElseIf $t=='readonly' Then
      If $s3=='' Then
        $s3=$it
      Else
        $s3&=$d&$it
      EndIf
    EndIf
  Next
  ;fill the return array
  $ra[0]=$s1
  $ra[1]=$s2
  $ra[2]=$s3
  $ra[3]=$s4
  Return $ra
EndFunc
;debug helper, sometimes _ArrayDisplay Hangs - is this an AutoItObject problem?
Func ArrayDisp($a)
  Local $s=''
  Local $x,$i,$to=UBound($a)-1
  For $x=0 To $to
    If $s=='' Then
      $s=$a[$x]
    Else
      $s&=@CRLF&$a[$x]
    EndIf
  Next
  Msg($s)
EndFunc
;scan entire file for function declarations with proper signature
Func collectFunctionString__ClassMaker($me,$classname,$a)
  ;cludge, we need this for property backers
  Local $fa=$me.fields_a
  ;Signatures look like: <pfx><classname><separator><functionname><suffix> or
  ;                      <pfx><functionname><separator><classname><suffix> depending on ClassMaker.classfirst
  ;
  ;Region: ;<storage> or
  ;        #region <storage>
  ;
  ;Decorator: Func <name>();<storage>
  ;
  ;ProperCase: Function names (see sig <functionname>) starting with uppercase are public, else private
  ;
  ;Storage determination overrides:
  ; Regions override Decorators which override ProperCase
  ;
  ;
  ;Property Backers: Always private, sig: _<functionname>
  ;                  Created for functions with 2 params where second param sig: $value='PROPERTY'
  ;
  ;
  Local $d=Chr(9)
  Local $s1=''
  Local $s2=''
  Local $s3=''
  Local $i,$it,$it2,$it3
  Local $in_cs
  ;undef is assumed public
  Local $t='undef'
  Local $end=UBound($a)-1
  Local $fn,$re_pfx,$re_sfx,$sep,$aa,$pt1,$pt2,$cls,$fnn,$sc
  For $x=1 To $end
    $i=$a[$x]
    $it=StringStripWS($i,3);lead and trail
    $it2=$it
    ;filters...
    If StringMid($it,1,1)==';' Then ContinueLoop
    If $it=='' Then ContinueLoop
    $it=StringLower($it)
    ;handle comment section toggle
    If $in_cs Then
      If ($it=='#ce' Or $it=='#comments-end') Then
        $in_cs=False
      EndIf
      ContinueLoop
    EndIf
    If $it=='#cs' Or $it=='#comments-start' Then
      $in_cs=True
      ContinueLoop
    EndIf
    ;check for our types of region declarations
    $it3=StringStripWS($i,4+2+1);lead and trail and spans
    If $it3=='#region public' Or $it3==';public' Then
      $t='public'
      ContinueLoop
    EndIf
    If $it3=='#region private' Or $it3==';private' Then
      $t='public'
      ContinueLoop
    EndIf
    If $it3=='#endregion' Then
      $t='undef'
      ContinueLoop
    EndIf
    ;filter... want functions
    If StringMid($it,1,5)<>'func ' Then
      ContinueLoop
    EndIf
    ;is it a function? then parse it
    $aa=StringRegExp($it2, "(?i:Func) ([^ \(]+)\(", 2)
    If @Error<>0 Then; no match??
      ;Msg('nomatch1:'&$it2)
      ContinueLoop
    EndIf
    ;save the full function name
    $fn=$aa[1]
    ;prepare to parse it into name parts...
    $re_pfx=$me.re_pfx;'_'
    $re_sfx=$me.re_sfx;''
    $sep=$me.sep;'__'
    Local $re=$re_pfx&"([A-Za-z0-9_]+)"&$sep&"([A-Za-z0-9_]+)"&$re_sfx;
    $aa=StringRegExp($fn, $re_pfx&"([A-Za-z0-9_]+)"&$sep&"([A-Za-z0-9_]+)"&$re_sfx, 2)
    If @Error<>0 Then; no match??
      ;Msg('nomatch2:'&$fn)
      ContinueLoop
    EndIf
    ;save the name parts
    $pt1=$aa[1]
    $pt2=$aa[2]
    $cls=$pt1
    $fnn=$pt2
    If Not $me.classfirst Then
      $cls=$pt2
      $fnn=$pt1
    EndIf
    ;filter for not right classname in function name part
    If StringLower($cls)<>StringLower($classname) Then
      ContinueLoop
    EndIf
    ;decide storage class, public or pvt
    $sc='public';default
    If $t=='undef' Then
      ;look for decorators
      $aa=StringRegExp($it2, "; *(?i)(PUBLIC|PRIVATE)", 2)
      If @Error<>0 Then;not found
        ;determine using propercase
        If StringMid($fnn,1,1)==StringUpper(StringMid($fnn,1,1)) Then
          $sc='public'
        Else
          $sc='private'
        EndIf
      Else
        ;decorator given
        $sc=StringLower($aa[1])
      EndIf
    Else
      ;use region
      $sc=$t
    EndIf
    ;handle creating a field backer
    If StringInStr($it3,',$value="property")')<>0 Or StringInStr($it3,",$value='property')")<>0 Then
      ;use the cludge here
      If $fa[1]=='' Then
        $fa[1]='_'&$fnn
      Else
        $fa[1]&=$d&'_'&$fnn
      EndIf
      ;continue on since we have to recognize the fn too
    EndIf
    ;data stored as <functionname for obj> <functionname in code>
    $it=$fnn&' '&$fn
    ;slot and append to proper string based on storage
    If $sc=='public' Then
      If $s1=='' Then
        $s1=$it
      Else
        $s1&=$d&$it
      EndIf
    ElseIf $sc=='private' Then
      If $s2=='' Then
        $s2=$it
      Else
        $s2&=$d&$it
      EndIf
    EndIf
  Next
  ;put the cludge back where we got it
  $me.fields_a=$fa
  Local $ra[3]
  ;fill our return array
  $ra[0]=$s1
  $ra[1]=$s2
  $ra[2]=$s3
  Return $ra
EndFunc
;make the object according to data
Func make__ClassMaker($me,$classname,$ap,$af)
  ;ap is the array of field data
  ;af is the array of function data
  Local $o;the object to be returned
  ;do we have base classes
  If $ap[3]<>'' Then
    ;Msg('$ap[3]:'&$ap[3])
    ;parse the data to array
    Local $bases=StringStripWS($ap[3],8)
    Local $basea=StringSplit($bases,' ,;',2)
    ;flip the array so we can inherit from the last item first to handle overwrite logically
    _ArrayReverse($basea)
    ;ArrayDisp($basea)
    Local $z,$basect=UBound($basea)-1
    Local $baseoa[UBound($basea)]
    Local $sb,$basename,$constructor,$baseo
    Local $okct=0
    ;for each base declaration, create and assume it onto our object
    For $z=0 To $basect
      $basename=$basea[$z]
      $constructor='New'&$basename
      ;Msg('creating base:'&$constructor)
      ;TODO:here maybe call other forms (without New prefix) on fail?
      $baseo=Call($constructor)
      ;TODO:Error reporting everywhere
      If IsObj($baseo) Then
        $o=_AutoItObject_Create($baseo);
        ;add it to stuff we made for later
        $baseoa[$z]=$baseo
        $okct+=1
      EndIf
    Next
    ;get back to normal
    _ArrayReverse($basea)
    _ArrayReverse($baseoa)
    ;tack this data onto our object: an array of our bases, and an array of their names
    _AutoItObject_AddProperty($o,'___basesarray', $ELSCOPE_PUBLIC, $baseoa)
    _AutoItObject_AddProperty($o,'___basesnames', $ELSCOPE_PUBLIC, $basea)
    ;if we successfully made any bases
    If $okct>0 Then
      ;make a ___bases property on our object to tack the bases instances onto
      Local $_baseso=_AutoItObject_Create();
      _AutoItObject_AddProperty($o,'___bases', $ELSCOPE_PUBLIC, $_baseso)
      ;the first base in list gets to be ___base
      Local $first=False
      For $z=0 To $basect
        If Not IsObj($baseoa[$z]) Then ContinueLoop
        If $first==False Then
          $first=True
          _AutoItObject_AddProperty($o,'___base', $ELSCOPE_PUBLIC, $baseoa[$z])
        EndIf
        ;TODO:figure out how inheritance is suppose to work when you dont have protected storage
        ;     and you cannot really privatize to the inheritor the things that are inherited and private
        ;
        ;add ___bases.<name>=<baseobj>
        _AutoItObject_AddProperty($_baseso,$basea[$z], $ELSCOPE_PUBLIC, $baseoa[$z])
        ; Cannot do this, circular refs mean destructor won't be called
        If False Then
          ;add ___inheritor to each of those we inherited
          ;TODO: are these inherits really present? if I change base.field will this.field be changed?
          ;      I suspect these are just flattened objects and bases are orphaned
          _AutoItObject_AddProperty($baseoa[$z],'___inheritor', $ELSCOPE_PUBLIC, $o)
          ;this is an attempt at a base calling a fn only defined in final, but this build-in behavior
          ;SEEMS to work thus far
          _AutoItObject_AddProperty($baseoa[$z],'___final', $ELSCOPE_PUBLIC, $o)
        EndIf
      Next
    EndIf
  Else
    ;no bases
    $o=_AutoItObject_Create();
  EndIf
  ;object typing
  _AutoItObject_AddProperty($o,'___type', $ELSCOPE_READONLY, $classname)
  ;prepare to do fields
  Local $x,$i,$a,$y,$p
  Local $scope,$n,$za,$fn,$sc
  ;data array is public, private, readonly
  ;TODO: private+readonly?? ugh, didn't think about that
  For $x=0 to 2
    $i=$ap[$x]
    ;which storage
    If $x==0 Then
      $scope=$ELSCOPE_PUBLIC
      $sc='public'
    ElseIf $x==1 Then
      $scope=$ELSCOPE_PRIVATE
      $sc='private'
    ElseIf $x==2 Then
      $scope=$ELSCOPE_READONLY
      $sc='readonly'
    EndIf
    ;empty string for these storage items
    If $i=='' Then
      If $x==0 Then
        ;Msg('No Public Fields')
      ElseIf $x==1 Then
        ;Msg('No Private Fields')
      Else
        ;Msg('No ReadOnly Fields')
      EndIf
      ContinueLoop
    EndIf
    ;split the string
    $a=StringSplit($i,Chr(9),1)
    ;each field
    For $y=1 To $a[0]
      $p=$a[$y]
      ;remove trailing semicolon
      If StringMid($p,StringLen($p),1)==';' Then
        $p=StringLeft($p,StringLen($p)-1)
      EndIf
      ;handle string has assignment
      ;TODO:how does Execute() work, can I get at locals somehow?
      If StringInStr($p,"=")>0 Then
        ;get the name part
        $n = StringReplace(StringLeft($p,StringInStr($p,"=")-1)," ","")
        ;add the evaluated field
        _AutoItObject_AddProperty($o,$n, $scope, Execute(StringTrimLeft($p,StringInStr($p,"="))))
        ContinueLoop
      EndIf
      ;handle declarations without assignments
      If StringLen($p)>0 Then
          ;get the name
          $n = StringReplace($p," ","")
          ;Msg('making field for:"'&$n&'" as '&$sc);
          ;add the field and set to a empty string
          _AutoItObject_AddProperty($o,$n, $scope, '')
          ContinueLoop
      EndIf
    Next
  Next
  ;prepare to gather iterator declarations (Enums)
  Local $enums[3]
  $enums[0]=''
  $enums[1]=''
  $enums[2]=''
  ;function data array is public,private
  For $x=0 to 1
    $i=$af[$x]
    ;set scope
    If $x==0 Then
      $scope=False
    ElseIf $x==1 Then
      $scope=True
    EndIf
    ;split data
    $a=StringSplit($i,Chr(9),1)
    ;for each function
    For $y=1 To $a[0]
      $p=$a[$y]
      ;split into <functionname for object> and <functionname in code>
      $za=StringSplit($p,' ',3)
      $n=$za[0]
      $fn=$za[1]
      ;handle destructor
      If $n=='destructor' Then
        ;Msg('adding destructor')
        ;$o.AddDestructor($n, $fn)
        _AutoItObject_AddDestructor($o,$fn)
      Else
        ;handle iterator (enums)
        If $n=='EnumNext' Then
          $enums[0]=$p
        ElseIf $n=='EnumReset' Then
          $enums[1]=$p
        ElseIf $n=='EnumSkip' Then
          $enums[2]=$p
        Else
          ;handle normal
          _AutoItObject_AddMethod($o,$n,$fn,$scope)
        EndIf
      EndIf
    Next
  Next
  ;now build iterators (enums)
  If $enums[0]<>'' Then
    ;TODO:error handling
    If $enums[1]<>'' Then
      If $enums[2]<>'' Then
        _AutoItObject_AddEnum($o,$enums[0],$enums[1],$enums[2])
      Else
        _AutoItObject_AddEnum($o,$enums[0],$enums[1]])
      EndIf
    EndIf
  EndIf
  Return $o
EndFunc

Any feedback is welcome, especially information on the limits of AIO.

 

Posted (edited)

RafaelMaciel,

I think I did warn you when I gave a reply to you original post that it looked like a bug but that I could be wrong. And I was absolutely right, I was wrong.

What we should have done was to read the manual! If you look at the first post that Prog@ndy made, he stated, amongst other things,

 


Q. My GUI freezes! Why and how do I fix it? All methods are essentially dllcallbacks. Unfortunately this means that messages are not processed while your methods are being executed. As long as you keep your main loop outside any method, you'll be fine.

So I modified the example I produced as below, and lo and behind, we are fine!

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include "C:\Program Files\Autoit3\include\AutoitObject.au3"

Dim $doexit
dim $AnalistaFormMain


_AutoItObject_StartUp()

extern2("Window 1") ;create window without using objects

While $doexit = 0
    Sleep(30)
WEnd


Global $C_Analista = _Analista_create();global detentora do objeto ANALISTA


$C_Analista.formMain

While $doexit = 0
    Sleep(30)
WEnd

$C_Analista = 0;destroy the object

_AutoItObject_Shutdown();don't forget this line although the examples do


Func _Analista_create()
    Local $oClassObject = _AutoItObject_Class()
    $oClassObject.Create()

    $oClassObject.AddMethod("formMain", "_Analista_main")
    $oClassObject.AddDestructor("_DestructorForAnalista")
    Return $oClassObject.Object
EndFunc   ;==>_Analista_create

Func _Analista_main($oSelf)
    extern2("window from object")
EndFunc   ;==>_Analista_main

Func extern2($title)
    AutoItSetOption("guioneventmode", 1)
    $doexit = 0
    #region ### START Koda GUI section ###
    $AnalistaFormMain = GUICreate($title, 224, 438, 10, 10);, BitOR($WS_SYSMENU, $WS_BORDER, $WS_CAPTION))
    GUISetState(@SW_SHOW)
    #endregion ### END Koda GUI section ###
    ConsoleWrite("step 4" & @LF)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGui")

EndFunc   ;==>extern2

Func CloseGui()
    ConsoleWrite("close gui?" & @LF)
    GUIDelete($AnalistaFormMain)
    $doexit = 1
EndFunc   ;==>CloseGui


Func _DestructorForAnalista($oSelf)
    ConsoleWrite("!...destructing... 'Analista'" & @CRLF)
    GUIDelete($AnalistaFormMain)
EndFunc   ;==>_DestructorForAnalista
 
Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Posted

Cross-Posting from here:'?do=embed' frameborder='0' data-embedContent>>

 

"Hi (probably replying to late to this but I just came across it whilst looking for something else)

It is not a good idea to put your main loop inside a method.

Basically the code will run inside the method and it doesn't get a chance to process your input.

Here is an alternative approach (hope it helps)"


#include 'AutoitObject.au3'
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
_AutoItObject_StartUp()

#region Form Class ========================================
Func Form()
    Local $this = _AutoItObject_Class()

    ; field properties
    $this.AddProperty('Handle', $ELSCOPE_READONLY)
    $this.AddProperty('IsInitialised', $ELSCOPE_READONLY, False)

    ; get/set propeties
    $this.AddMethod('Visible', '___Form_Visible')

    ; methods
    $this.AddMethod('Load', '___Form_Load')

    ; destructors
    $this.AddDestructor('_Analista_Finalise')
    Return $this.Object
EndFunc   ;==>Form
;-------------------------------------------------------
Func ___Form_Load($self, $iCaption = 'Form', $iLeft = Default, $iTop = Default, $iWidth = Default, $iHeight = Default, $iStyle = Default, $iStyleEx = Default)
    $self.Handle = String(GUICreate($iCaption, $iWidth, $iHeight, $iLeft, $iTop, $iStyle, $iStyleEx))
    $self.IsInitialised = True
EndFunc   ;==>___Form_Load
;-------------------------------------------------------
Func ___Form_Visible($self, $iVisible = Default)
    If Not $self.IsInitialised Then Return SetError(1)
    Switch @NumParams
        Case 1 ; get
            Return (BitAND(WinGetState(HWnd($self.Handle), ''), 2) = 1) ; 2 = Window is visible
        Case 2 ; set
            If Not IsBool($iVisible) Then Return SetError(2)
            Switch $iVisible
                Case True
                    Return WinSetState(HWnd($self.Handle), '', @SW_SHOW)
                Case False
                    Return WinSetState(HWnd($self.Handle), '', @SW_HIDE)
            EndSwitch
    EndSwitch
EndFunc   ;==>___Form_Visible
;-------------------------------------------------------
Func ___Form_Finalise($self)
    If Not $self.IsInitialised Then Return SetError(1)
    GUIDelete(HWnd($self.Handle))
EndFunc   ;==>___Form_Finalise
#endregion Form Class ========================================


; Main Program
Global $C_Analista = Form()
;~ $C_Analista.Load('Analista', 10, 10, 224, 438, BitOR($WS_SYSMENU, $WS_BORDER, $WS_CAPTION))
$C_Analista.Load('Analista')
$C_Analista.Visible = True

While 1
    $nMsg = GUIGetMsg()
    ConsoleWrite('!...Tela  travada' & @CRLF)
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            $C_Analista.Visible = False
            $C_Analista = 0
            _AutoItObject_Shutdown()
            Exit
    EndSwitch
WEnd
Posted

About Ptrs and Hwnds in AIO

The docs weren't so clear on this, so I am posting my little goose chase here for posterity.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <AutoItObject.au3>

; ===============================================================================================================================
; Background: In attempting to use AutoItObject, I discover neither fields nor function return types can be Ptr.
;             Though the docs say Ptrs cannot be params, and we cannot pass ByRef, it does not say anything about
;             field types and return types.
;             Ptr values will be converted to Int32, making it impossible to create an assignable hwnd property on
;             an AutoItObject.
;             This means you can create the assignable, but every time you use it you must wrap it in an HWnd().
;             This holds true whether you are inside the object or a client
;             Here is an example of the code to assign as a method, which will create an assignable:
#cs
Func Hwnd__FormObj($me,$value='0')
  If @NumParams = 2 Then ;am assigning
    ;could store it in backer as Int32 auto-not-magically via simple assignment, but doing it as string here
    $me._Hwnd='0x'&hex($value)
  Else ;am being read
    ;this returns an Int32, not an Hwnd. See below
    Return hwnd(int($s))
  EndIf
EndFunc
#ce
;             This is the usage inside the object
#cs
Func WinMove__FormObj($me,$x,$y)
  ;note the conversion, same applies when you are client of class, ie HWnd($obj.Hwnd)
  Return WinMove(HWnd($me.Hwnd),"",$x,$y)
EndFunc
#ce
; ===============================================================================================================================

; debug util, can be anything, has no external effect
Global $thisfile='C:\batch\borg\BadHwndTest.au3'

Global $hGui
; setup for AIO
_AutoItObject_Startup()
OnAutoItExitRegister("EvtScriptExit")
Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc")

; spec
Global $wintitle="TargetWindow"

; create our AIO
Global $AIO=AutoItObjCtor()
; globals for testing
Global $hgui_as_str
Global $hgui_as_hwnd

Global $hgui_as_str_from_aio
Global $hgui_as_hwnd_from_aio
; debug testing var
Global $inform_step=0

;Make it
Example1()
Exit
; Main
Func Example1()
    Local $msg
    $hGui=GUICreate($wintitle)
    GUISetState(@SW_SHOW)
    ; BEGIN TESTING
    $hgui_as_str='0x'&hex($hGui)
    Inform('With $hgui_as_str="0x"&hex($hGui), we have a valid str', _
    "Using $hgui_as_str. Is typical and will show hwnd in hex form 0x????????:"&@CRLF&$hgui_as_str)
    ;
    $hgui_as_hwnd=Hwnd(Int($hgui_as_str))
    Inform('With $hgui_as_hwnd=Hwnd(Int($hgui_as_str)), we convert $hgui_as_str to hwnd', _
    "Using $hgui_as_hwnd. Is typical and will show window title '"&$wintitle&"':"&@CRLF&WinGetTitle($hgui_as_hwnd,"")); all is well
    ;
    $AIO.hwnd_as_str=$hgui_as_str
    Inform('With $AIO.hwnd_as_str=$hgui_as_str, we prepare to let the AutoItObject do the conversion...', _
    "Using $AIO.GetHwnd(). Will Fail with 0, should show title '"&$wintitle&"':"&@CRLF&WinGetTitle($AIO.GetHwnd()));
    ;
    Inform('But, We ARE getting a handle', _
    "Using hex($AIO.GetHwnd()). Will Succeed and show hwnd in hex form 0x????????:"&@CRLF&'0x'&hex($AIO.GetHwnd()))
    ;
    Inform('Compare Object Types with VarGetType()', _
    "Using $hGui, $AIO.GetHwnd(). Aha, is returning Int32 not Ptr:"&@CRLF&'$hGui:'&VarGetType($hGui)&@CRLF&'$AIO.GetHwnd():'&VarGetType($AIO.GetHwnd()))
    ;
    Inform('Try Convering the Int32 to Hwnd', _
    "Using $AIO.GetHwnd(). Will Succeed and should show title '"&$wintitle&"':"&@CRLF&WinGetTitle(Hwnd($AIO.GetHwnd())));
    ;
    $AIO.hwnd_as_hwnd=$hGui
    Inform('With $AIO.hwnd_as_hwnd, Can a field be a hwnd?', _
    "Using VarGetType($AIO.hwnd_as_hwnd). No, it cannot:"&@CRLF&'$hGui:'&VarGetType($hGui)&@CRLF&'$AIO.hwnd_as_hwnd:'&VarGetType($AIO.hwnd_as_hwnd))

    While 1
      $msg = GUIGetMsg()
      If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    WEnd
    GUIDelete()
EndFunc   ;==>Example1

; Begin AIO stuff
Func AutoItObjCtor()
  Local $me = _AutoItObject_Create()
  _AutoItObject_AddProperty($me,"hwnd_as_str",$ELSCOPE_PUBLIC,'')
  _AutoItObject_AddProperty($me,"hwnd_as_hwnd",$ELSCOPE_PUBLIC,'')
  _AutoItObject_AddMethod($me,"GetHwnd","_AutoItObj_GetHwnd")
  _AutoItObject_AddMethod($me,"ProveCanReturnHwnd","_AutoItObj_ProveCanReturnHwnd")
  Return $me
EndFunc

Func _AutoItObj_GetHwnd($me)
  Msg('In _AutoItObj_GetHwnd(),$me.hwnd_as_str:'&$me.hwnd_as_str)
  ;HERE! hwnd function does not work, or so I thought, the real problem is cannot return an Hwnd
  Return hwnd(int($me.hwnd_as_str))
EndFunc

Func _AutoItObj_ProveCanReturnHwnd($me)
  Msg('In _AutoItObj_ProveCanReturnHwnd, goint to return $hGui:0x'&hex($hgui))
  Return $hGui;
EndFunc


;UTILS
Func Msg($s)
  MsgBox(0,$thisfile,$s)
EndFunc
Func Inform($t,$s)
  $inform_step+=1
  $s='Step '&$inform_step&@CRLF&$s
  MsgBox(0,$t,$s)
EndFunc
Func _ErrFunc()
  Local $line="[COM Error]:s"&$oError.source&" ScriptLine(" & $oError.scriptline & ") : Number 0x" & Hex($oError.number, 8) & " - " & $oError.windescription
  Msg($line)
EndFunc
  • 3 weeks later...
Posted

BUG!: Whats so special about 'E3'? Cannot use this name as a method?

#include <AutoItObject.au3>
OnAutoItExitRegister("EvtScriptExit")
_AutoItObject_StartUp()

Global $o=_AutoItObject_Create()

;BUG: Cannot seem to make a property-type method called E3, other names work however

MsgBox(0,'VarGetType($o)',VarGetType($o));checkit

;Change this to false to show the bug
Global $make_it_work=True


If Not $make_it_work Then
  ;Make an E3 property and backer
  _AutoItObject_AddProperty($o,'_E3',$ELSCOPE_PUBLIC,'initialized')
  _AutoItObject_AddMethod($o,'E3','E3_property',False)
Else
  ;Make an F3 property and backer
  _AutoItObject_AddProperty($o,'_E3',$ELSCOPE_PUBLIC,'initialized')
  _AutoItObject_AddMethod($o,'F3','E3_property',False); THIS LINE DIFFERS IN NAME ONLY 'F3'
EndIf



If Not $make_it_work Then
  MsgBox(0,'$o.E3',$o.E3); ERROR Error in expression at $o.E3
Else
  MsgBox(0,'$o.F3',$o.F3); Not a problem
EndIf


Func E3_property($me,$value=-1)
  If @NumParams==2 Then
    $me._E3=$value
  Else
    Return $me._E3
  EndIf
EndFunc

Func EvtScriptExit()
  _AutoItObject_Shutdown()
EndFunc

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...