VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
Go Back  Xtreme Visual Basic Talk > > > VS 2005 Shared Add-In and ShadowCopy


Reply
 
Thread Tools Display Modes
  #1  
Old 05-28-2007, 10:08 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default VS 2005 Shared Add-In and ShadowCopy


I have an Office Shared Add-In created using the template in VS 2005 and would like to implement shadowcopy for this DLL so that it can be modified without requiring the users to exit all instances of Office first. It is installed under Terminal Services so 50+ users could have multiple copies of Office apps open at once and getting them 'out' is not easy.

I am aware of Add-In Express and while that is an option, the add-in itself is very simple and I would like to know how to accomplish this, regardless.
Reply With Quote
  #2  
Old 05-28-2007, 11:09 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Hi topry,

Technically, I don't think you can do this directly, but we may be able to get done what you need.

The problem is that althogh .NET pulls in a copy of its referenced DLLs (whether .NET or COM DLL dependencies), COM programs such as MS Office work under COM rules wherby the registered COM component is reference directly. And while the COM DLL is in use, the COM DLL is locked and cannot be overwritten.

When you create a managed shared add-in using .NET, you are exposing your classes to COM by compiling with 'Register for COM Interop' turned on, and having your connect class implement the GuidAttribute and ProgIdAttribute. (This is all handled for you by the Shared Add-in Wizard.) I have not tested this in .NET, but since you are having trouble updating the .NET assembly, it seems that the MS Office application (a COM application) is holding a reference to the DLL and so the DLL is locked for editing or overwriting.

My thinking on how to get around this is to create two .NET assembly's: (a) the shared add-in (the "front end") and (b) a class library (the "back end"). The shared add-in will be registered for COM as it is currently. (It has to be for your MS Office routine to recognize it and load it.) However, this front end should be mostly a shell, simply making calls to the "back end" class library DLL. This back-end you should be able to replace at will, even if others are running a current copy. This is because .NET assemblies load in their dependencies as copies of the original DLL and so you can copy over the original as needed.

However, unless you actually-re-compile the "front end" DLL, I don't think that the copy of the "back end" DLL reference within the folder of the "front end" DLL will update. However, I think you should be able to manually copy paste the "back end" DLL fom the bin\release\ directory into the correct location in the "front end" DLL's folders. Doing this, I believe that all current users of Office will be unaffected and that new instances of MS Office will load the shared add-in with the new functionaility. But you'll have to test it.

I can't say that I have ever tried this, but I think this should work. Let me know if this was a clear enough explanation, and of course, come back if you get stuck or if you have any other questions...

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #3  
Old 05-28-2007, 11:19 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Thank you for the prompt reply -

Since a reference to the Office app loading the add-in is passed in the OnConnection event, that reference in turn must be passed to the separate class/DLL that you propose. Should that DLL be replaced after instantiation, it would not of course effect the current running instance, which is memory, but should any 'future' instances.

Obviously, I had not considered this but its easy enough to test. I will post my findings once I give it a go.

Also - thank you for your excellent article on automating Office from .Net (Automating Office Programs with VB.Net / COM Interop) it helped me come to grips with an issue I had spent way too many days chasing.
Reply With Quote
  #4  
Old 05-28-2007, 11:39 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Quote:
Originally Posted by topry View Post
Since a reference to the Office app loading the add-in is passed in the OnConnection event, that reference in turn must be passed to the separate class/DLL that you propose. Should that DLL be replaced after instantiation, it would not of course effect the current running instance, which is memory, but should any 'future' instances.
Yes that's the idea. And this is exactly how Shadow Copy works, by the way. Existing users are unaffected because they are running off of a copy. The reference passing you are describing is, as you say, memory referneces and should not affect (or lock) the file of the underlying assembly. That's the plan anyway!

Quote:
Obviously, I had not considered this but its easy enough to test. I will post my findings once I give it a go.
Please do, I hope this works out for you... Hope, hope...

Quote:
Also - thank you for your excellent article on automating Office from .Net (Automating Office Programs with VB.Net / COM Interop) it helped me come to grips with an issue I had spent way too many days chasing.
No problem. I'm glad it helped. (And I thank you for the feedback. ) The reference release problem is the most common question we get on this forum by far. And so this is why the tutorial puts so much emphasis on that issue. I'm glad that it helped you out, it really can be a head-banger!

