Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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 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).


Note that the MyEngineDLLAccess class is not instantiated. All the methods in this class are static and can be accessed directly by referencing the class. (Note that to make the example simpler, not all DLL import statements are shown.)


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.Text;
namespace MyOrganisation.OpenMI.MyModel
{
   public class MyEngineDotNetAccess
   {
      public void Initialize(string filePath)
      {
         if(!(MyModelDLL.Initialize(filePath, ((uint) filePath.Length))))
         {
            CreateAndThrowException();
         }
      }
 
      public void PerformTimeStep()
      {
         if(!(MyModelDLL.PerformTimeStep()))
         {
             CreateAndThrowException();
         }
      }

      public void Finish()
      {
         if(!(MyModel.Finish()))
         {
            CreateAndThrowException();
         }
      }

      private void CreateAndThrowException()
      {
         int numberOfMessages = 0;
         numberOfMessages = MyModelDLL.GetNumberOfMessages();
         string message = 'Error Message from MyModel ';
         for (int i = 0; i < numberOfMessages; i++)
         {
             int n = i;
             StringBuilder messageFromCore = new StringBuilder(' ');
             MyModelDLL.GetMessage(ref n, messageFromCore,(uint) messageFromCore.Length);
             message +='; ';
             message += messageFromCore.ToString().Trim();
         }
         throw new Exception(message);
     }
}
Step 5: Implementing the MyEngineWrapper class

The fifth step is to implement the MyEngineWrapper class (Figure 11).

Image Added

The MyEngineWrapper class must implement the ILinkableEngine interface (Oatc.OpenMI.Sdk.Wrapper.ILinkableEngine). The easiest way to get started is to make your development environment auto-generate the stub code for this interface.


The first step is to implement the Initialize method and the Finish method.


The MyEngineWrapper has a private field variable (_myEngine) that holds a reference to the MyEngineDotNetAccess class. The Initialize method will instantiate the MyEngineDotNetAcccess object and assign a reference to this object to the _myEngine variable.


Example code for this is shown below.

Code Block

using System;
using System.Collections
namespace MyOrganisation.OpenMI.MyModel
{
    public class MyEngineWrapper : org.OpenMI.Utilities.Wrapper.IEngine
    {
       private MyEngineDotNetAccess _myEngine;
       public void Initialize(Hashtable properties)
       {
          _myEngine = new MyEngineDotNetAccess();
          _myEngine.Initialize((string)properties['FilePath']);
       }

       public void Finish()
       {
          _simpleRiverEngine.Finish();
       }
    }
}
Step 6: Implementing the MyModelLinkablComponent