Programmer's Guide > Solid Edge > Handling 'Application is Busy' and 'Call was Rejected By Callee' errors |
If you automate Solid Edge from an external (out-of-proc) application, you may receive one of the following errors:
These errors occur due to threading contention issues between automation clients and Solid Edge. They can be handled by implementing the OleMessageFilter error handlers in your automation application. Once you have the code in place, simply call OleMessageFilter.Register() before you make any calls to COM clients and OleMessageFilter.Revoke() at the end of your program.
In order for OleMessageFilter to work, you must ensure that Thread.GetApartmentState method returns STA. In Windows Forms applications, this is the default. In Console applications, it is not the default. You will need to specify the STAThreadAttribute on your Main() function. |
In Console applications, you must decorate your Sub Main() function with STAThreadAttribute.
VB.NET example usage |
Copy Code
|
---|---|
<STAThread()> _ Sub Main() OleMessageFilter.Register() ' Make COM calls. OleMessageFilter.Revoke() End Sub |
In your Visual Basic .NET project, create a new class and name it OleMessageFilter.vb. Copy this example code and paste it into the new class.
VB.NET implementation of OleMessageFilter |
Copy Code
|
---|---|
Imports System.Runtime.InteropServices Imports System.Threading Public Class OleMessageFilter Implements IOleMessageFilter Public Shared Sub Register() Dim newFilter As IOleMessageFilter = New OleMessageFilter() Dim oldFilter As IOleMessageFilter = Nothing Dim iRetVal As Integer If (Thread.CurrentThread.GetApartmentState() = ApartmentState.STA) Then iRetVal = CoRegisterMessageFilter(newFilter, oldFilter) Else Throw New COMException("Unable to register message filter because the current thread apartment state is not STA.") End If End Sub Public Shared Sub Revoke() Dim oldFilter As IOleMessageFilter = Nothing CoRegisterMessageFilter(Nothing, oldFilter) End Sub Private Function HandleInComingCall(ByVal dwCallType As Integer, _ ByVal hTaskCaller As System.IntPtr, _ ByVal dwTickCount As Integer, _ ByVal lpInterfaceInfo As System.IntPtr) _ As Integer Implements IOleMessageFilter.HandleInComingCall Return SERVERCALL.SERVERCALL_ISHANDLED End Function Private Function RetryRejectedCall(ByVal hTaskCallee As System.IntPtr, _ ByVal dwTickCount As Integer, _ ByVal dwRejectType As Integer) _ As Integer Implements IOleMessageFilter.RetryRejectedCall If dwRejectType = SERVERCALL.SERVERCALL_RETRYLATER Then Return 99 End If Return -1 End Function Private Function MessagePending(ByVal hTaskCallee As System.IntPtr, _ ByVal dwTickCount As Integer, _ ByVal dwPendingType As Integer) _ As Integer Implements IOleMessageFilter.MessagePending Return PENDINGMSG.PENDINGMSG_WAITDEFPROCESS End Function <DllImport("Ole32.dll")> _ Private Shared Function CoRegisterMessageFilter(ByVal newFilter As IOleMessageFilter, _ ByRef oldFilter As IOleMessageFilter) _ As Integer End Function End Class Enum SERVERCALL SERVERCALL_ISHANDLED = 0 SERVERCALL_REJECTED = 1 SERVERCALL_RETRYLATER = 2 End Enum Enum PENDINGMSG PENDINGMSG_CANCELCALL = 0 PENDINGMSG_WAITNOPROCESS = 1 PENDINGMSG_WAITDEFPROCESS = 2 End Enum <ComImport(), _ Guid("00000016-0000-0000-C000-000000000046"), _ InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _ Interface IOleMessageFilter <PreserveSig()> _ Function HandleInComingCall(ByVal dwCallType As Integer, _ ByVal hTaskCaller As IntPtr, _ ByVal dwTickCount As Integer, _ ByVal lpInterfaceInfo As IntPtr) _ As Integer <PreserveSig()> _ Function RetryRejectedCall(ByVal hTaskCallee As IntPtr, _ ByVal dwTickCount As Integer, _ ByVal dwRejectType As Integer) _ As Integer <PreserveSig()> _ Function MessagePending(ByVal hTaskCallee As IntPtr, _ ByVal dwTickCount As Integer, _ ByVal dwPendingType As Integer) _ As Integer End Interface |
In Console applications, you must decorate your Main() function with STAThreadAttribute.
C# example usage |
Copy Code
|
---|---|
[STAThread] static void Main(string[] args) { OleMessageFilter.Register(); // Make COM calls. OleMessageFilter.Revoke(); } |
In your Visual C# project, create a new class and name it OleMessageFilter.cs. Copy this example code and paste it into the new class. You will want to modify the namespace of the example code to match your own namespace.
C# implementation of OleMessageFilter |
Copy Code
|
---|---|
using System; using System.Runtime.InteropServices; using System.Threading; namespace SolidEdge.SDK { class OleMessageFilter : IOleMessageFilter { public static void Register() { IOleMessageFilter newFilter = new OleMessageFilter(); IOleMessageFilter oldFilter = null; if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { CoRegisterMessageFilter(newFilter, out oldFilter); } else { throw new COMException("Unable to register message filter because the current thread apartment state is not STA."); } } public static void Revoke() { IOleMessageFilter oldFilter = null; CoRegisterMessageFilter(null, out oldFilter); } int IOleMessageFilter.HandleInComingCall( int dwCallType, System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr lpInterfaceInfo) { return (int)SERVERCALL.SERVERCALL_ISHANDLED; } int IOleMessageFilter.RetryRejectedCall( System.IntPtr hTaskCallee, int dwTickCount, int dwRejectType) { if (dwRejectType == (int)SERVERCALL.SERVERCALL_RETRYLATER) { return 99; } return -1; } int IOleMessageFilter.MessagePending( System.IntPtr hTaskCallee, int dwTickCount, int dwPendingType) { return (int)PENDINGMSG.PENDINGMSG_WAITDEFPROCESS; } [DllImport("Ole32.dll")] private static extern int CoRegisterMessageFilter( IOleMessageFilter newFilter, out IOleMessageFilter oldFilter); } enum SERVERCALL { SERVERCALL_ISHANDLED = 0, SERVERCALL_REJECTED = 1, SERVERCALL_RETRYLATER = 2 } enum PENDINGMSG { PENDINGMSG_CANCELCALL = 0, PENDINGMSG_WAITNOPROCESS = 1, PENDINGMSG_WAITDEFPROCESS = 2 } [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] interface IOleMessageFilter { [PreserveSig] int HandleInComingCall( int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo); [PreserveSig] int RetryRejectedCall( IntPtr hTaskCallee, int dwTickCount, int dwRejectType); [PreserveSig] int MessagePending( IntPtr hTaskCallee, int dwTickCount, int dwPendingType); } } |