.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
4160 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 2 of 46
mariominati
in reply to: drauckman

You Maybe have a Problem with Windows using a different Path through localized imstall.
Message 3 of 46
drauckman
in reply to: drauckman

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?

Message 4 of 46


@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.

 

 

Message 5 of 46
drauckman
in reply to: drauckman

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.

Message 6 of 46
_gile
in reply to: drauckman

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
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

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

 

 

Message 8 of 46
DiningPhilosopher
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().

Message 9 of 46
drauckman
in reply to: drauckman

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.

Message 10 of 46
drauckman
in reply to: drauckman

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?

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

Hi guys

 

I recommend you take a look at this bundle example http://adndevblog.typepad.com/autocad/2012/06/autocad-performance-gauges-app.html

 

It shows how to load multiple DLLs, and also how to automatically hook into the Autoloaders prebuilt AssemblyResolve event handler.

 

Also, take a look at this white paper http://adndevblog.typepad.com/autocad/2013/01/autodesk-autoloader-white-paper.html

 

 

 




Fenton Webb
AutoCAD Engineering
Autodesk

Message 12 of 46
jeff
in reply to: fenton.webb

Would it be much trouble to copy project, delete most files, and strip down to one or two functions just for something to reference each other and post project?

You can also find your answers @ TheSwamp
Message 13 of 46
drauckman
in reply to: fenton.webb

I did not see those articles previously, thanks!

 

The only two things I could see in those examples that I did not try was assembly mappings and the component entry with appname, version module etc.

 

I have tried different combinations of this in the PackageContents and it does not change the functionality.  I have tried the suggestion on the other page to 3. Load the extra dll before actually needing it: and 4. Handle AppDomain.AssemblyResolve event and load the assembly there (My AssemblyResolve event handler is never called though, why I do not know)

 

If this is true:

"One of the features of the Autoloader is the ability for it to load WPF Dll’s away from the acad.exe directory; it does this by implementing an AssemblyResolve event handler."

Then it means that AutoCAD is messing around with the same event handler I am trying to get into, although I read the last handler registered wins.  This does not appear to be the case for me.

 

There are two very important points to remember though -> This project can be loaded/run by using Netload, from the exact folder and structure that the bundle is in

 

Maybe though there is a reason why?  I do not understand how during the development/debugging process you can use Netload with no problems and then when you want to deploy all of a sudden there are these mysteries?  IMHO if you can hit Netload, point to an assembly and everything fires up, you should be able to have this equal functionality in the Autoloader, otherwise why introduce it if you have to go back to messing around with registry etc.

 

I see in the gauge example on that page that you have many assembly mappings, and I do not understand why these are required, I have a total of 8 .dll's and as long as they are all in the same folder as the dll that I am loading everything works.  I only have a single contents folder though so maybe when the layout gets more complex with versions etc I might need the same?

 

I did not see anywhere in the gauge example where Assembly.LoadFrom was used and this is currently the only part that is giving me a problem, the other assemblies can be found as far as I can tell.

 

Since all my other assemblies whether or not they are WPF, class libraries etc get loaded fine I suspect that there is a problem with how the Autoloader is handling the AssemblyResolve event or something related to its functionality.  All of the AssemblyResolve code in the gauge example is redundant and if you removed it everything *should* still load, AssemblyResolve is only called when an assembly can't be found.

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

Any chance you can post your bundle so I can take a closer look for you?




Fenton Webb
AutoCAD Engineering
Autodesk

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

This the last iteration of the bundle that I created

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

I get this error, do you see the same? If so, I'd like to know the code you have in that function please...

 




Fenton Webb
AutoCAD Engineering
Autodesk

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

The picture does not show up for me in any browser that I try

Message 18 of 46
jeff
in reply to: drauckman

Doh!

 

Looks like pointing to file on his computer.

 

image.PNG

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

Just guessing, that the failure is happening before you've added the AssemblyResolve handler. If you can put it in another assembly that gets loaded before the one that's having the problem, it may be called.

Message 20 of 46

After a quick look at your bundle, here is what I would suggest you do.

 

1.  Remove everything from your MyPlugIn.Initialize() method, and put it in another static method on the MyPlugIn class.

 

2. In MyPlugIn.Initialize() add a handler for the Application.Idle event.

 

3. In the handler for the Application_Idle event, remove the handler from the event, so it is called only once, and then call the method that contains the code that you removed from Initialize().

 

The basic idea is to defer execution of that code until after the Autoloader has finished doing whatever it is doing that is causing the code to fail, so that it executes in the same context it would execute if  your plugin was loaded via NETLOAD.

 

This is really just a workaround, that you need to use to avoid having to dig a hole to China to find out what exactly is causing the failure. The AutoLoader doesn't seem to have any kind of built-in self-diagnostics that would allow you to identify what it is doing and deduce the cause of unexpected failures.  White papers are helpful, but built-in self-diagnostics that could be enabled to see what is actually going on, would be far better.

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