|
In this article, I'm going to walk through the first steps involved in preparing an otherwise mild-mannered application for that jump into the phonebooth, whereupon it will exit the phonebooth as Superman...er.. no...maybe just an Add-In-Aware application.
using System;
using System.Collections.Generic;
using System.Text;
using System.AddIn.Contract;
using System.AddIn.Contract.Automation;
using System.Runtime.Remoting;
using Microsoft.VisualStudio.Tools.Applications.Contract;
using Microsoft.VisualStudio.Tools.Applications; // the SDK sample walkthrough forgets this!!
namespace AddInHostDemo.Extensibility
{
public class HostItemProvider : ContractAdapterBase,
IHostItemProviderContract
{
private HostedApplicationRoot _application;
public HostItemProvider(HostedApplicationRoot application,
TypeInfrastructureManager typeInfrastructureManager)
: base(typeInfrastructureManager)
{
_application = application;
}
protected override IContract QueryContract(string contractIdentifier)
{
if (string.Compare(contractIdentifier,
typeof(IHostItemProviderContract).AssemblyQualifiedName,
StringComparison.Ordinal) == 0)
{
return (IContract)this;
}
return base.QueryContract(contractIdentifier);
}
public IRemoteObjectContract GetHostObject(string objectType,
string cookie)
{
if (string.Compare(objectType,
typeof(AddInHostDemo.HostedApplicationRoot).FullName,
StringComparison.Ordinal) == 0)
{
RemoteObjectAdapter adapter = new RemoteObjectAdapter(
typeof(AddInHostDemo.HostedApplicationRoot),
_application,
TypeInfrastructureManager);
return adapter;
}
throw new ArgumentOutOfRangeException();
}
// plumbing methods, included in ShapeApp sample as-is
protected override string RemoteToString()
{
return this.ToString();
}
protected override int GetRemoteHashCode()
{
return this.GetHashCode();
}
protected override bool RemoteEquals(IContract contract)
{
if (contract == null)
return false;
if (!System.Runtime.Remoting.RemotingServices.IsObjectOutOfAppDomain(contract))
{
HostItemProvider contractAdapter =
contract as HostItemProvider;
return this.Equals(contractAdapter);
}
return false;
}
}
}
ContractAdapterBase is a class from which all host item providers must inherit. I won't go into too much detail here - for all of the classes that I mention in these articles that are part of the VS 2005 SDK, you can check them out in the SDK documentation. While I'm finding that the walkthrough for AddIns in the SDK basically sucks, the per-class reference sections are actually quite informative. QueryContract returns a host item provider contract. GetHostObject is responsible for returning the appropriate host object. You'll note that in the above case, I return the _application instance whenever the client (AddIn) requests an object with a fully qualified name that matches the fully qualified name of that type. If they didn't ask for that, I defer the request to the parent object. As much as I hate to see it, this entire scenario is very COM-ish. That fact bothers me. It grates on every nerve I own, and a couple that I'm borrowing. It makes the hair on the back of my neck stand up... making me wish I could reach back there to shave it... This is 2006 here people, can we please put all of the COM metaphors, similies, hyperboles, and haikus in the grave where they belong?!?!?!
The next class to create is the ApplicationExtension class. This is kind of a catch-all utility class. This class is going to contain the wrapper and helper methods that the application will use in order to load AddIns. To load AddIns, this application is going to scan a specific directory for all .dll files, and then use the System.AddIn namespace and Add-In management capabilities from the SDK to load the AddIns. Add the ApplicationExtension class to the Extensibility folder in your WinForms app:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Tools.Applications;
using Microsoft.VisualStudio.Tools.Applications.Contract;
using System.IO;
namespace AddInHostDemo.Extensibility
{
public class ApplicationException
{
private HostedApplicationRoot _application;
private Context _addInContext;
private AddInCollection _addInCollection;
private IHostItemProviderContract _itemProvider;
private string _addInPath;
private TypeInfrastructureManager _typeInfrastructureManager;
internal ApplicationExtension()
{
InitializeTypeInfrastructureManager();
}
internal void Connect(HostedApplicationRoot application)
{
_application = application;
_itemProvider = new HostItemProvider(
_application, _typeInfrastructureManager); // differs from the SDK walkthrough..
// more design guideline violations
_addInPath = Path.Combine(
System.Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments),
@"AddInHostDemo\AddIns");
LoadAddIns();
}
public void LoadAddIns()
{
if (!Directory.Exists(_addInPath))
return;
if (_addInContext == null)
{
_addInContext = new Context("Application", _itemProvider);
_addInCollection = new AddInCollection();
_addInContext.Add(_addInCollection);
}
string[] addInDirectoryNames =
Directory.GetDirectories(_addInPath);
foreach (string addInDirectoryName in addInDirectoryNames)
{
string addInShortName = string.Format("{0}.dll",
Path.GetFileName(addInDirectoryName));
string addInFullName = Path.Combine(
addInDirectoryName, addInshortName);
if (!File.Exists(addInFullName))
continue;
AddIn addIn = new AddIn(addInShortName, addInFullName);
_addInCollection.Add(addIn);
addIn.Load(addInDirectoryName);
}
}
internal TypeInfrastructureManager TypeInfrastructureManager
{
get { return _typeInfrastructureManager; }
}
private void InitializeTypeInfrastructureManager()
{
if (_typeInfrastructureManager == null)
_typeInfrastructureManager = Microsoft.VisualStudio.Tools.Applications.ProxyServices.
Helper.CAddInHostDemoInitializer.CreateTypeInfrastructureManager();
}
}
}
In a nutshell, this is the code that the main application form is going to call when the application starts up to scan through a directory and load all of the DLLs into the AddIn management system that is now part of the SDK, and will actually be a part of the core framework during the "Orcas" timeframe. Note the bolded, italicized, underlined, red text above. Anybody recognize a naming convention that is not part of the .NET Framework and belongs in the MFC graveyard from whence the necromancer revived it!?!? I do. This one wins the "WTH??!?" award of the day. As you'll see in a second, you run the proxygen.exe tool to create proxies, but you also use it to create what is called a host map, which is a class that contains a little helper class that initializes the type infrastructure manager (a fancy way of referring to a type map dictionary manager). The class that it generates for you is prefixed with a C, MFC-style.
So, to create the CAddInHostDemoInitializer class via proxygen, issue the following command-line from the \Program Files\Visual Studio 2005 SDK\2006.04\VisualStudioToolsForApplications\Tools\Proxygen\x86 directory (the 2006.04 refers to the CTP I'm using):
proxygen /l:"c:\blah\blah\blah-to-your-project\bin\debug\AddinHostDemo.exe" /h:HostMap.cs
Note that you need a compiled executable. Hopefully you built the app before this article and have an EXE handy. Note that you do not need a host item provider in your application to generate proxies or a host map, host item providers are an entirely runtime necessity. Now add that class as an "existing item" to the Extensibility folder of your main app. Rebuild, and you should have a compiled app that pretty much does nothing useful at this point.
At this point, you should have an Extensibility folder with the HostItemProvider.cs and ApplicationExtension.cs classes contained within it. You have not yet generated any client proxies, or a visual studio project template, or registered the application as an AddIn host. I took up more space on this blog post than I expected, so I will defer the host registration and proxy generation to the next post.
Your article can be more valuable for all worldwide community if you don't
use slangs and non technical words. It's so hard to us understand this
flowery text...
LOL- it's nice to see a little humor in the technobabble. Very nice.