.NET

Reply
Valued Mentor
Posts: 370
Registered: ‎05-06-2012
Message 21 of 41 (216 Views)

Re: Using AutoLoader with dependencies

01-24-2013 06:39 AM in reply to: tonofsteel

To make things easier, you can use the class below to automate doing what I described above. 

 

Add the included class to your project, then change the ancestor of your MyPlugin from "IExtensionApplication" to "ExtensionApplication" (e.g., delete the "I").

 

Change the access of your Initialize() and Terminate methods from 'public' to 'protected override'.

 

After doing that, your initialization code will execute on the first Idle event that fires after your plugin is loaded.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;

[Assembly: ExtensionApplication( typeof( ExtensionApplication ) )]

namespace Autodesk.AutoCAD.ApplicationServices { public abstract class ExtensionApplication : IExtensionApplication { void IExtensionApplication.Initialize() { Application.Idle += OnIdle; } void OnIdle( object sender, EventArgs e ) { Application.Idle -= OnIdle; this.Initialize(); } protected abstract void Initialize(); void IExtensionApplication.Terminate() { this.Terminate(); } protected virtual void Terminate() { } } }

 

Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 22 of 41 (206 Views)

Re: Using AutoLoader with dependencies

01-24-2013 08:43 AM in reply to: DiningPhilosopher

Thanks alot DiningPhilosopher for looking into this and giving some insight on how this might be worked around!  I have created the class and made the modifications you suggested.

 

I have run into something that has happened to me before, but I am not sure how I resolved it in the past.  I think it just started working again without too much of my intervention. 

 

The code that I have from what you described:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;


[assembly: ExtensionApplication(typeof(CAD.ExtensionApplication))]

namespace CAD
{
    public abstract class ExtensionApplication : IExtensionApplication
    {
        void IExtensionApplication.Initialize()
        {
            System.Windows.Forms.MessageBox.Show("Initializing");
            Application.Idle += OnIdle;
        }

        void OnIdle(object sender, EventArgs e)
        {
            Application.Idle -= OnIdle;
            this.Initialize();
        }

        protected abstract void Initialize();

        void IExtensionApplication.Terminate()
        {
            this.Terminate();
        }

        protected virtual void Terminate()
        {
        }
    }
}

 

Nothing happens when I try to load this either with Netload or the Autoloader.  The problem from what I remember is this line:

 

[assembly: ExtensionApplication(typeof(CAD.ExtensionApplication))]

 

AutoCAD is supposed to see that and load it up as an extension application, but never does.  I thought Tony T. mentioned that if you use these attributes that they either have to be on all or none of the commands/extension application classes for it to work properly.  The only change regarding attributes I did was comment this attribute out on my MyPlugin class since I can only have one.  The class with my commands in it remains un-touched and has the CommandClass attribute.

 

AutoCAD is now refusing to acknowledge these attributes since the commands and the extension are not being recognized.  If I try run a command it states it is undefined.

 

What am I doing wrong here, why does this have to be so impossible?

 

The message box never shows, the line is never hit in the debugger.

Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 23 of 41 (204 Views)

Re: Using AutoLoader with dependencies

01-24-2013 08:56 AM in reply to: tonofsteel

Ok found how to get it working, I needed remove this:

 

[assembly: ExtensionApplication(typeof(CAD.ExtensionApplication))]

 

and keep the attribute in my original class.  Now the code is getting called.

 

So far, it is still looking in my documents and throws the same exception.  Still the same deal that it is the LoadFrom command I mentioned earlier.  I will see if messing around with your idea I can modify/find something that will work.

 

The only thing I noticed change is that before when it threw the exception nothing would work, all my commands would be undefined.

 

I notice now though that the commands un-related to the code that uses LoadFrom works now.

 

There are two exceptions thrown with the same info, one is the message box I have in my try/catch statement in initialize, and the other is one thrown by the software itself.

 

I think I need to read over what you wrote again I may not have moved some code exactly the way you suggested.

Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 24 of 41 (201 Views)

Re: Using AutoLoader with dependencies

01-24-2013 09:17 AM in reply to: tonofsteel

Alright I have tried moving the initialize code around to different places including the MyPlugin class and even a different static class.

 

Same deal it is always going to my documents with the Autoloader, loads fine with Netload. 

ADN Support Specialist
Posts: 352
Registered: ‎07-24-2007
Message 25 of 41 (201 Views)

Re: Using AutoLoader with dependencies

01-24-2013 09:22 AM in reply to: DiningPhilosopher

FYI

 