Good luck with your task at hand, I've got my fingers crossed for you...

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #5  
Old 05-28-2007, 07:31 PM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Unfortunately, a quick test was not successful. Debugging an Add-In is a bit of a pain, but I will give it another shot when time permits.

Thanks again.
Reply With Quote
  #6  
Old 05-29-2007, 08:40 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Yeah, I was afraid of that.

When I gave that advice yesterday, I thought that it should work. But later in the day I searched a bit and read this article:

http://www.devx.com/dotnet/Article/10045

It makes it clear that for windows applications (as opposed to ASP.NET applications) shadow copy is not the norm, even if XCopy is. A file lock is held on the assembly while it is being run. So my guess is that your tests show that a lock is held on the dependent DLLs of the assembly as well?

However, that article also shows some ways around it using 'AppDomainSetup.ShadowCopyFiles = True' along with reflection to create a new AppDomain and then call Assembly.LoadFrom().

But as I see it, as long as one is using Assembly.LoadFrom(), then you really have full-control anyway. For example, you could copy the main Assembly to a local or temporary folder and then call Assembly.LoadFrom() on that. You wouldn't need to worry about creating a new AppDomain or dealing with the the 'AppDomainSetup.ShadowCopyFiles' setting at all.

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #7  
Old 05-30-2007, 08:15 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

I use a similar method (shadowcopy with a loader) for my main application, very easy to do and a great help for an in-house application that runs under terminal services that allows me to patch it at anytime. Which is why I would like the same functionality for the add-in.

While Assembly.LoadFrom will allow you to load any assembly from a specified location, the trick is the version checking, etc that ShadowCopy does for you. Without that, checking versions, copying the file when a new version exists, etc would be a bit..ugly.

I still haven't figured out how to implement that portion of it from within the Add-In stub file. I know it is possible (as Add-In Express does it), just need to noodle out the specifics.

I would have thought you could set .ShadowCopyFiles = "true' for the current appdomain, but finding information for that has of yet, been fruitless.

Framework 1.1 had a .SetShadowCopyFiles method that apparently was for this purpose but it has been deprecated, replaced with .ShadowCopyFiles which is part of AppDomainSetup.

Last edited by topry; 05-30-2007 at 08:51 AM.
Reply With Quote
  #8  
Old 05-30-2007, 10:14 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Hi topry,

Quote:
Originally Posted by topry View Post
I use a similar method (shadowcopy with a loader) for my main application, very easy to do and a great help for an in-house application that runs under terminal services that allows me to patch it at anytime. Which is why I would like the same functionality for the add-in.
Yes, this would definately be nice...

Quote:
While Assembly.LoadFrom will allow you to load any assembly from a specified location, the trick is the version checking, etc that ShadowCopy does for you. Without that, checking versions, copying the file when a new version exists, etc would be a bit..ugly.
I'm not so sure. I would think that this could be easily simulated yourself. For example, lets say that there is a folder location that always has the newest version. (It always has the newest version, because that's where you save it.) Upon loading, the front end add-in goes to that folder and copies the newest version to a folder on the local C-drive. It then loads from the C-drive location using Assembly.LoadFrom(). Admitedly, most of the time it will be copying in unnecessarily (because there are no changes), but this would work fine.

To take it to the next level, you could simply include a Text, XML or Manifest file that held the version information. Your add-in could then read that file and compare it to the existing one in the local C-drive folder location. If the local version is up-to-date, then don't bother with the copy and just go straight to the Assembly.LoadFrom() call.

These are just some thoughts off the top of my head, but I don't see why this couldn't do the trick.

Quote:
I still haven't figured out how to implement that portion of it from within the Add-In stub file. I know it is possible (as Add-In Express does it), just need to noodle out the specifics.
Dennis knows this program well. I'm not as familiar though. (He has an excellent blog article on it here.) So Add-In Express allows for this shadow-copy capability natively? That does sound nice. That said, I don't think that the late-bound loading approach should be too bad.

Quote:
I would have thought you could set .ShadowCopyFiles = "true' for the current appdomain, but finding information for that has of yet, been fruitless.
My guess is that this has to be done when the AppDomain is first created. Since your add-in is loaded into the default AppDomain you cannot change it's behavior. However, you can create a new AppDomain and set the AppDomainSetup.ShadowCopyFiles = "true". The DevX Article I listed above shows an example as follows:

Code:
Sub main() ' create a new evidence object, ' based on the current appdomain Dim myDomainSetup = New System.AppDomainSetup() myDomainSetup.ShadowCopyFiles = "true" With AppDomain.CreateDomain( _ "sample", AppDomain.CurrentDomain.Evidence, _ myDomainSetup) .ExecuteAssembly("..\..\Forms\bin\Forms.exe") End With End Sub
But I think that if you copy your files to a local folder location and then use Assembly.LoadFrom() to access that local folder, that this should be good enough?

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb

Last edited by Mike Rosenblum; 05-30-2007 at 10:24 AM.
Reply With Quote
  #9  
Old 05-30-2007, 10:24 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Thanks for the input (and all of your time on this)

The issue (as I see it and from limited testing) with simply using .LoadFrom() is:
User1 launches Word, in the .OnConnection event, the shared DLL is copied to the temp folder and loaded - all is good.

Shared DLL is updated.

User1 launches Excel or another instance of Word, the .OnConnection event tries to copy the new DLL, but the first one is still locked by Word, so the copy fails and either the .OnConnection fails, setting .LoadBehavior to 2 or it ends up using the prior version.

ShadowCopy handles this by checking the ver and if different, copies the DLL to a new location and does LoadFrom from there. Creating a new appdomain with .ShadowCopyFiles="true" is not the issue, my problem has been loading an instance of my DLL into that new appdomain.
I have tried .CreateInstanceFromAndUnWrap as well as .CreateInstanceFrom - without success...as of yet. Still trying to see if its an issue with it being from within the interop loader or just something stupid on my part.
Reply With Quote
  #10  
Old 05-30-2007, 10:38 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Ok, I see...

Well, I have two thoughts on this:

(1) The first idea would be to check if the local C-drive file location is locked. To be honest, I'm not 100% sure how to do that, but attempting the copy-paste protected by a Try-Catch block should do the trick. If it is locked, then the add-in can only load from the current C-drive location. That is, it cannot update currently, but it will the next time, as long as there are no local instances currently running on the PC. Certainly the next time the PC is rebooted and then any of the programs in question is run, it would definately be updated at that point.

