khimik Posted November 19, 2008 Share Posted November 19, 2008 I have worked out how to create Fortran dll's using g95 compiler and call them from AutoIt. AutoIt is a fantastic language, but when it comes to handling large amount of information or complex maths, it is quite slow. Fortran, on the other hand, is very fast, and there are many available maths libraries. The combination of AutoIt and Fortran dll's provides the power over Windows of AutoIt and the speed of Fortran. Here are the rules I found: 1) Fortran functions should be compiled by g95 as g95 -shared -o <function name>.dll <function name>.f95 2) G95 mangles function names by adding an underscore after the name, or two if the name already contains an underscore. Hence the function name called in DllCall should be appended with undescore(s). There are ways of avoiding this mangling (e.g., by using BIND( C) in Fortran) but it is not necessary. 3) Arguments passed TO the dll: - int/float data can be passed as variables using ByRef method (e.g., "int*"). Alternatively they can be passed as pointers ("ptr") to DllStruct. Variables can probably be also passed as values if one uses VALUE attribute in Fortran but I have not tested this. - strings can be passed as "str" or as pointers ("ptr") to DllStruct. In the latter case, the size of the DllStruct should be greater than the actual string by one character, as 0x00 is automatically added to the end of the string. In any case, for ALL strings passed to the dll, integer arguments with the length of the strings must be added to the end of the argument list. 4) All arguments received FROM the dll MUST be pointers to DllStruct. 5) Fortran function returns an array. First element in this array is the function return value, other elements are the arguments passed to the dll. 6) Use cdecl calling method in AutoIt, e.g., "int:cdecl". It is also possible to compile the Fortran dll with the -mrtd switch and use stdcall in AutoIt (e.g., "int"), but in one case I had an unexplained memory leak with this method. Also, if stdcall is used, then lengths of strings passed back from the dll should also be added to the end of the argument list. I attach a simple self-explanatory working example including source and compiled dll. The example illustrates diffrent ways of passing arguments to/from the dll. The dll and AutoIt script must be in the same directory. Once the dll is loaded/cached (e.g., if you run AutoIt script more than once, or change the script to load the dll before initialising the timer), it works ca. 100 times faster than the equivalent AutoIt code on my computer. Hope somebody will find this useful. AutoIt program: $timer = TimerInit() $r = 3.3 $i = DllStructCreate("int") DllStructSetData($i, 1, 8); Set value to 8. $str2 = DllStructCreate("char[16]"); 1 char longer as it will automatically be null-terminated DllStructSetData($str2, 1, "string variable") $str3 = DllStructCreate("char[65]") $j = DllStructCreate("int") ; An underscore was added by g95 compiler to the function name (e.g., to make it "test_"). ; Dll is called using cdecl method; 1st argument is passed ByRef, 2nd as a pointer, 3rd (str1) as a string, ; 4th (str2) as a pointer to a null-terminated string. Return parameters are pointers. ; Length of str1 and str2 is given at the end of the argument list ; Return value is $res_dll[0] $res_dll = DllCall("test.dll", "int:cdecl", "test_", "float*", $r, "ptr", DllStructGetPtr($i), _ "str", "string variable", "ptr", DllStructGetPtr($str2), "ptr", DllStructGetPtr($str3), _ "ptr", DllStructGetPtr($j), "int", StringLen("string variable"), "int", DllStructGetSize($str2)) MsgBox(0,"","Dll return value: " & $res_dll[0] & @CRLF & "String returned: " & DllStructGetData($str3,1) & @CRLF & _ "Integer returned: " & DllStructGetData($j, 1) & @CRLF & "Time taken: " & TimerDiff($timer)) $timer = TimerInit() For $k = 1 To 100000; the same maths as in Fortran dll $p = 3.14*$k + $r Next MsgBox(0,"","Time taken: " & TimerDiff($timer)) Fortran dll code: CODEinteger function test(r,i,str1,str2,str3,j) implicit none real, intent(in) :: r integer, intent(in) :: i character(len=*), intent(in) :: str1 character(len=*), intent(in) :: str2 character(len=65), intent(out) :: str3 integer, intent(out) :: j integer :: k real :: p do k=1,100000 p=3.14*k+r !do some simple maths end do if (TRIM(str1)==TRIM(str2)) then str3='equal strings' else str3='strings are different as str2 has 0x00 at the end' end if j=i+5 test=INT( r) end function test Attached file: test.dll, was compiled from above Fortran code with the following command: g95 -shared -o test.dll test.f95test.dll Link to comment Share on other sites More sharing options...
Paulus Posted December 8, 2009 Share Posted December 8, 2009 I downloaded test.dll and created autoit script "as-is" in the same directory, but something does not work. @error value after DllCall function is "2" (unknown "return type"). Link to comment Share on other sites More sharing options...
khimik Posted February 19, 2010 Author Share Posted February 19, 2010 This is really strange. I have written several specialised data treatment programs using this technique, and they run on at least 10 different computers here, mostly XP but we also had win2000 and even 98 if I remember it right. I just downloaded both programs and tried it and it worked. I had lots of dll errors until I figured out the right way but I never saw this error. Could you try it on another computer? Link to comment Share on other sites More sharing options...
Kealper Posted February 19, 2010 Share Posted February 19, 2010 Wow, this has quite a big speed increase, takes around 1.6ms for the DLL to do the math, and about 185ms for AutoIt on this machine, very nice Link to comment Share on other sites More sharing options...
Shafayat Posted February 19, 2010 Share Posted February 19, 2010 it took 1.45ms for the dll and almost 192ms for autoit. Wow! That's something. Thank you very much. [Not using this account any more. Using "iShafayet" instead] Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now