Author Topic: Slow Method  (Read 8083 times)

0 Members and 1 Guest are viewing this topic.

HD

  • Guest
Slow Method
« on: August 25, 2008, 02:30:13 PM »
The code below populates a ComboBox control with drawing template (dwt) files. When I debug this code, the line:  AcadApplication acadApp = new AcadApplication(); can take up to 15 seconds before moving onto the next statement. Does anyone have any ideas why I am encountering such a delay?

Code: [Select]
        private void DetailSheetForm_Load(object sender, EventArgs e)
        {
            AcadApplication acadApp = new AcadApplication();
            string templatePath = acadApp.Preferences.Files.TemplateDwgPath;

            DirectoryInfo di = new DirectoryInfo(templatePath);
            FileInfo[] templateFiles = di.GetFiles("*.dwt");

            // Populate the Template ComboBox.
            foreach (FileInfo item in templateFiles)
            {
                if (!cboTemplate.Items.Contains(item))
                    cboTemplate.Items.Add(item);
            }
        }

p.s. My operating environment is: Vista Pro, Visual Studio 2008 Pro, and AutoCAD 2009.

Glenn R

  • Guest
Re: Slow Method
« Reply #1 on: August 25, 2008, 03:09:27 PM »
That's because this line:
Code: [Select]
AcadApplication acadApp = new AcadApplication();

is spining up a new instance of AutoCAD through it's COM API/Interface...I'm not surprised it's taking as long as you say.

Glenn R

  • Guest
Re: Slow Method
« Reply #2 on: August 25, 2008, 03:49:15 PM »
Not at all. You haven't supplied enough information for me to say 'live with it' just yet ;)

First off, is this a standalone executable externally automating AutoCAD, or is it a NETLOAD'ed .dll?

Glenn R

  • Guest
Re: Slow Method
« Reply #3 on: August 25, 2008, 03:56:39 PM »
Actually, what I should have said, was, is it your intent to spin up another AutoCAD session in that method?

Glenn R

  • Guest
Re: Slow Method
« Reply #4 on: August 25, 2008, 04:08:42 PM »
As far as the NETLOAD goes, that's what I suspected. Did you do a search here?

Glenn R

  • Guest
Re: Slow Method
« Reply #5 on: August 25, 2008, 04:40:59 PM »
Because I knew how to nab AutoCAD preferences, I didn't search here. ...

Well if that's the way you've been it doing from NETLOAD'ed .dll's, then it's...not optimal, shall we say :)

A quick search of this forum for 'Preferences.Files' (as that seems to be the root of what you're trying to get), revealed several hits, the 1st (at this point in time) being the most relevant (and it actually has the string 'TemplateDwgPath' in it too, as an added bonus ;) )

Here it is.

Glenn R

  • Guest
Re: Slow Method
« Reply #6 on: August 25, 2008, 04:41:57 PM »
Hope this helps, as firing up another ACAD session is not a good idea, especially from inside an existing one. If you have further questions, post away.

Glenn R

  • Guest
Re: Slow Method
« Reply #7 on: August 25, 2008, 05:03:54 PM »
No probs Nick - just 'steering' you along is all...

Glenn R

  • Guest
Re: Slow Method
« Reply #8 on: August 26, 2008, 04:31:10 AM »
Why are you doing this:

Code: [Select]
if (String.IsNullOrEmpty(templatePath) == true)

It's a bit verbose don't you think?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #9 on: August 26, 2008, 06:05:40 AM »
You should probably remove this line as you are trying to release something you did not create

Code: [Select]
Marshal.ReleaseComObject(ap);

Glenn R

  • Guest
Re: Slow Method
« Reply #10 on: August 26, 2008, 06:31:43 AM »
Dan,

It decrements the COM Interface pointer reference count. As Nick is getting an interface pointer to AcadPreferences it seems valid.
However, the runtime will probably clean up regardless, so it's alright to remove it.

I've seen TonyT using this and I would think he would have a good reason to do so......

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #11 on: August 26, 2008, 07:53:42 AM »
Tony T would be wrong in this case :)

Glenn R

  • Guest
Re: Slow Method
« Reply #12 on: August 26, 2008, 07:58:58 AM »
After more reading, I concur.

Glenn R

  • Guest
Re: Slow Method
« Reply #13 on: August 26, 2008, 09:50:21 AM »
The test is fine and is what I would do as well. What I meant is that this:

Code: [Select]
if (String.IsNullOrEmpty(templatePath) == true)

is returning a bool from evaluating a function, then testing for equality with == and finally the 'if' statemment does it's test.

I would have written it like so:

Code: [Select]
if (string.IsNullOrEmpty(templatePath)) return;

sinc

  • Guest
Re: Slow Method
« Reply #14 on: August 26, 2008, 10:16:24 AM »

It decrements the COM Interface pointer reference count. As Nick is getting an interface pointer to AcadPreferences it seems valid.

