Jump to content

Close _ArrayDisplay using timeout


Recommended Posts

Hello All,

I use _ArrayDisplay a lot because it's so convenient.

I'd like some input on how to have it timeout and close without the need to click.

I'm sure this is very easy for some people here, but the solution eludes me.

Thank you in advance for any direction.

taurus905

Func _ArrayDisplay(Const ByRef $aArray, $sTitle = Default, $sArrayRange = Default, $iFlags = Default, $vUser_Separator = Default, $sHeader = Default, $iMax_ColWidth = Default)
    #forceref $vUser_Separator
    Local $iRet = __ArrayDisplay_Share($aArray, $sTitle, $sArrayRange, $iFlags, Default, $sHeader, $iMax_ColWidth, 0, False)
    Return SetError(@error, @extended, $iRet)
EndFunc   ;==>_ArrayDisplay

 

"Never mistake kindness for weakness."-- Author Unknown --"The highest point to which a weak but experienced mind can rise is detecting the weakness of better men."-- Georg Lichtenberg --Simple Obfuscator (Beta not needed.), Random names for Vars and Funcs

Link to comment
Share on other sites

The easiest way in my opinion is to create another process responsible to close the arraydisplay after a specified delay :

#pragma compile(AutoItExecuteAllowed, true)

#include <Constants.au3>
#include <Array.au3>
#include <WinAPIFiles.au3>

Opt ("MustDeclareVars", True)

Local $aVar = [1,2,3,4,5,6,7,8]
Local $sTitle = "My Array Display Title"

_CreateChild($sTitle, 5000)
_ArrayDisplay($aVar, $sTitle)

Func _CreateChild ($sTitle, $iDuration)
  Local $sTempFile = _WinAPI_GetTempFileName (@TempDir, "~")
  Local $sScript = _
    "#NoTrayIcon" & @CRLF & _
    "While Sleep(100)" & @CRLF & _
    "If WinExists('" & $sTitle & "') Then ExitLoop" & @CRLF & _
    "WEnd" & @CRLF & _
    "Sleep(" & $iDuration & ")" & @CRLF & _
    "If WinExists('" & $sTitle & "') Then WinClose('"  & $sTitle & "')" & @CRLF & _
    "Sleep(200)" & @CRLF & _
    "FileDelete (@ScriptFullPath)"
  FileWrite ($sTempFile, $sScript)
  Run (@AutoItExe & ' /AutoIt3ExecuteScript "' & $sTempFile & '"', @TempDir, @SW_HIDE)
EndFunc

 

Link to comment
Share on other sites

4 minutes ago, Nine said:

The easiest way in my opinion is to create another process responsible to close the arraydisplay after a specified delay :

Thank you, Nine.

That's a very elegant solution.

I love to learn new ways to use AutoIt (my favorite for creating tools).

taurus905

"Never mistake kindness for weakness."-- Author Unknown --"The highest point to which a weak but experienced mind can rise is detecting the weakness of better men."-- Georg Lichtenberg --Simple Obfuscator (Beta not needed.), Random names for Vars and Funcs

Link to comment
Share on other sites

Hi taurus905 & Nine :
I always liked the AdlibRegister way, which calls the Adlib function only once (maximum) in OP's case, for example :

#include <Array.au3>

Local $aVar = [0,1,2,3,4,5,6,7,8,9]
Local $iTimeOut = 5 ; <=== 5s, change to your wish
Global $g_sTitle = "Close in " & $iTimeOut & "s"

AdlibRegister("MyAdLibFunc", $iTimeOut * 1000)
_ArrayDisplay($aVar, $g_sTitle)
AdlibUnRegister("MyAdLibFunc")

; ...script continuation here

Func MyAdLibFunc()
    If WinExists($g_sTitle) Then
        AdlibUnRegister("MyAdLibFunc")
        WinClose($g_sTitle)
    EndIf
EndFunc   ;==>MyAdLibFunc

But I don't know if it's a good idea to close automatically the new version of ArrayDisplay after a timeout without exiting AutoIt, as the script continues.

What about the eventual big global arrays $_g_ArrayDisplay_aIndex and $_g_ArrayDisplay_aIndexes which could still use a lot of memory ? And the subclassing in ArrayDisplay not being removed, no problem with that ? IDK :frantics:

Edit: the Adlib function could even be shorter in OP's case, something like this :

Func MyAdLibFunc()
    AdlibUnRegister("MyAdLibFunc")
    WinClose($g_sTitle)
EndFunc   ;==>MyAdLibFunc

 

Edited by pixelsearch
Link to comment
Share on other sites

6 minutes ago, pixelsearch said:

But I don't know if it's a good idea to close automatically the new version of ArrayDisplay after a timeout without exiting AutoIt, as the script continues.

Hello pixelsearch,

Your input is always welcomed.

In fact, in many cases I want the AutoIt script to continue.

I will test Nine's solution and yours to see which works best for the particular instance.

I appreciate both of your ideas, since I love to have options.

taurus905

"Never mistake kindness for weakness."-- Author Unknown --"The highest point to which a weak but experienced mind can rise is detecting the weakness of better men."-- Georg Lichtenberg --Simple Obfuscator (Beta not needed.), Random names for Vars and Funcs

Link to comment
Share on other sites

@pixelsearch  I like your solution, but I have found that in some situations (when the function is truly blocking), the adlib approach (or other timer) will not work.  So this is why I always favor the second-process approach, which will work all the time.  Just my 2 cents BTW.

Link to comment
Share on other sites

Hi Nine
Thanks for your input.
I did some tests in 2019 and kept them in a script, so I'll post it now 3 years after, without changing a line in it.
I don't feel like running it again or re-testing but I never considered ArrayDisplay as a blocking function. The AdLib way coupled with ArrayDisplay has been used nearly daily since 2019 by a person I sent a script to,  and he never reported something strange happened, maybe he was lucky :)

#include <Array.au3>
#include <MsgBoxConstants.au3>

Opt("WinTitleMatchMode", -2)    ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase

If ProcessExists("SciTE.exe") = 0 Then
    MsgBox($MB_SYSTEMMODAL, "", "You will need SciTE.exe to be running for ConsoleWrite to display.")
EndIf

Example()

Func Example()
    ; Register the function MyAdLibFunc() to be called every 250ms (default).
    AdlibRegister("MyAdLibFunc")

    ; Sleep does not stop AdLib functions from running.
    Sleep(1000)

    ; ==============================================================================================================================
    ; Help file : "AdLib functions don't run while a blocking function is shown e.g. MsgBox, InputBox, WinWait, WinWaitClose etc..."
    ; ==============================================================================================================================

    MsgBox($MB_SYSTEMMODAL, "", "No console message(s) will be shown whilst the messagebox is displayed.") ; ok, blocking function

    ; InputBox("Just a test", "Enter what you want") ; ok, blocking function

    ; Initiates a Browse for Folder dialog.
    ; $sFileSelectFolder = FileSelectFolder("Select a folder", "") ; ok, blocking function (help file, topic... HotKeySet)

    ; Initiates an Open File dialog.
    ; $sFileOpenDialog = FileOpenDialog("Select a file", @WindowsDir & "\", "All (*.*)") ; ok, blocking function

    ; Initiates a Save File dialog.
    ; $sFileSaveDialog = FileSaveDialog("Choose a filename", @WorkingDir, "Scripts (*.au3)") ; ok, blocking function

    ; WinWait("fghdfghj") ; NOT a blocking function (help file wrong, topics AdlibRegister & AdlibUnRegister)
    ; *******

    ; Open WordPad before this test, then run this script without closing WordPad immediately
    ; WinWaitClose("WordPad") ; NOT a blocking function (help file wrong, topics AdlibRegister & AdlibUnRegister)
    ; ************

    ; https://www.autoitscript.com/forum/topic/197449-_arraydisplay-and-msgbox-at-same-time/
    ; Local $aArray[5] = [0, 1, 2, 3, 4]
    ; _ArrayDisplay($aArray) ; NOT a blocking function as a Mod wrote "_ArrayDisplay is a blocking function" in the precedent link
    ; *************

    ; When needed, add functions here for testing if they are blocking functions or not

    ; The AdLib function MyAdLibFunc() will start again.
    Sleep(1000)

    ; Unregister the function MyAdLibFunc() from being called every 250ms.
    AdlibUnRegister("MyAdLibFunc")
EndFunc   ;==>Example

Func MyAdLibFunc()
    ; Assign a static variable to hold the number of times the function is called.
    Local Static $iCount = 0
    $iCount += 1

    ConsoleWrite("MyAdLibFunc called " & $iCount & " time(s)" & @CRLF)
EndFunc   ;==>MyAdLibFunc

 

Link to comment
Share on other sites

2 hours ago, pixelsearch said:

Edit: the Adlib function could even be shorter in OP's case, something like this :

@pixelsearch I was wondering why AdlibUnRegister("MyAdLibFunc") is called twice.

Is there a reason, or could the first one be removed?

#include <Array.au3>

Local $aVar = [0,1,2,3,4,5,6,7,8,9]
Local $iTimeOut = 5 ; <=== 5s, change to your wish
Global $g_sTitle = "Close in " & $iTimeOut & "s"

AdlibRegister("MyAdLibFunc", $iTimeOut * 1000)
_ArrayDisplay($aVar, $g_sTitle)
AdlibUnRegister("MyAdLibFunc")

; ...script continuation here

Func MyAdLibFunc()
    AdlibUnRegister("MyAdLibFunc")
    WinClose($g_sTitle)
EndFunc   ;==>MyAdLibFunc

 

"Never mistake kindness for weakness."-- Author Unknown --"The highest point to which a weak but experienced mind can rise is detecting the weakness of better men."-- Georg Lichtenberg --Simple Obfuscator (Beta not needed.), Random names for Vars and Funcs

Link to comment
Share on other sites

add timer  :think: to __ArrayDisplay_Share to auto close

#include <GUIConstantsEx.au3>

Example()
Func Example()
    Local $hGUI = GUICreate("Example", 400, 400)
    Local $idOK = GUICtrlCreateButton("OK", 310, 370, 85, 25)
    GUISetState(@SW_SHOW, $hGUI)

    Local $iTimmer = TimerInit()    ;<<=== timer
    While 1
        If TimerDiff($iTimmer) > 3000 Then ExitLoop     ;<<=== check to auto close
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idOK

            EndSwitch
        WEnd
        GUIDelete($hGUI)
EndFunc

 

Link to comment
Share on other sites

13 hours ago, pixelsearch said:

I never considered ArrayDisplay as a blocking function.

HI
Could you please explain/elaborate ?
ArrayDisplay (__ArrayDisplay_Share) includes a gui with an infinite While loop, and no global var inside to interact with to allow an exit from this loop
Your code works (nicely indeed) using a WinClose, which is (sort of) a brute force way and not really a gentle & sweet exit/return from the func :)

