.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Catastrophic failure HRESULT: 0x8000FFFF (E_UNEXPECTED)

30 REPLIES 30
SOLVED
Reply
Message 1 of 31
sszabo
8964 Views, 30 Replies

Catastrophic failure HRESULT: 0x8000FFFF (E_UNEXPECTED)

I am trying to run acad code from a WCF service in process.  I get most everything work just fine but for some reason I get this cryptic error when I try to loop through a selection set of AcadEntity objects.  The weird part is that if I place the same loop in a simple IExtensionApplication command it works fine.

 

Does anyone have any suggestions how to make this work?  I assume something to do with wcf service behavior/acad threading model but not sure what.

 

Here is the full source code, note that I am not using Editor.WriteMessage because that's one of the things I cannot get working from WCF so I am relying on NLog to generate the output on the bottom of this message. If you have an idea how to make Editor.WriteMessage work from WCF I'd appreciate your help as well.

 

Thanks in advance,

Steve 

 

Imports System.ServiceModel

Imports System.ServiceModel.Description

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.Interop

Imports Autodesk.AutoCAD.Interop.Common

Imports Autodesk.AutoCAD.ApplicationServices

Imports MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application

Imports NLog

 

#Region "WCF SERVICE"

<ServiceContract()>

Public Interface ISelectItems

    <OperationContract()>

    Sub SelectItems()

End Interface

 

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single, ConcurrencyMode:=ConcurrencyMode.Single)>

Public Class wcfSelectItems

    Implements ISelectItems

    Private log As Logger = LogManager.GetCurrentClassLogger

    Public Sub SelectItems() Implements ISelectItems.SelectItems

        log.Info("This will crash")

        DoSelection()

    End Sub

    Public activeDoc As Document = MgdAcApplication.DocumentManager.MdiActiveDocument

    Public Sub DoSelection()

        Try

            Using acDocLck As DocumentLock = activeDoc.LockDocument()

                Dim td As AcadDocument = DocumentExtension.GetAcadDocument(activeDoc)

                Dim ssetObj As AcadSelectionSet = td.SelectionSets.Add("SSALL0")   ' creates named selection set

                ssetObj.Select(AcSelect.acSelectionSetAll)

                log.Trace("We have a selection of size = {0}", ssetObj.Count)

                Try

                    For Each ent As AcadEntity In ssetObj

                        log.Trace("{0}", ent.ObjectName)

                    Next

                Catch

                    log.Error("This is the crash: '{0}'", Err.Description)

                End Try

            End Using

        Catch

            log.Error(Err.Description)

        End Try

    End Sub

 

End Class

#End Region

 

 

Public Class clsSelectedItems

    Implements IExtensionApplication

    Private log As Logger = LogManager.GetCurrentClassLogger

 

#Region "ACAD COMMAND"

    <CommandMethod("DoSelection")> _

    Public Sub DoSelection_Method()

        log.Info("This is OK")

        DoSelection()

    End Sub

