Sign in to follow this  
Followers 0

Threaded Dll Sample

18 posts in this topic

#1 ·  Posted

Multi threaded dll created in freebasic.

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[0]
EndFunc 
Func apiStopit()
   Local $ret = dllcall($dll, "int", "Stopit")
   Local $err = @error
   if $err <> 0 then 
      DllError($err)
   EndIf   
   Return $ret[0]
EndFunc 

Func apiStatus()
   Local $ret = dllcall($dll, "int", "Status")
   Local $err = @error
   if $err <> 0 then 
      DllError($err)
   EndIf   
   Return $ret[0]
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[0]
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

thdll.zip

Share this post


Link to post
Share on other sites



#2 ·  Posted

Share this post


Link to post
Share on other sites

#3 ·  Posted

@Uten

This is very enlightning for those who want to create own written DLL's, and glue into AutoIT.

I am not a Freebasic man myself but it looks very inviting :(

More examples are welcome if it expands to possibilities of AutoIT.

Very nice !!

Yeah, I poked around in the forum for the first time today (saw a couple of your post too uten :think: ), the syntax looks easy enough to get down (a tad confusing in parts), but the possibility of effortlessly multithreading this way is appealing indeed (finally have a need for it after all this time with 1 of my scripts).

I haven't downloaded it yet, I'm going to do some more reading first, but thank you so much for the continued enlightenment and possible solutions for non-existant options at this time!


[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

#4 ·  Posted

I might add that this was my first attempt at doing anything with freebasic. :( I did some reading about it and in the help files a while ago and thought it would be worth a try. It took me more than the three hours I thought I would have to spend to get it going, but now it is done.

The compiler is quite young so I think one should expect hiccups along the way. But it is open source, (and if I recall correctly the current compiler is written in freebasic, so if it does not fit your bill you can do something about it :think:

Share this post


Link to post
Share on other sites

#5 ·  Posted

Good stuff! ^^ Gonna use this in my next project .. if i ever start it lol

Share this post


Link to post
Share on other sites

#6 ·  Posted

I seriously need AutoIt to support multithreading. Singlethread makes networking near impossible. I would love to hear a method that works.

Share this post


Link to post
Share on other sites

#7 ·  Posted

1


-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]

Share this post


Link to post
Share on other sites

#8 ·  Posted

+1

???

@AutoIt Smith: A search and read session in the forums will explain why AutoIt is not multithreading ready by itselfe (and I'm shure you allready know this.. :whistle: ). It was not designed for multithreading and the code is not reentrant safe.

If we, the userbase, really want it to be multithreaded I think we have to take the provided source and make it thread safe (as a profe of consept) and then hope the developers of AutoIt will accept the changes and let the people whome has doen them make the requiered changes to the rest of the AutoIt code or do it them selfe. If you want to do this remember that size matters both to the community and the developers.

It should not be to much hazzle to make a mulithreaded networking component (dll or plugin) in freebasic (or C++) and use it in AutoIt.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Yes, this should come in quite handy. As you guys probably know i have written a search engine in autoit and right now i am using a FreeBasic dll to do the searching since it is faster than autoit. The only problem is that i need to create another thread so that the search function in the dll doesn't pause the whole program as it searches for files which only take a couple seconds, but the program should never be unresponsive.

Thanks Uten. I will probably end up writing this into my searchengine.dll. :lmao:

-The Kandie Man

EDIT:

Got it to work. Woot! Now all i have to do is some slight modification to my main autoit search engine script. ;)

Edited by The Kandie Man

"So man has sown the wind and reaped the world. Perhaps in the next few hours there will no remembrance of the past and no hope for the future that might have been." & _"All the works of man will be consumed in the great fire after which he was created." & _"And if there is a future for man, insensitive as he is, proud and defiant in his pursuit of power, let him resolve to live it lovingly, for he knows well how to do so." & _"Then he may say once more, 'Truly the light is sweet, and what a pleasant thing it is for the eyes to see the sun.'" - The Day the Earth Caught Fire

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

I was very impressed by this and wanted to learn FreeBASIC to try and create some shell extensions for AutoIt (not there yet though). So to start learning I expanded on this example a bit to something a bit more AutoIt relevant, and that is threaded Message Boxes. Simple, but a good place to start and illustrate the example.

The example script I have demonstrates a few things that can be done. First is the use of mutexes in FreeBASIC to control threads. I've commented out 2 of the Mutex*** lines so all the message boxes pop up at once to demonstrate the threading, but if you put them back in and recompile the DLL then the boxes will come up one at a time, but the threads will be queued, meaning your script is still running and the closing / opening of the boxes is independent.

Second is an example of passing an array of information back to AutoIt. The _GetMutex() function passes back a pointer to a 2 element array with the handles of the 2 created mutexes. The values are retrieved by creating a DllStruct at the pointer.

Third is an example of properly waiting for all the threads to terminate before closing the AutoIt script. The main message boxes use the _ThreadWait() function in a loop, and the _GetMutex() boxes are stored by the DLL, and use the _WaitFinished() function to wait for them to close. I tried to put this loop in the Destructor so the DLL would wait automatically, but it didn't work. For some reason the DLL cannot see that the threads are closed and so it hangs in the loop. If anyone knows why, please do tell.

Oh, it's also got an elementary use of Types. This is the first time I've used one, so it was a good learning experience. I tried to pass a type structure back to AutoIt in the _GetMutex() function, and while AutoIt got the pointer correctly, I could not retrieve the data with the DllStruct like I could with the array. If anyone knows the answer to that one, I'd like to know as well.

This could pretty easily be extended for any functions you need to run threaded from an AutoIt script. I hope it's useful!

thdll.dll source (thdll.bas)

#Include Once "windows.bi"

Dim Shared As Any Ptr hMutex, tMutex, mutexptr(1)
ReDim Shared As Any Ptr mboxwait(0)

Type boxinfo
    hWnd As HWND
    As String lpText, lpCaption
    uType As UInteger
End Type

Dim Shared mbox As boxinfo

Sub _onstart Constructor
    hMutex = MutexCreate()
    tMutex = MutexCreate()
    mutexptr(0) = hMutex
    mutexptr(1) = tMutex
End Sub

Sub _tMessageBox (mPtr As boxinfo Ptr)
    Dim info As boxinfo = *mPtr
    MutexUnlock(tMutex)
    
'   MutexLock(hMutex)
        MessageBox(info.hWnd, info.lpText, info.lpCaption, info.uType)
'   MutexUnLock(hMutex)
End Sub

Function _MessageBox Cdecl Alias "_MessageBox" (ByVal hWnd As HWND, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As UInteger) As Any Ptr Export
    Dim hThread As Any Ptr
    
    MutexLock(tMutex)
    mbox.hWnd = hWnd
    mbox.lpText = lpText
    mbox.lpCaption = lpCaption
    mbox.uType = uType
    hThread = ThreadCreate(Cast(Any Ptr, @_tMessageBox), @mbox)
    Return hThread
End Function

Function _GetMutex Cdecl Alias "_GetMutex" () As Any Ptr Export
    Dim hThread As Any Ptr
    
    hThread = _MessageBox(NULL, "Mutex ptr:  0x" & Hex(@mutexptr(0)) & Chr(13) & "hMutex:  0x" & Hex(hMutex) & Chr(13) & "tMutex:  0x" & Hex(tMutex), "INFO", MB_OK Or MB_ICONEXCLAMATION)
    If mboxwait(UBound(mboxwait)) <> 0 Then
        ReDim Preserve mboxwait(UBound(mboxwait) + 1)
        mboxwait(UBound(mboxwait)) = hThread
    Else
        mboxwait(UBound(mboxwait)) = hThread
    EndIf
    Return @mutexptr(0)
End Function

Function _WaitThread Cdecl Alias "_WaitThread" (ByVal wThread As Any Ptr) As Integer Export
    ThreadWait(wThread)
    Return ERROR_SUCCESS
End Function

Function _WaitFinished Cdecl Alias "_WaitFinished" () As Integer Export
    Dim i As Integer
    
    For i = 0 To UBound(mboxwait)
        ThreadWait(mboxwait(i))
    Next i
    Return ERROR_SUCCESS
End Function

Sub _OnExit Destructor
    MutexDestroy(hMutex)
    MutexDestroy(tMutex)
End Sub

And the example AutoIt script. Watch the console for the output information.

NOTE: The DLL must use DllOpen() / DllClose() so the mutex and other information persists across DLL calls.

$dllname = @ScriptDir & "\thdll.dll"
$dll = DllOpen($dllname)

For $i = 1 To 3
    $ret = DllCall($dll, "ptr:cdecl", "_GetMutex")
Next

ConsoleWrite("Mutex array ptr: " & $ret[0] & @CRLF)
$mutex = DllStructCreate("ptr m1; ptr m2", $ret[0])
ConsoleWrite("Mutex 1: " & DllStructGetData($mutex, "m1") & @CRLF)
ConsoleWrite("Mutex 2: " & DllStructGetData($mutex, "m2") & @CRLF & @CRLF)

Dim $thread[3]
For $i = 1 To 3 
    $ret = DllCall($dll, "ptr:cdecl", "_MessageBox", _
                            "hwnd", Chr(0), _
                            "str", "Message Box " & $i, _
                            "str", "Thread Test", _
                            "uint", BitOR(0, 64) _
                            )
    ConsoleWrite("Error: " & @error & @CRLF)
    ConsoleWrite("Ret: " & $ret[0] & @CRLF)
    $thread[$i - 1] = $ret[0]
Next

ConsoleWrite(@CRLF & "-> ** do stuff while message boxes are up **" & @CRLF & @CRLF)

For $i = 0 To 2
    $ret = DllCall($dll, "int:cdecl", "_WaitThread", "ptr", $thread[$i])
    ConsoleWrite("Thread " & $thread[$i] & " done." & @CRLF)
    ConsoleWrite("Error: " & @error & @CRLF)
    ConsoleWrite("Ret: " & $ret[0] & @CRLF)
Next

ConsoleWrite(@CRLF & "-> ** Waiting for _GetMutex() message boxes to close... **" & @CRLF)
DllCall($dll, "int:cdecl", "_WaitFinished")
ConsoleWrite(@CRLF & "-> ** All threads finished! **" & @CRLF)

DllClose($dll)
ConsoleWrite("DLL closed." & @CRLF)
Edited by wraithdu

Share this post


Link to post
Share on other sites

#11 ·  Posted

I know this is an old topic but autoit is crashing with this dll now. And any dll i try to make with freebasic for that matter. Any Ideas?

>AutoIT3.exe ended.rc:-1073741819

>Exit code: -1073741819 Time: 5.522

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

You can create threads with Autoit, so you don't need a DLl to do that.

You just mustn't use an AutoIt-Function with DLLCallbackRegister as the Thread-Functions. (The thread runs, but AutoIt crahses after a few secs)

So yo have to use just one func in the DLL which wil be the ThreadProc. For Messageboxes you could use the MessageBoxIndirect from user32.dll.

Example at the end of script:

Global Const $STATUS_PENDING = 0x103
Global Const $STILL_ACTIVE = $STATUS_PENDING

; ThreadID is @extended
;===============================================================================
;
; Function Name:   _Thread_Create
; Description::    Creates a thread
; Parameter(s):    see MSDN (lpThreadId is removed)
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  @extended will be ThreadID
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Create($lpThreadAttributes, $dwStackSize, $lpStartAddress, $lpParameter, $dwCreationFlags)
    Local $result = DllCall("kernel32.dll","ptr","CreateThread", "ptr", $lpThreadAttributes, "dword", $dwStackSize, "ptr", $lpStartAddress, "ptr", $lpParameter, "dword", $dwCreationFlags, "dword*", 0)
    Return SetError($result[0]=0,$result[6],$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_Terminate
; Description::    Terminates a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Terminate($hThread,$dwExitCode)
    Local $result = DllCall("Kernel32.dll","int","TerminateThread","ptr",$hThread,"dword",$dwExitCode)
    Return SetError($result[0]=0,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_Exits
; Description::    Exits the current thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): none
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Exit($dwExitCode)
    DllCall("Kernel32.dll","none","ExitThread","dword",$dwExitCode)
EndFunc
;===============================================================================
;
; Function Name:   _Thread_GetExitCode
; Description::    retrieves ExitCode of a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_GetExitCode($hThread)
    Local $result = DllCall("Kernel32.dll","int","GetExitCodeThread","ptr",$hThread,"dword*",0)
    Return SetError($result[0]=0,0,$result[2])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_GetID
; Description::    retrieves ThreadID of a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_GetID($hThread)
    Local $result = DllCall("Kernel32.dll","dword","GetThreadId","ptr",$hThread)
    Return SetError($result[0]=0,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_GetPriority
; Description::    retrieves priority of a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_GetPriority($hThread)
    Local $result = DllCall("Kernel32.dll","int","GetThreadPriority","ptr",$hThread)
    Return SetError($result[0]=0,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_SetPriority
; Description::    sets priority of a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_SetPriority($hThread,$nPriority)
    Local $result = DllCall("Kernel32.dll","int","SetThreadPriority","ptr",$hThread,"int",$nPriority)
    Return SetError($result[0]=0,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_Suspend
; Description::    suspends a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Suspend($hThread)
    Local $result = DllCall("Kernel32.dll","int","SuspendThread","ptr",$hThread)
    Return SetError($result[0]=-1,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_Resume
; Description::    resumes a thread
; Parameter(s):    see MSDN
; Requirement(s):  minimum Win2000
; Return Value(s): see MSDN
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Resume($hThread)
    Local $result = DllCall("Kernel32.dll","int","ResumeThread","ptr",$hThread)
    Return SetError($result[0]=-1,0,$result[0])
EndFunc
;===============================================================================
;
; Function Name:   _Thread_Wait
; Description::    Waits for a thread to terminate
; Parameter(s):    $hThread  - Handle of thread
;                  $nTimeOut - [optional] Timeout (default: 0xFFFFFFFF => INFINTE)
; Requirement(s):  minimum Win2000
; Return Value(s): Success: true
;                  on TimeOut, @eeor will be set to -1
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Wait($hThread,$nTimeout=0xFFFFFFFF)
    Local $result = DllCall("Kernel32.dll", "dword", "WaitForSingleObject", "ptr", $hThread, "int", $nTimeout)
    If @error Then Return SetError(2,0,0)
    Switch $result[0]
        Case -1, 0xFFFFFFFF
            Return SetError(1,0,0)
        Case 0x00000102
            Return SetError(-1,0,1)
        Case Else
            Return 1
    EndSwitch
EndFunc


#include <WinAPI.au3>
$tagMSGBOXPARAMS = _
        "UINT cbSize;" & _
        "HWND hwndOwner;" & _
        "ptr hInstance;" & _
        "ptr lpszText;" & _
        "ptr lpszCaption;" & _
        "DWORD dwStyle;" & _
        "ptr lpszIcon;" & _
        "UINT_PTR dwContextHelpId;" & _
        "ptr lpfnMsgBoxCallback;" & _
        "DWORD dwLanguageId;"



; creates a struct for an Unicode-String
Func _UnicodeStruct($text)
    ; Prog@ndy
    Local $s = DllStructCreate("wchar[" & StringLen($text)+1 & "]")
    DllStructSetData($s,1,$text)
    Return $s
EndFunc

; retrieves Address of a function
Func _Thread_GetProcAddress($hModule,$sProcname)
    ; Prog@ndy
    Local $result = DllCall("kernel32.dll","ptr","GetProcAddress","hwnd",$hModule,"str",$sProcname)
    Return $result[0]
EndFunc

; Struct to send to the Thread
; in this case the MsgBox-Params
$MSGBOXPARAMS = DllStructCreate($tagMSGBOXPARAMS)
DllStructSetData($MSGBOXPARAMS,"cbSize",DllStructGetSize($MSGBOXPARAMS))
$stText = _UnicodeStruct("The messageBox in a separate thead!")
DllStructSetData($MSGBOXPARAMS,"lpszText",DllStructGetPtr($stText))
$stCaption = _UnicodeStruct("Caption")
DllStructSetData($MSGBOXPARAMS,"lpszCaption",DllStructGetPtr($stCaption))
DllStructSetData($MSGBOXPARAMS,"dwStyle",17) ; msgBox-style

; Use MessageBoxIndirect Unicode as ThreadProc
; normal MessageBox doesn't work, since CreateThread just has one possible parameter.
Local $hThreadProc = _Thread_GetProcAddress(_WinAPI_GetModuleHandle("user32.dll"),"MessageBoxIndirectW")

$hThread = _Thread_Create(0 ,0, $hThreadProc, DllStructGetPtr($MSGBOXPARAMS), 0)
$ThreadID = @extended

While MsgBox(69, "main", "Main script is not blocked" )=4
WEnd
MsgBox(0, "Thread-Info", "Handle: " & $hThread & @CRLF & "Thread-ID: " & $ThreadID)

_Thread_Wait($hThread)
$code = _Thread_GetExitCode($hThread)
MsgBox(0, 'Thread ended', "Threaded MsgBox returned: " & $code)
Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#13 ·  Posted

@ProgAndy

Nice little example. Is there any reason you don't use _WinAPI_WaitForSingleObject($hThread) in your _Thread_Wait() function?

Share this post


Link to post
Share on other sites

#14 ·  Posted

yes that was a great example. Thanks! Im going to play with those. Anyway I figured out the problem regarding freebasic dll. Functions need to be called with cdecl after the return value for this dll.

Ex: $ret = dllcall($dll, "int:cdecl","Startit")

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

@ProgAndy

Nice little example. Is there any reason you don't use _WinAPI_WaitForSingleObject($hThread) in your _Thread_Wait() function?

There is just one reason: i forgot to use it ... Here it is:
;===============================================================================
;
; Function Name:   _Thread_Wait
; Description::    Waits for a thread to terminate
; Parameter(s):    $hThread  - Handle of thread
;                  $nTimeOut - [optional] Timeout (default: 0xFFFFFFFF => INFINTE)
; Requirement(s):  minimum Win2000
; Return Value(s): Success: true
;                  on TimeOut, @eeor will be set to -1
;                  On error, @error will be set to 1
; Author(s):       Prog@ndy
;
;===============================================================================
;
Func _Thread_Wait($hThread,$nTimeout=0xFFFFFFFF)
    Local $result = DllCall("Kernel32.dll", "dword", "WaitForSingleObject", "ptr", $hThread, "int", $nTimeout)
    If @error Then Return SetError(2,0,0)
    Switch $result[0]
        Case -1, 0xFFFFFFFF
            Return SetError(1,0,0)
        Case 0x00000102
            Return SetError(-1,0,1)
        Case Else
            Return 1
    EndSwitch
EndFunc
Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#16 ·  Posted

Hi ProgAndy,

The implementation is simple, still I cant understand the below line

_Thread_GetProcAddress(_WinAPI_GetModuleHandle("user32.dll"),"MessageBoxIndirectW")

Can you provide a simple example to just call a user defined function MyFunction() inside the _Thread_Create() function

$hThread = _Thread_Create(0 ,0, MyFunction, DllStructGetPtr($MSGBOXPARAMS), 0)

Share this post


Link to post
Share on other sites

#17 ·  Posted

What do you mean with user defined function? A function written in AutoIt? That won't work since the AutoIt-interpreter is not threadsafe.

What you can do is creating a function in a DLL and use that as a thread:

DLLOpen("myThreadFunc.dll") ;<- open DLL
$hDLLHandle = _WinAPI_GetModuleHandle("myThreadFunc.dll") ; get address of the loaded DLL
$hThreadProc = _Thread_GetProcAddress($hDLLHandle, "MyThreadFunc") ; get address of the function in the dll

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#18 ·  Posted

Thank you very much for your fast response.

If I create a function in DLL then, I cant access AutoIt Script file resoruces (variables/functions).

So how to overcome this problem ?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0