1

In my current employment, A major task is to take an existing engineering tool, and update it, as it has stopped working on the modern OS's.

Now the tool was written in FORTRAN, and most of the source file headers state something like:

C    modified by (obfuscated) at dd. mm. 19yy to do something

The employees have cycled since then, and much of the documentation was either never done, or has been lost. So it's up to us to decipher how the program operates, and then recreate that functionality in a more modern language.

For this purpose we have chosen C#.

I am somewhat able to read FORTRAN, so deciphering the math, and logic have so far been straight forward, but I am stuck when comes to dllimports.

I have no clue who made the dll's, or where the source code is, but What I have determined is that they are responsible for some of the key calculations for some of our vendors components. Hence I cannot simply replace the dll with new code as I have no clue which equations are in there..

What I have found out is that the old program sent xml formatted data to the dll entries, and got an xml-like string back. I cannot however replicate it, as I am not completely sure how it works.

Can anybody explain this, or perhaps even translate this to a C++ / C# equivalent?

  ! interface for CalculateStuff.dll
  INTERFACE
    SUBROUTINE CalculateComponent(Input, Output)
      !DEC$ ATTRIBUTES REFERENCE, ALIAS : '_CC@16' :: CalculateComponent
      !DEC$ ATTRIBUTES DLLIMPORT :: CalculateStuff
      CHARACTER*(*) Input, Output
      !DEC$ ATTRIBUTES REFERENCE :: Input
      !DEC$ ATTRIBUTES REFERENCE :: Output
    END SUBROUTINE
  END INTERFACE

Currently I have this snippet, (C#) but it seems to fail on me:

class CalculateStuff{
    [DllImport("CalculateStuff.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall, EntryPoint = "_CC@16")]
    public static extern void CalculateComponent(ref string input, ref string output);
}

edit 1: added charset and now the program gave me this exception, its an improvement I think:

An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

edit 2: recompiled as 32bit application, and now I get:

External component has thrown an exception.

edit 3: changed return type to void, as this makes completely sense to me.

edit 4: added the calling convention defined as stdCall, due to many comments hinting that, it didn't help. have also tried defining the parameter types as string, or ref string nothing changes.

Henrik
  • 2,180
  • 16
  • 29
  • Fortran probably encodes strings differently than C#. Does adding `CharSet = CharSet.Ansi` to the `DllImport` help? Also, how does it fail? – Aasmund Eldhuset Jun 17 '15 at 07:17
  • Well, the dll response is null. will try to set the Charset also :) – Henrik Jun 17 '15 at 07:31
  • There's also the `MarshalAs` attribute that you can apply to each parameter, which offers more customization possibilities. I'm also guessing that either both or neither of the parameters need to be `ref`. Also, since it's a subroutine, it doesn't have a return value, so I'm also guessing that the C# function should be `void`. – Aasmund Eldhuset Jun 17 '15 at 07:50
  • Re. your edit: Do you get different errors by varying the charset? (If all charsets but one give the same error, that one is probably the right one.) – Aasmund Eldhuset Jun 17 '15 at 07:52
  • Should be `string input, StringBuilder output` I guess. However, the @16 indicates a 32 bit stdcall DLL with 16 bytes of parameters. So I guess that a couple of length parameters are included too. Probably after all the other parameters. – David Heffernan Jun 17 '15 at 08:10
  • I will look into the `MarshallAs`. @Aasmund Eldhuset: tried changing it back. The old behaviour described in the comment, is no longer reproduced, now the error mentioned in the edit is thrown for all charsets. I must have changed something else also, when I edited the code. – Henrik Jun 17 '15 at 09:25
  • @Davide Heffernan, that part about the `@16` was something I didn't know. However, the "strings" used by FORTRAN is 255 is defined like this: `character(kind=1,len=15000) :: outstring` – Henrik Jun 17 '15 at 09:29
  • `prevComment.Replace("is 255", "");` ;) – Henrik Jun 17 '15 at 09:38
  • 1
    If you have the old MSDN subscription disks, they may still have Powerstation 5 which will have the manual describing the usage of !MS$, which is the same as !DEC$. – cup Jun 17 '15 at 11:23
  • There is actually a chance that we have that :D – Henrik Jun 17 '15 at 11:27
  • 2
    There are a few things going on here. The first is that the DLL routine, as others have said, uses the STDCALL calling mechanism, There is a C# way to specify that, but I am not sure what it is. Another is the string lengths. Here you'll have to know which compiler built the DLL, as the lengths may immediately follow the string addresses, or they may be at the end. My guess is that they will follow the addresses, as that was the DEC/Compaq (and MS) convention, and if the DLL was built using Intel Visual Fortran, the lengths would probably be at the end. – Steve Lionel Jun 17 '15 at 12:38
  • Hi Steve, thank you for the comment, the FORTRAN program interfacing the DLL, was built with the intel13 compiler. I believe the DLL wraps another DLL, as the original application requires the visual C++ VC90 runtime to work properly. – Henrik Jun 17 '15 at 13:12
  • See related http://stackoverflow.com/questions/10317691/making-fortran-dll-and-calling-it-from-c-sharp and http://stackoverflow.com/questions/6961410/type-marshalling-to-call-a-fortran-subroutine-from-c-sharp – John Alexiou Jul 28 '15 at 14:07

0 Answers0