Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

How to pass a character variable to Fortran dll?

Xudong_L_
Beginner
1,586 Views

Hi all,

For some reason, I have to invoke several Fortran dlls using JavaScript, and I've met problems when I tried to pass a character variable to Fortran.

The following is the dll and corresponding Fortran codes (x64):

!-------------------------------------------------------------------------------------------

character(len=1) function pass(inStr,inLen)
    !DEC$ ATTRIBUTES C,DLLEXPORT::pass
    implicit none
    character(len=1),intent(in)::inStr
    integer,intent(in)::inLen
    character(len=1)::tempStr
    
    pass=inStr
    
end function

!-------------------------------------------------------------------------------------------

And I invoke the dll in JavaScript like this (by means of no-ffi):

//-------------------------------------------------------------------------------------------

const dllPath = path.join(__dirname, '../../dlls/PassStr.dll')

var DLL = ffi.Library(dllPath, {

'pass':['string', ['string', 'int']]

})

DLL.pass.async("A", 1, (err, result) => {

})

//-------------------------------------------------------------------------------------------

But the dll cannot catch the character. I've heard that it may due to the character encoding i.e. UTF-8/Unicode, but I don't really know how to solve the problem. So anybody has some comments?

Thank a lot!

 

0 Kudos
5 Replies
Eugene_E_Intel
Employee
1,586 Views
Hello, I'm not a JavaScript expert, but from doing some searching around, it does seem that this is string encoding issue. It seems that you need to take your strings in JavaScript and convert them to arrays of bytes that contain ASCII characters. Here are some links that may be relevant: https://stackoverflow.com/questions/12332002/how-to-store-a-byte-array-in-javascript https://stackoverflow.com/questions/94037/convert-character-to-ascii-code-in-javascript Note that this will only work,if your original string contains only the characters that can be represented as ASCII. Thank you.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,586 Views

I think this is more of an issue that you have not declared the function "pass" arguments properly in your JavaScript.

The Fortran function "pass" is declared as returning the address of a 1 byte character, that takes as arguments the address of a 1 byte character, and the address/reference of a 4-byte integer containing the length (1) of the one byte character referebce a Jav

I am not a Java programmer, I have used C#, it appears that you have declared the interface as:

returning a string object (which may or may not be Unicode, which contains reference/pointer to characters, plus string length)
taking as arguments a reference to a Java string object, and a reference to an integer. It is unknown to me as to if int in Java is 16, 32 or 64 bits.

I would look at experimenting with calling a C function with signature of

   char* test(char* cp, int* len);

Once that is working then rework it to call your pass function.

I think your pass function needs to be declared as

character(len=*) function pass(inStr,inLen)
    !DEC$ ATTRIBUTES C,DLLEXPORT::pass
    implicit none
    character(len=*),intent(in)::inStr
    integer,intent(in)::inLen
    character(len=1024), save ::tempStr  ! caution only 1 copy in SAVE
    tempStr = "This is a test"
    pass=tempStr // ":" // inStr(1:inLen) ! "This is a test:whatWasIninStr"
    
end function

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,586 Views

Notes, make the one copy of the tempStr long enough to contain the maximum number of possible characters. You can make this an allocatable if need be. On the Java side, declare the function return as returning a reference to fixed length character buffer (same worst case length) that accepts the return arg. Then convert (copy) the trailing space trimmed result as a Java string. It may be better to define the function as a subroutine (void function) that has arguments (inStr, inLen, outStr, outLen) and thus you do not have to change the Fortran DLL should you decide to increase the Java maximum string lengths. This also eliminates the requirement of having a single buffer for holding the return argument.

Jim Dempsey

0 Kudos
Xudong_L_
Beginner
1,586 Views

Dear Eugene and Jim,

Thank you for your comments!

First of all, I have to say that I'm not a JavaScript programmer either. I have tried to test your solutions. As for Jim's suggestion, ( character(len=*) function pass(inStr,inLen) ), Fortran cannot catch the content of inStr either. If I print "inStr" in the Fortran function "pass", I can see nothing just like I only define character(len=*)::inStr but don't initialize it. What's worse, when I tried to test Eugene's suggestion, I found that the Fortran dll even cannot receive the content of an integer array sent by JavaScript.

There is a great possibility that the inconsistency between the data structure of Fortran and JavaScript leads to this problem. I'm still trying to fix it. I'll be very appreciated if you and anyone else can give me further comments.

Thank you all!

Xudong Li

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,586 Views

>>DLL.pass.async("A", 1, (err, result) =>{});

The first argument is a reference to a Java string object and not a reference to a block of data containing characters.

char buffer[] = new char [1024]; // big enough for your later use
buffer[0] = 'A'; // don't care about [1], [2], ...
DLL.pass.async(buffer, 1, (err, result) =>{}); // Java may want {;}

 

I do not know if the 1 above is passed by value or reference, you will need to check this out and correct.

Jim Dempsey

0 Kudos
Reply