Link to comment
Share on other sites

44 minutes ago, mikell said:

Could you please explain/elaborate ?

Hey Soulful cat @mikell it's been a long time !

imho a "blocking function" is a function that stops AdlibRegister to be called while the function is active, no more, no less.

If you look at the help file example, topics AdlibRegister or AdlibUnRegister, you'll notice this important sentence written in the example :

; AdLib functions don't run while a blocking function is shown e.g. MsgBox, InputBox, WinWait, WinWaitClose etc.

My tests above (from 2019) show this sentence is not true, because WinWait and WinWaitClose keep on running AdLib functions, while MsgBox and InputBox stop AdLib from running. So who wrote this sentence in the example as it's half true, half false ?

It would have been a better idea to indicate somewhere a list of all the blocking functions (or in the topic of each blocking function). A non exhaustive list is : MsgBox , InputBox , FileSelectFolder [as indicated in topic... HotKeySet ! then tested in 2019] , FileOpenDialog , FileSaveDialog etc...

That's the reason why I consider _ArrayDisplay "not blocking" as you can run an Adlib function while ArrayDisplay is active... no more, no less :)

15 hours ago, Nine said:

I like your solution, but I have found that in some situations (when the function is truly blocking)...

Nine expressed this in a nice way because he indicated why he always chooses "the second-process approach, which will work all the time". He knows that _ArrayDisplay isn't a "truly blocking function" (compared to MsgBox for example) and "truly" is the word !
So instead of checking each time if a function is a "truly" blocking function or not, he prefers to always use the 2nd process approach, while I prefer the simpler AdLib approach... when possible :) 

Link to comment
Share on other sites

Another reason why I prefer the second-process approach is that you can pass as many parameters as you need to without creating global variables.  The adlib approach forces the creation of many globals if you intend to vary the calls.  Since the best practices in programming is to reduce as much as possible the usage of global variables... :)

Link to comment
Share on other sites

  • 2 years later...

2 years later...

Just playing with this a little now. If I have time I'll look for another solution. @Nine I like that idea but it seems the first problem I found is it has to be run on a PC that has Autoit installed. I'd have to have the end-user install (or pre-package) the @AutoItExe package to use the specified Run() command 🙂

I like the left field/right field brain storming.

Link to comment
Share on other sites

Thanks @argumentum Ok I don't see a way yet of doing it using @jugador method since _ArrayDisplay is a synchronous blocking function but for now I might use @pixelsearch method as shown below but there's still a global variable $g_sTitle I'll just accept for now:

 

#include <GUIConstantsEx.au3>
#include <Array.au3>

Example()

Func Example()
    Local $hGUI = GUICreate("Example", 400, 400)
    Local $idOK = GUICtrlCreateButton("ArrayDisplay Timeout", 250, 370, 115, 25)
    GUISetState(@SW_SHOW, $hGUI)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $idOK
                AdlibRegister("_CloseArrayDisplay", 2500) ; Check every 500 ms
                Local $aArray[5] = [1, 2, 3, 4, 5]
                Global $g_sTitle = "Array Display"
                _ArrayDisplay($aArray, $g_sTitle)   ; Display the array
        EndSwitch
    WEnd

    GUIDelete($hGUI)
    AdlibUnRegister("_CloseArrayDisplay") ; Stop checking when the main loop ends
EndFunc

Func _CloseArrayDisplay()
    If WinExists($g_sTitle) Then
        AdlibUnRegister("_CloseArrayDisplay")
        WinClose($g_sTitle)
    EndIf
EndFunc


 

Edited by NassauSky
Link to comment
Share on other sites

2 hours ago, NassauSky said:

I don't see a way yet of doing it using @jugador method

These UDFs can be tweaked at will for personal use. Don't be afraid of braking anything. You can always restore the original ( if you make a copy/backup of it ).

_ArrayDisplay(), if you look at the code, runs __ArrayDisplay_Share(). So you'd edit __ArrayDisplay_Share() with a global variable in "ArrayDisplayInternals.au3". Look for "If $aMsg[1] = $hGUI Then" and add your easily patchable code (TM)  to it, like:

If $__g_ArrayDisplay_Timeout_msExit Then
            If TimerDiff($hRetTimer) > $__g_ArrayDisplay_Timeout_msExit Then
                GUIDelete($hGUI)
                Exit $__g_ArrayDisplay_Timeout_ecExit
            EndIf
        EndIf

        If $aMsg[1] = $hGUI Then

then you put those new variables on top of the script with a helper function to set them:

Global $__g_ArrayDisplay_Timeout_msExit = 0 ; if timeout: EXIT
Global $__g_ArrayDisplay_Timeout_ecExit = 99 ; if timeout exit: show this @ExitCode
Func _DebugArrayDisplay_TimeoutExit($mSec = Default, $iExitCode = Default)
    If $mSec <> Default Then $__g_ArrayDisplay_Timeout_msExit = $mSec
    If $iExitCode <> Default Then $__g_ArrayDisplay_Timeout_ecExit = $iExitCode
    Return SetError(0, $__g_ArrayDisplay_Timeout_ecExit, $__g_ArrayDisplay_Timeout_msExit)
EndFunc   ;==>_DebugArrayDisplay_TimeoutExit

That way you can call your helper function _DebugArrayDisplay_TimeoutExit() to setup your timeout, then after that call _ArrayDisplay()

,,,now that I look at it looks intimidating. But we learn by doing so, go at it. Is just code.

 

Might as well give you the ArrayDisplayInternals.au3 I use

Spoiler
#include-once

#include "AutoItConstants.au3"
#include "MsgBoxConstants.au3"
#include "StringConstants.au3"
#include <GUIConstantsEx.au3>; added For __ArrayDisplay_SubItemHitTest_ClipPut
#include <GuiListView.au3>; added For __ArrayDisplay_SubItemHitTest_ClipPut

; #INDEX# =======================================================================================================================
; Title .........: Internal UDF Library for AutoIt3 _ArrayDisplay() and _DebugArrayDisplay()
; AutoIt Version : 3.3.16.1 ;;; https://www.autoitscript.com/forum/topic/196962-suggested-modification-to-arraydisplayinternalsau3/?do=findComment&comment=1507661
; Description ...: Internal functions for the Array.au3 and Debug.au3
; Author(s) .....: Melba23, jpm, LarsJ, pixelsearch
; Modifier(s) ...: Tippex ; https://www.autoitscript.com/forum/topic/196962-suggested-modification-to-arraydisplayinternalsau3/
;                : argumentum
; ===============================================================================================================================

#Region Global Variables and Constants

; #VARIABLES# ===================================================================================================================
; for use with the notify handler

Global $_g_ArrayDisplay_bUserFunc = False
Global $_g_ArrayDisplay_hListView
Global $_g_ArrayDisplay_iTranspose
Global $_g_ArrayDisplay_iDisplayRow
Global $_g_ArrayDisplay_aArray
Global $_g_ArrayDisplay_iDims
Global $_g_ArrayDisplay_nRows
Global $_g_ArrayDisplay_nCols
Global $_g_ArrayDisplay_iItem_Start
Global $_g_ArrayDisplay_iItem_End
Global $_g_ArrayDisplay_iSubItem_Start
Global $_g_ArrayDisplay_iSubItem_End
Global $_g_ArrayDisplay_aIndex
Global $_g_ArrayDisplay_aIndexes[1]
Global $_g_ArrayDisplay_iSortDir
Global $_g_ArrayDisplay_asHeader
Global $_g_ArrayDisplay_aNumericSort

Global $ARRAYDISPLAY_ROWPREFIX = "#"
Global $ARRAYDISPLAY_NUMERICSORT = "*"
; ===============================================================================================================================

; #CONSTANTS# ===================================================================================================================
Global Const $ARRAYDISPLAY_COLALIGNLEFT = 0 ; (default) Column text alignment - left
Global Const $ARRAYDISPLAY_TRANSPOSE = 1 ; Transposes the array (2D only)
Global Const $ARRAYDISPLAY_COLALIGNRIGHT = 2 ; Column text alignment - right
Global Const $ARRAYDISPLAY_COLALIGNCENTER = 4 ; Column text alignment - center
Global Const $ARRAYDISPLAY_VERBOSE = 8 ; Verbose - display MsgBox on error and splash screens during processing of large arrays
Global Const $ARRAYDISPLAY_ONLYCOPYBUTTONS = 16 ; Only 'Copy' buttons displayed
Global Const $ARRAYDISPLAY_NOBUTTONSDISPLAY = 32 ; No buttons displayed
Global Const $ARRAYDISPLAY_NOROW = 64 ; No 'Row' column displayed
Global Const $ARRAYDISPLAY_CHECKERROR = 128 ; return if @error <> 0 (avoid display after _Array*() errors)
Global Const $ARRAYDISPLAY_NODATALABELDISPLAY = 256 ; 128 ; No data label displayed
Global Const $ARRAYDISPLAY_NoRightClick = 512

Global Const $_ARRAYCONSTANT_tagLVITEM = "struct;uint Mask;int Item;int SubItem;uint State;uint StateMask;ptr Text;int TextMax;int Image;lparam Param;" & _
        "int Indent;int GroupID;uint Columns;ptr pColumns;ptr piColFmt;int iGroup;endstruct"
