Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

4.4 Step 4: Implementing the MyEngineDotNetAccess

The fourth step is to implement the MyEngineDotNetAccess class (Figure 10).

Fig 10. MyEngineDotNetAccess class

 
The MyEngineDotNetAccess has two purposes: to change the calling conventions to C# conventions and to change error messages into .NET exceptions.

The listed code below shows the Simple River example code for a MyEngineDotNetAccess class that implements the Initialize method, the performTimeStep method and the Finish method. In each of these methods the corresponding method in the MyEngineDLLAccess class is called and, if this method returns false, the error message from the engine is queried through the GetMessage method (following which an exception is created and thrown).

...

The normal convention for Fortran DLLs is that values are returned through the function (effectively, they are passed by reference); for C# results are passed by value. Therefore there may be a need to state explicitly that C# parameters passed to a Fortran routine are to be passed by reference. In Fortran, arrays normally start from index 1 whereas in C# the convention is to start from zero. These differences can be handled in the MyEngineDotNetAccess class. When you have completed the implementation of the methods shown below you can create and implement the corresponding test class and run the unit test.

Code Block
using System; 
using System.Text; 

namespace MyOrganisationOatc.OpenMI.MyModel {    public class MyEngineDotNetAccessExamples.ModelComponents.SimpleRiver.Wrapper
{

	public class SimpleRiverEngineDotNetAccess
	{
		IntPtr _FortranDllHandle;

		public void Initialize(string filePath)
		{
      {      _FortranDllHandle public void Initialize(string filePath)= Kernel32Wrapper.LoadLibrary(@"Oatc.OpenMI.Examples.ModelComponents.SimpleRiver.Engine.dll");

       {     string curDir   = System.IO.Directory.GetCurrentDirectory();

			if(\!(MyModelDLLSimpleRiverEngineDllAccess.Initialize(filePath, ((uint) filePath.Length))))         {           CreateAndThrowException();         }       }
			{
				CreateAndThrowException();
			}
		}

         public void PerformTimeStep()
        {
            if (\!(MyModelDLLSimpleRiverEngineDllAccess.PerformTimeStep()))
            {
                CreateAndThrowException();
         }   }
    }       }

		public void Finish()       {          if(\!(MyModel
		{
			if(!(SimpleRiverEngineDllAccess.Finish()))          {              CreateAndThrowException();          }
			{
				CreateAndThrowException();
			}
			while(Kernel32Wrapper.FreeLibrary(_FortranDllHandle));
		}
       }        
		private void CreateAndThrowException()       {          
		{
			int numberOfMessages = 0;          
			numberOfMessages = MyModelDLLSimpleRiverEngineDllAccess.GetNumberOfMessages();          
			string message = '"Error Message from MyModelSimpleRiver ';Fortran          Core ";

			for (int i = 0; i < numberOfMessages; i++)
			{
				int n = i;
				StringBuilder messageFromCore = new StringBuilder("      {                int n = i;             StringBuilder messageFromCore = new StringBuilder(' ');             MyModelDLL");
				SimpleRiverEngineDllAccess.GetMessage(ref n, messageFromCore, (uint) messageFromCore.Length);             
				message \+='"; ';             message \";
				message += messageFromCore.ToString().Trim();          }          
			}
			throw new Exception(message);       } 
		}
	}
}