#End Region

 

    Public m_DefaultService As String = "ISelectItems"

    Public m_DefaultIP As String = "127.0.0.1"

    Public m_DefaultPort As String = "7200"

    Public m_DefaultProtocol As String = "http"

    Private m_serviceHost As ServiceHost = Nothing

 

    Public Sub Initialize() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Initialize

        hostService(m_DefaultIP, m_DefaultPort)

    End Sub

 

    Public Sub Terminate() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Terminate

        If Not m_serviceHost Is Nothing Then

            m_serviceHost.Close()

        End If

    End Sub

    Public activeDoc As Document = MgdAcApplication.DocumentManager.MdiActiveDocument

 

    'Do selection routine, exact same as above.  This one works:

    Public Sub DoSelection()

        Try

            Using acDocLck As DocumentLock = activeDoc.LockDocument()

                Dim td As AcadDocument = DocumentExtension.GetAcadDocument(activeDoc)

                Dim ssetObj As AcadSelectionSet = td.SelectionSets.Add("SSALL1")   ' creates named selection set

                ssetObj.Select(AcSelect.acSelectionSetAll)

                log.Trace("We have a selection of size = {0}", ssetObj.Count)

                Try

                    For Each ent As AcadEntity In ssetObj

                        log.Trace("{0}", ent.ObjectName)

                    Next

                Catch

                    log.Error("This is the crash: '{0}'", Err.Description)

                End Try

            End Using

        Catch

            log.Error(Err.Description)

        End Try

    End Sub

 

    ' Set up a WCF service endpoint and start service

    Public Sub hostService(ByVal _hostIP As String, ByVal _port As String)

        Dim wcfEndpoint As String = String.Format("{0}://{1}:{2}/{3}", m_DefaultProtocol, _hostIP, _port, m_DefaultService)

        Try

            Dim baseAddress As Uri = New Uri(wcfEndpoint)

            m_serviceHost = New ServiceHost(GetType(wcfSelectItems), baseAddress)

            Dim binding = CreateNewHttpBinding(GetType(wcfSelectItems).FullName)

            m_serviceHost.AddServiceEndpoint(GetType(ISelectItems), binding, "IAcadInProc")

            Dim smb As New ServiceMetadataBehavior()

            smb.HttpGetEnabled = True

            m_serviceHost.Description.Behaviors.Add(smb)

        Catch ex As Exception

            log.Error("EX 2. {0}", ex.ToString)

        End Try

        m_serviceHost.Open()

        log.Info("Listening on {0}", wcfEndpoint)

    End Sub

 

    'We avoid using config files for now:

    Private Shared Function CreateNewHttpBinding(ByVal name As String) As WSHttpBinding

        Dim result As New WSHttpBinding

        result.Name = name

        result.OpenTimeout = New TimeSpan(0, 1, 0)

        result.ReceiveTimeout = New TimeSpan(0, 10, 0)

        result.SendTimeout = New TimeSpan(0, 1, 0)

        result.BypassProxyOnLocal = False

        result.TransactionFlow = False

        result.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard

        result.MaxBufferPoolSize = 2147483647

        result.MaxReceivedMessageSize = 2147483647

        result.MessageEncoding = WSMessageEncoding.Text

        result.TextEncoding = System.Text.Encoding.UTF8

        result.UseDefaultWebProxy = True

        result.AllowCookies = False

        result.ReaderQuotas.MaxStringContentLength = 2147483647

        result.ReaderQuotas.MaxDepth = 12

        result.ReaderQuotas.MaxArrayLength = 16384

        result.ReaderQuotas.MaxBytesPerRead = 4096

        result.ReaderQuotas.MaxNameTableCharCount = 16384

        result.ReliableSession.Ordered = False

        result.ReliableSession.InactivityTimeout = New TimeSpan(0, 10, 0)

        result.ReliableSession.Enabled = False

        result.Security.Mode = SecurityMode.None

        result.Security.Transport.ClientCredentialType = HttpClientCredentialType.None

        result.Security.Message.ClientCredentialType = MessageCredentialType.None

        Return (result)

    End Function

End Class

 

 

OUTPUT:

 

Info    clsSelectedItems     Listening on http://127.0.0.1:7200/ISelectItems
Info    wcfSelectItems       This will crash
Trace    wcfSelectItems     We have a selection of size = 200
Error    wcfSelectItems       This is the crash: 'Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))'
Info    clsSelectedItems       This is OK
Trace    clsSelectedItems       We have a selection of size = 200
Trace    clsSelectedItems       AcDbText
Trace    clsSelectedItems       AcDbViewport
Trace    clsSelectedItems       AcDbViewport
% <--------------ETC. CUT------------->%

 

30 REPLIES 30
Message 2 of 31
drauckman
in reply to: sszabo

How do you get the first example that does not work to run?  It looks like you might be trying to use a mix of ObjectARX .NET and COM and run out of process.

 

If you are not netloading the assembly in-process then the ObjectARX .NET will not work.

 

Change the first example to only use COM, or do as you did in the second and get your service running through the initialize method to allow you to use the .NET API.

Message 3 of 31
sszabo
in reply to: drauckman

