jugador Posted July 20 Posted July 20 As @Jon decided not to provide Array pointer, here's a small UDF to convert an array to a SafeArray and vice versa. You can get the SafeArray.au3 from https://www.autoitscript.com/forum/topic/200660-variants-and-safearrays/ #include <Array.au3> #include "SafeArray.au3" #include "ArrayPointer UDF.au3" __Example_0A() Func __Example_0A() Local $Ary_0 = [[123456, 12.34, 'how are you?', -0.1234], [-100.001, 0.00009, "", 'Is it working?']] _ArrayDisplay( $Ary_0 ) Local $t_SAobj Local $o_SAobj = __SafeArray_Dummy_Obj($t_SAobj) ;~~ Convert Array to SafeArray Pointer ;~~ Now you can pass the SafeArray pointer($psa) to any language, such as C, Python.......... Local $psa $o_SAobj.Array_to_SafeArray($Ary_0, $psa) SafeArrayUnaccessData( $psa ) ;~~ convert SafeArray Pointer to Array Local $p_Array_Copy $o_SAobj.SafeArray_to_Array($psa, $p_Array_Copy) SafeArrayDestroy($psa) ;~~ delete the safeArray pointer when done. _ArrayDisplay( $p_Array_Copy ) $o_SAobj = 0 __Delete_SafeArray_ObjectFromTag( $t_SAobj ) EndFunc ArrayPointer UDF.au3 KaFu 1
jugador Posted July 21 Author Posted July 21 1) Convert DllStruct of int to Array expandcollapse popup#include <Array.au3> #include "SafeArray.au3" #include "Variant.au3" #include "ArrayPointer UDF.au3" __Example_1A() Func __Example_1A() Local $n = 10 Local $t_DllStruct = DllStructCreate( "int[" & $n & "]" ) Local $p_DllStruct = DllStructGetPtr( $t_DllStruct ) Local $nSize = DllStructGetSize($t_DllStruct) ConsoleWrite("+ " & $nSize & @CRLF) For $i = 1 To $n DllStructSetData($t_DllStruct, 1, $i, $i) Next Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND ) DllStructSetData( $tsaBound, "cElements", $n ) DllStructSetData( $tsaBound, "lLbound", 0 ) Local $psa = SafeArrayCreate( $VT_I4, 1, $tsaBound ) Local $psaData SafeArrayAccessData( $psa, $psaData ) Local $tSafeArrayBytes = DllStructCreate( "byte[" & $nSize & "]", $psaData ) DllStructSetData( $tSafeArrayBytes, 1, DllStructGetData( DllStructCreate( "byte[" & $nSize & "]", $p_DllStruct ), 1 ) ) SafeArrayUnaccessData( $psa ) Local $t_SF_Obj Local $o_SF_Obj = __SafeArray_Dummy_Obj($t_SF_Obj) If Not IsObj($o_SF_Obj) Then Return Local $p_Array $o_SF_Obj.SafeArray_to_Array($psa, $p_Array) SafeArrayDestroy($psa) _ArrayDisplay( $p_Array ) $o_SF_Obj = 0 __Delete_SafeArray_ObjectFromTag( $t_SF_Obj ) EndFunc 2) Convert DllStruct of char to Array expandcollapse popup#include <Array.au3> #include "SafeArray.au3" #include "Variant.au3" #include "ArrayPointer UDF.au3" __Example_1B() Func __Example_1B() Local $t_DllStruct = DllStructCreate("wchar var1[20];char var2[20];char var3[20]") DllStructSetData($t_DllStruct, "var1", "How are you?") DllStructSetData($t_DllStruct, "var2", "Is it working?") DllStructSetData($t_DllStruct, "var3", "Hope, so....") Local $p_DllStruct = DllStructGetPtr($t_DllStruct) Local $nSize = DllStructGetSize($t_DllStruct) Local $nFields = 3 Local $tsaBound = DllStructCreate($tagSAFEARRAYBOUND) DllStructSetData($tsaBound, "cElements", $nFields) DllStructSetData($tsaBound, "lLbound", 0) Local $psa = SafeArrayCreate($VT_BSTR, 1, $tsaBound) Local $psaData SafeArrayAccessData($psa, $psaData) Local $bstr Local $tSafeArrayStrings = DllStructCreate("ptr[" & $nFields & "]", $psaData) For $i = 1 To $nFields $bstr = SysAllocString(DllStructGetData($t_DllStruct, $i)) DllStructSetData($tSafeArrayStrings, 1, $bstr, $i) $bstr = 0 Next SafeArrayUnaccessData($psa) Local $t_SF_Obj Local $o_SF_Obj = __SafeArray_Dummy_Obj($t_SF_Obj) If Not IsObj($o_SF_Obj) Then Return Local $p_Array $o_SF_Obj.SafeArray_to_Array($psa, $p_Array) SafeArrayDestroy($psa) _ArrayDisplay($p_Array) $o_SF_Obj = 0 __Delete_SafeArray_ObjectFromTag($t_SF_Obj) EndFunc
jugador Posted August 6 Author Posted August 6 (edited) _ArrayDelete ( Delete Row of 1D and 2D Array ) I considered doing this using ASM code, but @Jos raised a question, so I discarded that method. https://www.autoitscript.com/forum/topic/212996-asm-help-using-string/ You can perform array Add, Insert, Merge, Slice operations using the same technique shown below. The problem is that to manipulate a SafeArray by column using RtlMoveMemory, you need to write C code. expandcollapse popup#include <Array.au3> #include "SafeArray.au3" #include "Variant.au3" #include "ArrayPointer UDF.au3" ;__Example_A() __Example_B() Func __Example_A() Local $Ary_0 = [['A1', 'A2', 'A3', 'A4'], ['B1', 'B2', 'B3', 'B4'], ['C1', 'C2', 'C3', 'C4'], ['D1', 'D2', 'D3', 'D4'], ['E1', 'E2', 'E3', 'E4'], _ ['F1', 'F2', 'F3', 'F4'], ['G1', 'G2', 'G3', 'G4'], ['H1', 'H2', 'H3', 'H4'], ['I1', 'I2', 'I3', 'I4'], ['J1', 'J2', 'J3', 'J4']] ; Local $Ary_0 = ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'] _ArrayDisplay( $Ary_0 ) ; $hTime_B = TimerInit() ; _ArrayDelete($Ary_0, '0;3;5;7;8') ; ConsoleWrite("> _ArrayDelete: " & TimerDiff($hTime_B)&@CRLF) $hTime_C = TimerInit() __Delete_1D_2D_Row($Ary_0, '0,3,5,7,8') ConsoleWrite("> __Delete_1D_2D_Row: " & TimerDiff($hTime_C)&@CRLF) _ArrayDisplay( $Ary_0 ) EndFunc Func __Example_B() $hTime_A = TimerInit() Local $Ary_0[5000][100] For $i = 0 To UBound($Ary_0, 1) - 1 For $j = 0 To UBound($Ary_0, 2) - 1 $Ary_0[$i][$j] = $i & "-" & $j Next Next ConsoleWrite("> Array_Create: " & TimerDiff($hTime_A)&@CRLF) ; $hTime_B = TimerInit() ; _ArrayDelete($Ary_0, '0;3;5;7;8') ; ConsoleWrite("> _ArrayDelete: " & TimerDiff($hTime_B)&@CRLF) $hTime_C = TimerInit() __Delete_1D_2D_Row($Ary_0, '0,3,5,7,8') ConsoleWrite("> __Delete_1D_2D_Row: " & TimerDiff($hTime_C)&@CRLF) EndFunc ; #FUNCTION# ============================================================================= ; Name...........: __Delete_1D_2D_Row ; @jugador ; ======================================================================================== Func __Delete_1D_2D_Row(Byref $Array, $row_to_delete) Local $t_SAobj Local $o_SAobj = __SafeArray_Dummy_Obj($t_SAobj) ; Local $SafeArray_time_A = TimerInit() Local $psa_A $o_SAobj.Array_to_SafeArray($Array, $psa_A) SafeArrayUnaccessData( $psa_A ) ; ConsoleWrite("! Time taken to pass Array through Com object: " & TimerDiff($SafeArray_time_A) &@CRLF) ; Local $SafeArray_time_taken_toDelete = TimerInit() Local $New_PsaCopy __SafeArray_Delete_Row($psa_A, $New_PsaCopy, $row_to_delete) ; ConsoleWrite("+ __SafeArray_Delete_Row: " & TimerDiff($SafeArray_time_taken_toDelete) &@CRLF) ; Local $SafeArray_time_B = TimerInit() Local $Array_Copy $o_SAobj.SafeArray_to_Array($New_PsaCopy, $Array_Copy) ; ConsoleWrite("! Time taken to pass SafeArray through Com object: " & TimerDiff($SafeArray_time_B) &@CRLF) SafeArrayDestroy($New_PsaCopy) SafeArrayDestroy($psa_A) $o_SAobj = 0 __Delete_SafeArray_ObjectFromTag( $t_SAobj ) $Array = $Array_Copy EndFunc ; #FUNCTION# ============================================================================= ; Name...........: __SafeArray_Delete_Row ; @jugador ; ======================================================================================== Func __SafeArray_Delete_Row(Byref $pSafearray, Byref $pFreshCopy, $row_to_delete) Local $vt_Size = 16 Local $n_Row, $n_Column Local $tSafeArray = DllStructCreate( $tagSAFEARRAY, $pSafearray ) Local $cDims = DllStructGetData( $tSAFEARRAY, "cDims" ) If $cDims = 1 Then $n_Row = DllStructGetData( $tSAFEARRAY, "cElements" ) $n_Column = 1 Local $t_New_SArray = DllStructCreate( $tagSAFEARRAYBOUND) DllStructSetData( $t_New_SArray, 1, $n_Row ) DllStructSetData( $t_New_SArray, 2, 0 ) $pFreshCopy = SafeArrayCreate( $VT_VARIANT, 1, $t_New_SArray ) Endif If $cDims = 2 Then Local $RC_array = __Get_SafeArray_Number_of_Row_Column($pSafearray) $n_Row = $RC_array[0] $n_Column = $RC_array[1] Local $t_New_SArray = DllStructCreate( $tagSAFEARRAYBOUND & $tagSAFEARRAYBOUND) DllStructSetData( $t_New_SArray, 1, $n_Column ) DllStructSetData( $t_New_SArray, 2, 0 ) DllStructSetData( $t_New_SArray, 3, $n_Row ) DllStructSetData( $t_New_SArray, 4, 0 ) $pFreshCopy = SafeArrayCreate( $VT_VARIANT, 2, $t_New_SArray ) Endif If $cDims > 2 Then Return Local $Psa_Source, $Psa_Destination SafeArrayAccessData( $pSafearray, $Psa_Source ) SafeArrayAccessData( $pFreshCopy, $Psa_Destination ) Local $Total_Row = $n_Row - 1 Local $a_Row_to_Delete = StringSplit($row_to_delete, ',', 2) Local $R_flag = False, $Row_Hold = '' Local $to_Delete_Row_Number, $Row_for_Sanity_Check = '' Local $No_of_Row_toCopy = 0, $Source_Row_No = 0, $Destination_Row_No = 0 For $i = 0 To UBound($a_Row_to_Delete) - 1 $to_Delete_Row_Number = $a_Row_to_Delete[$i] If $to_Delete_Row_Number = $Row_for_Sanity_Check Then $R_flag = False $Row_Hold = $i Else $Source_Row_No = ($R_flag ? $a_Row_to_Delete[$i - 1] + 1 : (($i = 0) ? 0 : $a_Row_to_Delete[$Row_Hold] + 1)) $Destination_Row_No += $No_of_Row_toCopy $No_of_Row_toCopy = $to_Delete_Row_Number - $Row_for_Sanity_Check If $to_Delete_Row_Number <> 0 Then DllCall("kernel32.dll", "none", "RtlMoveMemory", _ "ptr", $Psa_Destination + (($Destination_Row_No * $n_Column) * $vt_Size), _ "ptr", $Psa_Source + (($Source_Row_No * $n_Column) * $vt_Size), _ "dword", (($No_of_Row_toCopy * $n_Column) * $vt_Size)) Endif $R_flag = True Endif $Row_for_Sanity_Check = $to_Delete_Row_Number + 1 Next Local $Re_dim = $Destination_Row_No + $No_of_Row_toCopy If ($Total_Row - $to_Delete_Row_Number) > 0 Then DllCall("kernel32.dll", "none", "RtlMoveMemory", _ "ptr", $Psa_Destination + (($Re_dim * $n_Column) * $vt_Size), _ "ptr", $Psa_Source + ((($to_Delete_Row_Number + 1) * $n_Column) * $vt_Size), _ "dword", ((($Total_Row - $to_Delete_Row_Number) * $n_Column) * $vt_Size)) $Re_dim = $Re_dim + ($Total_Row - $to_Delete_Row_Number) Endif SafeArrayUnaccessData($pFreshCopy) Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND) DllStructSetData( $tsaBound, 1, $Re_dim ) DllStructSetData( $tsaBound, 2, 0 ) SafeArrayRedim( $pFreshCopy, $tsaBound ) EndFunc ; #FUNCTION# ============================================================================= ; Name...........: __Get_SafeArray_Number_of_Row_Column ; ======================================================================================== Func __Get_SafeArray_Number_of_Row_Column(Byref $pSafearray) Local $irow_UBound, $icolumn_UBound Local $irow_LBound, $icolumn_LBound Local $tArray[2] SafeArrayGetUBound($pSafearray, 2, $irow_UBound) SafeArrayGetLBound($pSafearray, 2, $irow_LBound) SafeArrayGetUBound($pSafearray, 1, $icolumn_UBound) SafeArrayGetLBound($pSafearray, 1, $icolumn_LBound) $tArray[0] = ($irow_UBound + $irow_LBound) + 1 $tArray[1] = ($icolumn_UBound + $icolumn_LBound) + 1 Return $tArray EndFunc __Example_B() ConsoleWrite: __Example_B() > Array_Create: 1145.71739533647 ! Time taken to pass Array through Com object: 537.44615029274 <<= can't do anyting about this as this is AutoIt internal thing + __SafeArray_Delete_Row: 5.64971355980248 ;<============= this the original time taken to delete given row ! Time taken to pass SafeArray through Com object: 266.234002568688 <<= can't do anyting about this as this is AutoIt internal thing > __Delete_1D_2D_Row: 868.525524148816 So to delete row of Array[5000][100], actual time taken just 5.64971355980248 Edited August 7 by jugador
jugador Posted August 7 Author Posted August 7 Reference link: https://www.autoitscript.com/forum/topic/213041-autoit-com-speed-with-variants/#comment-1544904 https://www.autoitscript.com/forum/topic/213008-array-pointer/#comment-1545071 While passing data through Com object it's taking time, @Jon can AutoIt be optimized when passing data through a Com object ?
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now