TheSwamp

Code Red => .NET => Topic started by: Chris K on April 29, 2009, 06:54:36 PM

Title: Interop at startup
Post by: Chris K on April 29, 2009, 06:54:36 PM
I have two .dll's that are loaded via netload from acad.lsp.  They each have
command methods that are accessed from lisp.  One functions correctly the
other does not.  However, both function correctly after the startup of
AutoCAD is complete (outside of Acad.lsp).  The only difference, from a
programming standpoint, is that one dll uses InteropServices the other does
not.  Does anyone know of issues with interop at startup?  I can post code
if anyone wants to give it a closer look.
Title: Re: Interop at startup
Post by: Jeff_M on April 29, 2009, 07:17:24 PM
S.W.A.G.---->>>> Try using acaddoc.lsp since it loads later in the load cycle. Or, place the loading in the registry. I have an application that uses Interops and have never had a problem with it loading this way.
Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 11:10:54 AM
Jeff_M thanks for the feedback.  Forgot to mention I've tried Acaddoc.lsp
and the registry.  Same effect.  Sounds like it's something else I'm not
seeing, considering you've done the same with success in the past.  Below
is a list of the external references I'm using, maybe this with help.

Code: [Select]
using Autodesk.AutoCAD;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Runtime;
using acApp = Autodesk.AutoCAD.ApplicationServices.Application;
using lispTools = IMFTUtilities.AcadUtilities.LispTools;

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Data.Common;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using sysMetadata = System.EnterpriseServices.Internal.GenerateMetadata;

One other thing I've noticed.  It only happens for the first drawing loaded
in a session.  For all subsequent drawings the .dll works perfectly.  This seems
to make sense, since the .dll is already loaded into memory. Any additional thoughts,
this one has really got me stumped?
Title: Re: Interop at startup
Post by: It's Alive! on April 30, 2009, 11:16:54 AM
are you implementing IExtensionApplication ?
Title: Re: Interop at startup
Post by: sinc on April 30, 2009, 12:07:11 PM
Chances are good that we will not be able to help you with this unless you can post some code.
Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 02:27:06 PM
Daniel,

Originally I was, but I thought that may have been the problem so I have a non-IExtension version that I've been working with lately.

are you implementing IExtensionApplication ?

Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 02:53:52 PM
Sinc,

I can appreciate that.  Below is a .zip of the project with the required database in the IMFTLayerMaker folder.  The .mdb needs to be in a folder in the AutoCAD support search path.  The Lisp syntax for the use of IMFTLayerMaker is as follows:

