WildByDesign Posted Sunday at 12:44 PM Posted Sunday at 12:44 PM I already have a ListView that is working great and performant. Performant until adding the part which adds delay problem. I use WM_NOTIFY with Case $LVN_ITEMCHANGED to populate other areas of my GUI successfully with keyboard navigation and mouse clicks. Problem: There is one small part of my GUI that needs to be populated in this same method, but unfortunately it must rely on the STDOUT of another command line utility. So naturally, as expected, this causes a noticeable delay when navigating through each ListView item. I don't know if I need another script (compiled to exe) to run as a second process to run the command line utility with STDOUT and return the output back to the main process so that I don't cause the delay in the ListView. I understand that the control that I'm trying to populate will have a slight delay before populating and I am OK with that. I just don't want to hold up the ListView. I just don't know what is the most simplistic, most efficient way to go about this. It would be just one variable that would be used to populate the control and would essentially be True or False. I am not 100% sure if I absolutely need multi-process or not. I have thought about maybe storing the result (True or False) in a registry key or INI file and retrieving it. Thank you for your time. I am at a dead end right now on this one.
WildByDesign Posted Sunday at 12:47 PM Author Posted Sunday at 12:47 PM Also, can an AutoIt script (compiled to exe) that is already running receive command line parameters?
Nine Posted Sunday at 12:56 PM Posted Sunday at 12:56 PM I don't think multi-threading would help you since you are waiting for the answer of the other process. But without an actual test case script, it is just about what I can help. WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Reveal hidden contents Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy
argumentum Posted Sunday at 01:00 PM Posted Sunday at 01:00 PM (edited) On 3/30/2025 at 12:47 PM, WildByDesign said: that is already running receive command line parameters? Expand ...too late I'd make a GUI and master script, and IPC everything else. Edited Sunday at 04:20 PM by argumentum English WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Sunday at 01:48 PM Author Posted Sunday at 01:48 PM @argumentum Thank you for your response. I'm going to do some research into the IPC stuff later today. @Nine I was able to remove a lot of stuff out of my script so that I can post it here. $iMsstylesFileName is the label being populated with the theme Msstyle filename. This is populated with the GetMsstyles() func. This is populated instantly because there is no waiting for STDOUT on this one. $iAnswer is the label being populated with a True or False. But for the purpose of this example and not including an external binary, I am just getting the STDOUT from the "whoami" command line. This is populated with the IsMsstylesPatched() func. This is the one causing the delay with ListView because it is waiting on STDOUT from the "whoami" command line. If we comment out IsMsstylesPatched() then we can see how fast the ListView normally functions. Reveal hidden contents expandcollapse popup; *** Start added Standard Include files by AutoIt3Wrapper *** #include <Array.au3> #include <File.au3> #include <GuiListView.au3> #include <WinAPIInternals.au3> #include <WinAPIRes.au3> #include <AutoItConstants.au3> #include <FileConstants.au3> #include <FontConstants.au3> #include <GUIConstantsEx.au3> #include <ListViewConstants.au3> #include <StringConstants.au3> #include <StructureConstants.au3> #include <WindowsConstants.au3> ; *** End added Standard Include files by AutoIt3Wrapper *** #NoTrayIcon Global $ParsedThemeName, $aFileList, $sFilePath, $iMsstyles, $iMsstylesFind $aFileList = _FileListToArray(@WindowsDir & "\Resources\Themes", "*.theme", $FLTA_FILES, True) _ArrayDelete($aFileList, 0) $aFileList2 = _FileListToArray(@WindowsDir & "\Resources\Ease of Access Themes", "*.theme", $FLTA_FILES, True) _ArrayDelete($aFileList2, 0) $aFileList3 = _FileListToArray(@LocalAppDataDir & "\Microsoft\Windows\Themes", "*.theme", $FLTA_FILES, True) _ArrayDelete($aFileList3, 0) _ArrayConcatenate($aFileList, $aFileList2) _ArrayConcatenate($aFileList, $aFileList3) _ArrayColInsert($aFileList, 1) For $i = 0 To UBound($aFileList) - 1 $aFileList[$i][1] = $aFileList[$i][0] $sFilePath = $aFileList[$i][0] $sFilePath = ParseThemeName() $aFileList[$i][0] = StringReplace($aFileList[$i][0], $aFileList[$i][0], $sFilePath) Next _ArraySort($aFileList) $hGUI = GUICreate("ThemeToolX", 600, 800, -1, -1, $WS_SIZEBOX + $WS_SYSMENU + $WS_MINIMIZEBOX + $WS_MAXIMIZEBOX) GUISetFont(10, $FW_NORMAL, -1, "Segoe UI") $CapabilitiesList = GUICtrlCreateListView(" ", 20, 20, 400, 400, $LVS_NOCOLUMNHEADER + $LVS_SORTASCENDING + $LVS_SHOWSELALWAYS + $LVS_SINGLESEL) $hCapabilitiesList = GUICtrlGetHandle($CapabilitiesList) _GUICtrlListView_AddArray($hCapabilitiesList,$aFileList) _GUICtrlListView_SetColumnWidth($hCapabilitiesList, 0, $LVSCW_AUTOSIZE_USEHEADER) GUICtrlSendMsg($CapabilitiesList, $WM_CHANGEUISTATE, 65537, 0) $iMsstylesFileName = GUICtrlCreateLabel(" ", 20, 460, 500) $iAnswer = GUICtrlCreateLabel(" ", 20, 480, 500) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY2") GUISetState() Func ParseThemeName() ;Local $sFilePath = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes", "CurrentTheme") ; Get DisplayName from theme file $idDisplayName = StringRegExpReplace(fileread($sFilePath), '(?s).*DisplayName=(\N+).*', "$1") ; Search $idDisplayName for DisplayName with @ symbol $FilterName = StringInStr($idDisplayName, "@") ; FilterName = 1 means idDisplayName contains an @ symbol If $FilterName = 1 Then ; Get last 4 digits from $idDisplayName for DLL resource lookup $customString = StringRight($idDisplayName, 4) $customLoadDLL = _WinAPI_LoadLibrary (@SystemDir & "\themeui.dll") $customThemeName = _WinAPI_LoadString ( $customLoadDLL, $customString ) $customFreeDLL = _WinAPI_FreeLibrary ( $customLoadDLL ) Global $ParsedThemeName = $customThemeName Return $ParsedThemeName Else Global $ParsedThemeName = $idDisplayName Return $ParsedThemeName EndIf EndFunc Func GetMsstyles() ; Get Msstyles Path from theme file $iMsstylesFind = IniRead($iMsstyles, "VisualStyles", "Path", "default") $iMsstylesFind = StringReplace($iMsstylesFind, "%ResourceDir%", @WindowsDir & "\Resources") $iMsstylesFind = StringReplace($iMsstylesFind, "%SystemRoot%", @WindowsDir) $iMsstylesFind = StringReplace($iMsstylesFind, "resources", "Resources", 0, $STR_CASESENSE) $iMsstylesFind = StringReplace($iMsstylesFind, "themes", "Themes", 0, $STR_CASESENSE) $iMsstylesFind = StringReplace($iMsstylesFind, "WINDOWS", "Windows", 0, $STR_CASESENSE) ;ConsoleWrite($iMsstyles & @CRLF) GUICtrlSetData($iMsstylesFileName, $iMsstylesFind) EndFunc Func IsMsstylesPatched() GUICtrlSetData($iAnswer, " ") ; need to determine if msstyles is patched Local $o_Pid = Run(@ComSpec & " /c " & "whoami", @ScriptDir, @SW_HIDE, $STDOUT_CHILD) ProcessWaitClose($o_Pid) $out = StdoutRead($o_Pid) GUICtrlSetData($iAnswer, $out) EndFunc Func WM_NOTIFY2($hWnd, $iMsg, $iwParam, $ilParam) Local $hCapabilitiesList, $tNMHDR, $hWndFrom, $iCode $hCapabilitiesList = $CapabilitiesList If Not IsHWnd($hCapabilitiesList) Then $hCapabilitiesList = GUICtrlGetHandle($CapabilitiesList) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "HwndFrom")) $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hCapabilitiesList Switch $iCode Case $LVN_ITEMCHANGED Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) Local $iItem = DllStructGetData($tInfo, "Item") $iMsstyles = $aFileList[$iItem][1] GetMsstyles() IsMsstylesPatched() ;GUICtrlSetData($iAnswer, $iMsstyles) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc While 1 $MSG = GUIGetMsg() Select Case $MSG = $GUI_EVENT_CLOSE Exit EndSelect WEnd
Solution Nine Posted Sunday at 02:17 PM Solution Posted Sunday at 02:17 PM (edited) I see. Unless "whoami" process can be loaded once and run all the time, instead of calling it (with run) every time, there is not much value to try multi-threading or IPC. Maybe there is a dll that could return your request, that way you would get the answer instantly. Nevertheless, if you want to speed up your code, you should replace ProcessWaitClose with your own. As per help file : Quote The process is polled approximately every 250 milliseconds. Expand Which is quite slow. You could use something like this : Func ProcessWaitCloseEx($iPID) While ProcessExists($iPID) And Sleep(10) WEnd EndFunc ps : Another option is to read only once the answer from the "whoami" process, you could do it on the initial load or have an array containing the answers once read. pps : If you decide to go with the initial load approach, then you could delegate the reading to another process (then IPC or multi-thread would be helpful) while you prepare your GUI and show it to the user... Edited Sunday at 02:41 PM by Nine WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Reveal hidden contents Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy
Nine Posted Sunday at 03:51 PM Posted Sunday at 03:51 PM Another thing with your code. While playing with it I noticed that sometimes a small + (copy sign) was appearing. It seems that your WM_NOTIFY2 winproc doesn't like much staying in the function too long. By using a dummy control, and sending the responsibility to get and show the registry read and the run is solving the issue and accelerate the display... ... Global $idDummy = GUICtrlCreateDummy() ... Case $MSG = $idDummy GetMsstyles() IsMsstylesPatched() ... Case $LVN_ITEMCHANGED Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) Local $iItem = DllStructGetData($tInfo, "Item") $iMsstyles = $aFileList[$iItem][1] GUICtrlSendToDummy($idDummy) WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Reveal hidden contents Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy
argumentum Posted Sunday at 04:23 PM Posted Sunday at 04:23 PM On 3/30/2025 at 1:48 PM, WildByDesign said: I'm going to do some research into the IPC stuff later today. Expand ..using your script I figure that you may want to prefetch the info. It does not change that often. WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Sunday at 04:42 PM Author Posted Sunday at 04:42 PM On 3/30/2025 at 2:17 PM, Nine said: Which is quite slow. You could use something like this : Func ProcessWaitCloseEx($iPID) While ProcessExists($iPID) And Sleep(10) WEnd EndFunc Expand This is a very good idea. I can’t test until later in the day, but I imagine this might be enough of a difference and keep things simple. On 3/30/2025 at 3:51 PM, Nine said: By using a dummy control, and sending the responsibility to get and show the registry read and the run is solving the issue and accelerate the display. Expand And with this further improving overall performance, that is great news. I will test it all later and see. I really prefer to keep it simple and avoid IPC and extra binary unless I really have to. On 3/30/2025 at 2:17 PM, Nine said: Maybe there is a dll that could return your request, that way you would get the answer instantly. Expand It is interesting that you mention this. The SecureUxTheme actually does provide a library DLL with well documented options for obtaining theme info, applying themes, etc. But the problem with my lack of experience is that I have no idea even where to begin with constructing DllCall and things like that in AutoIt. This would certainly be the most performant method. On 3/30/2025 at 4:23 PM, argumentum said: ..using your script I figure that you may want to prefetch the info. It does not change that often. Expand Yes, true. It would not change often at all. Prefetch would be smart. I do have an array to store stuff in as well. Great idea.
WildByDesign Posted Sunday at 04:44 PM Author Posted Sunday at 04:44 PM I believe the details for the SecureUxTheme library are here: https://github.com/namazso/SecureUxTheme/tree/master/ThemeLib It is far beyond my abilities though.
Nine Posted Sunday at 04:52 PM Posted Sunday at 04:52 PM On 3/30/2025 at 2:17 PM, Nine said: initial load Expand == On 3/30/2025 at 4:23 PM, argumentum said: prefetch Expand A final note on your WM_NOTIFY, you get to have 3 notifications (except for the very first one), 2 for the previous selected item and 1 for the newly selected item. So there is 2 useless calls to the "whoami" process, which slow down a lot your listview. By having a static variable that check if the item has effectively changed, you would accelerate by 66% the performance of your GUI... WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Reveal hidden contents Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy
WildByDesign Posted Sunday at 06:58 PM Author Posted Sunday at 06:58 PM On 3/30/2025 at 4:52 PM, Nine said: By having a static variable that check if the item has effectively changed, you would accelerate by 66% the performance of your GUI... Expand That is a significant find, thank you. I tested what you said with a simple ConsoleWrite and it was certainly doing 3 each time. So I will make the function discard values that are equal to previous so that it doesn’t run 3 times like that.
WildByDesign Posted Sunday at 08:59 PM Author Posted Sunday at 08:59 PM @Nine I finally got a chance to sit down and implement your suggestions. Your custom ProcessWaitCloseEx function made a dramatic difference. That alone made me quite happy with how it's functioning now. I also filtered out the duplicates from WM_NOTIFY so that the command only runs 1 time now and that smoothed out the GUI performance even more. The only thing that did not work for some reason was the dummy control. I get the response back from GetMsstyles() but not from IsMsstylesPatched() even though they are both there. But I am happy with the way everything is performing now so it's not too much of a concern getting the dummy control to work. By the way, I really appreciate your time and your expertise on this. It really made a significant difference and all without the need for any multi-process IPC and so on.
argumentum Posted Sunday at 09:11 PM Posted Sunday at 09:11 PM #include <GUIConstantsEx.au3> Global $g_idLabel = 0 Example() Func Example() GUICreate("Busy or not, here I go...", 400, 200) $g_idLabel = GUICtrlCreateLabel("nothing", 10, 10, 100) GUISetState(@SW_SHOW) AdlibRegister(flipit, 2000) While GUIGetMsg() <> $GUI_EVENT_CLOSE WEnd GUIDelete() EndFunc ;==>Example Func flipit() Local Static $bBusy = False $bBusy = Not $bBusy GUICtrlSetData($g_idLabel, $bBusy ? "busy" : "nothing") GUISetCursor($bBusy ? 1 : 2, 1) EndFunc ;==>flipit ..to tell the user that the script is doing something. WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Sunday at 09:39 PM Author Posted Sunday at 09:39 PM On 3/30/2025 at 9:11 PM, argumentum said: ..to tell the user that the script is doing something. Expand This is great. Thank you for sharing. argumentum 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now