- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Okay, just when you think you've gotten over the hurdle in a mix-language programming project something always comes out of left field to bring you to a grinding halt.
I have one project involving calling DLLs from Excel that I've been using for several years now. The Fortran was originally coded using Compaq Visual Fortran. I have strings that I pass back and forth between Exce and Fortran using the "CVF" hidden string length convention; the hidden stringth length arguments in the call to Fortran immediately follows the string arguments in the calling statement. No problem.
When I migrated to Intel Visual Fortran, the convention changed to putting all the hidden string arguments "After All Arguments" in the calling statement. Instead of making a lot of code changes at the time I discovered that I could tell IVF to use the CVF calling convention. This has worked just fine ever since.
I am now designing another Excel/Fortran DLL application modeled closely on the on above. The difference is, I need to make a call to a C routine from the Fortran DLL (yes, this is the same project that is a subject of my previous threads; I have been making progress). I've discovered in working the C/Fortran issues that C (in Visual Studio 2005 or Visual Studio itself) apparently needs to see this hidden string length using the IVF convention in the calls between C and Fortran; i.e. with all the hidden length arguments "After All Arguments" in the calling statement. I don't think I can change the calling convention on the C side.
No problem, I just went into the Fortran andput all the hidden length arguments in my call statements to the"end of the line" sort of speak and also changed "Project/Confiuration Properties/Fortran/External Procedures/Calling Convention" setting to "Default". No problem. Remember, though this was all done on the C/Fortran side; debugging from the Fortran side by having the debuggerin Visual Studio start up Excel etc. Ialso wentinto Excel and changed my declaration and call statements to reflect this, although as I point out below, teh first routine I tried calling from Excel only has one string to pass.
Now the problem. When I call any Fortran procedure that involves passing strings in the dll I get a "Run-time error '49': Bad DLL calling convention".
First of all: The first call I tried from Excel involves only ONE string. I simply cannot get the actual argument and hidden length argument in the wrong order when there is only one string to pass.
Second of all: I have discovered that the problem appears to be happening on exiting of theFortran routine, not when it's entered.
How do I know this? First of all, Ihave no problems whatsoever when I debug from the Fortran side; Excelcomes up I, start the Macro and I go right intoand past the call statement on the Fortran side and all the values of the arguments in the Fortransubroutinestatement look good.
Second: I've discovered that if I have a run-time erroron the Fortran side and run directly from Excel I get a severe Fortran error and Excel crasheswithout the "Run-time 49" error, implying that I'm getting past the Subroutine statement and into the Fortran code. So I then purposelyput a couple of lines of code right before theRETURN and END SUBROUTINE lines in theFortran code to give a run-time error: i.e. I set an integer variable to say 199 and then set another variable to somearray("integer variable=199") when somearray is only declared to have, say, 150 elements. When I run from Excel I get a severe Fortran message that tells me I can't have an array index of "199" when the array has been declared to have only 150 elements.
I comment the above run-time error code out and when I run from Excel I get the "Run-time 49" error. I appear to be gettting this error when exiting the Fortran and code on attempting to return to Excel/VBA, not when the Fortran routine is initially called by Excel.
What's up with this??
One possible solution: Under "Project/Configuration Properties/Fortran/External Procedures/Calling Convention" setting to "Default" there is a note that says: "Calling Convention Selects the default calling convention for an application (can be overridden by INTERFACE)...."
I could set the Calling Convention to CVF to satisfy Excel and I have an INTERFACE block inside a Module in my Fortran routine that interacts with the C code (thanks to IanH) but I don't have the faintest idea (and I've searched) what code to put in my interface block for "overriding" the default calling convention to satisfy the C code.
Below is the thread that contains the Module/Interface block example given to me by IanH which I'm using: search page for "Simple version".
http://software.intel.com/en-us/forums/showthread.php?t=62562
Thanks.
Mike
I have one project involving calling DLLs from Excel that I've been using for several years now. The Fortran was originally coded using Compaq Visual Fortran. I have strings that I pass back and forth between Exce and Fortran using the "CVF" hidden string length convention; the hidden stringth length arguments in the call to Fortran immediately follows the string arguments in the calling statement. No problem.
When I migrated to Intel Visual Fortran, the convention changed to putting all the hidden string arguments "After All Arguments" in the calling statement. Instead of making a lot of code changes at the time I discovered that I could tell IVF to use the CVF calling convention. This has worked just fine ever since.
I am now designing another Excel/Fortran DLL application modeled closely on the on above. The difference is, I need to make a call to a C routine from the Fortran DLL (yes, this is the same project that is a subject of my previous threads; I have been making progress). I've discovered in working the C/Fortran issues that C (in Visual Studio 2005 or Visual Studio itself) apparently needs to see this hidden string length using the IVF convention in the calls between C and Fortran; i.e. with all the hidden length arguments "After All Arguments" in the calling statement. I don't think I can change the calling convention on the C side.
No problem, I just went into the Fortran andput all the hidden length arguments in my call statements to the"end of the line" sort of speak and also changed "Project/Confiuration Properties/Fortran/External Procedures/Calling Convention" setting to "Default". No problem. Remember, though this was all done on the C/Fortran side; debugging from the Fortran side by having the debuggerin Visual Studio start up Excel etc. Ialso wentinto Excel and changed my declaration and call statements to reflect this, although as I point out below, teh first routine I tried calling from Excel only has one string to pass.
Now the problem. When I call any Fortran procedure that involves passing strings in the dll I get a "Run-time error '49': Bad DLL calling convention".
First of all: The first call I tried from Excel involves only ONE string. I simply cannot get the actual argument and hidden length argument in the wrong order when there is only one string to pass.
Second of all: I have discovered that the problem appears to be happening on exiting of theFortran routine, not when it's entered.
How do I know this? First of all, Ihave no problems whatsoever when I debug from the Fortran side; Excelcomes up I, start the Macro and I go right intoand past the call statement on the Fortran side and all the values of the arguments in the Fortransubroutinestatement look good.
Second: I've discovered that if I have a run-time erroron the Fortran side and run directly from Excel I get a severe Fortran error and Excel crasheswithout the "Run-time 49" error, implying that I'm getting past the Subroutine statement and into the Fortran code. So I then purposelyput a couple of lines of code right before theRETURN and END SUBROUTINE lines in theFortran code to give a run-time error: i.e. I set an integer variable to say 199 and then set another variable to somearray("integer variable=199") when somearray is only declared to have, say, 150 elements. When I run from Excel I get a severe Fortran message that tells me I can't have an array index of "199" when the array has been declared to have only 150 elements.
I comment the above run-time error code out and when I run from Excel I get the "Run-time 49" error. I appear to be gettting this error when exiting the Fortran and code on attempting to return to Excel/VBA, not when the Fortran routine is initially called by Excel.
What's up with this??
One possible solution: Under "Project/Configuration Properties/Fortran/External Procedures/Calling Convention" setting to "Default" there is a note that says: "Calling Convention Selects the default calling convention for an application (can be overridden by INTERFACE)...."
I could set the Calling Convention to CVF to satisfy Excel and I have an INTERFACE block inside a Module in my Fortran routine that interacts with the C code (thanks to IanH) but I don't have the faintest idea (and I've searched) what code to put in my interface block for "overriding" the default calling convention to satisfy the C code.
Below is the thread that contains the Module/Interface block example given to me by IanH which I'm using: search page for "Simple version".
http://software.intel.com/en-us/forums/showthread.php?t=62562
Thanks.
Mike
Link Copied
22 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Mike,
This may only be slightly helpful. We also recently had a DLL calling convention issue. In our case a Visual Basic program calling a Fortran DLL versus a Fortran DLL calling another Fortran DLL. It turned out that the calling convention requirements were different for the two cases. For VB calling Fortran we need to define the full set of ATTRIBUTES including DLLEXPORT, ALIAS, STDCALL, and the REFERENCE list of arguments in the call statement. But for the Fortran to Fortran DLL case, the extra ATTRIBUTES caused a problem with the default calling convention, and we only needed to define DLLEXPORT. There really isn't a way to have a single DLL accessible routine the can be accessed by both VB and Fortran. Our work-around is to defined two different routines as accessible interfaces, which in turn call the same underlying routine for calculations.
Perhaps your case is similar such that you need to define different calling conventions for the Excel and C cases, which means you could create two accessible subroutines in your DLL. And those two accessible routines would call the same routine that actually does the work.
Regards,
Greg
This may only be slightly helpful. We also recently had a DLL calling convention issue. In our case a Visual Basic program calling a Fortran DLL versus a Fortran DLL calling another Fortran DLL. It turned out that the calling convention requirements were different for the two cases. For VB calling Fortran we need to define the full set of ATTRIBUTES including DLLEXPORT, ALIAS, STDCALL, and the REFERENCE list of arguments in the call statement. But for the Fortran to Fortran DLL case, the extra ATTRIBUTES caused a problem with the default calling convention, and we only needed to define DLLEXPORT. There really isn't a way to have a single DLL accessible routine the can be accessed by both VB and Fortran. Our work-around is to defined two different routines as accessible interfaces, which in turn call the same underlying routine for calculations.
Perhaps your case is similar such that you need to define different calling conventions for the Excel and C cases, which means you could create two accessible subroutines in your DLL. And those two accessible routines would call the same routine that actually does the work.
Regards,
Greg
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - sabur
I've discovered in working the C/Fortran issues that C (in Visual Studio 2005 or Visual Studio itself) apparently needs to see this hidden string length using the IVF convention in the calls between C and Fortran; i.e. with all the hidden length arguments "After All Arguments" in the calling statement. I don't think I can change the calling convention on the C side.
Frankly, I sort of stopped reading after this: this statement is not true, and there likely lies the start of your problem. Let me also address similar problem in Greg's reply:
Quoting - Greg Thorwald
There really isn't a way to have a single DLL accessible routine the can be accessed by both VB and Fortran.
Yes there is. First, note that Intel Fortran is capable of declaring routines -- using !DEC$ATTRIBUTES directives -- which conform to various calling conventions and their implementation details. Check the documentation for C, STDCALL, [NO]MIXED_STR_LEN_ARG, VALUE, REFERENCE, DEFAULT and ALIAS attributes. (Unfortunately, some of these interact in non-obvious ways, which I've ranted about before, but let's skip the details).
These directives generally override compiler settings: e.g. if you compile with /iface:cvf, and declare your routine with !DEC$ATTRIBUTES C, the routine will be C.
Generally, if you want to call a C (or VB or Delphi or...) routine from Fortran, you must do one of the following:
- Write a proper INTERFACE body for that routine with appropriate !DEC$ATTRIBUTES for routine and arguments
- Compile your code with appropriate compiler switches. In this approach, you don't change your code, but you obviously have a problem if you want to interface with 2 different languages simultaneously.
- Declare your routines with appropriate !DEC$ATTRIBUTES
- Compile your code with appropriate compiler switches.
Now, on to Greg's note: if you use non-default !DEC$ATTRIBUTES, how to call those routines from fellow Fortran routines? The answer is: use explicit interfaces. That is, if you place your routines in MODULEs, they can call each other according to standard Fortran rules, no matter which combination of attributes they have. If you don't want to use MODULEs, you must stick to INTERFACE blocks.
I suppose I could elaborate further, but I hope the above helped nonetheless.
Also, there is now a standard way to interface with other languages -- ISO_C_BINDING module -- but it's somewhat less flexible than !DEC$ATTRIBUTES, so I'd skip it as well, for the sake of simplicity. Though I'd recommend to use it if you aim for portability.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Jugoslav Dujic
Frankly, I sort of stopped reading after this: this statement is not true, and there likely lies the start of your problem. Let me also address similar problem in Greg's reply:
Quoting - Greg Thorwald
There really isn't a way to have a single DLL accessible routine the can be accessed by both VB and Fortran.
Yes there is. First, note that Intel Fortran is capable of declaring routines -- using !DEC$ATTRIBUTES directives -- which conform to various calling conventions and their implementation details. Check the documentation for C, STDCALL, [NO]MIXED_STR_LEN_ARG, VALUE, REFERENCE, DEFAULT and ALIAS attributes. (Unfortunately, some of these interact in non-obvious ways, which I've ranted about before, but let's skip the details).
These directives generally override compiler settings: e.g. if you compile with /iface:cvf, and declare your routine with !DEC$ATTRIBUTES C, the routine will be C.
Generally, if you want to call a C (or VB or Delphi or...) routine from Fortran, you must do one of the following:
- Write a proper INTERFACE body for that routine with appropriate !DEC$ATTRIBUTES for routine and arguments
- Compile your code with appropriate compiler switches. In this approach, you don't change your code, but you obviously have a problem if you want to interface with 2 different languages simultaneously.
- Declare your routines with appropriate !DEC$ATTRIBUTES
- Compile your code with appropriate compiler switches.
Now, on to Greg's note: if you use non-default !DEC$ATTRIBUTES, how to call those routines from fellow Fortran routines? The answer is: use explicit interfaces. That is, if you place your routines in MODULEs, they can call each other according to standard Fortran rules, no matter which combination of attributes they have. If you don't want to use MODULEs, you must stick to INTERFACE blocks.
I suppose I could elaborate further, but I hope the above helped nonetheless.
Also, there is now a standard way to interface with other languages -- ISO_C_BINDING module -- but it's somewhat less flexible than !DEC$ATTRIBUTES, so I'd skip it as well, for the sake of simplicity. Though I'd recommend to use it if you aim for portability.
Okay, this sounds promising; there is a way to have C do the "CVF" convention. I'm not sure how to implement it though.
Do I put something like "!DEC$ ATTRIBUTES STDCALL, MIXED_STR_LEN_ARG,REFERENCE::MAIN" after the "SUBROUTINE MAIN BIND(C) line in the code below?
I've tried various combinations; Just using "MIXED_STR_LEN_ARG", with and without STDCALL and REFERENCE etc. and I always seem to get the error message:
[cpp]Error 1 error #7796: Only a function or subroutine subprogram may have the !DEC$ ATTRIBUTES directive [NO]MIXED_STR_LEN_ARG specifier. [MAIN] C:ACS147Fortran95ACSFortran95READDATAFILEACS.for 22 [/cpp]
Is there a problem with using this along with the BIND(C) protocol? Remember, everything is working fine with the MODULE, INTERFACE and C BINDING code. I.e. I'm getting the data I want from the C side to Fortran, I'd hate to mess with that.
Also, when I change the "Calling Convention" in properties back to CVF as the code is shown below (without the !DEC$... line after the SUBROUTINE MAIN BIND(C) statement) I get the following message:
[cpp]Error 1 error LNK2019: unresolved external symbol _MAIN@44 referenced in function _SEEDATA. READDATAFILEACS.obj
I'm assuming I need to change the calling convention back to CVF on the Fortran side so that I don't have the "bad DLL calling convention" issue when executing from Excel.[/cpp]
The code below is the Fortran subroutine that calls the C subroutine. READDATAFILE is called from another subroutine that is called from EXCEL.
Thanks for your help!
Mike
[cpp]C********************************************************************
C
C SUBROUTINE READDATAFILE.for
C
C This subroutine reads the data file and stores the information
C in the QAEU Common
C
C********************************************************************
MODULE seedata
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
! The data
REAL(C_DOUBLE), BIND(C) :: datastuffraw(20000,400)
REAL(C_DOUBLE), BIND(C) :: datastuffeun(20000,400)
CHARACTER(15,C_Char), BIND(C) :: grpnm
INTEGER(C_INT), BIND(C) :: numchn,scans
c Does the 15 need to be 1?
c CHARACTER(KIND=C_CHAR), DIMENSION(*) :: grpnm
INTERFACE
SUBROUTINE MAIN BIND(C)
! No arguments.
! Everything is global.
! Array dimensions are hard coded.
! All very bad.
c CHARACTER(KIND=C_CHAR), DIMENSION(80) :: grpnm
END SUBROUTINE
END INTERFACE
END MODULE seedata
Subroutine READDATAFILE(fname)
USE seedata
USE stuff
implicit none
! Expose subroutine ReadDataFile to users of this DLL
!
c !DEC$ ATTRIBUTES DLLEXPORT::READDATAFILE
C Common for Data
ccc COMMON/QAEU/XEU(3000),SCAN_CHAN(60000,500),SCAN_CHANAVE(10001,500)
C Common for zscan (time)
ccc COMMON/REALNUMBER/time
ccc REAL time, xeu
ccc REAL scan_chan,scan_chanave
INTEGER*4 begz2scanz,avrgintz
C Common for Passed Parameters
COMMON/QAARG/begin_scan, end_scan, iaverage, nopts, opts,
& BegZ2scanz, avrgintz
integer begin_scan, end_scan, iaverage, nopts, opts(10)
C Common for Filenames
COMMON/QAFILES/labDAQ_path, resource_path, data_path,
& data_filename, info_filename, param_filename
C Volatile /QAFILES/
!DEC$ ATTRIBUTES DLLEXPORT::/QAFILES/
c CHARACTER*(*) filename
CHARACTER*80 labDAQ_Path, resource_path, data_path
CHARACTER*80 data_filename, info_filename, param_filename
C Common for Recording Information
COMMON/QAREC/scan_rate, total_scans, reading_number,
* total_chans, ichan_list, scan_integer
INTEGER*4 scan_rate
INTEGER*4 total_scans
INTEGER*2 reading_number
INTEGER*2 total_chans
INTEGER*2 ichan_list(196)
INTEGER*4 scan_integer
C Common for Debug
COMMON/QADEBUG/sim,debug
LOGICAL sim
LOGICAL debug
C Local Variables
character*20 project_name
character*4 data_keyword
integer Get_UnitNo, iounit, iodebug
integer iscan, jchan
CHARACTER*(80) fname
CHARACTER(80) OUTPUT_TEXT,str_out
CHARACTER(LEN=80,KIND=C_CHAR) :: str1
c CHARACTER(LEN=15,KIND=C_CHAR) :: grpnm
INTEGER*4 INT_ARG, OUTPUT_LEN, numChannels, numscans
CHARACTER(80) INPUT_TEXT
c real*8 DATASTUFF(90000,500)
str1 = C_CHAR_"TestYo..." // C_NULL_CHAR
c Teststring = "HelloFromMd" // C_NULL_CHAR
fname = fname // C_NULL_CHAR
int_arg = 123
Call MAIN(datastuffraw, datastuffeun, int_arg, numChannels,
& numscans, fname,str1,grpnm)
scan_chan = datastuffeun
c RETURN
END[/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - sabur
Okay, this sounds promising; there is a way to have C do the "CVF" convention. I'm not sure how to implement it though.
Do I put something like "!DEC$ ATTRIBUTES STDCALL, MIXED_STR_LEN_ARG,REFERENCE::MAIN" after the "SUBROUTINE MAIN BIND(C) line in the code below?
I've tried various combinations; Just using "MIXED_STR_LEN_ARG", with and without STDCALL and REFERENCE etc. and I always seem to get the error message:
[cpp]Error 1 error #7796: Only a function or subroutine subprogram may have the !DEC$ ATTRIBUTES directive [NO]MIXED_STR_LEN_ARG specifier. [MAIN] C:ACS147Fortran95ACSFortran95READDATAFILEACS.for 22 [/cpp]
Is there a problem with using this along with the BIND(C) protocol? Remember, everything is working fine with the MODULE, INTERFACE and C BINDING code. I.e. I'm getting the data I want from the C side to Fortran, I'd hate to mess with that.
Also, when I change the "Calling Convention" in properties back to CVF as the code is shown below (without the !DEC$... line after the SUBROUTINE MAIN BIND(C) statement) I get the following message:
[cpp]Error 1 error LNK2019: unresolved external symbol _MAIN@44 referenced in function _SEEDATA. READDATAFILEACS.obj
I'm assuming I need to change the calling convention back to CVF on the Fortran side so that I don't have the "bad DLL calling convention" issue when executing from Excel.[/cpp]
The code below is the Fortran subroutine that calls the C subroutine. READDATAFILE is called from another subroutine that is called from EXCEL.
Thanks for your help!
Mike
[cpp]C********************************************************************
C
C SUBROUTINE READDATAFILE.for
C
C This subroutine reads the data file and stores the information
C in the QAEU Common
C
C********************************************************************
MODULE seedata
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
! The data
REAL(C_DOUBLE), BIND(C) :: datastuffraw(20000,400)
REAL(C_DOUBLE), BIND(C) :: datastuffeun(20000,400)
CHARACTER(15,C_Char), BIND(C) :: grpnm
INTEGER(C_INT), BIND(C) :: numchn,scans
c Does the 15 need to be 1?
c CHARACTER(KIND=C_CHAR), DIMENSION(*) :: grpnm
INTERFACE
SUBROUTINE MAIN BIND(C)
! No arguments.
! Everything is global.
! Array dimensions are hard coded.
! All very bad.
c CHARACTER(KIND=C_CHAR), DIMENSION(80) :: grpnm
END SUBROUTINE
END INTERFACE
END MODULE seedata
Subroutine READDATAFILE(fname)
USE seedata
USE stuff
implicit none
! Expose subroutine ReadDataFile to users of this DLL
!
c !DEC$ ATTRIBUTES DLLEXPORT::READDATAFILE
C Common for Data
ccc COMMON/QAEU/XEU(3000),SCAN_CHAN(60000,500),SCAN_CHANAVE(10001,500)
C Common for zscan (time)
ccc COMMON/REALNUMBER/time
ccc REAL time, xeu
ccc REAL scan_chan,scan_chanave
INTEGER*4 begz2scanz,avrgintz
C Common for Passed Parameters
COMMON/QAARG/begin_scan, end_scan, iaverage, nopts, opts,
& BegZ2scanz, avrgintz
integer begin_scan, end_scan, iaverage, nopts, opts(10)
C Common for Filenames
COMMON/QAFILES/labDAQ_path, resource_path, data_path,
& data_filename, info_filename, param_filename
C Volatile /QAFILES/
!DEC$ ATTRIBUTES DLLEXPORT::/QAFILES/
c CHARACTER*(*) filename
CHARACTER*80 labDAQ_Path, resource_path, data_path
CHARACTER*80 data_filename, info_filename, param_filename
C Common for Recording Information
COMMON/QAREC/scan_rate, total_scans, reading_number,
* total_chans, ichan_list, scan_integer
INTEGER*4 scan_rate
INTEGER*4 total_scans
INTEGER*2 reading_number
INTEGER*2 total_chans
INTEGER*2 ichan_list(196)
INTEGER*4 scan_integer
C Common for Debug
COMMON/QADEBUG/sim,debug
LOGICAL sim
LOGICAL debug
C Local Variables
character*20 project_name
character*4 data_keyword
integer Get_UnitNo, iounit, iodebug
integer iscan, jchan
CHARACTER*(80) fname
CHARACTER(80) OUTPUT_TEXT,str_out
CHARACTER(LEN=80,KIND=C_CHAR) :: str1
c CHARACTER(LEN=15,KIND=C_CHAR) :: grpnm
INTEGER*4 INT_ARG, OUTPUT_LEN, numChannels, numscans
CHARACTER(80) INPUT_TEXT
c real*8 DATASTUFF(90000,500)
str1 = C_CHAR_"TestYo..." // C_NULL_CHAR
c Teststring = "HelloFromMd" // C_NULL_CHAR
fname = fname // C_NULL_CHAR
int_arg = 123
Call MAIN(datastuffraw, datastuffeun, int_arg, numChannels,
& numscans, fname,str1,grpnm)
scan_chan = datastuffeun
c RETURN
END[/cpp]
Okay, let's try and simplify things. I created a very simple Fortran/VBA code combination. Below is the Excel/VBA code: ("the Public Declare...." statement is actually all on one line)
[cpp]Option Explicit Option Base 1 Public Declare Sub BADD Lib "C:TestFortranBADDLLTESTBADDLLTESTDebugbaddlltest.dll" (inum As Integer) Dim inum As Integer Sub testout() inum = 4 Call BADD(inum) End Sub [/cpp]
Here is the Fortran DLL:
[cpp]Subroutine BADD(int) !DEC$ ATTRIBUTES DLLEXPORT::BADD INTEGER*4 int int = 6 End[/cpp]
No C/C++ code is involved at all. The same thing happens:
1) With "Properties/Fortran/External Procedures/Calling Convention" set to "CVF (/iface:cvf)" this works like a charm.
2) If I do not pass any argument it also worked like a charm whether or not "...Calling Convention" was set to "CVF (/iface:cvf)" or "Default". (Not suprising)
3) If I try to pass an argument (an integer in this example) and "...Calling Convention" is set to "Default" I get a "Bad DLL calling convention" error. This error, as I've described above, occurs when leaving the Fortran subroutine.
I just don't get it. (sigh)
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - sabur
3) If I try to pass an argument (an integer in this example) and "...Calling Convention" is set to "Default" I get a "Bad DLL calling convention" error. This error, as I've described above, occurs when leaving the Fortran subroutine.
Mike,
read Jugoslav's reply carefully (as he's always right).
.... if I recall correctly, you need STDCALL, MIXED_STR_LEN_ARG, REFERENCE (and ALIAS if you want to retain uppercase).
You have bad calling convention error, most probably, because you're not aliasing (and have name suffix issue) once switched to IVF defaults (CVF uses STDCALL and that's what VB expects in your declaration).
I have to admit that I don't quite understand your explanation on that you receive that error message on exit (from Fortran). To my knowledge the situation is that VB expects something else (STDCALL) than you're providing (using IVF defaults), and that means: (1) naming convention, (2) passing by reference/value (I guess VBA uses by value) and also (3) stack cleanup (Callee/Caller).
See this Steve's reply to other thread on how to call Fortran dll from VB.NET. This should work for you. This KB article also clarifies couple of things (for the future). Refer to a nice description on the calling convention differences in ATTRIBUTES Properties and Calling Conventions in IVF Help.
I believe that a good practise (in mixed language programming) is to explicitly define alias, calling convention, reference/value atributes for arguments, as this saves you pain of adjusting once defaults change (what happens sometimes, as you observe yourself, and in painful way -> CVF and IVF).
A.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just out of curiosity I tried to run example from IVF Samples directory, in which ...... Excel calls Fortran dll. I used IVF 11 and Excel 2007. Everything seems to work.
VBA
FORTRAN side
VBA
[cpp]Declare Sub FortranCall Lib "D:UsersArturRunsTestsExcelFcall.dll" (r1 As Long, ByVal num As String)[/cpp]
FORTRAN side
[cpp]subroutine FortranCall (r1, num)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE, ALIAS:"FortranCall" :: FortranCall
integer, intent(in) :: r1
character(10), intent(out) :: num
!DEC$ ATTRIBUTES REFERENCE :: num
num = ''
write (num,'(i0)') r1 * 2
return
end subroutine FortranCall[/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
And one more (and the last thing). Seeing your declaration: you use integer on VBA side and on Fortran integer*4. This can't go together, I believe.
As you can see, the Intel sample uses Long (VBA) and integer (Fortran) (default, which is integer kind = 4)), and this is OK. You're passing integer (kind =2) and tell Fortran to expect integer (kind = 4).
From MSDN
Three data types in Microsoft Visual Basic for Applications (VBA) can represent integers, or whole numbers: the Integer, Long, and Byte data types. Of these, the Integer and Long types are the ones you are most likely to use regularly. The difference between them is their size: Integer variables can hold values between -32,768 and 32,767, while Long variables can range from -2,147,483,648 to 2,147,483,647.
So, read Jugoslav's reply carefully (and follow it), and check the small things.
A.
As you can see, the Intel sample uses Long (VBA) and integer (Fortran) (default, which is integer kind = 4)), and this is OK. You're passing integer (kind =2) and tell Fortran to expect integer (kind = 4).
From MSDN
Three data types in Microsoft Visual Basic for Applications (VBA) can represent integers, or whole numbers: the Integer, Long, and Byte data types. Of these, the Integer and Long types are the ones you are most likely to use regularly. The difference between them is their size: Integer variables can hold values between -32,768 and 32,767, while Long variables can range from -2,147,483,648 to 2,147,483,647.
So, read Jugoslav's reply carefully (and follow it), and check the small things.
A.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - sabur
Okay, let's try and simplify things. I created a very simple Fortran/VBA code combination. Below is the Excel/VBA code: ("the Public Declare...." statement is actually all on one line)
Here is the Fortran DLL:
No C/C++ code is involved at all. The same thing happens:
1) With "Properties/Fortran/External Procedures/Calling Convention" set to "CVF (/iface:cvf)" this works like a charm.
2) If I do not pass any argument it also worked like a charm whether or not "...Calling Convention" was set to "CVF (/iface:cvf)" or "Default". (Not suprising)
3) If I try to pass an argument (an integer in this example) and "...Calling Convention" is set to "Default" I get a "Bad DLL calling convention" error. This error, as I've described above, occurs when leaving the Fortran subroutine.
[cpp]Option Explicit
Option Base 1
Public Declare Sub BADD Lib "C:TestFortranBADDLLTESTBADDLLTESTDebugbaddlltest.dll" (inum As Integer)
Dim inum As Integer
Sub testout()
inum = 4
Call BADD(inum)
End Sub
[/cpp]
Here is the Fortran DLL:
[cpp]Subroutine BADD(int)
!DEC$ ATTRIBUTES DLLEXPORT::BADD
INTEGER*4 int
int = 6
End[/cpp]
No C/C++ code is involved at all. The same thing happens:
1) With "Properties/Fortran/External Procedures/Calling Convention" set to "CVF (/iface:cvf)" this works like a charm.
2) If I do not pass any argument it also worked like a charm whether or not "...Calling Convention" was set to "CVF (/iface:cvf)" or "Default". (Not suprising)
3) If I try to pass an argument (an integer in this example) and "...Calling Convention" is set to "Default" I get a "Bad DLL calling convention" error. This error, as I've described above, occurs when leaving the Fortran subroutine.
For the start, let's assume that you don't use /iface:cvf, i.e. that you have the default compiler options.
VBA expects STDCALL (CVF) calling convention. STDCALL and Ifort default (C) do the stack cleanup differently. Stack cleanup comes into play when there are arguments. With or without arguments, it's highly recommended that you match calling conventions. That means you need at least to add within subroutine BADD:
[cpp]!DEC$ATTRIBUTES STDCALL, ALIAS: "BADD":: BADD[/cpp](Attribute STDCALL has nasty side effect that it lowercases the name by default (bleh) so we need to uppercase it back via alias). In this way, it will be again callable from VBA.
If you want to call a C routine from your code, you probably need an INTERFACE block, with correct prototype. At this stage, I'd recommend that you don't use BIND(C) -- it may interact with !DEC$ATTRIBUTES and confuse the matters further. Offhand, your interface block for the code given above should read (I don't have C prototype so I'm half-guessing):
[cpp]INTERFACE
SUBROUTINE MAIN(datastuffraw, datastuffeun, int_arg, &
numChannels, numscans, fname,str1,grpnm)
!DEC$ATTRIBUTES C, DECORATE, ALIAS: "MAIN":: MAIN
REAL(8):: datastuffraw(90000,500)
???:: datastuffeun
INTEGER:: int_arg, numChannels, numscans
!DEC$ATTRIBUTES REFERENCE:: fname
CHARACTER(*):: fname
!DEC$ATTRIBUTES REFERENCE:: str1
CHARACTER(*):: str1
!DEC$ATTRIBUTES REFERENCE:: grpnm
CHARACTER(*):: grpnm
END SUBROUTINE
END INTERFACE[/cpp]
(P.S. Please, don't call your routines "main" :-). That's likely to confuse linker, as well as readers)
Also, as Artur said, there's likely a VBA:Fortran integer size mismatch (frankly, I also thought that VBA Integer=Fortran Integer(4), but obviously not).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Jugoslav Dujic
For the start, let's assume that you don't use /iface:cvf, i.e. that you have the default compiler options.
VBA expects STDCALL (CVF) calling convention. STDCALL and Ifort default (C) do the stack cleanup differently. Stack cleanup comes into play when there are arguments. With or without arguments, it's highly recommended that you match calling conventions. That means you need at least to add within subroutine BADD:
[cpp]!DEC$ATTRIBUTES STDCALL, ALIAS: "BADD":: BADD[/cpp](Attribute STDCALL has nasty side effect that it lowercases the name by default (bleh) so we need to uppercase it back via alias). In this way, it will be again callable from VBA.
If you want to call a C routine from your code, you probably need an INTERFACE block, with correct prototype. At this stage, I'd recommend that you don't use BIND(C) -- it may interact with !DEC$ATTRIBUTES and confuse the matters further. Offhand, your interface block for the code given above should read (I don't have C prototype so I'm half-guessing):
[cpp]INTERFACE
SUBROUTINE MAIN(datastuffraw, datastuffeun, int_arg, &
numChannels, numscans, fname,str1,grpnm)
!DEC$ATTRIBUTES C, DECORATE, ALIAS: "MAIN":: MAIN
REAL(8):: datastuffraw(90000,500)
???:: datastuffeun
INTEGER:: int_arg, numChannels, numscans
!DEC$ATTRIBUTES REFERENCE:: fname
CHARACTER(*):: fname
!DEC$ATTRIBUTES REFERENCE:: str1
CHARACTER(*):: str1
!DEC$ATTRIBUTES REFERENCE:: grpnm
CHARACTER(*):: grpnm
END SUBROUTINE
END INTERFACE[/cpp]
(P.S. Please, don't call your routines "main" :-). That's likely to confuse linker, as well as readers)
Also, as Artur said, there's likely a VBA:Fortran integer size mismatch (frankly, I also thought that VBA Integer=Fortran Integer(4), but obviously not).
First, in reply to ArturGuzik's 8:22 pm PST reply:
Yes, I know Jugoslav's alrights right, the problem is, is that he and most everyone else here is a bit over my head! :) I'm still in the "this is what works, I don't know why stage", although it's getting a little better. I just not that famililar with putting !DEC$ statements together, although after the last couple of days it has become much clearer. I'm obviously a high level programmer. The ideal solution is to have someone in the computer services division do this (show me) for me but I don't think we have anybody that can do this and we don't seem to have anyone who's kept up with the latest Fortran. Heck, right now I'd pay a consultant, if I could find one locally, to hand-hold me through this. As it is, I'm stuck doing it bit by painful bit. I try to do a lot of googling and reading, which gives me a lot of bits and pieces but it is very difficult to put it together, especially for my particular situation.
Anyway, you're reference to Steve's reply was very helpful. However, if I include REFERENCE as in:
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,REFERENCE,Alias:'READDATAFILE'::READDATAFILE
I get a Run-time error '453': "Can't find DLL entry point READDATAFILE in C:...."
If I take out REFERENCE things seem to work okay. However, I don't need the hidden argument in the VBA declaration and when I'm in the Fortran dll the string I'm passing comes up garbage in the dubugger but reads fine in the debugger in the C code and in VBA and I seem to get the correct results in the Fortran dll. I'm also at the moment having trouble getting an integer to pass from the Fortran back to VBA.
I did this before I saw the posts following your're 8:22 pm one. I will now look more closely at those and see what I can come up with.
Jugoslav,
A couple of things real quick before I look into your last post. I take it that if I just had a Fortran/C issue, the BINDING stuff would be the way to go, but with Excel/VBA involved and requireing !DEC$ directives that this might cause a conflict between the !DEC$ directives and the BINDING stuff?
Yes, I agree with the "MAIN" naming thing, but somehow I was under the impression that the main function in a C routine had to be called "MAIN"? Or am I wrong. In either case, I was not the one who named it. Or are you suggesting I call it something else using "Alias"?
I will now look into your coding example. Thanks.
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The reason you get an error by adding REFERENCE is that you're using fixed-form source (bad!) and the directive now extends past column 72. You can get around this by adding a second directive line:
!DEC$ ATTRIBUTES REFERENCE :: READDATAFILE
!DEC$ ATTRIBUTES REFERENCE :: READDATAFILE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Steve Lionel (Intel)
The reason you get an error by adding REFERENCE is that you're using fixed-form source (bad!) and the directive now extends past column 72. You can get around this by adding a second directive line:
!DEC$ ATTRIBUTES REFERENCE :: READDATAFILE
!DEC$ ATTRIBUTES REFERENCE :: READDATAFILE
Thanks Steve! Of course, those directive lines don't "shade out" when you pass column 72 as do regular code statements. After a bit of thrashing around with the help of the above hint I managed to get things to work. The string reads okay in the DLL, I got my integer value to show up in VBA and my head hasn't exploded yet.
Yes, I know, I know, fixed-form bad. New stuff I do in free-form.
However, I'm still getting warnings such as:
"LNK4217: locally defined symbol READDATAFILE imported in function MYPCALCS"
These are my delcarations in READDATAFILE: (for some reason the "Pencil" insert thing kept breaking these lines up)
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,Alias:'READDATAFILE'::READDATAFILE
!DEC$ ATTRIBUTES REFERENCE::READDATAFILE
This is what is in MYPCALCS:
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'MYPCALCS'::MYPCALCS
!DEC$ ATTRIBUTES REFERENCE::MYPCALCS
.
.
.
CALL READDATAFILE(fname,numchannels)
Don't know if this is significant or not.
Thanks again
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Mike,
believe me, I understand the pain you're going through. The mixed-language programming is that sort of thing, where you can't take anything for granted. I mean, even the approach you took ("If I set this it works, so if I set that it should work too (but usually don't.... why, why, why??!!!!)" is due to the fact that some issues/setting/arguments "interplay" with each other in not obvious way, so naturally you need a guidance. I always go back to Chapter ATTRIBUTES Properties and Calling Conventions in Help files, which is clear on all you need to know about calling other languages. Actually entire Mixed language programming Section is very good. As far as googling goes, well, from time to time you might find a wrong suggestion leading in wrong way (for example regarding .Net programming, everybody seems to be an expert suggesting sometimes very strange things).
So if you want correct suggestion on Fortran this Forum is the place. Steve or Jugoslav can answer any question, as they know everything (I believe that Steve after answering thousands of questions actually can read your mind:-))
Quoting - sabur
I'm also at the moment having trouble getting an integer to pass from the Fortran back to VBA.
Attributes (as Steve already pointed out) can be in separate lines, say:
!DEC$ ATTRIBUTES DLLEXPORT, C :: MyRoutine
!DEC$ ATTRIBUTES DECORATE, ALIAS :'MyRoutine':: MyRoutine
!DEC$ ATTRIBUTES REFERENCE :: i
!DEC$ ATTRIBUTES REFERENCE :: a
!DEC$ ATTRIBUTES REFERENCE :: status
Passing back your integer.
You need to pass it by reference (on Fotran side):
!DEC$ ATTRIBUTES REFERENCE :: i
(this means argument INTENT (INOUT) or (OUT)).
making changes on Fortran side usually means you need to adjust also VBA side (ByRef/ByVal).
A.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,Alias:'READDATAFILE'::READDATAFILE
!DEC$ ATTRIBUTES REFERENCE::READDATAFILE
This is what is in MYPCALCS:
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'MYPCALCS'::MYPCALCS
!DEC$ ATTRIBUTES REFERENCE::MYPCALCS
CALL READDATAFILE(fname,numchannels)
!DEC$ ATTRIBUTES REFERENCE::READDATAFILE
This is what is in MYPCALCS:
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'MYPCALCS'::MYPCALCS
!DEC$ ATTRIBUTES REFERENCE::MYPCALCS
CALL READDATAFILE(fname,numchannels)
Mike,
for clarity separate your attributes like that:
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL :: READDATAFILE
!DEC$ ATTRIBUTES ALIAS : .............
!DEC$ ATTRIBUTES REFERENCE :: argument1, argument2
docs:
The ATTRIBUTES directive options REFERENCE and VALUE specify how a dummy argument is to be passed.
A.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The messages about locally defined imported symbols can be ignored. This happens when you USE a module containing DLLEXPORT directives but you're building the DLL.
REFERENCE does not imply anything about INTENT, though I'll agree that INTENT(OUT) and pass by value don't mix.
REFERENCE does not imply anything about INTENT, though I'll agree that INTENT(OUT) and pass by value don't mix.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - sabur
A couple of things real quick before I look into your last post. I take it that if I just had a Fortran/C issue, the BINDING stuff would be the way to go, but with Excel/VBA involved and requireing !DEC$ directives that this might cause a conflict between the !DEC$ directives and the BINDING stuff?
Yes, I agree with the "MAIN" naming thing, but somehow I was under the impression that the main function in a C routine had to be called "MAIN"? Or am I wrong. In either case, I was not the one who named it. Or are you suggesting I call it something else using "Alias"?
I will now look into your coding example. Thanks.
Yes, I agree with the "MAIN" naming thing, but somehow I was under the impression that the main function in a C routine had to be called "MAIN"? Or am I wrong. In either case, I was not the one who named it. Or are you suggesting I call it something else using "Alias"?
I will now look into your coding example. Thanks.
No, C main function is equivalent to Fortran PROGRAM. If you write a library or dll, you certainly don't want or need one. It is possible to call any routine "MAIN" or "Main" (not so sure about "main"), but it's plainly confusing. I'm not suggesting that you use ALIAS, just... give it some other sensible name (if you have access to the sources, of course; if not, live with it).
ISO_C_BINDING is standardized (Fortran 2003) way to interact with C (and other compatible language) routines; that means that you can build these sources with other F2003 compatible compilers. It is an alternative to !DEC$ATTRIBUTES, but the semantics and syntax are different. I'd simply avoid using them in combination, especially for the same subset of routines. ISO_C_BINDING is somewhat less flexible than !DEC$ATTRIBUTES.
In theory, it's possible that you use BIND(C) throughout, but you need STDCALL to interact with VBA, and I'm not sure whether you can mix BIND(C, ALIAS="Foobar") and !DEC$ATTRIBUTES STDCALL, and what exactly the combination yields. That's why I recommended to use !DEC$ATTRIBUTES throughout (and you don't seem to need portability).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Jugoslav Dujic
We do not allow you to use these together for exactly this reason - there is no agreement on what the combination means.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The irony here is that (i) in Win32 some forty odd IVF modules make use of SDTCALL (for calling the Win32 API) and (ii) IVF is for writing code that runs on Windows, portability be d...d.
Gerry
Gerry
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Steve Lionel (Intel)
We do not allow you to use these together for exactly this reason - there is no agreement on what the combination means.
"Okay, just when you think you've gotten over the hurdle...."
(pause to go search for deals on "StraitJackets" on Amazon.com - hmmm, here's one for $169.95 - don't seem to have one in a medium tall though - I happen to take a longer than average sleeve length... oh wait, nevermind, it's a straitjacket, arm length is not a problem.)
Alright, I will be coming back with questions concerning Jugoslav's suggestions. I think I was able to get rid of all but one type of error message the other night.
Mike
Perhaps you should undo my "Question is answered Yes" line at the beginning of the thread? :) :) :)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For this purpose, just ignore the existence of BIND(C) as it does not meet your needs. Everything you want to do can be done with !DEC$ ATTRIBUTES.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Jugoslav Dujic
No, C main function is equivalent to Fortran PROGRAM. If you write a library or dll, you certainly don't want or need one. It is possible to call any routine "MAIN" or "Main" (not so sure about "main"), but it's plainly confusing. I'm not suggesting that you use ALIAS, just... give it some other sensible name (if you have access to the sources, of course; if not, live with it).
ISO_C_BINDING is standardized (Fortran 2003) way to interact with C (and other compatible language) routines; that means that you can build these sources with other F2003 compatible compilers. It is an alternative to !DEC$ATTRIBUTES, but the semantics and syntax are different. I'd simply avoid using them in combination, especially for the same subset of routines. ISO_C_BINDING is somewhat less flexible than !DEC$ATTRIBUTES.
In theory, it's possible that you use BIND(C) throughout, but you need STDCALL to interact with VBA, and I'm not sure whether you can mix BIND(C, ALIAS="Foobar") and !DEC$ATTRIBUTES STDCALL, and what exactly the combination yields. That's why I recommended to use !DEC$ATTRIBUTES throughout (and you don't seem to need portability).
Jugaslov,
Here's the code that I've got so far. This is the routine READDATAFILE (along with a MODULE and your INTERFACE example from above) that is called by Excel and itself calls a C program called MUD (changed from MAIN like you suggested). I've taken out all the Binding stuff.
Observations:
1) If I don't put CHARACTER statmements in for "str1" and "grpnm" such as below:
[cpp] CHARACTER(80 or *) :: str1I get the following error: (for "gprnm" also)
CHARACTER(15 or *) :: grpnm
[/cpp]
Error 1 error #6404: This name does not have a type, and must have an explicit type. [STR1] C:ACS147Fortran95ACSFortran95READDATAFILEACS.for 86
2) When I put in:
[cpp] CHARACTER(*) :: str1Error 1 error #6832: This passed length character name has been used in an invalid context. [STR1] C:ACS147Fortran95ACSFortran95READDATAFILEACS.for 42
CHARACTER(*) :: grpnm
I get the error: (also for grpnm of course)[/cpp]
3) If I put in:
[cpp] CHARACTER(80) :: str1The code compiles okay buy when I debug from MUD, I get alignment problems between the arguments in the Fortran call statement and the MUD entry point and can't figure out why; I think the Binding stuff took care of this type of thing before I got rid of it.
CHARACTER(15) :: grpnm[/cpp]
On the MUD side, the first two arguemtns, the arrays, seem okay, the next 3 integers, (int *argc...) "cannot be evaulated" and "ivf_fname_len" is equal to the integer 123 which is what "argc" should be.
Beginning of C code follows the Fortran code below.
[cpp] MODULE seedata
IMPLICIT NONE
REAL(8):: datastuffraw(2000,400)
REAL(8):: datastuffeun(2000,400)
c CHARACTER(*) :: str1
c CHARACTER(*) :: grpnm
INTERFACE
SUBROUTINE MUD(datastuffraw, datastuffeun, int_arg,
& numChannels, numscans, fname, str1, grpnm)
!DEC$ATTRIBUTES C, DECORATE, ALIAS: "MUD":: MUD
REAL(8):: datastuffraw(2000,400)
REAL(8):: datastuffeun(2000,400)
INTEGER(4):: int_arg, numChannels, numscans
!DEC$ATTRIBUTES REFERENCE:: fname
CHARACTER(*):: fname
!DEC$ATTRIBUTES REFERENCE:: str1
CHARACTER(*):: str1
!DEC$ATTRIBUTES REFERENCE:: grpnm
CHARACTER(*):: grpnm
END SUBROUTINE
END INTERFACE
END MODULE seedata
Subroutine READDATAFILE(fname,numchannels,numscans)
USE seedata
USE stuff
implicit none
CHARACTER(80) :: str1
CHARACTER(15) :: grpnm
! Expose subroutine ReadDataFile to users of this DLL
!
!DEC$ ATTRIBUTES DLLEXPORT,STDCALL,Alias:'READDATAFILE'::READDATAFILE
!DEC$ ATTRIBUTES REFERENCE::READDATAFILE
INTEGER*4 begz2scanz,avrgintz
C Common for Passed Parameters
COMMON/QAARG/begin_scan, end_scan, iaverage, nopts, opts,
& BegZ2scanz, avrgintz
integer begin_scan, end_scan, iaverage, nopts, opts(10)
c CHARACTER*80 labDAQ_Path, resource_path, data_path
c CHARACTER*80 data_filename, info_filename, param_filename
C Common for Recording Information
COMMON/QAREC/scan_rate, total_scans, total_chans,
* scan_integer,reading_number,ichan_list
INTEGER*4 scan_rate
INTEGER*4 total_scans
INTEGER*2 reading_number
INTEGER*4 total_chans
INTEGER*2 ichan_list(196)
INTEGER*4 scan_integer
CHARACTER(80) fname
CHARACTER(80) OUTPUT_TEXT,str_out
ccc CHARACTER(LEN=80,KIND=C_CHAR) :: str1
ccc CHARACTER(LEN=15) :: grpnm
INTEGER*4 int_arg, numChannels, numscans
ccc str1 = C_CHAR_"TestYo..." // C_NULL_CHAR
ccc fname = fname // C_NULL_CHAR
fname(len(fname):len(fname)) =char(0)
int_arg = 123
Call MUD(datastuffraw, datastuffeun, int_arg, numChannels,
& numscans, fname,str1,grpnm)
total_chans = numchannels
total_scans = numscans
scan_chan = datastuffeun
c RETURN
END[/cpp]
C code: (only beginning part through MUD function)
[cpp]// Include files //----------------------------------------------------------------------------- #include "nilibddc.h" #include#include #include //#define Dllimport __declspec( dllimport ) //MJB //#define DllExport __declspec( dllexport ) //MJB //#define _main main //MJB //DllExport MAIN(); //MJB extern MUD(); //MJB Doing this allows debugging from FortRead to go into CDLL //----------------------------------------------------------------------------- // Macros //----------------------------------------------------------------------------- #define ddcChk(f) if (ddcError = (f), ddcError < 0) goto Error; else #ifdef nullChk #undef nullChk #endif #define nullChk(p) if (!(p)) { ddcError = DDC_OutOfMemory; goto Error; } else //----------------------------------------------------------------------------- // Constants //----------------------------------------------------------------------------- //static const char * FILE_PATH = "testtdms.tdms"; static const char * FILE_PATH = "C:ACS11_3_2008_2_57.tdms "; //static const char * FILE_PATH = "C:ACS2_6_2008_9_58 AM.tdms"; //----------------------------------------------------------------------------- // Forward declarations //----------------------------------------------------------------------------- static int ReadFile (void); static int ReadGroups (DDCFileHandle file); static int ReadChannels (DDCChannelGroupHandle group); double GetAvgDataValue (unsigned __int64 numDataValues, double *data); //extern char stuff_mp_FILE_PATH[81]; //MJB //extern char stuff_mp_str2; //MJB extern char Teststring[12]; //MJB #define cols 400 //MJB #define rows 2000 //MJB void fix_string_for_f90(char output_text[], size_t slen); //MJB double datastuffraw[cols][rows]; //MJB double datastuffeun[cols][rows]; //MJB extern int numChannels; //MJB int numchn; //MJB int scans; //MJB //unsigned __int64 scans; //MJB int count; //MJB unsigned int groupn=0; char *grpnm; //MJB ************************************* /*12/23: This is where I think I'm declaring grpnm to be global */ //int ivf_grpnm_len; //MJB //int *argc //----------------------------------------------------------------------------- // Program entry-point function //----------------------------------------------------------------------------- //int MAIN (int argc, char *argv[]) //Original commented out by MJB //MAIN (double *array2) //MJB MUD (double *datastuffraw, double *datastuffeun, int *argc, int *numc, int *scansn, char*fname, char* str1, char* grpnm,int ivf_fname_len, int ivf_str1_len, int ivf_grpnm_len) //MJB { int ddcError = 0; *argc = 2; //MJB Simply added in attempt to pass an integer. Not integral to original code FILE_PATH = fname; ddcChk (ReadFile()); *numc = numchn; *scansn = scans; Error: if (ddcError < 0) printf ("nError: %sn", DDC_GetLibraryErrorDescription(ddcError)); else printf ("nNo errors.n"); printf("End of program, press Enter key to quitn"); getchar(); return 0; } //----------------------------------------------------------------------------- // Helper functions //-----------------------------------------------------------------------------
.
.
.
.[/cpp]
Thanks
Mike
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page