This is a page of bugs, glitches and workarounds discovered during my attempt to compile and execute 60,000+ lines of working FORTRAN F77 code using the ABSOFT® compiler under Windows XP
| Glitches, Bugs and Workarounds for ABSOFT FORTRAN 9.0 |
|---|
Unexplained compile-time failures and crashes
|
|
tmod-2612 tmod: INTERNAL This occurs with: Workaround: |
Unexpected syntax: ")" was expected but found "EOS". EOS means "end of statement" - make sure "(" and ")" match. |
Unrecoverable error encountered while attempting to print buffered messages - hit EOF while trying to issue message 400 at line 5. EOF means "end of file" - a DOS end-of-file code is at the end of the source code - delete it. It shows as |
Misplaced ^ indicator
CALL XX (val(loc(TRIM(X))) Column = 35 is correct. ^ is incorrectly positioned. |
Unable to obtain license: license not found Answer: the license must be in the expected folder, e.g., c:\Absoft9.0, and the environment variables must match. |
Cray character pointer
|
Long external names STDCALL EXTERNAL spssGetNumberofVariables STDCALL EXTERNAL spssGNV !spssGetNumberofVariables INTEGER*4 spssGNV !spssGetNumberofVariables X=spssGNV( ) then Alias it in unicode.als: _spssGNV _spssGetNumberofVariables |
Cray Character Pointer Wrong: |
.OR. values Wrong: |
| Workaround: add unicode.alias and mrwe.als to the linker alias list under "set project options". |
Unreferenced external names STDCALL EXTERNAL spssSetVarName Workaround: annoying when there are many of these in an INCLUDE file. Remove INCLUDE file, and code only those explicitly used. |
| Unreferenced external symbols
# link error: undefined symbol - _GetSystemInfo Add references to your link alias .als file, and "add" your .als to the linker options |
| Force a new link
Changing a library etc. does not force a new link. Make a trivial change to any compiled module, e.g., a blank to the end of a line. |
| Function calls to external routines fail or produce unexpected results
Did you put a char(0) at the end of your Fortran character string? |
| Mangled routine namesIf you have your own functions in different .obj, then their names may be mangled. Mangle them in your link alias .als file.
In one .f file: In another .f file: So insert in your alias .als file: or move the routines into the same .f file |
| Bugs and Workarounds for ABSOFT FORTRAN 6 - may still be in 9.0 |
|---|
|
Code to parallel Visual Basic "DoEvents" call mrwe_yield |
To get a two-dimensional numeric array from VB6 to a Fortran dll
This is fortsub.f
stdcall subroutine fortsub (darray)
implicit none
automatic
integer*4 darray (0:2, 0:3)
STDCALL EXTERNAL MessageBoxA
INTEGER*4 MessageBoxA, RETCODE
RETCODE = MessageBoxA(
+ val(0),
+ val(loc(
+ '+'//CHAR(darray(0,0))//
+ '+'//CHAR(darray(1,2))//
+ '+'//CHAR(darray(2,1))//'+'//CHAR(0))),
+ val(loc("fortsub message box"//CHAR(0))),
+ val(0))
END
This is f.bat to create fortsub.dll:
f77 -c fortsub.f
echo fortsub > fortsub.xps
echo _fortsub@4 fortsub >fortsub.als
lnk /dll fortsub.obj absRT0.lib user32.lib fmath.lib /exports:fortsub.xps /aliases:fortsub.als
Start VB6, standard Exe, put a Command button on Form1, double-click on the Command button. Paste in this code:
Private Declare Sub fortsub Lib "c:\(your path)\fortsub.dll" (LParam As Any)
Private Sub Command1_Click()
Dim darray(2, 3) As Long
darray(0, 0) = Asc("Z")
darray(1, 2) = Asc("A")
darray(2, 1) = Asc("B")
Call fortsub(darray(0, 0))
End Sub
Then compile and run. Click on the Command Button. The message box should display:
+Z+A+B+
|
From Fortran to a Visual Basic dll (useful for calls to Excel etc.)
In VB6.0: project type: ActiveX dll.
Paste into VB6:
---->
Option Explicit
Public Sub WINVB(A As Long, B As Long, C As Long)
MsgBox ("Visual Basic (should be 65 66):" +Str$(A)+str$(B))
A = ASC("X")
B = ASC("Y")
End Sub
Public Sub DllRegisterServer()
' nothing here
End Sub
Public Sub DllUnregisterServer()
' nothing here
End Sub
<--- end of paste
Make WINVB.DLL
In Visual C++, new project, static library, winvc; finish.
New source file: add to project, winvc
Paste in the following:
---->
#import "c:\{your path}\WINVB.dll" no_namespace // define import path to VB DLL
long WINVC(long& A, long& B, long& C) {
try {
CoInitialize(NULL);
// _Class1Ptr is the Smart pointer wrapper class representing the default interface of the VB object
_Class1Ptr ptr;
// create instance of VB object. __uuidof(Class1) gets the CLSID of the VB object.
ptr.CreateInstance(__uuidof(Class1));
ptr->WINVB(&A, &B, &C); // send addr of var
}
catch(_com_error &e) { return (e.Error()) ;}
CoUninitialize();
return (0);
}
<--- end of paste
Build winvc.lib.
In Absoft Fortran: fortvb.f:
---->
PROGRAM FORTVB
IMPLICIT NONE
INTEGER*4 A, B
STDCALL EXTERNAL MessageBoxA
INTEGER*4 MessageBoxA, RETCODE
A = 44 ! this is A
B = 45 ! this is B
CALL WINVC (A, B, C)
C show the contents in a Message Box to check that we have linked correctly
RETCODE = MessageBoxA(
+ val(0),
+ val(loc(
+ '+'//CHAR(A)//'+'//CHAR(B)//'+'//CHAR(0))),
+ val(loc("After VB message box: should be +X+Y+"//CHAR(0))),
+ val(0))
C MESSAGE BOX SHOULD BE +X+Y+
END
<--- end of paste
To compile and run
f77 -c fortvb.f
echo _WINVC ?WINVC@@YAJAAJ00@Z >fortvb.als
lnk -out:fortvb.exe fortvb.obj WINVC.lib fio.lib absRT0.lib user32.lib kernel32.lib fmath.lib libac.lib comdlg32.lib ole32.lib libcpsx.lib msvcrt.lib comsupp.lib oleaut32.lib /aliases:fortvb.als
run: fortvb.exe
|
ABSOFT FORTRAN skips last line of an ASCII file if it doesn't end LF. So put in an LF
C CHECK THAT LAST MEANINGFUL CODE IS AN "LF" = CHAR(10)
INTEGER*4 FNUM, IOS, IARRAY(13), FSTAT, FWORK
CHARACTER*(*) FNAME
CHARACTER*1 FCHAR
OPEN (UNIT=FNUM,FILE=FNAME,ACCESS='DIRECT',
+ RECL=1, IOSTAT=IOS, STATUS='OLD', ACTION='BOTH')
c obtain file statistics
IOS = FSTAT(FNUM, IARRAY)
C IARRAY(8) IS SIZE OF FILE IN BYTES!
FWORK = IARRAY(8)
C NOW START READING FILE FROM BACK END UNTIL THERE IS A PROBLEM
50 IF (FWORK.GT.0) THEN
READ (FNUM,IOSTAT=IOS,REC=FWORK) FCHAR
IF (IOS.EQ.0) THEN
C IS LAST ACTIVE CODE "LF"? - IF SO, ALL OK
IF (FCHAR.EQ.CHAR(10)) GOTO 200
IF (FCHAR.GE.' ') THEN
C LAST ACTIVE CODE IS GREATER OR EQUAL TO BLANK: LF PROBLEM
C SO WRITE LF AT END-OF-FILE
WRITE (FNUM,IOSTAT=IOS,REC=IARRAY(8)+1) CHAR(10)
GOTO 200
ENDIF
FWORK = FWORK - 1
GOTO 50
ENDIF
ENDIF
ENDIF
200 CLOSE (FNUM, IOSTAT=IOS)
|
| More as I remember them ... |
To call a program from FORTRAN, there's probably an easier way, but I use the Windows API CreateProcess. Something like:
implicit none
AUTOMATIC
include "mrwe.inc"
record/STARTUPINFO/si
record/PROCESS_INFORMATION/pi
integer iret, iret2
si.cb = 68 ! sizeof(si)
si.lpReserved = 0
si.lpDesktop = 0
si.lpTitle = 0
si.dwFlags = 0
si.cbReserved2 = 0
si.lpReserved2 = 0
iret = CreateProcess(
& VAL4(0),
& VAL(LOC(trim("myprogram.exe input1")//char(0))),
& VAL4(0),
& VAL4(0),
& VAL4(FALSE),
& VAL4(DETACHED_PROCESS .OR. NORMAL_PRIORITY_CLASS),
& VAL4(0),
& VAL4(0),
& si,
& pi)
iret = CloseHandle (val(pi.hProcess))
iret2 = CloseHandle (val(pi.hThread))
For a program that's called to read the command line:
stdcall function WinMain (hInstance, hPrevInst, lpszCmdLine, nCmdLine)
integer WinMain, hInstance ,hPrevInst, lpszCmdLine, nCmdLine
value hInstance, hPrevInst, lpszCmdLine ,nCmdLine
character*1024 CommandLine
pointer (pCommandLine, CommandLine)
C for the command line
pCommandLine = lpszCmdLine
c the command line has length is: index(CommandLine, char(0))-1
|
This is useful if the DLL may not exist, or may be a different version to the developer's, or may not have the module, ....
C Do this once to get the entry point
Subroutine GetDLLEntryPoint (YourEntryPoint)
stdcall external LoadLibraryA, GetProcAddress
integer*4 LoadLibraryA, GetProcAddress
integer*4 pl, pm, plvalue, YourEntryPoint
character*100 LibraryName, ModuleName
YourEntryPoint=0
LibraryName = "KERNEL32.DLL"//char(0)
ModuleName = "SetFilePointerEx"//char(0)
pl = loc(YourLibraryName)
plvalue = LoadLibraryA (val(pl))
if (plvalue.ne.0) then
pm = loc(YourModuleName)
YourEntryPoint = GetProcAddress (val(plvalue), val(pm))
endif
end
C Do this each time you need to access the module in the DLL
if (YourEntryPoint.ne.0) then
call YourDLLModule (val(YourEntryPoint),val(your parameter 1), val(),...)
endif
C This does the DLL module access
SUBROUTINE YourDLLModule (YourEntryPoint, your parameter 1, ...)
STDCALL EXTERNAL YourEntryPoint
integer*4 iostat, your parameter 1, ....
iostat = YourEntryPoint (val(your parameter 1), ....)
end
|
Go to Top of Page
Go to Winsteps & Facets home Press Page
For more information, contact
Rasch measurement software and publications
by e-mail using the comment form above.
Our current URL is www.winsteps.com
Winsteps® is a registered trademark
The URL of this page is www.winsteps.com/absoft.htm
| A Christian thought for today |