Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/10/2018 in all areas

  1. Danp2

    Error question

    Look under the Activity > My Active Streams. You can customize this to get what you want. For example -- https://www.autoitscript.com/forum/discover/content-posted/?&stream_club_select=undefined&stream_club_filter=undefined&stream_ownership=custom&stream_custom_members=caramen&stream_date_type=all You'll need to split this into multiple commands, like this -- $myArray = _StringBetween($Ligne, '[', ']') ; Now check either @error or IsArray() If Not @error Then $Dep = $myArray[0] Endif
    2 points
  2. [New Release] - 06 April 2019 Added: Error-checking for sensible column numbers in the $aSortData array, with an additional error status. ------------------------------------------------------------------------------------------------------------------------ While answering a recent question about sorting a ListView on several columns, I developed this function to sort a 2D array on several columns and I though I might give it a wider audience. Here is the function: #include-once ;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 ; #INCLUDES# ========================================================================================================= #include <Array.au3> ; =============================================================================================================================== ; #INDEX# ======================================================================================================================= ; Title .........: ArrayMultiColSort ; AutoIt Version : v3.3.8.1 or higher ; Language ......: English ; Description ...: Sorts 2D arrays on several columns ; Note ..........: ; Author(s) .....: Melba23 ; Remarks .......: ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _ArrayMultiColSort : Sort 2D arrays on several columns ; =============================================================================================================================== ; #INTERNAL_USE_ONLY#================================================================================================= ; __AMCS_SortChunk : Sorts array section ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _ArrayMultiColSort ; Description ...: Sort 2D arrays on several columns ; Syntax.........: _ArrayMultiColSort(ByRef $aArray, $aSortData[, $iStart = 0[, $iEnd = 0]]) ; Parameters ....: $aArray - The 2D array to be sorted ; $aSortData - 2D array holding details of the sort format ; Format: [Column to be sorted, Sort order] ; Sort order can be either numeric (0/1 = ascending/descending) or a ordered string of items ; Any elements not matched in string are left unsorted after all sorted elements ; $iStart - Element of array at which sort starts (default = 0) ; $iEnd - Element of array at which sort endd (default = 0 - converted to end of array) ; Requirement(s).: v3.3.8.1 or higher ; Return values .: Success: No error ; Failure: @error set as follows ; @error = 1 with @extended set as follows (all refer to $sIn_Date): ; 1 = Array to be sorted not 2D ; 2 = Sort data array not 2D ; 3 = More data rows in $aSortData than columns in $aArray ; 4 = Start beyond end of array ; 5 = Start beyond End ; @error = 2 with @extended set as follows: ; 1 = Invalid string parameter in $aSortData ; 2 = Invalid sort direction parameter in $aSortData ; 3 = Invalid column index in $aSortData ; Author ........: Melba23 ; Remarks .......: Columns can be sorted in any order ; Example .......; Yes ; =============================================================================================================================== Func _ArrayMultiColSort(ByRef $aArray, $aSortData, $iStart = 0, $iEnd = 0) ; Errorchecking ; 2D array to be sorted If UBound($aArray, 2) = 0 Then Return SetError(1, 1, "") EndIf ; 2D sort data If UBound($aSortData, 2) <> 2 Then Return SetError(1, 2, "") EndIf If UBound($aSortData) > UBound($aArray) Then Return SetError(1, 3) EndIf For $i = 0 To UBound($aSortData) - 1 If $aSortData[$i][0] < 0 Or $aSortData[$i][0] > UBound($aArray, 2) -1 Then Return SetError(2, 3, "") EndIf Next ; Start element If $iStart < 0 Then $iStart = 0 EndIf If $iStart >= UBound($aArray) - 1 Then Return SetError(1, 4, "") EndIf ; End element If $iEnd <= 0 Or $iEnd >= UBound($aArray) - 1 Then $iEnd = UBound($aArray) - 1 EndIf ; Sanity check If $iEnd <= $iStart Then Return SetError(1, 5, "") EndIf Local $iCurrCol, $iChunk_Start, $iMatchCol ; Sort first column __AMCS_SortChunk($aArray, $aSortData, 0, $aSortData[0][0], $iStart, $iEnd) If @error Then Return SetError(2, @extended, "") EndIf ; Now sort within other columns For $iSortData_Row = 1 To UBound($aSortData) - 1 ; Determine column to sort $iCurrCol = $aSortData[$iSortData_Row][0] ; Create arrays to hold data from previous columns Local $aBaseValue[$iSortData_Row] ; Set base values For $i = 0 To $iSortData_Row - 1 $aBaseValue[$i] = $aArray[$iStart][$aSortData[$i][0]] Next ; Set start of this chunk $iChunk_Start = $iStart ; Now work down through array For $iRow = $iStart + 1 To $iEnd ; Match each column For $k = 0 To $iSortData_Row - 1 $iMatchCol = $aSortData[$k][0] ; See if value in each has changed If $aArray[$iRow][$iMatchCol] <> $aBaseValue[$k] Then ; If so and row has advanced If $iChunk_Start < $iRow - 1 Then ; Sort this chunk __AMCS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1) If @error Then Return SetError(2, @extended, "") EndIf EndIf ; Set new base value $aBaseValue[$k] = $aArray[$iRow][$iMatchCol] ; Set new chunk start $iChunk_Start = $iRow EndIf Next Next ; Sort final section If $iChunk_Start < $iRow - 1 Then __AMCS_SortChunk($aArray, $aSortData, $iSortData_Row, $iCurrCol, $iChunk_Start, $iRow - 1) If @error Then Return SetError(2, @extended, "") EndIf EndIf Next EndFunc ;==>_ArrayMultiColSort ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __AMCS_SortChunk ; Description ...: Sorts array section ; Author ........: Melba23 ; Remarks .......: ; =============================================================================================================================== Func __AMCS_SortChunk(ByRef $aArray, $aSortData, $iRow, $iColumn, $iChunkStart, $iChunkEnd) Local $aSortOrder ; Set default sort direction Local $iSortDirn = 1 ; Need to prefix elements? If IsString($aSortData[$iRow][1]) Then ; Split elements $aSortOrder = StringSplit($aSortData[$iRow][1], ",") If @error Then Return SetError(1, 1, "") EndIf ; Add prefix to each element For $i = $iChunkStart To $iChunkEnd For $j = 1 To $aSortOrder[0] If $aArray[$i][$iColumn] = $aSortOrder[$j] Then $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn] ExitLoop EndIf Next ; Deal with anything that does not match If $j > $aSortOrder[0] Then $aArray[$i][$iColumn] = StringFormat("%02i-", $j) & $aArray[$i][$iColumn] EndIf Next Else Switch $aSortData[$iRow][1] Case 0, 1 ; Set required sort direction if no list If $aSortData[$iRow][1] Then $iSortDirn = -1 Else $iSortDirn = 1 EndIf Case Else Return SetError(1, 2, "") EndSwitch EndIf ; Sort the chunk Local $iSubMax = UBound($aArray, 2) - 1 __ArrayQuickSort2D($aArray, $iSortDirn, $iChunkStart, $iChunkEnd, $iColumn, $iSubMax) ; Remove any prefixes If IsString($aSortData[$iRow][1]) Then For $i = $iChunkStart To $iChunkEnd $aArray[$i][$iColumn] = StringTrimLeft($aArray[$i][$iColumn], 3) Next EndIf EndFunc ;==>__AMCS_SortChunk And here is an example to show it working: #include "ArrayMultiColSort.au3" #include <String.au3> ; Only used to fill array ; Create and display array Global $aArray[100][4] For $i = 0 To 99 $aArray[$i][0] = _StringRepeat(Chr(Random(65, 68, 1)), 5) $aArray[$i][1] = _StringRepeat(Chr(Random(74, 77, 1)), 5) $aArray[$i][2] = _StringRepeat(Chr(Random(80, 83, 1)), 5) $aArray[$i][3] = _StringRepeat(Chr(Random(87, 90, 1)), 5) Next _ArrayDisplay($aArray, "Unsorted") ; Copy arrays for separate examples below $aArray_1 = $aArray $aArray_2 = $aArray ; This sorts columns in ascending order - probably the most common requirement ; Sort requirement: ; Col 0 = Decending ; Col 1 = Ascending ; Col 2 = Required order of elements (note not alphabetic PQRS nor reverse SRQP) ; Col 3 = Ascending Global $aSortData[][] = [ _ [0, 1], _ [1, 0], _ [2, "SSSSS,QQQQQ,PPPPP,RRRRR"], _ [3, 0]] ; Sort and display array _ArrayMultiColSort($aArray_1, $aSortData) ; Display any errors encountered If @error Then ConsoleWrite("Oops: " & @error & " - " & @extended & @CRLF) _ArrayDisplay($aArray_1, "Sorted in order 0-1-2-3") ; But the UDF can sort columns in any order ; Sort requirement: ; Col 2 = Decending ; Col 0 = Ascending Global $aSortData[][] = [ _ [2, 1], _ [0, 0]] ; Sort and display array _ArrayMultiColSort($aArray_2, $aSortData) ; Display any errors encountered If @error Then ConsoleWrite("Oops: " & @error & " - " & @extended & @CRLF) _ArrayDisplay($aArray_2, "Sorted in order 2-0") And here are both in zip form: ArrayMultiColSort.zip As usual all comments welcome. M23
    1 point
  3. GUIRegisterMsg() subclasses an AutoIt GUI. Ie. a window created with GuiCreate(). A few issues are related to GUIRegisterMsg(): It cannot subclass a control Some messages cannot be handled Only one function for a specific message These issues cannot be described as errors. They are probably consequences of a design choice to limit the complexity of the function. A few issues are related to the subclassing technique in general: _WinAPI_SetWindowLong() The Subclassing bug GUIRegisterMsg20() addresses all these issues. 2020-02-23: It's probably not true that GUIRegisterMsg() is based on the subclassing technique. The messages handled by GUIRegisterMsg() are more likely to originate from the message loop in the window procedure (implemented in internal code) of the main GUI window. What is subclassing? Subclassing is a technique to get information from standard controls through Windows messages, and to modify the functionality of standard controls by responding to these messages. Eg. to change the background color of listview cells. GUIRegisterMsg20 GUIRegisterMsg20.au3 is a small UDF implemented in 100 code lines. This is the documentation for GUIRegisterMsg20(): ; Register a message handler function for a window or control message ; GUIRegisterMsg20( $vWinOrCtrl, _ ; Window handle or control ID/handle ; $WM_MESSAGE, _ ; Window message or control message ; $hFunction ) ; User supplied message handler func ; ; $vWinOrCtrl GUI handle as returned by GUICreate, controlID as returned by GUICtrlCreate<Control> functions ; or control handle as returned by _GUICtrl<Control>_Create UDF functions or GUICtrlGetHandle. ; ; $WM_MESSAGE A Windows message code as listed in Appendix section in help file. Or a control message code ; eg. a LVM_MESSAGE or TVM_MESSAGE as listed in ListViewConstants.au3 or TreeViewConstants.au3. ; This parameter is only checked to be within the valid range of Windows and control messages: ; 0x0000 - 0x7FFF. ; ; $hFunction The user supplied function (not the name but the FUNCTION) to call when the message appears. ; The function is defined in exactly the same way as the function for the official GUIRegisterMsg: ; Takes four input parameters ($hWnd, $iMsg, $wParam, $lParam) and returns $GUI_RUNDEFMSG to conti- ; nue with default message handling, or a specific value if the message is handled by the function. ; ; Error code in @error Return value ; 1 => Invalid window handle or control ID/handle Success => 1 ; 2 => Invalid Window or control message Failure => 0 ; 3 => Invalid function handle ; 4 => Too many subclasses And this is the very central internal function that is called directly from the code in ComCtl32.dll: Func GUIRegisterMsg20_Handler( $hWnd, $iMsg, $wParam, $lParam, $idx, $pData ) If $iMsg <> $aGUIRegisterMsg20[$idx][3] Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Local $vRetVal = $aGUIRegisterMsg20[$idx][4]( $hWnd, $iMsg, $wParam, $lParam ) ; Execute user supplied message handler function If $vRetVal == "GUI_RUNDEFMSG" Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Return $vRetVal #forceref $pData EndFunc It's rarely necessary to call GUIUnRegisterMsg20(). Message handlers are unregistered when the program exits. An exception is a situation where message handles are registered and unregistered on the fly, eg. due to user actions. Message monitor When it comes to topics like subclassing, a message monitor is required eg. Windows Message Monitor. ListView example Listview example is a custom drawn listview with colored cells. If we focus on subclass implementation, this is the difference between GUIRegisterMsg() and GUIRegisterMsg20() code. GUIRegisterMsg(): ; ... GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; ... GUIRegisterMsg20(): #include "..\..\Includes\GUIRegisterMsg20.au3" ; ... GUIRegisterMsg20( $hGui, $WM_NOTIFY, WM_NOTIFY ) ; ... GUIRegisterMsg20() takes $hGui as first parameter. The message handler function in third parameter is a function variable. Not a string. The message handler function, WM_NOTIFY, is exactly the same in the two examples. If you run the scripts that contains message monitor code, you will notice a remarkable difference between the two scripts. In the GUIRegisterMsg20() script, there are no NM_CUSTOMDRAW notifications in the monitor. What's the reason? All GUIRegisterMsg() examples in help file that looks like this: ; ... GUIRegisterMsg( $WM_MESSAGE, "WM_MESSAGE" ) ; ... Can be implemented with GUIRegisterMsg20() this way: ; ... GUIRegisterMsg20( $hGui, $WM_MESSAGE, WM_MESSAGE ) ; ... Input example Input example is based on this forum thread. Run Input.au3 to see the issues: You can paste a number into the control, a context menu shows up on right click, and a tooltip is displayed if you press a letter. Let's see what's going on with the message monitor. When you solve issues with a message monitor, you are generally interested in finding a particular message or a pattern of a few messages. If there are multiple instances of the message or pattern, it's easier to find. The action that generates the message or pattern should be repeated 3 - 4 times. Run "Input, wmm.au3", paste a number into the control 3 - 4 times eg. 18 (result = 18181818), right click 3 - 4 times, press a letter 3 - 4 times. Press Esc to delete Input GUI and start WMM GUI. Scroll down until you see tomato red messages. You'll see the messages WM_PASTE, WM_CONTEXTMENU and EM_SHOWBALLOONTIP. Note that all three messages are received by the Input control. This means that GUIRegisterMsg() cannot be used. It can only handle messages received by the GUI. Because all messages are received by the Input control you can register three message handlers this way in "Input, subclass.au3": ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, WM_PASTE ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, WM_CONTEXTMENU ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, EM_SHOWBALLOONTIP ) To implement message handler functions you have to read Microsoft documentation. Only for EM_SHOWBALLOONTIP it's completely clear that the message is suppressed by returning False or 0. For all three messages, however, you must return 0 to suppress the message: ; WM_PASTE message handler function Func WM_PASTE( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; WM_CONTEXTMENU message handler function Func WM_CONTEXTMENU( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; EM_SHOWBALLOONTIP message handler function Func EM_SHOWBALLOONTIP( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc As all three functions are the same, the code can be reduced a little bit in "Input, final.au3": ; GUICtrlCreateInput - Disable copy/ paste, right click menu and balloon pop-up ; https://www.autoitscript.com/forum/index.php?showtopic=179052 #include <GuiEdit.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "..\..\Includes\GUIRegisterMsg20.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Create GUI GUICreate( "Input (numbers only)", 300, 118 ) ; Create Input Local $idInput = GUICtrlCreateInput( "", 50, 50, 200, 18, $GUI_SS_DEFAULT_INPUT+$ES_NUMBER ) ; Create Label GUICtrlCreateLabel( "No paste, no context menu, no balloontip", 50, 70, 200, 18 ) ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, InputFunc ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, InputFunc ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, InputFunc ) ; Show GUI GUISetState() ; Msg loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete() EndFunc ; Input message handler function Func InputFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. Header example The width of listview columns can be changed by dragging header item separators with the mouse. If you want to disable this feature you have to suppress HDN_BEGINTRACK notifications from the header control. They are contained in WM_NOTIFY messages. And you have to suppress WM_SETCURSOR messages when the mouse cursor hover over header item separators. This prevents a cursor shape indicating that separators can be dragged. Run "ListView header, wmm.au3". Drag the header item separators forth and back. This generates a huge number of messages. Press Esc to delete GUI and start WMM GUI. Scroll down until you see tomato red messages. Note that HDN_BEGINTRACK notifications in WM_NOTIFY messages are sent first to the listview and then to the GUI. They can be catched by GUIRegisterMsg(). Here they'll be catched by GUIRegisterMsg20() from the listview. WM_SETCURSOR messages must be catched from the header: ; Subclass ListView and Header GUIRegisterMsg20( $idListView, $WM_NOTIFY, ListViewFunc ) GUIRegisterMsg20( $hHeader, $WM_SETCURSOR, HeaderFunc ) Handler functions: ; ListView message handler function Func ListViewFunc( $hWnd, $iMsg, $wParam, $lParam ) If $HDN_BEGINTRACKW = DllStructGetData( DllStructCreate( $tagNMHEADER, $lParam ), "Code" ) Then Return 1 Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ; Header message handler function Func HeaderFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 1 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Again, just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. 2020-02-23: Note that if you want to prevent the width of the listview columns from being changed you can simply add the HDS_NOSIZING style to the header control. I wasn't aware of that when I made the example. TreeView example (2018-08-15) TreeView example is based on this forum thread. Run TreeView.au3 (copied from first post in thread) to see the issue: No WM_COMMAND messages are received on right click in treeview. "TreeView, wmm.au3" shows the problem: WM_COMMAND messages generated on right clicks are sent to the treeview and not the main GUI. This means that GUIRegisterMsg() isn't able to catch the messages. To solve the problem include GUIRegisterMsg20.au3 in top of script and use GUIRegisterMsg20() to subclass the treeview as it's done in "TreeView, subclass.au3": ;... #include "..\..\Includes\GUIRegisterMsg20.au3" ;... GUIRegisterMsg20( $g_hTreeView, $WM_COMMAND, WM_COMMAND ) The existing WM_COMMAND() message handler is reused. That was two code lines to solve the problem. It can hardly be easier. Too much code (2018-09-30) A custom drawn listview generates a lot of WM_NOTIFY messages. If custom draw code is used to draw selected items with GDI-functions in the post paint drawing stage, much code will be executed to respond to all these messages. If it's also a virtual listview, it'll double the number of messages (Examples\5) Too much code\ListView.au3): Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local Static $tText = DllStructCreate( "wchar[100]" ), $pText = DllStructGetPtr( $tText ) Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ) Switch DllStructGetData( DllStructCreate( $tagNMHDR, $lParam ), "Code" ) Case $LVN_GETDISPINFOW ; Fill virtual listview Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If Not BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Return Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO,"Item")][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return Case $NM_CUSTOMDRAW ; Draw back colors Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" ), $iItem Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) If GUICtrlSendMsg( $idListView, $LVM_GETITEMSTATE, $iItem, $LVIS_SELECTED ) Then Return $CDRF_NOTIFYPOSTPAINT ; Selected item DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", $aColors[$iItem][DllStructGetData($tNMLVCUSTOMDRAW,"iSubItem")] ) ; Normal item Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem Local $hDC = DllStructGetData( $tNMLVCUSTOMDRAW, "hdc" ) ; Subitem rectangle $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) Local $iSubItem = DllStructGetData( $tNMLVCUSTOMDRAW, "iSubItem" ) DllStructSetData( $tRect, "Left", $LVIR_LABEL ) DllStructSetData( $tRect, "Top", $iSubItem ) GUICtrlSendMsg( $idListView, $LVM_GETSUBITEMRECT, $iItem, $pRect ) DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + 2 ) DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Right" ) - 2 ) DllStructSetData( $tRect, "Bottom", DllStructGetData( $tRect, "Bottom" ) - 1 ) ; Subitem back color Local $hBrush = DllCall( "gdi32.dll", "handle", "CreateSolidBrush", "int", $aColors[$iItem][$iSubItem] )[0] ; _WinAPI_CreateSolidBrush DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "bool", "DeleteObject", "handle", $hBrush ) ; _WinAPI_DeleteObject ; Draw subitem text DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0 ) ; _WinAPI_SetTextColor DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItems[$iItem][$iSubItem], "int", -1, "struct*", $tRect, "uint", $DT_CENTER ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc If there are a lot of messages and some messages perform quite a lot of code, you can end up in a situation where more code is performed than there's time for. The result is that the WM_NOTIFY messages are blocked and the code fails: You can provoke the error this way: Click a row in the listview (not one of the very top rows). Press Shift+Down arrow to select multiple rows. The problem will arise after just a few rows. Press Ctrl+Break in SciTE to stop the code. 2020-02-23: The only solution to the problem is probably to implement the WM_NOTIFY() function in compiled code as demonstrated here. Message flow (update 2018-09-30) In these examples, the message flow is examined with left and right mouse clicks. Several message handles are implemented. A standard AutoIt message loop (MessageLoop Mode) where messages are received with GUIGetMsg(). A message handler based on GUIRegisterMsg(). And a message handler created with GUIRegisterMsg20(). In addition, there is the internal AutoIt message handler (C++ code). The purpose is to determine in which order a message is received by all these different message handlers. Script 1) implements the three message handlers. By examining the message flow with the monitor we can see that the messages are received in this order: Script 2) implements an additional GUIRegisterMsg20() message handler for the same mouse click messages but with another message handler function. It seems that the last created GUIRegisterMsg20() handler, is the first to receive the mouse clicks. In script 3) mouse clicks are performed in an Edit control instead of an empty GUI. The GUIRegisterMsg() message handler does not receive the mouse clicks. At what point in the flow chart does the message monitor hook into the message flow? Since message detection is implemented through subclassing it hooks into the message flow just before the internal AutoIt message handler. Now we can answer the question from the listview example above: Why do we not see any NM_CUSTOMDRAW notifications in the message monitor from the GUIRegisterMsg20() script. Because these notifications are all answered with one of the custom draw return values and not $GUI_RUNDEFMSG. The custom draw return values goes directly back to the operating system and the messages are no longer forwarded in the message chain. The message flow stops already at the GUIRegisterMsg20() message handler function and never reaches the internal AutoIt message handler. Therefore, the messages do not reach the monitor either. The issues The listview example at the top shows that GUIRegisterMsg20() is very similar to GUIRegisterMsg(). You can do the same things with GUIRegisterMsg20() as you can do with GUIRegisterMsg(). This means that you can use GUIRegisterMsg20() in a UDF, while the user can use GUIRegisterMsg() in his own code exactly as described in the help file. From the flow chart above you know that the GUIRegisterMsg20() message handler function will receive messages before the GUIRegisterMsg() message handler function. Let's review the issues mentioned in beginning of post. Only GUIRegisterMsg20() can subclass a control and receive control messages. This is demonstrated in the input example. The mouse clicks in the edit control discussed above shows that GUIRegisterMsg() isn't receiving all WM_MESSAGEs and therefore cannot handle these messages. The mouse clicks in the section above also shows that GUIRegisterMsg20() can use several functions for the same message. Because GUIRegisterMsg20() uses SetWindowSubclass to implement subclassing, problems related to _WinAPI_SetWindowLong() are avoided. Because GUIRegisterMsg20() returns directly from the DefSubclassProc DllCall, the subclassing bug never comes into play. Conclusion GUIRegisterMsg20 UDF takes care of the tedious and cumbersome task of configuring subclassing. Ie. to set up SetWindowSubclass, DefSubclassProc and RemoveWindowSubclass functions. It uses a message handler function that is very similar to the function used in the official GUIRegisterMsg(). You can concentrate on analyzing the message flow and code the message handler function. 7z-file You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Note that the contents of the Includes folder in the Windows Message Monitor 7z-file must be installed in the WMMincl directory to use Windows Message Monitor. Comments are welcome. Let me know if there are any issues. GUIRegisterMsg20.7z
    1 point
  4. For some time I was wondering how to execute AutoIt code from a web browser. I made some solutions using IE.au3, but that's only one browser. Is there a way to execute AutoIt from ANY browser? There is one - custom protocols. So, I looked how to add one, and here it is - running AutoIt from any web browser. AutoIt Protocol Example (run install.au3 before!): 2+2 in a MsgBox Edit: you can't use this protocol in posts here, how sad Have fun!
    1 point
  5. did you do what @FrancescoDiMuro suggested?
    1 point
  6. Same way, use _StringBetween #include <String.au3> $s = "blablabla vous envoie ce message : " Msgbox(0,"", _StringBetween($s, "", ' vous envoie')[0] ) It's a pretty nice solution if you don't feel sure with regex OK, here is an example #include <Array.au3> $s = "[ANAH][88][Demandeur][45896_1529768635] Question concernant mon dossier " $a = StringRegExp($s, '\[([^\]]+)\]', 3) _ArrayDisplay($a) explanations : the brackets are escaped when used as literals because they are special characters In the capturing group, [...] is a character class (refer to the help file), and ^\] means "a char which is not a closing bracket" So literally, the expression \[([^\]]+)\] means : "get one or more chars, included in brackets, which are not a closing bracket"
    1 point
  7. Melba23

    A question:

    amerali, Welcome to the AutoIt forum. Unfortunately you appear to have missed the Forum rules on your way in. Please read them now - particularly the bit about not discussing game automation - and then you will understand why you will get no help and this thread will now be locked. See you soon with a legitimate question I hope. careca, Things "at the moment" are no different from any time over the past few years. To my mind transferring file "to the game" is "interaction" and not just simple file transfer - so illegal. M23
    1 point
  8. careca

    A question:

    if you search the forum for how to send emails, you'll find numerous posts. Come back with some code and then we can talk. BTW imo this is not game related, because you dont interact with the game, only with it's files, but who knows, how things are at the moment, this topic may be locked.
    1 point
  9. FrancescoDiMuro

    A question:

    About a game?
    1 point
  10. FrancescoDiMuro

    A question:

    Bot used for?
    1 point
  11. FrancescoDiMuro

    A question:

    File: How is this file? Can you provide an example? Send: where? Upload: where?
    1 point
  12. FrancescoDiMuro

    A question:

    @amerali Don't quote who is replying to you. Just type @ and the name of who replied to you. As I have stated above, tell us more about it. We can't help you if you don't provide source code/examples...
    1 point
  13. To enhance performance you could use: Local $oUsedRange = $oExcel.Application.Workbooks("Accounts.xlsx").ActiveSheet.UsedRange For $i=1 to 100 step 1 $oUsedRange.Replace($i&".","") Next
    1 point
  14. @mikell Man your help was imba Here is my script for furter user that whould like to understand easy script for starter... First of all i was needing that line to do same of you : $s = "[ANAH][88][Demandeur][45896_1529768635] Question concernant mon dossier " So i did that : $Ligne = _GetValueInArray($aSplit, '[ANAH]') $Dep = _StringBetween($Ligne, '[', ']')[0] $Role = _StringBetween($Ligne, '[', ']')[1] 1000 Thx. @mikell My last question : In this line : blablabla vous envoie ce message : Particulary if the blablabla can be bliblibli blobloblo or unknow name. How to get blablabla in a $variable ?? Edit: Answer : $pattern = '(?s).+?(\d+)\]\[([^\]]+).+?Bonjour,\s+(.+?) vous envoie.+?email : (\N+).+?tél. : (\N+)' $a = StringRegExp($DataLut, $pattern, 3) $Nom = $a [2]
    1 point
  15. You inserted an additional parameter ("E"&$Index). This doesn't work. Concatenate to one parameter like: _Excel_RangeInsert($OpenWorkbook.ActiveSheet, "D" & $Index & ":E" & $Index, $xlShiftDown)
    1 point
  16. genius257

    @ Adding conditions

    Hi @Deye. So I think you need multiple regular expressions. To make expression(s) you work with less complicated, I would suggest you do the following: remove all comments from the string you are processing. Match (almost) all strings with RegEx below. Take each match and translate it into a complete string with the Execute command. filter results, depending if result is a a legal path depending on your current file system (NTFS, FAT32, ...). Add those results to the regex matching #include ..., #AutoIt3Wrapper_Res_File_Add=... (where you've stripped the part of the string that is not part of the file path) Do whatever you want with the result Note that this RegEx does not support string escapes in the AutoIt syntax. (?(DEFINE)(?<string>(["'])((?!\2).)*\2)(?<spacing>[\h]*)(?<macro>[@][A-Za-z]+))(((?&string)|(?&macro))(\h*[&](\h+[_]\h*\n)?\h*(?&string)|(?&macro))?)+ Hope this is of some use to you. Sorry for the response time, I am the process of moving ^^' Edit: Ofc. my solution does not support methods with string definition either, like: $a = "this is a" & Mood(1) & "day" $b = "this is a" & Mood(0) & "day" Func Mood($good) Return $good?'happy':'sad' EndFunc
    1 point
  17. Seems to be easy. Just check the 2 pid's: ShellExecute return's a Pid for each process you start, so just loop until both ended. So this: $sPid1 = ShellExecute(@ScriptDir & "\Log\Validator.log") Sleep(2000) $sPid2 = ShellExecute(@ScriptDir & "\Sample.xml") ; pause the script here until this xml will close. $bOK =False Do $bOK = Not ProcessExists($pid1) If $bOK Then $bOK = Not ProcessExists($pid2) sleep(100) Until $bOK should do your job.
    1 point
  18. Ok I believe I get the picture, more or less. First there are some problems with your table design. 1) SQLite doesn't have datatypes STRING nor DATETIME. Those columns are parsed as being unknown datatypes with affinity BLOB. Probably not what you intended. 2) "operational_minutes" should probably call "operational_hours" 3) Both "operational_minutes" and "late_hours" should be REAL, not STRING (nor TEXT). 4) You can't make further use of result columns aliased. That's why "abs_count" is unknown. 5) You probably don't need to use "autoincrement" for the id primary key. That doesn't mean what you think it means. To fix this I defined a table like this: CREATE TABLE "data_db" ( "id" INTEGER PRIMARY KEY, "employee_number" TEXT, "employee_name" TEXT, "supervisor" TEXT, "date" TEXT, "schedule_status" TEXT, "attendance_status" TEXT, "operational_hours" REAL, "late_hours" REAL); I had to type (you pasted a picture) some random data in: id employee_number employee_name supervisor date schedule_status attendance_status operational_hours late_hours 1 100123 John Doe Bryan McGrath 2018-08-09 WORK WORK 7.47 1.55 2 100124 Jane Doe Bryan McGrath 2018-08-09 WORK ABSENT 0 0 3 178223 Joe Grifith Neil Grant 2018-08-09 WORK WORK 8 0 4 182123 Ryan Banks Summer Harley 2018-08-09 WORK ABSENT 0 0 5 143708 Paul Tanner Summer Harley 2018-08-08 WORK WORK 7.15 0.34 6 075891 Bill Moots Neil Grant 2018-08-09 WORK WORK 8.12 0 7 000156 Shirley Vroot Neil Grant 2018-08-07 WORK ABSENT 0 0 8 000163 Shirley Wok Neil Grant 2018-08-07 WORK WORK 7.52 0 9 542980 Dan Vroot Neil Grant 2018-08-07 WORK WORK 6.45 0 10 514802 Sheila Vroot Neil Grant 2018-08-07 WORK WORK 8.33 1.06 Then this statement should be close to what you want: SELECT supervisor, COUNT(employee_name) emp_count, SUM(CASE WHEN attendance_status LIKE 'ABSENT' THEN 1 else 0 END) abs_count, SUM(CASE WHEN late_hours > 0 THEN 1 else 0 END) late_count, printf('%2.2f', 100.0 * SUM(CASE WHEN attendance_status LIKE 'ABSENT' THEN 1 else 0 END) / COUNT(employee_name)) abs_rate FROM data_db WHERE supervisor != '' GROUP BY supervisor The result then is: supervisor emp_count abs_count late_count abs_rate Bryan McGrath 2 1 1 50.00 Neil Grant 6 1 1 16.67 Summer Harley 2 1 1 50.00 Note that your DB currently contains text instead of numeric values.
    1 point
  19. Or even shorter Global $handle MsgBox(0, "Result", (FileWrite($handle, "Text") = 1) ? "Success!" : "Error!")
    1 point
  20. No, there's no reason except readability Your code can even be shortened to:
    1 point
  21. Can't believe that none of these functions: _ChromeObjGetHTMLById($objid, $timeout = 5) _ChromeObjGetHTMLByName($objname, $index = 0, $timeout = 5) _ChromeObjGetHTMLByTagName($tagname, $index = 0, $timeout = 5) can do a part of the job for you. But you have to investigate time to learn about HTML, regex and/or string functions. If chrome.au3 isn't possible, try download site with HTTP or with InetGet.
    1 point
  22. Right, but learning regex is never a waste of time #include <Array.au3> Global $sData = FileRead('Dossier.txt') $pattern = '(?s).+?(\d+)\]\[([^\]]+).+?Bonjour,\s+(.+?) vous envoie.+?email : (\N+).+?tél. : (\N+)' $a = StringRegExp($sData, $pattern, 3) _ArrayDisplay($a)
    1 point
  23. StringRegExp and StringRegExpReplace are very powerful but not needed, if you (same as mine) don't understand to use it. You can use a combination of String* and _StringBetween (using StringRegExp) Small example for _StringBetween: #include <Array.au3> #include <String.au3> Global $sData = FileRead('Dossier.txt') $aSplit = StringSplit($sData, @CRLF, 3) _ArrayDisplay($aSplit) $sEMail = _GetValueInArray($aSplit, '- email : ') ConsoleWrite($sEMail & @CRLF) Global $aData = _StringBetween($aSplit[0], '[', ']') _ArrayDisplay($aData) Func _GetValueInArray($aArray, $sInStr) Local $sRet = '' For $i = 0 To UBound($aArray) - 1 If StringInStr($aArray[$i], $sInStr) Then $sRet = StringReplace($aArray[$i], $sInStr, '') ExitLoop EndIf Next Return $sRet EndFunc ;==>_GetValueInArray As you see $aData[1] is 88 and EMail is stored in a var. dossier.txt
    1 point
  24. @caramen StringReplace(), StringInStr(), StringRegExp(), StringRegExpReplace()
    1 point
  25. Hi @caramen If this data is collected in a browser page, you could start to take a look at Browsers UDF. You could just take a look at _IE UDF, which is very intuitive and easy to use
    1 point
  26. Jon

    Forum Rules

    We want the forum to be a pleasant place for everyone to discuss AutoIt scripting, and we also want to protect the reputation of AutoIt. So we ask you to respect these simple rules while you are here: Forum Posting 1. Do not ask for help with AutoIt scripts, post links to, or start discussion topics on the following subjects: Malware of any form - trojan, virus, keylogger, spam tool, "joke/spoof" script, etc. Bypassing of security measures - log-in and security dialogs, CAPTCHAs, anti-bot agents, software activation, etc. Automation of software/sites contrary to their EULA (see Reporting bullet below). Launching, automation or script interaction with games or game servers, regardless of the game. Running or injecting any code (in any form) intended to alter the original functionality of another process. Decompilation of AutoIt scripts or details of decompiler software. This list is non-exhaustive - the Moderating team reserve the right to close any thread that they feel is contrary to the ethos of the forum. 2. Do not post material that could be considered pornographic, violent or explicit - or express personal opinions that would not be acceptable in a civilized society. Do not post any copyrighted material unless the copyright is owned by you or by this site. 3. To protect this community, any files posted by you are subject to checks to ensure that they do not contain malware. This includes, but is not limited to, decompilation and reverse engineering. 4. Do not flame or insult other members - and just report the thread to a Moderator (see below) if you are so attacked. 5. Do not PM other users asking for support - that is why the forum exists, so post there instead. 6. Do not create multiple accounts - if you inadvertently created multiple accounts then contact a Moderator to close the unwanted ones. 7. Do not repost the same question if the previous thread has been locked - particularly if you merely reword the question to get around one of the prohibitions listed above. 8. Do not delete your posts, nor completely remove their content, if doing so will interrupt the flow of the thread. 9. Do not post in a thread while the Moderating team are actively trying to determine whether it is legal. The Moderation team will do their best to act in fair and reasonable manner. Sanctions will only be applied as a last resort and any action taken will be explained in the relevant thread. If moderation action is taken, you will need to acknowledge this through a dialog or you will be unable to post further in the forum. Please note that this dialog is not an agreement that the warning was justified - it is only there so that members are aware that moderation action has been taken and that they may have certain restrictions applied to their account. If you feel that you have been unfairly moderated then contact the Moderator concerned - using a PM or the "Report" button is preferable to opening a new thread (although new members may have to do this). But do be aware that the Moderation team has the final word - the rules are set out by the site owner and you are only welcome here if you respect his wishes. Signatures and Avatars There is no formal policy for the use of signatures but if a moderator thinks it is too big and/or distracting then you may be asked to tone it down. No-one likes wading through signatures that are a page high. Similarly for avatars, expect distracting flashing and animated gifs to be removed. Reporting If you feel a post needs Moderator attention, please use the "Report" button next to the post date at the top. You can then enter details of why you have reported the post - but there is no need to include the content of the post as that is done automatically. The Moderating team will be alerted to the post and will deal with it as soon as they can. If you suspect a EULA violation, do not expect the Moderating team to do all the work - please provide some evidence in the report such as a copy of (or link to) the EULA in question, as well as the section you believe has been violated. Finally, please do not enter into an argument with the original poster - that is why we have Moderators. Spam Please do not react to spam in any way other than reporting it. Multiple reports are combined by the forum software, so there is no need to announce that you have reported the spam - in fact doing so only increases the work for the Moderator who deals with it. Interacting with this website Anyone found abusing the website is subject to harsh punishment without warning. A non-exhaustive list of potential abuses include: Automated forum registration or login. Automated posting or sending messages on the forum. Automated manipulation of polls, user reputation or other forum features. Automated creation or comments on issue tracker tickets. Automated creation or editing of wiki pages. Other abuses which are either examples of excessive bandwidth usage or automation of the site. Use common sense. If you do not have common sense, don't do anything. Do not automate the forum, wiki or issue tracker in any way at all. Scripts which automatically update AutoIt such as AutoUpdateIt are acceptable as long as they are not abused and do not generate excessive bandwidth usage.
    1 point
  27. Simple StringSplit usage $Value = "C:\PROGRA~1\COMMON~1\SYMANT~1\VIRUSD~1\20090907.050" $split = StringSplit($Value, "\") $result= $split[$split[0]] Msgbox(0,"", $result)
    1 point
×
×
  • Create New...