by Fenton Webb
If you are a seasoned RealDWG developer, you will have probably noticed that the .NET version of the RealDWG SDK’s HostApplicationServices object does not implement all of the virtual functions that are exposed by its unmanaged ObjectDBX counterpart, AcDbHostApplicationServices.
For the most part, this is a good idea because it simplifies your RealDWG application immensely.
The problem is that sometimes, just sometimes, you really need the full power of the SDK. If you do need that power from .NET then you are going to need to implement a Mixed Mode RealDWG app – one that implements both an underlying unmanaged AcDbHostApplicationServices derived class and a managed HostApplicationServices class that feeds off of it.
So in this example, I simply want to override AcDbHostApplicationServices::fatalError() with my own implementation. This is because the default implementation simply calls Exit( 0 ) which in my case is bad because I want to process many DWG files without failure. If I did not override this function, my RealDWG app would simply exit out and not finish.
Here’s the RealDWG .NET code I want to use… Ok, it’s not scanning lots of DWG files but you get the idea… Remember, I want an exception to be thrown when RealDWG encounters a corrupted DWG file rather than calling Exit( 0 )…
Imports Autodesk.AutoCAD.DatabaseServices Imports System.Windows.Forms ' by Fenton Webb, DevTech, Autodesk 30/04/2010 Public Class SimpleSampleDBXEngine Shared Sub Main() ' init the undelying CLI C++ HostApplication Using app As AdskDBXEngine = New AdskDBXEngine For i As Integer = 0 To 100 Try ' new the database making sure to dispose it once we are finished, using/end using Using db As New Database(False, True) ' read some drawing tile db.ReadDwgFile("d:wutempfatal.dwg", FileOpenMode.OpenForReadAndAllShare, False, Nothing) ' set the working database via our DbxExtender DevTech.DbxExtender.Utils.SetWorkingDatabase(db) End Using Catch ex As Exception MessageBox.Show(ex.Message) End Try Next End Using End Sub End Class I’m going to implement my own unmanaged AcDbHostApplicationServices, but I still need to create .NET HostApplicationServices class which my .NET code can use… it’s implemented but not Initialize()’d – basically it’s a dummy HostApplicationServices object… Imports Autodesk.AutoCAD Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.Geometry ' by Fenton Webb, DevTech, Autodesk 30/04/2010 'this host app should never be called. It will be replaced by DevTech.DbxExtender.Utils.Initialize() Public Class DummyHost Inherits HostApplicationServices Public Overrides Function FindFile(ByVal fileName As String, ByVal database As Autodesk.AutoCAD.DatabaseServices.Database, ByVal hint As Autodesk.AutoCAD.DatabaseServices.FindFileHint) As String FindFile = Nothing End Function End Class Public Class AdskDBXEngine Implements IDisposable Public Sub New() ' create a new database Try Dim host As New DummyHost RuntimeSystem.Initialize(host, 1033) GC.KeepAlive(host) DevTech.DbxExtender.Utils.Initialize() Catch ex As Exception Throw New Exception("Error creating new database") End Try End Sub Public Sub Dispose() Implements IDisposable.Dispose DevTech.DbxExtender.Utils.Terminate() End Sub End Class Now into an unmanaged C++ DBX module… Here’s my C++ implementation of my custom AcDbHostApplicationServices object… ////////////////////////////////////////////////////////////////////////// // by Fenton Webb, DevTech, Autodesk 30/04/2010 //----------------------------------------------------------------------------- //----- HostApplicationServices.cpp //----------------------------------------------------------------------------- #include "StdAfx.h" #include "HostApplicationServices.h" #include "Wininet.h" #include "Shlwapi.h" ////////////////////////////////////////////////////////////////////////// #pragma unmanaged ////////////////////////////////////////////////////////////////////////////// HostApplication::HostApplication() { } ////////////////////////////////////////////////////////////////////////////// HostApplication::~HostApplication() { CString local,url; for (POSITION pos = m_localToUrl.GetStartPosition();pos!=NULL;) { m_localToUrl.GetNextAssoc(pos,local,url); DeleteUrlCacheEntry(url); } } ////////////////////////////////////////////////////////////////////////////// // Return the Install directory for customizable files Acad::ErrorStatus HostApplication::getRoamableRootFolder(const ACHAR*& folder) { Acad::ErrorStatus ret = Acad::eOk; static ACHAR buf[MAX_PATH] = _T("