; ===============================================================================================================================

#EndRegion Global Variables and Constants

#Region Functions list

; #CURRENT# =====================================================================================================================
; ===============================================================================================================================

; #INTERNAL_USE_ONLY# ===========================================================================================================
; __ArrayDisplay_Share
; __ArrayDisplay_SortIndexes
; ___ArrayDisplay_NotifyHandler
; __ArrayDisplay_GetSortColStruct
; __ArrayDisplay_SortArrayStruct
; __ArrayDisplay_Transpose
; __ArrayDisplay_HeaderSetItemFormat
; __ArrayDisplay_GetItemText
; __ArrayDisplay_GetItemTextStringSelected
; __ArrayDisplay_JustifyColumn
; ===============================================================================================================================

#EndRegion Functions list

Global $__g_ArrayDisplay_Timeout_msReturn = 0 ; if timeout: close the gui
Func _DebugArrayDisplay_TimeoutReturn($mSec = Default)
    If $mSec <> Default Then $__g_ArrayDisplay_Timeout_msReturn = $mSec
    Return $__g_ArrayDisplay_Timeout_msReturn
EndFunc   ;==>_DebugArrayDisplay_DefaultFlags

Global $__g_ArrayDisplay_Timeout_msExit = 0 ; if timeout: EXIT
Global $__g_ArrayDisplay_Timeout_ecExit = 99 ; if timeout exit: show this @ExitCode
Func _DebugArrayDisplay_TimeoutExit($mSec = Default, $iExitCode = Default)
    If $mSec <> Default Then $__g_ArrayDisplay_Timeout_msExit = $mSec
    If $iExitCode <> Default Then $__g_ArrayDisplay_Timeout_ecExit = $iExitCode
    Return SetError(0, $__g_ArrayDisplay_Timeout_ecExit, $__g_ArrayDisplay_Timeout_msExit)
EndFunc   ;==>_DebugArrayDisplay_TimeoutExit

Global $__g_ArrayDisplay_Share_iFlags = 0
Func _DebugArrayDisplay_DefaultFlags($iFlags = Default)
    If $iFlags <> Default Then $__g_ArrayDisplay_Share_iFlags = $iFlags
    Return $__g_ArrayDisplay_Share_iFlags
EndFunc   ;==>_DebugArrayDisplay_DefaultFlags

Func __ArrayDisplay_SubItemHitTest_ClipPut($hWnd, $iX = -1, $iY = -1)
    $hWnd = GUICtrlGetHandle($hWnd)
    Local $_mPos = MouseGetPos(), $aTest = _GUICtrlListView_SubItemHitTest($hWnd, $iX, $iY)
    ReDim $aTest[12]
    $aTest[11] = _GUICtrlListView_GetItemText($hWnd, $aTest[0], $aTest[1])
    ClipPut($aTest[11])
    ToolTip($aTest[11], $_mPos[0] - 20, $_mPos[1] - 60, "ClipPut", 0, 4)
    AdlibRegister("__ArrayDisplay_ToolTipOff", 500)
    Return $aTest
EndFunc   ;==>__ArrayDisplay_SubItemHitTest_ClipPut
Func __ArrayDisplay_ToolTipOff()
    AdlibUnRegister("__ArrayDisplay_ToolTipOff")
    ToolTip("")
EndFunc   ;==>__ArrayDisplay_ToolTipOff

Func __ArrayDisplay_Share(Const ByRef $aArray, $sTitle = Default, $sArrayRange = Default, $iFlags = Default, $vUser_Separator = Default, $sHeader = Default, $iDesired_Colwidth = Default, $hUser_Function = Default, $bDebug = True, Const $_iScriptLineNumber = @ScriptLineNumber, Const $_iCallerError = @error, Const $_iCallerExtended = @extended)
    Local $hRetTimer = TimerInit(), $sMsgBoxTitle = (($bDebug) ? ("_DebugArrayDisplay") : ("_ArrayDisplay"))

    ; to avoid user_function using _DebugAArrayDislay() recursion
    If $_g_ArrayDisplay_bUserFunc Then
        $hUser_Function = Default
        $bDebug = False
    EndIf
    If Not IsKeyword($hUser_Function) = $KEYWORD_DEFAULT Then
        $_g_ArrayDisplay_bUserFunc = True
    EndIf

    ; Default values
    If $sTitle = Default Then $sTitle = $sMsgBoxTitle
    If $sArrayRange = Default Then $sArrayRange = ""
    If $iFlags = Default Then $iFlags = $__g_ArrayDisplay_Share_iFlags
    If $iFlags = Default Then $iFlags = 0
    If $vUser_Separator = Default Then $vUser_Separator = ""
    If $sHeader = Default Then $sHeader = ""

    Local $iMin_ColWidth = 55
    Local $iMax_ColWidth = 350
