Leaderboard
Popular Content
Showing content with the highest reputation on 02/18/2020 in all areas
-
DotNet.au3 UDF to access .NET Framework from AutoIt
stevepresley reacted to LarsJ for a topic
.NET Common Language Runtime (CLR) Framework was published five months ago. CLR.au3 which is the main UDF makes it possible to execute .NET code directly in an AutoIt script. .NET code in this context should be perceived in a very broad sense. As shown in the examples, there are virtually no limits to the possibilities that the UDF opens up for. .NET Common Language Runtime (CLR) Framework is the result of the work in Using .NET libary with AutoIt, possible? CLR.au3 is implemented in this thread. Most of the code in CLR.au3 is a translation of CLR.ahk from .NET Framework Interop (CLR, C#, VB) in the AutoHotkey forum. DotNet.au3 is a complete translation of CLR.ahk. This example is about DotNet.au3. It contains information about the functions in the UDF. Usage of the functions is demonstrated through small examples. And there is a description of a few .NET Framework concepts. The AutoHotkey project The AutoHotkey project started in .NET Framework Interop in autumn 2009. The latest update of CLR.ahk in .NET Framework Interop (CLR, C#, VB) was november 2011. The whole project seems to have been developed over this 3-year period. The project was developed by Lexikos in the AutoHotkey forum. He certainly looks very knowledgeable about the code in the .Net Framework and he has done a great job in implementing the AutoHotkey code in CLR.ahk. Lots of credit to Lexikos. If you want to test the AutoHotkey code, you can find a recipe here. DotNet.au3 Because a lot of COM support is included internally in AutoHotkey and especially because AutoHotkey natively supports safearrays, the code in CLR.ahk is short and compact. 150 code lines. In the zip-file below AutoIt safearray support is implemented in two separate UDFs: SafeArray.au3 and AccVarsUtilities.au3. Both of these UDFs were started in Accessing AutoIt Variables. That way, it has also been possible to keep the code in DotNet.au3 short and compact. 190 code lines. You should take a look at DotNet.au3. It's nice and easily readable code (maybe not so easy to understand, but easy to read). 7 functions DotNet.au3 contains 7 functions and 2 internal functions. The first 3 functions DotNet_Start(), DotNet_StartDomain() and DotNet_StopDomain() are only used to optimize the .NET Framework host (more about .NET concepts below). If you are satisfied with the default .NET Framework host, you can completely skip these functions. The next 3 functions DotNet_LoadAssembly(), DotNet_LoadCScode() and DotNet_LoadVBcode() are used to load .NET code into a domain. Before it's possible to execute .NET code it must be loaded into a domain. If DotNet_Start() and DotNet_StartDomain() have not been called, DotNet_Start() is called automatically by the 3 functions and the default domain is used to execute .NET code. DotNet_LoadAssembly() loads .NET code in a .NET assembly DLL-file into a domain. The other functions compiles C# and VB source code on the fly, creates a .NET assembly DLL-file in memory and loads the assembly file into a domain. All 3 functions returns a .NET code object which is a reference to the .NET code. The last function DotNet_CreateObject() takes a .NET code object and a class name as input parameters and creates an object as an instance of the class. The class must be defined in the .NET code. Because .NET code is object-oriented code, everything is performed through objects. Now the methods of the object can be called and this executes the functions in the .NET code. Below is a brief description of the 7 functions. $oRuntimeHost = DotNet_Start( $sVersion = "" ) DotNet_Start() Loads the .NET Framework code-execution environment known as the CLR into the AutoIt process and returns a .NET runtime host (a .NET Framework host). Default is to use the latest version of .NET Framework installed on the PC. Specify $sVersion eg. "v2.0.50727" to use an older version of .NET Framework. DotNet_Start() is automatically called by the other functions in DotNet.au3. You only need to call DotNet_Start() if you want to use an older version of .NET Framework. @error = 1 indicates that DotNet_Start() has failed. DotNet_StartDomain( ByRef $oAppDomain, $sFriendlyName = "", $sBaseDirectory = "" ) Creates and starts a user domain to run .NET code. Several user domains can be created and started at the same time. $oAppDomain is the returned domain object. $sFriendlyName is a name to identify the domain. $sBaseDirectory is the base directory where from .NET assemblies are loaded into the domain. The only purpose of $sFriendlyName is to be able to recognize the domain when the domains are listed with DotNet_ListDomains(). DotNet_ListDomains() is a utility function implemented in DotNetUtils.au3. The purpose of $sBaseDirectory is to be able to specify the directory where .NET assemblies are stored. The usage of $sBaseDirectory is demonstrated in examples. A default domain is automatically created by the other functions in DotNet.au3. You only need to call DotNet_StartDomain() if you want to specify a base directory for the domain. DotNet_StopDomain( ByRef $oAppDomain ) Unloads .NET assemblies loaded into the user domain and stops the domain. $oAppDomain is the domain object. The default domain cannot be stopped. $oNetCode = DotNet_LoadAssembly( $sAssemblyName, $oAppDomain = 0 ) DotNet_LoadAssembly() loads .NET code in a .NET assembly DLL-file into a domain and returns a .NET code object (a reference to the .NET code). $sAssemblyName is the name of the assembly DLL-file. $oAppDomain is the user domain. If no user domain is specified the assembly is loaded into the default domain. @error = 2 indicates that DotNet_LoadAssembly() has failed. $oNetCode = DotNet_LoadCScode( $sCode, $sReferences = "", $oAppDomain = 0, $sFileName = "", $sCompilerOptions = "" ) $oNetCode = DotNet_LoadVBcode( $sCode, $sReferences = "", $oAppDomain = 0, $sFileName = "", $sCompilerOptions = "" ) DotNet_LoadCScode() and DotNet_LoadVBcode() compiles C# and VB source code on the fly, creates a .NET assembly DLL-file in memory, loads the assembly file into a domain and returns a .NET code object. $sCode is the C# or VB source code. $sReferences is a pipe (|) delimited list of .NET DLL assemblies that the C#/VB code requires. Eg. "System.dll" or "System.Windows.Forms.dll". $oAppDomain is the user domain. If no user domain is specified the code is loaded into the default domain. The other parameters are related to the compilation process. If $sFileName is the name of a DLL-file the code is compiled into a .NET assembly DLL-file. Else the code is compiled in memory. $sCompilerOptions is rarely used. See Microsoft documentation for details. @error = 3/4 indicates that DotNet_LoadCScode() or DotNet_LoadVBcode() has failed. @error = 5 indicates a syntax error in the C# or VB source code. Such an error can be corrected by correcting the error in the source code. $oObject = DotNet_CreateObject( ByRef $oNetCode, $sClassName, $v3 = Default, ..., $v9 = Default ) DotNet_CreateObject() creates an object as an instance of a class. $oNetCode is a .NET code object as returned by one of the functions DotNet_LoadAssembly(), DotNet_LoadCScode() or DotNet_LoadVBcode(). $sClassName is the name of a class defined in the .NET code. The other parameters depends on the specific class. Summary Two functions must be called to execute .NET code directly in an AutoIt script. One of the functions DotNet_LoadAssembly(), DotNet_LoadCScode() or DotNet_LoadVBcode() to load the .NET code into a domain. And DotNet_CreateObject() to create an object from a class defined in the .NET code. Now the functions in the .NET code can be executed by calling the methods of the object. .NET concepts The .NET CLR In more or less the same way as AutoIt3.exe or AutoIt3_x64.exe is needed to run AutoIt code, the .NET CLR (Common Language Runtime) or the .NET Framework code-execution environment is needed to run .NET code. To be able to run .NET code inside an AutoIt script, the CLR or the .NET Framework code-execution environment must be loaded into the AutoIt process. This is the purpose of DotNet_Start(). The CLR can be loaded into a process through several of the functions in MSCorEE.dll. CorBindToRuntimeEx is one of these functions. DotNet_Start() executes CorBindToRuntimeEx in MSCorEE.dll and loads the CLR into the AutoIt process. A program or a part of a program which is able to start the CLR and execute .NET code is referred to as a .NET runtime host, a CLR host or simply a .NET Framework host. The code in DotNet.au3 implements an AutoIt .NET Framework host. Managed/unmanaged code .NET code which is executed (or managed) through the functions in the CLR is referred to as managed code. C# and VB code is managed code. Code which is not executed through the functions in the CLR is referred to as unmanaged code. AutoIt code is unmanaged code. You usually only distinguish between managed/unmanaged code in relation to .NET code and the .NET Framework. When you are executing .NET code there is often a part of both unmanaged and managed code involved. If you are executing .NET code through AutoIt, the AutoIt code is the unmanaged code and the .NET code is the managed code. The functions in MSCorEE.dll are some of the functions which belongs to the .NET Framework that can be executed from unmanaged code eg. AutoIt code. That's the reason why these functions are used to start the .NET Framework. The COM interfaces _AppDomain, _Assembly and _Type in Interfaces.au3 are some of the interfaces which belongs to the .NET Framework that can be used in unmanaged code. That's the reason why these interfaces are used to implement the functions in DotNet.au3. Managed code like C# cannot be translated into unmanaged code like AutoIt. There is no way to translate a command like "using System;" from C# to AutoIt. In many situations you can implement the same code in AutoIt as you can in C#. But that's generally not a simple translation of the C# code. It's a new implementation of the code. .NET domains With the functions in DotNet.au3 you can create an AutoIt .NET Framework host as shown in this picture: The blue box illustrates the unmanaged AutoIt code which is used to start the .NET Framework and load the CLR into the AutoIt process. The red box illustrates the default domain and several user domains where the managed .NET code is executed. Managed .NET code is always executed within a domain. The purpose of DotNet_StartDomain() and DotNet_StopDomain() is to create, start and stop user domains. If DotNet_StartDomain() isn't called the default domain is used. A domain in managed code is equivalent to a process in unmanaged code. The purpose of domains is to prevent that a crash in one part of the .NET code should lead to a crash in all of the .NET code. A crash of the code in a domain makes the domain inapplicable and a new domain must be created with DotNet_StartDomain(). This is very similar to the way that code is executed in separate processes in the operating system. The purpose of executing code in separate processes is (among other things) to prevent that a crash of the code in one process should lead to a crash of the code in several processes and finally to a crash of the entire operating system. A crash of the code in the default domain makes the entire CLR, that's loaded into the AutoIt process inapplicable. Because it's only possible to load the CLR into the same process once, the only way to reload the CLR is to restart the entire AutoIt process. That is to stop and start the AutoIt script. Usually it does not matter if the default domain or a user domain is used to execute .NET code. It's only strictly necessary to create a user domain if there is a need to specify a base directory for .NET assemblies. The only way to specify a base directory is through DotNet_StartDomain(). .NET assemblies Before it's possible to execute .NET code in a domain, the code must be loaded into the domain. Code is always loaded into a domain through a .NET assembly. This is also the case when .NET code is created on the fly by compiling C# or VB code in memory. Then the .NET code is stored in a .NET assembly which is created in memory and therefrom loaded into the domain. The purpose of DotNet_LoadAssembly() is to load .NET code in a .NET assembly DLL-file into a domain. Either the default domain or a user domain. The purpose of DotNet_LoadCScode() and DotNet_LoadVBcode() is to compile C# and VB code on the fly, create a .NET assembly in memory and load the .NET code into a domain. All 3 functions returns a .NET code object which can be used in DotNet_CreateObject() to create .NET objects. When a .NET assembly is stored as a file on disk it's usually stored with a DLL- or an EXE-extension. It contains information about classes, objects, methods, properties, events, datatypes etc. concerning the resources in the assembly. It's a binary file. A .NET assembly DLL-file should not be confused with a standard DLL-file eg. a DLL-file that belongs to the Windows operating system. A .NET assembly DLL-file contains managed code. A standard DLL-file contains unmanaged code. In the same way as there are tools to extract information about the code in a standard DLL-file, there are also tools to extract information about the code in a .NET assembly DLL-file. One of these tools is ILSpy. More about ILSpy in examples section below. .NET objects Because .NET code is object-oriented code, everything is performed through objects, properties and methods. When functions are executed in .NET code, they are executed as object methods. DotNet_CreateObject() takes a .NET code object as returned by DotNet_LoadAssembly(), DotNet_LoadCScode() or DotNet_LoadVBcode() and a class name as input parameters and creates a .NET object as an instance of the class. The class must be defined in the .NET code. Now the methods of the object can be called and this executes the functions in the .NET code. Examples The Examples folder contains scripts to demonstrate the usage of the functions in DotNet.au3. In scripts where .NET code is needed for the demonstration, the code is copied from original AutoHotkey examples: An example with a XPTable.dll .NET assembly (implemented in AutoIt in this post) and two simple C# and VB code examples. I don't want to review all examples. The examples are small examples like this: #include "..\..\Includes\DotNet.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Start the latest version of .NET Framework ; DotNet_Start() is automatically called by the other functions in DotNet.au3 ; You only have to call DotNet_Start() if you need an older version of .NET Framework DotNet_Start() If @error Then Return ConsoleWrite( "DotNet_Start ERR" & @CRLF ) ConsoleWrite( "DotNet_Start OK" & @CRLF ) EndFunc The example simply starts the .NET Framework from an AutoIt script. Run the examples in SciTE by pressing F5 on the keyboard. A few examples with "(compile me)" in the file name must be compiled. Run these examples by double-clicking the exe-file. ILSpy .NET assembly browser ILSpy is an open-source .NET assembly browser. Download ILSpy_Master_2.4.0.1963_Binaries.zip, unzip it and run ILSpy.exe. There is no installer. If you open \Examples\4) DotNet_LoadAssembly\XPTable.dll through the File | Open... menu you'll see this information in the right pane window: // ...\Examples\4) DotNet_LoadAssembly\XPTable.dll // XPTable, Version=1.1.0.27823, Culture=neutral, PublicKeyToken=24950705800d2198 // Global type: <Module> // Architecture: AnyCPU (64-bit preferred) // Runtime: .NET 1.1 using System; using System.Reflection; [assembly: AssemblyVersion("1.1.0.27823")] [assembly: CLSCompliant(true)] [assembly: AssemblyCompany("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCopyright("Copyright © 2005, Mathew Hall. All rights reserved.")] [assembly: AssemblyDelaySign(false)] [assembly: AssemblyDescription("A fully customisable ListView style control based on Java's JTable")] [assembly: AssemblyKeyFile("..\\..\\XPTable.snk")] [assembly: AssemblyKeyName("")] [assembly: AssemblyProduct("XPTable")] [assembly: AssemblyTitle("XPTable")] [assembly: AssemblyTrademark("")] Note the comments in the top. This line: // Architecture: AnyCPU (64-bit preferred) means that the DLL-file can be used as both a 32 and a 64 bit .NET assembly DLL-file. Using C# and VB Code in AutoIt Using C# and VB Code in AutoIt through .NET Framework is an example that uses DotNet.au3 UDF in order to be able to execute compiled C# and VB code in AutoIt scripts. Zip-file The zip-file contains two folders: Examples\ and Includes\. The project depends on eight include files of which DotNet.au3 is the actual UDF. To make it easier to use the UDF, all include files are collected in one large file: DotNetAll.au3. To use DotNet.au3 UDF in your own project just include 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. DotNet.7z1 point -
Lua Wrapper
oHenry reacted to matwachich for a topic
AutoIt3 Lua Wrapper This is an AutoIt3 wrapper for the Lua scripting language. Consider it beta software, but since I will be using it in commercial product, expect it to evolve. It has been developped with Lua 5.3.5. Updates will come for new Lua version. Everything works just fine, except one (big) limitation: Anything that throws a Lua error (using C setjmp/longjmp functionality) will crash your AutoIt program. That means that it is impossible to use throw errors from an AutoIt function called by Lua (luaL_check*, lua_error...). It is hosted in Github: https://github.com/matwachich/au3lua Simple example #include <lua.au3> #include <lua_dlls.au3> ; Initialize library _lua_Startup(_lua_ExtractDll()) OnAutoItExitRegister(_lua_Shutdown) ; create new execution state $pState = _luaL_newState() _luaopen_base($pState) ; needed for the lua's print function $iRet = _luaL_doString($pState, 'print("Hello, world!")') If $iRet <> $LUA_OK Then ; read the error description on top of the stack ConsoleWrite("!> Error: " & _lua_toString($pState, -1) & @CRLF) Exit EndIf ; close the state to free memory (you MUST call this function, this is not AutoIt's automatic memory management, it's a C library) _lua_close($pState)1 point -
RegEx - display string that DOESN'T match a pattern
seadoggie01 reacted to Nine for a topic
The absolute way to test for a valid URL is : #include <Constants.au3> MsgBox ($MB_SYSTEMMODAL,"",_IsValidURL ("https://www.autoitscript.com/forum/topic/201773-regex-display-string-that-doesnt-match-a-pattern/")) MsgBox ($MB_SYSTEMMODAL,"",_IsValidURL ("https;//www.autoitscript.com/forum/topic/201773-regex-display-string-that-doesnt-match-a-pattern/")) MsgBox ($MB_SYSTEMMODAL,"",_IsValidURL ("http://www.autoitscript.net/forum/topic/201773-regex-display-string-that-doesnt-match-a-pattern/")) MsgBox ($MB_SYSTEMMODAL,"",_IsValidURL ("https://ww.autoitscript.com/forum/topic/201773-regex-display-string-that-doesnt-match-a-pattern/")) Func _IsValidURL ($sURL) Return InetGetSize ($sURL) > 0 EndFunc1 point -
You can post it in bug tracker, that also applies to documentation and wiki, if I am not mistaken...1 point
-
1 point
-
Tested on single monitor (win 10), compiled x86, made a shortcut in startup folder. Working : #include <Constants.au3> #include <IE.au3> Local $oIE = _IECreate ("google.ca") Local $hWnd = _IEPropertyGet ($oIE, "hwnd") WinMove ($hWnd, "", 100, 100, 800, 600) Sleep (3000) WinSetState ($hWnd, "", @SW_MAXIMIZE) Sleep (1000)1 point
-
#include <GUIConstants.au3> #include <WinAPITheme.au3> GUICreate("Test", 400, 300) GUICtrlCreateLabel("Test", 10, 10, 50, 23) GUICtrlCreateButton("Test", 10, 50, 50, 23) GUICtrlCreateCheckbox("Test", 10, 100, 50, 23) GUICtrlCreateRadio("Test", 10, 150, 50, 23) GUICtrlCreateLabel("Test", 110, 10, 50, 23) GUICtrlSetColor(-1, 0x00FF00) GUICtrlCreateButton("Test", 110, 50, 50, 23) GUICtrlSetColor(-1, 0x00FF00) $idCB = GUICtrlCreateCheckbox("Test", 110, 100, 50, 23) _WinAPI_SetWindowTheme (GUICtrlGetHandle($idCB), "0", "0") GUICtrlSetColor(-1, 0x00FF00) ; --> NO problem $idRB = GUICtrlCreateRadio("Test", 110, 150, 50, 23) _WinAPI_SetWindowTheme (GUICtrlGetHandle($idRB), "0", "0") GUICtrlSetColor(-1, 0x00FF00) ; --> No problem GUICtrlCreateLabel("Test", 210, 10, 50, 23) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateButton("Test", 210, 50, 50, 23) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateCheckbox("Test", 210, 100, 50, 23) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateRadio("Test", 210, 150, 50, 23) GUICtrlSetBkColor(-1, 0x00FF00) GUISetState(@SW_SHOW) While 1 If GUIGetMsg() = $GUI_EVENT_CLOSE Then Exit WEnd Working for me on Win 101 point
-
Nice mikell, but I would change to ".*\D(\d+)\..*" in case there is a number in the extension (ex.au3)1 point
-
Try this StringRegExpReplace($String, ".*\D(\d+).*", "$1")1 point
-
This hook allows the first click, then disables it for a given delay, then re-enables it The gui is for visualization only #include <WinApi.au3> #include <WindowsConstants.au3> HotKeySet('{ESC}', '_Close') Global Const $MSLLHOOKSTRUCT = $tagPOINT & ";dword mouseData;dword flags;dword time;ulong_ptr dwExtraInfo" Global $hHook, $n, $delay = 2000 Local $hFunc, $pFunc, $hMod $hFunc = DllCallbackRegister('_MouseProc', 'long', 'int;wparam;lparam') $pFunc = DllCallbackGetPtr($hFunc) $hMod = _WinAPI_GetModuleHandle(0) $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pFunc, $hMod) $gui = GuiCreate("test", 100, 80, -1, 20) $label = GuiCtrlCreateLabel("", 10, 20, 80, 50) GuiSetState() While 1 If GuiGetMsg() = -3 Then _Close() Sleep(10) WEnd Func _MouseProc($iCode, $iwParam, $ilParam) Static $t = $delay If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) Local $info = DllStructCreate($MSLLHOOKSTRUCT, $ilParam) Switch $iwParam Case $WM_MBUTTONDOWN If TimerDiff($t) < $delay Then Return 1 ;<<< disable $t = TimerInit() $n += 1 GuiCtrlSetData($label, "Mbutton Down " & $n) EndSwitch Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam) EndFunc Func _Close() _WinAPI_UnhookWindowsHookEx($hHook) DllCallbackFree($hHook) Exit EndFunc1 point
-
You can try to create an object with the ObjEvent() function and use this object as a parameter in the ServerStart() method. It's usually easiest if you have some working code as a starting point. Especially if you are also able to run and debug the code. Then you can try to translate the code into AutoIt.1 point
-
While @Neutro answer is correct, I don't get your 12 Mb data -> 1 Mb .xls file, but that's unimportant. More worrisome is the issue with Excel (or AutoIt, or C, or Fortran, whatever) handling of numeric data, particularly with evolving algorithms, when you can't easily back them up by a strong uncertainty calculation nor a fixed target precision (that is: I want the result of the following computation to be correct within +/- 1e-9). It's indeed very easy to get completely wrong results using widely used languages/tools, seemingly simple algorithms and inconspicious real-world data, even with well established IEEE floating-point. See for instance https://www.autoitscript.com/forum/topic/197061-floating-point-can-be-toxic/1 point
-
BmpSearch - Search for Bitmap within Bitmap - Assembly Version
blackeye87 reacted to Beege for a topic
This below works; however, I had to adjust the window capture height to 12. _GDIPlus_BitmapCreateFromMemory gives me an error code of 3 for some reason when height is 10 from the example. _GDIPlus_Startup() ;initialize GDI+ Local $hHighlight_Capture = GUICreate('', 36, 12, -1, -1, $WS_POPUPWINDOW, $WS_EX_CONTROLPARENT) ;... _ScreenCapture_Capture(@ScriptDir & '\find.bmp', $aPos[0], $aPos[1], $aPos[0] + $aPos[2], $aPos[1] + $aPos[3]) Local $hFind = _GDIPlus_BitmapCreateFromMemory(Binary(FileRead(@ScriptDir & '\find.bmp')), True) If @error Then Exit (ConsoleWrite('_GDIPlus_BitmapCreateFromMemory ERROR: ' & @error & @CRLF))1 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
-
Using C# and VB Code in AutoIt through .NET Framework
IndianSage reacted to LarsJ for a topic
UDF Version of examples "Examples\3) UDF version of examples" in zip-file in bottom of first post contains a version of the optimized AutoIt/VB examples in the post above implemented as a single UDF. There is also a DLL-version of the UDF. Note the initialization function at the top of Includes\ArrayFuncsOpt.au3: Func ArrayFuncsOptInit() Static $oNetCode = 0, $oArrayClass = 0 If IsObj( $oArrayClass ) Then Return $oArrayClass ; Compile and load VB code, create ArrayClass object $oNetCode = DotNet_LoadVBcode( FileRead( "..\Includes\ArrayFuncsOpt.vb" ), "System.dll" ) $oArrayClass = DotNet_CreateObject( $oNetCode, "ArrayClass" ) Return $oArrayClass EndFunc $oNetCode is a reference to the VB code. $oArrayClass is an object that's created from the ArrayClass in the VB code. These variables are static to be able to avoid any global variables. The initialization function is usually called at the beginning of the user script. But the initialization function is also called in each of the four functions in ArrayFuncsOpt.au3 in this way: Static $oArrayClass = 0 If $oArrayClass = 0 Then $oArrayClass = ArrayFuncsOptInit() If the initialization function isn't called it'll work anyway. This is very convenient for example in relation to tests. DLL-version In a production environment the compiled VB code should be stored in a .NET assembly DLL-file, and the AutoIt user code should be compiled as an EXE-file. In the DLL-version the initialization function looks like this: Func ArrayFuncsOptInit() Static $oNetCode = 0, $oArrayClass = 0 If IsObj( $oArrayClass ) Then Return $oArrayClass ; Load ArrayFuncsOpt.dll and create ArrayClass object $oNetCode = DotNet_LoadAssembly( "ArrayFuncsOpt.dll" ) $oArrayClass = DotNet_CreateObject( $oNetCode, "ArrayClass" ) Return $oArrayClass EndFunc If the .NET assembly DLL-file is stored in the same folder as the AutoIt EXE-file, the AutoIt code is always able to find and load the DLL-file.1 point -
Using C# and VB Code in AutoIt through .NET Framework
IndianSage reacted to LarsJ for a topic
Real C# and VB examples One of the great advantages of AutoIt is that the code development process is easy and fast. One of the (few) disadvantages is that the code execution speed is limited by the fact that AutoIt is an interpreted language. Especially calculations in loops eg. calculations on arrays with many elements can be slow compared to the speed of the same calculations in compiled code. Another problem related to arrays is that AutoIt arrays cannot easily be accessed from compiled languages. Nearly a year ago, a technique was introduced in Accessing AutoIt Variables to access AutoIt arrays from compiled code. But this technique is complicated and external development tools are needed to generate the compiled code. The possibility to use C# and VB code in AutoIt through .NET Framework makes it easy to execute compiled code in an AutoIt script, and it makes it easy to pass arrays back and forth between the AutoIt code and the compiled code. And everything (write, compile, load and execute the code and even create an assembly dll-file) can be done through AutoIt. Although it's different languages, the difference between pure calculations and loops is often not so great. If the C# and VB code is restricted to a single function or a single central loop, that's crucial for the execution speed, it should not be too hard to convert AutoIt code to C# or VB code. With the possibility to use C# and VB code in AutoIt through .NET Framework, processing loops and arrays in compiled code has never been easier. C# and VB are very popular programming languages. There are literally millions of examples on the internet. This means that you almost never have to start completely from scratch. You can almost always find an example to copy. Four new examples In first post, an example of calculating prime numbers has been examined. The C#/VB code is 100 times faster than the AutoIt code. This post is a review of four new examples. The examples are 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. The purpose of the examples is to show how to convert AutoIt code to compiled code in different but common areas. The examples also shows which types of code can be optimized and which types of code cannot be much optimized. The compiled code in these examples is VB code. There is no C# code. For each example there is an implementation in pure AutoIt code, and an implementation in AutoIt/VB code. Files related to optimized AutoIt/VB code has "Opt" in the file name. A little bit of error checking is done in each of the examples. At least checking function parameters. All error checking is of course done in AutoIt code. There seems not to be much point in optimizing error checking with compiled code. The examples are added to the zip-file in bottom of first post. They are stored in Examples\2) Real C# and VB examples\. All four examples are structured in the same way. There is a main folder and two subfolders: Examples\ and Includes\. The subfolders contains a handful of files. The code in the second example is a continuation of the code in the first example. The code in the third example is a continuation of the code in the first and second example. The code in the last example is a continuation of the code in the previous examples. If you want to try all the examples at once you can go directly to the last example. If you run the example with pure AutoIt code and the example with optimized AutoIt/VB code, you can easily get an impression of the speed difference. Because arrays and CSV-files are large arrays and files, they are shown in virtual listviews with _ArrayDisplayEx() and CSVfileDisplay(). These functions are stored in Display\ folder in the zip-file. Below is a review of the four examples with focus on the second example about sorting. Generate random data The code in this example creates a 2D array of random data where the columns can contain 5 different data types: strings, integers, floats (doubles), dates and times. Dates and times are integers on the formats yyyymmdd and hhmmss, and are created as correct dates and times. See Includes\Rand2DArray.txt for documentation. The optimized AutoIt/VB code is about 10 times faster than the pure AutoIt code. Index based sorting A 2D array can be sorted by one or more columns. Sorting by more columns is relevant if the columns contains duplicates. A column can be sorted as either strings or numbers (integers or floats) in ascending or descending order. See Includes\Sort2DArray.txt for documentation. That it's an index based sorting means that the array itself is not sorted but that an index is created that contains the array row indices in an order that matches the sorting order. This is usually a good sorting technique for arrays with many rows and columns where more than one column is included in the sorting. And it makes it possible to sort the same array in several ways by creating multiple sorting indexes. This is the AutoIt sorting code: ; Index based sorting of a 2D array by one or more columns. Returns the ; sorting index as a DllStruct (Sort2DArray) or an array (Sort2DArrayOpt). Func Sort2DArray( _ $aArray, _ ; The 2D array to be sorted by index $aCompare ) ; Info about columns used in sorting, see 1) in docu ; Check parameters ; ... Local $iRows = UBound( $aArray ) Local $iCmps = UBound( $aCompare ) Local $tIndex = DllStructCreate( "uint[" & $iRows & "]" ) Local $pIndex = DllStructGetPtr( $tIndex ) Static $hDll = DllOpen( "kernel32.dll" ) ; Sorting by multiple columns Local $lo, $hi, $mi, $r, $j For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $r = 0 ; Compare result (-1,0,1) $j = 0 ; Index in $aCompare array $mi = Int( ( $lo + $hi ) / 2 ) While $r = 0 And $j < $iCmps $r = ( $aCompare[$j][1] ? StringCompare( $aArray[$i][$aCompare[$j][0]], $aArray[DllStructGetData($tIndex,1,$mi+1)][$aCompare[$j][0]] ) : _ $aArray[$i][$aCompare[$j][0]] < $aArray[DllStructGetData($tIndex,1,$mi+1)][$aCompare[$j][0]] ? -1 : _ $aArray[$i][$aCompare[$j][0]] > $aArray[DllStructGetData($tIndex,1,$mi+1)][$aCompare[$j][0]] ? 1 : 0 ) * $aCompare[$j][2] $j += 1 WEnd Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall( $hDll, "none", "RtlMoveMemory", "struct*", $pIndex+($mi+1)*4, "struct*", $pIndex+$mi*4, "ulong_ptr", ($i-$mi)*4 ) DllStructSetData( $tIndex, 1, $i, $mi+1+($lo=$mi+1) ) Next Return $tIndex EndFunc Note that a DllStruct is used to implement the sorting index. And this is the VB sorting code: Public Function Sort2DArray( aObjects As Object(,), aCompare As Object(,) ) As Integer() Dim iRows As Integer = aObjects.GetUpperBound(1) + 1 Dim iCmps As Integer = aCompare.GetUpperBound(1) + 1 Dim MyList As New Generic.List( Of Integer ) MyList.Capacity = iRows MyList.Add(0) 'Sorting by multiple columns Dim lo, hi, mi, r, j As Integer For i As Integer = 1 To iRows - 1 lo = 0 hi = i - 1 Do r = 0 'Compare result (-1,0,1) j = 0 'Index in $aCompare array mi = ( lo + hi ) / 2 While r = 0 And j < iCmps r = If( aCompare(1,j), String.Compare( aObjects(aCompare(0,j),i), aObjects(aCompare(0,j),MyList.Item(mi)) ), If( aObjects(aCompare(0,j),i) < aObjects(aCompare(0,j),MyList.Item(mi)), -1, If( aObjects(aCompare(0,j),i) > aObjects(aCompare(0,j),MyList.Item(mi)), 1, 0 ) ) ) * aCompare(2,j) j += 1 End While Select r Case -1 hi = mi - 1 Case 1 lo = mi + 1 Case 0 Exit Do End Select Loop Until lo > hi MyList.Insert( If(lo=mi+1,mi+1,mi), i ) Next Return MyList.ToArray() End Function Here MyList is used to implement the sorting index. A list in VB is a 1D array where items can be inserted into the list without the need for manually (in a loop) to move subsequent items a row down to get room for the new item. This is handled internally in the implementation of the list. In both the AutoIt and VB code, the index is created through a binary sorting and insertion algorithm. Note the similarity between the AutoIt and the VB code. Due to the list the VB code seems to be the easiest code. The optimized AutoIt/VB code is about 10 times faster than the pure AutoIt code. Convert array The 2D array is converted into a 1D array of strings in CSV format. The most remarkable of this example is that the AutoIt/VB code is only 1-2 times faster than the pure AutoIt code. There are mainly two reasons for this. Firstly, it's very simple code and that's to the advantage of the AutoIt code. Secondly, the COM conversions (discussed in a section in Accessing AutoIt Variables) plays an important role. And that's to the disadvantage of the VB code. Save array In the last example the 1D array of strings is saved as a CSV file. The AutoIt/VB code is a bit faster than the pure AutoIt code. The execution speed is predominantly determined by how fast a file can be written to the disk drive. This takes approximately equal time in VB and AutoIt code. Note that the VB code does not contain a loop to save the strings. There is an internal function for storing a 1D array of strings. Zip-file at bottom of first post is updated.1 point -
Extracting just the filename and extension from a full path?
ThomasBennett reacted to Melba23 for a topic
nf67, Or you can use these SREs from Malkey to get various parts of the path directly: Local $sFile = "C:\Program Files\Another Dir\AutoIt3\AutoIt3.chm" ; Drive letter - Example returns "C" Local $sDrive = StringRegExpReplace($sFile, ":.*$", "") ; Full Path with backslash - Example returns "C:\Program Files\Another Dir\AutoIt3\" Local $sPath = StringRegExpReplace($sFile, "(^.*\\)(.*)", "\1") ; Full Path without backslash - Example returns "C:\Program Files\Another Dir\AutoIt3" Local $sPathExDr = StringRegExpReplace($sFile, "(^.:)(\\.*\\)(.*$)", "\2") ; Full Path w/0 backslashes, nor drive letter - Example returns "\Program Files\Another Dir\AutoIt3\" Local $sPathExDrBSs = StringRegExpReplace($sFile, "(^.:\\)(.*)(\\.*$)", "\2") ; Path w/o backslash, not drive letter: - Example returns "Program Files\Another Dir\AutoIt3" Local $sPathExBS = StringRegExpReplace($sFile, "(^.*)\\(.*)", "\1") ; File name with ext - Example returns "AutoIt3.chm" Local $sFilName = StringRegExpReplace($sFile, "^.*\\", "") ; File name w/0 ext - Example returns "AutoIt3" Local $sFilenameExExt = StringRegExpReplace($sFile, "^.*\\|\..*$", "") ; Dot Extenstion - Example returns ".chm" Local $sDotExt = StringRegExpReplace($sFile, "^.*\.", ".$1") ; Extenstion - Example returns "chm" Local $sExt = StringRegExpReplace($sFile, "^.*\.", "") MsgBox(0, "Path File Name Parts", _ "Drive " & @TAB & $sDrive & @CRLF & _ "Path " & @TAB & $sPath & @CRLF & _ "Path w/o backslash" & @TAB & $sPathExBS & @CRLF & _ "Path w/o Drv: " & @TAB & $sPathExDr & @CRLF & _ "Path w/o Drv or \'s" & @TAB & $sPathExDrBSs & @CRLF & _ "File Name " & @TAB & $sFilName & @CRLF & _ "File Name w/o Ext " & @TAB & $sFilenameExExt & @CRLF & _ "Dot Extension " & @TAB & $sDotExt & @CRLF & _ "Extension " & @TAB & $sExt & @CRLF) M231 point