We have a Startup attribute in the Commands element that does this for you... Basically, if you define your commands for your app, you can define one of the commands as a startup command. The Autoloader will wait until AutoCAD has loaded fully before executing the command.

 

e.g.

 

<?xml version="1.0" encoding="utf-8"?>
<ApplicationPackage SchemaVersion="1.0" AppVersion="1.0.2" ProductCode="{8C7F1C11-E241-455C-9A2D-A6EE734BEE62}" Name="Delco Menus" AutodeskProduct="AutoCAD" Description="Delco Menus" FriendlyVersion="1.0.0" ProductType="Application" SupportedLocales="Enu" AppNameSpace="appstore.exchange.autodesk.com" Author="Automation Inc." UpgradeCode="{136A3C34-DE39-48A3-B1E7-FC7EA0C643D6}" OnlineDocumentation="www.automation.com">
  <CompanyDetails Name="Automation Inc." Email="---@automation.com" Url="www.automation.com" Phone=" " />
  <RuntimeRequirements OS="Win64" Platform="AutoCAD*" />
  <Components Description="Contents parts">
    <RuntimeRequirements OS="Win64" Platform="AutoCAD*" SeriesMin="R19.0" SeriesMax="R19.0" />
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/DelcoMenus.dll" AppDescription="DelcoMenus" LoadOnAutoCADStartup="True">
      <Commands>
        <Command Local="DELCO_STARTUP" Global="DELCO_STARTUP" Description="Delco Startup Command" StartupCommand="True" HelpTopic="#StartupAnchor" />
      </Commands>
      <AssemblyMappings>
        <AssemblyMapping Name="DelcoMenus" Path="./Contents/DelcoMenus.dll" />
      </AssemblyMappings>
    </ComponentEntry>
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/Delco.HardwareDesign.CAD.Application.AutoCAD.dll" AppDescription="DelcoMenus" />
    <ComponentEntry AppName="DelcoMenus" Version="1.0" ModuleName="./Contents/Delco.HardwareDesign.CADDatabase.Data.dll" AppDescription="DelcoMenus" />
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/Delco.HardwareDesign.Data.dll" AppDescription="DelcoMenus" />
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/Delco.HardwareDesign.Data.EntityFramework.dll" AppDescription="DelcoMenus" />
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/Delco.HardwareDesign.Data.Model.dll" AppDescription="DelcoMenus" />
    <ComponentEntry AppName="DelcoMenus" AppType="Dependency" Version="1.0" ModuleName="./Contents/EntityFramework.dll" AppDescription="DelcoMenus" />
  </Components>
</ApplicationPackage>





Fenton Webb

Developer Technical Services

Autodesk Developer Network


Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 26 of 41 (195 Views)

Re: Using AutoLoader with dependencies

01-24-2013 09:38 AM in reply to: fenton.webb

Thanks Fenton!

 

I did this and get the same results.  Still looking in my documents.  It must be that what DiningPhilospher suggested essentially is similar to the StartupCommand because it does exactly the same thing.  It throws an exception but it still goes on to load the rest of the assemblies because the commands work where they did not before.

 

Now that I have my initialize code with LoadFrom in a add-in command, I tried to load my add-in and then call this command from the AutoCAD editor after a Netload.   Once again, loads fine with no exceptions and all of the add-in works.

Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 27 of 41 (193 Views)

Re: Using AutoLoader with dependencies

01-24-2013 10:18 AM in reply to: tonofsteel
Further Developments: I found out that if the Autoloader is run at all for an add-in, and if your code at any time uses LoadFrom it will try to read from My Documents. Once AutoCAD finds a bundle to load, and invokes the Autoloader it changes something internally so that working with assemblies gets screwed up. Netload does not do this. There is some code in the Autoloader somewhere that screwing this all up. I have a command defined with the code that causes the exception. I no longer have anything trying to run this code while the autoloader loads up all of my assemblies. If I try to call this command 10 seconds or 1 hour after AutoCAD starts up it will throw the exception, if Autoload is used. If I use netload then it works fine.
Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 28 of 41 (189 Views)

Re: Using AutoLoader with dependencies

01-24-2013 10:47 AM in reply to: tonofsteel

Finally a solution, why couldn't anyone at Autodesk just come out and say that the Autoloader sets the Environment.CurrentDirectory to My Documents????   You have the source, can't you see that?

 

I did not know enough about the LoadFrom command, and since I did not change any environment variables in my code I didn't understand what was going on.  Now that I painfully learned more about how all this works I have found the most simple solution.

 

Behold:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;

using System.Reflection;

// This line is not mandatory, but improves loading performances
[assembly: ExtensionApplication(typeof(AutoCAD.StupidWorkaround.MyPlugin))]
namespace AutoCAD.StupidWorkaround
{
    public class MyPlugin : IExtensionApplication
    {
        public void Initialize()
        {
            Application.Idle += OnIdle;
        }

        void OnIdle(object sender, EventArgs e)
        {
            Application.Idle -= OnIdle;

            System.Windows.Forms.MessageBox.Show(Environment.CurrentDirectory);
            string filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
            string completeFilePath = System.IO.Path.GetDirectoryName(filePath);
            Environment.CurrentDirectory = completeFilePath;
            System.Windows.Forms.MessageBox.Show(completeFilePath);
            Assembly.LoadFrom(@"DelcoMenus.dll");
        }

        public void Terminate()
        {
            
        }
    }
}

 

As soon as I do that and have my package contents:

 

<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage SchemaVersion="1.0" AppVersion="1.0"
    ProductCode="{20F44DBA-0878-4ADE-91B4-E540E45A37FB}"
    Name="Stupid Workaround"
>

  <CompanyDetails
    Name="Automation Inc."
    Email="d@automation.com"
  />

  <Components>
    <RuntimeRequirements SupportPath="./Contents/" SeriesMax="R19.0" SeriesMin="R19.0" Platform="AutoCAD*" OS="Win64" /> 
    <ComponentEntry ModuleName="./Contents/AutoCAD.StupidWorkaround.dll" AppName="StupidWorkaround" AppType=".Net" LoadOnAutoCADStartup="True">
      <AssemblyMappings>
        <AssemblyMapping Name="StupidWorkaround" Path="./Contents/StupidWorkaround.dll" />
      </AssemblyMappings>
    </ComponentEntry>
  </Components>

</ApplicationPackage>

 

So really at the end of the day all I needed to do was set an environment variable that someone decided they were going to treat this differently with each method of loading.  Thanks alot!

 

If you are using:

http://through-the-interface.typepad.com/through_the_interface/2008/09/loading-net-mod.html

 

or LoadFrom in general where the default operation is to load from the same directory the executing assembly is located in try setting the environment variable like above.

Valued Contributor
Posts: 93
Registered: ‎12-04-2009
Message 29 of 41 (184 Views)

Re: Using AutoLoader with dependencies

01-24-2013 11:09 AM in reply to: tonofsteel

One more thing to note from:

 

http://stackoverflow.com/questions/3187088/could-not-load-file-or-assembly

 

The method LoadFrom will use Environment.CurrentDirectory to build the full path to the assembly that will be loaded. The current directory is not the same as the application base path.

You should provide the full path to LoadFrom method, you can build it using AppDomain.CurrentDomain.BaseDirectory if the file is located in the same folder then the executable.

 

Unfortunatly for me I am using libraries that do not build the full path and assume the current directory is where it is located.  The full path should technically be built, but if you use AppDomain.CurrentDomain.BaseDirectory you get the AutoCAD folder, so that is not helpfull in this case.

 

If you happen to be using code that has LoadFrom statements, you can just store the existing Environment.CurrentDirectory in a temporary variable, set it to where you want, and then set it back after your code runs to prevent other code from failing if it is also setting this and expecting nothing to mess with it.

 

If you are writing LoadFrom statements in your code then the full path should be built like above in the code, but put it directly into LoadFrom instead of assuming that the Environment.CurrentDirectory will be a certain value.

ADN Support Specialist
Posts: 352
Registered: ‎07-24-2007
Message 30 of 41 (180 Views)

Re: Using AutoLoader with dependencies

01-24-2013 11:27 AM in reply to: tonofsteel

Sorry, but the Autoloader itself does not set the CurrentDirectory.

 

Generally speaking, you must never rely on the CurrentDirectory in your app - its very dangerous.

 

Finally, I'm not sure the design of your app, but we have many hundreds of people using the Autoloader to easily deploy their apps with no problems. Some of which have many many dependent DLLs. If I knew the design of your app more clearly, I'd be able to suggest a more robust design.

 

Maybe you could show me via netmeeting sometime. my email address is my name separated with a dot, followed by @autodesk.com





Fenton Webb

Developer Technical Services

Autodesk Developer Network


You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Welcome to the new Autodesk Community!
If this is your first visit, click here to get started and make the most of the Community. Let us know what you think of the new experience in the Community Feedback Forum.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community