;~  If $iDesired_Colwidth = Default Then ; do not change predefined $iMin_ColWidth, $iMax_ColWidth
    If $iDesired_Colwidth > 0 Then $iMax_ColWidth = $iDesired_Colwidth
    If $iDesired_Colwidth < 0 Then $iMin_ColWidth = -$iDesired_Colwidth
    If $iMax_ColWidth = Default Then $iMax_ColWidth = 350
    If $iMax_ColWidth > 4095 Then $iMax_ColWidth = 4095 ; needed as the structure inside the notify handler is declared as Static
    If $hUser_Function = Default Then $hUser_Function = 0

    ; Check for transpose, column align, verbosity and "Row" column visibility
    $_g_ArrayDisplay_iTranspose = BitAND($iFlags, $ARRAYDISPLAY_TRANSPOSE)
    Local $iColAlign = BitAND($iFlags, 6) ; 0 = Left (default); 2 = Right; 4 = Center
    Local $iVerbose = Int(BitAND($iFlags, $ARRAYDISPLAY_VERBOSE))
    $_g_ArrayDisplay_iDisplayRow = Int(BitAND($iFlags, $ARRAYDISPLAY_NOROW) = 0)
    Local $iRightClickClipPut = True
    If BitAND($iFlags, $ARRAYDISPLAY_NoRightClick) = $ARRAYDISPLAY_NoRightClick Then $iRightClickClipPut = False

    ; Set lower button border
    ;Local $iButtonBorder = (($bDebug) ? (40) : (20))

    If IsDeclared("iButtonBorder") = $DECLARED_UNKNOWN Then Local $iButtonBorder
    $iButtonBorder = 40
    If $bDebug Then
        Select
            Case Not BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) And BitAND($iFlags, $ARRAYDISPLAY_NOBUTTONSDISPLAY) ;Allow border to show data label
                $iButtonBorder = 20
            Case BitAND($iFlags, $ARRAYDISPLAY_NOBUTTONSDISPLAY) ;No border required for buttons or label (see above, NODATALABELDISPLAY = True)
                $iButtonBorder = 0
            Case Not BitAND($iFlags, $ARRAYDISPLAY_ONLYCOPYBUTTONS) ;Allow border to show both copy & exit buttons (& data label if required)
                $iButtonBorder = 40
            Case BitAND($iFlags, $ARRAYDISPLAY_ONLYCOPYBUTTONS) And Not BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) ; Allow border to show copy buttons & data label (no exit button required)
                $iButtonBorder = 40
            Case Not BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) ;Allow border to show copy buttons, data label & exit button (NODATALABELDISPLAY = False)
                $iButtonBorder = 40
            Case BitAND($iFlags, $ARRAYDISPLAY_ONLYCOPYBUTTONS) And BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) ;Allow border to show copy buttons (no data label)
                $iButtonBorder = 20
            Case Else
                $iButtonBorder = 40
        EndSelect
    Else
        $iButtonBorder = 20 ;Allow border to show data label as there's no NODATALABELDISPLAY option for _ArrayDisplay()
    EndIf

    #Region Check valid array

    Local $sMsg = "", $iRet = 1
    Local $fTimer = 0
    If IsArray($aArray) Then
        $_g_ArrayDisplay_aArray = $aArray
        $_g_ArrayDisplay_iDims = UBound($_g_ArrayDisplay_aArray, $UBOUND_DIMENSIONS)
        If $_g_ArrayDisplay_iDims = 1 Then $_g_ArrayDisplay_iTranspose = 0
        $_g_ArrayDisplay_nRows = UBound($_g_ArrayDisplay_aArray, $UBOUND_ROWS)
        $_g_ArrayDisplay_nCols = ($_g_ArrayDisplay_iDims = 2) ? UBound($_g_ArrayDisplay_aArray, $UBOUND_COLUMNS) : 1

        ; Split custom header on separator
        Dim $_g_ArrayDisplay_aNumericSort[$_g_ArrayDisplay_nCols]

        ; Dimension checking
        If $_g_ArrayDisplay_iDims > 2 Then
            $sMsg = "Larger than 2D array passed to function"
            $iRet = 2
        EndIf
        If $_iCallerError Then
            If $bDebug Then
                ; Call _DebugReport() if available
                If IsDeclared("__g_sReportCallBack_DebugReport_Debug") Then
                    $sMsg = "@@ Debug( " & $_iScriptLineNumber & ") : @error = " & $_iCallerError & " in " & $sMsgBoxTitle & "( '" & $sTitle & "' )"
                    Execute('$__g_sReportCallBack_DebugReport_Debug("' & $sMsg & '")')
                EndIf
                $iRet = 3
            ElseIf BitAND($iFlags, $ARRAYDISPLAY_CHECKERROR) Then
                $sMsg = "@error = " & $_iCallerError & " when calling the function"
                If $_iScriptLineNumber > 0 Then $sMsg &= " at line " & $_iScriptLineNumber
                $iRet = 3
            EndIf
        EndIf
    Else
        $sMsg = "No array variable passed to function"
    EndIf
    If $sMsg Then
        If $iVerbose And MsgBox($MB_SYSTEMMODAL + $MB_ICONERROR + $MB_YESNO, _
                $sMsgBoxTitle & "() Error: " & $sTitle, $sMsg & @CRLF & @CRLF & "Exit the script?") = $IDYES Then
            Exit
        Else
            Return SetError($iRet, 0, 0)
        EndIf
    EndIf

    #EndRegion Check valid array

    #Region Check array range

    ; Determine copy separator
    Local $iCW_ColWidth = Number($vUser_Separator)

    ; Get current separator character
    Local $sCurr_Separator = Opt("GUIDataSeparatorChar")

    ; Set default user separator if required
    If $vUser_Separator = "" Then $vUser_Separator = $sCurr_Separator

    ; Declare variables
    $_g_ArrayDisplay_iItem_Start = 0
    $_g_ArrayDisplay_iItem_End = $_g_ArrayDisplay_nRows - 1
    $_g_ArrayDisplay_iSubItem_Start = 0
    $_g_ArrayDisplay_iSubItem_End = (($_g_ArrayDisplay_iDims = 2) ? ($_g_ArrayDisplay_nCols - 1) : (0))

    Local $avRangeSplit
    ; Check for range settings
    If $sArrayRange Then
        ; Split into separate dimension sections
        Local $vTmp, $aArray_Range = StringRegExp($sArrayRange & "||", "(?U)(.*)\|", $STR_REGEXPARRAYGLOBALMATCH)
        ; Rows range
        If $aArray_Range[0] Then
            $avRangeSplit = StringSplit($aArray_Range[0], ":")
            If @error Then
                $_g_ArrayDisplay_iItem_End = Number($aArray_Range[0])
            Else
                $_g_ArrayDisplay_iItem_Start = Number($avRangeSplit[1])
                If $avRangeSplit[2] <> "" Then
                    $_g_ArrayDisplay_iItem_End = Number($avRangeSplit[2])
                EndIf
            EndIf
        EndIf
        ; Check row bounds
        If $_g_ArrayDisplay_iItem_Start < 0 Then $_g_ArrayDisplay_iItem_Start = 0
        If $_g_ArrayDisplay_iItem_End >= $_g_ArrayDisplay_nRows Then $_g_ArrayDisplay_iItem_End = $_g_ArrayDisplay_nRows - 1
        If ($_g_ArrayDisplay_iItem_Start > $_g_ArrayDisplay_iItem_End) And ($_g_ArrayDisplay_iItem_End > 0) Then
            $vTmp = $_g_ArrayDisplay_iItem_Start
            $_g_ArrayDisplay_iItem_Start = $_g_ArrayDisplay_iItem_End
            $_g_ArrayDisplay_iItem_End = $vTmp
        EndIf

        ; Columns range
        If $_g_ArrayDisplay_iDims = 2 And $aArray_Range[1] Then
            $avRangeSplit = StringSplit($aArray_Range[1], ":")
            If @error Then
                $_g_ArrayDisplay_iSubItem_End = Number($aArray_Range[1])
            Else
                $_g_ArrayDisplay_iSubItem_Start = Number($avRangeSplit[1])
                If $avRangeSplit[2] <> "" Then
                    $_g_ArrayDisplay_iSubItem_End = Number($avRangeSplit[2])
                EndIf
            EndIf
            ; Check column bounds
            If $_g_ArrayDisplay_iSubItem_Start > $_g_ArrayDisplay_iSubItem_End Then
                $vTmp = $_g_ArrayDisplay_iSubItem_Start
                $_g_ArrayDisplay_iSubItem_Start = $_g_ArrayDisplay_iSubItem_End
                $_g_ArrayDisplay_iSubItem_End = $vTmp
            EndIf
            If $_g_ArrayDisplay_iSubItem_Start < 0 Then $_g_ArrayDisplay_iSubItem_Start = 0
            If $_g_ArrayDisplay_iSubItem_End >= $_g_ArrayDisplay_nCols Then $_g_ArrayDisplay_iSubItem_End = $_g_ArrayDisplay_nCols - 1
        EndIf
    EndIf

    ; Create data display
    Local $sDisplayData = "[" & $_g_ArrayDisplay_nRows & "]"
    If $_g_ArrayDisplay_iDims = 2 Then
        $sDisplayData &= " [" & $_g_ArrayDisplay_nCols & "]"
    EndIf

    ; Create tooltip data
    Local $sTipData = ""
    If $sArrayRange Then
        If $sTipData Then $sTipData &= " - "
        $sTipData &= "Range set " & $sArrayRange
    EndIf
    If $_g_ArrayDisplay_iTranspose Then
        If $sTipData Then $sTipData &= " - "
        $sTipData &= "Transposed"
    EndIf

    If $sArrayRange Or $_g_ArrayDisplay_iTranspose Then $_g_ArrayDisplay_aArray = __ArrayDisplay_CreateSubArray()

    #EndRegion Check array range

    #Region Check custom header

    ; Split custom header on separator
    $_g_ArrayDisplay_asHeader = StringSplit($sHeader, $sCurr_Separator, $STR_NOCOUNT) ; No count element
    If UBound($_g_ArrayDisplay_asHeader) = 0 Then Dim $_g_ArrayDisplay_asHeader[1] = [""]
    $sHeader = "Row"
    Local $iIndex = $_g_ArrayDisplay_iSubItem_Start
    If $_g_ArrayDisplay_iTranspose Then
        ; All default headers
        $sHeader = "Row"
        For $j = 0 To $_g_ArrayDisplay_nCols - 1
            $sHeader &= $sCurr_Separator & $ARRAYDISPLAY_ROWPREFIX & " " & $j + $_g_ArrayDisplay_iSubItem_Start
        Next
    Else
        ; Create custom header with available items
        If $_g_ArrayDisplay_asHeader[0] Then
            ; Set as many as available
            For $iIndex = $_g_ArrayDisplay_iSubItem_Start To $_g_ArrayDisplay_iSubItem_End
                ; Check custom header available
                If $iIndex >= UBound($_g_ArrayDisplay_asHeader) Then ExitLoop
                If StringRight($_g_ArrayDisplay_asHeader[$iIndex], 1) = $ARRAYDISPLAY_NUMERICSORT Then
                    $_g_ArrayDisplay_asHeader[$iIndex] = StringTrimRight($_g_ArrayDisplay_asHeader[$iIndex], 1) ; remove "*" from right
                    $_g_ArrayDisplay_aNumericSort[$iIndex - $_g_ArrayDisplay_iSubItem_Start] = 1 ; 1 (numeric sort) or empty (natural sort)
                EndIf

                $sHeader &= $sCurr_Separator & $_g_ArrayDisplay_asHeader[$iIndex]
            Next
        EndIf
        ; Add default headers to fill to end
        For $j = $iIndex To $_g_ArrayDisplay_iSubItem_End
            $sHeader &= $sCurr_Separator & "Col " & $j
        Next
    EndIf
    ; Remove "Row" header if not needed
    If Not $_g_ArrayDisplay_iDisplayRow Then $sHeader = StringTrimLeft($sHeader, 4)

    #EndRegion Check custom header

    #Region Generate Sort index for columns

    __ArrayDisplay_SortIndexes(0, -1)

    ; compute the time to generate one colum info to to the sorting
    Local $hTimer = TimerInit()
    __ArrayDisplay_SortIndexes(1, 1)
    $fTimer = TimerDiff($hTimer)
    If $fTimer * $_g_ArrayDisplay_nCols < 1000 Then
        ;       __ArrayDisplay_SortIndexes(-1)
        __ArrayDisplay_SortIndexes(2, $_g_ArrayDisplay_nCols)
;~      If $bDebug Then ConsoleWrite("Sorting all indexes = " & TimerDiff($hTimer) & @CRLF & @CRLF)
    Else