Blech!

Why is that method returning a COM object?  Just yet another way for Autodesk to complicate things and keep us on our toes?  Or is there some good reason for it?

Glenn R

  • Guest
Re: Slow Method
« Reply #15 on: August 26, 2008, 10:24:18 AM »
None that I can tell. Part of the API left in COM land....

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #16 on: August 26, 2008, 01:21:27 PM »
Tony T would be wrong in this case :)

I may have been wrong on this, it seems when you use the property AcadApplication it does in fact increment the reference. The underlying call is Marshal::GetObjectForIUnknown(IntPtr) . What this does is create a managed object that will be garbage collected. However I suppose if one wanted to explicitly decrement the reference, one could by using Marshal::ReleaseComObject(object). It may be better to let the GC handle this though

Sorry TonyT  :oops:

sinc

  • Guest
Re: Slow Method
« Reply #17 on: August 26, 2008, 03:08:04 PM »
We've actually been talking about the AcadPreferences object, which for some reason is a COM object, and not a managed object.

Glenn R

  • Guest
Re: Slow Method
« Reply #18 on: August 26, 2008, 03:49:02 PM »
I thought there would be a good reason Tony was using this as he does have extensive experience with the API's and he has in the past lamented on Autodesk's COM implementation (so has RR).

It does make some sort of sense though that the 'top' object, AcadApplication in this case, does increment it's reference count accordingly, as AutoCAD would very much want to know when its application count changed....just some ramblings.

Glenn R

  • Guest
Re: Slow Method
« Reply #19 on: August 26, 2008, 04:04:58 PM »
One of the reasons for confusion in this area I think, is the use of 'chained calls' ie:

AcadApplication.Preferences.Files

Is this a ref count on the application, Preferences and Files....?????

This is a reason I tend to avoid chained calls and explicitly have variables for each level to do with what I please, which is in marked contrast to the historical use of VB, where I've seen code with very long chained calls....more musings........

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Slow Method
« Reply #20 on: August 26, 2008, 06:40:42 PM »
Quote
... explicitly have variables for each level to do with what I please ...
slightly related ..

it also helps to name the variables to identify the COM relationship.
.. well, helps the reader anyway ; and considering we all spend more time solving problems and reading code than actually typing code, every little bit of clarity is of assistance.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #21 on: August 26, 2008, 09:03:59 PM »
Preferences also makes a call to Marshal::GetObjectForIUnknown(). I also see a couple of others in there that do the same i.e, MenuGroupsand MenuBar

I am just curious as to why TonyT does not trust the GC to free the RCW.  Would it be worthwhile to create an IDisposable template for com objects?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #22 on: August 27, 2008, 12:54:14 AM »
Something like

Code: [Select]
public struct ComObject<T> : IDisposable where T : class
  {
    private T m_comObject;
    private bool m_disposed;
    public ComObject(object comObject)
    {
      if (comObject == null)
        throw new ArgumentNullException("object comObject");
      if (!Marshal.IsComObject(comObject))
        throw new ArgumentException("Expects System.__ComObject");
      this.m_comObject = (T)comObject;
      this.m_disposed = false;
    }

    public void Dispose()
    {
      this.Dispose(true);
      GC.SuppressFinalize((ComObject<T>)this);
    }

    private void Dispose(bool disposing)
    {
      if (!this.m_disposed)
      {
        Marshal.ReleaseComObject(this.m_comObject);
        this.m_comObject = default(T);
        this.m_disposed = true;
      }
    }
    public T comObject { get { return this.m_comObject; }}
  }

Code: [Select]
public class Commands
  {
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr AcadGetIDispatch(bool bAddRef);

    [CommandMethod("doit")]
    static public void doit()
    {
      Editor ed = AcAp.Application.DocumentManager.MdiActiveDocument.Editor;
      try
      {
        //using (ComObject<AcadApplication> obj = new ComObject<AcadApplication>
        //                      (Marshal.GetObjectForIUnknown(AcadGetIDispatch(true))))
        using (ComObject<AcadApplication> App = new ComObject<AcadApplication>AcAp.Application.AcadApplication))
        {
          ed.WriteMessage(App.comObject.Name);
        }
      }
      catch (System.Exception ex)
      {
        AcExtensions.EdMethods.WriteCatchMessage(ex);
      }
    }
  }

Glenn R

  • Guest
Re: Slow Method
« Reply #23 on: August 27, 2008, 04:20:14 AM »
I think that's unnecessary Dan. I believe Tony was just being a good citizen and cleaning up after himself. I suppose it's rather like 'using' which we all use frequently to clean up immediately.

I also tend to agree, this is just calling ::Release() on the RCW, which is a spun up, 'proxy' if you will, managed object, handling the COM goo plumbing for talking between the managed and unmanaged world.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8722
  • AKA Daniel
Re: Slow Method
« Reply #24 on: August 27, 2008, 04:50:13 AM »