If you copy and paste the code into a new VB Class Project and add the following references it should work as advertised, that's how I got the output. 

 

AcCoreMgd

AcDBMgd

AcMgd

Autodesk.AutoCAD.Interop

Autodesk.AutoCAD.Interop.Common

NLog

System.Runtime.Serialization

System.ServiceModel

 

When you say "it doesn't work" please let me know where are you getting stuck?

 

After compiled this DLL should be netloaded and it should host the WCF service automatically on http://127.0.0.1:7200/ISelectItems endpoint as the logs indicate.

 

That's my problem, as a newbie I am not very good with the .NET API and there are things I simply couldn't make work with it.  For instance AcadSelectionSet.  If you have some code example showing what you mean I'd appreciate your effort. 

 

My idea of a quick and dirty solution to this problem for now is to just create ACAD commands for what doesn't work directly and send these commands in the service requests instead of trying to make ACAD play nice with WCF because I can still call ActiveDocument.SendCommand() from WCF.

 

Message 4 of 31
drauckman
in reply to: drauckman

How do you load and get this part of the code to run on its own:

 

Imports System.ServiceModel

Imports System.ServiceModel.Description

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.Interop

Imports Autodesk.AutoCAD.Interop.Common

Imports Autodesk.AutoCAD.ApplicationServices

Imports MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application

Imports NLog

 

#Region "WCF SERVICE"

<ServiceContract()>

Public Interface ISelectItems

    <OperationContract()>

    Sub SelectItems()

End Interface

 

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single, ConcurrencyMode:=ConcurrencyMode.Single)>

Public Class wcfSelectItems

    Implements ISelectItems

    Private log As Logger = LogManager.GetCurrentClassLogger

    Public Sub SelectItems() Implements ISelectItems.SelectItems

        log.Info("This will crash")

        DoSelection()

    End Sub

    Public activeDoc As Document = MgdAcApplication.DocumentManager.MdiActiveDocument

    Public Sub DoSelection()

        Try

            Using acDocLck As DocumentLock = activeDoc.LockDocument()

                Dim td As AcadDocument = DocumentExtension.GetAcadDocument(activeDoc)

                Dim ssetObj As AcadSelectionSet = td.SelectionSets.Add("SSALL0")   ' creates named selection set

                ssetObj.Select(AcSelect.acSelectionSetAll)

                log.Trace("We have a selection of size = {0}", ssetObj.Count)

                Try

                    For Each ent As AcadEntity In ssetObj

                        log.Trace("{0}", ent.ObjectName)

                    Next

                Catch

                    log.Error("This is the crash: '{0}'", Err.Description)

                End Try

            End Using

        Catch

            log.Error(Err.Description)

        End Try

    End Sub

 

End Class

#End Region

 

Message 5 of 31
sszabo
in reply to: drauckman

This is just the WCF interface. You have to host it in the clsSelectedItems class by calling the hostService() Sub  and if you do that from Initialize() that will happen automatically when you netload the DLL.  Again, I put all these classes in 1 file intentionally so that people can simply copy/paste into a new class project and should be ready to go.   If that doesn't work for you please tell me what's the error you are getting.

 

Just a followup on my previous idea: sending the command from the WCF class still gives me this error which is unbelievable because it's executing directly in my IExtensionApplication class and if I invoke the VERY SAME function from the acad command directly it works fine.  This is the strangest thing I've ever seen.

Message 6 of 31
sszabo
in reply to: sszabo

Here is what I am talking about:

 

If you add the following helper function to wcfSelectItems, you should be able to invoke any ACAD command from WCF remotely:

 

    Private ReadOnly Property Acad() As AcadApplication

        Get

            Return DirectCast(Application.AcadApplication, AcadApplication)

        End Get

    End Property

 

    Public Sub SendCommand(ByVal cmd As String)

        Using acDocLck As DocumentLock = activeDoc.LockDocument()

            Try

                Dim cmdStr As String = "(command " + Chr(34) + cmd + Chr(34) + " " + ")" + vbCr

                Acad.ActiveDocument.SendCommand(cmdStr)

            Catch

                log.Error("EX 5. {0}", Err.Description)

            End Try

        End Using

    End Sub

 

