Author Topic: Slow Method  (Read 8084 times)

0 Members and 1 Guest are viewing this topic.

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 »