Hallo meine lieben - schon mal Danke für das rege Feedback - ich komme aber erst später dazu, hier ausgiebig(er) zu antworten.
Beiträge von SEuBo
-
-
-
Was Du vermutlich brauchst, ist ein sog. Backbuffer. Schau Dir mal ein paar Threads im Zusammenhang von AutoIt, GDI+ und Backbuffer an.
Außerdem solltest Du die Grafik wahrscheinlich nur zu bestimmten Zeitpunkten aktualisieren. Windows stellt dafür Events (Stichwort: WM_PAINT) zur Verfügung.
Mehr Infos gibt es z.B. hier:
GDI+ Backbuffer verstehen - Übersicht
https://www.autoitscript.com/forum/topic/10…i-doublebuffer/
https://www.autoitscript.com/forum/topic/86210-gdi/
Hier ist ein altes Beispiel von mir, als ich noch tiefer in dem Thema steckte - starten, Shift-Taste gedrückt halten und die Maus bewegen:
Spoiler anzeigen
C
Alles anzeigen#cs GDI+ Example - Draw on Transparent & Click-Through GUI by SEuBo, 24.12.2010 http://www.elitepvpers.com/forum/autoit/903693-autoit-auf-den-bildschirm-malen.html #ce #include <WinAPIEx.au3> #include <Misc.au3> #include <GDIPlus.au3> #include <WindowsConstants.au3> ;Variablen deklarieren Local $hGUI, $hGraphics, $hBitmap, $hBackBuffer, $hPen Local $hDLL, $aMPos, $aMPos_New ;GDI+ initialisieren, DLL für _IsPressed öffnen und ESC als HotKey festlegen _GDIPlus_Startup() $hDLL = DllOpen("user32.dll") HotKeySet("{ESC}","_Exit") ;Transparente GUI erstellen $hDummy = GUICreate("") ; Dummy GUI, damit richtiges nicht in Taskleiste auftaucht. $hGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST,$WS_EX_TRANSPARENT),$hDummy) GUISetBkColor(0xABCDEF, $hGUI) _WinAPI_SetLayeredWindowAttributes($hGUI, 0xABCDEF, 255) ;Graphic-Objekt, Pinsel und Backbuffer erstellen und GUI anzeigen $hPen = _GDIPlus_PenCreate(0xFFFF0000,4) ; Roten Pinsel mit Breite von 4 px. $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hBitmap = _GDIPlus_BitmapCreateFromGraphics(@DesktopWidth, @DesktopHeight, $hGraphics) $hBackBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap) GUISetState() While Sleep(10) $aMPos = MouseGetPos() While _IsPressed(10, $hDLL) $aMPos_New = MouseGetPos() ;~ If Not IsArray($aMPos) Then $aMPos = $aMPos_New If $aMPos[0] <> $aMPos_New[0] Or $aMPos[1] <> $aMPos_New[1] Then _GDIPlus_GraphicsDrawLine($hBackBuffer, $aMPos[0], $aMPos[1], $aMPos_New[0], $aMPos_New[1],$hPen) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) $aMPos = $aMPos_New EndIf WEnd WEnd Func _Exit() _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_PenDispose($hPen) GUIDelete($hGUI) Exit EndFunc
Viele Grüße,
-
-
AutoItSimpleObjects.au3
Spoiler anzeigen
AutoIt: AutoItSimpleObjects.au3
Alles anzeigen; AutoIt Simple Objects #include <AutoItObject_Internal.au3> Func _ASO_Create($oParent = Null) Local $oObject = IDispatch(QueryInterface, AddRef, Release, GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, _ __ASO_Invoke) ; <-- If $oParent <> Null Then For $sKey In $oParent.__keys $oObject.__set($sKey, $oParent.__get($sKey)) Next EndIf _ASO_AddProperty($oObject, '__dirty', False) ;_ASO_AddMethod($oObject, '__call', _ASO_CallMethod) ;_ASO_AddMethod($oObject, '__addMethod', _ASO_AddMethod) ;_ASO_AddMethod($oObject, '__addProperty', _ASO_AddProperty) Return $oObject EndFunc ;==>_ASO_Create ;Func _ASO_CallMethod(Const ByRef $oObject, Const ByRef $vMethod) ; Local $oThis = (IsObj($oObject)?$oObject:_ASO_This()) ; Local $pFunc = (IsFunc($vMethod)?$vMethod:$oThis.__get($vMethod)) ; Return $pFunc() ;EndFunc ;==>_ASO_AddProperty Func _ASO_AddProperty(Const ByRef $oObject, Const ByRef $sPropertyName, $vPropertyValue = "") Local $oThis = (IsObj($oObject)?$oObject:_ASO_This()) $oThis.__set($sPropertyName, $vPropertyValue) EndFunc ;==>_ASO_AddProperty Func _ASO_AddMethod(Const ByRef $oObject, Const ByRef $sMethodName, $vFunction) Local $oThis = (IsObj($oObject)?$oObject:_ASO_This()) If Not IsFunc($vFunction) Then $vFunction = Execute($vFunction) $oThis.__set($sMethodName, $vFunction) EndFunc ;==>_ASO_AddMethod Func _ASO_This($__oINTERNALUSE = Null) Local Static $pThis = Null If $__oINTERNALUSE <> Null Then $pThis = $__oINTERNALUSE If $__oINTERNALUSE = Null Then AddRef($pThis) Return ObjCreateInterface($pThis, $IID_IDispatch, Default,True) EndIf EndFunc ;==>_ASO_This Func __ASO_Invoke($pSelf, $dispIdMember, $riid, $lcid, $wFlags, $pDispParams, $pVarResult, $pExcepInfo, $puArgErr) If $dispIdMember = 0 Then Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") Local $bCase = Not (BitAND($iLock, $__AOI_LOCK_CASE) > 0) __AOI_PropertyGetFromName(__AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("Properties"), "ptr"), "", $bCase) $dispIdMember = @error <> 0 ? -1 : (@extended + 1) EndIf ;ConsoleWrite(StringFormat("Invoke $pSelf %s, $dispIdMember %s, $riid %s, $lcid %s, $wFlags %s, $pDispParams %s, $pVarResult %s, $pExcepInfo %s, $puArgErr %s", _ ;$pSelf, $dispIdMember, $riid, $lcid, $wFlags, $pDispParams, $pVarResult, $pExcepInfo, $puArgErr)) If $dispIdMember = -1 Then Return $DISP_E_MEMBERNOTFOUND Local $tVARIANT, $_tVARIANT, $tDISPPARAMS Local $t Local $i Local $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) Local $tProperty = DllStructCreate($tagProperty, $pProperty) If $dispIdMember < -1 Then If $dispIdMember = -3 Then;__isExtensible Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") Local $iExtensible = $__AOI_LOCK_CREATE $tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) $tVARIANT.vt = $VT_BOOL $tVARIANT.data = (BitAND($iLock, $iExtensible) = $iExtensible) ? 1 : 0 Return $S_OK EndIf If $dispIdMember = -4 Then;__case $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If (Not (BitAND($wFlags, $DISPATCH_PROPERTYGET) = 0)) Then If $tDISPPARAMS.cArgs <> 0 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) $tVARIANT.vt = $VT_BOOL Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") $tVARIANT.data = (BitAND($iLock, $__AOI_LOCK_CASE) > 0) ? 0 : 1 Else; $DISPATCH_PROPERTYPUT If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If $tVARIANT.vt <> $VT_BOOL Then Return $DISP_E_BADVARTYPE Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_UPDATE) > 0 Then Return $DISP_E_EXCEPTION Local $tLock = DllStructCreate("BYTE", $pSelf + __AOI_GetPtrOffset("lock")) $b = DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs), "data") DllStructSetData($tLock, 1, _ (Not $b) ? BitOR(DllStructGetData($tLock, 1), $__AOI_LOCK_CASE) : BitAND(DllStructGetData($tLock, 1), BitNOT(BitShift(1, 0 - (Log($__AOI_LOCK_CASE) / Log(2))))) _ ) EndIf Return $S_OK EndIf If $dispIdMember = -13 Then;__lookupSetter $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) DllStructSetData($t, "str_ptr", $tDISPPARAMS.rgvargs) $t.str_ptr = DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs), "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") If Not GetIDsOfNames($pSelf, $riid, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) = $S_OK Then Return $DISP_E_EXCEPTION $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) $tProperty = __AOI_PropertyGetFromId($pProperty, $t.id - 1) If Not $tProperty.__setter = 0 Then VariantClear($pVarResult) VariantCopy($pVarResult, $tProperty.__setter) EndIf Return $S_OK EndIf If $dispIdMember = -12 Then;__lookupGetter $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) DllStructSetData($t, "str_ptr", $tDISPPARAMS.rgvargs) $t.str_ptr = DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs), "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") If Not GetIDsOfNames($pSelf, $riid, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) = $S_OK Then Return $DISP_E_EXCEPTION $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) $tProperty = __AOI_PropertyGetFromId($pProperty, $t.id - 1) If Not $tProperty.__getter = 0 Then VariantClear($pVarResult) VariantCopy($pVarResult, $tProperty.__getter) EndIf Return $S_OK EndIf If $dispIdMember = -2 Then;__assign Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_CREATE) > 0 Then Return $DISP_E_EXCEPTION $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs = 0 Then Return $DISP_E_BADPARAMCOUNT Local $tVARIANT = DllStructCreate($tagVARIANT) Local $iVARIANT = DllStructGetSize($tVARIANT) Local $i Local $pExternalProperty, $tExternalProperty Local $pProperty, $tProperty Local $iID, $iIndex, $pData For $i = $tDISPPARAMS.cArgs - 1 To 0 Step -1 $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + $iVARIANT * $i) If Not (DllStructGetData($tVARIANT, "vt") = $VT_DISPATCH) Then Return $DISP_E_BADVARTYPE $pExternalProperty = __AOI_GetPtrValue(DllStructGetData($tVARIANT, "data") + __AOI_GetPtrOffset("Properties"), "ptr") While 1 If $pExternalProperty = 0 Then ExitLoop $tExternalProperty = DllStructCreate($tagProperty, $pExternalProperty) $pProperty = __AOI_PropertyGetFromName(__AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("Properties"), "ptr"), _WinAPI_GetString($tExternalProperty.Name), False) $iID = @error <> 0 ? -1 : @extended $iIndex = @extended If ($iID = -1) Then $pData = __AOI_PropertyCreate(_WinAPI_GetString($tExternalProperty.Name)) $tProperty = DllStructCreate($tagProperty, $pData) VariantClear($tProperty.Variant) VariantCopy($tProperty.Variant, $tExternalProperty.Variant) If $iIndex = -1 Then;first item in list DllStructSetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1, $pData) Else $tProperty = DllStructCreate($tagProperty, $pProperty) $tProperty.Next = $pData EndIf Else $tProperty = DllStructCreate($tagProperty, $pProperty) VariantClear($tProperty.Variant) VariantCopy($tProperty.Variant, $tExternalProperty.Variant) EndIf $pExternalProperty = $tExternalProperty.Next WEnd Next Return $S_OK EndIf If $dispIdMember = -7 Then;__isSealed Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") Local $iSeal = $__AOI_LOCK_CREATE + $__AOI_LOCK_DELETE $tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) $tVARIANT.vt = $VT_BOOL $tVARIANT.data = (BitAND($iLock, $iSeal) = $iSeal) ? 1 : 0 Return $S_OK EndIf If $dispIdMember = -6 Then;__isFrozen Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") Local $iFreeze = $__AOI_LOCK_CREATE + $__AOI_LOCK_UPDATE + $__AOI_LOCK_DELETE $tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) $tVARIANT.vt = $VT_BOOL $tVARIANT.data = (BitAND($iLock, $iFreeze) = $iFreeze) ? 1 : 0 Return $S_OK EndIf If $dispIdMember = -18 Then;__get $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If $tVARIANT.vt <> $VT_BSTR Then Return $DISP_E_BADVARTYPE $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) DllStructSetData($t, "str_ptr", $tDISPPARAMS.rgvargs) $t.str_ptr = DllStructGetData($tVARIANT, "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") If Not GetIDsOfNames($pSelf, 0, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) = $S_OK Then Return $DISP_E_EXCEPTION Return Invoke($pSelf, $t.id, $riid, $lcid, $DISPATCH_PROPERTYGET, $pDispParams, $pVarResult, $pExcepInfo, $puArgErr) EndIf If $dispIdMember = -19 Then;__set $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 2 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + DllStructGetSize(DllStructCreate($tagVARIANT))) If $tVARIANT.vt <> $VT_BSTR Then Return $DISP_E_BADVARTYPE $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) $t.str_ptr = DllStructGetData($tVARIANT, "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") If Not GetIDsOfNames($pSelf, 0, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) = $S_OK Then Return $DISP_E_EXCEPTION $tDISPPARAMS.cArgs = 1 Return Invoke($pSelf, $t.id, $riid, $lcid, $DISPATCH_PROPERTYPUT, $pDispParams, $pVarResult, $pExcepInfo, $puArgErr) EndIf If $dispIdMember = -20 Then;__exists $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If $tVARIANT.vt <> $VT_BSTR Then Return $DISP_E_BADVARTYPE Local $sProperty = _WinAPI_GetString($tVARIANT.data);the string to search for $tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) $tVARIANT.vt = $VT_BOOL Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") Local $bCase = Not (BitAND($iLock, $__AOI_LOCK_CASE) > 0) Local $pProperty = __AOI_PropertyGetFromName(__AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("Properties"), "ptr"), $sProperty, $bCase) $tVARIANT.data = @error <> 0 ? 0 : 1 Return $S_OK EndIf If $dispIdMember = -16 Then;__destructor Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_CREATE) > 0 Then Return $DISP_E_EXCEPTION $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT If (Not (DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs), "vt") = $VT_RECORD)) And (Not (DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs), "vt") = $VT_BSTR)) Then Return $DISP_E_BADVARTYPE Local $tVARIANT = DllStructCreate($tagVARIANT) Local $pVARIANT = MemCloneGlob($tVARIANT) $tVARIANT = DllStructCreate($tagVARIANT, $pVARIANT) VariantInit($pVARIANT) VariantCopy($pVARIANT, $tDISPPARAMS.rgvargs) DllStructSetData(DllStructCreate("PTR", $pSelf + __AOI_GetPtrOffset("__destructor")), 1, $pVARIANT) Return $S_OK EndIf If $dispIdMember = -5 Then;__freeze $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 0 Then Return $DISP_E_BADPARAMCOUNT Local $tLock = DllStructCreate("BYTE", $pSelf + __AOI_GetPtrOffset("lock")) DllStructSetData($tLock, 1, BitOR(DllStructGetData($tLock, 1), $__AOI_LOCK_CREATE + $__AOI_LOCK_DELETE + $__AOI_LOCK_UPDATE)) Return $S_OK EndIf If $dispIdMember = -14 Then;__seal $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 0 Then Return $DISP_E_BADPARAMCOUNT Local $tLock = DllStructCreate("BYTE", $pSelf + __AOI_GetPtrOffset("lock")) DllStructSetData($tLock, 1, BitOR(DllStructGetData($tLock, 1), $__AOI_LOCK_CREATE + $__AOI_LOCK_DELETE)) Return $S_OK EndIf If $dispIdMember = -9 Then;__preventExtensions $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 0 Then Return $DISP_E_BADPARAMCOUNT Local $tLock = DllStructCreate("BYTE", $pSelf + __AOI_GetPtrOffset("lock")) DllStructSetData($tLock, 1, BitOR(DllStructGetData($tLock, 1), $__AOI_LOCK_CREATE)) Return $S_OK EndIf If $dispIdMember = -17 Then;__unset Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_DELETE) > 0 Then Return $DISP_E_EXCEPTION $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 1 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If Not ($VT_BSTR = $tVARIANT.vt) Then Return $DISP_E_BADVARTYPE Local $sProperty = _WinAPI_GetString($tVARIANT.data);the string to search for Local $tProperty = 0, $tProperty_Prev While 1 If $pProperty = 0 Then ExitLoop $tProperty_Prev = $tProperty $tProperty = DllStructCreate($tagProperty, $pProperty) Local $bCase = Not (BitAND($iLock, $__AOI_LOCK_CASE) > 0) If ($bCase And _WinAPI_GetString($tProperty.Name) == $sProperty) Or ((Not $bCase) And _WinAPI_GetString($tProperty.Name) = $sProperty) Then If $tProperty_Prev = 0 Then DllStructSetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1, $tProperty.Next) Else $tProperty_Prev.Next = $tProperty.Next EndIf VariantClear($tProperty.Variant) _MemGlobalFree(GlobalHandle($tProperty.Variant)) $tProperty = 0 _MemGlobalFree(GlobalHandle($pProperty)) Return $S_OK EndIf $pProperty = $tProperty.Next WEnd Return $DISP_E_MEMBERNOTFOUND EndIf If ($dispIdMember = -8) Then;__keys Local $aKeys[0] Local $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) While 1 If $pProperty = 0 Then ExitLoop Local $tProperty = DllStructCreate($tagProperty, $pProperty) ReDim $aKeys[UBound($aKeys, 1) + 1] $aKeys[UBound($aKeys, 1) - 1] = DllStructGetData(DllStructCreate("WCHAR[" & _WinAPI_StrLen($tProperty.Name) & "]", $tProperty.Name), 1) If $tProperty.Next = 0 Then ExitLoop $pProperty = $tProperty.Next WEnd Local $oIDispatch = IDispatch() $oIDispatch.a = $aKeys VariantClear($pVarResult) VariantCopy($pVarResult, DllStructGetData(DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oIDispatch) + __AOI_GetPtrOffset("Properties")), 1)), "Variant")) $oIDispatch = 0 Return $S_OK EndIf If ($dispIdMember = -10) Then;__defineGetter Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_CREATE) > 0 Then Return $DISP_E_EXCEPTION $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 2 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If Not (($tVARIANT.vt = $VT_RECORD) Or ($tVARIANT.vt = $VT_BSTR)) Then Return $DISP_E_BADVARTYPE Local $tVARIANT2 = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + DllStructGetSize($tVARIANT)) If Not ($tVARIANT2.vt = $VT_BSTR) Then Return $DISP_E_BADVARTYPE $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) DllStructSetData($t, "str_ptr", $tDISPPARAMS.rgvargs + DllStructGetSize(DllStructCreate($tagVARIANT))) $t.str_ptr = DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + DllStructGetSize(DllStructCreate($tagVARIANT))), "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") GetIDsOfNames($pSelf, 0, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) $tProperty = __AOI_PropertyGetFromId($pProperty, $t.id - 1) If ($tProperty.__getter = 0) Then Local $tVARIANT_Getter = DllStructCreate($tagVARIANT) $pVARIANT_Getter = MemCloneGlob($tVARIANT_Getter) VariantInit($pVARIANT_Getter) Else Local $pVARIANT_Getter = $tProperty.__getter VariantClear($pVARIANT_Getter) EndIf $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) VariantCopy($pVARIANT_Getter, $tVARIANT) $tProperty.__getter = $pVARIANT_Getter Return $S_OK ElseIf ($dispIdMember = -11) Then;defineSetter Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_CREATE) > 0 Then Return $DISP_E_EXCEPTION $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If $tDISPPARAMS.cArgs <> 2 Then Return $DISP_E_BADPARAMCOUNT $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) If Not (($tVARIANT.vt = $VT_RECORD) Or ($tVARIANT.vt = $VT_BSTR)) Then Return $DISP_E_BADVARTYPE Local $tVARIANT2 = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + DllStructGetSize($tVARIANT)) If Not ($tVARIANT2.vt = $VT_BSTR) Then Return $DISP_E_BADVARTYPE $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) $t = DllStructCreate("ptr id_ptr;long id;ptr str_ptr_ptr;ptr str_ptr") DllStructSetData($t, "id_ptr", DllStructGetPtr($t, 2)) DllStructSetData($t, "str_ptr", $tDISPPARAMS.rgvargs + DllStructGetSize(DllStructCreate($tagVARIANT))) $t.str_ptr = DllStructGetData(DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + DllStructGetSize(DllStructCreate($tagVARIANT))), "data") $t.str_ptr_ptr = DllStructGetPtr($t, "str_ptr") GetIDsOfNames($pSelf, 0, $t.str_ptr_ptr, 1, $lcid, DllStructGetPtr($t, "id")) $pProperty = DllStructGetData(DllStructCreate("ptr", $pSelf + __AOI_GetPtrOffset("Properties")), 1) $tProperty = DllStructCreate($tagProperty, $pProperty) $tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) For $i = 1 To $t.id - 1 $pProperty = $tProperty.Next $tProperty = DllStructCreate($tagProperty, $pProperty) Next If ($tProperty.__setter = 0) Then Local $tVARIANT_Setter = DllStructCreate($tagVARIANT) Local $pVARIANT_Setter = MemCloneGlob($tVARIANT_Setter) VariantInit($pVARIANT_Setter) Else Local $pVARIANT_Setter = $tProperty.__setter VariantClear($pVARIANT_Setter) EndIf VariantCopy($pVARIANT_Setter, $tVARIANT) $tProperty.__setter = $pVARIANT_Setter Return $S_OK EndIf Return $DISP_E_EXCEPTION EndIf For $i = 1 To $dispIdMember - 1 $pProperty = $tProperty.Next $tProperty = DllStructCreate($tagProperty, $pProperty) Next $tVARIANT = DllStructCreate($tagVARIANT, $tProperty.Variant) If BitAND($wFlags, $DISPATCH_METHOD) = $DISPATCH_METHOD Then $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) Local $tHelperProperty, $iArguments, $oHelper = IDispatch() $oHelper.val = 0 $tHelperProperty = DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oHelper) + __AOI_GetPtrOffset("Properties")), 1)) VariantClear($tHelperProperty.Variant) VariantCopy($tHelperProperty.Variant, $tVARIANT) $sFunc = $oHelper.val If $tDISPPARAMS.cArgs Then Local $aArguments[$tDISPPARAMS.cArgs + 1];, $sArguments For $i = 1 To $tDISPPARAMS.cArgs $tVariantSource = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + (($tDISPPARAMS.cArgs - $i) * DllStructGetSize($tVARIANT))) VariantCopy($tHelperProperty.Variant, $tVariantSource) $aArguments[$i] = $oHelper.val Next $aArguments[0] = 'CallArgArray' $oHelper.val = 0 _ASO_This($pSelf) If IsFunc($sFunc) Then $iRet = Call($sFunc, $aArguments) $iError = @error $iExtended = @extended If Hex($iError, 4) = 'DEAD' Then Return $DISP_E_BADPARAMCOUNT ; insert magic to return byRef params here. ;~ For $i = 2 To $tDISPPARAMS.cArgs ;~ $tVariantSource = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs + (($tDISPPARAMS.cArgs - $i - 1) * DllStructGetSize($tVARIANT))) ;~ $oHelper.val = $aArguments[$i] ;~ VariantClear($tVariantSource) ;~ VariantCopy($tVariantSource, $tHelperProperty.Variant) ;~ Next $oHelper.val = $iRet SetError($iError, $iExtended) VariantClear($pVarResult) VariantCopy($pVarResult, $tHelperProperty.Variant) Return $S_OK Else If IsFunc($sFunc) Then _ASO_This($pSelf) $oThis = _ASO_This() $oHelper.val = '0xDEAD' If Not $oThis.__dirty Then Local $aArguments[1] = ["CallArgArray"] $oHelper.val = Call($sFunc, $aArguments) $iError = @error $iExtended = @extended $oError = 0 EndIf If $oHelper.val <> '0xDEAD' And Hex($iError, 4) = 0 Then VariantCLEAR($pVarResult) VariantCopy($pVarResult, $tHelperProperty.Variant) SetError($iError, $iExtended) Return $S_OK EndIf _ASO_This($pSelf) EndIf ; Return whatever user asked for. VariantCopy($pVarResult, $tVARIANT) Return $S_OK EndIf ElseIf (BitAND($wFlags, $DISPATCH_PROPERTYGET) = $DISPATCH_PROPERTYGET) Then $_tVARIANT = DllStructCreate($tagVARIANT, $pVarResult) If Not ($tProperty.__getter = 0) Then $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) Local $oIDispatch = IDispatch() $oIDispatch.val = 0 $oIDispatch.ret = 0 DllStructSetData(DllStructCreate("INT", $pSelf - 4 - 4), 1, DllStructGetData(DllStructCreate("INT", $pSelf - 4 - 4), 1) + 1) $oIDispatch.parent = 0 Local $tProperty02 = DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oIDispatch) + __AOI_GetPtrOffset("Properties")), 1)) $tProperty02 = DllStructCreate($tagProperty, $tProperty02.Next) $tProperty02 = DllStructCreate($tagProperty, $tProperty02.Next) $tVARIANT = DllStructCreate($tagVARIANT, $tProperty02.Variant) $tVARIANT.vt = $VT_DISPATCH $tVARIANT.data = $pSelf $oIDispatch.arguments = IDispatch(); $oIDispatch.arguments.length = $tDISPPARAMS.cArgs Local $aArguments[$tDISPPARAMS.cArgs], $iArguments = $tDISPPARAMS.cArgs - 1 Local $_pProperty = DllStructGetData(DllStructCreate("ptr", Ptr($oIDispatch) + __AOI_GetPtrOffset("Properties")), 1) Local $_tProperty = DllStructCreate($tagProperty, $_pProperty) For $i = 0 To $iArguments VariantClear($_tProperty.Variant) VariantCopy($_tProperty.Variant, $tDISPPARAMS.rgvargs + (($iArguments - $i) * DllStructGetSize($_tVARIANT))) $aArguments[$i] = $oIDispatch.val Next $oIDispatch.arguments.values = $aArguments $oIDispatch.arguments.__seal() $oIDispatch.__defineSetter("parent", PrivateProperty) VariantClear($_tProperty.Variant) VariantCopy($_tProperty.Variant, $tProperty.__getter) Local $fGetter = $oIDispatch.val VariantClear($_tProperty.Variant) VariantCopy($_tProperty.Variant, $tProperty.Variant) $oIDispatch.__seal() Local $mRet = Call($fGetter, $oIDispatch) Local $iError = @error, $iExtended = @extended VariantClear($tProperty.Variant) VariantCopy($tProperty.Variant, $_tProperty.Variant) $oIDispatch.ret = $mRet $_tProperty = DllStructCreate($tagProperty, $_tProperty.Next) VariantCopy($pVarResult, $_tProperty.Variant) $oIDispatch = 0 Return ($iError <> 0) ? $DISP_E_EXCEPTION : $S_OK Return $S_OK ;~ Else ;~ $oHelper = IDispatch() ;~ $oHelper.val = 0 ;~ $tHelperProperty = DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oHelper) + __AOI_GetPtrOffset("Properties")), 1)) ;~ ;~ VariantInit($tHelperProperty.Variant) ;~ VariantCopy($tHelperProperty.Variant, $tVARIANT) ;~ ;~ ConsoleWrite("PropertyGet:") ;~ ConsoleWrite(VarGetType($oHelper.val) & @LF) EndIf VariantCopy($pVarResult, $tVARIANT) Return $S_OK ElseIf (BitAND($wFlags, $DISPATCH_PROPERTYPUT) = $DISPATCH_PROPERTYPUT) Then $tDISPPARAMS = DllStructCreate($tagDISPPARAMS, $pDispParams) If Not ($tProperty.__setter = 0) Then Local $oIDispatch = IDispatch() $oIDispatch.val = 0 $oIDispatch.ret = 0 DllStructSetData(DllStructCreate("INT", $pSelf - 4 - 4), 1, DllStructGetData(DllStructCreate("INT", $pSelf - 4 - 4), 1) + 1) $oIDispatch.parent = 0 Local $tProperty02 = DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oIDispatch) + __AOI_GetPtrOffset("Properties")), 1)) $tProperty02 = DllStructCreate($tagProperty, $tProperty02.Next) $tProperty02 = DllStructCreate($tagProperty, $tProperty02.Next) $tVARIANT = DllStructCreate($tagVARIANT, $tProperty02.Variant) $tVARIANT.vt = $VT_DISPATCH $tVARIANT.data = $pSelf Local $_pProperty = DllStructGetData(DllStructCreate("ptr", Ptr($oIDispatch) + __AOI_GetPtrOffset("Properties")), 1) Local $_tProperty = DllStructCreate($tagProperty, $_pProperty) Local $_tProperty2 = DllStructCreate($tagProperty, $_tProperty.Next) VariantClear($_tProperty.Variant) VariantCopy($_tProperty.Variant, $tProperty.__setter) VariantClear($_tProperty2.Variant) VariantCopy($_tProperty2.Variant, $tDISPPARAMS.rgvargs) Local $fSetter = $oIDispatch.val VariantClear($_tProperty.Variant) VariantCopy($_tProperty.Variant, $tProperty.Variant) $oIDispatch.__seal() Local $mRet = Call($fSetter, $oIDispatch) Local $iError = @error, $iExtended = @extended VariantClear($tProperty.Variant) VariantCopy($tProperty.Variant, $_tProperty.Variant) $oIDispatch.ret = $mRet $_tProperty = DllStructCreate($tagProperty, $_tProperty.Next) VariantCopy($pVarResult, $_tProperty.Variant) $oIDispatch = 0 Return ($iError <> 0) ? $DISP_E_EXCEPTION : $S_OK Return $S_OK ;~ Else ;~ $oHelper = IDispatch() ;~ $oHelper.val = 0 ;~ $tHelperProperty = DllStructCreate($tagProperty, DllStructGetData(DllStructCreate("ptr", Ptr($oHelper) + __AOI_GetPtrOffset("Properties")), 1)) ;~ ;~ VariantClear($tHelperProperty.Variant) ;~ VariantCopy($tHelperProperty.Variant, $tDISPPARAMS.rgvargs) ;~ ;~ ConsoleWrite("PropertyGet:") ;~ ConsoleWrite(VarGetType($oHelper.val) & @LF) EndIf Local $iLock = __AOI_GetPtrValue($pSelf + __AOI_GetPtrOffset("lock"), "BYTE") If BitAND($iLock, $__AOI_LOCK_UPDATE) > 0 Then Return $DISP_E_EXCEPTION $_tVARIANT = DllStructCreate($tagVARIANT, $tDISPPARAMS.rgvargs) VariantClear($tVARIANT) VariantCopy($tVARIANT, $_tVARIANT) EndIf Return $S_OK EndFunc ;==>__ASO_Invoke
-
Hallo zusammen,
ich möchte Euch hier eine erste Version von AutoItSimpleObjects vorstellen. Das Ziel ist es, erstes Feedback zu sammeln, um zu erfahren, wohin die Reise gehen soll - also was man sich als Community unter objektorientierung in AutoIt vorstellt, welche Funktionalität man sich dabei wünscht, und wie man damit einen Mehrwert für die Sprache bringen kann. Ich finde es schade, dass AutoItObject nicht mehr weiterentwickelt wird, und AutoItObject_Internal nur Attribute, setter()- und getter()- kann. Deswegen möchte ich das Thema aufgreifen. DISCLAIMER: Alles was ich im Folgenden über AutoItSimpleObjects sage, beschreibt den aktuellen Zustand - nicht immer unbedingt das finale Ziel. Wenn ich also z.B. sage, es gibt nur öffentliche Attribute - dann heißt das nicht, dass das so bleiben muss.
Wer noch nie von objektorientierter Programmierung gehört hat, tut sich gut daran, ggf. eine kurze Runde durch das Internet zu drehen. Starten kann man z.B. hier: https://de.wikipedia.org/wiki/Objektorientierung
1. Was kann AutoItSimpleObjects?* (*Stand jetzt)
AutoItSimpleObjects (kurz "ASO") ermöglicht die Erzeugung von einfachen Objekten, die Attribute und -Methoden besitzen können. Im Gegensatz zu AutoItObject werden dafür keine zusätzlichen Dateien wie z.B. DLL's benötigt.
Die Erzeugung von Objekten, Zuweisung von Methoden oder das Anlegen von Attributen ist dabei stark an das originale AutoItObject angelehnt - Alle Attribute und Methoden sind allerdings öffentlich.
AutoItSimpleObjects unterstützt 64-Bit und zur Not auch ByRef Parameter in Methodenaufrufen. Objekte können kopiert werden, was eine Art der Pseudo-Vererbung ermöglicht.
2. Was ist AutoItSimpleObjects?
Technisch gesehen ist AutoItSimpleObjects ein Wrapper zu AutoItObject_Internal, der mit einer eigenen Invoke-Methode und einigen wenigen Komfortfunktionen daherkommt.
AutoItObject beinhaltet somit die gesamte Funktionialität von AutoItObject_Internal und fügt ihr folgende wesentliche Merkmale hinzu:
- Die eigene Invoke-Methode ermöglicht den Aufruf von Methoden, die nicht __getter- oder __setter-Methoden sind.
- Alle Objekte haben eine zusätzliche Eigentschaft "__dirty".
Die Objekte, die in ASO erzeugt werden, sind Instanzen von IDispatch - Zugriff auf Attribute und Methodenaufrufe sind also Callbacks - deswegen sollten Methoden klein und kurz gehalten werden. (Bitte keine GUI-Messageloops in Methoden. :))
3. Was kann AutoItSimpleObjects (noch) NICHT?
- Vererbung
- Klassen
- Sichtbarkeiten
- Interfaces
4. Wie verwende ich AutoItSimpleObjects / Was gibt es zu beachten?
Im nachfolgenden ein kurzes Beispiel zur Anlage eines einfachen Objekts, der Zuweisung von Attributen und der Definition von Methoden:
AutoItSimpleObjects Example.au3
AutoIt: AutoItSimpleObjects - Example.au3
Alles anzeigen#include <AutoItSimpleObjects.au3> #include <Array.au3> #AutoIt3Wrapper_Run_Au3Check=y $oObject = _ASO_Create() _ASO_AddProperty($oObject, 'test') _ASO_AddMethod($oObject, 'Method1', __method1) _ASO_AddMethod($oObject, 'Method2_with_byref', _TestMethodByref) _ASO_AddMethod($oObject, 'Method3', _method3) ; ------------------------------------------------------------------------------ ; Test access to properties ; ------------------------------------------------------------------------------ $oObject.test = 12 MsgBox(0, "Access Property:", "The value of $oObject.test is: " & $oObject.test) ; ------------------------------------------------------------------------------ ; Test access to Method (Method1, no ByRef) ; ------------------------------------------------------------------------------ $vRet = $oObject.Method1("Test Title", "Text") MsgBox(0, "Access Method1:", 'Method1(...) returned: ' & @TAB & $vRet) ; ------------------------------------------------------------------------------ ; Test access to Method (Method2, with ByRef) ; ------------------------------------------------------------------------------ Local $aArray[3] = [1, 2, 3] _ArrayDisplay($aArray, 'ByRef Parameters: Array before') ; Attention: This does not work! $oObject.Method2_with_byref($aArray, "Oh no!") ; The Workaround is: $pMethod2_with_byref = $oObject.__get("Method2_with_byref") $vRet = $pMethod2_with_byref($aArray, "New Value!") _ArrayDisplay($aArray, 'ByRef Parameters: Array after') MsgBox(0, "Access Method2:", 'Method2(...) returned: ' & @TAB & $vRet) ; ------------------------------------------------------------------------------ ; Test access to Method (Method3, no parameters) ; ------------------------------------------------------------------------------ $vRet = $oObject.Method3() MsgBox(0, "Access Method3:", 'Method3() returned: ' & @TAB & $vRet) Func __method1($sTitle, $sParam) Local $oThis = _ASO_This() MsgBox(32, "Access Method1: " & $sTitle, _ StringFormat("Parameter $sParam is: \t\t%s\n" & _ "Object Property $oThis.test is: \t%s\n\n" & _ "Method will return: \t\t'42'", $sParam, $oThis.test)) Return 42 EndFunc ;==>__method1 Func _TestMethodByref(ByRef $aData, $sText) Local $oThis = _ASO_This() ReDim $aData[UBound($aData) + 1] $aData[UBound($aData) - 1] = $sText ;_ArrayDisplay($aData, "inside method") Return 'some or some other data' EndFunc ;==>_TestMethodByref Func _method3() Local $oThis = _ASO_This() MsgBox(0, "Access Method3:", "Hello from inside method3") Return 1 + Random(1, 10000, 1) EndFunc ;==>_method3
Ansonsten kann AutoItSimpleObjects genau wie AutoItObject_Internal genutzt werden. Siehe dazu die Beispiele auf GitHub. Es gilt folgendes zu beachten:
- Im Gegensatz zu AutoItObject benötigen Funktionen keinen zusätzlichen Parameter $oSelf als ersten Parameter der Funktion. Die Deklaration von Methoden wird dadurch einfacher.
- Der Zugriff auf das aktuelle Objekt innerhalb einer Methode erfolgt stattdessen mittels Aufruf von $oThis = _ASO_This() am Anfang der Funktion.
- Der Zugriff auf eine Methode $oObject.Methodname() ohne Klammern (also $oObject.Methodname) ruft die zugewiesene Funktion ohne Parameter auf, statt eine Funktionsreferenz zurückzuliefern. Das ist technisch bedingt, weil uns AutoIt nicht ermöglicht, zwischen Attributszugriff und Methodenaufruf ohne Parameter zu unterscheiden. Zeile 48 könnte also auch so lauten: $vRet = $oObject.Method3**
- Die Nutzung von ByRef-Parametern in einem Methodenaufruf erfordert es, die Funktionsreferenz in einer separaten Variable zu speichern, siehe Zeile 30 ff. Dabei muss die Funktionsreferenz unbedingt mit $oObject.__get("Methodname") geholt werden - ein Zugriff mittels $pFunc = $oObject.Methodname führt zu einem Fehler. Siehe vorheriger Punkt.**
- Die Methoden _ASO_AddMethod(...) und _ASO_AddProperty(...) sind eigentlich überflüssig. Attribute müssen nicht explizit angelegt werden, sondern werden bei der ersten Zuweisung automatisch Public erstellt und Methoden werden dadurch erstellt, dass einem Attribute eine Funktionsreferenz zugewiesen wird. Zeile 6-11 im oberen Beispiel können also auch wie folgt lauten:
AutoIt$oObject = _ASO_Create() $oObject.test = "" $oObject.Method1 = __method1 $oObject.Method2_with_byref = _TestMethodByref $oObject.Method3 = _method3
** dieses Verhalten lässt sich durch das setzen des __dirty-Attributs eines Objektes auf 'True' ändern; ist ein Objekt __dirty, so wird es beim Zugriff auf eine Methode die Funktionsreferenz der zugewiesenen Funktion zurückliefern, statt sie ohne Parameter aufzurufen. Das hat zur Folge, dass Methoden ohne Parameter nur mit dem AutoIt Schlüsselwort "Call" aufgerufen werden können, oder die Funktionsreferenz in einer separaten Variable gespeichert werden muss, um sie ohne Parameter aufzurufen. Auf der anderen Seite können mit gesetztem __dirty-Flag ByRef-Parameter verwendet werden, ohne die Funktionsreferenz vorher explizit in einer Variable zu speichern.
Siehe dazu nachfolgendes Beispiel:AutoItSimpleObjects Example_dirty.au3
Spoiler anzeigen
AutoIt: AutoItSimpleObjects - Example - __dirty.au3
Alles anzeigen#include <AutoItSimpleObjects.au3> #include <Array.au3> #AutoIt3Wrapper_Run_Au3Check=n ; < Important for the ($oObject.Method)(...)-Syntax to work. $oObject = _ASO_Create() $oObject.__dirty = True _ASO_AddProperty($oObject, 'test') _ASO_AddMethod($oObject, 'Method1', __method1) _ASO_AddMethod($oObject, 'Method2_with_byref', _TestMethodByref) _ASO_AddMethod($oObject, 'Method3', _method3) ; ------------------------------------------------------------------------------ ; Test access to properties ; ------------------------------------------------------------------------------ $oObject.test = 12 MsgBox(0, "Access Property:", "The value of $oObject.test is: " & $oObject.test) ; ------------------------------------------------------------------------------ ; Test access to Method (Method1, no ByRef) ; ------------------------------------------------------------------------------ $vRet = $oObject.Method1("Test Title", "Text") MsgBox(0, "Access Method1:", 'Method1(...) returned: ' & @TAB & $vRet) ; ------------------------------------------------------------------------------ ; Test access to Method (Method2, with ByRef) ; ------------------------------------------------------------------------------ Local $aArray[3] = [1, 2, 3] _ArrayDisplay($aArray, 'ByRef Parameters: Array before') ; Attention: This does not work! $oObject.Method2_with_byref($aArray, "Oh no!") ; The Workaround is: $vRet = ($oObject.Method2_with_byref) ($aArray, "New Value!") _ArrayDisplay($aArray, 'ByRef Parameters: Array after') MsgBox(0, "Access Method2:", 'Method2(...) returned: ' & @TAB & $vRet) ; ------------------------------------------------------------------------------ ; Test access to Method (Method3, no parameters) ; ------------------------------------------------------------------------------ ; Attention: This does not work! $vRet = $oObject.Method3() ; The Workaround is: $vRet = Call($oObject.Method3) MsgBox(0, "Access Method3:", 'Method3() returned: ' & @TAB & $vRet) Func __method1($sTitle, $sParam) Local $oThis = _ASO_This() MsgBox(32, "Access Method1: " & $sTitle, _ StringFormat("Parameter $sParam is:\t\t%s\n" & _ "Object Property $oThis.test is:\t%s\n\n" & _ "Method will return:\t\t'42'", $sParam, $oThis.test)) Return 42 EndFunc ;==>__method1 Func _TestMethodByref(ByRef $aData, $sText) Local $oThis = _ASO_This() ReDim $aData[UBound($aData) + 1] $aData[UBound($aData) - 1] = $sText ;_ArrayDisplay($aData, "inside method") Return 'some or some other data' EndFunc ;==>_TestMethodByref Func _method3() Local $oThis = _ASO_This() MsgBox(0, "Access Method3:", "Hello from inside method3") Return 1 + Random(1, 10000, 1) EndFunc ;==>_method3
Zu beachten ist hier noch einmal folgende Kurzschreibweise, speziell für/mit ByRef-Paremetern.
In Zeile 1 ist ($oObject.Method2_with_byref) eingeklammert; deswege wird zuerst die Funktionsreferenz von Method2_with_byref aufgelöst. Danach wird die Funktion "normal" von AutoIt aufgerufen.
In Zeile 2 wird die Methode über das IDispatch-Interface aufgerufen, das keine ByRef Paramter unterstützt. FYI: Ohne gesetztes __dirty-Flag würde $oObject.Method2_with_byref in Zeile 1 über IDispatch ohne Parameter aufgerufen.
AutoIt$vRet = ($oObject.Method2_with_byref)($aArray, "New Value!") $vRet = $oObject.Method2_with_byref($aArray, "doesn't work :(")
5. Was brauche ich von Euch?
Anwendungsfälle, Ideen, Feedback.
Mal ins Blaue gedacht: Wofür würdet Ihr OO- benutzen? Sind Dinge wie Interfaces, Klassen, Traits, ByRef-Paramter, usw. für Euch unabdingbar bzw. was wäre Funktionalität, die Ihr nicht braucht?
Ist die UDF einfach genug - oder zu einfach gehalten? Sind die Syntaxmöglichkeiten in AutoIt ausreichend?
Die UDF: AutoItSimpleObjects.au3
siehe Post #2, oder Anhang
AutoItSimpleObjects Example.au3 / AutoItSimpleObjects Example_dirty.au3
s.o.
-
2. Problem: Wie mache ich mich von der Dateiendung unabhängig.
FileFindFirstFile/FileFindNextFile oder _FileListToArray - du suchst dann nach Dateien mit Dateiendung .* und bist so auch nicht gezwungen, alle im Universum existierenden Dateiendungen in dein Script zu tippen, oben vorgeschlagen.
bei der 2. und 3. Eingabe muss ich eine Null vorstellen bzw. mit Nullen auffüllen. Wie kann ich bei der Eingabe von 2 auf 00002 stellen?
Oder statt mit StringFormat, was ich immer etwas kryptisch finde, einfach mit StringRight.
StringRight("00000" & $iZahl, 5)
-
Hi Guys. hab jetzt nur quer gelesen, ... könnte das hier helfen: "Lua Com" ?
Mit Sicherheit vielleicht. Yjuq kann das wahrscheinlich besser beurteilen
-
Hey,
in's blaue hinein gesprochen: WinHTTP ist grundsätzlich erst einmal nur eine Sammlung von Funktionen, die eine direkte Kommunikation mittels HTTP Protokoll ermöglicht.
Das heißt einfach gesagt - Du kannst mit einem Webserver sprechen, ohne einen Browser verwenden zu müssen. Das wird i.d.R. aus Performancegründen gemacht. Soweit klar.
Wenn man mittels WinHTTP mit einem Webserver "spricht", macht man in der Regel viele der Dinge, die ein Browser automatisch macht, manuell. Das setzen von Cookies, Weiterleitung auf andere Websiten, Umschalten der Verschlüsselung, etc.
Will man mittels WinHTTP Formularfelder auf Websiten ausfüllen, oder Checkboxen anklicken - dann teilt man das dem Webserver genau so mit, wie es ein Browser tun würde. Im Browser trägst Du alles fein säuberlich ein und drückst dann auf "Senden". Der Browser überträgt die Formulardaten dann an den Webserver. In aller Regel geschieht das im Internet mittels HTTP Post Request.
Du wirst also folgendes machen müssen:
Nach dem erfolgreichen Login musst du einen erneuten HTTP POST Request absetzen, der dein "Checkbox-Formular" an den Server überträgt. Um über die Daten bescheid zu wissen, die Du senden musst, kannst Du den Login im Browser ausführen und die HTTP Requests und Responses mitschneiden (Stichwort "LiveHttpHeaders"). Den entsprechenden Request musst Du in WinHTTP nachbilden.
-
Sorry, keine Lösung für dein Problem, aber bei mir gibts Fehler bei F7 ohne die roten Anführungszeichen.
#AutoIt3Wrapper_Run_Before=""%autoitdir%\AutoIt3.exe" "%in%" -Something"
thx!
Schlechte Nachrichten:
schade!
Du kannst für die SciTE eine eigene implementation für F7 schreiben. Basierend darauf kannst du eine Start-Skript generieren welche diese Anweisungen beinhaltet und deine Hauptdatei einbindet. Musst halt nur sämtliche include files für diese Anweisungen parsen und in dein Start-Skript schmeißen.
Du kannst diese Implementation entweder in Lua schreiben oder vielleicht durch eine Mischung von AutoIt und der SciTE Config Files herbeiführen. Vielleicht auch Lua + Autoit. Musst dich wohl durch die SciTE Docu durchwühlen.
Oder ich sage einfach, dass zusätzlich zu einer Include-Anweisung auch noch die Zeile #AutoIt3Wrapper_Run_Before=""%autoitdir%\AutoIt3.exe" "%in%" -Something" eingefügt werden muss, wenn die Leutchens zu faul sind, das Script vor dem Compilen einmal mit F5 zu starten.
-
Ich war gerade dabei noch die AutoIt Objekte einzubinden, also eine einfache Funktion die dir ermöglicht auf alle deine vorhandenen AutoIt Objekte zuzugreifen.
Das Gegenstück zu AutoIt's ObjGet() in Lua würde mir schon reichen
Vielleicht hat jemand anderes noch eine Idee? Mich wundert es sowieso warum sich hier keiner meldet.
Ich denke das Problem ist, dass ,
1) sich Threads schnell "verrennen", und Leute nicht unbedingt gewollt sind, einer ellenlangen sehr technischen Konversation zu folgen.
2) sich Leute weniger interessieren, wenn es schon einen Workaround gibt oder im Thread schon eine mögliche Lösung vorgeschlagen wurde. (Frei nach dem Motto: "Soll er das doch irgendwie reinbasteln und fertig!".)3) die landläufige Meinung ist, dass es "nicht geht". AutoIt kann das nicht und Punkt. Aber die Erde war auch einmal der Mittelpunkt des Universums und alles andere war Quatsch.
Über die Jahre habe ich einige Versuche in diese Richtung u.a. mittels Multithreading oder Injection, etc. mitbekommen, und wahrscheinlich die Hälfte der Erkenntnisse daraus wieder vergessen. Bei mir hängengeblieben, ist aber, dass es noch keiner so wirklich geschafft hat. Und das verstehe ich einfach nicht! Hier (und auch im englischen Forum) sind so viele schlaue Leute - da wird der verrückteste Scheiß gebastelt... aber keiner schafft es, den AutoIt Interpreter zu bändigen?!
Ich finde diesen Thread hier so interessant - da sieht man was passiert, wenn man so eine Frage im Englischen Forum stellt. Der gute Busti hat alles versucht und immer wieder neue Ansätze präsentiert bis er kleingeredet wurde. https://www.autoitscript.com/forum/topic/19…e-struct-of-it/
Also Leute!
Die Frage ist und bleibt offen: Wie generiere ich (möglichst elegant) eine AutoIt-Funktion zur Laufzeit?
-
Hallo zusammen,
mit #AutoIt3Wrapper_Run_Before kann ich einen Befehl ausführen, bevor das Script kompilliert wird. Beispiel:
Folgendes Script verhält sich unterschiedlich, je nachdem ob man in SciTE F5 oder F7 drückt:
Code: startuptest.au3#AutoIt3Wrapper_Run_Before="%autoitdir%\AutoIt3.exe "%in%" -Something" #OnAutoItStartRegister "StartUpFunction" Func StartUpFunction() If StringInStr($CmdLineRaw, "-Something", 1) Then MsgBox(64,"","Ich mache besondere Dinge") Else MsgBox(0,"","Ganz normale Dinge.") EndIf EndFunc
Wenn Ich nun aber das Ganze in ein Include hülle, wird #AutoIt3Wrapper_RunBefore ignoriert, und das Script macht vor dem Compilen nun gar nichts mehr. Kennt jemand dafür eine Lösung?
Danke und viele Grüße
-
Hey,
Ja? Das ist ja der Sinn dahinter. Schau dir Post #18 nochmal an. Da wird alles direkt geladen und ist direkt global verfügbar. Wenn du ein neues Objekt in deiner GUI anlegst kannst du es auch direkt verwenden ohne Neustart. Das ganze lässt sich auf alles übertragen. Ganze Skripte können geladen und ausgeführt werden zur Laufzeit.
Da habe ich gestern irgendwie Module und Plugins durcheinandergewürfelt und die Frage falsch gestellt, sorry. Dass alle Funktionen und Globals in der Lua Laufzeitumgebung verfügbar sind, hab ich kapiert. Wenn ich eine Funktionssammlung - also ein Lua Module/Rock - runterladen und integrieren will geht das on the fly. Coole Sache.
Plugins (base, file, io, ...) entsprechen dann eingebauten AutoIt Funktionen? Kann ich Plugins zur Laufzeit aktualisieren/nachladen, nachdem schon Module geladen/Funktionen ausgeführt wurden?
Versuch mal #AutoIt3Wrapper_UseX64=y davor zu packen. Da war die Lua UDF noch nicht ganz fertig und ich hatte es nur in 64 bit getestet.
Und ich nur im 32 Bit Mode - Funktioniert, danke.
Mir ist durchaus klar an was für ein Problem du sitzt. Eine Lua integration ist mein erster Vorschlag dafür. Es macht eigentlich genau das was du wünscht. Du kannst das auch (wie bereits gesagt) mit AutoIt und IPC umständlicher lösen. Ist halt nur mehr aufwand und vermutlich mehr Anfälliger für Fehler (wenn dir irgendwelche Prozesse abschmieren etc.)
Dass Du mein Problem verstehst hab ich nicht bezweifelt - ich beschwer' mich ja gar nicht. Ich glaube, es fällt mir schwer den Umfang und die Vision zu beschreiben. Lua scheint ne schicke Geschichte zu sein und ich kann mir auch gut vorstellen, das in Teilen der Anwendung zu ermöglichen. Aber dann gerne als Alternative zu AutoIt (deswegen die Frage nach dem Zugriff auf die Objekte mittels RoT). Meine persönliche Vision ein geschlossenes System - alles ist eins (Die oben erwähnte Trennung in Business-Objekte und System-Objekte eigentlich auch nur temporär.) . Ein System, in einer Sprache geschrieben - mit einer Sprache erweiterbar - direktes Feedback, weil alles direkt am Bildschirm stattfindet - keine statik, alles ist polymorph und veränderbar - GUI Elemente die die Objekte repräsentieren. Am liebsten hätte ich die Programmiersprache Self - in abgespeckt und ein ganz klein bisschen anders, und simpler - einfach zu verstehen und nutzen im Büro/Enterprise-Kontext. Mit moderner GUI.
Lua kann das mit Sicherheit auch alles leisten - und wäre einerseits für simple Aufgaben wie Datentransformationen einfach genug um von einem Key User getippt zu werden - aber auch mächtig genug um das ganze GUI Handling, IPC, Printing, Datenbank, Filehandling zu erledigen. Alles cool. Ich bin mit den Services und der Laufzeitumgebung meiner Applikation aber schon weit fortgeschritten und am Point of no Return vorbei - alles noch einmal auf Lua umzubauen, ist Budgettechnisch nicht mehr drin und würde auch die weitere Entwicklung verlangsamen. Da fehlt dann einiges an Routine um flott zu coden - 12 Jahre Erfahrung krieg' ich in Lua demnächst nicht mehr Zusammen. Zeittechnisch fällt das also auch weg; ich habe bestimmte Ziele die ich einhalten muss. Deswegen ist es AutoIt und bleibt es AutoIt als "first language". Der im ersten Post beschriebene Workaround funktioniert für ja mich auch - die Objekte mit neuen/geänderten Methoden werden in Worker ausgelagert bis die Applikation neu startet. Zugriff auf alle Daten der Applikation gibts quasi automatisch da alles in einem Applikation Objekt liegt, das ich einfach mittels Parameter übergeben kann. Es ist im Prinzip nur die Frage der Eleganz, die ich im ersten Post stelle.
Übrigens: Wenn ich nicht ausgiebig Antworte, ist das nicht als unhöflich zu verstehen - ich bin wie oben gesagt dankbar für den Hinweis und die Arbeit mit den Lua Scripten - ich versuche aber aus o.g. Gründen bewusst den Thread in eine bestimmte Richtung zu lenken. - und die Richtung ist AutoIt. Ich passe auch noch einmal den Titel und ersten Post an, damit der Hinweis auf AutoIt klarer wird.
Cheers,
-
??? - Ich hab bereits alles beschrieben. Eigentlich waren die ersten Beispielskripte dafür gedacht. Aber okey... Ich schreib dir noch ein Beispiel. <.<
Du brauchst nicht genervt zu sein. Das sorgt nicht unbedingt für eine gute Gesprächsgrundlage.
Vielleicht sehe ich es nicht. Ich spreche von den Files in RE: Self Modifying Code / IPC / Funktionen zur Laufzeit erzeugen
Dein erstes Beispiel ruft nur eine simple Lua Funktion auf,
Dein zweites Besipiel schiebt ein Int in die Lua Welt,
Dein drittes Beispiel endet in einem Programmabbruch.
Kann ich Plugins zur Lua-Laufzeit nachladen? - Also im AutoIt-Kontext gesprochen (wo es nicht möglich ist): eine UDF herunterladen, ins Scriptverzeichnis einfügen, und während das Programm schon läuft Includen?
Danke,
-
Ich find's nett, dass Du Dir die Mühe mit den Beispielscripten machst - aber hilfreicher fände ich es, wenn die Antworten Bezug auf die Frage in dem Post nehmen würden.
Also konkret: Der Zugriff auf das AutoItObject-Object, entweder mittels Parameter oder ROT. Ich habe nicht vor AutoItObject als Ganzes abzulösen, sehe aber nicht wie ich einen komplexen datentyp übergebe.
Danke Dir,
-
Hey,
danke für die Mühe mit dem Lua Beispiel - sieht ganz nett aus. Potential hat es auf jeden Fall - aber am Ende des Tages bin ich mir nicht sicher, ob das mit meiner Vision einhergeht. Ich behalte das im Hinterkopf.
Wichtiger wäre mir das hier: RE: Self Modifying Code / IPC / Funktionen zur Laufzeit erzeugen
Danke und viele Grüße
-
Kein Problem, ich war heute ja auch sehr kurz angebunden
habe versucht, es minimalistisch zu halten - wenn irgendwas unklar ist, einfach fragen.
-
Danke für Euren Input!
Bist du sicher, dass es sich so verhält? Meiner Vorstellung nach sollte ein ROT Objekt für alle Scripts gleich verfügbar sein. Vielleicht wird das Objekt im aktuellen Script nicht geändert (im Sinne von aktualisieren des bestehenden Objekts) sondern neu erstellt? - Bedenke, dass ich hierbei nur rate, mein Wissen reicht dafür nicht aus! Aber vielleicht liest ja jemand mit, der sich besser auskennt.
Download zip: rot problem example autoitobject.zip
Problem und Workaround noch einmal anschaulich.
-> Example_Problem.au3 bzw. Example_Workaround.au3 starten.
So hat mich z.B. verwundert im Zusammenhang mit ROT über Server und Client zu lesen. In meinem Fall, wo ich ein COM ROT Dictionary Objekt benutze, braucht es keinen Server in dem Sinne. Ein Standard-Objekt wird erstellt ObjCreate("Scripting.Dictionary") und im ROT registriert $oRunningObjectTable.Register($iFlags, $pObject, $pMoniker, $iHandle). Danach ist das Dictionary in allen Scripts zur Verfügung, die das "Zauberwort" kennen, also der Moniker (Name) unter dem man das Dict im ROT registriert hat.
Guter Hinweis - ich werde mir bei Gelegenheit anschauen, wie die .Register-Methode von ausprogrammiert ist, bzw. ob man mit den Flags noch etwas machen kann - vielleicht macht das einen Unterschied.
Wieviel Aufwand wäre es denn, wenn du ein Minimal-Demo erstellst, mit einem Hauptscript das einen Button hat (und ein Edit*?), mit dem ein "Business Objekte" Script erzeugt werden kann? * Das Edit habe ich erwähnt, weil ich ja nicht weiß, wie die User das im echten Programm machen. - Dann sollten noch 1 - 2 Buttons drauf, die das machen bzw. nicht machen, worum es dir geht, also die Funktionen aus dem Unterscript aufrufen, ohne Prog-Neustart. Noch eine Datei hinzufügen, die den Code mit 1 - 2 Foo-Funktionen für das Unterscript enthält, den man im Edit einfügt, um das Unterscript per Button zu erstellen.
Download zip: generate objects gui.zip
-> Zum Testen: Starten, "Add Objekt" -> beliebiger name eingeben -> "Add Method" -> beliebiger Name eingeben -> im Popup nun code einfügen - zum beispiel folgenden
-> Codeeingabefenster schließen -> Methode in der Liste Rechts auswählen -> "Run Method" -> Nichts wird passieren.
-> Programm neustarten -> Edit Objekt -> Methode auswählen -> Run Method -> wird ausgeführt werden.
Ich hab nur heute / morgen leider nicht mehr viel Zeit, daher musts du noch aufs Wochenende warten. Viel zu tun
Kein Problem. Das läuft nicht weg; ich bin z.Z. auch im Stress. Das Lua Beispiel muss ich mir noch ancshauen, ich melde mich dazu.
Danke schon mal für eure antworten & input.
-
Dann möchte ich dich gleichmal auf ein Problem hinweisen, das leider nicht lösbar ist und mich viele Nerven gekostet hat: AutoIt-Object -- Parameter einer Methode als ByRef
Danke - das ist in der Tat eine der Limitierungen, die mich bisher gehindert hat, es zu testen. Bisher macht sich das Geschwindigkeitstechnisch kaum Bemerkbar. Hier wird aber auch nocht mit verhältnismäßig kleinen Datenmengen gearbeitet. Erstens sind die Objekte sehr schmal, und zweitens sind es nur eine Handvoll Belege. Mal sehen, ab wann das ByRef Problem zum Problem wird.
-
Hey,
Wie gesagt, mein Wissen über AutoItObject ist sehr bescheiden. Ich benutze z.B. AutoItServer.au3 aus dem Thread "Access AutoIt" von trancexx. Für mich sind eher COM ROT Objekte wichtig, z.B. hier von LarsJ, wobei interesannte Aspekte unter "Usage" beschrieben sind, z.B. gleich der erste Punkt "Passing array between AutoIt programs".
Mir ging es da bis vor kurzem Ähnlich - ich habe mich bis vor diesem Projekt auch nicht mit AutoItObject beschäftigt - es ist schon frech, wie gut und schnell man damit komplexe Anwendungen baut. Der Hinweis auf ROT lässt mich ein bisschen schmunzeln, denn das ist genau die Technik, die in meinem Workaround in Post 1 genutzt wird. Dabei hatte ich mich auch von Access AutoIt insprieren lassen.
1. Die wichtigste Frage für mich: Müssen die "Module" (Scripte die die Klassen der Business Objekte enthalten) unbedingt in das Haupt-Modul/Script inkludiert werden? Wenn sie z.B. weiter als separate Module laufen können, braucht es keinen Neustart der Anwendung.
Nein - und tatsächlich habe ich gestern schon überlegt, ob es nicht eleganter wäre, die Objekte in eigene "Worker" auszulagern. Oder wenigstens die ObjectFactory-Klasse, die Objekte erstellt. Dann müsste nur diese neu starten und nicht die GUI Applikation. Die Idee gefällt mir.
2. Kann ein AutoItObject-Object zur Laufzeit erweitert werden? Kann also ein zur Laufzeit erstelltes Modul seine Eigenschaften und Methoden dem bestehenden Au3-Objekt hinzufügen?
Ja! Man kann zu jedem Zeitpunkt eine Methode oder ein Attribut hinzufügen oder die Sichtbarkeit ändern (und wahrscheinlich auch löschen) - aber ich glaube man kann keine Objekte "kopieren".
Das einzige Problem tritt hier auf, wenn das Objekt nicht im aktuellen Prozess erstellt wurde.
Heißt: Übergebe ich ein Objekt mittels ROT and ein anderes Script, kann ich dort nur noch Methoden aufrufen und Eigenschaften ändern; aber keine neuen erstellen.
Deswegen gibt es in meinem initialen beispiel auch 2 Objekte: Das Objekt, das aus dem Hauptscript kommt (ROT Server), ist im zweiten Script (ROT Client) quasi halb-schreibgeschützt.
In einem Script verwende ich ein Dictionary als COM ROT Objekt zur IPC zwischen AutoIt und VBScript. Ein Dict kann als KeyValues, glaube ich, so ziemlich alles aufnehmen, auch Arrays und Objekte. Vielleicht könnte man so deine Au3-Objekte in allen Modulen verfügbar machen. ...
Mit dem Dict habe ich bisher kaum gearbeitet. Vor allem nicht im ROT Kontext.... Kannst Du in beiden Scripten (also server und client) KeyValues hinzufügen und löschen, bzw. sortieren usw.?
PS: Zum Thema IPC hatte ich nun das hier gebaut:
https://www.autoitscript.com/forum/topic/20…ct-pure-autoit/
PPS: Die ursprüngliche Frage bleibt aber eigentlich bestehen - denn am schönsten wäre eine Möglichkeit, dass ich überhaupt nichts irgendwohin auslagere oder neustarte, sondern irgendwie zur Laufzeit eine Funktion "foo" generiere, die ich mit z.B Call("foo") eine Zeile später aufrufen kann. ( - oder an _AutoItObjects_AddMethod) übergeben...
Danke Euch!