(2) In order to always update, regardless of any programs that might be using the DLL currently, then I would copy in the DLL to a new temp folder location each time. Either use a random number generator to create a unique folder name or perhaps use the the current time-stamp in seconds or milliseconds. Done this way, each instance of Excel, Word, etc. would all have their own local copies each time. And running off the most recent version would always occur. And I guess you should delete the temp folder when exiting. (Actually, I think the file system itself should have a temp-folder capability, but I'm not an expert on this.)

The disadvantage to version #2, is that you would be ALWAYS copying in your DLL every time that Word or Excel is loaded. Using version #1 would not always update to the newest version, but would only attempt the copy-paste operation if there actually is a required update present, saving you time when the add-in loads.

This is the best I can think of. There may not be a perfect solution here, but one of these should be ok, I would think?

Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb

Last edited by Mike Rosenblum; 05-30-2007 at 04:20 PM.
Reply With Quote
  #11  
Old 05-30-2007, 12:21 PM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Turns out its a bit uglier than I first thought. I had never tried to use LoadFrom for an assembly - hit a few oddities that were a bit counter-intuitive, then I found this: http://www.hanselman.com/blog/Fusion...eWhatever.aspx

I've purchased AddIn Express, so Im heading down that path now. While I will revisit this later just because I want to know, I do think that creating a new AppDomain and using ShadowCopy is likely the most reasonable method.

Thanks again for you time and thoughts.

EDIT:
Also, some info on ShadowCopy and AppDomain.Load - While my app would create a shadowcopy of the DLL, the original was still locked. That too is a bit trickier than the docs would lead you to believe:

http://groups.google.com/group/micro...95a2ff4954d702

.../
The problem lies in the way AppDomain.Load() works.

When you make a call to AppDomain.Load, the assembly is loaded in the
target domain (which is appDomain in your case) BUT the call returns a
reference to the same assembly back to your parent domain (the one
where the code is running). When this happens, the dll gets loaded in
the parent domain where there is no setting to shadow copy the files.


So you see, shadow copy is working for the target domain, but it
doesn't happen in the parent domain. Hence, the file gets locked.


If you want to load the assembly in the target domain without getting
a reference back in the parent domain, you will have to write a class
that will load the assembly for you in the target domain. i.e.,
something like a proxy object where you would first create an instance
of the Loader object in the target domain and then call
Loader.LoadMyAssembly(filename) which would load the specified file in
the target domain and NOT return any reference to it. The only caveat
is that you should never get a direct reference to the loaded
assembly, even if it just an interface. The moment you do that, it
will get loaded in your parent domain and you're back at square one.

/

Last edited by topry; 05-30-2007 at 01:17 PM.
Reply With Quote
  #12  
Old 05-30-2007, 02:12 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Ok, well using AddIn Express would sound like a good way to go if it automatically handles this shadow copy issue for you.

Just so you know, the way to deal with the situation discussed in the Scott Hanselman thread you linked is to create an interface compiled within a separate class library that both your add-in and your late-loaded assembly both reference. The assembly is then loaded, an instance of the assembly's class is created, and then it is cast to the interface defined in the separate class library. (This is very simplified, but this is the basic idea.)

That said, if a 3rd party add-in can do the work for you, it would certainly be easier.
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #13  
Old 05-30-2007, 02:17 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Ah, ok, I see that you added an edit...

Quote:
Originally Posted by topry View Post
EDIT:
Also, some info on ShadowCopy and AppDomain.Load - While my app would create a shadowcopy of the DLL, the original was still locked. That too is a bit trickier than the docs would lead you to believe:

http://groups.google.com/group/micro...95a2ff4954d702

.../
The problem lies in the way AppDomain.Load() works.

When you make a call to AppDomain.Load, the assembly is loaded in the
target domain (which is appDomain in your case) BUT the call returns a
reference to the same assembly back to your parent domain (the one
where the code is running). When this happens, the dll gets loaded in
the parent domain where there is no setting to shadow copy the files.


So you see, shadow copy is working for the target domain, but it
doesn't happen in the parent domain. Hence, the file gets locked.
Yes, but if you first copy your assembly to a local folder (or better, to a unique temporary folder) and then load from that location, then you don't mind that it gets locked. Right?

Anyway, that's the idea I was proposing. It does require a little work, but it's doable...
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #14  
Old 05-30-2007, 02:18 PM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

My 'shared' DLL does use a public interface, its required to do early binding on the object from within our external applications. I had ShadowCopy working up to this point, where the original DLL was also being locked. I need to get this project into testing, so I will revisit it later - as I want to see if I can get it to work. Depending on the AddIn-Express overhead, I may return to it sooner than expected.

Interesting stuff, and just about as painful as my first go-round with Remoting.
Reply With Quote
  #15  
Old 05-30-2007, 02:25 PM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Quote:
Originally Posted by topry View Post
My 'shared' DLL does use a public interface, its required to do early binding on the object from within our external applications.
Ok, then you really should have no trouble then. Although, you will have to move the definition of the interface to a separate Class Library because the location (the definition of the interface) cannot change. Ideally, it would be put into the GAC to ensure this.

Quote:
I had ShadowCopy working up to this point, where the original DLL was also being locked.
I'm not quite sure what's happening here. The front-end Add-in will be locked, of course, because it is exposed and registered as a COM DLL. If, however, you mean that the late-loaded DLL was locked, this is ok if it's in a temp-folder location.

Quote:
I need to get this project into testing, so I will revisit it later - as I want to see if I can get it to work. Depending on the AddIn-Express overhead, I may return to it sooner than expected.
Sounds like a good plan, I hope that AddIn-Express works out for you!

Quote:
Interesting stuff, and just about as painful as my first go-round with Remoting.
Yeah, I hear ya'. Remind me to stay away from remoting then... LOL

Good luck topry,
Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb

Last edited by Mike Rosenblum; 05-30-2007 at 04:17 PM.
Reply With Quote
  #16  
Old 05-31-2007, 06:04 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Remoting in 1.x was painful. Ingo Rammer released a good book on the topic but there were so many caveats that it made me long for DCOM. In 2.0 they added IPC support which is very easy (comparatively) to implement for one way communication - raising events....not so much.

FYI- AddIn Express is an interesting product. While worth the price, it is limited in one area that I need and that is IPC. Their only method of interfacing with the AddIn from another process is via the PostMessage API. While I had asked if IPC was possible, I was assuming a similar COM interface methodology. I haven't used PostMessage for this purpose in ...a while.

Oh, the issue I had with my quick ShadowCopy test was that the source DLL was locked - the one I would be copying over/updating. I had not abstracted it out using the Interface. I found the reference I posted about that after the fact. Guess I will give that a quick go now. Thanks again for your input and help.
Reply With Quote
  #17  
Old 05-31-2007, 07:30 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Quote:
Remoting in 1.x was painful. Ingo Rammer released a good book on the topic but there were so many caveats that it made me long for DCOM. In 2.0 they added IPC support which is very easy (comparatively) to implement for one way communication - raising events....not so much.
Thanks for the info. I really know very little about this stuff. I guess going forward WCF will be the way to go, from what I've read it's a nice blend of Remoting and Web Service communication. But this is not my area...

Quote:
FYI- AddIn Express is an interesting product. While worth the price, it is limited in one area that I need and that is IPC. Their only method of interfacing with the AddIn from another process is via the PostMessage API. While I had asked if IPC was possible, I was assuming a similar COM interface methodology. I haven't used PostMessage for this purpose in ...a while.
Yes, Add-in Express does look very impressive.

As for IPC communication with your COM Add-in, you actually can. The caveat is that I've never done this using a Managed COM add-in, and there is a quirk in the VBA/VB6 syntax to do this that might make this problematic when attempted from .NET. You'll have to test to be sure. But here's the basic idea:

(1) Within your Connect class, you modify the OnConnection() event handler to set the 'AddinInst As Object' parameter to 'Me' (or 'this' if using C#). Using Visual Basic 6.0 it would look as follows:

Code:
Private Sub Connect_OnConnection(_ ByVal Application As Object, _ ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) AddInInst = Me ' <-- The Key line! End Sub
The oddity in the above is that you are omitting the 'Set' keyword. This would seem to make no sense in VB6, but I'm pretty sure this is the correct syntax. It's unclear to me what is happening at the VB 6.0 level here. Since AddInInst is being passed in ByVal, it is NOT being set to the instance of the Connect class (the 'Me' instance). Because the 'Set' keyword is omitted, what appears to be happening is that the default property of the AddInInst is being Let-assigned to the 'Me' instance. And because of this unusual syntax, I'm not sure you'll be able to make this assignment from .NET at all -- because there is no way to assign to a parameterless default property using .NET.

I can see two potential ways around this:

(1) You can attempt to simply implement IDT2Exetensibility2 directly within .NET. That is, you could simply try the direct 'AddInInst = Me' assignment -- It might just work, who knows? If not, then I would attempt late binding. Easiest in VB.NET to set 'Option Strict Off' and then I would attempt to call 'AddInInst.Object = Me'. Yes, using ".Object" as the default property name is an assumption on my part, but it is an educated guess, as we'll see in a bit...

(2) Option #2 is to make your COM Add-in in VB 6.0. It's only the front-end anyway, so this is no big deal. (That is, it's no big deal if you have a copy of Visual Basic 6.0 lying around somewhere.) Then create an instance of your .NET Add-in via VBA.CreateObject("MyAssemblyName.MyClassName"), which loads your front-end .NET Assembly. The loaded .NET assembly then does the file-copy operations of the back-end .NET assembly as necessary to a local folder and then launches the back-end assebly from the local folder location.

Ok, either way, once you have your Connect_OnConnection() event handler assigning 'AddInInst = Me', you can access your Add-in via Automation. For example, assuming that your Add-in is running within the Excel application, you could get the add-in instance as follows:
Code:
Dim xlApp As Excel.Application = _ GetObject(, "Excel.Application") Dim myAddin As MyAddinName.MyClassName = _ CType(xlApp.ComAddins("MyAddinName.MyClassName").Object, _ MyAddinName.MyClassName)
From there you should be able to access your add-in as needed. As you can see, it is a bit of work, but I don't think it's quite as bad as it might look at first. If you are under time-pressure, however, it might be best just putting this info in a drawer somewhere for the future...

Quote:
Oh, the issue I had with my quick ShadowCopy test was that the source DLL was locked - the one I would be copying over/updating. I had not abstracted it out using the Interface. I found the reference I posted about that after the fact. Guess I will give that a quick go now. Thanks again for your input and help.
Ok, good luck, let us know how it goes...

,
Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
  #18  
Old 05-31-2007, 08:37 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

Thanks - I had no problem accessing the COM Interface of the AddIn when using the VS template, directly via late binding and by implementing a public interface, you can use early binding (which is what Im currently doing).

AddIn Express however (according to their support) requires you use PostMessage. The object exposed to the Office app in the .ComAddIns collection is apparently a proxy and they do not have an interface to marshal the methods from their loader/stub to the user generated code.

FYI- I did get ShadowCopy to work in a test Windows app but the same method is failing in the AddIn. It required creating three new classes. 1) A public interface 2) A Proxy object 3) the 'work' DLL that needs to be replaced/updated.

