...
The next step is to create the wrapper classes (Figure 8). For this stage, make sure that the OpenMI Software Development Kit is installed on your PC.
Fig 8. C# wrapping classes
Load the .NET development environment. You should create one assembly for your wrapper classes and it is strongly recommended that you also create one assembly for the corresponding test classes.
You should use the following naming conventions for your wrapper assembly:
Assembly name: MyOrganisation.OpenMI.MyModel
Assembly DLL name: MyOrganisation.OpenMI.MyModel.DLL
Namespace: MyOrganisation.OpenMI.MyModel
Class names: MyModelEngineWrapper, MyModelEngineDotNetAccess, MyModelEngineDLLAccess, MyModelLinkableComponent
Naming conventions for the test assembly:
Assembly name: MyOrganisation.OpenMITest.MyModel
Assembly DLL name: MyOrganisation.OpenMITest.MyModel.DLL
Namespace: MyOrganisation.OpenMI.MyModel
Class names: MyModelEngineWrapperTest, MyModelEngineDotNetAccessTest, MyModelEngineDLLAccessTest, MyModelLinkableComponentTest
Now install the NUnit test software (see Chapter 6)
To the wrapper assembly, add the following references:
Org.OpenMI.Standard
Org.OpenMI.Backbone
Org.OpenMI.Utilities.Wrapper
To the test assembly, add the following references:
Org.OpenMI.Standard
Org.OpenMI.Backbone
Org.OpenMI.Utilities.Wrapper
NUnit.framework
MyOrganisation.OpenMI.MyModel
After creating the assemblies and the classes, you can start working on the first class,
MyEngineDLLAccess. Details are given in the next section.
Step 3: Accessing the functions in th engine core
The third step is to implement the MyEngineDLLAccess class (Figure 9).
Fig 9. MyEngineDllAccess class
Because you are using a C# implementation of OpenMI, your engine needs to be accessible from .NET. In the pattern shown above this is handled in two wrappers, MyEngineDLLAccess and MyEngineDotNetAccess. The MyEngineDLLAccess class will make a one-to-one conversion of all exported functions in the engine core code to public .NET methods. The MyEngineDotNetAccess class will change some of the calling conventions.
The specific implementation of the MyEngineDLLAccess class depends on the compiler you are using. Start by implementing export methods for the Initialize, PerformTimeStep, Finish and Dispose functions.
The code listed below shows an example of such an implementation for the Simple River Fortran engine. Note that this implementation corresponds to a particular Fortran compiler; the syntax may vary between compilers.
Code Block |
---|
using System;
using System.Run-time.InteropServices;
using System.Text;
namespace MyOrganisation.OpenMI.MyModel
{
public class MyEngineDLLAccess
{
\[DLLImport(@'C:\MyEngine\bin\MyEngine.DLL',
EntryPoint = 'INITIALIZE',
SetLastError=true,
ExactSpelling = true,
CallingConvention=CallingConvention.Cdecl)\]
public static extern bool Initialize(string filePath, uint length);
\[DLLImport(@'C:\MyEngine\bin\MyEngine.DLL',
EntryPoint = 'PERFORMTIMESTEP',
SetLastError=true,
ExactSpelling = true,
CallingConvention=CallingConvention.Cdecl)\]
public static extern bool PerformTimeStep();
\[DLLImport(@'C:\MyEngine\bin\MyEngine.DLL',
EntryPoint = 'FINISH',
SetLastError=true,
ExactSpelling = true,
CallingConvention=CallingConvention.Cdecl)\]
public static extern bool Finish();
}
}
|