Jump to content
LarsJ

Accessing AutoIt Arrays

Recommended Posts

LarsJ

An experienced AutoIt user can make the observation that it's possible to pass an array to compiled code as a parameter to a method in a COM object. This also seems to be the only way.

An obvious way to process an array in compiled code is therefore simply to create an object and a method to process the array.

Another but not quite so obvious way is to replace the methods in an existing object with new methods coded in AutoIt. Inside these methods, you can access an AutoIt array as a pointer to a safearray or as a pointer to the data area in a safearray. And one of these pointers can be passed to compiled code.

Note that through a pointer to the data area in a safearray it's possible to access array memory directly.

In both of these ways, safarrays plays an important role because COM arrays are safearrays.

And you can also conclude that AutoIt arrays are internally stored as safarrays.

The first way to create a new object is convenient in programming languages like C# and VB.NET. This way is demonstrated in Using C# and VB Code in AutoIt.

Using C# and VB Code in AutoIt is based on DotNet.au3 UDF to access .NET Framework from AutoIt. The advantage of using the latter UDF is that there is no need for an IDE to develop C# or VB code. There is no need other than AutoIt and SciTE. When the code is run in SciTE, C# and VB error messages are displayed in the console. Registering DLL files to access the objects is also not an issue. This is handled through .NET Framework.

The other way of replacing the methods in an existing object is convenient in programming languages like assembler, C, C++ and FreeBasic. This way is demonstrated in Accessing AutoIt Variables.

When using this way, an IDE is usually needed to develop and compile code. The exception is flat assembler code, that can be handled entirely through AutoIt, SciTE and FASM.DLL. There is a short description and example here.

This new project is a common UDF to access AutoIt arrays from compiled code in one of these two ways and to access array memory directly. A small example which implements a Delete.au3 UDF to delete rows and columns demonstrates the usage of the UDF. It's shown how to use Delete.au3 in your own project.

 

Accessing Arrays UDF

The zip-file below is structured this way:

  • AccArrays\ - Accessing Arrays UDF
  • Delete\    - Delete example
  • Display\   - Display funcs
  • Project\   - Project example

AccArrays\ is further divided into

  • AccArrays\ - 7 files that implements the UDF
  • Utilities\ - Utility functions

The 7 files that implements the UDF are copied from Accessing AutoIt Variables and Using C# and VB Code in AutoIt. Some of the files are shortened to only include code necessary for this project. Also, some function and variable names have been changed and shortened.

Delete\ and Project\ are discussed below. Display\ contains functions copied from Data display functions.

 

Delete example

The Delete example implements 3 functions: DelRowsNum, DeleteRows and DeleteColumns.

DelRowsNum demonstrates how to access array memory directly to delete rows in a 1D or 2D array of numbers (no strings). This function is coded entirely in AutoIt.

DeleteRows is the general function to delete rows that also can handle arrays containing strings. C++ code is used to performance optimize the function.

DeleteColumns deletes columns in a 2D array. The hard work in this function is performed by VB code.

Delete\ is divided into 5 main folders:

  • DLLFiles\ - C++ and VB dll-files
  • Examples\ - Function examples
  • Includes\ - Include files
    • Delete.au3 - Main include
    • Functions\ - Implementations
      • DelRowsNum.au3 - Code for DelRowsNum()
      • DeleteRows.au3 - Code for DeleteRows()
      • DeleteColumns.au3 - Code for DeleteColumns()
      • Initialization.au3 - Code to load dll-files
      • Internal\ - Internal files
  • Sources\ - C++ and VB source files
  • Utilities\ - Create .NET assembly dll

Before the functions are reviewed, we need to look at a few concepts and topics.

Row- and column-major arrays
Row- and column-major order of arrays is about how arrays are stored in memory.

This is an array with 3 rows and 4 columns

$aArray[3][4] = [ [ 1, 2, 3, 4 ], _
                  [ 5, 6, 7, 8 ], _
                  [ 9,10,11,12 ] ]