The Proxy and Work DLL inherit the public interface.
Primary object creates a new appdomain, loads the proxy.
The constructor of the proxy creates yet another appdomain and loads the 'work' DLL.

Using a Win form to create the proxy, I can invoke methods on the interface of the proxy, which in turn invokes the 'work' dll, which is not locked. I can replace the 'work' dll while one instance is loading and the next instance reflects the change.

However, getting it to work from the COM AddIn is a bit more of a challenge. I will tinker with it as I have time and if I ever get it going, I will post the steps/info.
Reply With Quote
  #19  
Old 05-31-2007, 10:58 AM
topry topry is offline
Newcomer
 
Join Date: May 2007
Posts: 23
Default

So...how do you reference the assembly typename without putting the assembly in the GAC?

When creating a new appdomain and then using .CreateInstanceFromAndUnwrap(AssemblyName, "TypeName"), if the assembly is not in the GAC, it results in: "Type is not resolved for member 'typename'"

I don't want to put these DLLs in the GAC for several reasons, not least of which it makes debugging a pain, and pushing updates is much more time consuming.

This is not an issue when testing in a Winforms app, only in the add-in which is instantiated by Word. Winforms app only requires ("assembly.dll", "TypeName"), in the AddIn, I have to pass the FQ path to the DLL (not an issue), but I cannot figure out how to get it to resolve the type...
Reply With Quote
  #20  