Code: [Select]
(imftlayerdef '("Mview" ""))  ;;; 'Mview' is the layername and '' is the layerstatus..... '("33" "e") is another example

This should return a dotted list containing the layer setting info for layer "Mview".

Hope this helps.  If anything else is needed just let me know.  Any help is appreciated.

Chances are good that we will not be able to help you with this unless you can post some code.
Title: Re: Interop at startup
Post by: Glenn R on April 30, 2009, 03:59:47 PM
Loading via lisp is too late for most things you need to do at startup with the 'higher/lower' level languages. This sort of thing is really a matter of 'when' in the startup order.

I'll try and look at your code over the next few days and see what's what. However, I have to ask, why are you using AutoCAD's Interop from a .NET application...you rarely if ever have to resort to this.

Also, unless I missed it in my brief scan of this thread, you haven't mentioned the following important pieces of information:

AutoCAD version you're targetting.
.NET Framework version you're targetting.
Visual Studio version (or whatever else IDE you're using).
Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 04:13:19 PM
Glenn, sorry.  Acad 2009, DotNet 2.0 and VS2005.  I'm using interop to retrieve the file support file search path, there may be a better way, but this is the only way I know.  Still a bit green at this.

Loading via lisp is too late for most things you need to do at startup with the 'higher/lower' level languages. This sort of thing is really a matter of 'when' in the startup order.

I'll try and look at your code over the next few days and see what's what. However, I have to ask, why are you using AutoCAD's Interop from a .NET application...you rarely if ever have to resort to this.

Also, unless I missed it in my brief scan of this thread, you haven't mentioned the following important pieces of information:

AutoCAD version you're targetting.
.NET Framework version you're targetting.
Visual Studio version (or whatever else IDE you're using).
Title: Re: Interop at startup
Post by: Glenn R on April 30, 2009, 04:25:12 PM
Chris, that helps alot - thanks.

However, my apologies - I neglected some other info I and others would need:

You mentioned something wasn't working - this generally signifies an error. What, if any, errors are you getting?
Also, without looking at your zip file and the only code you've posted 'in this thread' is 'Using' statements, I don't know what language you're using...?

Also, can you explain, what your application does, particularly why you need to use 'Interop' for certian parts (one dll as opposed to the other)?
Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 05:15:25 PM
I'm using C# and the errors returned are below.  Also, I haven't been able to run in debug mode because the only error only occurs with the first drawing loaded of a session.  My inexperience is hurting me on this one.  Thanks for the help.  I'll remember what to include in the future.

Error#1
   ---------------------------
   GetLayerPropertiesDS
   ---------------------------
   System.Runtime.InteropServices.COMException (0x800401E3): Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
      at System.Runtime.InteropServices.Marshal.GetActiveObject(Guid& rclsid, IntPtr reserved, Object& ppunk)
      at System.Runtime.InteropServices.Marshal.GetActiveObject(String progID)
      at IMFTUtilities.AcadUtilities.MiscTools.Preferences.GetSupportPaths()
      at IMFTUtilities.AcadUtilities.MiscTools.Misc.IMFTFindFile(String pFilename)
      at IMFTLayerMaker.LayerMaker.GetLayerPropertiesDS()
   ---------------------------
   OK   
   ---------------------------


Error #2
   ---------------------------
   GetLayerDefinition
   ---------------------------
   System.NullReferenceException: Object reference not set to an instance of an object.
             at IMFTLayerMaker.LayerMaker.GetLayerDefinition(String& pLayerName, String& pLayerStatus)
   ---------------------------
   OK   
   ---------------------------

Chris, that helps alot - thanks.

However, my apologies - I neglected some other info I and others would need:

You mentioned something wasn't working - this generally signifies an error. What, if any, errors are you getting?
Also, without looking at your zip file and the only code you've posted 'in this thread' is 'Using' statements, I don't know what language you're using...?

Also, can you explain, what your application does, particularly why you need to use 'Interop' for certian parts (one dll as opposed to the other)?
Title: Re: Interop at startup
Post by: Glenn R on April 30, 2009, 05:43:01 PM
Another thing I should have asked for:

What OS are you running this on Chris?
Title: Re: Interop at startup
Post by: Chris K on April 30, 2009, 06:25:23 PM
I'm running XP 32-bit, SP2 on a Dell Optiplex GX620, 2GB, GeForce FX8500.  :-D

Another thing I should have asked for:

What OS are you running this on Chris?
Title: Re: Interop at startup
Post by: Glenn R on May 01, 2009, 03:05:44 AM
Are you using GetObject/GetActiveObject in your code and if so, why?
Title: Re: Interop at startup
Post by: Glenn R on May 01, 2009, 04:22:52 PM
You're using this:

Code: [Select]
// Cast the current autocad application from .net to COM interop
Autodesk.AutoCAD.Interop.AcadApplication oApp;
oApp = (Autodesk.AutoCAD.Interop.AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.17.2");

in a dll that runs INSIDE AutoCAD! You only need to use this construct if you're hooking into AutoCAD from an external process. This is a not the way to do what you want as you're ALREADY running inside AutoCAD in the first place!

You also go on to use this:
Code: [Select]
// Get the user preferences on the current profile
                AcadPreferences profile = oApp.Preferences;

                // Configure the default preferences
                try
                {
                    strPaths = oApp.Preferences.Files.SupportPath;
                    strPaths = System.IO.Directory.GetCurrentDirectory() + ";" + strPaths;
                    return strPaths;
                }
                catch (acRuntime.Exception e)
                {
                    MessageBox.Show(e.Message, "IMFTUtilities.ACADUtilities.Preferences.GetSupportPaths");
                    return string.Empty.ToString();
                }

when you could have ignored all that guff and just used this:
Code: [Select]
oApp = acApp.AcadApplication as AcadApplication;
string strPath = oApp.Preferences.Files.SupportPath;

It's late here and I'm tired, but that's pretty much how I remember it.
Title: Re: Interop at startup
Post by: Chris K on May 04, 2009, 10:54:06 AM
Glenn, thanks that was the issue. 

Okay, so where I went wrong was connecting to AutoCAD using the wrong implementation of interoperation, I was trying to use an external connection while running the code from the application.  So, Acad had to finish its' startup before it is available for external connections.  That explains why it wouldn't work on the initial start-up, the session wasn't established yet.  Am I getting that correct?

You're using this:

Code: [Select]
// Cast the current autocad application from .net to COM interop
Autodesk.AutoCAD.Interop.AcadApplication oApp;
oApp = (Autodesk.AutoCAD.Interop.AcadApplication)Marshal.GetActiveObject("AutoCAD.Application.17.2");

in a dll that runs INSIDE AutoCAD! You only need to use this construct if you're hooking into AutoCAD from an external process. This is a not the way to do what you want as you're ALREADY running inside AutoCAD in the first place!

You also go on to use this:
Code: [Select]
// Get the user preferences on the current profile
                AcadPreferences profile = oApp.Preferences;

                // Configure the default preferences
                try
                {
                    strPaths = oApp.Preferences.Files.SupportPath;
                    strPaths = System.IO.Directory.GetCurrentDirectory() + ";" + strPaths;
                    return strPaths;
                }
                catch (acRuntime.Exception e)
                {
                    MessageBox.Show(e.Message, "IMFTUtilities.ACADUtilities.Preferences.GetSupportPaths");
                    return string.Empty.ToString();
                }

when you could have ignored all that guff and just used this:
Code: [Select]
oApp = acApp.AcadApplication as AcadApplication;
string strPath = oApp.Preferences.Files.SupportPath;

It's late here and I'm tired, but that's pretty much how I remember it.
Title: Re: Interop at startup
Post by: Glenn R on May 04, 2009, 01:57:26 PM
Essentially, yes.
Title: Re: Interop at startup
Post by: Chris K on May 04, 2009, 02:03:04 PM
Cool, thanks.
Title: Re: Interop at startup
Post by: Glenn R on May 05, 2009, 06:11:42 PM
Having reflected on this, it begs the question: why did you use what you did (GetActiveObject) in the first place?
Title: Re: Interop at startup
Post by: Chris K on May 06, 2009, 05:52:13 PM
To be honest, it is an adaption of a vba routine containing similar code.  Looks like I did a poor job porting it to dotnet. I am, as I've said, very green at dotnet programming and C#.  Most of my programming experience has been with MSAccess.  Anything I've learned has been from examples here on The Swamp, a slough of Wrox books, a few AU handouts and a Jerry Winters VB.NET programming book.  I am always looking for more or better references, so if you have any suggestions, I'm game.  I would like to write solid code that will stand the test of time.  Maybe someday.

Hope this explains my errant ways.

Having reflected on this, it begs the question: why did you use what you did (GetActiveObject) in the first place?
Title: Re: Interop at startup
Post by: Glenn R on May 06, 2009, 06:26:09 PM
Hey Chris,

Thanks for the clarification. I re-scanned the thread and I noticed you mentioned you were 'green' as you put it, but I didn't realise that you were coming from an MSAccess background, which I assume is VBA and that .NET and C# was knew to you. I applaud your drive to learn something new and to increase your understanding of AutoCAD programming. It's a big beast, but it's well worth it.

I and other members of this forum, highly recommend this book (http://www.theswamp.org/index.php?topic=23022.0), as an excellent guide to C# and .NET in general. Personally, from what I have seen of Mr Winters writings, I would not recommend it.

As far as writing code that stands the test of time, I think that's what all here aim for. Keep at it - it's fun, well worth it and you'll get some very good advice from this forum, some knowlegeable people on the adesk forums themselves and Kean Walmsley's (from Autodesk) blog, Through the Interface (http://through-the-interface.typepad.com/).

Above all, search here and ask questions.

Cheers,
Glenn.
Title: Re: Interop at startup
Post by: Chris K on May 07, 2009, 06:21:55 PM
Glenn,

Thanks for the feedback.  I'll pick-up Pro C#, looks interesting enough.  Thanks also for the other sources, I've seen Kean's blog, but so far it tends to be all little over my head.  Thanks again for the help.

Regards,
Chris