.NET

Reply
Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 1 of 41 (913 Views)
Accepted Solution

Using AutoLoader with dependencies

913 Views, 40 Replies
01-08-2013 11:02 AM
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage SchemaVersion="1.0" AppVersion="1.0"
    ProductCode="{20F44DBA-0878-4ADE-91A4-E540E45A37FB}"
    Name="Menus"
>

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

  <Components>
    <RuntimeRequirements SupportPath=".\Contents\" SeriesMax="R19.0" SeriesMin="R19.0" Platform="AutoCAD*" OS="Win64"/> 
    <ComponentEntry ModuleName=".\Contents\Data.Mapping.dll" AppName="DelcoMapping" AppType="Dependency">
        <RuntimeRequirements SupportPath=".\Contents\" />
    </ComponentEntry>
    <ComponentEntry ModuleName=".\Contents\Menus.dll" AppName="Menus" AppType=".Net" LoadOnAutoCADStartup="True">
    </ComponentEntry>
  </Components>

</ApplicationPackage>

 

I set the support path, and even define the component entry to look for the Data.Mapping.dll in the contents folder.  This file exists there however everytime I start AutoCAD it says it cannot load file or assembly Data.Mapping.dll in the C:/Users/User/Documents/ folder

 

So I am at a loss, how much more explicit can you get as to where this file is located in the packagecontents.xml???  Why does AutoCAD not read the file from the location which has been clearly specified? 

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.

Member
mariominati
Posts: 4
Registered: ‎01-23-2006
Message 2 of 41 (892 Views)

Re: Using AutoLoader with dependencies

01-08-2013 02:39 PM in reply to: tonofsteel
You Maybe have a Problem with Windows using a different Path through localized imstall.
Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 3 of 41 (857 Views)

Re: Using AutoLoader with dependencies

01-17-2013 02:44 PM in reply to: tonofsteel

Does anyone out there have any experience creating a bundle with multiple DLL's?  Has anyone else run into problems loading referenced DLL's?  I manually created the bundle and copied the files over, if I create an installer would this resolve locating dependencies?

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 4 of 41 (843 Views)

Re: Using AutoLoader with dependencies

01-20-2013 02:49 AM in reply to: tonofsteel

tonofsteel wrote:
 

I set the support path, and even define the component entry to look for the Data.Mapping.dll in the contents folder.  This file exists there however everytime I start AutoCAD it says it cannot load file or assembly Data.Mapping.dll in the C:/Users/User/Documents/ folder

 

So I am at a loss, how much more explicit can you get as to where this file is located in the packagecontents.xml???  Why does AutoCAD not read the file from the location which has been clearly specified? 


The error message you quoted is  'cannot load...'.

 

'Cannot load' and cannot find/locate are not one and the same. It may be finding the assembly but the attempt to load it is failing due to a number of possible reasons, like a missing or bad dependent assembly/.DLL.

 

Did you try NETLOADing the assembly from the same location? You should also try registering the assembly for demand loading at startup using the Applications key in the registry (e.g, the 'old way'), rather than using the AutoCAD plug-in loader.

 

If using those methods work, then the problem is clearly in AutoCAD's plug-in loader.

 

 

Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 5 of 41 (820 Views)

Re: Using AutoLoader with dependencies

01-21-2013 07:39 AM in reply to: tonofsteel

The error that I get is:

 

MyPlugin.Initialize(): Could not load file or assembly 'file:///C:\Users\user\Documents\Data.Mapping.dll' or one of its dependencies.  The system cannot find the file specfied.

 

This error is valid, this file is not in my documents folder.  My question is why is AutoCAD looking in that folder?  Especially because I have the following:

 

<RuntimeRequirements SupportPath=".\Contents\"

 

The contents has all of the .dll files in it including the main project .dll.  AutoCAD is finding this main file since it is getting to MyPlugin.Initialize() Even if I do not point to the dependency .dlls shouldn't AutoCAD automatically at the very least look in the same folder as the main .dll for its dependencies?

 

Just in case that is not enough:

 

    <ComponentEntry ModuleName=".\Contents\Data.Mapping.dll" AppName="DMapping" AppType="Dependency">

 

I have directly pointed out to AutoCAD where this file is located, so why would this exception be thrown before AutoCAD looks in the location I have pointed out?

 

While developing I am compiling to debug, and when AutoCAD starts I Netload the main .dll file from the debug bin folder.  Since CopyLocal for all dependency .dlls is set to true they also are all in this same folder.  My application loads fine and everything runs.  I now want to deploy and that is how I got started with the bundles and the above problems.

 

For testing I manually created the bundle folder structure, the XML file and copied the debug .dlls directly to the content folder.

 

I am sure that this process is similar to what others might do when developing a plugin so what do you do differently when going from the Netload to the bundle?

 

I notice as well in that trace that the error thrown includes:

at System.Reflection.Assembly.LoadFrom(String assemblyFile)

 

So would this be .Net looking for this file and not AutoCAD?  Other than what I have done in the XML file I do not know how to point to the correct file location.  It seems intuitive enough for me that when trying to load a dependency one of the default actions should be to look in the same folder as the assembly that is running.

 

I will try the old method, but I would really like to know what piece I am missing here.

*Expert Elite*
_gile
Posts: 2,086
Registered: ‎04-29-2006
Message 6 of 41 (809 Views)

Re: Using AutoLoader with dependencies

01-21-2013 12:55 PM in reply to: tonofsteel

Hi,

 

Did you try with only one 'ComponentEntry' node for the main DLL ?

Your app should find the Dependency dll while it's in a support path folder.

 

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

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

  <Components>
    <RuntimeRequirements SupportPath=".\Contents\" SeriesMax="R19.0" SeriesMin="R19.0" Platform="AutoCAD*" OS="Win64"/> 
    <ComponentEntry ModuleName=".\Contents\Menus.dll" AppName="Menus" AppType=".Net" LoadOnAutoCADStartup="True">
    </ComponentEntry>
  </Components>

</ApplicationPackage>

 

Gilles Chanteau
Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 7 of 41 (790 Views)

Re: Using AutoLoader with dependencies

01-22-2013 02:25 PM in reply to: _gile

I have tried this, the above post is what I arrived at after many iterations of trying to get this to work.  I do not understand what is going on here:

 

<ComponentEntry ModuleName="./Contents/Data.Mapping.dll" AppType="Dependency" />

 

Can anyone answer why it is looking for this file in my documents? 

 

On another note I have tracked down this line in one of the libraries I am using:

 

Assembly asm = Assembly.LoadFrom(MakeLoadReadyAssemblyName(mappingAssembly));

 

And this line would be trying to load Data.Mapping.dll

 

For some reason if I use netload to manually go to my dll in my bundle folder it loads and runs fine.  If I use the Autoloader then all of a sudden it wants to look in my documents for dependencies that are in the same folder as the executing assembly.  Something behind the scenes is not right here.

 

So I guess I can use Autoloader to load my own Autoloader that runs netload to load my add-in? 

 

Who would make the Autoloader work any different than Netload?

 

Maybe I can modify the above Assembly.LoadFrom so that I somehow find the path of the currently executing assembly and then pre-pend this for a complete path?

 

Something along the following?:

string path;
path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase );

 Anyone have any experience with stuff like this?

 

 

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 8 of 41 (783 Views)

Re: Using AutoLoader with dependencies

01-22-2013 05:35 PM in reply to: _gile

The problem is clearly in the Autodesk plug-in loader if your app loads without failure using NETLOAD.

 

Here is one possible way of working around the issue:

 

Handle the AppDomain.CurrentDomain.AssemblyResolve event. In handler for that event, when you see that it is looking for your Data.Mapping.dll assembly, use Assembly.LoadFrom() to load the assembly yourself (presuming you know where it is located or, you can find it), and then just return the Assembly object that's returned by Assembly.LoadFrom().

Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 9 of 41 (767 Views)

Re: Using AutoLoader with dependencies

01-23-2013 07:55 AM in reply to: tonofsteel

The Assembly.LoadFrom documentation states the following:

 

assemblyFile may be absolute or relative to the current directory, and the assembly is loaded into the domain of the caller.

 

When I use the above code snippet I posted to get the path I fully expected it to somehow be pointing to my documents but when I run it the correct path for the bundle contents folder is shown.

 

Thanks DiningPhilosopher I will have to try your suggestion next, it looks like there is a good chance that is what I will need to do to get this working.

Valued Contributor
tonofsteel
Posts: 93
Registered: ‎12-04-2009
Message 10 of 41 (764 Views)

Re: Using AutoLoader with dependencies

01-23-2013 08:40 AM in reply to: tonofsteel

I have added the following code:

 

class MyPlugin : IExtensionApplication
{
     public void Initialize()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

 

And the event handler:

 

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    MessageBox.Show(args.RequestingAssembly.FullName + " requested: " + args.Name);

 

And of course this event never happens and the code is never called.  I still get the same exception with the same path info and the same everything.

 

If AutoCAD for some reason is handling this event would this cause my handler not to get called?

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.