Handling Solid Edge Events

Solid Edge provides a wide range of COM event sets that notify us when certain things occur. In this article, I will discuss how you can attach to these events from .NET. Prior to .NET, handling COM events was rather straightforward. It’s a little tricker in .NET but still completely possible as you’ll see.

For this article, I will be focusing on most popular Solid Edge event set, ISEApplicationEvents.

From .NET, we have two approaches available for connecting to COM events.

  1. Delegate Event Model
  2. Connection Point Model

Delegate Event Model

The delegate event model is typically more natural to .NET developers. This approach allows you to handle specific events rather than every event that an event set exposes.

If you open the Object Browser and search for ISEApplicationEvents, you will see the raw interface definition. This raw interface is not what we need in the delegate event model.

ObjectBrowser_ISEApplicationEvents.jpg

There is a hidden class that is generated by the type library importer named ISEApplicationEvents_Event that we need to leverage in this approach. In order to see the hidden class ISEApplicationEvents_Event, modify the Object Browser settings as shown below to Show Hidden Types And Members.

ShowHiddenTypesAndMembers.jpg

With the Object Browser settings in place, now search for ISEApplicationEvents_Event

ObjectBrowser_ISEApplicationEvents_Event.jpg

Now that we are aware that ISEApplicationEvents_Event exists, we can leverage it with the following sample code. Please note that the code below is for demonstration purposes only and does not handle situations like when the BeforeQuit event is raised.

*Note that the ISEApplicationEvents_Event class will not be available in the code editor intellisense since it is a hidden class. You will have to manually type the full name and it will resolve.

Visual Basic – Delegate Event Model Example

Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace EventTest
Partial Public Class Form1
Inherits Form

Private _application As SolidEdgeFramework.Application
Private _applicationEvents As SolidEdgeFramework.ISEApplicationEvents_Event

Public Sub New()
InitializeComponent()
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
‘ Connect to Solid Edge.
_application = DirectCast(Marshal.GetActiveObject(“SolidEdge.Application”), SolidEdgeFramework.Application)

‘ Connect to application events.
_applicationEvents = CType(_application.ApplicationEvents, SolidEdgeFramework.ISEApplicationEvents_Event)
AddHandler _applicationEvents.AfterDocumentSave, AddressOf _applicationEvents_AfterDocumentSave
AddHandler _applicationEvents.BeforeDocumentSave, AddressOf _applicationEvents_BeforeDocumentSave
End Sub

Private Sub _applicationEvents_AfterDocumentSave(ByVal theDocument As Object)
‘ Handle AfterDocumentSave.
End Sub

Private Sub _applicationEvents_BeforeDocumentSave(ByVal theDocument As Object)
‘ Handle BeforeDocumentSave.
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
‘ Disconnect to application events.
RemoveHandler _applicationEvents.BeforeDocumentSave, AddressOf _applicationEvents_BeforeDocumentSave
RemoveHandler _applicationEvents.AfterDocumentSave, AddressOf _applicationEvents_AfterDocumentSave
_applicationEvents = Nothing
End Sub
End Class
End Namespace

C# – Event Delegate Model Example

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EventTest
{
public partial class Form1 : Form
{
private SolidEdgeFramework.Application _application;
private SolidEdgeFramework.ISEApplicationEvents_Event _applicationEvents;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
// Connect to Solid Edge.
_application = (SolidEdgeFramework.Application)Marshal.GetActiveObject(“SolidEdge.Application”);

// Connect to application events.
_applicationEvents = (SolidEdgeFramework.ISEApplicationEvents_Event)_application.ApplicationEvents;
_applicationEvents.AfterDocumentSave += _applicationEvents_AfterDocumentSave;
_applicationEvents.BeforeDocumentSave += _applicationEvents_BeforeDocumentSave;
}

void _applicationEvents_AfterDocumentSave(object theDocument)
{
// Handle AfterDocumentSave.
}

void _applicationEvents_BeforeDocumentSave(object theDocument)
{
// Handle BeforeDocumentSave.
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Disconnect to application events.
_applicationEvents.BeforeDocumentSave -= _applicationEvents_BeforeDocumentSave;
_applicationEvents.AfterDocumentSave -= _applicationEvents_AfterDocumentSave;
_applicationEvents = null;
}
}
}