;~      If $bDebug Then ConsoleWrite("Sorting one index = " & TimerDiff($hTimer) & @CRLF)
    EndIf

    #EndRegion Generate Sort index for columns

    #Region GUI and Listview generation

    ; Display splash dialog if required
    If $iVerbose And ($_g_ArrayDisplay_nRows * $_g_ArrayDisplay_nCols) > 1000 Then
        SplashTextOn($sMsgBoxTitle, "Preparing display" & @CRLF & @CRLF & "Please be patient", 300, 100)
    EndIf

    ; GUI Constants
    Local Const $_ARRAYCONSTANT_GUI_DOCKBOTTOM = 64
    Local Const $_ARRAYCONSTANT_GUI_DOCKBORDERS = 102
    Local Const $_ARRAYCONSTANT_GUI_DOCKHEIGHT = 512
    Local Const $_ARRAYCONSTANT_GUI_DOCKLEFT = 2
    Local Const $_ARRAYCONSTANT_GUI_DOCKRIGHT = 4
    Local Const $_ARRAYCONSTANT_GUI_DOCKHCENTER = 8
    Local Const $_ARRAYCONSTANT_GUI_EVENT_CLOSE = -3
    Local Const $_ARRAYCONSTANT_GUI_EVENT_ARRAY = 1
    Local Const $_ARRAYCONSTANT_GUI_FOCUS = 256
    Local Const $_ARRAYCONSTANT_SS_CENTER = 0x1
    Local Const $_ARRAYCONSTANT_SS_CENTERIMAGE = 0x0200
    Local Const $_ARRAYCONSTANT_LVM_GETITEMRECT = (0x1000 + 14)
    Local Const $_ARRAYCONSTANT_LVM_GETITEMSTATE = (0x1000 + 44)
    Local Const $_ARRAYCONSTANT_LVM_GETSELECTEDCOUNT = (0x1000 + 50)
    Local Const $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE = (0x1000 + 54)
    Local Const $_ARRAYCONSTANT_LVS_EX_GRIDLINES = 0x1
    Local Const $_ARRAYCONSTANT_LVIS_SELECTED = 0x0002
    Local Const $_ARRAYCONSTANT_LVS_SHOWSELALWAYS = 0x8
    Local Const $_ARRAYCONSTANT_LVS_OWNERDATA = 0x1000
    Local Const $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT = 0x20
    Local Const $_ARRAYCONSTANT_LVS_EX_DOUBLEBUFFER = 0x00010000 ; Paints via double-buffering, which reduces flicker
    Local Const $_ARRAYCONSTANT_WS_EX_CLIENTEDGE = 0x0200
    Local Const $_ARRAYCONSTANT_WS_MAXIMIZEBOX = 0x00010000
    Local Const $_ARRAYCONSTANT_WS_MINIMIZEBOX = 0x00020000
    Local Const $_ARRAYCONSTANT_WS_SIZEBOX = 0x00040000

    ; Set coord mode 1
    Local $iCoordMode = Opt("GUICoordMode", 1)

    ; Create GUI
    Local $iOrgWidth = 210, $iHeight = 200, $iMinSize = 250
    Local $hGUI = GUICreate($sTitle, $iOrgWidth, $iHeight, Default, Default, BitOR($_ARRAYCONSTANT_WS_SIZEBOX, $_ARRAYCONSTANT_WS_MINIMIZEBOX, $_ARRAYCONSTANT_WS_MAXIMIZEBOX))
    Local $aiGUISize = WinGetClientSize($hGUI)
    ; Create ListView
    Local $idListView = GUICtrlCreateListView($sHeader, 0, 0, $aiGUISize[0], $aiGUISize[1] - $iButtonBorder, BitOR($_ARRAYCONSTANT_LVS_SHOWSELALWAYS, $_ARRAYCONSTANT_LVS_OWNERDATA))
    $_g_ArrayDisplay_hListView = GUICtrlGetHandle($idListView)
    GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_LVS_EX_GRIDLINES, $_ARRAYCONSTANT_LVS_EX_GRIDLINES)
    GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT, $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT)
    GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_LVS_EX_DOUBLEBUFFER, $_ARRAYCONSTANT_LVS_EX_DOUBLEBUFFER)
    GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_WS_EX_CLIENTEDGE, $_ARRAYCONSTANT_WS_EX_CLIENTEDGE)
    Local $hHeader = HWnd(GUICtrlSendMsg($idListView, (0x1000 + 31), 0, 0)) ; $LVM_GETHEADER _GUICtrlListView_GetHeader($idListView)
    ; Set resizing
    GUICtrlSetResizing($idListView, $_ARRAYCONSTANT_GUI_DOCKBORDERS)

    ; Fill listview
    Local $iColFill = $_g_ArrayDisplay_nCols + $_g_ArrayDisplay_iDisplayRow
    ; Align columns if required - $iColAlign = 2 for Right and 4 for Center
    If $iColAlign Then
        ; Loop through columns
        For $i = 0 To $iColFill - 1
            __ArrayDisplay_JustifyColumn($idListView, $i, $iColAlign / 2)
        Next
    EndIf

    GUICtrlSendMsg($idListView, (0x1000 + 47), $_g_ArrayDisplay_nRows, 0) ; $LVM_SETITEMCOUNT

    ; Get row height
    Local $tRECT = DllStructCreate("struct; long Left;long Top;long Right;long Bottom; endstruct") ; $tagRECT
    DllCall("user32.dll", "struct*", "SendMessageW", "hwnd", $_g_ArrayDisplay_hListView, "uint", $_ARRAYCONSTANT_LVM_GETITEMRECT, "wparam", 0, "struct*", $tRECT)
    ; Set required GUI height
    Local $aiWin_Pos = WinGetPos($hGUI)
    Local $aiLV_Pos = ControlGetPos($hGUI, "", $idListView)
    $iHeight = (($_g_ArrayDisplay_nRows + 3) * (DllStructGetData($tRECT, "Bottom") - DllStructGetData($tRECT, "Top"))) + $aiWin_Pos[3] - $aiLV_Pos[3]
    ; Check min/max height
    If $iHeight > @DesktopHeight - 100 Then
        $iHeight = @DesktopHeight - 100
    ElseIf $iHeight < $iMinSize Then
        $iHeight = $iMinSize
    EndIf

    If $iVerbose Then SplashOff()

    ; Sorting information
    $_g_ArrayDisplay_iSortDir = 0x00000400 ; $HDF_SORTUP
    Local $iColumn = 0, $iColumnPrev = -1
    If $_g_ArrayDisplay_iDisplayRow Then
        $iColumnPrev = $iColumn
        __ArrayDisplay_HeaderSetItemFormat($hHeader, $iColumn, 0x00004000 + $_g_ArrayDisplay_iSortDir + $iColAlign / 2) ; $HDF_STRING
    EndIf
    $_g_ArrayDisplay_aIndex = $_g_ArrayDisplay_aIndexes[0]

    #EndRegion GUI and Listview generation

    ; Register WM_NOTIFY message handler through subclassing
    Local $p__ArrayDisplay_NotifyHandler = DllCallbackGetPtr(DllCallbackRegister("__ArrayDisplay_NotifyHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr"))
    DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $hGUI, "ptr", $p__ArrayDisplay_NotifyHandler, "uint_ptr", 0, "dword_ptr", 0)   ; $iSubclassId = 0, $pData = 0

    #Region Adjust dialog width

    Local $iWidth = 40, $iColWidth = 0, $aiColWidth[$iColFill]
    ; Get required column widths to fit items
    Local $iColWidthHeader, $iMin_ColW = 55
    For $i = 0 To $iColFill - 1
        If $i > 0 Then $iMin_ColW = $iMin_ColWidth ; to be use only for #col > 0
        GUICtrlSendMsg($idListView, (0x1000 + 30), $i, -1)                            ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE
        $iColWidth = GUICtrlSendMsg($idListView, (0x1000 + 29), $i, 0)                    ; $LVM_GETCOLUMNWIDTH
        ; Check width of header if set
        If $sHeader <> "" Then
            If $iColWidth = 0 Then ExitLoop
            GUICtrlSendMsg($idListView, (0x1000 + 30), $i, -2)                            ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE_USEHEADER
            $iColWidthHeader = GUICtrlSendMsg($idListView, (0x1000 + 29), $i, 0)              ; $GETCOLUMNWIDTH
            ; Set minimum if required
            If $iColWidth < $iMin_ColW And $iColWidthHeader < $iMin_ColW Then
                GUICtrlSendMsg($idListView, (0x1000 + 30), $i, $iMin_ColW)                ; $LVM_SETCOLUMNWIDTH
                $iColWidth = $iMin_ColW
            ElseIf $iColWidthHeader < $iColWidth Then
                GUICtrlSendMsg($idListView, (0x1000 + 30), $i, $iColWidth)                    ; $LVM_SETCOLUMNWIDTH
            Else
                $iColWidth = $iColWidthHeader
            EndIf
        Else
            ; Set minimum if required
            If $iColWidth < $iMin_ColW Then
                GUICtrlSendMsg($idListView, (0x1000 + 30), $i, $iMin_ColW)                ; $LVM_SETCOLUMNWIDTH
                $iColWidth = $iMin_ColW
            EndIf
        EndIf
        ; Add to total width
        $iWidth += $iColWidth
        ; Store  value
        $aiColWidth[$i] = $iColWidth
    Next
    ; Now check max size
    If $iWidth > @DesktopWidth - 100 Then
        ; Apply max col width limit to reduce width
        $iWidth = 40
        For $i = 0 To $iColFill - 1
            If $aiColWidth[$i] > $iMax_ColWidth Then
                ; Reset width
                GUICtrlSendMsg($idListView, (0x1000 + 30), $i, $iMax_ColWidth)        ; $LVM_SETCOLUMNWIDTH
                $iWidth += $iMax_ColWidth
            Else
                ; Retain width
                $iWidth += $aiColWidth[$i]
            EndIf
            If $i < 20 And $bDebug Then ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iWidth = ' & $iWidth & " $i = " & $i & @CRLF)                      ;### Debug Console
        Next
    EndIf

    ; Check max/min width
    If $iWidth > @DesktopWidth - 100 Then
        $iWidth = @DesktopWidth - 100
    ElseIf $iWidth < $iMinSize Then
        $iWidth = $iMinSize
    EndIf

    #EndRegion Adjust dialog width

    ; Allow for borders with vertical scrollbar
    Local $iScrollBarSize = 0
    If $iHeight = (@DesktopHeight - 100) Then $iScrollBarSize = 15

    ; Resize dialog
    WinMove($hGUI, "", (@DesktopWidth - $iWidth + $iScrollBarSize) / 2, (@DesktopHeight - $iHeight) / 2, $iWidth + $iScrollBarSize, $iHeight)

    ; Resize ListView
    $aiGUISize = WinGetClientSize($hGUI)
    GUICtrlSetPos($idListView, 0, 0, $iWidth, $aiGUISize[1] - $iButtonBorder)

    #Region Create bottom infos

    Local $iButtonWidth_1 = $aiGUISize[0] / 2
    Local $iButtonWidth_2 = $aiGUISize[0] / 3
    Local $idCopy_ID = 9999, $idCopy_Data = 99999, $idData_Label = 99999, $idUser_Func = 99999, $idExit_Script = 99999
    If $bDebug Then
        ; Create buttons
        $idCopy_ID = GUICtrlCreateButton("Copy Data && Hdr/Row", 0, $aiGUISize[1] - $iButtonBorder, $iButtonWidth_1, 20)
        $idCopy_Data = GUICtrlCreateButton("Copy Data Only", $iButtonWidth_1, $aiGUISize[1] - $iButtonBorder, $iButtonWidth_1, 20)
        ; Check if other buttons are required
        If Not BitAND($iFlags, $ARRAYDISPLAY_ONLYCOPYBUTTONS) And Not BitAND($iFlags, $ARRAYDISPLAY_NOBUTTONSDISPLAY) Then
            Local $iButtonWidth_Var = $iButtonWidth_1
            Local $iOffset = $iButtonWidth_1
            If IsFunc($hUser_Function) Then
                ; Create UserFunc button if function passed
                $idUser_Func = GUICtrlCreateButton("Run User Func", $iButtonWidth_2, $aiGUISize[1] - 20, $iButtonWidth_2, 20)
                $iButtonWidth_Var = $iButtonWidth_2
                $iOffset = $iButtonWidth_2 * 2
            EndIf
            ; Create Exit button and data label
            $idExit_Script = GUICtrlCreateButton("Exit", $iOffset, $aiGUISize[1] - 20, $iButtonWidth_Var, 20)
            ;$idData_Label = GUICtrlCreateLabel($sDisplayData, 0, $aiGUISize[1] - 20, $iButtonWidth_Var, 18, BitOR($_ARRAYCONSTANT_SS_CENTER, $_ARRAYCONSTANT_SS_CENTERIMAGE))
            If Not BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) Then $idData_Label = GUICtrlCreateLabel($sDisplayData, 0, $aiGUISize[1] - 20, $iButtonWidth_Var, 18, BitOR($_ARRAYCONSTANT_SS_CENTER, $_ARRAYCONSTANT_SS_CENTERIMAGE))
        Else
            If Not BitAND($iFlags, $ARRAYDISPLAY_NODATALABELDISPLAY) Then $idData_Label = GUICtrlCreateLabel($sDisplayData, 0, $aiGUISize[1] - 20, $aiGUISize[0], 18, BitOR($_ARRAYCONSTANT_SS_CENTER, $_ARRAYCONSTANT_SS_CENTERIMAGE))
        EndIf
    Else
        $idData_Label = GUICtrlCreateLabel($sDisplayData, 0, $aiGUISize[1] - 20, $aiGUISize[0], 18, BitOR($_ARRAYCONSTANT_SS_CENTER, $_ARRAYCONSTANT_SS_CENTERIMAGE))
    EndIf
    ; Change label colour and create tooltip if required
    If $_g_ArrayDisplay_iTranspose Or $sArrayRange Then
        GUICtrlSetColor($idData_Label, 0xFF0000)
        GUICtrlSetTip($idData_Label, $sTipData)
    EndIf
    GUICtrlSetResizing($idCopy_ID, $_ARRAYCONSTANT_GUI_DOCKLEFT + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)
    GUICtrlSetResizing($idCopy_Data, $_ARRAYCONSTANT_GUI_DOCKRIGHT + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)
    GUICtrlSetResizing($idData_Label, $_ARRAYCONSTANT_GUI_DOCKLEFT + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)
    GUICtrlSetResizing($idUser_Func, $_ARRAYCONSTANT_GUI_DOCKHCENTER + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)
    GUICtrlSetResizing($idExit_Script, $_ARRAYCONSTANT_GUI_DOCKRIGHT + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)

    #EndRegion Create bottom infos

    ; Display dialog
    GUISetState(@SW_SHOW, $hGUI)

    ; Check if sort clicking can take a while
    If $fTimer > 1000 And Not $sArrayRange Then
        Beep(750, 250)
        ToolTip("Sorting Action can take as long as " & Ceiling($fTimer / 1000) & " sec" & @CRLF & @CRLF & "Please be patient when you click to sort a column", 50, 50, $sMsgBoxTitle, $TIP_WARNINGICON, $TIP_BALLOON)
        Sleep(3000)
        ToolTip("")
    EndIf

    #Region GUI Handling events

    ; Switch to GetMessage mode
    Local $iOnEventMode = Opt("GUIOnEventMode", 0), $aMsg
    ConsoleWrite("__ArrayDisplay_Share() loadded in: " & TimerDiff($hRetTimer) & @CRLF)

    While 1

        $aMsg = GUIGetMsg($_ARRAYCONSTANT_GUI_EVENT_ARRAY) ; Variable needed to check which "Copy" button was pressed
        If $__g_ArrayDisplay_Timeout_msReturn Then
            If TimerDiff($hRetTimer) > $__g_ArrayDisplay_Timeout_msReturn Then ExitLoop
        EndIf
        If $__g_ArrayDisplay_Timeout_msExit Then
            If TimerDiff($hRetTimer) > $__g_ArrayDisplay_Timeout_msExit Then
                GUIDelete($hGUI)
                Exit $__g_ArrayDisplay_Timeout_ecExit
            EndIf
        EndIf

        If $aMsg[1] = $hGUI Then
            Switch $aMsg[0]
                Case $GUI_EVENT_MINIMIZE
                    If $__g_ArrayDisplay_Timeout_msReturn Or $__g_ArrayDisplay_Timeout_msExit Then
                        $__g_ArrayDisplay_Timeout_msReturn = 0
                        $__g_ArrayDisplay_Timeout_msExit = 0
                        WinSetTitle($hGUI, "", '(#) ' & $sTitle)
                    EndIf

                Case $_ARRAYCONSTANT_GUI_EVENT_CLOSE
                    ExitLoop

                Case $GUI_EVENT_SECONDARYUP
                    If $iRightClickClipPut Then __ArrayDisplay_SubItemHitTest_ClipPut($idListView)

                Case $idCopy_ID, $idCopy_Data
                    ; Count selected rows
                    Local $iSel_Count = GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_GETSELECTEDCOUNT, 0, 0)
                    ; Display splash dialog if required
                    If $iVerbose And (Not $iSel_Count) And ($_g_ArrayDisplay_iItem_End - $_g_ArrayDisplay_iItem_Start) * ($_g_ArrayDisplay_iSubItem_End - $_g_ArrayDisplay_iSubItem_Start) > 10000 Then
                        SplashTextOn($sMsgBoxTitle, "Copying data" & @CRLF & @CRLF & "Please be patient", 300, 100)
                    EndIf
                    ; Generate clipboard text
                    Local $sClip = "", $sItem, $aSplit, $iFirstCol = 0
                    If $aMsg[0] = $idCopy_Data And $_g_ArrayDisplay_iDisplayRow Then $iFirstCol = 1
                    ; Add items
                    For $i = 0 To GUICtrlSendMsg($idListView, 0X1004, 0, 0) - 1 ; $LVM_GETITEMCOUNT
                        ; Skip if copying selected rows and item not selected
                        If $iSel_Count And Not (GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_GETITEMSTATE, $i, $_ARRAYCONSTANT_LVIS_SELECTED) <> 0) Then
                            ContinueLoop
                        EndIf
                        $sItem = __ArrayDisplay_GetItemTextStringSelected($idListView, $i, $iFirstCol)
                        If $aMsg[0] = $idCopy_ID And Not $_g_ArrayDisplay_iDisplayRow Then
                            ; Add row data
                            $sItem = $ARRAYDISPLAY_ROWPREFIX & " " & ($i + $_g_ArrayDisplay_iItem_Start) & $sCurr_Separator & $sItem
                        EndIf
                        If $iCW_ColWidth Then
                            ; Expand columns
                            $aSplit = StringSplit($sItem, $sCurr_Separator)
                            $sItem = ""
                            For $j = 1 To $aSplit[0]
                                $sItem &= StringFormat("%-" & $iCW_ColWidth + 1 & "s", StringLeft($aSplit[$j], $iCW_ColWidth))
                            Next
                        Else
                            ; Use defined separator
                            $sItem = StringReplace($sItem, $sCurr_Separator, $vUser_Separator)
                        EndIf
                        $sClip &= $sItem & @CRLF
                    Next
                    $sItem = $sHeader
                    ; Add header line if required
                    If $aMsg[0] = $idCopy_ID Then
                        $sItem = $sHeader
                        If Not $_g_ArrayDisplay_iDisplayRow Then
                            ; Add "Row" to header
                            $sItem = "Row" & $sCurr_Separator & $sItem
                        EndIf
                        If $iCW_ColWidth Then
                            $aSplit = StringSplit($sItem, $sCurr_Separator)
                            $sItem = ""
                            For $j = 1 To $aSplit[0]
                                $sItem &= StringFormat("%-" & $iCW_ColWidth + 1 & "s", StringLeft($aSplit[$j], $iCW_ColWidth))
                            Next
                        Else
                            $sItem = StringReplace($sItem, $sCurr_Separator, $vUser_Separator)
                        EndIf
                        $sClip = $sItem & @CRLF & $sClip
                    EndIf
                    ;Send to clipboard
                    ClipPut($sClip)
                    ; Remove splash if used
                    SplashOff()
                    ; Refocus ListView
                    GUICtrlSetState($idListView, $_ARRAYCONSTANT_GUI_FOCUS)

                Case $idListView
                    $iColumn = GUICtrlGetState($idListView)
                    If Not IsArray($_g_ArrayDisplay_aIndexes[$iColumn + Not $_g_ArrayDisplay_iDisplayRow]) Then
                        ; in case all indexes have not been set during start creation
                        __ArrayDisplay_SortIndexes($iColumn + Not $_g_ArrayDisplay_iDisplayRow)
                    EndIf

                    If $iColumn <> $iColumnPrev Then
                        __ArrayDisplay_HeaderSetItemFormat($hHeader, $iColumnPrev, 0x00004000 + $iColAlign / 2) ; $HDF_STRING
                        If $_g_ArrayDisplay_iDisplayRow And $iColumn = 0 Then
                            $_g_ArrayDisplay_aIndex = $_g_ArrayDisplay_aIndexes[0]
                        Else
                            $_g_ArrayDisplay_aIndex = $_g_ArrayDisplay_aIndexes[$iColumn + Not $_g_ArrayDisplay_iDisplayRow]
                        EndIf
                    EndIf
                    ; $_g_ArrayDisplay_iSortDir = ($iColumn = $iColumnPrev) ? $_g_ArrayDisplay_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP : $HDF_SORTUP
                    $_g_ArrayDisplay_iSortDir = ($iColumn = $iColumnPrev) ? $_g_ArrayDisplay_iSortDir = 0x00000400 ? 0x00000200 : 0x00000400 : 0x00000400 ; $HDF_SORTUP
                    __ArrayDisplay_HeaderSetItemFormat($hHeader, $iColumn, 0x00004000 + $_g_ArrayDisplay_iSortDir + $iColAlign / 2)  ; $HDF_STRING
                    GUICtrlSendMsg($idListView, (0x1000 + 140), $iColumn, 0) ; $LVM_SETSELECTEDCOLUMN
                    GUICtrlSendMsg($idListView, (0x1000 + 47), $_g_ArrayDisplay_nRows, 0) ; $LVM_SETITEMCOUNT
                    $iColumnPrev = $iColumn

                Case $idUser_Func
                    ; Get selected indices
                    Local $aiSelItems[1] = [0]
                    For $i = 0 To GUICtrlSendMsg($idListView, 0x1004, 0, 0) - 1 ; $LVM_GETITEMCOUNT
                        If (GUICtrlSendMsg($idListView, $_ARRAYCONSTANT_LVM_GETITEMSTATE, $i, $_ARRAYCONSTANT_LVIS_SELECTED) <> 0) Then
                            $aiSelItems[0] += 1
                            ReDim $aiSelItems[$aiSelItems[0] + 1]
                            $aiSelItems[$aiSelItems[0]] = $i + $_g_ArrayDisplay_iItem_Start
                        EndIf
                    Next

                    ; Pass array and selection to user function
                    $hUser_Function($_g_ArrayDisplay_aArray, $aiSelItems)
                    $_g_ArrayDisplay_bUserFunc = False

                    __ArrayDisplay_CleanUp($hGUI, $iCoordMode, $iOnEventMode, $_iCallerError, $_iCallerExtended, $p__ArrayDisplay_NotifyHandler)
                    ;;__ArrayDisplay_Share($aArray, $sTitle, $sArrayRange, $iFlags, $vUser_Separator, $sHeader, $iMax_ColWidth, $hUser_Function, $bDebug, $_iScriptLineNumber, $_iCallerError, $_iCallerExtended)
                    Return SetError($_iCallerError, $_iCallerExtended, -1)

                Case $idExit_Script
                    ; Clear up
                    GUIDelete($hGUI)
                    Exit
            EndSwitch
        EndIf
    WEnd

    #EndRegion GUI Handling events

    __ArrayDisplay_CleanUp($hGUI, $iCoordMode, $iOnEventMode, $_iCallerError, $_iCallerExtended, $p__ArrayDisplay_NotifyHandler)

    Return SetError($_iCallerError, $_iCallerExtended, 1)