If the array is stored in memory as a row-major array it's stored row by row:

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12

If the array is stored in memory as a column-major array it's stored column by column:

1 | 5 | 9 | 2 | 6 | 10 | 3 | 7 | 11 | 4 | 8 | 12

If array memory can be accessed directly then row manipulations can be performed solely by memory move operations (without any loops) in a row-major array. Column manipulations can be performed solely by memory move operations (without any loops) in a column-major array.

This is not important in a conventional AutoIt function because array memory cannot be accessed directly. But it's different for a safearay in an AutoIt object method and for a VB array in a VB object method.

When a true AutoIt array is passed to an AutoIt object method as a safearray of variants, this safearray is a row-major array and row manipulations can be performed solely by memory move operations with RtlMoveMemory.

When an AutoIt array is passed to a VB object method as an array of objects, this array is a column-major array and column manipulations can be performed solely by memory move operations with Array.Copy and similar methods.

Use safearrays to create fast functions to manipulate rows in an array. Use VB arrays to create fast functions to manipulate columns in an array.

Problem with safearrays
But there is a significant problem with safarrays. Direct memory manipulation of safarrays of variants can only be performed if data in the variants is entirely stored within the variant structure. This generally means that data in the variants and safearrays must be numbers (integers, floats).

For strings, only a pointer to the string is stored in the variant. The string itself is stored as a BSTR somewhere else in memory. Direct memory manipulation of safarrays containing strings isn't possible. Elements in a safarray containing strings must be handled ono by one in a loop eg. a C++ loop.

Passing arrays to/from methods
Another problem is passing arrays back and forth between AutoIt code and object method code. This takes time. For large arrays with more than 1,000,000 elements the time can be significant. Especially passing arrays from AutoIt code to object method code. And particularly arrays containing strings. This topic will be dealed with in more details in a later post.

Because it takes a long time to pass an array from AutoIt code to object method code, it's a great advantage to be able to process multiple rows/columns and multiple groups of rows/columns at once. In this way you only need to pass the array once.

DelRowsNum
DelRowsNum accesses array memory directly and can therefore only handle arrays of numbers (no strings). For arrays of numbers this function is very fast:

#include-once
#include "Internal\DelFunc.au3"

; Delete one or more rows at the specified (row) indices in a 1D or 2D array that contains numbers only
; DelRowsNum( _
;     ByRef $aArray, _ ; The 1D or 2D array to delete rows in.
;     $vIndex )        ; The (row) indices in $aArray where the rows are to be deleted. This can be a single index, a 1D array of indi-
;                      ; ces or a 2D array of "index/number of rows" pairs. Indices must be in ascending order and cannot be duplicated.
;
;     @error:    1 = $aArray is not a 1D or 2D array
;                2 = $vIndex is not a valid specification of $aArray indices/rows
;                3 = Mismatch between $aArray and $vIndex
;                    Indices plus number of rows in $vIndex must be smaller than number of rows in $aArray, indices
;                    must be in ascending order, and rows to delete must not overlap (a row must not be deleted twice).
Func DelRowsNum( _
  ByRef $aArray, _ ; The 1D or 2D array to delete rows in.
  $vIndex )        ; The (row) indices in $aArray where the rows are to be deleted.

  ; Check parameters, pass data to method, execute method
  RowsDelete( $aArray, $vIndex, DelRowsNumMtd ) ; DelFunc.au3
  If @error Then Return SetError(@error,0,0)
EndFunc