Connection Point Model

The Connection Point Model is a more raw, manual approach to handling events. It involves having a class implement an event interface, ISEApplicationEvents in this case. This means you will be handling every event that a particular event set raises.

In order to do this from .NET, we will need to leverage the IConnectionPointContainer and IConnectionPoint interfaces from the System.Runtime.InteropServices.ComTypes namespace.

Visual Basic – Connection Point Model Example

Option Infer On

Imports System
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports System.Windows.Forms

Namespace EventTest
Partial Public Class Form1
Inherits Form
Implements SolidEdgeFramework.ISEApplicationEvents

Private _application As SolidEdgeFramework.Application
Private _connectionPoint As IConnectionPoint
Private _cookie As Integer

Public Sub New()
InitializeComponent()
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
‘ Connect to Solid Edge.
_application = DirectCast(Marshal.GetActiveObject(“SolidEdge.Application”), SolidEdgeFramework.Application)

ConnectEvents()
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
DisconnectEvents()
End Sub

Private Sub ConnectEvents()
‘ Get the event GUID.
Dim typeGuid = GetType(SolidEdgeFramework.ISEApplicationEvents).GUID

‘ Get a reference to the IConnectionPointContainer.
Dim container As IConnectionPointContainer = DirectCast(_application, IConnectionPointContainer)

‘ Lookup the IConnectionPoint.
container.FindConnectionPoint(typeGuid, _connectionPoint)

‘ Advise the sink.
_connectionPoint.Advise(Me, _cookie)
End Sub

Private Sub DisconnectEvents()
‘ Unadvise the sink.
_connectionPoint.Unadvise(_cookie)

‘ Clear variables.
_cookie = 0
_connectionPoint = Nothing
End Sub

#Region “ISEApplicationEvents”

Public Sub AfterActiveDocumentChange(ByVal theDocument As Object)
End Sub

Public Sub AfterCommandRun(ByVal theCommandID As Integer)
End Sub

Public Sub AfterDocumentOpen(ByVal theDocument As Object)
End Sub

Public Sub AfterDocumentPrint(ByVal theDocument As Object, ByVal hDC As Integer, ByRef ModelToDC As Double, ByRef Rect As Integer)
End Sub

Public Sub AfterDocumentSave(ByVal theDocument As Object)
End Sub

Public Sub AfterEnvironmentActivate(ByVal theEnvironment As Object)
End Sub

Public Sub AfterNewDocumentOpen(ByVal theDocument As Object)
End Sub

Public Sub AfterNewWindow(ByVal theWindow As Object)
End Sub

Public Sub AfterWindowActivate(ByVal theWindow As Object)
End Sub

Public Sub BeforeCommandRun(ByVal theCommandID As Integer)
End Sub

Public Sub BeforeDocumentClose(ByVal theDocument As Object)
End Sub

Public Sub BeforeDocumentPrint(ByVal theDocument As Object, ByVal hDC As Integer, ByRef ModelToDC As Double, ByRef Rect As Integer)
End Sub

Public Sub BeforeDocumentSave(ByVal theDocument As Object)
End Sub

Public Sub BeforeEnvironmentDeactivate(ByVal theEnvironment As Object)
End Sub

Public Sub BeforeQuit()
End Sub

Public Sub BeforeWindowDeactivate(ByVal theWindow As Object)
End Sub

#End Region
End Class
End Namespace

C# – Connection Point Model Example

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;

