Skip to end of metadata
Go to start of metadata

You are viewing an old version of this content. View the current version.

Compare with Current View Version History

« Previous Version 22 Next »

Overview

With the release of ETABS v22.0.0 , SAFE v22.0.0 , SAP2000 v26.0.0 , and CSiBridge v26.0.0 , it is now possible to create plugins for CSI products using .NET 8 . To learn more about the .NET 8 platform , please see What's new in .NET 8 . This example will guide a developer through creating a simple .NET 8 plugin using the C# programming language. By making use of the cross-product CSI API library, this example is compatible with ETABS v22.0.0 , SAFE v22.0.0 , SAP2000 v26.0.0 , and CSiBridge v26.0.0 (or a higher version of any of these). For an example plugin using .NET Framework, please see NET Framework Plugin Example .

Walkthrough

Prerequisites

This walkthrough uses Microsoft Visual Studio 2022 and the .NET 8 SDK. One of the following CSI products must be installed on the development computer: ETABS v22.0.0 , SAFE v22.0.0 , SAP2000 v26.0.0 , or CSiBridge v26.0.0 (higher versions of any product will also work)

Procedure

  1. Selecting C# as the language, create a new project of type Class Library. Ensure that the selected project type targets .NET or .NET Standard, not .NET Framework.


2. For convenience, set your project name to the desired name of your plugin. For this example, we will use the name CSiNET8PluginExample1


3. Select .NET 8.0 as the desired Framework


4. Once your project is created, add a reference to the CSI API library. This will be located in the installed program directory, e.g. C:\Program Files\Computers and Structures\ETABS 22\ .  


To create a plugin compatible with multiple CSI products, use the cross-product API library, CSiAPIv1.DLL . This library contains all available interfaces, however no CSI product implements every interface. Some API methods are not applicable to specific 

If you are making a plugin only for one CSI product, you can use the program-specific API library. The program-specific API libraries are:


ProgramAPI Library
ETABSETABSv1.DLL
SAFESAFEv1.DLL
SAP2000SAP2000v1.DLL
CSiBridgeCSiBridge1.DLL


5. Almost all plugins will depend on other (non-CSI) libraries to execute complicated functionality. To simulate the correct management of these dependencies, this plugin makes trivial use of the popular Newtonsoft.Json serialization/deserialization library. It can be added to your project using the NuGet package manager. It is freely available on GitHub.



5. Some manual edits must be made to the project file in order for the plugin to run successfully. Open the project file (in our example, CSiNET8PluginExample1.csproj ) in a text editor, and make the highlighted changes shown below


<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<TargetFramework>net8.0</TargetFramework>	
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<Platforms>AnyCPU;x64</Platforms>
	</PropertyGroup>



	<ItemGroup>
	  <Reference Include="CSiAPIv1">
	    <HintPath>..\..\..\..\..\API\CSI.API\bin\Debug\CSiAPIv1.dll</HintPath>
	  </Reference>
	</ItemGroup>

</Project>  
<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<TargetFramework>net8.0-windows</TargetFramework>	
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<Platforms>AnyCPU;x64</Platforms>
		<EnableDynamicLoading>true</EnableDynamicLoading>
		<UseWindowsForms>true</UseWindowsForms>
	</PropertyGroup>

	<ItemGroup>
	  <Reference Include="CSiAPIv1">
	    <HintPath>..\..\..\..\..\API\CSI.API\bin\Debug\CSiAPIv1.dll</HintPath>
		<Private>false</Private>
		<ExcludeAssets>runtime</ExcludeAssets>
	  </Reference>
	</ItemGroup>

</Project> 

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<TargetFramework>net8.0-windows</TargetFramework>	
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<Platforms>AnyCPU;x64</Platforms>
		<EnableDynamicLoading>true</EnableDynamicLoading>
		<UseWindowsForms>true</UseWindowsForms>
	</PropertyGroup>

	<ItemGroup>
	  <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
	</ItemGroup>

	<ItemGroup>
	  <Reference Include="CSiAPIv1">
	    <HintPath>..\..\..\..\..\API\CSI.API\bin\Debug\CSiAPIv1.dll</HintPath>
		<Private>false</Private>
		<ExcludeAssets>runtime</ExcludeAssets>
	  </Reference>
	</ItemGroup>

</Project>

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<TargetFramework>net8.0-windows</TargetFramework>
		<UseWindowsForms>true</UseWindowsForms>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<EnableDynamicLoading>true</EnableDynamicLoading>
		<Platforms>AnyCPU;x64</Platforms>
	</PropertyGroup>

	<ItemGroup>
	  <Reference Include="CSiAPIv1">
	    <HintPath>..\..\..\..\..\API\CSI.API\bin\Debug\CSiAPIv1.dll</HintPath>
		<Private>false</Private>
		<ExcludeAssets>runtime</ExcludeAssets>
	  </Reference>
	</ItemGroup>

</Project>


