Leaderboard
Popular Content
Showing content with the highest reputation on 10/09/2018 in all areas
-
Description: Launch.IT is a simple & moddable/hackable Windows App-Launcher (like MacOS' Spotlight) Features: A lot of customizations (background-pics, colors, position, etc...) can be made via the ".ini" file You can add aliases in the ".ini" file to launch apps/files and browse url/folders Make use of its 5 functionalities: App launcher (and files/url/path browser), Windows search (find results from your files and folder), Windows Run, DOS commands execution (command prompt), and Google Search It has some embeeded commands like '::help' to display Launch.IT help window Use hotkeys like {Shift}+{Esc} to switch between minimized and default/maximized GUI or {Esc} to exit program. Screenshots: Download: Launch.IT.zip Launch.IT in brief: Originally, the aim of this tool was to implement an alternative to Apple's Spotlight (provided along with MacOS) in my Professional Win7 PC for more convenience (and by laziness XD). Now, I'm using this tool (which I have completely customized to add further functionalities like Calculator, Remote-Desktop, SSH, etc...) every day at work on a Win10 PC. And believe it or not, this makes me saving an incredible amount of time. Like me, do not hesitate to rework the code to add functionalities and modify Launch.IT behaviour. I hope you'll like it1 point
-
GUIRegisterMsg20 - Subclassing Made Easy
Professor_Bernd reacted to LarsJ for a topic
GUIRegisterMsg() subclasses an AutoIt GUI. Ie. a window created with GuiCreate(). A few issues are related to GUIRegisterMsg(): It cannot subclass a control Some messages cannot be handled Only one function for a specific message These issues cannot be described as errors. They are probably consequences of a design choice to limit the complexity of the function. A few issues are related to the subclassing technique in general: _WinAPI_SetWindowLong() The Subclassing bug GUIRegisterMsg20() addresses all these issues. 2020-02-23: It's probably not true that GUIRegisterMsg() is based on the subclassing technique. The messages handled by GUIRegisterMsg() are more likely to originate from the message loop in the window procedure (implemented in internal code) of the main GUI window. What is subclassing? Subclassing is a technique to get information from standard controls through Windows messages, and to modify the functionality of standard controls by responding to these messages. Eg. to change the background color of listview cells. GUIRegisterMsg20 GUIRegisterMsg20.au3 is a small UDF implemented in 100 code lines. This is the documentation for GUIRegisterMsg20(): ; Register a message handler function for a window or control message ; GUIRegisterMsg20( $vWinOrCtrl, _ ; Window handle or control ID/handle ; $WM_MESSAGE, _ ; Window message or control message ; $hFunction ) ; User supplied message handler func ; ; $vWinOrCtrl GUI handle as returned by GUICreate, controlID as returned by GUICtrlCreate<Control> functions ; or control handle as returned by _GUICtrl<Control>_Create UDF functions or GUICtrlGetHandle. ; ; $WM_MESSAGE A Windows message code as listed in Appendix section in help file. Or a control message code ; eg. a LVM_MESSAGE or TVM_MESSAGE as listed in ListViewConstants.au3 or TreeViewConstants.au3. ; This parameter is only checked to be within the valid range of Windows and control messages: ; 0x0000 - 0x7FFF. ; ; $hFunction The user supplied function (not the name but the FUNCTION) to call when the message appears. ; The function is defined in exactly the same way as the function for the official GUIRegisterMsg: ; Takes four input parameters ($hWnd, $iMsg, $wParam, $lParam) and returns $GUI_RUNDEFMSG to conti- ; nue with default message handling, or a specific value if the message is handled by the function. ; ; Error code in @error Return value ; 1 => Invalid window handle or control ID/handle Success => 1 ; 2 => Invalid Window or control message Failure => 0 ; 3 => Invalid function handle ; 4 => Too many subclasses And this is the very central internal function that is called directly from the code in ComCtl32.dll: Func GUIRegisterMsg20_Handler( $hWnd, $iMsg, $wParam, $lParam, $idx, $pData ) If $iMsg <> $aGUIRegisterMsg20[$idx][3] Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Local $vRetVal = $aGUIRegisterMsg20[$idx][4]( $hWnd, $iMsg, $wParam, $lParam ) ; Execute user supplied message handler function If $vRetVal == "GUI_RUNDEFMSG" Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Return $vRetVal #forceref $pData EndFunc It's rarely necessary to call GUIUnRegisterMsg20(). Message handlers are unregistered when the program exits. An exception is a situation where message handles are registered and unregistered on the fly, eg. due to user actions. Message monitor When it comes to topics like subclassing, a message monitor is required eg. Windows Message Monitor. ListView example Listview example is a custom drawn listview with colored cells. If we focus on subclass implementation, this is the difference between GUIRegisterMsg() and GUIRegisterMsg20() code. GUIRegisterMsg(): ; ... GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; ... GUIRegisterMsg20(): #include "..\..\Includes\GUIRegisterMsg20.au3" ; ... GUIRegisterMsg20( $hGui, $WM_NOTIFY, WM_NOTIFY ) ; ... GUIRegisterMsg20() takes $hGui as first parameter. The message handler function in third parameter is a function variable. Not a string. The message handler function, WM_NOTIFY, is exactly the same in the two examples. If you run the scripts that contains message monitor code, you will notice a remarkable difference between the two scripts. In the GUIRegisterMsg20() script, there are no NM_CUSTOMDRAW notifications in the monitor. What's the reason? All GUIRegisterMsg() examples in help file that looks like this: ; ... GUIRegisterMsg( $WM_MESSAGE, "WM_MESSAGE" ) ; ... Can be implemented with GUIRegisterMsg20() this way: ; ... GUIRegisterMsg20( $hGui, $WM_MESSAGE, WM_MESSAGE ) ; ... Input example Input example is based on this forum thread. Run Input.au3 to see the issues: You can paste a number into the control, a context menu shows up on right click, and a tooltip is displayed if you press a letter. Let's see what's going on with the message monitor. When you solve issues with a message monitor, you are generally interested in finding a particular message or a pattern of a few messages. If there are multiple instances of the message or pattern, it's easier to find. The action that generates the message or pattern should be repeated 3 - 4 times. Run "Input, wmm.au3", paste a number into the control 3 - 4 times eg. 18 (result = 18181818), right click 3 - 4 times, press a letter 3 - 4 times. Press Esc to delete Input GUI and start WMM GUI. Scroll down until you see tomato red messages. You'll see the messages WM_PASTE, WM_CONTEXTMENU and EM_SHOWBALLOONTIP. Note that all three messages are received by the Input control. This means that GUIRegisterMsg() cannot be used. It can only handle messages received by the GUI. Because all messages are received by the Input control you can register three message handlers this way in "Input, subclass.au3": ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, WM_PASTE ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, WM_CONTEXTMENU ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, EM_SHOWBALLOONTIP ) To implement message handler functions you have to read Microsoft documentation. Only for EM_SHOWBALLOONTIP it's completely clear that the message is suppressed by returning False or 0. For all three messages, however, you must return 0 to suppress the message: ; WM_PASTE message handler function Func WM_PASTE( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; WM_CONTEXTMENU message handler function Func WM_CONTEXTMENU( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; EM_SHOWBALLOONTIP message handler function Func EM_SHOWBALLOONTIP( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc As all three functions are the same, the code can be reduced a little bit in "Input, final.au3": ; GUICtrlCreateInput - Disable copy/ paste, right click menu and balloon pop-up ; https://www.autoitscript.com/forum/index.php?showtopic=179052 #include <GuiEdit.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "..\..\Includes\GUIRegisterMsg20.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Create GUI GUICreate( "Input (numbers only)", 300, 118 ) ; Create Input Local $idInput = GUICtrlCreateInput( "", 50, 50, 200, 18, $GUI_SS_DEFAULT_INPUT+$ES_NUMBER ) ; Create Label GUICtrlCreateLabel( "No paste, no context menu, no balloontip", 50, 70, 200, 18 ) ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, InputFunc ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, InputFunc ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, InputFunc ) ; Show GUI GUISetState() ; Msg loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete() EndFunc ; Input message handler function Func InputFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. Header example The width of listview columns can be changed by dragging header item separators with the mouse. If you want to disable this feature you have to suppress HDN_BEGINTRACK notifications from the header control. They are contained in WM_NOTIFY messages. And you have to suppress WM_SETCURSOR messages when the mouse cursor hover over header item separators. This prevents a cursor shape indicating that separators can be dragged. Run "ListView header, wmm.au3". Drag the header item separators forth and back. This generates a huge number of messages. Press Esc to delete GUI and start WMM GUI. Scroll down until you see tomato red messages. Note that HDN_BEGINTRACK notifications in WM_NOTIFY messages are sent first to the listview and then to the GUI. They can be catched by GUIRegisterMsg(). Here they'll be catched by GUIRegisterMsg20() from the listview. WM_SETCURSOR messages must be catched from the header: ; Subclass ListView and Header GUIRegisterMsg20( $idListView, $WM_NOTIFY, ListViewFunc ) GUIRegisterMsg20( $hHeader, $WM_SETCURSOR, HeaderFunc ) Handler functions: ; ListView message handler function Func ListViewFunc( $hWnd, $iMsg, $wParam, $lParam ) If $HDN_BEGINTRACKW = DllStructGetData( DllStructCreate( $tagNMHEADER, $lParam ), "Code" ) Then Return 1 Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ; Header message handler function Func HeaderFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 1 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Again, just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. 2020-02-23: Note that if you want to prevent the width of the listview columns from being changed you can simply add the HDS_NOSIZING style to the header control. I wasn't aware of that when I made the example. TreeView example (2018-08-15) TreeView example is based on this forum thread. Run TreeView.au3 (copied from first post in thread) to see the issue: No WM_COMMAND messages are received on right click in treeview. "TreeView, wmm.au3" shows the problem: WM_COMMAND messages generated on right clicks are sent to the treeview and not the main GUI. This means that GUIRegisterMsg() isn't able to catch the messages. To solve the problem include GUIRegisterMsg20.au3 in top of script and use GUIRegisterMsg20() to subclass the treeview as it's done in "TreeView, subclass.au3": ;... #include "..\..\Includes\GUIRegisterMsg20.au3" ;... GUIRegisterMsg20( $g_hTreeView, $WM_COMMAND, WM_COMMAND ) The existing WM_COMMAND() message handler is reused. That was two code lines to solve the problem. It can hardly be easier. Too much code (2018-09-30) A custom drawn listview generates a lot of WM_NOTIFY messages. If custom draw code is used to draw selected items with GDI-functions in the post paint drawing stage, much code will be executed to respond to all these messages. If it's also a virtual listview, it'll double the number of messages (Examples\5) Too much code\ListView.au3): Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local Static $tText = DllStructCreate( "wchar[100]" ), $pText = DllStructGetPtr( $tText ) Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ) Switch DllStructGetData( DllStructCreate( $tagNMHDR, $lParam ), "Code" ) Case $LVN_GETDISPINFOW ; Fill virtual listview Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If Not BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Return Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO,"Item")][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return Case $NM_CUSTOMDRAW ; Draw back colors Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" ), $iItem Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) If GUICtrlSendMsg( $idListView, $LVM_GETITEMSTATE, $iItem, $LVIS_SELECTED ) Then Return $CDRF_NOTIFYPOSTPAINT ; Selected item DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", $aColors[$iItem][DllStructGetData($tNMLVCUSTOMDRAW,"iSubItem")] ) ; Normal item Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem Local $hDC = DllStructGetData( $tNMLVCUSTOMDRAW, "hdc" ) ; Subitem rectangle $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) Local $iSubItem = DllStructGetData( $tNMLVCUSTOMDRAW, "iSubItem" ) DllStructSetData( $tRect, "Left", $LVIR_LABEL ) DllStructSetData( $tRect, "Top", $iSubItem ) GUICtrlSendMsg( $idListView, $LVM_GETSUBITEMRECT, $iItem, $pRect ) DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + 2 ) DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Right" ) - 2 ) DllStructSetData( $tRect, "Bottom", DllStructGetData( $tRect, "Bottom" ) - 1 ) ; Subitem back color Local $hBrush = DllCall( "gdi32.dll", "handle", "CreateSolidBrush", "int", $aColors[$iItem][$iSubItem] )[0] ; _WinAPI_CreateSolidBrush DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "bool", "DeleteObject", "handle", $hBrush ) ; _WinAPI_DeleteObject ; Draw subitem text DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0 ) ; _WinAPI_SetTextColor DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItems[$iItem][$iSubItem], "int", -1, "struct*", $tRect, "uint", $DT_CENTER ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc If there are a lot of messages and some messages perform quite a lot of code, you can end up in a situation where more code is performed than there's time for. The result is that the WM_NOTIFY messages are blocked and the code fails: You can provoke the error this way: Click a row in the listview (not one of the very top rows). Press Shift+Down arrow to select multiple rows. The problem will arise after just a few rows. Press Ctrl+Break in SciTE to stop the code. 2020-02-23: The only solution to the problem is probably to implement the WM_NOTIFY() function in compiled code as demonstrated here. Message flow (update 2018-09-30) In these examples, the message flow is examined with left and right mouse clicks. Several message handles are implemented. A standard AutoIt message loop (MessageLoop Mode) where messages are received with GUIGetMsg(). A message handler based on GUIRegisterMsg(). And a message handler created with GUIRegisterMsg20(). In addition, there is the internal AutoIt message handler (C++ code). The purpose is to determine in which order a message is received by all these different message handlers. Script 1) implements the three message handlers. By examining the message flow with the monitor we can see that the messages are received in this order: Script 2) implements an additional GUIRegisterMsg20() message handler for the same mouse click messages but with another message handler function. It seems that the last created GUIRegisterMsg20() handler, is the first to receive the mouse clicks. In script 3) mouse clicks are performed in an Edit control instead of an empty GUI. The GUIRegisterMsg() message handler does not receive the mouse clicks. At what point in the flow chart does the message monitor hook into the message flow? Since message detection is implemented through subclassing it hooks into the message flow just before the internal AutoIt message handler. Now we can answer the question from the listview example above: Why do we not see any NM_CUSTOMDRAW notifications in the message monitor from the GUIRegisterMsg20() script. Because these notifications are all answered with one of the custom draw return values and not $GUI_RUNDEFMSG. The custom draw return values goes directly back to the operating system and the messages are no longer forwarded in the message chain. The message flow stops already at the GUIRegisterMsg20() message handler function and never reaches the internal AutoIt message handler. Therefore, the messages do not reach the monitor either. The issues The listview example at the top shows that GUIRegisterMsg20() is very similar to GUIRegisterMsg(). You can do the same things with GUIRegisterMsg20() as you can do with GUIRegisterMsg(). This means that you can use GUIRegisterMsg20() in a UDF, while the user can use GUIRegisterMsg() in his own code exactly as described in the help file. From the flow chart above you know that the GUIRegisterMsg20() message handler function will receive messages before the GUIRegisterMsg() message handler function. Let's review the issues mentioned in beginning of post. Only GUIRegisterMsg20() can subclass a control and receive control messages. This is demonstrated in the input example. The mouse clicks in the edit control discussed above shows that GUIRegisterMsg() isn't receiving all WM_MESSAGEs and therefore cannot handle these messages. The mouse clicks in the section above also shows that GUIRegisterMsg20() can use several functions for the same message. Because GUIRegisterMsg20() uses SetWindowSubclass to implement subclassing, problems related to _WinAPI_SetWindowLong() are avoided. Because GUIRegisterMsg20() returns directly from the DefSubclassProc DllCall, the subclassing bug never comes into play. Conclusion GUIRegisterMsg20 UDF takes care of the tedious and cumbersome task of configuring subclassing. Ie. to set up SetWindowSubclass, DefSubclassProc and RemoveWindowSubclass functions. It uses a message handler function that is very similar to the function used in the official GUIRegisterMsg(). You can concentrate on analyzing the message flow and code the message handler function. 7z-file You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Note that the contents of the Includes folder in the Windows Message Monitor 7z-file must be installed in the WMMincl directory to use Windows Message Monitor. Comments are welcome. Let me know if there are any issues. GUIRegisterMsg20.7z1 point -
The collection of examples in .NET Common Language Runtime (CLR) Framework shows that there are virtually no limits to the possibilities that the usage of .NET Framework and .NET code in AutoIt opens up for. One possibility which certainly is very interesting is the possibility of using C# and VB code in AutoIt. That is, to create, compile and execute C# and VB source code directly through an AutoIt script without the need for any external tools at all, eg. an integrated development environment (IDE) program or similar. You can even create a .NET assembly dll-file with your C# or VB code that you can simply load and execute. Why is it interesting to execute C# or VB code in an AutoIt script? It's interesting because C# and VB code is executed as compiled code and not as interpreted code like AutoIt code. Compiled code is very fast compared to interpreted code. In AutoIt and all other interpreted languages probably 99% or more of the total execution time is spend by the code interpretor to interpret the code lines, while only 1% or less of the total execution time is spend by executing the actual code. Compiled code is directly executable without the need for a code interpretor. That's the reason why compiled code is so much faster than interpreted code. Using C# and VB code in AutoIt is interesting because it can be used to performance optimize the AutoIt code. There may be many other good reasons for using C# and VB code in AutoIt, but here the focus is on code optimization. In the help and support forums you can regularly find questions related to this topic. You can find many examples where assembler code is used in connection with performance optimization. Recently, there has been some interest in FreeBASIC. Code optimization is clearly a topic that has some interest. How difficult is writing C# and VB code compared to assembler and FreeBASIC code? It's certainly much easier and faster than writing assembler code. Because you can do everything through AutoIt without the need for an IDE, it's probably also easier than FreeBASIC. As usually you get nothing for free. The cost is that there is some overhead associated with executing compiled code. You must load and start the code. You need methods to move data back and forth between the AutoIt code and the compiled code. You'll not see that all compiled code is 100 times faster than AutoIt code. Somewhere between 10 and 100 times faster is realistic depending on the complexity of the code. And probably also only code running in loops is interesting and preferably a lot of loops. How C# and VB code can be used in AutoIt through .NET Framework is what this example is about. The rest of first post is a review of introductory C# and VB examples. The purpose of the examples is to make it easier to use C# and VB code in AutoIt. They show how to do some of the basic things in C#/VB that you can do in AutoIt. They focus on topics that are relevant when both AutoIt and C#/VB code is involved. Eg. how to pass variables or arrays back and forth between AutoIt and C#/VB code. The examples are not meant to be a regular C#/VB tutorial. C# and VB Guides in Microsoft .NET Documentation is a good place to find information about C# and VB code. Dot Net Perls example pages have some nice examples. To avoid first post being too long, three posts are reserved for topics that will be presented in the coming weeks. DotNet.au3 UDF DotNet.au3 UDF to access .NET Framework from AutoIt is used to access the .NET Framework. But you do not at all need a detailed knowledge of the code in DotNet.au3 to use C#/VB code in AutoIt. The UDF is stored as DotNetAll.au3 in Includes\ in the zip-file in bottom of post. Includes\ only contains this file. Introductory C# and VB examples The code in the examples below is VB code. But the zip-file in bottom of post contains both C# and VB versions of the examples. Code templates This is the vb and au3 code templates that's used in all of the examples. TemplateVB.vb (TemplateVB-a.vb is provided with comments): Imports System Class Au3Class Public Sub MyMethod() Console.WriteLine( "Hello world from VB!" ) End Sub End Class Note that Console.WriteLine writes output to SciTE console. TemplateVB.au3: #include "..\..\..\Includes\DotNetAll.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() Local $oNetCode = DotNet_LoadVBcode( FileRead( "TemplateVB.vb" ), "System.dll" ) Local $oAu3Class = DotNet_CreateObject( $oNetCode, "Au3Class" ) $oAu3Class.MyMethod() EndFunc Usually, 2 code lines are sufficient to make .NET code available in AutoIt. DotNet_LoadVBcode() compiles the VB code, creates the .NET code in memory, loads the code into the default domain and returns a .NET code object which is a reference to the .NET code. DotNet_CreateObject() takes the .NET code object and a class name as input parameters and creates an object from the class. See DotNet.au3 UDF. Now the sub procedure MyMethod in the VB code can be executed as an object method. Most examples contains just a few code lines like the templates. I don't want to review all examples, but to get an idea of what this is about, here's a list of the top level folders in the zip-file: Code templates Introductory topics Comments Comment block Line continuation ConsoleWrite MessageBox Public keyword Multiple methods Subs, functions Global variable Error handling Missing DLL-file Imports, using CS-VB mismatch Code typing errors Set @error macro Passing variables Passing 1D arrays Passing 2D arrays Simple examples Prime numbers Create DLL Prime numbers So far, there is only one example with more than just a few code lines. This is an example of calculating prime numbers. This example is also used to show how to create a .NET assembly dll-file. These two examples are reviewed with more details below. Prime numbers The example calculates a certain number of prime numbers and returns the prime numbers as a 1D array. It shows how to pass an AutoIt variable (number of prime numbers) to the C#/VB code and how to return a 1D array of integers (the prime numbers) from the C#/VB code to AutoIt. Especially arrays are interesting in relation to compiled code. This is Microsoft documentation for VB arrays and C# arrays. Design considerations If you want to create a UDF that uses advanced techniques such as compiled code, and you want to make it available to other members, you should consider the design. Consider how the code should be designed to be attractive to other members. You should probably not design the code so other members will need to execute .NET code, create objects, and call object methods in their own code. This should be done in a function in the UDF so that a user can simply call an easy-to-use AutoIt function in the usual way. AutoIt and VB code There are three versions of the example. A pure AutoIt version in the au3-folder, an AutoIt/VB version in the VB-folder and an AutoIt/C# version in the CS-folder. The pure AutoIt and the AutoIt/VB versions are reviewed below. AutoIt code in au3\CalcPrimes.au3. This is the pure AutoIt UDF to calculate primes: #include-once Func CalcPrimes( $nPrimes ) Local $aPrimes[$nPrimes], $iPrime = 2, $iPrimes = 0 If $nPrimes <= 100 Then ConsoleWrite( $iPrime & @CRLF ) ; Store first prime $aPrimes[$iPrimes] = $iPrime $iPrimes += 1 $iPrime += 1 ; Loop to calculate primes While $iPrimes < $nPrimes For $i = 0 To $iPrimes - 1 If Mod( $iPrime, $aPrimes[$i] ) = 0 Then ExitLoop Next If $i = $iPrimes Then If $nPrimes <= 100 Then ConsoleWrite( $iPrime & @CRLF ) $aPrimes[$iPrimes] = $iPrime $iPrimes += 1 EndIf $iPrime += 1 WEnd Return $aPrimes EndFunc Note the similarity between the AutoIt code above and the VB code below. If you can write the AutoIt code you can also write the VB code. VB code in VB\CalcPrimesVB.vb to calculate primes: Imports System Class PrimesClass Public Function CalcPrimes( nPrimes As Integer ) As Integer() Dim aPrimes(nPrimes-1) As Integer, iPrime As Integer = 2, iPrimes As Integer = 0, i As Integer If nPrimes <= 100 Then Console.WriteLine( iPrime ) 'Store first prime aPrimes(iPrimes) = iPrime iPrimes += 1 iPrime += 1 'Loop to calculate primes While iPrimes < nPrimes For i = 0 To iPrimes - 1 If iPrime Mod aPrimes(i) = 0 Then Exit For Next If i = iPrimes Then If nPrimes <= 100 Then Console.WriteLine( iPrime ) aPrimes(iPrimes) = iPrime iPrimes += 1 End If iPrime += 1 End While Return aPrimes End Function End Class AutoIt code in VB\CalcPrimesVB.au3. This is the AutoIt/VB UDF to calculate primes. #include-once #include "..\..\..\..\..\Includes\DotNetAll.au3" Func CalcPrimesVBInit() CalcPrimesVB( 0 ) EndFunc Func CalcPrimesVB( $nPrimes ) Static $oNetCode = 0, $oPrimesClass = 0 If $nPrimes = 0 Or $oNetCode = 0 Then ; Compile and load VB code, create PrimesClass object $oNetCode = DotNet_LoadVBcode( FileRead( "CalcPrimesVB.vb" ), "System.dll" ) $oPrimesClass = DotNet_CreateObject( $oNetCode, "PrimesClass" ) If $nPrimes = 0 Then Return EndIf ; Execute CalcPrimes method and return 1D array of primes Return $oPrimesClass.CalcPrimes( $nPrimes ) EndFunc Note the initialization code in CalcPrimesVB() where the VB code is compiled and loaded and the $oPrimesClass object is created. If the user forgets to call CalcPrimesVBInit() it'll work anyway. Examples with pure AutoIt code in au3\Examples.au3. This is user code: #include <Array.au3> #include "CalcPrimes.au3" Opt( "MustDeclareVars", 1 ) Examples() Func Examples() ShowPrimes( 10 ) ; Used under development ShowPrimes( 1000 ) ; 400 milliseconds ShowPrimes( 5000 ) ; 8 seconds EndFunc Func ShowPrimes( $nPrimes ) ConsoleWrite( "$nPrimes = " & _ $nPrimes & @CRLF ) Local $hTimer = TimerInit() Local $aPrimes = CalcPrimes( $nPrimes ) ConsoleWrite( "Time = " & _ TimerDiff( $hTimer ) & @CRLF & @CRLF ) _ArrayDisplay( $aPrimes ) EndFunc Note again that the user code in the pure AutoIt examples above is almost identical to the user code in the AutoIt/VB examples below. The only difference the user will notice is the speed. To calculate 5000 prime numbers, the C#/VB code is 100 times faster. Try yourself. Examples with AutoIt/VB code in VB\ExamplesVB.au3. This is user code: #include <Array.au3> #include "CalcPrimesVB.au3" Opt( "MustDeclareVars", 1 ) ExamplesVB() Func ExamplesVB() CalcPrimesVBInit() ShowPrimesVB( 10 ) ; Used under development ShowPrimesVB( 1000 ) ; 10 milliseconds ShowPrimesVB( 5000 ) ; 80 milliseconds ShowPrimesVB( 10000 ) ; 200 milliseconds ;ShowPrimesVB( 50000 ) ; 5 seconds EndFunc Func ShowPrimesVB( $nPrimes ) ConsoleWrite( "$nPrimes = " & _ $nPrimes & @CRLF ) Local $hTimer = TimerInit() Local $aPrimes = CalcPrimesVB( $nPrimes ) ConsoleWrite( "Time = " & _ TimerDiff( $hTimer ) & @CRLF & @CRLF ) _ArrayDisplay( $aPrimes ) EndFunc .NET assembly dll-file In a production environment the compiled VB code should be stored in a .NET assembly dll-file. The first step is to create the dll-file from the VB source code: #include "..\..\..\..\..\Includes\DotNetAll.au3" ; Compile VB code and load the code into CalcPrimesVB.dll: A .NET assembly dll-file DotNet_LoadVBcode( FileRead( "CalcPrimesVB.vb" ), "System.dll", 0, "CalcPrimesVB.dll" ) ; You can delete the PDB-file (binary file containing debug information) If you inspect the dll-file with ILSpy.exe (see DotNet.au3 UDF) you'll see these comments in top of the output in the right pane window: // ...\7) Create DLL\Prime numbers\VB\CalcPrimesVB.dll // CalcPrimesVB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // Global type: <Module> // Architecture: AnyCPU (64-bit preferred) // Runtime: .NET 4.0 Note that the dll-file can be used in both 32 and 64 bit code (Architecture: AnyCPU). The second step is to modify the AutoIt/VB UDF to load the code from the dll-file: #include-once #include "..\..\..\..\..\Includes\DotNetAll.au3" Func CalcPrimesVBInit() CalcPrimesVB( 0 ) EndFunc Func CalcPrimesVB( $nPrimes ) Static $oNetCode = 0, $oPrimesClass = 0 If $nPrimes = 0 Or $oNetCode = 0 Then ; Load CalcPrimesVB.dll and create PrimesClass object $oNetCode = DotNet_LoadAssembly( "CalcPrimesVB.dll" ) $oPrimesClass = DotNet_CreateObject( $oNetCode, "PrimesClass" ) If $nPrimes = 0 Then Return EndIf ; Execute CalcPrimes method and return 1D array of primes Return $oPrimesClass.CalcPrimes( $nPrimes ) EndFunc The user code in the examples is exactly the same. But in a production environment the AutoIt user code is usually compiled into an exe-file. Please compile the user code and double click the exe-file to run it. If the AutoIt user code is compiled into an exe-file and the VB dll-file is stored in the same folder as the exe-file, the AutoIt code is always able to find and load the VB dll-file. Summary C# and VB code through .NET Framework is without any doubt the absolute easiest way to execute compiled code in an AutoIt script. It's especially easy because everything (write, compile, load and execute the code and even create an assembly dll-file) can be done through AutoIt. There is no need for any external tools at all. Usually, only 2 lines of AutoIt code are required to make the compiled code available in an AutoIt script. When it comes to calculations and array manipulations, the difference between C#/VB code and AutoIt code is not that big. Under development of C#/VB code (debug) information can be written to SciTE console or a message box. Syntax errors in the code are reported in SciTE console. Because the compiled code is executed as object methods, this solves an otherwise impossible problem of passing arrays back and forth between AutoIt code and compiled code. Posts below Real C# and VB examples. Four examples about generating a 2D array of random data, sorting the array by one or more columns through an index, converting the 2D array to a 1D array in CSV format, and finally saving the 1D array as a CSV file. Post 2. UDF version of examples in post 2. Also a version with a .NET assembly dll-file. Post 3. Adv. C# and VB examples. An introduction to threading. Post 4. Some considerations regarding calculation of prime numbers. Post 7. Optimizing C# and VB code. Optimizing code through multithreading. Optimizing code by storing array as global variable in VB code, thereby avoiding spending time passing arrays back and forth between AutoIt code and VB code. Post 8. Zip-file The zip-file contains two folders: Examples\ and Includes\. Includes\ only contains DotNetAll.au3. You need AutoIt 3.3.10 or later. Tested on Windows 10, Windows 7 and Windows XP. Comments are welcome. Let me know if there are any issues. UsingCSandVB.7z1 point
-
Capturing EXE Console output and response
FrancescoDiMuro reacted to water for a topic
Welcome to AutoIt and the forum! Did you have a look at StdinWrite and StdoutRead?1 point -
Question on adding functionality to an application
Fractured reacted to FrancescoDiMuro for a topic
@Fractured About your questions... 1) ControlTreeView() controls any Treeview of almost any GUI, even if it's not created by you; 2) AfxOleControl is the class name of the control. If you try to get information about the Toolbar in Notepad++, you'll see that it changes; but, when you have the handle of that control, you can do almost everthing with it. I can't ask you to make a reproducer script, so, I can only say what you could try EDIT: Reading you last post, seems that there is a Dll that it's used to read data from AfxOleControl, is it right?1 point -
No Response at Client-server Program
Earthshine reacted to Zero_T for a topic
1 point -
Question on adding functionality to an application
Fractured reacted to FrancescoDiMuro for a topic
@Fractured Since you are going forward with you script, let me give you a little hint... There are several functions to deal with Treeview controls: _GUICtrlTreeView_* functions and ControlTreeView()1 point -
Question on adding functionality to an application
Fractured reacted to FrancescoDiMuro for a topic
@Fractured Have you already tried with Win* functions and/or Control* functions to see if you can automate it in some way?1 point -
Retrieve all links from website and save to Notepad
FrancescoDiMuro reacted to Subz for a topic
I'm bored so here is a working example: #include <IE.au3> Local $bFileOpen = False, $hFileOpen, $sFileOpen = @ScriptDir & "\twstlinks.txt" Local $sSearch = "https://www.twst.com/interview/" Local $iSearch = StringLen($sSearch) Local $oIE = _IECreate("https://www.twst.com/", 1) Local $oLinks = _IELinkGetCollection($oIE) If IsObj($oLinks) Then For $oLink In $oLinks If StringLeft($oLink.href, $iSearch) = $sSearch Then _WriteLinks($oLink.href) Next EndIf If $bFileOpen Then FileClose($hFileOpen) Func _WriteLinks($_sLink) If $bFileOpen Then FileWrite($hFileOpen, $_sLink & @CRLF) Else $hFileOpen = FileOpen($sFileOpen, 1) FileWrite($hFileOpen, $_sLink & @CRLF) $bFileOpen = True EndIf EndFunc1 point -
Then you use () to embed the wanted part: Local $iLIP1= StringRegExp('Anakin."120" Yoda', 'Anakin."(\d+)" Yoda', 3) ; currently untested Simpel1 point
-
If you want 120 extracted from the sample text, then try this. #include <Array.au3> Local $aLIP1 = StringRegExp('Star."100" Anakin."120" Yoda."140" Wars', 'Anakin\."(\d+)" Yoda', 3) ; "(\d+)" - this group captures only digits. _ArrayDisplay($aLIP1, "ana") ; Array only contains $aLIP1[0] = 120 ; or MsgBox(0, "Result", StringRegExp('Star."100" Anakin."120" Yoda."140" Wars', 'Anakin\."(\d+)" Yoda', 3)[0])1 point
-
Button and Checkboxes
Moist reacted to FrancescoDiMuro for a topic
@Moist GUISetOnEvent() is to set a function to run when an event is fired from a GUI; GUICtrlSetOnEvent() is to set a function to run when a control fire some events ( a click, for example ). So, use: GUICtrlSetOnEvent($btnExitButton, "ExitApplication") ; For a Control GUISetOnEvent($GUI_EVENT_CLOSE, "ExitApplication") ; For the GUI1 point -
Button and Checkboxes
pixelsearch reacted to FrancescoDiMuro for a topic
@Moist You can use the Select statement to do what you are trying to do #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Opt("GUIOnEventMode", 1) #Region ### START Koda GUI section ### Form= Global $frmMainForm = GUICreate("A Form", 161, 112, -1, -1) GUISetOnEvent($GUI_EVENT_CLOSE, "ExitApplication") Global $chkCheckbox1 = GUICtrlCreateCheckbox("First Checkbox", 16, 15, 113, 17) GUICtrlSetFont(-1, 10, 400, 0, "Arial") Global $chkCheckbox2 = GUICtrlCreateCheckbox("Second Checkbox", 16, 39, 129, 17) GUICtrlSetFont(-1, 10, 400, 0, "Arial") Global $btnButton1 = GUICtrlCreateButton("Button", 43, 71, 75, 25) GUICtrlSetFont(-1, 10, 800, 0, "Arial") GUICtrlSetOnEvent(-1, "ButtonPress") GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 Sleep(100) WEnd Func ExitApplication() Exit EndFunc Func _IsChecked($idControlID) Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED EndFunc Func ButtonPress() Select Case _IsChecked($chkCheckbox1) And _IsChecked($chkCheckbox2) ConsoleWrite("Both Checkboxes are selected." & @CRLF) Case _IsChecked($chkCheckbox1) ConsoleWrite("Checkbox1 is selected." & @CRLF) Case _IsChecked($chkCheckbox2) ConsoleWrite("Checkbox2 is selected." & @CRLF) Case Else ConsoleWrite("No checkboxes selected." & @CRLF) EndSelect EndFunc1 point -
As it is considered not as a core item and people should be able to choose their editor of choice. I solely maintain the SciTE4AutoIt installer and only the SciTE source is part of the shared SVN, all other sources of the compiled programs (tidy,au3stripper) aren't shared. Jos1 point
-
Read ListBox Text
caramen reacted to FrancescoDiMuro for a topic
@caramen Once you have the handle of the ListBox, why don't you use _GUICtrlListBox_GetText as I've already suggested to you? $cControlIDForti = ControlGetHandle($cHNW2, "" , "[CLASS:ListBox; INSTANCE:1]") MsgBox (0,"",$cControlIDForti) ; Handle of the ListBox $cControlIDFortiCount = _GUICtrlListBox_GetCount($cControlIDForti) ; Items count in the ListBox MsgBox (0,"",$cControlIDFortiCount) ; $cFortiDoneStat= _GUICtrlGetText($cControlIDFortiCount) ; _GUICtrlGetText, a function that you may dreamed? ; Taking a text from a number? What the ?! For $i = 1 To $ControlIDFortiCount ConsoleWrite("Item " & $i & " text is '" & _GUICtrlListBox_GetText($cControlIDForti, $i) & "'." & @CRLF) Next Try it and let us know.1 point -
How do I check if command prompt requires input?
FrancescoDiMuro reacted to spudw2k for a topic
If you can't rely on checking the output to determine which command(s) are halting your process/script, how do you expect to know how to respond with proper input? Can you give a real-world example of what you are running into?1 point -
[SOLVED] How to tell Autoit that "A" is different than "a"
nooneclose reacted to Malkey for a topic
It appears you need to understand the AutoIt help file. Look up the StringReplace function in the AutoIt help file. (Cursor over StringReplace in SciTE and press F1 key) See "StringReplace ( "string", "searchstring/start", "replacestring" [, occurrence = 0 [, casesense = 0]] ) Note: the square barackets around the two last optional parameters, each show their default values of zero. When the 5th parameter, casesense, needs to be 1, the 0ptional 4th parameter will be need to be in place in order to identify the 5th parameter. In the include file "StringConstants.au3" you will find the variable, "$STR_CASESENSE" equal to 1. So, the 5th parameter can be "$STR_CASESENSE" or "1", they are the same value. Also note:- Return Value Returns the new string .... #include <StringConstants.au3> ; Variable $Encode contains the new string $Encode = StringReplace(StringReplace(StringReplace($test_String, $charAA, $ch184, 0, $STR_CASESENSE), $chara, $ch251, 0, $STR_CASESENSE), $charBB, $char195, 0, $STR_CASESENSE)1 point -
[SOLVED] How to tell Autoit that "A" is different than "a"
nooneclose reacted to water for a topic
You are using the parameter the wrong way: Just 1, not $str_casesense=11 point