.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using AutoLoader with dependencies

45 REPLIES 45
SOLVED
Reply
Message 1 of 46
drauckman
4159 Views, 45 Replies

Using AutoLoader with dependencies

<?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? 

Tags (2)
45 REPLIES 45
Message 21 of 46

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() { } } }

 

Message 22 of 46

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.

Message 23 of 46
drauckman
in reply to: drauckman

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.

Message 24 of 46
drauckman
in reply to: drauckman

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. 

Message 25 of 46

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
AutoCAD Engineering
Autodesk

Message 26 of 46
drauckman
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.

Message 27 of 46
drauckman
in reply to: drauckman

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.
Message 28 of 46
drauckman
in reply to: drauckman

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.

Message 29 of 46
drauckman
in reply to: drauckman

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.

Message 30 of 46
fenton.webb
in reply to: drauckman

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
AutoCAD Engineering
Autodesk

Message 31 of 46

In case anyone else is working with LoadFrom() in their code I am going to write a summary of what I have learnt.

 

From what I have read and observed I think what ends up happening is when you use Netload in your code it opens up a dialog to browse to the file that you want to load.  When you change directories and select the file, the dialog changes the Environment.CurrentDirectory to the path that you just selected.  Thus when LoadFrom runs the CurrentDirectory variable is pointing to the folder so if you only pass in an assembly name everything works.

 

I am wrong and jumped to conclusions about Autodesk changing something in their code directly, and I will admit that I was getting fairly frustrated with the whole scenario which may have lead me to that.  The Netload and Autoloader mechanics do work differently, just there is not as much of a mystery anymore as to what is really happening.

 

This is the fourth application I am using the offending library in, and they have all either been standalone or loaded with Netload, and since all of the assembly loading using LoadFrom happens at the initialization of any application I have written everything has worked fine.  If I did have a file dialog in my application and asked the user to load a file from someplace and then tried LoadFrom later on to load a feature then my standalone application would run into the same trouble.

 

So I totally agree with Fenton that using this variable is very dangerous and should be avoided.  I did not even realize that this situation was occurring since it is a third party library that I am using that has this code in it.  I have not worked with LoadFrom() until debugging lead me to that line of code.  If I was familiar enough with it to know about what was happening I could have solved this much more easily.

 

It is easy enough now that I know about this to build the full path and pass it into LoadFrom with my code, but what happens if I end up using a third party .dll that does not?  Luckily in this scenario I have the source code that I can modify, but if I didn't this could be a problem.

 

So I think that as a worst case work-around that if you set the CurrentDirectory as I did above before calling any code that initializes your libraries then this *should* take care of most of the issues that you may run into, and may be enough to get past these issues if you are using a closed source third party library that uses LoadFrom in this way.

 

Since the majority of the time that I am going to load some assembly I assume that it is in the same directory as my "main" assembly, or the assembly doing the loading I am going to build the path with the function calls as above, and pass the fully built path into LoadFrom instead of letting it try resolve the correct path (which will use Environment.CurrentDirectory if you do not specify the path, which very well could be wrong)

 

Anyways at the end of the day I ended up learning something new, and if this thread ends up helping anyone else with LoadFrom then I guess there was some point to all of this.  Thanks to everyone who took a look at this and gave feedback, especially DiningPhilospher and Fenton, I greatly appreciate the help and guidance.

Message 32 of 46
fenton.webb
in reply to: drauckman

My pleasure. The offer still stands, if you want to netmeet, let me know.




Fenton Webb
AutoCAD Engineering
Autodesk

Message 33 of 46

Sorry, I'm not clear on something.

 

The bottom line (for me at least), is that your code loads and runs using NETLOAD, but has a problem with the Autoloader, which shouldn't require a patch or intervention.

 

Per chance, did you try testing it using manual registration for demand-loading (either at AutoCAD startup or upon command invocation).

 

If the problem is in your third-party library then why doesn't it happen with NETLOAD?  And, does it happen with manual registration for demand-loading?

 

The documentation for LoadFrom() clearly states that when it is called to load an assembly with a based path, the load context includes the path to that assembly, and that probing for any dependent assemblies referenced from the assembly that was loaded using LoadFrom() will be done in the same location. 

 

That means that the runtime will look in the same folder as the assembly that was loaded using LoadFrom() with a full path, for dependent assemblies when they are requested, and should find them there, regardless of what the current directory is.

 

Perhaps it is that the Autoloader is not using LoadFrom(), but I haven't investigated that.

 

 

 

 

Message 34 of 46
drauckman
in reply to: drauckman

I tried to find the original articles that I read that described the behavior of LoadFrom() but it is buried someplace in my bookmarks.  The Microsoft documentation is lacking a bit in this area and I did find people posting about their experiences with this, which provided the final clues.

 

Basically these two things conspire against you when trying to load an assembly using only the assembly name:

1. LoadFrom uses the Environment.CurrentDirectory to resolve relative paths if you do not supply a full path and filename.  This may or may not be the path to your executing assembly.

