vbdotnet express 2008 acad 2009 netloaded dll using acad com
am i the only one who experiences this?
if i create a dll that errors out (trapped with try/catch)
when i close acad to edit and rebuild dll acad process hangs in task mgr
acad variable gotten with
Private Function GetAutoCADInstance() As AcadApplication
Try
m_AcadApp = DirectCast(Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication, AcadApplication)
Catch ex As Exception
Me.Logentry("Failed to get acad application " + ex.Message)
m_AcadApp = Nothing
End Try
Return m_AcadApp
End Function
is there something i should do to allow acad to close properly after program run(even if it errors)
acad will close after prog run if no errors occur(and i'm pretty sure i'm trapping them all with try but i must not be releasing the acad object somehow)
i'm trying to close acad in Dispose() by making the clasees implement iDisposable
shouldn't that be running at the end of the app whether it errors or not?
thanks
mark
Again, you're not reading my posts or you're just ignoring them.
You don't need any Dispose() and you don't need to release
any AutoCAD COM objects from a NETLOADed DLL.
The problem of AutoCAD not shutting down has nothing to
do with any of that.
I am reading your posts and not ignoring them! 🙂
I'm just stuck in the concept that the reason acad isn't closing is because i have a reference to it hung in the background
so yes, due to my stupidity and stubbornness I can see why it would seem i'm ignoring it.
so if i get rid of dispose and get rid of setting acad = nothing that will fix my problem?
thanks
mark
No, getting rid of Dispose and not bothering to release COM objects
will not solve the problem of AutoCAD not shutting down. I can't tell
you why that's happening without seeing your code, and what it
does, or doesn't do when an exception occurs.
Usually, when I'm debugging AutoCAD, I don't bother closing it,
I just hit the Stop Debugging button in Visual Studio, which kills
the debug process (acad.exe) dead in its tracks, and that's that.
If you choose to do that, make sure that you routinely clear out
your temp folder, because when you terminate AutoCAD from
Visual Studio, it leaves all open temporary files (e.g., *.ac$ and
so on) in the temp folder, and when the number of objects in
that folder becomes large, it impacts performance.
well you probably wouldn't have time to look through the code, though i'd be thrilled to send it if you did. I don't know how to post up a whole project.
almost all my catch expressions follow this pattern:
catch ex as exception
m_util.logentry ("Error ", ex.Message) '<---writes to log file
return False (or Return Nothing) ..if it's a function
End try
i'm not sure what i should be doing in those actually. i'm just notifying myself where the errors are(via log file)
i haven't been debugging throughthe ide for some reason(not sure why) I tend to rebuild the dll, start acad, netload, then run as enduser would be doing. maybe i'll try the debug in ide way again.
this is interesting.
if i debug from the ide, it opens acad, i open my testdwg, netload the new dll, call the commands and get Unknown command.
If i open acad, netload the dll, call the commands, they are there.
is that normal?
I'm guessing not
🙂
mark
Make sure that 'CopyLocal' is set to false for all AutoCAD assembliy references.
Code that is designed that way is fatally flawed because it traps errors
and allows the program to continue to run.
When an unexpected error occurs, the program should stop, it should
not continue running, whether you log the error or not.
My guess is that AutoCAD isn't shutting down because of something
related to your error logging.
Tony, thanks for hangin in with me on this...
hope this isn't too long...i don't know the length protocol on this web forum.
so how do i make the program stop after i log the error?
i thought try/catch was a recommended method.
basic program form
i have 3 classes in this app
one defines the acad commands
the acad command calls the "main" class
the main class creates the "utility" class
the "utility" class creates the reference to acad and provides it to "main" via .Acad and .AcadDoc properties
the "utility" class also logs all activity so i can see where things go south.
which they obviously do a lot of around here. 🙂
the logging sub in mcsutil.vb
Sub Logentry(ByVal strMsg As String, Optional ByVal BracketInfo As String = "", Optional ByVal bAddTimeStamp As Boolean = False)
If m_Debug Then
If Not m_acadDoc Is Nothing Then
If userIsDeveloper() Then
m_acadDoc.Utility.Prompt(vbCrLf & strMsg)
If Len(BracketInfo) > 0 Then
m_acadDoc.Utility.Prompt("<" & BracketInfo & ">")
End If
End If
End If
Debug.Print(vbCrLf & strMsg)
Try
Dim sw As StreamWriter = New StreamWriter(m_DebugFileName, True)
If bAddTimeStamp Then
sw.WriteLine(Now)
End If
sw.WriteLine(strMsg)
If Len(BracketInfo) > 0 Then
sw.WriteLine("<" & BracketInfo & ">")
End If
sw.Close()
Catch ex As Exception
If userIsDeveloper() Then
MsgBox(ex.Message)
End If
End Try
End If
End Sub
the userIsDeveloper() function just keeps debug dialogs from popping up on users machines while i'm in the process of tweaking an app in progress
an example of the command.vb file
Imports Autodesk.AutoCAD
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.Interop
Imports Autodesk.AutoCAD.Interop.Common
Imports System.IO
Public Class AcadCommands
Private inst As New MCSdxf
<CommandMethod("Cnc", CommandFlags.Session)> _
Public Sub CncPartList()
If inst Is Nothing Then inst = New MCSdxf
inst.Init()
inst.CNC_FormPartList()
inst = Nothing
End Sub
the mcsdxf.init function
Function Init() As Boolean
m_Util = New MCSUtil(True)
m_Util.Init2(True)
If m_acad Is Nothing Then
m_acad = m_Util.ACAD
End If
If m_acad Is Nothing Then
MsgBox("Can not get AutoCAD instance.", MsgBoxStyle.Exclamation, "")
Exit Function
End If
m_acadDoc = m_acad.ActiveDocument
If m_acadDoc Is Nothing Then
MsgBox("No active document.", MsgBoxStyle.Information, "")
Exit Function
End If
Init = True
End Function
the mcsutil.init2 function
Function Init2(ByVal bDebug As Boolean) As Boolean
m_Debug = bDebug
Try
m_AcadApp = DirectCast(Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication, AcadApplication)
m_acadDoc = m_AcadApp.ActiveDocument
Return True
Catch ex As Exception
Return False
End Try
End Function
any advice?
my plan was for the init functions to return bool
then each level would check
If m_Util.Init2(True) then
...
else
Return False
End if
so that way any failure would percolate up to the top level to end the program.
i'm not currently doing that as i havent' had any failures yet at that level(of init)
but most of the internal calls check the return values of functions and if they failed i don't continue with normal operation, but again try to percolate up the error state up the stack of calls to the main level.
most of my problems have been getting all the casting right after i decided to go with option strict on
lots of acad functions will not retun a value even if there's no error if i don't get all my casting back and forth from object to arrays or specific acadobjects etc(depending on the acad method i'm calling)
thanks for all your time and guidance.
mark
You can re-raise the exception after logging it using 'throw':
try { SomethingDangerous(); } catch{ System.Exception ex ) { LogError( ex ); throw; // <- re-raises the exception }
tony,
another question if i may.
i confirmed copy local is false, btw i'm reffing the objectarx sdk versions of the acad dlls if that makes any diff.
one thing i was wondering, looking at the vbproj file in notepad, is why i ended up with two <NoWarn> sections
i don't know if that's normal or because i started with someone elses' app as a skeleton and did massive changes to convert to what i wanted to do. (the only thing left from the orig is the format of the command defs)
i'm posting this in case you can see something in the call to startaction / startprogram lines that i may have not gotten right.
when i try the debug from the ide, and then manually netload the dll after acad starts(via lisp call), the commands are not defined in that acad session. If i start acad and netload the dll in the same way, the commands are defined.
here's part of the vbproj file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4C427581-4C44-4F77-95F1-5A2D8B1E8D7B}</ProjectGuid>
<OutputType>Library</OutputType>
<StartupObject>
</StartupObject>
<RootNamespace>MCS_DXF</RootNamespace>
<AssemblyName>MCS_DXF</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<OptionExplicit>On</OptionExplicit>
<OptionCompare>Binary</OptionCompare>
<OptionStrict>Off</OptionStrict>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<StartAction>Program</StartAction>
<StartProgram>C:\Program Files\AutoCAD 2009\acad.exe</StartProgram>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>MCS_DXF.xml</DocumentationFile>
<NoWarn>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</NoWarn>
<RegisterForComInterop>false</RegisterForComInterop>
<PlatformTarget>AnyCPU</PlatformTarget>
<WarningsAsErrors>
</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>MCS_DXF.xml</DocumentationFile>
<NoWarn>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</NoWarn>
<RegisterForComInterop>false</RegisterForComInterop>
<WarningsAsErrors>
</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="AcDbMgd, Version=18.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ObjectARX 2010\inc-win32\AcDbMgd.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="AcMgd, Version=18.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ObjectARX 2010\inc-win32\AcMgd.dll</HintPath>
<Private>False</Private>
The <NoWarn> sections are the supressed warnings.
There are two because there are two configurations for debug and release builds.
thanks for that info.
so does it look correct for debugging in acad?
i don't know why when i debug run from the vbexpress ide acad opens, i net load the dll, but the commands aren't available
if i start acad and netload the dll the commands are avilable.
what am i doing wrong?
Usually, commands not available while debugging is because
the referenced AutoCAD assemblies do not have the CopyLocal
set to false.
so given in this case they are set to false, what else could it be?
i wonder if it's related to my logging, as you mentioned that may be what's keeping acad alive after trying to close acad following an error in the dll app.
the only thing i'm doing in the logging that touches acad is writing to the command line
maybe 'll drop that and see if it helps.
any other ideas?
No, but disabling the logging function so it does nothing should
be simple enough to do, and answer your question.