Hi All
I'm trying to use Fenton Webb's BlockView.Net control in my addin(in fact I use two of them).
It works fine but there are some issues (i.e. the addin crashes Autocad if I start the command/dialog, close it and start it again).
So, if anybody has any experience with this control, I have a couple of questions:
1. Did anybody encounter the problem mentioned above, its reason and maybe a solution?
2. There is the issue of the control crashing Visual Studio when trying to open the form in designer (see Kean Walmsley's blog http://through-the-interface.typepad.com/through_the_interface/2008/06/autocad-net-ver.html ).
In the same blog, Toby Tanzillo proposed a solution based on System.Process.GetCurrentProcess, but one cannot add or modify code in the designer. Has anyone succeeded using that?
3. For each file to view, the control creates a new Database which remains there for the life of the Autocad session, eating up memory etc.
Can these Databases be deleted when the command exits? Could one use a single Database, erasing its contents each time before reading in anothe file?
Well, this was a mothfull.
Any tips will be much appreciated.
alex
Solved! Go to Solution.
Solved by Balaji_Ram. Go to Solution.
Hi Alex,
I havent come across any specific crash similar to what you have mentioned. If you can please let me know the steps to reproduce the behavior, I can try it out and see if I can spot the problem.
What Tony Tanzillo has suggested is to find if the current process name is "acad.exe" and if it is not, omit all the code related to the GSPreview control. Another way for this is to check the "DesignMode" which will tell if you are in the designer. For example the following changes in "BlockViewDialog.cs" and "GsPreviewCtrl.cs" will let you open in the form in the designer. This worked for me, but I have seen guys reporting problems with the use of "DesignMode" in which case you will need to use the method that Tony has suggested. Here is one such link :
http://www.david-gouveia.com/problems-with-designmode-in-winforms/
public BlockViewDialog() { InitializeComponent(); if (!DesignMode) {// initialise the GsPreviewCtrl onl if not in design mode InitDrawingControl(AcadApp.DocumentManager.MdiActiveDocument, AcadApp.DocumentManager.MdiActiveDocument.Database); } } public void refreshView() { // refresh view only if not in design mode if (!DesignMode) { mpView.Invalidate(); mpView.Update(); } } protected override void OnSizeChanged(EventArgs e) { // Ensure size change only if not in design mode if (!DesignMode) { base.OnSizeChanged(e); if (mpDevice != null) { mpDevice.OnSize(this.Size); } } } }
If you are unable to open inside form designer, then you may have to add a similar check in other places of your code that use the preview control.
Regarding the use of a single database, I think it is possible. I havent tried it though.
Following steps might be of help :
1) The "GsPreviewCtrl.cs" has a ClearAll method which can be called first and then the database disposed.
2) Create a new database and then call the "InitDrawingControl" and pass-in the newly created database.
Hope this helps.
Hi Balaji.
Just when I was loosing all hope
Thank you for the DesignMode solution. I will try it. I'll probably have to move all relevant code out of the form designer created file, but it is great anyway.
Regarding the use of a single db, I am trying - unsuccessfully - to create one side-database and use it repeatedly as a container of drawable objects (erasing the existing objects and 'pasting' new ones) and feed it to the GS control to view the objects.
Regarding the crashes I mentioned, I was wrongly blaming the Preview control. The real reason was related to a modeless dialog not being properly dismissed.
Thank you again
alex
Hi Alex,
Just a suggestion - Can you trying creating a new side database instead of trying to erase the objects that you have already have in the db ?
Disposing the old database and creating a new side base and then passing it to the GsPreviewCtrl's "Init" method seems like an easier option to me.
Please let me know if you continue to have problem in getting this to work.
I will try to get a sample code for it.
Balaji
Thank you for replying.
There was a topic in the ObjectARX forum, raising some problems with repeatedly creating and destroyng databases, crashes, memory not being freed etc., so I thought it would be better to just use one temporary (not editable, not visible)database and dispose it at session end.
Maybe in .NET is safer. I will try it.
I will be grateful for an example.
Thanks
alex
Hi Alex,
Sorry for the delay.
Here is the change that I did to the "BlockViewDialog.cs" to ensure that there is only one database opened at a time.
As I had mentioned earlier, it is much simpler to dispose off the previous database and create a new one.
The change is in the "FileOpenMenuItem_Click" event handler :
private void FileOpenMenuItem_Click(object sender, EventArgs e) { // pick the place where o output the image type Autodesk.AutoCAD.Windows.OpenFileDialog dialog = new Autodesk.AutoCAD.Windows.OpenFileDialog("Open DWG File", null, "dwg", "OpenDWGFileDialog", Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.NoUrls); // if all is ok? if (DialogResult.OK == dialog.ShowDialog()) { // clear the preview control mPreviewCtrl.mpView.EraseAll(); /* #region Original code // create a new database dwgs.Add(new Database(false, true)); #endregion */ #region Modified code // create a new database if (dwgs.Count > 0) { // Dispose the earlier database. dwgs[0].Dispose(); // Create a new database for the existing one dwgs[0] = new Database(false, true); } else dwgs.Add(new Database(false, true)); #endregion // now read it in dwgs[dwgs.Count - 1].ReadDwgFile(dialog.Filename, FileOpenMode.OpenForReadAndReadShare, true, ""); // initialising the drawing control, pass the existing document still as the gs view still refers to it InitDrawingControl(AcadApp.DocumentManager.MdiActiveDocument, dwgs[dwgs.Count - 1]); } }
The change is very simple and will ensure that no other part of that sample requires any change.
Hope this helps.
Designer failures often occur because there is code that uses AutoCAD types in the constructor (whether the code is actually called at design time or not, does not matter), or other methods that are called at design-time.
Visual Studio must just-in-time compile methods to run them in the designer, and it is the JIT'ing of those methods that is actually what can fail, rather than a call to an AutoCAD API. In other words, the failure can occur long before any AutoCAD APIs are called, and results from the fact that the JIT'ing of a method requires all assemblies containing any types used in the method to be loaded, which can trigger loading of the AutoCAD assemblies. That will happen regardless of whether the if( DesignMode ) test succeeds or not, because the code that runs only when the test is false is still in the method and is being jitted.
To solve the problem, put all code that calls AutoCAD APIs or uses AutoCAD types in a separate method, and if the test indicates that you're not in the designer, then call that method. That works because the runtime will not jit a method unless it is actually called, so putting the code that uses AutoCAD types in a separate method that's never called at design time, ensures there's no JIT'ing of any code that calls AutoCAD APIs or uses AutoCAD types.
The same problem occurs with any other methods that are called at design-time. Including for example, the overide of the Form's OnSizeChanged() method. You must deal with it in the same way it is dealt with in the constuctor as shown below:
public class Form1 { // No calls to AutoCAD APIs or references to // AutoCAD types should be in the constructor: public Form1() { InitializeComponent(); if( ! base.DesignMode ) { RuntimeOnlyConstruct(); } } /// this method will never be jit'ed at design-time: void RuntimeOnlyConstruct() { // here it is safe to use AutoCAD types // and call AutoCAD APIs } // This method will also be JIT'ed at compile-time, // so you need to keep calls to AutoCAD code and // references to AutoCAD types out of this method, // by placing them into another method that's only // called when DesignMode is false: protected override void OnSizeChanged( EventArgs e ) { if( ! base.DesignMode ) RuntimeOnSizeChanged( e ); } void RuntimeOnSizeChanged( EventArgs e ) { // Ok to use AutoCAD APIs and types here } }
Hi DiningPhilosopher,
Your response was iluminating, I learned something I didn't know before and it also solves the problem.
It also connected with another problem I'm trying to solve:
Quoting from your response:
...the failure can occur long before any AutoCAD APIs are called, and results from the fact that the JIT'ing of a method requires all assemblies containing any types used in the method to be loaded
I'm trying to use an AutoCAD type in an out-of process program and the JIT compiler raises an exception when trying to load the AutoCAD assemblies, apparently because it can't load some unmanaged dependencies of those assemblies.
Do you know of a way to prevent it loading those dependencies, which are not needed anyway for the type I use.
The whole discussion is at: http://forums.autodesk.com/t5/NET/Is-dll-a-AutoCAD-plug-in/td-p/3662592
Thank you
alex
Attached is a fixed and slightly-refactored version of the BlockView.NET source code. You can open the BlockViewDialog in the designer without any problems (although i only tested it on Visual Studio 2008 because I didn't want to convert it to a 2010 project).
You'll also see some notes I added to the source regarding how to avoid design-time failures like the ones this sample was plagued with.
If you are trying to use types from AutoCAD's assemblies in any process other than AutoCAD, it will not work. Since you can't call any AutoCAD APIs, why do you think you need to use those assemblies from another process?
Thank you Philosopher,
I'll have to study your code and implement the changes.
About the Acad types:
I need to extract from a Autocad plug-in the command names defined in it (if any). See topic "Is dll a AutoCAD plug-in?"
http://forums.autodesk.com/t5/NET/Is-dll-a-AutoCAD-plug-in/td-p/3662592
Also my answer there.
Thank you for the sample and the steps to ovecome the issue.
You're quite welcome.
This is actually the first time I looked at it in the 4 or so years since it was published, and would like to thank Fenton for his efforts.