Func DelRowsNumMtd( $pvArray )
  ; Get data
  Local $aData
  AccArrays_PassDataToMethod( 1, $aData )
  Local $iRows = $aData[0], $iCols = $aData[1], $aIndex = $aData[2], $iIndex = $aData[3]

  ; Get safearray
  Local $psaArrayData
  Local $psaArray = DllStructGetData( DllStructCreate( "ptr", $pvArray + 8 ), 1 )
  SafeArrayAccessData( $psaArray, $psaArrayData )

  ; Bytes per row
  Local $iBytesPrRow = $iCols * ( @AutoItX64 ? 24 : 16 )

  ; Delete rows with RtlMoveMemory
  ; Delete rows by moving existing rows up
  Local $pCopyTo, $pCopyFrom
  For $i = $iIndex - 1 To 0 Step -1
    $pCopyTo = $psaArrayData + $aIndex[$i][0] * $iBytesPrRow
    $pCopyFrom = $pCopyTo + $aIndex[$i][1] * $iBytesPrRow
    DllCall( "kernel32.dll", "none", "RtlMoveMemory", "struct*", $pCopyTo, "struct*", $pCopyFrom, "ulong_ptr", ( $iRows - $aIndex[$i][0] - $aIndex[$i][1] ) * $iBytesPrRow )
    $iRows -= $aIndex[$i][1]
  Next

  SafeArrayUnaccessData( $psaArray )

  ; ReDim safearray to account for deleted rows
  AccArrays_SafeArrayRedim( $psaArray, $iRows )
EndFunc

The purpose of the For-loop in the method code is to delete multiple groups of rows at once.

DeleteRows
The general function that also can handle arrays containing strings is based on a C++ loop:

#include-once
#include "Initialization.au3"
#include "Internal\DelFunc.au3"

; Delete one or more rows at the specified (row) indices in a 1D or 2D array
; DeleteRows( _
;     ByRef $aArray, _ ; The 1D or 2D array to delete rows in.
;     $vIndex )        ; The (row) indices in $aArray where the rows are to be deleted. This can be a single index, a 1D array of indi-
;                      ; ces or a 2D array of "index/number of rows" pairs. Indices must be in ascending order and cannot be duplicated.
;
;     @error:    1 = $aArray is not a 1D or 2D array
;                2 = $vIndex is not a valid specification of $aArray indices/rows
;                3 = Mismatch between $aArray and $vIndex
;                    Indices plus number of rows in $vIndex must be smaller than number of rows in $aArray, indices
;                    must be in ascending order, and rows to delete must not overlap (a row must not be deleted twice).
;                4 = C++ code is not initialized
Func DeleteRows( _
  ByRef $aArray, _ ; The 1D or 2D array to delete rows in.
  $vIndex )        ; The (row) indices in $aArray where the rows are to be deleted.

  If Not DeleteInitDll( "IsDeleteInitDll" ) Then Return SetError(4,0,0)

  ; Check parameters, pass data to method, execute method
  RowsDelete( $aArray, $vIndex, DeleteRowsMtd ) ; DelFunc.au3
  If @error Then Return SetError(@error,0,0)
EndFunc

Func DeleteRowsMtd( $pvArray, $pvIndex )
  ; Get data
  Local $aData
  AccArrays_PassDataToMethod( 1, $aData )
  Local $iRows = $aData[0], $iCols = $aData[1], $iIndex = $aData[3]

  ; Get safearrays
  Local $psaArrayData, $psaIndexData
  Local $psaArray = DllStructGetData( DllStructCreate( "ptr", $pvArray + 8 ), 1 )
  Local $psaIndex = DllStructGetData( DllStructCreate( "ptr", $pvIndex + 8 ), 1 )
  SafeArrayAccessData( $psaArray, $psaArrayData )
  SafeArrayAccessData( $psaIndex, $psaIndexData )

  ; Delete rows through C++ loop
  ; Delete rows by moving existing rows up
  $iRows = DllCall( DeleteInitDll(), "int", "DeleteRows", "int", $iRows, "int", $iCols, "int", $iIndex, "ptr", $psaArrayData, "ptr", $psaIndexData )[0]

  SafeArrayUnaccessData( $psaArray )
  SafeArrayUnaccessData( $psaIndex )

  ; ReDim safearray to account for deleted rows
  AccArrays_SafeArrayRedim( $psaArray, $iRows )
EndFunc

Sources\Cpp\Delete.cpp:

#include <Windows.h>
#include <OleAuto.h>

int __stdcall DeleteRows( int iRows, int iCols, int iIndex, VARIANT *psaArray, VARIANT *psaIndex ) {
  int iArrayIdx, iDelRows;
  int iMoveTo, iMoveFrom, iMoveCnt;

  for ( int i = iIndex - 1; i >= 0; i-- ) {
    iArrayIdx = psaIndex[2*i+0].intVal;
    iDelRows  = psaIndex[2*i+1].intVal;

    // Move existing rows up
    iMoveTo   = iArrayIdx * iCols;
    iMoveFrom = iMoveTo + iDelRows * iCols;
    iMoveCnt  = ( iRows - iArrayIdx - iDelRows ) * iCols;
    for ( int j = 0; j < iMoveCnt; j++, VariantCopy( &psaArray[iMoveTo++], &psaArray[iMoveFrom++] ) );
    iRows -= iDelRows;
  }
  return iRows;
}

DeleteColumns
This function is based on VB code:

#include-once
#include "Initialization.au3"

; Delete one or more columns at the specified (column) indices in a 2D array
; DeleteColumns( _
;     ByRef $aArray, _ ; The 2D array to delete columns in.
;     $vIndex )        ; The (column) indices in $aArray where the columns are to be deleted. This can be a single index, a 1D array of indi-
;                      ; ces or a 2D array of "index/number of columns" pairs. Indices must be in ascending order and cannot be duplicated.
;
;     @error:    1 = $aArray is not a 2D array
;                2 = $vIndex is not a valid specification of $aArray indices/columns
;                3 = Mismatch between $aArray and $vIndex
;                    Indices plus number of columns in $vIndex must be smaller than number of columns in $aArray, indices
;                    must be in ascending order, and columns to delete must not overlap (a column must not be deleted twice).
;                4 = VB-code is not initialized
;                5 = No valid VB class object
Func DeleteColumns( _
  ByRef $aArray, _ ; The 2D array to delete columns in.
  $vIndex )        ; The (column) indices in $aArray where the columns are to be deleted.

  ; Check array dimensions
  Local $aI = [ $vIndex ], $aIndex = IsArray( $vIndex ) ? $vIndex : $aI
  If Not ( IsArray( $aArray ) And UBound( $aArray, 0 ) = 2 ) Then Return SetError(1,0,0)
  If Not ( UBound( $aIndex, 0 ) = 1 Or ( UBound( $aIndex, 0 ) = 2 And UBound( $aIndex, 2 ) = 2 ) ) Then Return SetError(2,0,0)

  ; Indices plus columns in $vIndex must be smaller than columns in $aArray, indices must be in
  ; ascending order, and columns to delete must not overlap (a column must not be deleted twice).
  Local $iCols = UBound( $aArray, 2 ), $iIndex = UBound( $aIndex )
  If UBound( $aIndex, 0 ) = 1 Then ; 1D array
    ; Make the 1D array into a 2D array of "index/number of columns" pairs
    Local $aIndexTmp[$iIndex][2]
    For $i = 0 To $iIndex - 1
      $aIndexTmp[$i][0] = $aIndex[$i] ; $aIndexTmp[$i][0] is the index in $aArray where the columns are to be deleted
      $aIndexTmp[$i][1] = 1           ; $aIndexTmp[$i][1] is the number of columns to delete in $aArray at the position given by the index
    Next
    $aIndex = $aIndexTmp              ; $aIndex = $aIndexTmp
  EndIf
  Local $iAllCols = $iCols, $j = $iIndex - 1
  ; Check that index do not exceed $iCols
  If $aIndex[$j][0] >= $iCols Then Return SetError(3,0,0) ; Indices in $aIndex must be in ascending order
  ; Check $aIndex for valid indices and row numbers       ; This means that it's enough to check the last index
  If $aIndex[$j][1] < 1 Or $aIndex[$j][0] + $aIndex[$j][1] > $iCols Then Return SetError(3,0,0)
  If $iCols - $aIndex[$j][1] < 1 Then Return SetError(3,0,0)
  $iCols -= $aIndex[$j][1]
  For $i = $iIndex - 2 To 0 Step -1
    If $aIndex[$i][0] > $aIndex[$i+1][0] Or $aIndex[$i][1] < 1 Or $aIndex[$i][0] + $aIndex[$i][1] > $iCols Or _
       $aIndex[$i][0] + $aIndex[$i][1] > $aIndex[$i+1][0] Then Return SetError(3,0,0)
    If $iCols - $aIndex[$i][1] < 1 Then Return SetError(3,0,0)
    $iCols -= $aIndex[$i][1]
  Next

  ; Convert $aIndex to an index of columns that are not deleted
  ; These columns can be copied into a new array
  ReDim $aIndex[$iIndex+1][5]
  $aIndex[0][2] = 0                   ; $aIndex[$i][2] is the index in $aArray where from the columns are to be copied
  $aIndex[0][3] = 0                   ; $aIndex[$i][3] is the index in the new array where the columns are to be inserted
  $aIndex[0][4] = $aIndex[0][0]       ; $aIndex[$i][4] is the number of columns to copy
  For $i = 1 To $iIndex - 1
    $aIndex[$i][2] = $aIndex[$i-1][0] + $aIndex[$i-1][1]
    $aIndex[$i][3] = $aIndex[$i-1][3] + $aIndex[$i-1][4]
    $aIndex[$i][4] = $aIndex[$i][0] - $aIndex[$i][2]
  Next
  $aIndex[$i][2] = $aIndex[$i-1][0] + $aIndex[$i-1][1]
  $aIndex[$i][3] = $aIndex[$i-1][3] + $aIndex[$i-1][4]
  $aIndex[$i][4] = $iAllCols - $aIndex[$i][2]

  If Not DeleteInitVbSrc( "IsDeleteInitVbSrc" ) And _
     Not DeleteInitVbDll( "IsDeleteInitVbDll" ) Then Return SetError(4,0,0)

  Local $oDeleteClass = DeleteInit()
  If Not IsObj( $oDeleteClass ) Then Return SetError(5,0,0)

  $aArray = $oDeleteClass.DeleteColumns( $aArray, $aIndex, $iCols )