EndFunc   ;==>__ArrayDisplay_Share

Func __ArrayDisplay_CleanUp($hGUI, $iCoordMode, $iOnEventMode, $_iCallerError, $_iCallerExtended, $p__ArrayDisplay_NotifyHandler)
    ; Cleanup
    DllCall("comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", $hGUI, "ptr", $p__ArrayDisplay_NotifyHandler, "uint_ptr", 0)   ; $iSubclassId = 0

    ; Release resources in case of big array used
    $_g_ArrayDisplay_aIndex = 0
    Dim $_g_ArrayDisplay_aIndexes[1]

    GUIDelete($hGUI)
    Opt("GUICoordMode", $iCoordMode) ; Reset original Coord mode
    Opt("GUIOnEventMode", $iOnEventMode) ; Reset original GUI mode

    Return SetError($_iCallerError, $_iCallerExtended, 1)
EndFunc   ;==>__ArrayDisplay_CleanUp

; #ADDITIONAL Functions to speed up _ArrayDisplay() or _DebugArrayDisplay()# ====================================================
; Thanks Larsj

Func __ArrayDisplay_NotifyHandler($hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData)
    If $iMsg <> 0x004E Then Return DllCall("comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam)[0]   ; 0x004E = $WM_NOTIFY

    Local Static $tagNMHDR = "struct;hwnd hWndFrom;uint_ptr IDFrom;INT Code;endstruct"
    Local Static $tagNMLVDISPINFO = $tagNMHDR & ";" & $_ARRAYCONSTANT_tagLVITEM

    Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)
    Switch HWnd(DllStructGetData($tNMLVDISPINFO, "hWndFrom"))
        Case $_g_ArrayDisplay_hListView
            Switch DllStructGetData($tNMLVDISPINFO, "Code")
                Case -177 ; $LVN_GETDISPINFOW
                    Local Static $tText = DllStructCreate("wchar[4096]"), $pText = DllStructGetPtr($tText)
                    Local $iItem = DllStructGetData($tNMLVDISPINFO, "Item")
                    Local $iRow = ($_g_ArrayDisplay_iSortDir = 0x00000400) ? $_g_ArrayDisplay_aIndex[$iItem] : $_g_ArrayDisplay_aIndex[$_g_ArrayDisplay_nRows - 1 - $iItem]
                    Local $iCol = DllStructGetData($tNMLVDISPINFO, "SubItem")

