khimik
Members-
Posts
9 -
Joined
-
Last visited
khimik's Achievements
Seeker (1/7)
0
Reputation
-
Calling Fortran dll's (g95 compiler) from AutoIt
khimik replied to khimik's topic in AutoIt Example Scripts
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? -
If I understand it correctly, you run MyTest, and from MyTest you call a function _ArrayDisplay_Rename(). This function creates a GUI which shows the array, plus two buttons. When the buttons are pressed, you want to read the button ID, delete the GUI with array, and return to the main script. So if you are in the OnEvent mode, your function could be: Func Buttonclicked() $button = @GUI_CtrlId EndFunc The main loop in the _ArrayDisplay_Rename() could be: $button = "" While 1 Sleep(100) If $button = "" Then ContinueLoop; keep idling while buttons are not pressed GUIDelete($whater your gui handle is); close the GUI if a button has been pressed Return; return back to the main script Wend Actually, this will be better in the MessageLoop mode, e.g., you will not have any on event functions. Instead, in the main loop you will have: While 1 Sleep(100) $button = GUIGetMsg(); see if there are any messages; save the ID of the button pressed as $button is a global variable Switch $button Case $btn1, $btn2; if 1st or 2nd button are pressed GUIDelete($whater your gui handle is); close the GUI Return; return back to the main script EndSwitch Wend
-
Sorry Exit means terminate script? You need to remove this keyword
-
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.f95 test.dll
-
I am not sure I understand. You now have two functions for two different buttons, so you can put different code to be executed when different buttons are pressed. If you want to check for the buttons inside the _ArrayDisplay_Test() function, and then return the button ID to the main script, then inside the function you assign the button ID to a global variable, e.g., in the main program (MyTest.au3) declare Global $btn, and in MyArray.au3 write $btn=@GUI_CTRLID when the button is clicked. Alternatively, you can make _ArrayDisplay_Test() return the button ID, e.g., save button ID in a local $btn variable in MyArray.au3 ($btn=@GUI_CTRLID) and then write Return $btn at the end of the function. In the main program, write $button = _ArrayDisplay_Test(); $button will have the button ID.
-
You are not looking at the right input box. In your code, the input you are looking for is on line 39. If you delete line 44, and assign input on line 39 to $Input1 [e.g., $Input1 = GUICtrlCreateInput("", 40, 168, 337, 22)], everything works OK.
-
Do you want to use MessageLoop mode or OnEvent mode? You need to set option Opt(GUIOnEventMode, 1) for GUICtrlSetOnEvent() to work. _ArrayDisplay sets this option to "disable" in the beginning of function, and then resets it to the previous mode at the end of the function.
-
Disable Mouse Button, Run App, Re-enable Button
khimik replied to peomalle's topic in AutoIt General Help and Support
Have a look at http://www.autoitscript.com/forum/index.php?showtopic=64738 -
I think there is a problem with Unicode implementation in DDEML. The following script uses POKE transaction to put "24" in Excel cell R2C2. Book1.xls should be open in Excel. #include <DDEML.au3> #include <DDEMLClient.au3> _DdeInitialize("", BitOR($APPCMD_CLIENTONLY, $CBF_SKIP_ALLNOTIFICATIONS)) $hszService = _DdeCreateStringHandle("excel") $hszTopic = _DdeCreateStringHandle("[Book1.xls]Sheet1") $hConvSrv = _DdeConnect($hszService, $hszTopic) $hszItem = _DdeCreateStringHandle("R2C2") $res = _DdeClientTransaction($XTYP_POKE, $hConvSrv, 24, 1000, $hszItem, $CF_TEXT) _DdeFreeStringHandle($hszService) _DdeFreeStringHandle($hszTopic) _DdeDisconnect($hConvSrv) _DdeUninitialize() However this code will only work if compiled as ANSI. If it is compiled as Unicode, only the first symbol ("2") is sent to the Excel cell (even if $CF_TEXT is replaced with $CF_UNICODETEXT). If "wchar" is replaced with "char" in line 619 of DDEML.au3, everything works fine. The alternative way of doing the POKE transaction which sends a data handle rather than a pointer to user32.dll, does not work. Stateless _DDEMLClient_Poke("excel", "[book1.xls]Sheet1", "R2C2", "24", $CF_UNICODETEXT) does not work either (also with $CF_TEXT). I think these issues are also connected with the Unicode problems. Thanks!