Leaderboard
Popular Content
Showing content with the highest reputation on 10/13/2019 in all areas
-
The main problem with a normal and also a virtual listview with many columns is that performance gets worse and worse as the number of columns increases. And the performance decrease starts at a relatively low number of columns and is significant. Examples\Reference.au3 in the zip-file in bottom of post is a reference example. It's a virtual listview with 1,000 rows and 100 columns. An owner drawn listview with the LVS_OWNERDRAWFIXED style is the listview that supports many columns. An owner drawn listview is updated through WM_DRAWITEM messages. One WM_DRAWITEM message is generated per visible listview row. No additional messages are generated for the listview columns. If $iColFirst and $iColLast are the first and last visible listview column, then a listview row with index $itemID can be updated with this code: ; Draw visible columns/subitems For $i = $iColFirst To $iColLast $sSubItmText = $itemID & " / " & $i DllStructSetData( $tRect, 2, $i ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $idListView, $LVM_GETSUBITEMRECT, $itemID, $pRect ) If Not $i Then DllStructSetData( $tRect, 3, DllStructGetData( $tRect, 1 ) + GUICtrlSendMsg( $idListView, $LVM_GETCOLUMNWIDTH, 0, 0 ) ) DllStructSetData( $tRect, 1, DllStructGetData( $tRect, 1 ) + 6 ) ; Left margin DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sSubItmText, "int", StringLen( $sSubItmText ), "ptr", $pRect, "int", 0 ) ; _WinAPI_DrawText Next In an owner drawn listview you have to handle the subitem rectangles yourself and update the subitem texts with GDI functions like DrawText. But eg. grid lines are drawn automatically through default code. $iColFirst and $iColLast can be calculated in a WM_NOTIFY message handler through LVN_ENDSCROLL notifications when listview columns are scrolled horizontally: Case $LVN_ENDSCROLL If Not DllStructGetData( DllStructCreate( $tagNMLVSCROLL, $lParam ), "DX" ) Then Return $GUI_RUNDEFMSG ; Horizontal scrollbar only ; First and last visible column in ListView GUICtrlSendMsg( $idListView, $LVM_SUBITEMHITTEST, 0, $pHitTestFirst ) $iColFirst = DllStructGetData( $tHitTestFirst, "SubItem" ) GUICtrlSendMsg( $idListView, $LVM_SUBITEMHITTEST, 0, $pHitTestLast ) $iColLast = DllStructGetData( $tHitTestLast, "SubItem" ) ; Redraw ListView GUICtrlSendMsg( $idListView, $LVM_REDRAWITEMS, 0, $iRows - 1 ) ; Redraw ListView items, Forces $WM_DRAWITEM messages to update ListView control In the examples the owner drawn style is combined with the virtual style, LVS_OWNERDATA, to be able to dynamically feed the listview with data directly from a data source. Medium number of columns If the number of columns is limited to a few hundred, the built-in listview header can support the columns. The examples are stored in Examples\Medium\ in the zip-file. Run the examples in SciTE with F5. FirstTest.au3 demonstrates the code snippets above. TooManyCols.au3 shows what happens if the listview contains more columns than the built-in header is able to support. Drag the thumb in the horizontal scrollbar all the way to the right to see that the header items are simply missing. In SelectedRows1.au3 you can select one or more rows. In SelectedRows2.au3 attempts have been made to reduce the flicker that occurs when the thumb in the horizontal scrollbar is swiftly dragged back and forth. More about flicker below. Checkboxes.au3 and IconImages.au3 shows how to add checkboxes and icons. By drawing everything yourself, you can arbitrarily decide which columns should be provided with checkboxes, icons or both. FillFromArray1.au3 and FillFromArray2.au3 demonstrates how to fill a listview from an array. Large number of columns For a large number of columns, 100,000 columns in most examples, you need to create the header control yourself with the functions in GuiHeader.au3. The header control isn't built into the listview but is an independent child window. The idea is to only show header items for visible listview columns. In ReSizeColumns.au3 listview columns can be resized to a minimum of 50 pixels. This makes a maximum of approx. 20 visible columns in the listview and therefore also a maximum of 20 header items. The first header item is always the header item with index 0. The second header item is always the header item with index 1. And so on. Header item texts (and header item widths if needed) are dynamically updated when listview columns are scrolled horizontally. The examples are stored in Examples\Large\ in the zip-file. There are three subfolders named UserDrawn, OwnerDrawn and CustomDrawn. The names refer to the technique used to draw the header control. The listview is still owner drawn. In UserDrawn\FirstTest.au3 the header control is updated directly in the LVN_ENDSCROLL section of the WM_NOTIFY message handler. It's simple code, but it generates a lot of flicker in the header control when the thumb in the horizontal scrollbar is dragged quickly back and forth. To avoid that much flicker, you can use either an owner or custom drawn header. OwnerDrawn\FirstTest.au3 shows an owner drawn header control. Because an owner drawn header doesn't directly support themes and because the code in the WM_DRAWITEM message handler becomes a bit more complicated when there are two owner drawn controls, a custom drawn header is the preferred technique. Custom drawn header The basic code is shown in CustomDrawn\FirstTest.au3. SelectedRows1.au3 implements selected items. If you select 10 items in a row so that a completely blue rectangle is created, and scrolls very quickly back and forth in the horizontal scrollbar, a lot of flicker occurs in the listview, especially in the blue rectangle. The flicker looks less violent if there are no selected rows. In SelectedRows2.au3 attempts have been made to reduce flicker. If you keep an eye on the header control when scrolling quickly in the horizontal scrollbar, the header is updated much fewer times than the listview. This generates much less flicker in the header. The reason why the header is updated fewer times is because the header isn't built into the listview but is an independent child window. The LVN_ENDSCROLL code updates the header and listview equally many times. But the header has to wait for WM_PAINT messages before it's updated. And a WM_PAINT message isn't generated until there is a delay in the number of WM_DRAWITEM messages. Ie. when there is a slight pause in the movement of the thumb in the horizontal scrollbar. The idea to reduce flicker in the listview is only to update the subitem texts most times, and to update visual features and effects eg. selected rows that is the cause of the most flicker very few times. This also improves performance during fast scrolls in the horizontal scrollbar. It doesn't take a lot of code just to update the subitem texts. Updating visual features and effects requires a lot more code. To get an overview of the Windows messages and notifications and the order of the messages, a message monitor is indispensable. ReSizeColumns.au3 demonstrates how to resize listview columns. Header item widths and texts are dynamically updated through NM_CUSTOMDRAW notifications when listview columns are scrolled horizontally. When a header item width is updated, it'll automatically generate new NM_CUSTOMDRAW notifications to update the text of the current header item and all header items to the right of the current one. The critical code is to avoid an endless loop of NM_CUSTOMDRAW notifications. Here too, a message monitor is indispensable. GoToRowColumn.au3 implements code to go to a spicific row/column in the listview. Right click ListView, update row/column numbers in GUI and press Enter. OneMillionColumns.au3 is an example with 1,000,000 columns. This example should be run on Windows 10 as 64 bit code only. ShowRowNumbers.au3. If row numbers are needed in a standard few-column listview, the first column is usually used for row numbers. But this doesn't work well in a listview with many columns. Here it's better to use an extra listview to the left for row numbers. When scrolling with the vertical scrollbar, the row numbers are updated accordingly. Note that the row numbers are updated discretely in the same way as the header when scrolling in the horizontal scroll bar. There is no keyboard support in this example. If you press End to go to the last row, the row numbers are not updated. I'll add a new example with keyboard support. KeyboardNavigation1.au3 (as well as 2 and 3) has keyboard support to navigate the listview with Home, End, PageUp and PageDown keys. Press Shift and one of the keys for horizontal navigation. As there is no selected row or cell in the examples, there is no support for the arrow keys. Especially Shift+Pageup/Down generates a lot of flicker in KeyboardNavigation1.au3. KeyboardNavigation2.au3 and KeyboardNavigation3.au3 are attempts to reduce flicker. In KeyboardNavigation2.au3, auto repeat of the PageUp/Down keys is disabled. In KeyboardNavigation3.au3, only the top/left row/column is updated when PageUp/Down is kept pressed constantly. Note that in these listviews with both many rows and many columns, performance and flicker appear to be two sides of the same coin. The better performance the less flicker and vice versa. MarkCurrentCell1.au3. Click to mark a cell. Click again to unmark the cell. No keyboard support. It looks like this: MarkCurrentCell2-4.au3 has keyboard support through the arrow keys as well as Home, End, PageUp and PageDown. Use Shift+Home/End/PageUp/PageDown for horizontal navigation. MarkCurrentCell3-4.au3 is an attempt to reduce flicker when PageUp/Down is kept pressed constantly. EditMarkedCell.au3 is based on MarkCurrentCell2.au3 and can be used to edit the text in the marked cell. Double-click or press Enter to edit the cell text. Press Esc or Enter in the edit box to cancel or accept the new cell text. ResizeGui.au3 is based on ShowRowNumbers.au3 and demonstrates a resizable GUI. Usage of many-column listviews A many-column listview with built-in header that supports a medium number of columns can be used as a regular listview. An ordinary listview performs poorly when there are many columns. This many-column listview based on owner drawn and virtual listview styles performs much better with the ability to optimize performance in specific situations. It may be difficult to imagine a usage for many-column listviews with a custom header that supports a large number of columns. May be such a listview can be better regarded as a kind of grid control, that eg. can be used for visual editing of an array or SQLite table. You can imagine a 2d-array with 1000 rows and 1000 columns. The data source in EditMarkedCell.au3 is exactly such an array. Zip-file The zip-file contains source files for examples and includes. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. The examples should run on all Windows versions. If necessary, reduce the number of rows and especially columns on older versions. Comments are welcome. Let me know if there are any issues. ManyColumns.7z2 points
-
Here is an old goodie from ms demonstrating concepts behind multithreading and using mutexes to control sharing the screen. Its unfortunately just a console application so you have to press compile (f7) to run (can get annoying if you want to play with the code) but still pretty cool :). Each little question mark box (could be any character (used to be a smiley face in win 7)) is its own thread keeping track of its own coordinates. Each thread shares the screenmutex by kinda waiting in line for ownership of it. When the thread gains control it updates the screen, then releases the mutex for the next thread. First I wrote it in pure autoit to confirm all working as expected. The Console functions actually threw me for a loop. They actual want the whole value of the coord structs and not a ptr to it so that "struct" without a * was a little uncommon. Below au3 code is just the lonely cell bouncing around. Func _BounceAU3() ;set a random starting id. we use this to rotate the colors Local $iMyID = Random(1, 15, 1) Local $tMyCell = DllStructCreate('char mc'), $tOldCell = DllStructCreate('char oc') Local $tMyAttrib = DllStructCreate('word ma'), $tOldAttrib = DllStructCreate('word oa') Local $tCoords = DllStructCreate($tagCOORD), $tOld = DllStructCreate($tagCOORD) Local $tDelta = DllStructCreate($tagCOORD) ;Random start and delta values $tCoords.X = Random(0, 119, 1) $tCoords.Y = Random(0, 29, 1) $tDelta.X = Random(-3, 3, 1) $tDelta.Y = Random(-3, 3, 1) ;set character/cell attributes $tMyCell.mc = $iMyID > 16 ? 0x01 : 0x02 ; doesnt seem to make a differnce in windows 10 $tMyAttrib.ma = BitAND($iMyID, 0x0F) ; Set the character color Do ;check the last position values DllCall('kernel32.dll', "bool", "ReadConsoleOutputCharacter", "handle", $g_hStdHandle, "struct*", $tOldCell, "dword", 1, "struct", $tOld, "dword*", 0) DllCall('kernel32.dll', "bool", "ReadConsoleOutputAttribute", "handle", $g_hStdHandle, "struct*", $tOldAttrib, "dword", 1, "struct", $tOld, "dword*", 0) ;if the last postion was this cell, blank/empty the cell. (Otherwise its been taken over by another thread) If ($tOldCell.oc = $tMyCell.mc) And ($tOldAttrib.oa = $tMyAttrib.ma) Then DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $g_hStdHandle, "byte*", 0x20, "dword", 1, "struct", $tOld, "dword*", 0) EndIf ;write the current cell DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $g_hStdHandle, "struct*", $tMyCell, "dword", 1, "struct", $tCoords, "dword*", 0) DllCall('kernel32.dll', "bool", "WriteConsoleOutputAttribute", "handle", $g_hStdHandle, "struct*", $tMyAttrib, "dword", 1, "struct", $tCoords, "dword*", 0) ;update coords $tOld.X = $tCoords.X $tOld.Y = $tCoords.Y $tCoords.X += $tDelta.X $tCoords.Y += $tDelta.Y ;change directions if we are out of bounds If $tCoords.X < 0 Or $tCoords.X >= 120 Then $tDelta.X *= -1 If $tCoords.Y < 0 Or $tCoords.Y >= 30 Then $tDelta.Y *= -1 Sleep(75) Until GUIGetMsg() = -3 EndFunc ;==>_BounceAU3 From there the that function converted into assembly so we can call as a thread. The only real differences are the extra parameters we passing as a structure and I also generate the random starting values in autoit instead, then pass them to the function. Here is what the main assembly function looks like. I added comments for each peice of code from au3 that we are translating: _('procf _Bounce uses ebx, pParms') ; ; create the local variables _(' locals') _(' BlankCell db 32') ; this first group covers the variables from the original script _(' MyCell db ?') _(' OldCell db ?') _(' MyAtt dw ?') _(' OldAtt dw ?') _(' tCoords COORD') _(' tDelta COORD') _(' tOld COORD') _(' bytesread dw ?') ; _(' iMyID dw ?') ; this group of local vars cover holding all the other paramerters we are passing in tParms _(' g_hScreenMutex dd ?') _(' g_hRunMutex dd ?') _(' g_hStdHandle dd ?') _(' pfWaitForSingleObject dd ?') _(' pfReleaseMutex dd ?') _(' pfReadChar dd ?') _(' pfReadAttr dd ?') _(' pfWriteChar dd ?') _(' pfWriteAttr dd ?') _(' endl') ; ;all of these push/pops are to transfer the rest of variables from tParms structure to the local variables we created ;first mov the structure address into ebx _(' mov ebx, [pParms]') ; ; now push and pop the values into the variables ; use _winapi_displaystruct() to view all the offsets being used in the [ebx+offset] lines _(' pushw [ebx]') ; _(' popw word[tCoords+COORD.X]') _(' pushw word[ebx+2]') ; _(' popw word[tCoords+COORD.Y]') _(' pushw word[ebx+4]') ; _(' popw word[tDelta+COORD.X]') _(' pushw word[ebx+6]') ; _(' popw word[tDelta+COORD.Y]') _(' pushw word[ebx+8]') ; _(' popw word[iMyID]') _(' push dword[ebx+12]') ; _(' pop dword[g_hScreenMutex]') _(' push dword[ebx+16]') ; _(' pop dword[g_hRunMutex]') _(' push dword[ebx+20]') ; _(' pop dword[g_hStdHandle]') _(' push dword[ebx+24]') ; _(' pop dword[pfWaitForSingleObject]') _(' push dword[ebx+28]') ; _(' pop dword[pfReleaseMutex]') _(' push dword[ebx+32]') ; _(' pop dword[pfReadChar]') _(' push dword[ebx+36]') ; _(' pop dword[pfReadAttr]') _(' push dword[ebx+40]') ; _(' pop dword[pfWriteChar]') _(' push dword[ebx+44]') ; _(' pop dword[pfWriteAttr]') _('.if word[iMyID] > 16') ; $tMyCell.mc = $iMyID > 16 ? 0x01 : 0x02 (no difference in windows 10) _(' mov word[MyCell], 1') _('.else') _(' mov word[MyCell], 2') _('.endif') ; _('pushw word[iMyID]') ; $tMyAttrib.ma = BitAND($iMyID, 0x0F) _('popw word[MyAtt]') _('and word[MyAtt], 15') ; _('.repeat') ; do ; ; Wait infinetly for the screen mutex to be available, then take ownership _(' invoke pfWaitForSingleObject, [g_hScreenMutex], -1') ; ; DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $hStdHandle, "byte*", 0x20, "dword", 1, "struct", $tOld, "dword*", 0) _(' invoke pfReadChar, [g_hStdHandle], addr OldCell, 1, dword[tOld], addr bytesread') ; _(' invoke pfReadAttr, [g_hStdHandle], addr OldAtt, 1, dword[tOld], addr bytesread') ; ; _(' mov al, byte[MyCell]') ;If ($tOldCell.oc = $tMyCell.mc) And ($tOldAttrib.oa = $tMyAttrib.ma) Then _(' mov cl, byte[MyAtt]') _(' .if (byte[OldCell] = al) & (byte[OldAtt] = cl)') _(' invoke pfWriteChar, [g_hStdHandle], addr BlankCell, 1, dword[tOld], addr bytesread') _(' .endif') ; ; DllCall('kernel32.dll', "bool", "WriteConsoleOutputCharacter", "handle", $hStdHandle, "struct*", $tMyCell, "dword", 1, "struct", $tCoords, "dword*", 0) _(' invoke pfWriteChar, [g_hStdHandle], addr MyCell, 1, dword[tCoords], addr bytesread') _(' invoke pfWriteAttr, [g_hStdHandle], addr MyAtt, 1, dword[tCoords], addr bytesread') ; _(' pushw word[tCoords+COORD.X]') ;$tOld.X = $tCoords.X _(' popw word[tOld+COORD.X]') ; _(' pushw word[tCoords+COORD.Y]') ;$tOld.Y = $tCoords.Y _(' popw word[tOld+COORD.Y]') _(' mov ax, word[tDelta+COORD.X]') ; $tCoords.X += $tDelta.X _(' add word[tCoords+COORD.X], ax') ; _(' mov ax, word[tDelta+COORD.Y]') ; $tCoords.Y += $tDelta.Y _(' add word[tCoords+COORD.Y], ax') ; ; If $tCoords.X < 0 Or $tCoords.X >= 120 Then $tDelta.X *= -1 _(' .if (word[tCoords+COORD.X] < 0 | word[tCoords+COORD.X] >= 120)') _(' neg word[tDelta+COORD.X]') _(' .endif') _(' .if (word[tCoords+COORD.Y] < 0 | word[tCoords+COORD.Y] >= 30)') _(' neg word[tDelta+COORD.Y]') _(' .endif') ; ; release the screen mutex _(' invoke pfReleaseMutex, [g_hScreenMutex]') ; ; wait 100 ms for the Runmutex to be available. _(' invoke pfWaitForSingleObject, [g_hRunMutex], 100') ; ; a return of 258 means it timed out waiting and that the run mutex (owned by the main autoit thread) is still alive. ; when the run mutex handle gets closed this will return a fail or abandonded. _('.until eax <> 258') ; ;exit thread _(' ret') _('endp') And finally how we call that assembled function from autoit to create the theads: ;create mutex for sharing the screen thats not owned by main thread Global $g_hScreenMutex = _WinAPI_CreateMutex('', False) ; ;create mutex that tells the threads to exit that is owned by main thread Global $g_hRunMutex = _WinAPI_CreateMutex('', True) ... ... ;assemble function Local $tBinExec = _fasmg_Assemble($g_sFasm, False) ;Local $tBinExec = _fasmg_CompileAu3($g_sFasm) If @error Then Exit (ConsoleWrite($tBinExec & @CRLF)) ;this is struct is for all the values Im passing to the thread. ;this will hold are random start x,y,delta values, handles, and pointers to functions called within the thread $tParms = DllStructCreate('short start[4];word myid;dword hands[3];ptr funcs[6]') $tParms.start(1) = Random(0, 119, 1) $tParms.start(2) = Random(0, 29, 1) $tParms.start(3) = Random(-3, 3, 1) $tParms.start(4) = Random(-3, 3, 1) $tParms.myid = 1 $tParms.hands(1) = $g_hScreenMutex $tParms.hands(2) = $g_hRunMutex $tParms.hands(3) = $g_hStdHandle $tParms.funcs(1) = _GPA('kernel32.dll', 'WaitForSingleObject') $tParms.funcs(2) = _GPA('kernel32.dll', 'ReleaseMutex') $tParms.funcs(3) = _GPA('kernel32.dll', 'ReadConsoleOutputCharacterA') $tParms.funcs(4) = _GPA('kernel32.dll', 'ReadConsoleOutputAttribute') $tParms.funcs(5) = _GPA('kernel32.dll', 'WriteConsoleOutputCharacterA') $tParms.funcs(6) = _GPA('kernel32.dll', 'WriteConsoleOutputAttribute') ;create 128 threads with different start values and colors for each one For $i = 1 To 128 $tParms.myid = $i $tParms.start(1) = Random(0, 119, 1) $tParms.start(2) = Random(0, 29, 1) $tParms.start(3) = Random(-3, 3, 1) $tParms.start(4) = Random(-3, 3, 1) If $tParms.start(3) + $tParms.start(4) = 0 Then $tParms.start(3) = (Mod(@MSEC, 2) ? 1 : -1) ; adjusting non-moving (0,0) delta values.. DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "struct*", $tBinExec, "struct*", $tParms, "dword", 0, "dword*", 0) Sleep(50) Next MsgBox(262144, '', '128 Threads Created') ;Close the run mutex handle. This will cause all the threads to exit _WinAPI_CloseHandle($g_hRunMutex) _WinAPI_CloseHandle($g_hScreenMutex) MsgBox(262144, '', 'Mutex handles closed. All Threads should have exited') Exit The attachment below contains both the compiled and source assembly. To play with the assembly source you need to add the fasmg udf in my sig. The compiled version should not need anything. Let me know if you have any issues. Special thanks to @trancexx for teaching me this with her clock example Bounce.zip2 points
-
Hello. You can get it done doing few changes to the code in this thread. Saludos1 point
-
Just create a button that when pressed, you use GuiCtrlRead(<input1>) & GuiCtrlRead(<input2>) &... then use Control functions to focus and set the results to.1 point
-
ImageSearch DLL error return problem
Mbee reacted to mistersquirrle for a topic
I've used this as well, and I know that I've found several versions, so the easiest thing to do is provide what I've been using (attached). I mainly have used the _ImageSearchArea part, with transparency, and a call with it for me usually looks like this: Local $sFile = 'image.png' ; Path to the image file, we dont need to open it or get a handle or anything first Local $aRange[] = [4, 100, 100, 300, 300] ; Area to search, x1, y1, x2, y2 Local $aCoords[2] ; Resulting location of the found image, either top left or center of image based on second parameter Local $iShade = 10 ; 10 'shades' of variance, useful if the image is saved with compression, for example Local $sTrans = "0xFF0000" ; Red in the image is 'transparent', and isnt used in the image comparison. Useful if a section of the image could be different on each check Local $bIS $bIS = _ImageSearchArea($sFile, 1, $aRange[1], $aRange[2], $aRange[3], $aRange[4], $aCoords[0], $aCoords[1], $iShade, $sTrans) If $bIS Then ; Do the thing EndIf I currently use this in Windows 10 without a problem, and I believe that it's run as 32 bit, so not sure how the 64 bit performs. I haven't really ever had any issues with using it. Let me know if you want more of an explanation or full example. ImageSearch files.zip1 point