2. When you start AutoCAD and it throws the Idle event the value for Environment.CurrentDirectory is the My Documents folder.

 

As Fenton mentioned it is very dangerous to use because you never know what is setting the CurrentDirectory.  Another article I read mentioned that he avoided using it becuase he observed that if you run a open file dialog box, the path that the user navigates to will be the new value of Environment.CurrentDirectory. (Did not investigate if  the dialog result has to be ok for this to be set for sure though)

 

That is the key why Netload works and nothing else will.  I am manually setting the CurrentDirectory variable by selecting my .dll file in AutoCAD Netload file open dialog.  After I Netload the Environment.CurrentDirectory variable is pointing at my directory with all my dependent dll's.

 

I can emulate this by using the following code in the Initialize() method of my plugin:

 

string filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
string completeFilePath = System.IO.Path.GetDirectoryName(filePath);
Environment.CurrentDirectory = completeFilePath;

 

If I use the Autoloader or demand loading without doing the above the default Environment.CurrentDirectory has not been changed from MyDocuments and the LoadFrom fails.

 


@DiningPhilosopher wrote:

The documentation for LoadFrom() clearly states that when it is called to load an assembly with a based path, the load context includes the path to that assembly, and that probing for any dependent assemblies referenced from the assembly that was loaded using LoadFrom() will be done in the same location.

 

That means that the runtime will look in the same folder as the assembly that was loaded using LoadFrom() with a full path, for dependent assemblies when they are requested, and should find them there, regardless of what the current directory is.


The documenation is misleading since "the runtime looking in the same folder as the assembly" actually in reality means that it is using Environment.CurrentDirectory.  This is the conclusion I get from what I have read and from messing around with coding this.  I only pass in the assembly name, and I do not see any way of forcing LoadFrom to resolve the actual assembly path rather than using Environment.CurrentDirectory.

 

I hope that is more clear of an answer?  In the end I think it is the documenation making it sound like it is going to use/resolve the current assembly path, when really it is cheating a bit and using Environment.CurrentDirectory assuming that it is the current assembly path.

 

I could not find anything like LoadFrom("AssemblyName", AssemblyLoadOptions.ResolveActualAssemblyPathInsteadOfUsingEnvironmentVar);  but if someone knows something to this effect I would be interested.

 

Message 35 of 46


@tonofsteel wrote:

The documenation is misleading since "the runtime looking in the same folder as the assembly" actually in reality means that it is using Environment.CurrentDirectory.  This is the conclusion I get from what I have read and from messing around with coding this.  I only pass in the assembly name, and I do not see any way of forcing LoadFrom to resolve the actual assembly path rather than using Environment.CurrentDirectory.

 

I hope that is more clear of an answer?  In the end I think it is the documenation making it sound like it is going to use/resolve the current assembly path, when really it is cheating a bit and using Environment.CurrentDirectory assuming that it is the current assembly path.

 

I could not find anything like LoadFrom("AssemblyName", AssemblyLoadOptions.ResolveActualAssemblyPathInsteadOfUsingEnvironmentVar);  but if someone knows something to this effect I would be interested.

 


Well, here's what I'll tell you.  I have countless plugins that have dependent assemblies that live in the same folder as the plugin, which is demand-loaded via the registry. When that happens, the current directory is not the folder the plugin is in, but the dependent assemblies in that same folder are still found and loaded, which according to you, should not be happening.

 

In fact, I write some code to deal with the general problem of shared assemblies, and what it does also seems to contradict what you say is happening. That code lets me keep assemblies that are shared by multiple plugins in a seperate folder from where the plugins that depend on them live (it uses an AssemblyResolve event handler and a path that I store in a .config file to locate the dependent assemblies).  In that case, the runtime cannot find the dependent assemblies, and so it invokes my AssemblyResolve event handler, which locates and loads the assemblies using LoadFrom(). Those assemblies that I'm resolving myself are themselves also dependent on other assemblies in the same folder, and after loading any assembly from that folder, the rest of them are found and loaded by the runtime, without having to change the current directory.

 

So, how can it be that I can load an assembly using LoadFrom() from any path (passing the entire path to the assembly), which references other assemblies in the same location, and without changing the current directory, the referenced assemblies are found by the runtime and loaded? I know the runtime is finding those other assemblies because my AssemblyResolve event handler is not being invoked for them.

 

So, something doesn't add up here, because I've been relying on the runtime to load dependent assemblies for ages, and have never seen this.

 

Message 36 of 46

I am not saying this should not be happening for you, I did not try to use demand loading via the registry so I am not sure if this would change the behavior of how my loading is working. 

 

This isn't the first time I have used the libraries that started giving me problems now.  The same method of loading up the dependencies occurs in at least four other pieces of software.  I have never run into trouble until the autoloader.

 

Try throw a message box up with Environment.CurrentDirectory at the init of your add in.  If it says like it does for me when I Netload that it is in fact the directory of your assembly, then your code is running just like mine is when I Netload, and if I would have tried this everything would be fine.  If it says My Documents then you are doing something right that I have been unable to without setting the CurrentDirectory manually.

 

I added an event handler to the AssembyResolve event like you showed but it was never called and I could never find out why. 

 

I used the following:

 

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

I added code to show a message box with the calling assembly name and what it was trying to resolve, but it never did show up. 

 

All I know is at the end of the day I can take the code that I first put up on here in my first message, add the lines:

 

string filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
string completeFilePath = System.IO.Path.GetDirectoryName(filePath);
Environment.CurrentDirectory = completeFilePath;

 And it will work.  So if my code throws errors trying to resolve assemblies in my documents, and then I add these three lines and everything works, *something* must be related to Environment.CurrentDirectory.  I am just describing why I think this is.

 

- This only occurs in my autoloader solution, all other software using this does not have this problem.

- When I use netload  the currentdirectory is the correct directory of my add in assembly

- When I use autoload the currentdirectory is my documents

- The only change between netload and autoload software is the above three lines

- After these three lines are added then the autoload solution works properly

 

Those above 5 statements are the only ones that I will stick to, those are the 5 facts I know for sure can be screen captured and the source files diff'd to verify there are in fact no embelishments.

 

The rest of it is my interpretation on what may be happneing in the background based on what I have read in other forums, and the above 5 things.

 

I am interested in getting assembly resolve working since this seems like a more robust way of handling these things, and adds the extra benefit of load from other directories when necessary.

 

I am also open to anyone who can take the above 5 things I have observed, and add the rest of the story to it if I am wrong.

 

I found post that got me looking into the LoadFrom CurrentDirectory operation:

 

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

 

Quote:

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.

 

The loadfrom exception states it can't load my file from My Documents -> The Environment.CurrentDirectory is My Documents.  Change Environment.CurrentDirectory to the assembly path and it loads.  Remember though I am not trying to say your code should not work, this is the ONE time I have had to do this, there is only one way of using my source that I have had to modify to get working.  In the vast majority of cases when you look at this var it will be the correct path.

 

To avoid these problems though and to avoid others I see you could run into you should:

- Not use LoadFrom -> Use Load instead

- Build the full path in your code and pass this into any loading functions

- Get the AssemblyResolve event handler working so you can catch these sorts of things and deal with them in one place.

 

 

Message 37 of 46
jeff
in reply to: drauckman

Skimming through some of the statements it does not seem to add up but might be just going through quickly.

 

For starters instead of using CodeBase

string filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath

What does Assembly.Location return?

 

Codebase returns where file was found, and Location returns path where file was actully loaded.

 

Are there any of the other dll's that might be getting loaded from that location that reference it?

 

As Tony mentioned the runtime will eventully look where the referencing dll is located unless it alredy has been loaded.

 

How the Runtime Locates Assemblies

 

 

 

 

 

 

 

 

You can also find your answers @ TheSwamp
Message 38 of 46

If you look at this document

 

You'll notice the following:

  

Other Locations Probed:
Assembly location can also be determined using the current binding context. This most often occurs when the Assembly.LoadFrom method is used and in COM interop scenarios. If an assembly uses the LoadFrom method to reference another assembly, the calling assembly's location is considered to be a hint about where to find the referenced assembly. If a match is found, that assembly is loaded. If no match is found, the runtime continues with its search semantics and then queries the Windows Installer to provide the assembly. If no assembly is provided that matches the binding request, an exception is thrown. This exception is a TypeLoadException in managed code if a type was referenced, or a FileNotFoundException if an assembly being loaded was not found.
Message 39 of 46
drauckman
in reply to: drauckman

The part in bold highlights exactly why I am confused with this whole thing.

 

I write LoadFrom("Mapping.dll") in my code.  This caller .dll file has been found and loaded separately since it is not part of the top level add-in that is loaded by the Autoloader.

 

I get the FileNotFoundException, and it states it can't find the file in My Documents.  All of my .dll files are in the same directory.

 

Quote:

"the calling assembly's location is considered to be a hint about where to find the referenced assembly"

 

Quote:

The loadfrom exception states it can't load my file from My Documents -> The Environment.CurrentDirectory is My Documents.  Change Environment.CurrentDirectory to the assembly path and it loads.

 

 

I will thus revise my question:

 

Although the documentation states that it will consider the calling assembly's location a hint for using LoadFrom, and the .dll file that I am trying to load is in the same location I get a FileNotFoundException.  This is strange since when I manually set Environment.CurrentDirectory to the calling assembly's location in my add-in initialization method the FileNotFoundException is no longer thrown and the assembly is loaded. 

 

The structure of my software is the AutoCAD Autoloader loads a Main.dll which has a reference to LoadMapping.dll  LoadMapping.dll has a function that is called in MainDll.  The called method in LoadMapping.dll has a LoadFrom statement, of which this behavior is observed.

 

Is there any explanation or insight on why this observed behavior may be occurring?

Message 40 of 46
fenton.webb
in reply to: drauckman

Just a quick question - what is the reason why you are not supplying the actual path to LoadFrom() again? Did I miss that point?




Fenton Webb
AutoCAD Engineering
Autodesk

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost