From time to time people as for multi threading in AutoIt. Although I think it would be cool to have the ability of launching code in a new thread I do not think it will happens before someone steps up and are prepared to practically create a new AutoIt code base. I say this because I have read what better informed people than me are saying about the subject.
Anyhow, you have this killer idea whom really needs to be done asynchronously what do you do? You write it in C/C++, VB or you can, do it as done in this sample, write it in freebasic.
Why would you do it in two languages rather than one. Probably because AutoIt is pretty nice for what it does best, act as the glue between your code and windows applications. You maybe have experience in creating simple GUI's in AutoIt. And the fileinstall function is probably the simplest way you can have your small utilities wrapped up in one exe. No install hazel.
Enough said. Her is a sample multithreaded dll written in freebasic version 0.15. The sample consist of 4 files.
1: The dll code
2: A dll interface definition to be used with freebasic applications.
3: A freebasic test application.
4: A AutoIt v3 Beta 118 application
You will also find all files, including compiled dll and freebasic test app, in a attached zip file at the bottom of this post.
The dll: thdll.bas
' FILENAME: thdll.bas ' COMPILE: fbc -dll thdll.bas ' PURPOSE: Demonstrate a multithreaded dll created with freebasic ' Include is not suposed to be used when we compile as dll ??? #include once "thdll.bi" dim shared gState as integer ' Status reflecting the job done in the thread dim shared gRun as integer ' Flag telling the thread to run or quit dim shared gCalls as integer ' Counting call's to this api dim gTH as integer ' Thread handel ID dim gMutexID as integer ' mutex id to be used when shared variables are updated. ' ' PURPOSE: Test calling conventions from application function AddNumbers CDECL(byval operand1 as integer, byval operand2 as integer) as integer export Return (operand1 + operand2) end function ' ' PURPOSE: Function to run in seperate tread. SUB mythread CDECL ( byval mutexID as integer ) ' Do some realy lengthy woork While gRun = 1 mutexlock(mutexID) ' Use mutex to lock memmory before update gState = gState + 1 mutexunlock(mutexID) 'print "gState:="; gState Sleep(1000) Wend END SUB ' ' PURPOSE: Start a thread FUNCTION Startit CDECL () AS INTEGER export gState = 0 gCalls +=1 gRun = 1 gMutexID = mutexcreate() gTH=threadcreate(@mythread, gMutexID) dim ret as integer ret = gTH Startit = ret END FUNCTION ' ' PURPOSE: Stop the thread FUNCTION Stopit CDECL () AS INTEGER export gCalls +=1 gRun = 0 if gTH <> 0 Then threadwait(gTH) mutexdestroy(gMutexID) Endif gTH = 0 Stopit = 1 END FUNCTION ' ' PURPOSE: Get a simple status message regarding the thread FUNCTION Status CDECL () AS INTEGER export Dim ret as integer gCalls +=1 mutexlock(gMutexID) ret = gState mutexunlock(gMutexID) 'print "Status gState:="; gState Status = ret END FUNCTION function Calls CDECL () as integer export Calls = gCalls end function
The interface file thdll.bi
'FILENAME: th.bi 'PURPOSE: Declarations for exported functions in thdll.bas ' 'NOTE: I got weired results before I did it all from scratch and aded on function, on declaration ' testcode in the runer and compiled. Did that until all functions were added. ' So I suspect that you can get in trouble if the function sequence in this file does not follow ' the sequence in the dll file. BUT I'M NOT SERTAN! declare function AddNumbers CDECL lib "thdll" alias "AddNumbers" ( byval operand1 as integer, byval operand2 as integer ) as integer declare FUNCTION Startit CDECL lib "thdll" alias "Startit" () AS INTEGER declare FUNCTION Stopit CDECL lib "thdll" alias "Stopit" () AS INTEGER declare FUNCTION Status CDECL lib "thdll" alias "Status" () AS INTEGER declare FUNCTION Calls CDECL lib "thdll" alias "Calls" () AS INTEGER
The freebasic test application (console): thrun.bas
'FILENAME: thrun.bas 'COMPILE: fbc thrun.bas 'PURPOSE: test functionality in thdll.bas 'USAGE: Run in command box. thdll.dll must be in path (same folder) #include "thdll.bi" ' Include file containing dll api interface randomize timer x = rnd * 10 y = rnd * 10 print x; " +"; y; " ="; AddNumbers( x, y ) dim nTh as integer nTh = Startit() 'Starting the thread while n <= 10 'Let it work for a while print "Status:="; Status() sleep(333) Wend nTh = Stopit() 'Stop the thread print "Finished : "; Status(); Calls()
The AutoIt test application: thrun.au3
;FILENAME: thrun.au3 ; ;mutithreaddll runner local $dllfilename = @ScriptDir & "\" & "thdll.dll" local $dll = DllOpen($dllfilename) local $ret if $dll = - 1 then msgbox(16, "ERROR", "Could not load dll " & $dllfilename) Else MsgBox(0,"ADDNUMBERS","Just a dll call test" & @CRLF & "2 + 2 = " & apiAddNubers(2, 2)) apiStartit() while (apiStatus() < 20) ConsoleWrite(apiStatus() & " - ") sleep(900) Wend MsgBox(0,"FINISHED","Loop finished: status():=" & apiStatus()) EndIf exit Func OnAutoitExit() msgbox(0,"TERMINATING", "OnAutoitExit") apiStopit() if $dll <> -1 then DllClose($dll) endif EndFunc Func apiStartit() Local $ret = dllcall($dll, "int","Startit") Local $err = @error if $err <> 0 then DllError($err) EndIf Return $ret EndFunc Func apiStopit() Local $ret = dllcall($dll, "int", "Stopit") Local $err = @error if $err <> 0 then DllError($err) EndIf Return $ret EndFunc Func apiStatus() Local $ret = dllcall($dll, "int", "Status") Local $err = @error if $err <> 0 then DllError($err) EndIf Return $ret EndFunc Func apiAddNubers($arg1, $arg2) Local $ret = dllcall($dll , "int", "AddNumbers", "int", $arg1, "int", $arg2) Local $err = @error if $err <> 0 then DllError($err) $ret = -1 EndIf Return $ret EndFunc Func DllError($err) Local $errMessage switch $err case 1 $errMessage = "Unable to use the DLL file" case 2 $errMessage = "unknown return type" case 3 $errMessage = "function not found in the DLL file" case Else $errMessage = "Unknow error number: " & $err EndSwitch msgbox(16, "DllError", "Error occured" & @CRLF & $errMessage) EndFunc
Happy coding, Uten