|
|
There is very strange assembly reference problem and loading problem I experience with my Outlook addin. Here are the detail (a long story :) ):
I have an old Outlook addin, written and build using .Net 1.1. The addin is loaded using an unmanaged shim in its own application domain. It works OK, with .Net 2.0, even if 1.1 is not present on the user's machine.
The addin uses a custom Outlook interop assembly, created by VS 2003 against Outlook 2000, and after that rebuild to be strongly typed (as is my addin).
In the addin project I reference only this custom interop assembly, no reference to the official MS interop assemblies.
When this addin is used in an environment with Outlook 2007 and .Net 2.0, where the official MS interop assemblies are installed in GAC, for some reason I see that the addin loads and uses them.
In the code of the Connect class, I have a using directive:
using Outlook;
which is the namespace of my custom interop assembly.
In Connect ctor I have these lines of code (added for testing purposes):
Assembly.LoadFrom(PATHTOMYASSEMBLY + "Interop.Outlook.dll"); Type type = typeof(Outlook.ApplicationClass); logger.Debug("Outlook.Application full type is: {0}", type.AssemblyQualifiedName);
This outputs:
Outlook.Application full type is: Outlook.ApplicationClass, Interop.Outlook, Version=9.0.0.0, Culture=neutral, PublicKeyToken=4cfbdc5349cf59d8
Which is exactly what I would expected.
The problem is, that when the OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) is called, I see in the log (I have a hook to AssemblyLoad event of the current domain) that MS interop assembly is loaded as well:
private void app_domain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) { Assembly loadedAssembly = args.LoadedAssembly; logger.Debug("Assembly {0} is loaded from: {1}", loadedAssembly.FullName, loadedAssembly.GlobalAssemblyCache ? "GAC" : loadedAssembly.Location); }
Output:
Assembly Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c is loaded from: GAC
My OnConnection method starts like this:
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { Type type = application.GetType(); logger.Debug("OnConnection application object's full type is: {0}", type.AssemblyQualifiedName);
Outlook.Application applicationObject = (Outlook.Application)application;
This outputs:
OnConnection application object's full type is: Microsoft.Office.Interop.Outlook.ApplicationClass, Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
This is really weird, as you can see that on the next line I can successfully cast to Outlook.Application without any problems.
I have checked with Reflector, and my assembly DOES NOT reference Microsoft's interop assemblies in any way. Same for my Interop.Outlook.dll.
So, does someone knows what's going on? What is the answer for these questions:
1. Why it loads the Microsoft assemblies at all? 2. How it is possible to cast between unrelated classes/interfaces, defined in different assemblies?
|
|
I'm not an expert in this area, but I think the issue here is basically that Microsoft's interop asemblies aren't just official, they're primary, and that makes a big difference. So maybe your interop assembly is behaving like a client app, and that means it must go through the Office PIAs. Instead of "you->Your interop assembly->COM class" it's "you->Your interop assembly->Office PIA->COM class", or something like that. The PIAs are installed so Office is going to insist that they be used instead of yours. Whether all that actually works properly, who knows. One of the reasons for PIAs is that if everyone uses them the types are common and can be shared between different assemblies. Anyway, just my thoughts.
-- Phil Wilson Definitive Guide to Windows Installer http://www.apress.com/book/view/1590592972
"Sunny" <icesunny[ at ]nospam.nospam> wrote in message news:04B85746-5680-4206-B3AF-20CFFE3471A7[ at ]microsoft.com...
[Quoted Text] > There is very strange assembly reference problem and loading problem I > experience with my Outlook addin. Here are the detail (a long story :) ): > > I have an old Outlook addin, written and build using .Net 1.1. The addin > is > loaded using an unmanaged shim in its own application domain. It works OK, > with .Net 2.0, even if 1.1 is not present on the user's machine. > > The addin uses a custom Outlook interop assembly, created by VS 2003 > against > Outlook 2000, and after that rebuild to be strongly typed (as is my > addin). > > In the addin project I reference only this custom interop assembly, no > reference to the official MS interop assemblies. > > When this addin is used in an environment with Outlook 2007 and .Net 2.0, > where the official MS interop assemblies are installed in GAC, for some > reason I see that the addin loads and uses them. > > In the code of the Connect class, I have a using directive: > > using Outlook; > > which is the namespace of my custom interop assembly. > > In Connect ctor I have these lines of code (added for testing purposes): > > Assembly.LoadFrom(PATHTOMYASSEMBLY + "Interop.Outlook.dll"); > Type type = typeof(Outlook.ApplicationClass); > logger.Debug("Outlook.Application full type is: {0}", > type.AssemblyQualifiedName); > > This outputs: > > Outlook.Application full type is: Outlook.ApplicationClass, > Interop.Outlook, Version=9.0.0.0, Culture=neutral, > PublicKeyToken=4cfbdc5349cf59d8 > > Which is exactly what I would expected. > > The problem is, that when the OnConnection(object application, > Extensibility.ext_ConnectMode connectMode, object addInInst, ref > System.Array > custom) is called, I see in the log (I have a hook to AssemblyLoad event > of > the current domain) that MS interop assembly is loaded as well: > > private void app_domain_AssemblyLoad(object sender, AssemblyLoadEventArgs > args) > { > Assembly loadedAssembly = args.LoadedAssembly; > logger.Debug("Assembly {0} is loaded from: {1}", > loadedAssembly.FullName, loadedAssembly.GlobalAssemblyCache ? "GAC" : > loadedAssembly.Location); > } > > Output: > > Assembly Microsoft.Office.Interop.Outlook, Version=12.0.0.0, > Culture=neutral, PublicKeyToken=71e9bce111e9429c is loaded from: GAC > > My OnConnection method starts like this: > > public void OnConnection(object application, Extensibility.ext_ConnectMode > connectMode, object addInInst, ref System.Array custom) > { > Type type = application.GetType(); > logger.Debug("OnConnection application object's full type is: {0}", > type.AssemblyQualifiedName); > > Outlook.Application applicationObject = > (Outlook.Application)application; > > This outputs: > > OnConnection application object's full type is: > Microsoft.Office.Interop.Outlook.ApplicationClass, > Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, > PublicKeyToken=71e9bce111e9429c > > This is really weird, as you can see that on the next line I can > successfully cast to Outlook.Application without any problems. > > I have checked with Reflector, and my assembly DOES NOT reference > Microsoft's interop assemblies in any way. Same for my > Interop.Outlook.dll. > > So, does someone knows what's going on? What is the answer for these > questions: > > 1. Why it loads the Microsoft assemblies at all? > 2. How it is possible to cast between unrelated classes/interfaces, > defined > in different assemblies? > >
|
|
"Phil Wilson" wrote:
[Quoted Text] > I'm not an expert in this area, but I think the issue here is basically that > Microsoft's interop asemblies aren't just official, they're primary, and > that makes a big difference. So maybe your interop assembly is behaving like > a client app, and that means it must go through the Office PIAs. Instead of > "you->Your interop assembly->COM class" it's "you->Your interop > assembly->Office PIA->COM class", or something like that. The PIAs are > installed so Office is going to insist that they be used instead of yours. > Whether all that actually works properly, who knows. One of the reasons for > PIAs is that if everyone uses them the types are common and can be shared > between different assemblies. Anyway, just my thoughts. >
Hi Phil, thanks for the answer, but if this is the case, there should be "official" way to define such a behavior for one's own COM classes as well, and I could not find anything like this. I.e. something, which informs the system what interop assembly to use for any given COM class. Or do you think this is internal functionality of Outlook/Office itself?
Thanks Sunny
|
|
|