And this works with any standard commands such as "RIBBONCLOSE" or "NETLOAD" etc.  However when I call it for the DoSelection command above it gives me the SAME EXACT E_UNEXPECTED error on the SAME EXACT LINE!  Any ideas?!

 

ps.  To Invoke this from the wcf interface you'll have to also add the following to ISelectItems:

 

    <OperationContract()>

    Sub AcadCmdSelectItems()

 

and the following to wcfSelectItems:

 

    Public Sub AcadCmdSelectItems() Implements ISelectItems.AcadCmdSelectItems

        SendCommand("DoSelection")

    End Sub

 

Message 7 of 31
sszabo
in reply to: drauckman

It just occured to me that this post doesn't contain some basic info on how to test a WCF server out of the box.  After compiling the code above you netload the DLL and then ACAD should be hosting and listening for WCF clients.  To actually invoke DOSELECTION from WCF you can use WCF Test Client that comes with .NET:

 

http://msdn.microsoft.com/en-us/library/bb552364.aspx

 

Message 8 of 31
drauckman
in reply to: sszabo

I have not been able to get this code running to reproduce your error.

 

When I navigate to the page I get the service info.

 

The logger does not log.

 

When I try to use WcfTestClient.exe I get exception Object Reference not set to an instance of an object for any URL that I enter.

Message 9 of 31
sszabo
in reply to: drauckman

Ok, I see. I appreciate your effort, if you still have some patience try these tips:

 

A.The logger does not log.

 

This is important because this is how you know that your service is hosted correctly in ACAD and what's the exact endpoint it's listening on.  Try the following steps:

 

1) Install the latest NLog from here: http://nlog-project.org/download

2) Add a New Item to your VB Class Project and select NLog Configuration File.  This will create an NLog.config file with default target going to "${basedir}/log.txt" where ${basedir} is your ACAD directory (For me that's C:\Program Files\Autodesk\AutoCAD 2013).  Copy this config file in your autocad directory. (Alternatively you can specify to Copy Always to your project output directory and set that to ACAD path).  You also have to copy C:\Program Files (x86)\NLog\.NET Framework 4.0\NLog.dll in your ACAD directory (provided you are using NLog 4.0 in your project)

 

Optionally you can also view your logs in real time as opposed to opening log.text all the time:

http://log2console.codeplex.com/

 

B) When I try to use WcfTestClient.exe I get exception Object Reference not set to an instance of an object for any URL that I enter.

 

You can open log.txt in your ACAD directory and copy the exact URL from the first line:

 

2013-01-29 13:50:36.7247|INFO|clsWcfTestPrj.clsSelectedItems|Listening on http://127.0.0.1:7200/ISelectItems

 

In WCF test client click File -> Add Service and paste in the blue URL above.  When connected you should be able to see the SelectItems request and you should be able to push the Invoke button.  In the logs you will see the error code.  Then you can go to ACAD command line and type in DOSELECTION and see all the selection objects listed provided you had a drawing open with objects in it.

 

Hope this will work, let me know if you need any more help.

 

 

Message 10 of 31
drauckman
in reply to: sszabo

WcfTestClient.exe will not work on my setup.  It always crashes and never loads up the service.  I got WCFStorm and got the logger going (config file needed to be in autoCAD directory for it to start writing files).

 

I now have the same error you were getting and it is getting logged. 

Message 11 of 31
sszabo
in reply to: drauckman

When you say "crashes" what do you mean?!  It goes away or just throws some exception.  If the latter what does it say?!  Also, you should be using the one that comes with VS

 

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe

 

If that's crashing you have an Visual Studio installation issue.

 

Also make sure the cmd window you are using to launch WcfTestClient.exe knows about the correct .NET path.  Mine is

 

C:\Windows\Microsoft.NET\Framework64\v4.0.30319

Message 12 of 31
drauckman
in reply to: drauckman

I get the Exception: Object reference not set to an instance of an object

 

