solidworks-api icon indicating copy to clipboard operation
solidworks-api copied to clipboard

Running multiple add-ins at the same time

Open brinkdinges opened this issue 4 years ago • 9 comments

I'm running into the fact that SolidDna can't really run two add-ins at the same time. Since SolidWorks can't differentiate two dll's with the same name, only one instance of SolidDna runs. If both add-ins use the same version for all libraries, they might start.

I've done some debugging today and this is what I'm seeing. What happens when you start the second add-in is:

  1. AddInIntegration's static properties SolidWorksAddInTitle, SolidWorksAddInDescription and SolidWorks are overwritten.
  2. PlugInIntegration.Plugins is overwritten with the plugins from the second add-in.
  3. Both add-ins actually may start properly

Shutting down one add-in does not go well:

  1. When you unload one of the add-ins using the Add-ins window in SolidWorks, PlugInIntegration.DisconnectedFromSolidWorks is called
  2. DisconnectedFromSolidWorks is called on each plugin in Plugins. Plugins contains only the plugins for the add-in that was loaded last. So the wrong items may be unloaded.
  3. AddInIntegration.SolidWorks is set to null
  4. When the second add-in is unloaded, the Disconnect event gets fired, but the wrong add-in might be informed and the SolidWorks property is already null. So sometimes the second add-in doesn't unload and then a SolidWorks process keeps running.

My suggestions are:

  1. To make AddInIntegration's static properties SolidWorksAddInTitle, SolidWorksAddInDescription (and SolidWorks?) instance properties
  2. Store a list of plugins in the add-in instance, remove the static list of plugins. Move PluginDetails as well?
  3. Create a static list of add-ins. Add the add-in in its ctor, remove it from the list in AddInIntegration.DisconnectFromSW.

I'm already making these changes, but I'm having trouble overseeing the implications. So if anyone would like to help that would be great :)

brinkdinges avatar Dec 25 '19 21:12 brinkdinges

I'm making some good progress. Status can be seen here.

brinkdinges avatar Dec 26 '19 13:12 brinkdinges

I fixed unloading the task pane by adding the AddInTitle property to the task pane, then getting the parent addin by this title. If a user forgets to set this property, the first add-in is used.

I don't like to get objects by their names. SolidWorks does that way too often, sometimes with terrible results. I just couldn't think of another way to get the parent add-in yet.

brinkdinges avatar Dec 27 '19 11:12 brinkdinges

I have removed the SolidAddIn singleton from IoC because we can have multiple add-ins now. I added getting the parent add-in by name, using the new AddInTitle property in TaskPaneIntegration. Not ideal but it works. I moved getting the reference assemblies to the SolidAddIn ctor.

I'm not really happy with the whole situation of how names are set, and the hopping between creating an add-in and plugins. There are basically two situations:

1: Registering in COM When we register in COM, we create a blank add-in to set up DI, get all plugins in its folder, then use the name from the first plugin as the add-in name. This name is then used to register the add-in, it's even called AddInTitle. Why does the add-in not have Name and Description properties? Would it not be simpler to find all add-in types and register those directly?

2: Running the add-in The add-in ctor is called, then ConnectToSW, which finds the plugins. In this case, we create the parent add-in first, then the child plugins. That means it would be straightforward to give the add-in Name and Description properties.

brinkdinges avatar Dec 27 '19 16:12 brinkdinges

Replaced AddInTitle from the previous comment by passing along the add-in type when creating a task pane in the same way the Host is passed.

brinkdinges avatar Dec 28 '19 12:12 brinkdinges

I noticed that the IoC setup ran for every add-in, so I moved it from the SolidAddIn instance to the static AddInIntegration and skip the setup for non-first add-ins. That means ConfigureServices isn't called on the non-first add-ins, but I don't know how to update the existing setup :disappointed:

brinkdinges avatar Dec 28 '19 12:12 brinkdinges

Hey will take a look from my end cause it's awesome idea and i'm going to use it in upcoming project.

Link-IT-Developer avatar Dec 29 '19 15:12 Link-IT-Developer

If we can't update the existing IoC setup, we could initialize it again when the second add-in loads. That's what it does now by accident. We can call ConfigureServices for each add-in when the second add-in loads.

I don't know if it's a good idea though. If both add-ins would add logging, I think the logging for both add-ins will be written to both outputs. Not a terrible problem, it could just be unexpected and confusing for developers to see logging from another product show up in your logs.

Luke, have you recently had contact with SolidWorks about why two DLLs with the same file name are not loaded properly? I'm emailing with Mick Kozikowski, but I'm having trouble conveying the problem and the severity.

brinkdinges avatar Jan 06 '20 20:01 brinkdinges

I just tried to copy the entire SolidDna project to my second add-in, then renamed the project and renamed the namespace. I would think that everything is now unique, so SolidWorks would be able to use both instances. But no, they still interfere with each other. Very strange.

I will ask for some help this week, I still have no idea how to fix this.

brinkdinges avatar Aug 09 '20 19:08 brinkdinges

I spoke to Artem Taturevych about this issue today, he kindly offered to help out a bit. A few of my notes from that meeting:

  • It's standard .net behavior that loaded assemblies with the same name are reused
  • It's standard .net behavior that the assembly version is not used as a unique identifier when the assembly isn't strong-named.

His advice:

  1. Don't use any static classes in a framework. Only allow extension methods and other stateless static methods.
  2. Strong name the assembly

Removing static classes is basically what I tried last December when I opened this issue. I removed the static AddinIntegration but left the static IoC, which then became the problem. Edit: I didn't make it stateless though.

I also experimented a bit today:

  1. Set PlugInIntegration.AutoDiscoverPlugins to false
  2. Create a PlugInDetails instance and add it to PlugInIntegration.PlugInDetails.
  3. Added a Loaded property to PlugInIntegration and set it after SolidDna loads it

This allowed me to start up two add-ins with one plugin each from different solutions. Shutting down nicely doesn't work yet, but that's doable. I got that to work last year.

brinkdinges avatar Sep 03 '20 12:09 brinkdinges