namespace EventTest
{
public partial class Form1 : Form, SolidEdgeFramework.ISEApplicationEvents
{
private SolidEdgeFramework.Application _application;
private IConnectionPoint _connectionPoint;
private int _cookie;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
// Connect to Solid Edge.
_application = (SolidEdgeFramework.Application)Marshal.GetActiveObject(“SolidEdge.Application”);

ConnectEvents();
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
DisconnectEvents();
}

private void ConnectEvents()
{
// Get the event GUID.
var typeGuid = typeof(SolidEdgeFramework.ISEApplicationEvents).GUID;

// Get a reference to the IConnectionPointContainer.
IConnectionPointContainer container = (IConnectionPointContainer)_application;

// Lookup the IConnectionPoint.
container.FindConnectionPoint(ref typeGuid, out _connectionPoint);

// Advise the sink.
_connectionPoint.Advise(this, out _cookie);
}

private void DisconnectEvents()
{
// Unadvise the sink.
_connectionPoint.Unadvise(_cookie);

// Clear variables.
_cookie = 0;
_connectionPoint = null;
}

#region ISEApplicationEvents

public void AfterActiveDocumentChange(object theDocument)
{
}

public void AfterCommandRun(int theCommandID)
{
}

public void AfterDocumentOpen(object theDocument)
{
}

public void AfterDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
{
}

public void AfterDocumentSave(object theDocument)
{
}

public void AfterEnvironmentActivate(object theEnvironment)
{
}

public void AfterNewDocumentOpen(object theDocument)
{
}

public void AfterNewWindow(object theWindow)
{
}

public void AfterWindowActivate(object theWindow)
{
}

public void BeforeCommandRun(int theCommandID)
{
}

public void BeforeDocumentClose(object theDocument)
{
}

public void BeforeDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
{
}

public void BeforeDocumentSave(object theDocument)
{
}

public void BeforeEnvironmentDeactivate(object theEnvironment)
{
}

public void BeforeQuit()
{
}

public void BeforeWindowDeactivate(object theWindow)
{
}

#endregion
}
}

Connection Point Model – Option 2

You know I can’t talk about this kind of stuff without mentioning the SolidEdge.Community NuGet Package. It’s situations like this where the open source package shines. The NuGet package installs a class library with pre-built classes to handle scenarios like this. In this particular case, it provides a ConnectionPointController class that makes attaching to COM events very easy.

Visual Basic – Connection Point Model using SolidEdge.Community NuGet Package

Imports SolidEdgeCommunity
Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace EventTest
Partial Public Class Form1
Inherits Form
Implements SolidEdgeFramework.ISEApplicationEvents

Private _application As SolidEdgeFramework.Application
Private _connectionPointController As ConnectionPointController

Public Sub New()
InitializeComponent()
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
‘ Connect to Solid Edge.
_application = DirectCast(Marshal.GetActiveObject(“SolidEdge.Application”), SolidEdgeFramework.Application)

_connectionPointController = New ConnectionPointController(Me)
_connectionPointController.AdviseSink(Of SolidEdgeFramework.ISEApplicationEvents)(_application)
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
_connectionPointController.UnadviseAllSinks()
End Sub

#Region “ISEApplicationEvents”

#End Region
End Class
End Namespace

C# – Connection Point Model using SolidEdge.Community NuGet Package

using SolidEdgeCommunity;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EventTest
{
public partial class Form1 : Form, SolidEdgeFramework.ISEApplicationEvents
{
private SolidEdgeFramework.Application _application;
private ConnectionPointController _connectionPointController;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
// Connect to Solid Edge.
_application = (SolidEdgeFramework.Application)Marshal.GetActiveObject(“SolidEdge.Application”);

_connectionPointController = new ConnectionPointController(this);
_connectionPointController.AdviseSink<SolidEdgeFramework.ISEApplicationEvents>(_application);
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_connectionPointController.UnadviseAllSinks();
}

#region ISEApplicationEvents

#endregion
}
}

Conclusion

I was a programmer long before .NET was released and can remember how easy it was handling events from Visual Basic 6 so I can appreciate how some of you might feel after reading this article. To me, this all boils down to change. Yes it is different. Yes it is a bit more code. Yes you have to understand more than you did before .NET. The question is what are you going to do about it? You can either say this is too hard and give up or spend a little time understanding and learning the new techniques to stay relevant. As always, my goal is to be the hand that reaches out says “It’s ok, I’ll help you.”.

Topics

Leave a Reply