************** Exception Text **************
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Tools.Common.SdkPathUtility.GetRegistryValue(String registryPath, String registryValueName)
   at Microsoft.Tools.Common.SdkPathUtility.GetSdkPath(Version targetFrameworkVersion)
   at Microsoft.Tools.TestClient.ToolingEnvironment.get_MetadataTool()

 

etc.....

 

 

Message 13 of 31
sszabo
in reply to: drauckman

Ok, I don't know.  But good thing you can at least see it with WCFStorm.  The weird stuff is when you add that SendCommand I posted above.  That invokes the DOSELECTION command that works when invoked from the command line and still results in the same exact error on the same line of code when called through wcf SendCommand...

Message 14 of 31
drauckman
in reply to: sszabo

This works for me:

 

 Public Sub DoSelection()
        Try
            activeDoc = MgdAcApplication.DocumentManager.MdiActiveDocument
            Using acDocLck As DocumentLock = activeDoc.LockDocument()
                Dim td As AcadDocument = DocumentExtension.GetAcadDocument(activeDoc)
                Dim ssetObj As AcadSelectionSet = td.SelectionSets.Add("SSALL0")   ' creates named selection set
                ssetObj.Select(AcSelect.acSelectionSetAll)
                log.Trace("We have a selection of size = {0}", ssetObj.Count)
                activeDoc.Editor.WriteMessage("We have a selection of size = {0}", ssetObj.Count)
                Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("We have a selection of size = " & ssetObj.Count.ToString())
                Try
                    For Each ent As AcadEntity In ssetObj
                        log.Trace("{0}", ent.ObjectName)
                    Next
                Catch
                    log.Error("This is the crash: '{0}'", Err.Description)
                End Try
            End Using
        Catch
            log.Error(Err.Description)
        End Try

    End Sub

 

At the beginning right after try I added this line:

 

activeDoc = MgdAcApplication.DocumentManager.MdiActiveDocument

When you step through the code it looks like active document is alright, but this class gets instantiated by the WCF system and when this property is initialized something is not connecting properly. 

 

To ensure this is working on the current active document maybe this should be a method instead of a property so it always checks and returns the active document?

 

Results:

 

2013-01-29 14:22:03.3589 INFO Listening on http://127.0.0.1:7200/ISelectItems
2013-01-29 14:22:18.6964 INFO This will crash
2013-01-29 14:22:18.7094 TRACE We have a selection of size = 13
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine
2013-01-29 14:22:21.1977 TRACE AcDbLine

 

I think the difference is because the Initialize plugin method is run by AutoCAD so when the current document is set it is correct.  The WCF deals with the wcfSelectItems class and when this class is created it is not in the same context as when AutoCAD loads the plugin class.

Message 15 of 31
sszabo
in reply to: drauckman

I tried this solution but I think you are right somehow I have to force autocad to activate the current document.  If I make the change you are suggesting I get a Object reference not set to an instance of an object.  I also tried to make it a function that returns the document: same result.

 

    Private Function activeDoc() As Document
        Return MgdAcApplication.DocumentManager.MdiActiveDocument
    End Function

Message 16 of 31
drauckman
in reply to: sszabo

Which line does the exception get thrown on?

Message 17 of 31
sszabo
in reply to: drauckman

    Public Sub DoSelection()
        Try
            Dim activeDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Using acDocLck As DocumentLock = activeDoc.LockDocument()

Message 18 of 31
drauckman
in reply to: sszabo

Is there any difference if you leave your property how you originally had it and change the line line after try to:

activeDoc = MgdAcApplication.DocumentManager.MdiActiveDocument

 

My code works if I take your original sample and just add this one line,  I still have the property in my code exactly how you had yours in the first post, I just update the activeDoc at the start of the method just after try

Message 19 of 31
sszabo
in reply to: drauckman

Yes, I tried that too.  Do you have ACAD 2013?

Message 20 of 31
drauckman
in reply to: sszabo

I have AutoCAD Electrical 2013, but should work the same for this example.  I am attaching my project that works.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost