Leaderboard
Popular Content
Showing content with the highest reputation on 05/08/2021 in all areas
-
Unions in Autoit can be tricky. I learned the hard way in my HTTPAPI UDF. To give credit where credit is due, @Danyfirex is the one that helped me understand it. Of course, I don't have a way to test this other than how I did it in the example below. The tricky part is getting the alignment of the union correct. As you sort of stated, the size of the largest data type in the union determines the union's alignment. And whether you are running as 32 or 64 bit can make a difference. In 32-bit mode, the largest data type in your union is 4 bytes. So the alignment should start on a multiple of 4. The size of the struct before the union, in 32-bit mode, is 28 bytes. Since 28 is a multiple of 4, no alignment adjustment needs to be done. The size of the struct, in 64-bit mode, is 32 bytes and the largest union data type is 8 bytes. So, again, no adjustment to the alignment needs to be done. Again, I haven't been able to test it to make sure that I have everything correct, but I think it looks right. Also, there's more than 1 way to do this in AutoIt. This is just the way that I chose because it seems the most straight forward. This should work in both 32 & 64 bit scripts. So when you implement it in your real script, you would use the appropriate struct (WORD/SENTENCE, MARK/PLAY, or NAME) depending on the event type you are working with. #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d #AutoIt3Wrapper_UseX64=N ;N = 32-bit / Y = 64-bit #include <Constants.au3> #include <WinAPIDiag.au3> #cs typedef struct { espeak_EVENT_TYPE type; //ENUM unsigned int unique_identifier; // message identifier (or 0 for key or character) int text_position; // the number of characters from the start of the text int length; // word length, in characters (for espeakEVENT_WORD) int audio_position; // the time in mS within the generated speech output data int sample; // sample id (internal use) void* user_data; // pointer supplied by the calling program union { int number; // used for WORD and SENTENCE events. const char *name; // used for MARK and PLAY events. UTF8 string char string[8]; // used for phoneme names (UTF8). Terminated by a zero byte unless the name needs the full 8 bytes. } id; } espeak_EVENT; #ce ;ESPEAK EVENT BASE STRUCT Global $gtag_ESPEAK_EVENT = _ "struct;" & _ "int type;" & _ "uint uid;" & _ "int textPosition;" & _ "int length;" & _ "int audioPosition;" & _ "int sample;" & _ "ptr userData;" & _ "endstruct;" ;ESPEAK ID UNION STRUCTs Global $gtag_ESPEAK_EVENT_UNION_ID_INT = _ "struct;" & _ "int id;" & _ "endstruct;" Global $gtag_ESPEAK_EVENT_UNION_ID_PTR = _ "struct;" & _ "ptr id;" & _ "endstruct;" Global $gtag_ESPEAK_EVENT_UNION_ID_CHAR = _ "struct;" & _ "char id[8];" & _ "endstruct;" ;ESPEAK EVENT STRUCTs with Unions Global $gtag_ESPEAK_EVENT_WORD_SENTENCE = _ $gtag_ESPEAK_EVENT & _ $gtag_ESPEAK_EVENT_UNION_ID_INT Global $gtag_ESPEAK_EVENT_MARK_PLAY = _ $gtag_ESPEAK_EVENT & _ $gtag_ESPEAK_EVENT_UNION_ID_PTR Global $gtag_ESPEAK_EVENT_NAME = _ $gtag_ESPEAK_EVENT & _ $gtag_ESPEAK_EVENT_UNION_ID_CHAR example() Func example() Local $tEspeakEvent $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT - @error = " & @error) _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT, "ESPEAK_EVENT_" & (@AutoItX64 ? " 64bit" : " 32bit")) $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_WORD_SENTENCE) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_WORD_SENTENCE - @error = " & @error) _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_WORD_SENTENCE, "ESPEAK_EVENT_WORD_SENTENCE" & (@AutoItX64 ? " 64bit" : " 32bit")) $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_MARK_PLAY) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_MARK_PLAY - @error = " & @error) _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_MARK_PLAY, "ESPEAK_EVENT_MARK_PLAY" & (@AutoItX64 ? " 64bit" : " 32bit")) $tEspeakEvent = DllStructCreate($gtag_ESPEAK_EVENT_NAME) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Error creating $gtag_ESPEAK_EVENT_NAME - @error = " & @error) _WinAPI_DisplayStruct($tEspeakEvent,$gtag_ESPEAK_EVENT_NAME, "ESPEAK_EVENT_NAME" & (@AutoItX64 ? " 64bit" : " 32bit")) EndFunc3 points
-
Help with a structure for a DLL
JockoDundee and one other reacted to Musashi for a topic
Aside : I do not think, that these parameters will affect the operation, see : · -q : quiet mode (this will only show errors and warnings) · -d : set the "MustDeclareVars" option to True · -w 1 : give a warning if an include file is included more than once · -w 2 : give a warning if #comments-end (or #ce) is missing · -w 3 : give a warning if variables are already declared · -w 4 : give a warning if local variables are used in the global scope · -w 5 : give a warning if a local variable is declared but not used · -w 6 : give a warning when using Dim · -w 7 : give a warning if ByRef parameters are incorrect2 points -
Help with a structure for a DLL
TheXman and one other reacted to JockoDundee for a topic
Several structures are created because the union could have several different data formats. Depending on the value of the type element, the union could either contain an 1) integer 2) pointer to a char 3) array of 8 chars so depending on what the type value is for a given record, you use the right struct to be able to interpret the bytes of the union correctly. Also, and btw, @TheXman really went beyond the call of duty on this one. If there was just someway in this forum to show him appreciation besides saying “Thanks!, now would be the time to find it 👉👉👉 👉👉👉👉👉👉👉👇2 points -
Multi-line items in custom drawn ListView
pixelsearch reacted to LarsJ for a topic
Items in a standard listview in details/report view (this example deals only with listviews in details/report view) can display a single line of text. There seems not to be any options to change this. There is no word wrap option. If you search the forums, it's possible to find examples of listviews with multiple lines of text in each row. The multi-line items are implemented as owner drawn items through LVS_OWNERDRAWFIXED control style and WM_DRAWITEM messages. A problem with the owner drawn technique is that you are forced to draw everything yourself. Besides item texts and the background behind texts (white for non-selected items, dark blue for selected items with focus, button face for selected items without focus) you also have to draw checkboxes, images, icons and the background behind these elements yourself. Another technique is custom drawn listview items. Custom drawn items are implemented through NM_CUSTOMDRAW notifications included in WM_NOTIFY messages. NM_CUSTOMDRAW notifications are generated automatically by the code in ComCtl32.dll when the listview is updated. Implementing custom drawn items is a matter of responding to these messages or not. The great advantage of custom drawn items is that the drawing process is divided into several stages. For a listview up to six different stages. Some of these stages can be used for default drawing without any additional code at all. Other stages can be used for custom drawing with your own code. Multi-line text items fits perfectly with the custom drawn technique. Item texts and the background is drawn by custom code. Checkboxes, images, icons and the background is drawn by default code. Increase height of listview items The usual way to increase the height of listview items is to respond to WM_MEASUREITEM messages. But this method can only be used for owner drawn listviews. In a custom drawn listview the height can be increased by defining a text font with a suitable height: Func _GUICtrlListView_SetItemHeightByFont( $hListView, $iHeight ) ; Get font of ListView control ; Copied from _GUICtrlGetFont example by KaFu ; See https://www.autoitscript.com/forum/index.php?showtopic=124526 Local $hDC = _WinAPI_GetDC( $hListView ), $hFont = _SendMessage( $hListView, $WM_GETFONT ) Local $hObject = _WinAPI_SelectObject( $hDC, $hFont ), $lvLOGFONT = DllStructCreate( $tagLOGFONT ) _WinAPI_GetObject( $hFont, DllStructGetSize( $lvLOGFONT ), DllStructGetPtr( $lvLOGFONT ) ) Local $hLVfont = _WinAPI_CreateFontIndirect( $lvLOGFONT ) ; Original ListView font _WinAPI_SelectObject( $hDC, $hObject ) _WinAPI_ReleaseDC( $hListView, $hDC ) _WinAPI_DeleteObject( $hFont ) ; Set height of ListView items by applying text font with suitable height $hFont = _WinAPI_CreateFont( $iHeight, 0 ) _WinAPI_SetFont( $hListView, $hFont ) _WinAPI_DeleteObject( $hFont ) ; Restore font of Header control Local $hHeader = _GUICtrlListView_GetHeader( $hListView ) If $hHeader Then _WinAPI_SetFont( $hHeader, $hLVfont ) ; Return original ListView font Return $hLVfont EndFunc Large images will also increase the height of listview items. See example E. Height of listview If the height of the listview does not fit an integer number of rows, you can see empty space below last row in the bottom of the listview. This issue is exacerbated by tall items. The following function is used to calculate the height of the listview to match a given number of rows: Func _GUICtrlListView_GetHeightToFitRows( $hListView, $iRows ) ; Get height of Header control Local $tRect = _WinAPI_GetClientRect( $hListView ) Local $hHeader = _GUICtrlListView_GetHeader( $hListView ) Local $tWindowPos = _GUICtrlHeader_Layout( $hHeader, $tRect ) Local $iHdrHeight = DllStructGetData( $tWindowPos , "CY" ) ; Get height of ListView item 0 (item 0 must exist) Local $aItemRect = _GUICtrlListView_GetItemRect( $hListView, 0, 0 ) ; Return height of ListView to fit $iRows items ; Including Header height and 8 pixels of additional room Return ( $aItemRect[3] - $aItemRect[1] ) * $iRows + $iHdrHeight + 8 EndFunc The calculation includes the height of the header. This means that the function works for a multi-line header with tall items (example A and B). Reference example WM_NOTIFY messages and NM_CUSTOMDRAW notifications are send to the parent of the listview control. The parent is the AutoIt GUI and messages can be handled by a function registered with GUIRegisterMsg. Example 1 is a reference example which shows the different stages of the custom drawing process. None of the stages contains any code except for ConsoleWrite statements. This is code for the reference example: #include <GUIConstants.au3> #include <GuiListView.au3> #include "GuiListViewEx.au3" Opt( "MustDeclareVars", 1 ) Global $hGui, $idListView, $hListView, $fListViewHasFocus = 0, $iItems = 3, $bAutoItMsgLoop = False Example() Func Example() ; Create GUI $hGui = GUICreate( "Custom draw stages", 420, 200 ) ; Create ListView $idListView = GUICtrlCreateListView( "", 10, 10, 400, 180, $GUI_SS_DEFAULT_LISTVIEW-$LVS_SINGLESEL, $WS_EX_CLIENTEDGE+$LVS_EX_FULLROWSELECT+$LVS_EX_GRIDLINES ) $hListView = GUICtrlGetHandle( $idListView ) ; Add columns to ListView _GUICtrlListView_AddColumn( $hListView, "Column 1", 94 ) _GUICtrlListView_AddColumn( $hListView, "Column 2", 94 ) _GUICtrlListView_AddColumn( $hListView, "Column 3", 94 ) _GUICtrlListView_AddColumn( $hListView, "Column 4", 94 ) ; Fill ListView For $i = 0 To $iItems - 1 GUICtrlCreateListViewItem( $i & "/Column 1|" & $i & "/Column 2|" & $i & "/Column 3|" & $i & "/Column 4", $idListView ) Next ; Adjust height of GUI and ListView to fit ten rows Local $iLvHeight = _GUICtrlListView_GetHeightToFitRows( $hListView, 10 ) WinMove( $hGui, "", Default, Default, Default, WinGetPos( $hGui )[3] - WinGetClientSize( $hGui )[1] + $iLvHeight + 20 ) WinMove( $hListView, "", Default, Default, Default, $iLvHeight ) ; Register WM_NOTIFY message handler ; To handle NM_CUSTOMDRAW notifications ; And to check when ListView receives/loses focus GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Register WM_ACTIVATE message handler ; If GUI loses focus selected listview items are drawn with a button face background color. ; To check when GUI receives/loses focus ; When GUI receives focus selected items are redrawn with the dark blue background color. GUIRegisterMsg( $WM_ACTIVATE, "WM_ACTIVATE" ) ; Detection of received focus is faster through the WM_ACTIVATE message than directly ; through the listview. This provides a faster and smoother redraw of selected items. ; Show GUI GUISetState( @SW_SHOW ) ; Message loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch If Not $bAutoItMsgLoop Then _ ; We want to see only one message at a time $bAutoItMsgLoop = ( ConsoleWrite( "AutoIt message loop <<<<<<<<<<<<<<<<<<<<<" & @CRLF ) > 0 ) WEnd ; Cleanup GUIDelete() EndFunc ; WM_NOTIFY message handler Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) #forceref $hWnd, $iMsg, $wParam Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Local $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Local $iCode = DllStructGetData( $tNMHDR, "Code" ) Switch $hWndFrom Case $hListView Switch $iCode Case $NM_CUSTOMDRAW $bAutoItMsgLoop = False Local $tNMLVCustomDraw = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMLVCustomDraw, "dwDrawStage" ) Switch $dwDrawStage ; Specifies the drawing stage ; Stage 1 Case $CDDS_PREPAINT ; Before the paint cycle begins ConsoleWrite( "Stage 1: CDDS_PREPAINT" & @CRLF ) Return $CDRF_NOTIFYITEMDRAW + _ ; Stage 2 will be carried out $CDRF_NOTIFYPOSTPAINT ; Stage 6 will be carried out Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window before an item is painted Return $CDRF_NOTIFYPOSTPAINT ; Notify the parent window after the paint cycle is complete ; Stage 2 Case $CDDS_ITEMPREPAINT ; Before an item is painted ConsoleWrite( "Stage 2: CDDS_ITEMPREPAINT" & @CRLF ) Return $CDRF_NOTIFYSUBITEMDRAW + _ ; Stage 3 will be carried out $CDRF_NOTIFYPOSTPAINT ; Stage 5 will be carried out Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window before a subitem is painted Return $CDRF_NOTIFYPOSTPAINT ; Notify the parent window after an item is painted ; Stage 3 Case BitOR( $CDDS_ITEMPREPAINT, _ $CDDS_SUBITEM ) ; Before a subitem is painted ConsoleWrite( "Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM" & @CRLF ) Return $CDRF_NOTIFYPOSTPAINT ; Stage 4 will be carried out Return $CDRF_NOTIFYPOSTPAINT ; Notify the parent window after a subitem is painted ; Stage 4 Case BitOR( $CDDS_ITEMPOSTPAINT, _ $CDDS_SUBITEM ) ; After a subitem has been painted ConsoleWrite( "Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM" & @CRLF ) ; Stage 5 Case $CDDS_ITEMPOSTPAINT ; After an item has been painted ConsoleWrite( "Stage 5: CDDS_ITEMPOSTPAINT" & @CRLF ) ; Stage 6 Case $CDDS_POSTPAINT ; After the paint cycle is complete ConsoleWrite( "Stage 6: CDDS_POSTPAINT" & @CRLF ) EndSwitch Case $NM_KILLFOCUS If $fListViewHasFocus Then GUICtrlSendMsg( $idListView, $LVM_REDRAWITEMS, 0, $iItems - 1 ) $fListViewHasFocus = 0 EndIf Case $NM_SETFOCUS If Not $fListViewHasFocus Then _ GUICtrlSendMsg( $idListView, $LVM_REDRAWITEMS, 0, $iItems - 1 ) $fListViewHasFocus = 2 EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ; WM_ACTIVATE message handler Func WM_ACTIVATE( $hWnd, $iMsg, $wParam, $lParam ) #forceref $iMsg, $lParam If $hWnd = $hGui Then _ $fListViewHasFocus = BitAND( $wParam, 0xFFFF ) ? 1 : 0 Return $GUI_RUNDEFMSG EndFunc Code is added to check when GUI and listview receives and loses focus. This is important in the other examples. Output in SciTE console immediately after example is opened: Stage 1: CDDS_PREPAINT Stage 2: CDDS_ITEMPREPAINT Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 5: CDDS_ITEMPOSTPAINT Stage 2: CDDS_ITEMPREPAINT Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 5: CDDS_ITEMPOSTPAINT Stage 2: CDDS_ITEMPREPAINT Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 3: CDDS_ITEMPREPAINT, CDDS_SUBITEM Stage 4: CDDS_ITEMPOSTPAINT, CDDS_SUBITEM Stage 5: CDDS_ITEMPOSTPAINT Stage 6: CDDS_POSTPAINT AutoIt message loop <<<<<<<<<<<<<<<<<<<<< Note that the entire custom draw process from stage 1 to 6 is not interrupted by the AutoIt message loop. The other examples are all based on the reference example. Examples This is common to all examples. First line in item texts is stored directly in the listview. Additional lines are stored in a global array named $aLines. Index in the array is item ID as returned by GUICtrlCreateListViewItem and stored in ItemParam internally in listview memory. Item texts and background is drawn with custom code. Other item elements and background is drawn with default code. In all examples LVS_SINGLESEL style is removed to be able to select multiple items. This is a picture of example E: Example 2, 3 and 4 are simple examples. Example 5 and 6 deals with subitem icons and colors. Example 7 about listview notifications shows a way to catch double click and Enter key. A dummy control is used to forward the double click event to AutoIt main message loop to avoid lengthy or blocking code in WM_NOTIFY function. Example 8 and 9 shows how to respond to header notifications and how to rearrange columns by dragging header items with the mouse. In both examples LVS_EX_HEADERDRAGDROP extended style is added to the listview. When columns are rearranged, header item index and listview subitem index is always the same independent of column position, while header item order changes depending on column position. Because the header is a child control of the listview, the listview must be subclassed to catch header notifications. Subclassing is implemented with the four functions SetWindowSubclass, GetWindowSubclass, RemoveWindowSubclass and DefSubclassProc (all implemented in WinAPIShellEx.au3). Since we are subclassing a header control contained in a listview this issue must be taking into account. Note that the subclass callback function is only running while the primary mouse button is pressed on the header. This means no performance impact on the listview eg. when you are dragging the scroll bar. This is important for a custom drawn listview. Quite a lot of extra code is added (most easily seen in example 9) to fix an issue due to column 0 and other columns have different left margins. When first column is moved to another position there is a white gap between columns for selected rows (Windows XP), or the text is painted too close to the left edge of the item (Windows 7). The problem is seen in the picture to the right where the two first columns are swapped: LVS_EX_HEADERDRAGDROP style is only used in example 8 and 9. Usage of a multi-line header is demonstrated in example A and B. See Custom/owner drawn multi-line header in ListView for more information. Example C shows a method to deal with focus issues when more controls (here just a single button) are added to the GUI. When the listview has focus selected items are drawn with the dark blue background color. The problem arises if the listview and GUI loses focus eg. to Calculator. When focus is lost selected items are drawn with the button face background color. If GUI receives focus again by clicking the button (and not the listview), selected items are first very briefly redrawn with the dark blue background color (it seems like a blink) and then with the correct button face background color. To avoid this issue a hidden label control is added to the GUI. Immediately before the GUI loses focus, focus is moved from the listview to the label. In example D items are added with the commands _GUICtrlListView_AddItem and _GUICtrlListView_AddSubItem. In all examples an array is used to store the multi-line item texts. The array contains all lines except the first line which is stored directly in the listview. This example shows how to manually store array row index in ItemParam when items are added with _GUICtrlListView_AddItem and _GUICtrlListView_AddSubItem. Inspiration for example E about large images in first column (see picture above) comes from this thread. In example E the images are used to increase the height of the listview items instead of a text font. Because it's large 128x128 pixel images there is plenty of room in subitems in second and third column. In all examples 15 lines of code is used to repaint the first line item text. The text that was painted by default code in middle of the item is first deleted by filling the item with the background color. Then the text is extracted from the listview and repainted in top of item. This code can be avoided by storing all text lines in the array. This is demonstrated in example F. This makes the custom draw code faster. Performance considerations In a custom drawn (or owner drawn or virtual) listview performance considerations are important because the custom drawing (or owner drawing or data display) is performed by AutoIt code. In a normal listview drawing and data display is performed by compiled C++ code in ComCtl32.dll. Lengthy and slow code in NM_CUSTOMDRAW Case statements (or WM_DRAWITEM functions or LVN_GETDISPINFO Case statements) should be avoided. Perform as many calculations as possible before the repetitive and fast executions of these code blocks. Use static variables to avoid repeating the same calculation again and again. Executing a function directly with DllCall or GUICtrlSendMsg is faster than executing the same function through an implementation in an UDF. Simple GDI functions are faster than more advanced GDI+ functions. Use different drawing stages to optimize custom drawing. The CDDS_PREPAINT stage is only performed once for the entire drawing process. The CDDS_ITEMPREPAINT stage is performed once per item. The stage given by BitOR( CDDS_ITEMPREPAINT, CDDS_SUBITEM ) is performed once per subitem including subitem 0. Default drawing should be used as much as possible, because the code is running in ComCtl32.dll. In a listview the time it takes to update all visible rows is proportional to the number of visible rows. Reducing the height of the list view and thus the number of visible rows improves performance. Especially in a custom drawn (or owner drawn or virtual) listview. ListviewMultilineItems.7z 1) Custom draw stages.au3 2) Two-line listview items.au3 3) Three-line listview items.au3 4) First column checkbox and icon.au3 5) Check boxes and icons.au3 6) Background and text colors.au3 7) ListView notifications.au3 8) Header notifications.au3 9) Rearrange columns.au3 A) Multi-line header 1.au3 A) Multi-line header 2.au3 C) Button control.au3 D) _GUICtrlListView_AddItem.au3 E) Large images in first column.au3 F) Storing all lines in array.au3 GuiHeaderEx.au3 GuiListViewEx.au3 ListViewCustomDraw.au3 Images\ 8 images for example E You need AutoIt 3.3.10 or later. Tested on Windows 7 32/64 bit and Windows XP 32 bit. Comments are welcome. Let me know if there are any issues. (Set tab width = 2 in SciTE to line up comments by column.) ListviewMultilineItems.7z1 point -
I think the code in both _GUICtrlTreeView_ClickItem64() and _GUICtrlTreeView_DisplayRectEx64() also works as 32 bit code. However, the 32 bit code has not been tested. So I would think that _GUICtrlTreeView_ClickItem64() and _GUICtrlTreeView_DisplayRectEx64() can be renamed to _GUICtrlTreeView_ClickItem() and _GUICtrlTreeView_DisplayRectEx() and replace the old functions.1 point
-
Virtual listviews for huge number of rows
pixelsearch reacted to LarsJ for a topic
In your code above, there is no immediate benefit to the subclassing technique. However, if you change the code to a UDF version, there is an advantage to the subclassing technique as you can avoid conflicts between WM_COMMAND and WM_NOTIFY message handles in both the UDF code and the user code. The performance impact of these tests will be the same for both a large and a small array because only visible rows are updated. If the listview contains 40 visible rows and 10 columns, then 400 items/subitems will be updated when you e.g. press PageUp/Down. It'll be the same for both a large and a small array. 400 simple tests to refresh an entire page will hardly be a problem. In a WM_NOTIFY message handler with a very large number of messages, one must definitely pay attention to the performance of the code. Implementing custom draw code in a virtual listview will generate both a very large number of $LVN_GETDISPINFOW and $NM_CUSTOMDRAW notifications. As demonstrated in the "Too much code" section here, you can easily execute more code than there is time for with a subsequent crash as a consequence. If one insists on keeping all the code, the only resort is probably to use compiled code. Therefore, it's advantageous to use arrays as indexes in $LVN_GETDISPINFOW and $NM_CUSTOMDRAW code instead of DllStructs because arrays are faster than DllStructs. Fortunately, there is a very fast method to convert a DllStruct of integers into a 1d array. The method is based on the techniques in Accessing AutoIt Variables. Instead of a pure AutoIt loop, a loop is executed in the internal AutoIt code in relation to these COM conversions. And this loop runs very fast as true compiled code: #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include <Array.au3> #include "AccVars.au3" Global $tIndex = DllStructCreate( "int[2000000]" ) For $i = 1 To 2000000 DllStructSetData( $tIndex, 1, $i-1, $i ) Next Global $iRows $iRows = 100000 Runtimes() $iRows = 250000 Runtimes() $iRows = 500000 Runtimes() $iRows = 750000 Runtimes() $iRows = 1000000 Runtimes() $iRows = 2000000 Runtimes() Func Runtimes() Local $s = StringRegExpReplace( $iRows, "(\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))", "\1,") ConsoleWrite( StringFormat( "%-30s", $s & " rows" ) & @CRLF ) ConsoleWrite( StringFormat( "%-30s", "Copy $tIndex to $aArray " ) & @CRLF ) ConsoleWrite( StringFormat( "%-30s", "--------------------------" ) & @CRLF ) ; AutoIt loop Local $hTimer = TimerInit() Local $aArray1[$iRows] For $i = 0 To $iRows - 1 $aArray1[$i] = DllStructGetData( $tIndex, 1, $i+1 ) Next ConsoleWrite( StringFormat( "%-30s", "AutoIt loop: " & StringFormat( "%9.4f", TimerDiff( $hTimer ) ) ) & @CRLF ) ; COM conversions $hTimer = TimerInit() Local $aArray2 = IntStructToArray() ConsoleWrite( StringFormat( "%-30s", "COM conversions: " & StringFormat( "%9.4f", TimerDiff( $hTimer ) ) ) & @CRLF & @CRLF ) If $iRows = 100000 Then _ArrayDisplay( $aArray2 ) #forceref $aArray1 EndFunc Func IntStructToArray() Local $aArray AccessVariables01( IntStructToArrayMtd, $aArray ) Return $aArray EndFunc ; DllStruct of ints --> 1D array Func IntStructToArrayMtd( $pvArray ) ; Create SafeArray of integers Local $tSafeArrayBound = DllStructCreate( $tagSAFEARRAYBOUND ) DllStructSetData( $tSafeArrayBound, "cElements", $iRows ) Local $pSafeArray = SafeArrayCreate( $VT_I4, 1, $tSafeArrayBound ) ; Copy data from DllStruct to SafeArray Local $pSafeArrayData SafeArrayAccessData( $pSafeArray, $pSafeArrayData ) DllCall( "kernel32.dll", "none", "RtlMoveMemory", "struct*", $pSafeArrayData, "struct*", $tIndex, "ulong_ptr", $iRows*4 ) SafeArrayUnaccessData( $pSafeArray ) ; Store SafeArray in $pvArray (pointer to variant) DllStructSetData( DllStructCreate( "word", $pvArray ), 1, $VT_ARRAY + $VT_I4 ) DllStructSetData( DllStructCreate( "ptr", $pvArray + 8 ), 1, $pSafeArray ) ; On function exit internal AutoIt COM conversions will convert the safearray ; of integers in $pvArray to a safearray of variants ie. a true AutoIt array. EndFunc Runtimes: 64 bit code on Windows 7 ========================== 100,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 114.6483 COM conversions: 4.4370 250,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 284.5634 COM conversions: 11.1708 500,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 561.3047 COM conversions: 22.2186 750,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 838.6758 COM conversions: 32.9380 1,000,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 1115.1990 COM conversions: 43.7237 2,000,000 rows Copy $tIndex to $aArray -------------------------- AutoIt loop: 2227.6890 COM conversions: 87.8566 IntStructToArray.7z1 point -
You could also use _ArrayFindAll #include <Array.au3> $sString = "17000220064602" $aString = StringSplit($sString, "", 1) $aResult = _ArrayFindAll($aString, "0") _ArrayDisplay($aResult)1 point
-
@TheXman ok, i got it I thank you very much friends. These helped me.❤️1 point
-
... or also by scanning each char of the string using string functions $sString = "17000220064602" For $i = 1 To StringLen($sString) If StringMid($sString, $i, 1) = "0" Then ConsoleWrite($i & " - ") Next1 point
-
Click on "Reveal hidden contents" in my previous post. And next time, don't say what didn't work without showing it.1 point
-
Virtual listviews for huge number of rows
pixelsearch reacted to Lion66 for a topic
Hi pixelsearch. Good examples. I admire how you understand this issue and modify your scripts. Inspired by your examples, I thought it was possible to connect one of your versions, including sorting, with marking the resulting yellow color, as in this thread: https://www.autoitscript.com/forum/topic/179112-incremental-search-in-owner-drawn-listview/#comments But my programming level is not sufficient for such a task and it did not work. If you find it possible to please us with the solution of this task, it would be interesting to see such a modification. Thank you.1 point -
Multiline String frome a txt file
AnnoyingClown reacted to Danp2 for a topic
@AnnoyingClown I think I found a way to make this work with a modified version of _WD_SetElementValue. Please try the following and report back -- #include "wd_core.au3" #include "wd_helper.au3" Local $sDesiredCapabilities, $sSession Local $sDelimiter = '\r\n' ;SetupChrome() SetupGecko() _WD_Startup() $sSession = _WD_CreateSession($sDesiredCapabilities) Local $sElement, $sText = '1234' & $sDelimiter & '5678' & $sDelimiter & '90' & $sDelimiter _WD_Navigate($sSession, "https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_textarea") _WD_LoadWait($sSession, 2000) $sElement = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//iframe[@id='iframeResult']") _WD_FrameEnter($sSession, $sElement) $sElement = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//textarea[@id='w3review']") _WD_SetElementValueNew($sSession, $sElement, $sText, $_WD_OPTION_Advanced) Func SetupChrome() _WD_Option('Driver', 'chromedriver.exe') _WD_Option('Port', 9515) _WD_Option('DriverParams', '--log-path="' & @ScriptDir & '\chrome.log"') $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"goog:chromeOptions": {"w3c": true, "excludeSwitches": [ "enable-automation"], "useAutomationExtension": false, "prefs": {"credentials_enable_service": false, "profile.password_manager_enabled": false}}}}}' EndFunc Func SetupGecko() _WD_Option('Driver', 'geckodriver.exe') _WD_Option('DriverParams', '--log trace') _WD_Option('Port', 4444) $sDesiredCapabilities = '{"capabilities": {"alwaysMatch": {"browserName": "firefox", "acceptInsecureCerts":true}}}' EndFunc ;==>SetupGecko Func _WD_SetElementValueNew($sSession, $sElement, $sValue, $iStyle = Default) Local Const $sFuncName = "_WD_SetElementValue" Local $sResult, $iErr, $sScript, $sJsonElement If $iStyle = Default Then $iStyle = $_WD_OPTION_Standard If $iStyle < $_WD_OPTION_Standard Or $iStyle > $_WD_OPTION_Advanced Then $iStyle = $_WD_OPTION_Standard Switch $iStyle Case $_WD_OPTION_Standard $sResult = _WD_ElementAction($sSession, $sElement, 'value', $sValue) $iErr = @error Case $_WD_OPTION_Advanced $sScript = "Object.getOwnPropertyDescriptor(arguments[0].__proto__, 'value').set.call(arguments[0], arguments[1]);arguments[0].dispatchEvent(new Event('input', { bubbles: true }));" $sJsonElement = '{"' & $_WD_ELEMENT_ID & '":"' & $sElement & '"}' $sResult = _WD_ExecuteScript($sSession, $sScript, $sJsonElement & ',"' & $sValue & '"') $iErr = @error EndSwitch Return SetError(__WD_Error($sFuncName, $iErr), 0, $sResult) EndFunc Note: This will still error out with @CRLF or similar with Firefox, so you need to translate these to '\n' or '\r\n' prior to calling the function.1 point -
Hi everyone, Some good news for you among all the gloom of these virus-ridden times: Nine, Subz and Danyfirex have accepted the invitation to become MVPs. Please join me in congratulating them on their new status in our community. Keep safe out there, M231 point