Old 05-31-2007, 11:43 AM
Mike Rosenblum's Avatar
Mike Rosenblum Mike Rosenblum is offline
Microsoft Excel MVP

Forum Leader
* Guru *
 
Join Date: Jul 2003
Location: New York, NY, USA
Posts: 7,848
Default

Quote:
Originally Posted by topry
AddIn Express however (according to their support) requires you use PostMessage. The object exposed to the Office app in the .ComAddIns collection is apparently a proxy and they do not have an interface to marshal the methods from their loader/stub to the user generated code...

However, getting it to work from the COM AddIn is a bit more of a challenge. I will tinker with it as I have time and if I ever get it going, I will post the steps/info.
If Add-in Express does what you need, then that should be easier. However, if it does not, then you might find that you have better control trying to do this yourself using Assembly.LoadFrom(). On the other hand, if tech support at Add-in express is very good, then maybe they can walk you through this.


Quote:
Originally Posted by topry View Post
So...how do you reference the assembly typename without putting the assembly in the GAC?

When creating a new appdomain and then using .CreateInstanceFromAndUnwrap(AssemblyName, "TypeName"), if the assembly is not in the GAC, it results in: "Type is not resolved for member 'typename'"

I don't want to put these DLLs in the GAC for several reasons, not least of which it makes debugging a pain, and pushing updates is much more time consuming.
I'm not sure that I see the need to create a new AppDomain. I would just use Assembly.LoadFrom(), loading into the current AppDomain.

This is how I would approach it, but I can't see your code and all the issues that you have to juggle.

If you do create a new AppDomain, then create it based on an Assembly that can be put in the GAC. Note that the class library that holds your interface is an excellent candidate to be locked down in the GAC so that its identity does not change -- and therefore casting to the interface is guaranteed. (This avoids the issue within the Hanselman blog you posted about above.)

I hope this helps...
Mike
__________________
My Articles:
| Excel from .NET | Excel RibbonX using VBA | Excel from VB6 | CVErr in .NET | MVP |
Avatar by Lebb
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
 
VS 2005 Shared Add-In and ShadowCopy
VS 2005 Shared Add-In and ShadowCopy
 
-->