;~                  ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iRow = ' & $iRow & '  $iCol= ' & $iCol & '  $iItem = ' & $iItem & @CRLF) ;### Debug Console

                    Local $sTemp
                    If $_g_ArrayDisplay_iDisplayRow = 0 Then
                        $sTemp = __ArrayDisplay_GetData($iRow, $iCol)
                        DllStructSetData($tText, 1, $sTemp)
                        DllStructSetData($tNMLVDISPINFO, "Text", $pText)
                    Else
                        If $iCol = 0 Then
                            If $_g_ArrayDisplay_iTranspose Then
                                Local $sCaptionCplt = ""
                                If $iRow + $_g_ArrayDisplay_iItem_Start < UBound($_g_ArrayDisplay_asHeader) _
                                        And StringStripWS($_g_ArrayDisplay_asHeader[$iRow + $_g_ArrayDisplay_iItem_Start], 1 + 2) <> "" Then
                                    $sCaptionCplt = " (" & StringStripWS($_g_ArrayDisplay_asHeader[$iRow + $_g_ArrayDisplay_iItem_Start], 1 + 2)
                                    If StringRight($sCaptionCplt, 1) = $ARRAYDISPLAY_NUMERICSORT Then $sCaptionCplt = StringTrimRight($sCaptionCplt, 1)
                                    $sCaptionCplt &= ")"
                                EndIf
                                DllStructSetData($tText, 1, "Col " & ($iRow + $_g_ArrayDisplay_iItem_Start) & $sCaptionCplt)
                            Else
                                DllStructSetData($tText, 1, $ARRAYDISPLAY_ROWPREFIX & " " & $iRow + $_g_ArrayDisplay_iItem_Start)
                            EndIf
                            DllStructSetData($tNMLVDISPINFO, "Text", $pText)
                        Else
                            $sTemp = __ArrayDisplay_GetData($iRow, $iCol - 1)
                            DllStructSetData($tText, 1, $sTemp)
                            DllStructSetData($tNMLVDISPINFO, "Text", $pText)
                        EndIf
                    EndIf
                    Return

            EndSwitch
    EndSwitch

    Return DllCall("comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam)[0]
    #forceref $iSubclassId, $pData
EndFunc   ;==>__ArrayDisplay_NotifyHandler

Func __ArrayDisplay_GetData($iRow, $iCol)
    Local $sTemp
    If $_g_ArrayDisplay_iDims = 2 Then
        $sTemp = $_g_ArrayDisplay_aArray[$iRow][$iCol]
    Else
        $sTemp = $_g_ArrayDisplay_aArray[$iRow]
    EndIf
    Switch VarGetType($sTemp)
        Case "Array"
            Local $sSubscript = ""
            For $i = 1 To UBound($sTemp, 0)
                $sSubscript = "[" & UBound($sTemp, $i) & "]"
            Next

            $sTemp = "{Array" & $sSubscript & "}"
        Case "Map"
            $sTemp = "{Map[" & UBound($sTemp) & "]}"
        Case "Object"
            $sTemp = "{Object}"
    EndSwitch
    If StringLen($sTemp) > 4095 Then $sTemp = StringLeft($sTemp, 4095)

    Return $sTemp
EndFunc   ;==>__ArrayDisplay_GetData

Func __ArrayDisplay_SortIndexes($iColStart, $iColEnd = $iColStart)
    Dim $_g_ArrayDisplay_aIndex[$_g_ArrayDisplay_nRows]
;~  Local $hTimer
    If $iColEnd = -1 Then
        ; column (0) already sorted
        Dim $_g_ArrayDisplay_aIndexes[$_g_ArrayDisplay_nCols + $_g_ArrayDisplay_iDisplayRow + 1]
;~      $hTimer = TimerInit()

        For $i = 0 To $_g_ArrayDisplay_nRows - 1
            $_g_ArrayDisplay_aIndex[$i] = $i
        Next

        $_g_ArrayDisplay_aIndexes[0] = $_g_ArrayDisplay_aIndex
;~      ConsoleWrite("Sorting array col#0 = " & TimerDiff($hTimer) & @CRLF)
    EndIf

    If $iColStart = -1 Then
        ; to index all columns
        $iColStart = 1
        $iColEnd = $_g_ArrayDisplay_nCols
    EndIf

    If $iColStart Then
        ; Index aArray columns
        Local $tIndex
        For $i = $iColStart To $iColEnd
;~          $hTimer = TimerInit()
            $tIndex = __ArrayDisplay_GetSortColStruct($_g_ArrayDisplay_aArray, $i - 1)

            For $j = 0 To $_g_ArrayDisplay_nRows - 1
                $_g_ArrayDisplay_aIndex[$j] = DllStructGetData($tIndex, 1, $j + 1)
            Next

            $_g_ArrayDisplay_aIndexes[$i] = $_g_ArrayDisplay_aIndex
;~          If $i < 20 Then ConsoleWrite("Sorting array col#" & $i & " = " & TimerDiff($hTimer) & @CRLF)
        Next
    EndIf

EndFunc   ;==>__ArrayDisplay_SortIndexes

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __ArrayDisplay_GetSortColStruct
; Description ...: Index based sorting of a 2D array by one or more columns
; Syntax.........: __ArrayDisplay_GetSortColStruct( $aArray, $iCol )
; Parameters ....: $aArray The 2D array to be sorted by index
;                   $iCol Index column used in sorting
; Return values .: the sorting index as a DllStruct of integers
; Author ........: Larj : FAS_Sort2DArrayAu3()
; Modified.......: jpm : extension to  1D Array
; Remarks .......:
; ===============================================================================================================================
Func __ArrayDisplay_GetSortColStruct(Const ByRef $aArray, $iCol)

    If UBound($aArray, $UBOUND_DIMENSIONS) < 1 Or UBound($aArray, $UBOUND_DIMENSIONS) > 2 Then
;~      ConsoleWrite("$aArray is not a 1D or 2D array variable" & @CRLF)
        Return SetError(6, 0, 0)
    EndIf

    Return __ArrayDisplay_SortArrayStruct($aArray, $iCol)
EndFunc   ;==>__ArrayDisplay_GetSortColStruct

Func __ArrayDisplay_SortArrayStruct(Const ByRef $aArray, $iCol)
    Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS)
    Local $tIndex = DllStructCreate("uint[" & $_g_ArrayDisplay_nRows & "]")
    Local $pIndex = DllStructGetPtr($tIndex)
    Static $hDll = DllOpen("kernel32.dll")
    Static $hDllComp = DllOpen("shlwapi.dll")

    Local $lo, $hi, $mi, $r, $nVal1, $nVal2

    ; Sorting by one column
    For $i = 1 To $_g_ArrayDisplay_nRows - 1
        $lo = 0
        $hi = $i - 1
        Do
            $mi = Int(($lo + $hi) / 2)
            If Not $_g_ArrayDisplay_iTranspose And $_g_ArrayDisplay_aNumericSort[$iCol] Then ; Numeric sort
                If $iDims = 1 Then
                    $nVal1 = Number($aArray[$i])
                    $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1)])
                Else
                    $nVal1 = Number($aArray[$i][$iCol])
                    $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])
                EndIf
                $r = $nVal1 < $nVal2 ? -1 : $nVal1 > $nVal2 ? 1 : 0
            Else ; Natural sort
                If $iDims = 1 Then
                    $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i]), 'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1)]))[0]
                Else
                    $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i][$iCol]), 'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol]))[0]
                EndIf
            EndIf
            Switch $r
                Case -1
                    $hi = $mi - 1
                Case 1
                    $lo = $mi + 1
                Case 0
                    ExitLoop
            EndSwitch
        Until $lo > $hi
        DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4)
        DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1))
    Next

    Return $tIndex
EndFunc   ;==>__ArrayDisplay_SortArrayStruct

Func __ArrayDisplay_CreateSubArray()
    ; the returned subarray is transposed
    Local $nRows = $_g_ArrayDisplay_iItem_End - $_g_ArrayDisplay_iItem_Start + 1
    Local $nCols = $_g_ArrayDisplay_iSubItem_End - $_g_ArrayDisplay_iSubItem_Start + 1

    Local $iRow = -1, $iCol, $iTemp, $aTemp
    If $_g_ArrayDisplay_iTranspose Then
        Dim $aTemp[$nCols][$nRows]
        For $i = $_g_ArrayDisplay_iItem_Start To $_g_ArrayDisplay_iItem_End
            $iRow += 1
            $iCol = -1
            For $j = $_g_ArrayDisplay_iSubItem_Start To $_g_ArrayDisplay_iSubItem_End
                $iCol += 1
                $aTemp[$iCol][$iRow] = $_g_ArrayDisplay_aArray[$i][$j]
            Next
        Next

        $iTemp = $_g_ArrayDisplay_iItem_Start
        $_g_ArrayDisplay_iItem_Start = $_g_ArrayDisplay_iSubItem_Start
        $_g_ArrayDisplay_iSubItem_Start = $iTemp

        $iTemp = $_g_ArrayDisplay_iItem_End
        $_g_ArrayDisplay_iItem_End = $_g_ArrayDisplay_iSubItem_End
        $_g_ArrayDisplay_iSubItem_End = $iTemp

        $_g_ArrayDisplay_nRows = $nCols
        $_g_ArrayDisplay_nCols = $nRows
    Else
        If $_g_ArrayDisplay_iDims = 1 Then
            Dim $aTemp[$nRows]
            For $i = $_g_ArrayDisplay_iItem_Start To $_g_ArrayDisplay_iItem_End
                $iRow += 1
                $aTemp[$iRow] = $_g_ArrayDisplay_aArray[$i]
            Next
        Else
            Dim $aTemp[$nRows][$nCols]
            For $i = $_g_ArrayDisplay_iItem_Start To $_g_ArrayDisplay_iItem_End
                $iRow += 1
                $iCol = -1
                For $j = $_g_ArrayDisplay_iSubItem_Start To $_g_ArrayDisplay_iSubItem_End
                    $iCol += 1
                    $aTemp[$iRow][$iCol] = $_g_ArrayDisplay_aArray[$i][$j]
                Next
            Next

            $_g_ArrayDisplay_nCols = $nCols
        EndIf

        $_g_ArrayDisplay_nRows = $nRows
    EndIf

;~  _DebugArrayDisplay($aTemp, "Subarray")
    Return $aTemp
EndFunc   ;==>__ArrayDisplay_CreateSubArray

; #DUPLICATED Functions to avoid big #include "GuiHeader.au3"# ==================================================================
; Functions have been simplified (unicode inprocess) according to __ArrayDisplay_Share() needs

Func __ArrayDisplay_HeaderSetItemFormat($hWnd, $iIndex, $iFormat)
    Local Static $tHDItem = DllStructCreate("uint Mask;int XY;ptr Text;handle hBMP;int TextMax;int Fmt;lparam Param;int Image;int Order;uint Type;ptr pFilter;uint State") ; $tagHDITEM
    DllStructSetData($tHDItem, "Mask", 0x00000004) ; $HDI_FORMAT
    DllStructSetData($tHDItem, "Fmt", $iFormat)
    Local $aResult = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", 0x120C, "wparam", $iIndex, "struct*", $tHDItem) ; $HDM_SETITEMW
    Return $aResult[0] <> 0
EndFunc   ;==>__ArrayDisplay_HeaderSetItemFormat

; #DUPLICATED Functions to avoid big #include "GuiListView.au3"# ================================================================
; Functions have been simplified (unicode inprocess) according to __ArrayDisplay_Share() needs

Func __ArrayDisplay_GetItemText($idListView, $iIndex, $iSubItem = 0)
    Local $tBuffer = DllStructCreate("wchar Text[4096]")
    Local $pBuffer = DllStructGetPtr($tBuffer)
    Local $tItem = DllStructCreate($_ARRAYCONSTANT_tagLVITEM)
    DllStructSetData($tItem, "SubItem", $iSubItem)
    DllStructSetData($tItem, "TextMax", 4096)
    DllStructSetData($tItem, "Text", $pBuffer)
    ;Global Const $LVM_GETITEMTEXTW = (0x1000 + 115) ; 0X1073
    If IsHWnd($idListView) Then
        DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $idListView, "uint", 0x1073, "wparam", $iIndex, "struct*", $tItem)
    Else
        Local $pItem = DllStructGetPtr($tItem)
        GUICtrlSendMsg($idListView, 0x1073, $iIndex, $pItem)
    EndIf

    Return DllStructGetData($tBuffer, "Text")
EndFunc   ;==>__ArrayDisplay_GetItemText

Func __ArrayDisplay_GetItemTextStringSelected($idListView, $iItem, $iFirstCol)
    Local $sRow = "", $sSeparatorChar = Opt('GUIDataSeparatorChar')
    Local $iSelected = $iItem ; get row

    ; GetColumnCount
    Local $hHeader = HWnd(GUICtrlSendMsg($idListView, 0x101F, 0, 0)) ; $LVM_GETHEADER
    Local $nCol = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hHeader, "uint", 0x1200, "wparam", 0, "lparam", 0)[0] ; $HDM_GETITEMCOUNT

    For $x = $iFirstCol To $nCol - 1
        $sRow &= __ArrayDisplay_GetItemText($idListView, $iSelected, $x) & $sSeparatorChar
    Next

    Return StringTrimRight($sRow, 1)
EndFunc   ;==>__ArrayDisplay_GetItemTextStringSelected

Func __ArrayDisplay_JustifyColumn($idListView, $iIndex, $iAlign = -1)
    ;Local $aAlign[3] = [$LVCFMT_LEFT, $LVCFMT_RIGHT, $LVCFMT_CENTER]

    Local $tColumn = DllStructCreate("uint Mask;int Fmt;int CX;ptr Text;int TextMax;int SubItem;int Image;int Order;int cxMin;int cxDefault;int cxIdeal") ; $tagLVCOLUMN
    If $iAlign < 0 Or $iAlign > 2 Then $iAlign = 0
    DllStructSetData($tColumn, "Mask", 0x01) ; $LVCF_FMT
    DllStructSetData($tColumn, "Fmt", $iAlign)
    Local $pColumn = DllStructGetPtr($tColumn)
    Local $iRet = GUICtrlSendMsg($idListView, 0x1060, $iIndex, $pColumn)  ; $_ARRAYCONSTANT_LVM_SETCOLUMNW
    Return $iRet <> 0
EndFunc   ;==>__ArrayDisplay_JustifyColumn

 

because it'll be easier to see the easily patchable code (TM)  techniques in action. Eventually you'll write cool stuff and I'd like to see that code ( for copy'n'paste ) :) 

and here is an example for the use of these helper functions:

#include <Array.au3>
_DebugArrayDisplay_TimeoutReturn(5000) ; timeout in 5 sec
Global $aArray[2] = [1,2]
_ArrayDisplay($aArray, "You've got 5 sec.")
_DebugArrayDisplay_TimeoutReturn(0) ; reset to default
_ArrayDisplay($aArray, "Wait forever")
ConsoleWrite("..the rest of your code" & @CRLF)

 

Disclaimer: "easily patchable code (TM)" is not a trademark of argumentum. :P

Edit: added the code from my next post to remove the timeout by minimizing the ArrayDisplay.

Edited by argumentum
updated code for the pause feature

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
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
 Share

  • Recently Browsing   0 members

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