EndFunc

Sources\Delete.vb:

Imports System

Class DeleteClass
  Public Function DeleteColumns( aArray As Object(,), aIndex As Object(,), iCols As Integer ) As Object(,)
    Dim iRows As Integer = aArray.GetUpperBound(1) + 1
    Dim aNewArray(iCols-1,iRows-1) As Object
    For i As Integer = 0 To aIndex.GetUpperBound(1)
      Array.Copy( aArray, aIndex(2,i) * iRows, aNewArray, aIndex(3,i) * iRows, aIndex(4,i) * iRows )
    Next
    Return aNewArray
  End Function
End Class

Initialization
Because DeleteRows and DeleteColumns are optimized with compiled code it's necessary to do some initialization to load the compiled code into the AutoIt process. This is done with the functions in Initialization.au3.

DeleteRows is optimized with C++ code which is compiled into dll-files and stored in DLLFiles\ as Delete.dll and Delete_x64.dll. Delete.dll and Delete_x64.dll is delivered in the zip-file. DeleteInitDll() in Initialization.au3 loads the dll-files:

; Load compiled code from C++ DLL file
; The DLL file must be specified with a full path
; Or it must be specified with a path relative to the running script
; Or it must be placed in the same folder as the running script
;
; If you're having trouble loading a DLL file, copy the DLL file to the same
; folder as the running script, and compile the script into an EXE file.
;
;     @error:    1 = $sDllPath is not specified and "Delete.dll" or
;                    "Delete_x64.dll" is not located with the running script
;                2 = "Delete.dll" or "Delete_x64.dll" cannot be found in $sDllPath
Func DeleteInitDll( $sDllPath = "" ) ; $sDllPath must be the path WITHOUT DLL filename
  Static $hDeleteDll = 0
  If $hDeleteDll Then Return $hDeleteDll
  If $sDllPath = "IsDeleteInitDll" Then Return $hDeleteDll
  Local $sDllFile = @AutoItX64 ? "Delete_x64.dll" : "Delete.dll"
  If Not $sDllPath Then
    If FileExists( $sDllFile ) Then
      $sDllPath = ".\"
    Else
      ConsoleWrite( "File path (without DLL filename) for """ & $sDllFile & """ must be specified, or" & @CRLF & _
                    """ & $sDllFile & "" must be placed in the same folder as the running script." & @CRLF )
      Return SetError(1,0,0)
    EndIf
  EndIf
  If StringRight( $sDllPath, 1 ) <> "\" Then $sDllPath &= "\"
  If Not FileExists( $sDllPath & $sDllFile ) Then
    ConsoleWrite( "DLL file """ & $sDllPath & $sDllFile & """ cannot be found" & @CRLF )
    Return SetError(2,0,0)
  EndIf
  $hDeleteDll = DllOpen( $sDllPath & $sDllFile )
EndFunc

DeleteColumns is optimized with VB code, but only the source code is delivered in the zip-file. The code is stored in Sources\Delete.vb. Delete.vb can be loaded in two ways. It can be compiled and loaded on the fly directly from the source. Or it can be compiled into a .NET assembly dll-file and loaded from the dll-file.

You have to create the .NET assembly dll-file yourself with Utilities\Delete_CreateDLL.au3. When you run this script Delete.vb is compiled into a dll-file and stored as DLLFiles\DeleteVb.dll. The same dll-file can be used in 32 and 64 bit code.

There are two reasons why you have to create the .NET assembly dll-file yourself:

  • You can create the dll-file with your installed version of .NET Framework
  • There is no need to deliver a .NET assembly dll-file in the zip-file

DeleteInitVbSrc() in Initialization.au3 compiles and loads Delete.vb on the fly:

; Compile and load .NET code from source file
; The source file must be specified with a full path
; Or it must be specified with a path relative to the running script
Func DeleteInitVbSrc( $sSrcPath )
  Static $bIsDeleteInitVbSrc = 0
  If $sSrcPath = "IsDeleteInitVbSrc" Then Return $bIsDeleteInitVbSrc
  If Not FileExists( $sSrcPath ) Then
    ConsoleWrite( "Source file """ & $sSrcPath & """ cannot be found" & @CRLF )
    Return SetError(2,0,0)
  EndIf
  ; Compile and load VB code
  Local $oNetCode = DotNet_LoadVBcode( FileRead( $sSrcPath ), "System.dll" )
  DeleteInit( $oNetCode )
  $bIsDeleteInitVbSrc = 1
EndFunc

DeleteInitVbDll() loads DeleteVb.dll:

; Load .NET code from .NET assembly DLL file
; The DLL file must be specified with a full path
; Or it must be specified with a path relative to the running script
; Or it must be placed in the same folder as the running script
;
; If you're having trouble loading a DLL file, copy the DLL file to the same
; folder as the running script, and compile the script into an EXE file.
Func DeleteInitVbDll( $sDllPath = "" )
  Static $bIsDeleteInitVbDll = 0
  If $sDllPath = "IsDeleteInitVbDll" Then Return $bIsDeleteInitVbDll
  If Not $sDllPath Then
    If FileExists( "DeleteVb.dll" ) Then
      $sDllPath = "DeleteVb.dll"
    Else
      ConsoleWrite( "File path for ""DeleteVb.dll"" must be specified, or" & @CRLF & _
                    """DeleteVb.dll"" must be placed in the same folder as the running script." & @CRLF )
      Return SetError(1,0,0)
    EndIf
  EndIf
  If Not FileExists( $sDllPath ) Then
    ConsoleWrite( "DLL file """ & $sDllPath & """ cannot be found" & @CRLF )
    Return SetError(2,0,0)
  EndIf
  ; Load DeleteVb.dll
  Local $oNetCode = DotNet_LoadAssembly( $sDllPath )
  DeleteInit( $oNetCode )
  $bIsDeleteInitVbDll = 1
EndFunc

 

Examples
This is the code for Examples\DeleteColumns\Using Delete.vb\10,000 rows.au3:

#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6

#include "..\..\..\..\Delete\Includes\Delete.au3"
DeleteInitVbSrc( "..\..\..\..\Delete\Sources\Delete.vb" )
#include "..\..\..\..\Display\Functions\ArrayDisplayEx\ArrayDisplayEx.au3"

Opt( "MustDeclareVars", 1 )

Example()

Func Example()
  ; Create array
  Local $iRows = 10000, $iCols = 16
  Local $aArray0[$iRows][$iCols]
  For $i = 0 To $iRows - 1
    For $j = 0 To $iCols - 1
      $aArray0[$i][$j] = $i & "/" & $j
    Next
  Next
  _ArrayDisplayEx( $aArray0, "$aArray0" )

  Local $aArray

  ; Example 1
  $aArray = $aArray0
  Local $aIndex1 = 3 ; Delete column 3
  DeleteColumns( $aArray, $aIndex1 )
  If @error Then Return ConsoleWrite( "DeleteColumns: @error = " & @error & @CRLF )
  _ArrayDisplayEx( $aArray, "Example 1" )

  ; Example 2
  $aArray = $aArray0
  Local $aIndex2 = [ 3, 8 ] ; Delete column 3 and 8
  DeleteColumns( $aArray, $aIndex2 )
  If @error Then Return ConsoleWrite( "DeleteColumns: @error = " & @error & @CRLF )
  _ArrayDisplayEx( $aArray, "Example 2" )

  ; Example 3
  $aArray = $aArray0
  Local $aIndex3 = [ [ 3, 2 ], _ ; Delete column 3 and 4
                     [ 8, 3 ] ]  ; Delete column 8, 9, 10
  DeleteColumns( $aArray, $aIndex3 )
  If @error Then Return ConsoleWrite( "DeleteColumns: @error = " & @error & @CRLF )
  _ArrayDisplayEx( $aArray, "Example 3" )
EndFunc

Note how Delete.au3 UDF is included and Delete.vb is initialized in top of the script with these lines:

#include "..\..\..\..\Delete\Includes\Delete.au3"
DeleteInitVbSrc( "..\..\..\..\Delete\Sources\Delete.vb" )

Use these lines to initialize Delete.dll or Delete_x64.dll:

#include "..\..\..\Delete\Includes\Delete.au3"
DeleteInitDll( "..\..\..\Delete\DLLFiles" ) ; No filename

Note how the folders Includes, Sources, and DLLFiles are located just below Delete\.

 

Project example

To use Delete.au3 UDF in your own project copy AccArrays\ and Delete\ (and also Display\ if you need display functions) to the project. In a production environment, Delete.vb should be compiled as a .NET assembly dll-file. Delete unnecessary subfolders in Delete\. Use the following code blocks to initialize VB and C++ code.

Initialize VB code from source file:

#include "Delete\Includes\Delete.au3"
DeleteInitVbSrc( "Delete\Sources\Delete.vb" )

Initialize VB code from .NET assembly dll-file:

#include "Delete\Includes\Delete.au3"
DeleteInitVbDll( "Delete\DLLFiles\DeleteVb.dll" )

Initialize C++ code from dll-files:

#include "Delete\Includes\Delete.au3"
DeleteInitDll( "Delete\DLLFiles" ) ; No filename

 

Zip-file

You need AutoIt 3.3.10 or later. Tested on Windows 10 and Windows 7.

Tomorrow some larger examples will be presented that are using AccArrays UDF. That's the really interesting code.

Comments are welcome. Let me know if there are any issues.

AccArrays.7z

Edited by LarsJ
Minor updates
  • Thanks 3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.