Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/26/2019 in all areas

  1. In a Windows GUI like an AutoIt GUI, functionality and user actions are largely controlled through Windows messages. Therefore, it's interesting to monitor Windows messages. That's the purpose of this example. How does it work? This is a simple example (Examples\1) Native controls\GUICtrlCreateButton.au3): #include <GUIConstantsEx.au3> #include "..\..\Includes\WinMsgMon_Button.au3" ; <<<<<<<<<<<<<<<<<<<< WinMsgMon_InitMsgs( "..\..\Includes" ) ; <<<<<<<<<<<<<<<<<<<< Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) WinMsgMon_GetMsgs( $hGUI, "$hGUI" ) ; <<<<<<<<<<<<<<<<<<<< ; Create button controls. Local $idMsgBox = GUICtrlCreateButton("Open MsgBox", 120, 170, 85, 25) WinMsgMon_GetMsgs( $idMsgBox, "$idMsgBox" ) ; <<<<<<<<<<<<<<<<<<<< Local $idClose = GUICtrlCreateButton("Close", 210, 170, 85, 25) WinMsgMon_GetMsgs( $idClose, "$idClose" ) ; <<<<<<<<<<<<<<<<<<<< ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $idMsgBox WinMsgMon_UserMsg( $idMsgBox, $WM_USER0, _ ; <<<<<<<<<<<<<<<<<<<< "Before MsgBox" ) MsgBox( 0, "Title", "One second timeout", 1 ) WinMsgMon_UserMsg( $idMsgBox, $WM_USER1, _ ; <<<<<<<<<<<<<<<<<<<< "After MsgBox" ) Case $GUI_EVENT_CLOSE, $idClose WinMsgMon_UserMsg( $idClose, $WM_USER0, _ ; <<<<<<<<<<<<<<<<<<<< "Before ExitLoop" ) ExitLoop EndSwitch WEnd ; Delete GUI and all controls. GUIDelete($hGUI) WinMsgMon_ViewMsgs( Example ) ; <<<<<<<<<<<<<<<<<<<< EndFunc ;==>Example Include UDF In this example WinMsgMon UDF is included as WinMsgMon_Button.au3 and not just WinMsgMon.au3. Because this is a button example, WinMsgMon_Button.au3 is included to be able to get detail information about button messages. WinMsgMon_InitMsgs() WinMsgMon_InitMsgs() is called immediately after inclusion of the UDF. The function sets up the path used to find text files with message information. In addition to the path, WinMsgMon_InitMsgs() can take an optional $iFlags parameter as input. See WinMsgMon.au3 and Rerun in Toolbar buttons section for more information. WinMsgMon_GetMsgs() WinMsgMon_GetMsgs() is the central function that collects messages. It takes two parameters: A window or control and optionally the name of the window or control. In the example above the function is called three times to be able to collect messages sent to the main GUI and two buttons. While messages are collected and stored, info is simultaneously written to SciTE console. The specified window or control names are used in console output and in WinMsgMon GUI. If no names are specified, the names Window1, Button1 and Button2 are used instead. WinMsgMon_UserMsg() WinMsgMon_UserMsg() sends user messages to the two buttons. 16 user messages are defined: $WM_USER0 - $WM_USERF. In the example $WM_USER0 and $WM_USER1 are send to $idMsgBox button before and after the MsgBox is opened and closed. And $WM_USER0 is send to $idClose button immediately before ExitLoop. This way it's easy to recognize the button clicks among the messages. WinMsgMon_ViewMsgs() WinMsgMon_ViewMsgs() is the central function that displays the messages in WinMsgMon GUI. In the example WinMsgMon_ViewMsgs() is called with Example function as parameter. The function parameter is optional and is used in relation to the Rerun button to be able to run Example once more. See Rerun in Toolbar buttons section. WinMsgMon_ViewMsgs() is called as the last line in Example() function. It does not necessarily have to be the last line. But it must definitely be after GUIDelete(). WinMsgMon_ViewMsgs() may well be called before a final long term calculation or file update. In simple situations you may have sufficient information in SciTE console output. In such cases you can omit the WinMsgMon_ViewMsgs() function. GUI window This is a small part of the messages generated by the example above as shown in WinMsgMon GUI: First column in main listview is message number. Note that the message number in first and second row is 220 and 225. This is because some messages eg. WM_MOUSEMOVE are unchecked in WM_MESSAGEs toolbar listview and therefore not displayed in main listview. Second column shows the window or control that receives the message. Name of idMsgBox button, of interest here, is written on a wheat colored background. Message column shows WM_MESSAGEs and control messages. Some messages are particularly interesting. They are written on a colored background. Notification column displays notifications contained in WM_NOTIFY and WM_COMMAND messages. The info columns shows information provided along with the messages. Console output The same messages as shown in SciTE console (long lines shortened): [ 220] idMsgBox WM_PAINT [ 221] idMsgBox WM_NCHITTEST [ 222] idMsgBox WM_SETCURSOR [ 223] hGUI WM_SETCURSOR [ 224] idMsgBox WM_MOUSEMOVE [ 225] hGUI WM_NOTIFY BCN_HOTITEMCHANGE From = idMsgBox HICF_ENTERING [ 226] idMsgBox WM_PAINT [ 227] idMsgBox WM_ERASEBKGND [ 228] hGUI WM_ERASEBKGND [ 229] hGUI WM_CTLCOLORDLG [ 230] hGUI WM_PRINTCLIENT [ 231] hGUI WM_CTLCOLORBTN [ 232] hGUI WM_NOTIFY NM_CUSTOMDRAW From = idMsgBox CDDS_PREERASE [ 233] hGUI WM_NOTIFY NM_CUSTOMDRAW From = idMsgBox CDDS_PREPAINT [ 234] idMsgBox WM_GETTEXTLENGTH [ 235] idMsgBox WM_GETTEXT [ 236] idMsgBox WM_USER1 [ 237] idMsgBox WM_PAINT Toolbar listviews The five toolbar buttons before the first separator opens five listviews. The buttons are hot-track enabled with the technique used in this example. Wins/Ctrls In Wins/Ctrls listview you check the window or control where from you want to see messages. Here messages from all windows and controls are shown: Because some messages eg. WM_MOUSEMOVE are unchecked only 742 of 1315 messages are shown. Click the checkmark or select the row and press Space key to show all messages. When a row is checked, main listview is updated instantly. Unchecked messages in other toolbar listviews are reset. See Set in Toolbar buttons section for an easy way to uncheck messages. Click the color cell or select the row and press Enter key to set background color. The combo control is implemented with the technique demonstrated in this example. The background color for all windows and controls (first row) cannot be set. Note that only single selection is enabled in this toolbar listview. In the other four listviews multiple selections are enabled. To close a toolbar listview click in main listview, click the toolbar button, move mouse pointer above titlebar or press Esc. WM_MESSAGEs In WM_MESSAGEs listview you uncheck messages that you don't want to see. WM_MOUSEMOVE and WM_NCHITTEST messages are already unchecked. WM_NOTIFY messages are written on an aquamarine background: To uncheck or set background color for all WM_NC-messages select the six rows and press Space or Enter key. When a message is un- or in-checked nothing happens until the listview is closed. Then the Refresh button is enabled. Before you click the Refresh button you can un- or in-check messages in other listviews. Click Refresh button to update main listview. When a color is set main listview is updated instantly. Control Msgs The Control Msgs listview is used to manage control messages: WM_0xC09B is an application defined and unregistered message and is shown as the message code. The two user messages are written on a tomato red background. WM_NOTIFYs and WM_COMMANDs WM_NOTIFYs and WM_COMMANDs listviews are used to manage notifications contained in WM_NOTIFY and WM_COMMAND messages. Toolbar listviews 2 - 5 Messages and notifications in toolbar listviews 2 - 5 are grouped by checked/unchecked items. Unchecked items in bottom of listviews. Update 2018-08-15. A Search can be initiated by double-clicking a message or notification in toolbar listviews 2 - 5. Update 2018-08-04. Toolbar buttons Click Refresh to update main listview after messages and notifications are un- or in-checked in toolbar listviews. Click Rerun to run the script and perform message collection once more. A submenu shows up with "Rerun script", "Write messages to console" and "Detail message information" items. The two last items are the same options as can be set through flag values in WinMsgMon_InitMsgs(). In the example in top of post WinMsgMon_ViewMsgs() takes Example as an input parameter. This is the function that will be executed when you click "Rerun script". The function parameter is optional. If not specified, Rerun button is disabled. The Search group is used to search for messages and notifications. When you click the Search button the Search listview shows up. Double click or press Enter key on an item in the listview to start a search. A search for WM_USER1 messages looks this way in main listview: Use Reset button to reset a search. A search can also be initiated by double-clicking a message or notification in toolbar listviews 2 - 5. Update 2018-08-04. Copy button copies text in selected rows to clipboard. Set button applies settings defined in WinMsgMon.ini. See below. A submenu shows up with Uncheck and Colors items. Click Uncheck to uncheck messages defined in ini-file. Colors are already set through GUI creation. Reset shows a submenu with Uncheck, Colors and Search items. Click an item to reset the feature. Use Set button to apply the feature again. Code info A few notes about the code in relation to toolbar listviews and buttons. All listviews are virtual listviews. Through message collection, indexes are created to display data in main listview and to perform searches. Several set of indexes are created. A set for all windows and controls at once. And a set for each single window and control. When a row in Wins/Ctrls toolbar listview (the leftmost listview) is checked, messages are displayed in main listview through one of these precalculated indexes. That's the reason why it's possible to display the messages in the same moment as the row is checked. Search indexes are created for each single message and notification in the Search listview. A set for all windows and controls at once. And a set for each single window and control. That's a lot of search indexes. In the example above, there are around 100 - 150 search indexes. Calculation of indexes is performed through dictionary objects. When you perform a search the matching rows in main listview are instantly drawn with the yellow background color through a precalculated search index. Next and Prev buttons also takes advantage of the indexes. As soon as a message or notification is unchecked in toolbar listviews 2 - 5 none of these precalculated indexes can be used any more. When you click Refresh a new index is calculated to be able to display the messages in main listview. When you start a search a new index is calculated to be able to display matching messages with the yellow background color, and to be able to use Next and Prev buttons. Up to 10,000 messages, performance should not be a problem. So far, no more messages have been tested. Arrays are dimensioned to a maximum of 100,000 messages. The number of windows and controls in leftmost toolbar listview is limited to 20. When you check an item in leftmost toolbar listview all unchecked messages and notifications are reset and the precalculated indexes can be used again. Functions Most functions have already been described through review of the example in top of post. There are only a few left: WinMsgMon_LoadMsgs() When the message flow from an application is monitored, usually only messages for a single control and main GUI is monitored at a time. However, there will nevertheless often be messages from eg. buttons that are very common controls. If button messages are not registered with WinMsgMon_GetMsgs( $idButton ), messages will appear with the code instead of the name. It's actually the notifications that will appear with the code instead of the name. Use WinMsgMon_LoadMsgs() to load notification names this way: #include "..\..\Includes\WinMsgMon.au3" WinMsgMon_InitMsgs( "..\..\Includes" ) WinMsgMon_LoadMsgs( "BCN_Notifications.txt" ) ; Button control notifications WinMsgMon_LoadMsgs( "EN_Notifications.txt" ) ; Edit control notifications WinMsgMon_RemMsgs() WinMsgMon_RemMsgs() removes all message monitors registered with WinMsgMon_GetMsgs(). WinMsgMon_RemMsgs() is called as the first command in WinMsgMon_ViewMsgs(). It's only necessary to call WinMsgMon_RemMsgs() if WinMsgMon_ViewMsg() isn't called. Ie. if the messages are written to SciTE console only. And only if code is executed after GUIDelete(). Detail info Detail info is information in columns named Info 1 - 4 in WinMsgMon GUI. This is information that can be extracted through wParam and lParam parameters in a message handler function. Detail info for WM_NOTIFY and WM_COMMAND messages is always extracted. Detail info for other window and control messages is depending on specific message handlers (script files). In this version only a few message handlers are implemented and only for a limited number of messages. To be able to collect detail info the message handler must be included in the script. In the example in top of post WinMsgMon_Button.au3 is included instead of WinMsgMon.au3 to be able to collect detail info for buttons. WinMsgMon.ini Includes\WinMsgMon.ini is included in the zip-file. If a copy of this file is placed in the same folder as the running script, the copy will be used instead. You can edit the copy to your own needs. An empty file disables all settings in Includes\WinMsgMon.ini. Includes\WinMsgMon.ini: [Apply Settings] Uncheck=True Colors=True [WM_MESSAGEs Uncheck] WM_ERASEBKGND=1 WM_IME_NOTIFY=1 WM_MOUSEMOVE=1 WM_MOVE=1 WM_MOVING=1 WM_NCHITTEST=1 WM_NCMOUSEMOVE=1 WM_PAINT=1 WM_PRINTCLIENT=1 WM_SETCURSOR=1 WM_TIMER=1 WM_WINDOWPOSCHANGED=1 WM_WINDOWPOSCHANGING=1 [WM_MESSAGEs Colors] WM_NOTIFY=Aquamarine WM_COMMAND=Aquamarine WM_KEYDOWN=Bisque WM_KEYUP=Bisque WM_CHAR=Bisque WM_DEADCHAR=Bisque WM_SYSKEYDOWN=Bisque WM_SYSKEYUP=Bisque WM_SYSCHAR=Bisque WM_SYSDEADCHAR=Bisque WM_LBUTTONDOWN=Khaki WM_LBUTTONUP=Khaki WM_LBUTTONDBLCLK=Khaki WM_RBUTTONDOWN=Khaki WM_RBUTTONUP=Khaki WM_RBUTTONDBLCLK=Khaki WM_MBUTTONDOWN=Khaki WM_MBUTTONUP=Khaki WM_MBUTTONDBLCLK=Khaki WM_MOUSEWHEEL=Khaki WM_XBUTTONDOWN=Khaki WM_XBUTTONUP=Khaki WM_XBUTTONDBLCLK=Khaki WM_CONTEXTMENU=LightPink WM_INITMENU=LightPink WM_INITMENUPOPUP=LightPink WM_MENUSELECT=LightPink WM_MENUCHAR=LightPink WM_MENURBUTTONUP=LightPink WM_MENUGETOBJECT=LightPink WM_UNINITMENUPOPUP=LightPink WM_MENUCOMMAND=LightPink WM_ENTERMENULOOP=LightPink WM_EXITMENULOOP=LightPink WM_NEXTMENU=LightPink [Control Messages Uncheck] [Control Messages Colors] WM_USER0=Tomato WM_USER1=Tomato WM_USER2=Tomato WM_USER3=Tomato WM_USER4=Tomato WM_USER5=Tomato WM_USER6=Tomato WM_USER7=Tomato WM_USER8=Tomato WM_USER9=Tomato WM_USERA=Tomato WM_USERB=Tomato WM_USERC=Tomato WM_USERD=Tomato WM_USERE=Tomato WM_USERF=Tomato [WM_NOTIFY Notifications Uncheck] [WM_NOTIFY Notifications Colors] [WM_COMMAND Notifications Uncheck] [WM_COMMAND Notifications Colors] "Uncheck=True" in "Apply Settings" section in WinMsgMon.ini means that unchecked messages are removed from main listview through GUI creation. As soon as an item in Wins/Ctrls toolbar listview (leftmost) is checked the removed messages are redisplayed. Click Set | Uncheck to remove the messages again. "Colors=True" in "Apply Settings" section means that colors are set through GUI creation. Examples Examples\ 1) Native controls - GUICtrlCreate<Control> examples supplied with message monitor code 2) UDF controls - _GUICtrl<Control>_Create examples (not included above) supplied with message monitor code 3) Miscellaneous Combo\ - ComboBox example including the corresponding Edit and ListBox controls. ListView\ - Four ListView examples with a standard ListView, a custom drawn ListView, a virtual ListView and a virtual and custom drawn ListView. Window\ - An example that shows how mouse clicks generates AutoIt messages ($GUI_EVENT_MESSAGEs). Two examples regarding blocked and paused GUIs. Includes Includes\ WinMsgMon.au3 - Main include file, collects messages WinMsgMon_Button.au3 - Button controls, detail information WinMsgMon_ComboBoxEx.au3 - ComboBoxEx controls, detail information WinMsgMon_ListBox.au3 - ListBox controls, detail information WinMsgMon_ListView.au3 - ListView controls, detail information WinMsgMon.ini - ini-file, colors and unchecked messages Internal\ - Internal files, implements the GUI Messages\ - Message info files CTRL_Information.txt - Info file for AutoIt window and 23 controls WM_Messages.txt - Common Windows messages CCM_Messages.txt - Common control messages <???>_Messages.txt - Messages for specific controls WM_NOTIFY\ NM_Notifications.txt - Common Windows notifications <???>_Notifications.txt - WM_NOTIFY notifications for specific controls WM_COMMAND\ <???>_Notifications.txt - WM_COMMAND notifications for specific controls 7z-file The 7z contains source code and message data. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. WinMsgMon.7z
    3 points
  2. This UDF brings the power and flexibility of jq to AutoIt scripts. jq is an open-source, powerful, and flexible command-line based JSON processor. As it says on their website, jq is like 'sed' for JSON. jq can be used for the simplest of tasks like retrieving JSON objects and values (parsing), to very advanced JSON processing using its numerous built-in functions and conditional processing. Its built-in functions can handle math, selection, conditional processing, mapping, object and array manipulation, flattening, reduction, grouping, and much more. You can even create your own jq functions. You can learn more about jq and even play with it in real-time, using jq's online jq playground, all on their website. Here and some helpful links to get you more familiar with jq, what can be done with it, its built-in functions, and its syntax. jq Website: https://jqlang.github.io/jq/ jq Manual: https://jqlang.github.io/jq/manual/ jqWiki (FAQ, Cookbook, Advanced Topics) https://github.com/jqlang/jq/wiki jq is a single 32 or 64 bit executable that has no other dependencies. Just like using the SQLite UDF, the only requirement to use this UDF is that the jq executable reside in a location in which the UDF can execute it. The latest win32 & win64 versions have been included in the UDF download. You can always get newer versions from the jq website. jq at a high level Like 'sed', jq reads JSON in, either through STDIN or one or more files, processes it thru one or more "filters", and outputs the results. You can, optionally, supply "options" that affect how it reads the input, where it gets its "filters", and how it writes its output. It looks a little like this: JSON ---> jq processor (using supplied filters and options) ---> Output So in jq lingo, you basically use "Filters" to tell jq what you want it to do. So in the UDF file, that is why the main functions ( _jqExec() and _jqExecFile() ) refer to filters and options. Please make note that jq works with relatively strict JSON. This means that all JSON read must be conform to the standard. Luckily, jq is pretty good at identifying where a format error exists in non standard JSON. The jq UDF There are 2 main funtions in the UDF file, _jqExec and jqExecFile. With these 2 functions, you can pretty much do anything that jq can do. The only difference between to two functions is whether the JSON is supplied by a string or a file. The 2 primary functions simply call the jq executable with the supplied information, after properly formatting the parameters. There are additional functions in the UDF to easily pretty-print your json, compact-print your json, dump the json data with its associated paths, and see if specific JSON keys exist, but they all just execute the _jqExec or _jqExecFile function with the proper filter. There are also a couple of extra functions to display what version of the UDF and jq executable you are currently using. There are also a couple of functions to enable and disable logging of jq information for debugging purposes. Most of the jq UDF file functions return an @error if unsuccessful. Some also include @extended info. Please see the actual function headers for more information on their usage and return values. The 2 primary functions below just format your jq request and pass it on the jq executable. The functions will also properly escape double quotes (") that are used in the filter. For most simple tasks, you just need to supply the JSON source and a filter. _jqExec($sJson, $sFilter, $sOptions = Default, $sWorkingDir = Default) Or _jqExecFile($sJsonFile, $sFilter, $sOptions = Default, $sWorkingDir = Default) Using jq in your script As stated earlier, the jq executable must reside somewhere where the script can locate and execute it. The _jqInit() function always has to be executed before any jq processing occurs. _jqInit() merely locates the executable or uses the supplied path. It also clears any previous debug log. The jq UDF folder contains a jq example script that has several examples to how to do some of the most common JSON processing tasks. Here are a few examples to get you started: How to pretty-print some JSON #include "jq.au3" ;_jqInit is only needed if the jq executale is not in the PATH or @ScriptDir _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"fruits":[{"Apple":{"color":"Red","season":"Fall"}}, {"Banana":{"color":"Yellow","season":"Summer"}}]}' $sCmdOutput = _jqPrettyPrintJson($sJson) ConsoleWrite(@CRLF & "Pretty-Print JSON" & @CRLF & $sCmdOutput & @CRLF) How to compact-print some JSON #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{ "fruits" : [{"Apple" : {"color":"Red","season":"Fall"}}, {"Banana":{"color":"Yellow","season":"Summer"}}]}' $sCmdOutput = _jqCompactPrintJson($sJson) ConsoleWrite(@CRLF & "Compact-Print JSON" & @CRLF & $sCmdOutput & @CRLF) Dump JSON data (paths and values) #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{ "fruits" : [{"Apple" : {"color":"Red","season":"Fall"}}, {"Banana":{"color":"Yellow","season":"Summer"}}]}' $sCmdOutput = _jqDump($sJson) ConsoleWrite(@CRLF & "Dump JSON paths and values" & @CRLF & $sCmdOutput & @CRLF) How to GET JSON values #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"Apple" : {"color":"Red","season":"Fall"}, "Banana":{"color":"Yellow","season":"Summer"}}' $sFilter = '.Banana.color' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("Get color of banana" & @CRLF) ConsoleWrite("Input: : " & _jqCompactPrintJson($sJson) & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & $sCmdOutput & @CRLF) or #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"Apple" : {"color":"Red","season":"Fall"}, "Banana":{"color":"Yellow","season":"Summer"}}' $sFilter = 'getpath(["Banana", "color"])' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("Get color of banana" & @CRLF) ConsoleWrite("Input: : " & _jqCompactPrintJson($sJson) & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & $sCmdOutput & @CRLF) Check for the existence of a key #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"Apple":{"color":"Red","season":"Fall"}, "Banana":{"color":"Yellow","season":"Summer"}}' $sFilter = '.Banana | has("color")' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("Check for existence of color key within Banana object" & @CRLF) ConsoleWrite("Input: : " & _jqCompactPrintJson($sJson) & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & $sCmdOutput & @CRLF) Count of how many Items in an object #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"Apple":{"color":"Red"}, "Banana":{"color":"Yellow","season":"Summer"}}' $sFilter = '.Banana | length' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("How many items in the Banana object" & @CRLF) ConsoleWrite("Input: : " & _jqCompactPrintJson($sJson) & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & $sCmdOutput & @CRLF) How to PUT/Create/Modify JSON #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sInput = "" $sFilter = 'setpath(["Apple","color"];"Red") | setpath(["Banana","color"];"Yellow") | setpath(["Banana","season"];"Summer")' $sOptions = '-n' ;required if no input supplied $sCmdOutput = _jqExec($sInput, $sFilter, $sOptions) ConsoleWrite("Update/Create JSON" & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & @CRLF & $sCmdOutput & @CRLF) List all of the fruits (top-level keys) #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '{"Apple":{"color":"Red"}, "Banana":{"color":"Yellow","season":"Summer"}}' $sFilter = 'keys | .[]' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("List all top-level keys (fruits)" & @CRLF) ConsoleWrite("Input : " & $sJson & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & @CRLF & $sCmdOutput & @CRLF) Calculate the sum of all of the objects' price * qty #include "jq.au3" ;Initialize jq environment _jqInit() If @error Then Exit ConsoleWrite("ERROR: Unable to initialize jq - @error = " & @error & @CRLF) $sJson = '[{"id":1,"price":20.00,"qty":10},{"id":2,"price":15.00,"qty":20.25},{"id":3,"price":10.50,"qty":30}]' $sFilter = 'map(.price * .qty) | add' $sCmdOutput = _jqExec($sJson, $sFilter) ConsoleWrite("Calculate the sum of all of the objects' price * qty" & @CRLF) ConsoleWrite("Input : " & $sJson & @CRLF) ConsoleWrite("Filter : " & $sFilter & @CRLF) ConsoleWrite("Output : " & $sCmdOutput & @CRLF) The examples above, and the ones in the example files, merely scratch the surface of what jq can do. It may look intimidating at first but it really isn't that bad once you start playing with it. You can find several more examples and play around with them or create your own using jqPlayground. jqPlayground is a separate, stand alone, interactive tool for creating, testing and learning JSON processing using jq. If you have any questions regarding the UDF, or how to perform a certain task using jq, I'll try my best to answer them. Since jq has been around for a while now, there's also several jq-related questions and answers on StackOverflow. >>> Download the UDF in the Files Section <<<
    1 point
  3. This is a simple and practical way to start and manage many processes. I use it to quickly query many remote clients for varyous informations. For processes I mean external programs that can run autonomously and that allows I/O redirection. Here the advantage is that when you start a process, you can also determine which function in your main program should receive results when the external process finishes executing. So you can have different processes and different "callback" functions. The whole works nearly autonomously and asynchronously. While spawned processes works, you can perform other tasks in the main script and leave the worry of receiving and managing the results, to the pre-established functions. As I sayd, everything is almost completely automatic and the processes do their work asynchronously and independently of the flow of the main script. To check and manage processes status, you have only to call as often as possible the _TasksCheckStatus() function that will quickly handle the running processes. AdlibRegister() could be used for this ripetitive "polling". In short: 1) setup single commandlines that will "generate" your wanted result 2) establish wich function of your main script should receive the above result 3) an optional Timeout in seconds is allowed (task from point 1 will be killed at timeout) see function header for details. The provided example of use, needs to be executed in a network environment with preferably many clients, and you have to be administrator. Populate the $aIPList[] array with ClientNames (or ip addresses), and this example script will query all the clients about some informations by running many processes asincronously. Then it will collect results from the processes as soon as "answers" are available and will populate the ListView with that data. I used a ListView so that you can see that all the cells will fill (quite quickly) in an asynchronous way. If you are not in a network with many clients, then this example is nearly useless... (sorry) Hope it can be of use... (suggestions, bug reports and emrovements are welcome) MultiTask.udf #include-once ; #include "Array.au3" ; #INDEX# ======================================================================================================================= ; Title .........: Multi Task Management (tasks spawned by the user via the _TaskRun function of this udf) ; AutoIt Version : ; Language ......: ; Description ...: Functions that assists to execute and manage user's spawned tasks. ; Author(s) .....: Chimp ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _TaskRun Run a new task and stacks its references for later use ; _TasksCheckStatus Check the status of all running tasks and call the CallBack function when a task completed ; =============================================================================================================================== ; #INTERNAL_USE_ONLY#============================================================================================================ ; __TaskRemove frees task's stacked references ; __NOP No OPeration function ; =============================================================================================================================== Global $aTasks[1][7] = [[0]] ; Create and initialize the task reference stack to 0 ; #FUNCTION# ==================================================================================================================== ; Name ..........: _TaskRun ; Description ...: Runs a new task as specified in $sCommand ; Syntax ........: _TaskRun($vIndex, $sCommand[, $sParser = "__NOP"[, $vTimeout = False]]) ; Parameters ....: $vIndex - A variant value passed by the caller as a reference to this task. ; this value will be returned to the callback function along with results. ; ; $sCommand - A string value containing the full command to be executed ; ; $sParser - [optional] The name of the function to be called at the end of this task. ; Default is __NOP that is a "do nothing" function. ; P.S. ; the $aParser function will be called by the _TasksCheckStatus() function when ; this task will finish to run: ; an 1D array with 4 elements will be passed to the called function: ; element [0] the caller's index reference of this task ; element [1] the StdOut result of this task ; element [2] the StdErr result of this task ; element [3] the time spent by this task ; ; $vTimeout - [optional] A variant value. Default is False. ; if specified is the number of seconds for the Timeout. ; After this amount of seconds, if this task is still running, it is killed ; ; Return values .: the total number of stacked tasks ; Author ........: Chimp ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _TaskRun($vIndex, $sCommand, $sParser = "__NOP", $vTimeout = False) ; ; Stack structure: ; ; +-----+ ; 0 | nr. | <-- [0][0] number of running tasks ; +-----+-----+-----+-----+-----+-----+-----+ ; 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ; +-----+-----+-----+-----+-----+-----+-----+ ; n | * | * | * | * | * | * | * | ; | | | | | | | ; | | | | | | [n][6] setted with the TimerInit() value at the start of this task. ; | | | | | | ; | | | | | [n][5] contains the required Timeout in seconds (Default is set to False = no timeout) ; | | | | | ; | | | | [n][4] The CallBack function name that will receive the results of this task ; | | | | ; | | | [n][3] the error message returned by the StdErr stream of this task ; | | | ; | | [n][2] the result of the command returned by the StdOut stream of this task ; | | ; | [n][1] the reference of this task passed by the user (will be passed back to the caller along with results) ; | ; [n][0] the PID of this running task ; ReDim $aTasks[$aTasks[0][0] + 2][7] ; add a new element to the stack $aTasks[0][0] += 1 ; add 1 to the number of running tasks ; Run the passed command with the I/O streams redirected $aTasks[$aTasks[0][0]][0] = Run($sCommand, "", @SW_HIDE, 6) ; 6 -> $STDOUT_CHILD (0x2) + $STDERR_CHILD (0x4) ; store references of this task to the stack $aTasks[$aTasks[0][0]][1] = $vIndex $aTasks[$aTasks[0][0]][4] = $sParser $aTasks[$aTasks[0][0]][5] = $vTimeout ; can be False or the number of seconds for the timeout of this task $aTasks[$aTasks[0][0]][6] = TimerInit() ; store the TimerInit() value for this task Return $aTasks[0][0] ; return the total number of running tasks EndFunc ;==>_TaskRun ; #FUNCTION# ==================================================================================================================== ; Name ..........: _TasksCheckStatus ; Description ...: Scans the status of all active tasks and checks if some task has finished its job ; This function should be called as aften as possible ; Syntax ........: _TaskCheckStatus() ; Parameters ....: None ; Return values .: number of still running tasks; * see remarks ; Author ........: Chimp ; Modified ......: ; Remarks .......: When a task finish, it is removed from the stack and results are passed to the callback function. ; An 1D array with 4 elements will be passed to the called function: ; element [0] the caller's index reference of this task ; element [1] the StdOut result of this task ; element [2] the StdErr result of this task ; element [3] the time spent by this task (approximative time) ; is an approximate datum because it also includes the delay ; added by the main loop before calling _TasksCheckStatus() ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _TasksCheckStatus() If $aTasks[0][0] = 0 Then Return 0 ; if no tasks then return Local $bEndTask ; will be setted to True if the checked task has finished or is killed by timeout Local $iPointer = 1 ; start checking from first task in the stack Local $aResults[4] ; this Array will be loaded with the results of the task Local $sCallBack ; the name of the function to call when a task ends its job Local $aArgs[2] = ["CallArgArray", ""] ; "special" array will be loaded with parameters for the CallBack function While $iPointer <= $aTasks[0][0] $bEndTask = False $aTasks[$iPointer][2] &= StdoutRead($aTasks[$iPointer][0]) ; read and store the StdOut stream $aTasks[$iPointer][3] &= StderrRead($aTasks[$iPointer][0]) ; read and store the StdErr stream ; If @error Then ; if there is an @error is because this task has finished its job If Not ProcessExists($aTasks[$iPointer][0]) Then ; if this task has finished its job $bEndTask = True ; flag the end of the work ElseIf $aTasks[$iPointer][5] <> False Then ; if task is still running see if a Timeout check was rquired and if so if is been reached If Int(TimerDiff($aTasks[$iPointer][6]) / 1000) >= $aTasks[$iPointer][5] Then ; timeout reached or exceeded!! $aTasks[$iPointer][3] = "@error Timeout " & $aTasks[$iPointer][3] ; insert an error message at the beginning of the StdErr stream StdioClose($aTasks[$iPointer][0]) ; close I/O streams ProcessClose($aTasks[$iPointer][0]) ; kill this process $bEndTask = True ; flag the end of this task EndIf EndIf If $bEndTask Then ; if this task has finished, get its results and send to the CallBack function $aResults[0] = $aTasks[$iPointer][1] ; ............. Index (the caller reference) $aResults[1] = $aTasks[$iPointer][2] ; ............. the StdOut generated by this task $aResults[2] = $aTasks[$iPointer][3] ; ............. the StdErr generated by this task $aResults[3] = TimerDiff($aTasks[$iPointer][6]) ; .. time spent by this task $sCallBack = $aTasks[$iPointer][4] ; the name of the function to be called $aArgs[1] = $aResults ; second element of the "CallArgArray" special array contains the $aResults array ; loaded with the parameters to be send to the CallBack function. (array in array) ; (the CallBack function will receive only the 1D 4 elements array $aResults) __TaskRemove($iPointer) ; remove references of this task from the stack ; call the CallBack function and pass the results of this task. ; (CallBack function should return as soon as possible because it stops the CheckStatus for the other tasks) ; Call($sCallBack, $aArgs) ; Call CallBack function --->---+ ; | ; <--- and return here ---------------------------------+ EndIf $iPointer += 1 ; check next task WEnd Return $aTasks[0][0] EndFunc ;==>_TasksCheckStatus ; Internal use. Remove the task references from the stack Func __TaskRemove($iElement) #cs If $iElement > $aTasks[0][0] Or $iElement < 1 Then Return StdioClose($aTasks[$iElement][0]) _ArrayDelete($aTasks, $iElement) #ce ; - new -------------------------------------------------- ; remove element without the _Array* udf If $iElement > 0 And $iElement <= $aTasks[0][0] Then StdioClose($aTasks[$iElement][0]) If $aTasks[0][0] > 1 Then For $i = 0 To UBound($aTasks, 2) - 1 $aTasks[$iElement][$i] = $aTasks[$aTasks[0][0]][$i] Next EndIf Else Return ; queue is empty or the required element is out of bound EndIf $aTasks[0][0] -= 1 ReDim $aTasks[$aTasks[0][0] + 1][UBound($aTasks, 2)] Return $aTasks[0][0] ; returns the number of tasks still running EndFunc ;==>__TaskRemove ; Internal use. An empty function Func __NOP($aDummy) ; NOP (No OPeration) EndFunc ;==>__NOP Example of use ; #RequireAdmin #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #include '.\MultiTask.au3' ; ; IMPORTANT following array should be populated with many real HostNames ; here are just nonsense items used as placeholders Global $aIPList[] = [@ComputerName, @IPAddress1, @ComputerName, @ComputerName, 'InexistentClient', @ComputerName] Global $hGrid ; The ListView Handle Global $ahGrid[1] ; An array to keep handles of any listview row Example() MsgBox(0, "Debug:", "Done" & @CRLF & "Hit OK to exit") Func Example() Local $Form1 = GUICreate("Clients status", 760, 400) ; ; Create the ListView $hGrid = GUICtrlCreateListView("HostName|IP|Info|Last reboot|CPU|Last logon|Current logon", 0, 0, 760, 400) _GUICtrlListView_SetColumnWidth($hGrid, 0, 140) ; HostName _GUICtrlListView_SetColumnWidth($hGrid, 1, 100) ; IP _GUICtrlListView_SetColumnWidth($hGrid, 2, 80) ; Ping info ms or Off or Unknown or Timeout) _GUICtrlListView_SetColumnWidth($hGrid, 3, 120) ; Last Reboot _GUICtrlListView_SetColumnWidth($hGrid, 4, 40) ; cpu load ; last 2 columns a mutually exclusive. If there is a user logged it's shown on the last column ; if there is not a user logged then the last user that was logged is shown on column 4 instead _GUICtrlListView_SetColumnWidth($hGrid, 5, 140) ; Last logged UserId (if nobody is logged now) _GUICtrlListView_SetColumnWidth($hGrid, 6, 140) ; Currently logged UserId _GUICtrlListView_SetExtendedListViewStyle($hGrid, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT)) ; show grid; select whole row ; GUISetState(@SW_SHOW) ; following line is needed if you have to refill the listview ; _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($hGrid)) ; empty the listview ReDim $ahGrid[UBound($aIPList)] ; this loop will run all needed tasks at once. ; The results of the tasks will be managed by the callback functions (nearly) autonomously and asynchronously For $i = 0 To UBound($aIPList) - 1 $ahGrid[$i] = _GUICtrlListView_AddItem($hGrid, "") ; create a listview row ; ; ... for each client ... ; ; spawn ping commands. result will be send to the _PingParse() function _TaskRun($i, "Ping -a -n 1 -4 " & $aIPList[$i], "_PingParse") ; spawn commands to recall LoggedOn User. Result will be send to the _LoggedOn() function _TaskRun($i, "wmic /node:" & $aIPList[$i] & " computersystem get username /value", "_LoggedOn", 5) ; 5 = timeout in 5 seconds ; spawn commands to recall Last reboot time. result will be send to the _LastReboot() function _TaskRun($i, "wmic /node:" & $aIPList[$i] & " os get lastbootuptime /value", "_LastReboot", 5) ; spawn commands to recall % of CPU load. result will be send to the _CPU_load() function _TaskRun($i, "wmic /node:" & $aIPList[$i] & " cpu get loadpercentage /value", "_CPU_load", 7) Next ; now, while all tasks are running ; we could perform other activities in the meantime ; or we can wait the end of all the tasks Do Sleep(250) ; you could perform other jobs here while waiting for the tasks to finish Until Not _TasksCheckStatus() ; <-- this function performs management of running tasks ; and should be called as often as possible EndFunc ;==>Example ; below are CallBack functions ; #FUNCTION# ==================================================================================================================== ; Name ..........: _PingParse (a callback function) ; Description ...: this function analize the output of a ping command and "extract" needed infos ; it fills columns 0 1 and 2 of the list view ($aTarget[0] is the line number of the listview to be filled) ; Syntax ........: _PingParse($aTarget[, $bDomain = True]) ; Parameters ....: $sTarget - An array with Ping results passed by the MultiTasks as soon as any ping task ends ; the passed array contains following data: ; $aTarget[0] Index for this task ; $aTarget[1] StdOut from ping (the whole output of the ping) ; $aTarget[2] StdErr from ping ; $aTarget[3] Time spent by this task to complete (is NOT the ping roundtrip time) ; $bDomain - [optional] A binary value. Default is True. (keep domain info in host name) ; ; Return values .: None. It Fills Listview columns 0, 1 and 2 ; column 0 : resolved HostName or "" ; column 1 : IP address or "" (this can contain last known IP even if now is offline) ; column 2 : roundtrip time or "Unknown" or "timeout" or "Off" ; ; Author ........: Chimp ; =============================================================================================================================== Func _PingParse($aTarget, $bDomain = True) ; $aTarget contains 4 elements: [0] Index, [1] StdOut, [2] StdErr, [3] time spent by this task Local $sOutput = $aTarget[1] ; stdout Local $0, $1, $2, $3, $aMs ; Local $iAnswer = -1, $iName = -1 Local $aResult[3] = ["", "", ""] ; [0]ms, [1]HostName, [2]IP $aMs = StringRegExp($sOutput, "([0-9]*)ms", 3) If Not @error Then ; Ping replayed $aResult[0] = $aMs[UBound($aMs) - 1] ; average ms Else ; $aResult[0] = "off" EndIf $0 = StringInStr($sOutput, "Ping") $1 = StringInStr($sOutput, "[") ; HostName decoded? If $1 Then ; HostName decoded $2 = StringInStr($sOutput, "]") $3 = StringInStr($sOutput, " ", 0, -2, $1) $aResult[1] = StringMid($sOutput, $3 + 1, $1 - $3 - 1) ; HostName $aResult[2] = StringMid($sOutput, $1 + 1, $2 - $1 - 1) ; IP Else If $0 Then ; pinging an IP address? ; $aResult[1] = "" ; no HostName Local $aFindIP = StringRegExp($sOutput, "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", 3) If Not @error Then $aResult[2] = $aFindIP[0] Else ; unknown HostName $aResult[0] = "Unknown" $aResult[1] = $aIPList[$aTarget[0]] ; retrieve HostName from the $aIPList array EndIf EndIf If $bDomain = False Then Local $aSplit = StringSplit($aResult[1], ".", 2) ; 2 = $STR_NOCOUNT $aResult[1] = $aSplit[0] ; romove .domain part from the HostName EndIf If StringLeft($aTarget[2], 14) = "@error Timeout" Then $aResult[0] = "Timeout" ; Now that we have the infos, we compile related cells in ListView ; grid row-handle data column _GUICtrlListView_SetItemText($hGrid, $ahGrid[$aTarget[0]], $aResult[1], 0) ; first column "HostName" _GUICtrlListView_SetItemText($hGrid, $ahGrid[$aTarget[0]], $aResult[2], 1) ; second column "IP address" _GUICtrlListView_SetItemText($hGrid, $ahGrid[$aTarget[0]], $aResult[0], 2) ; third column "Infos about the ping" ; ConsoleWrite("Debug: " & "-> " & $aResult[0] & @TAB & $aResult[1] & @TAB & $aResult[2] & @CRLF) EndFunc ;==>_PingParse Func _LastReboot($aParameters) ; Last reboot DateTime $aParameters[1] = StringStripWS($aParameters[1], 8) Local $equal = StringInStr($aParameters[1], "=") If $equal Then _GUICtrlListView_AddSubItem($hGrid, $ahGrid[$aParameters[0]], WMIDateStringToDate(StringMid($aParameters[1], $equal + 1)), 3) ; column 3 EndIf EndFunc ;==>_LastReboot Func _CPU_load($aParameters) ; % of CPU load $aParameters[1] = StringStripWS($aParameters[1], 8) Local $equal = StringInStr($aParameters[1], "=") If $equal Then _GUICtrlListView_AddSubItem($hGrid, $ahGrid[$aParameters[0]], StringMid($aParameters[1], $equal + 1), 4) ; column 4 EndIf EndFunc ;==>_CPU_load Func _LoggedOn($aParameters) ; User now logged $aParameters[1] = StringStripWS($aParameters[1], 8) ; if none is logged, then find the user that was last logged (also using _TaskRun) If $aParameters[1] = "" Or $aParameters[1] = "UserName=" Then ; following syntax is by @iamtheky (thanks) ; https://www.autoitscript.com/forum/topic/189845-regexp-pattern-in-findstr-dos-command/?do=findComment&comment=1363106 Local $sCmd = 'cmd /c FOR /F "usebackq skip=2 tokens=1-3" %A IN (`REG QUERY ' & '"\\' & $aIPList[$aParameters[0]] & _ '\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI" /REG:64 /v LastLoggedOnUser 2^>nul`) Do @echo %C' _TaskRun($aParameters[0], $sCmd, "_LastLogged", 5) ; find last logged user and, when ready, send result to _LastLogged() Else ; if someone is logged then write username to column 6 Local $aUser = StringSplit($aParameters[1], "=", 2) ; 2 = $STR_NOCOUNT _GUICtrlListView_AddSubItem($hGrid, $ahGrid[$aParameters[0]], $aUser[UBound($aUser) - 1], 6) ; column 6 EndIf EndFunc ;==>_LoggedOn Func _LastLogged($aParameters) _GUICtrlListView_AddSubItem($hGrid, $ahGrid[$aParameters[0]], $aParameters[1], 5) ; column 5 EndFunc ;==>_LastLogged Func WMIDateStringToDate($dtmDate) ; thanks to @kylomas ; https://www.autoitscript.com/forum/topic/169252-wmi-password-age-issue/?do=findComment&comment=1236082 ; reformat date to mm/dd/yyyy hh:mm:ss and zero fill single digit values Return StringRegExpReplace(StringRegExpReplace($dtmDate, '(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).*', '$2/$3/$1 $4:$5:$6'), '(?<!\d)(\d/)', '0$1') EndFunc ;==>WMIDateStringToDate
    1 point
  4. (Aside from the dispute that is currently taking place) Just my personal experiences : Q : Is a quality certificate beneficial ? A : Yes (in the vast majority of cases) Q : Does it make sense to report 'false positives' to the antivirus companies ? A : Yes (most of the problems will be solved within a few days) As @iamtheky already wrote : There is no magic bullet. I always find it somehow irritating, that people easily pay $1000+ per year for their mobile phone but getting a heart attack if they have to spend $200 on a good certificate. (a bit off topic) What concerns me more from a privacy point of view is : The development goes increasingly in the direction of real-time cloud protection services. You can still disable this feature (at the moment), but my trust in this approach is rather low. From a technical perspective this might be great, but we all know what will happen to our personal informations .
    1 point
  5. 1 point
  6. Something like this? #include <AD.au3> ; Open Connection to the Active Directory _AD_Open() If @error Then Exit MsgBox(16, "Active Directory Example Skript", "Function _AD_Open encountered a problem. @error = " & @error & ", @extended = " & @extended) Global $aObjects = _AD_GetObjectsInOU("", "(ANR=john.Doe@company.com)", 2, "sAMAccountName,distinguishedName,displayname", "displayname") If @error > 0 Then Exit MsgBox(64, "", "No records found") _ArrayDisplay($aObjects)
    1 point
  7. I think you meant 'Experts (especially water). You're excluding him from the experts there ;D
    1 point
  8. You should take a look at the WinHTTP UDF.
    1 point
  9. 1 point
×
×
  • Create New...