Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

How to call CVF6.6 dll from C#

sumitm
Beginner
686 Views
Hi,
I need some help in the above subject.
I had made a standard dll for my C# developer. He is finding it difficult to call that from C# and all previous examples were involving strings. Ours involve real and integer type arrays.
He has also asked if I could supply him with a standard COM dll instead. He says it is easy to integrate .NET with COM instaed of standard Win32 dlls.


Basically, the question is how to import a particular subroutine from one of my dlls.

Following is the fortran Dll I created


  SUBROUTINE PDP(X,Y,W,M,P,N) ! Parison digitization(X,Y,W) -> P(*,7):S,RA,W,VOL,RI,RO,YA
   !DEC$ ATTRIBUTES DLLEXPORT :: PDP
      !DEC$ ATTRIBUTES C, ALIAS:'PDP' :: PDP
   use colorb  ! to transfer value of S(9) contour length
  ! use pieval
   implicit none
   integer,Parameter:: M1=9
      Real P(42,M1),X(M1),Y(M1),W(M1),S(M1),R(M1) ! P was (21,M)
   real GP,CI,PI3,FR,DS,SN,CS,WS,VV,DZ
   Integer I,J,N,L,K,M
      DATA GP,CI/2., -25.4/
      PI3=PI/3
      S(1)=0
      DO 2 J=2,M ! M is now 9. Was 7 in earlier version
      I=J-1
      R(J)=X(J)-W(J)/2. ! Middle of Preform Wall
      DS=SQRT((R(J)-R(I))**2+(Y(J)-Y(I))**2) ! Distance between Adj points
      IF(J.EQ.2) DS=.5*PI*R(2) ! A fourth of the quadrant perimeter
      S(J)=S(I)+DS ! Contour length
      P(1,J)=0.   ! P(1, 1..8)=0
   2  CONTINUE
      DZ=S(M)/(N-1) ! Divide total contour length into 20 equal segments, N is 20
      P(1,1)=0.
      P(1,3)=W(1)
      R(1)=R(2)
 
      pf_ct_l=S(M)  !to transfer value of contour length for CCGR routine
 
      I=1
      DO 3 L=2,N
      K=L-1
      P(L,1)=K*DZ ! P(1..20,1) are the new height locations
      J=I
   4  J=J+1
      IF(S(J).LT.P(L,1).AND.J.LT.M) GOTO 4
      I=J-1
      FR=(P(L,1)-S(I))/(S(J)-S(I)) ! fraction
      P(L,3)=W(I)+(W(J)-W(I))*FR  !wall thickness at each location
      P(L,2)=R(I)+(R(J)-R(I))*FR   ! outside radius at each location
      P(L,7)=Y(I)+FR*(Y(J)-Y(I))   ! Height at each location
      P(L,5)=(P(L,2)-.5*P(L,3))  ! Radius at midpoint
      P(L,6)=(P(L,2)+.5*P(L,3))  
      IF(J.LE.2) THEN
       SN=SIN(P(L,1)/R(2)) ! P(L,1)/R(2) is the angle and R(2)*Sin () is the x distance
       P(L,2)=R(2)*SN
       P(L,5)=(R(2)-.5*P(L,3))*SN
       P(L,6)=(R(2)+.5*P(L,3))*SN
       CS=SQRT(1-SN*SN)
       P(L,7)=Y(2)-R(2)*CS
      ENDIF
      WS=P(K,3)+P(L,3)
      VV=PI3*DZ*(P(K,2)*(P(K,3)+WS)+P(L,2)*(P(L,3)+WS))
      P(L,4)=P(K,4)+VV
   3  CONTINUE
      RETURN
      END SUBROUTINE PDP
{/pre]


Following is the dll import that he used in C#
                        [DllImport("pdp_dll.dll")]

                        public static extern void PDP([MarshalAs(UnmanagedType.LPArray)]ref float[] X,

                                    [MarshalAs(UnmanagedType.LPArray)]ref float[] Y,

                                    [MarshalAs(UnmanagedType.LPArray)]ref float[] W,

                                    [MarshalAs(UnmanagedType.I4)]ref int PN,

                                    [MarshalAs(UnmanagedType.LPArray)]ref float[,] PPP,

                                    [MarshalAs(UnmanagedType.I4)]ref int points);

 

When I try to call the PDP method from code, with something like this:

 

                                    float[] X = new float[9];

                                    X.Initialize();

                                    float[] Y = new float[9];

                                    Y.Initialize();

                                    float[] W
 = new float[9];

                                    W.Initialize();

                                    float[,] PPP = new float[42,9];

                                    PPP.Initialize();

 

                                    try

                                    {

                                                int intLength = 9;

                                                int intPoints = 42;

                                                PDP(ref X, ref Y, ref W, ref intLength, ref PPP, ref intPoints);

                                    }

                                    catch (Exception ex)

                                    {

                                                MessageBox.Show(ex.Message);

                                    }

 

 

 

An ?Object reference not set to an instance of an object? exception is thrown. I believe this is a common error to occur if your DllImport statement does not match the method signature correctly.


Any help would be greatly appreciated.

Thanks




0 Kudos
4 Replies
hweisberg
Beginner
686 Views
You could turn your subroutine into a COM server using the wizard in CVF Professional, but why? Your current approach should work and seems simpler.

Try breaking the problem into smaller parts -- for example just passing an int or an array of floats.

MarshalAs(UnmanagedType.I4) may be a problem. Fortran expects a pointer to a integer, not an integer. MarshalAs(UnmanagedType.LPArray) might work better.
0 Kudos
sumitm
Beginner
686 Views
Thanks!

Can you show me a little example of how to turn this into a COM server. I am probably trying something way out of my league but an example would be helpful. I looked at all the sample examples under advanced/com. Is there one that is closer to my case that I can study.

My C# developer told me that ".NET creates interop dlls automatically for working with COM objects, so there is usually no problem with having to figure out calling conventions" and also that" you can?t use LPArray on an integer. Also, the fact that I have declared the integers to be passed by reference IS a pointer, which he mentions Fortran is expecting "

It is not my idea to put one against the other but any solution in either way would be very much appreciated.

Thanks

0 Kudos
hweisberg
Beginner
686 Views
Fortran with the "C" calling convention expects integers and floats to be passed by value and arrays to be passed by reference. Try the following:

public static extern void Hello(float[] X, float[] Y, float[] W, int PN, float[,] PPP, int points);

and

Hello(X, Y, W, intLength, PPP, intPoints);

This uses P/Invoke's default marshalling, which should correctly pass your int's and arrays in and return values from the arrays.
0 Kudos
sumitm
Beginner
686 Views
Many Thanks for your help.

My C# developer says it seems to work now.

I may have some more questions later on.

Thanks again

Sumit
0 Kudos
Reply