6. With the modifications to the project file, you should be able to add a new Windows Form to your project


7. The exact layout of the plugin form is not important, but for the copy and paste code in the steps below to operate correctly, the form must be named Form1, and must contain a Button control named button1 and RichTextBox control named richTextBox1


8. Open the Form1.cs file and paste in the following code


using CSiAPIv1;

namespace CSiNET8PluginExample1
{
    public partial class Form1 : Form
    {

        protected cSapModel _sapModel;
        protected cPluginCallback _pluginCallback;

        public Form1()
        {
            InitializeComponent();
            FormClosing += Form1_FormClosing;
        }

        public void SetSapModel(ref cSapModel inSapModel, ref cPluginCallback inPluginCallback)
        {
            _sapModel = inSapModel;
            _pluginCallback = inPluginCallback;

            richTextBox1.Text = "Hello CSI Friends";
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // It is very important to call _pluginCallback.Finish(0) when the form closes, !!!
            // otherwise, the CSI program will wait and be hung !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            _pluginCallback.Finish(0);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                CreateStructure(richTextBox1.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show("The following error terminated the Plugin:" + Environment.NewLine + ex.Message);
            }
            finally
            {
                this.Close();
            }
        }

        public void CreateStructure(string text)
        {
            int CallResult;
            int i;
            string FrameName = "FrameName";

            var aVectorFont = new cVectorFont();
            double CharHeight = 200.0;
            var HAlignment = cVectorFont.TextAlignment.kTA_HLeft;
            var VAlignment = cVectorFont.TextAlignment.kTA_VTop;
            double[] textX = new double[1], textY = new double[1];
            int NumPts;

            // test for exception handling
            if (string.Equals(text, "crash", StringComparison.InvariantCultureIgnoreCase))
            {
                textX[99] = 0; // out of bounds
            }

            aVectorFont.FillTextVertices(text.ToUpper(), CharHeight, HAlignment, VAlignment, ref textX, ref textY);
            NumPts = textX.Length;

            CallResult = _sapModel.InitializeNewModel();
            CallResult = _sapModel.File.NewBlank();
            for (i = 0; i < NumPts - 2; i++)
            {
                FrameName = "FrameName" + (i / 2).ToString();
                CallResult = _sapModel.FrameObj.AddByCoord(textX[i], textY[i], 0, textX[i + 1], textY[i + 1], 0, ref FrameName);
                i++;
            }

            _sapModel.View.RefreshView(0, false);
        }

    }
}



9. Rename the Class1.cs file to cPlugin.cs and paste in the following code. Please pay attention to the comments in the code, they contain important information about correct plugin operation.

using CSiAPIv1;

namespace CSiNET8PluginExample1
{
    // Implementing the cPluginContract interface is not required, however
    // it is recommended to ensure that the required cPlugin methods are created correctly.
    // Do not implement the Info or Main methods explicitly,
    // i.e. their method signatures are correct as is
    public class cPlugin : cPluginContract
    {
        private static string _modality = "Non-Modal";

        private static string _versionString = "2.0";

        public int Info(ref string Text)
        {
            try
            {
                Text = "This plugin is supplied by Computers and Structures, Inc., " +
                       "as a simple example for developers of new plugins for CSI products. " +
                       "It starts a new blank model, then converts a line of text into " +
                       "frame objects and adds them to the model. If you enter the " +
                       "text \"crash\", an error will be generated for testing purposes. " +
                       "Version " + _versionString;
            }
            catch (Exception)
            {
            }

            return 0;
        }

        public void Main(ref cSapModel sapModel, ref cPluginCallback pluginCallback)
        {
            var aForm = new Form1();

            try
            {
                aForm.SetSapModel(ref sapModel, ref pluginCallback);

                if (string.Compare(_modality, "Non-Modal", true) == 0)
                {
                    // Non-modal form, allows graphics refresh operations in CSI program, 
                    // but Main will return to CSI program before the form is closed.
                    aForm.Show();
                }
                else
                {
                    // Modal form, will not return to CSI program until form is closed,
                    // but may cause errors when refreshing the view.
                    aForm.ShowDialog();
                }

                // It is very important to call pluginCallback.Finish(iError) when the form closes, !!!
                // otherwise, the CSI program will wait and be hung !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // This must be done inside the closing event for the form itself, not here !!!!!!!!!!!

                // If you simply have algorithmic code here without any forms, 
                // then call pluginCallback.Finish(iError) here before returning to the CSI program

                // If your code will run for more than a few seconds, you should exercise
                // the Windows messaging loop to keep the program responsive. You may 
                // also want to provide an opportunity for the user to cancel operations.

            }
            catch (Exception ex)
            {
                MessageBox.Show("The following error terminated the plugin:" + Environment.NewLine + ex.Message);

                // call Finish to inform the CSI program that the plugin has terminated
                try
                {
                    pluginCallback.Finish(1);
                }
                catch (Exception)
                {
                }
            }
        }
    }
}
  • No labels