Add-in Express™ for Microsoft® Office and .netAdd-in Express Home > Add-in Express for Office and .NET > Online Guide > Tips and notes > Development tips
Office extensions development: tips and tricks
You might have an impression that building add-ins is a very simple task. Please don't get too enthusiastic. Sure, Add-in Express
for Office and .net makes embedding your code to Microsoft Office applications very simple, but you are to write the application code yourself,
and we guess it would be something more intricate than a single call of MessageBox. On this page you will find some tips and tricks that hopefully will be helpful.
Supporting several Office versions in the same project
There are two aspects of this theme:
- Supporting the CommandBar and Ribbon UI in one project
- You can add both Command Bar UI and Ribbon UI components
onto the add-in module. When your add-in is loaded in a particular version
of the host application, either command bar or ribbon controls will show up. Find additional information in
Command bars in the Ribbon UI.
- Accessing version-specific features of an Office application
Choosing interop assemblies
An Office interop assembly provides the compiler with early-binding information on COM interfaces contained in a given Office
application (COM library) of a given version. That's why there are interops for Office 2003, 2007, 2010.
Because Office applications are almost 100% backward compatible, you can still use any interop version to access any version
of the host application. There are two things worth mentioning:
When using an interop for an arbitrary Office version, you are required to check the version of the Office application that
loads your add-in before accessing two kinds of things: a) that introduced in a newer Office version and b) that missing in an
older Office version. For instance, consider developing an Outlook add-in using the Outlook 2003 interop; the add-in must support
Outlook 2000 - 2010. Let's examine accessing two properties of the MailItem class: a) MailItem.Sender introduced
in Outlook 2010 and b) MailItem.BodyFormat introduced in Outlook 2002.
Since our add-in uses the Outlook 2003 interop, you cannot just write sender = theMailItem.Sender in your code:
doing this will cause a compile-time error. To bypass this, you must write a code that checks if the add-in is loaded in
Outlook 2010 and use late binding to access that property. "Late binding" means that you use Type.InvokeMember();
look at this article on MSDN or search
for samples on our .NET forum.
Since MailItem.BodyFormat is missing in Outlook 2000, you cannot just write bodyFormat = theMailItem.BodyFormat:
doing this will fire a run-time exception when your add-in is loaded in Outlook 2000. To bypass this, you must write a code that
checks if the add-in is loaded in Outlook 2000 and avoid accessing that property in this case.
The following questions are discussed in the
Supporting several Office versions in an add-in. Interop assemblies and late binding article on our technical blog:
- What interop assembly to choose for your add-in project?
- How does an interop assembly version influence the development time?
- How to support a given Office version correctly?
Use the latest version of the loader
Since the code of the loader frequently changes, you must use its latest version. Whenever you install a new Add-in Express version,
you need to unregister your add-in, copy adxloader.dll and adxloader64.dll located in {Add-in Express }\Redistributables to the Loader
folder of you project; for XLL add-ins, you must also rename it to adxloader.{XLL add-in project name}.dll. After replacing the loader
must rebuild (not just build) your project and register it. If everything was done correctly, you'll see the new loader version in
adxloader.log (see Loader's log). Find some background info in
Insight of Add-in Express Loader.
Several Office versions on the machine
Although Microsoft allows installing multiple Office versions on a PC, it isn't recommended to do so. Below is a rather long citation
from an article by Andrew Whitechapel.
First, the Office client apps are COM-based. Normal COM activation relies on the registry. COM registration is a "last one wins" model.
That is, you can have multiple versions of a COM server, object, interface or type library on a machine at the same time. Also, all of these
entities can be registered. However, multiple versions can (and usually do) use the same identifiers, so whichever version was registered
last overwrites any previous one. Also, when it comes time to activate the object, only the last one registered will be activated. COM
identity at runtime depends on an object's implementation of QueryInterface, but COM identity at the point of discovery depends on GUIDs.
GUIDs are used because they provide a guaranteed (for all practical purposes) unique identifier (surprise).
As soon as you put multiple versions of a COM server/object/interface/typelib onto the same machine, you introduce scope for variability.
That is, although COM activation will ensure that the GUID-identified object gets used at the point of activation, you've set up the environment
such that the object that this GUID identifies can change unpredictably over time - even short periods of time. This is one of the many reasons
why it is very difficult to successfully develop solutions on a machine with multiple versions of Office - and one of the reasons we do not
support this. But wait, how can this be? Surely a COM interface never versions? That's true, but, first, Office interfaces are not pure COM
interfaces - they're automation interfaces, which are allowed to version (while retaining the same GUID). Second, the objects that implement
the interfaces are obviously allowed to version, as are the typelibs that describe them.
Please read the rest of the article:
Why is VS development not supported with multiple versions of Office?
How to find files on the target machine programmatically?
You can find the actual location of your files on the target PC using the following code:
System.Reflection.Assembly.GetExecutingAssembly().CodeBase
Using threads
All object models provided by Office are not thread-safe. Using an object model from a thread other than the main one may produce unpredictable
consequences. Once, we read Inspector.Count in a thread; after we stopped doing this, the users stopped complaining of a strange behavior of the
Down arrow key when composing an e-mail.
When you need to use an object model in a thread, you can bypass this by using the SendMessage method and OnSendMessage event of the add-in module.
One side of those members is described in Wait a little. The other side is that the OnSendMessage event occurs in the main thread. That is, you can
send a message from a thread and handle the message in the main thread. See also
On using threads in managed Office extensions on our blog.
Releasing COM objects
When working with COM objects, remember these two rules:
- You must never release COM objects obtained through the parameters of events provided by Add-in Express.
- You must always release COM objects retrieved by you ("manually") from any COM object.
To understand why (and how) to release COM objects, consider the following code line:
C#:
Outlook.Explorer explorer = OutlookApp.ActiveExplorer();
VB.NET:
Dim explorer as Outlook.Explorer = OutlookApp.ActiveExplorer()
That code line creates three objects: a COM object corresponding to the active Outlook Explorer window and two .NET objects. The .NET objects are:
- A Runtime-callable wrapper (RCW) that references the COM object
- A .NET object that references the RCW. This .NET object is identified in the code above as explorer.
When you set explorer to null (Nothing in VB.NET), the corresponding .NET object lives until the next run of the Garbage Collector (GC). Accordingly,
the RCW lives, too. And this means the COM object isn't released. The further course of events depends on the COM object you created and the implementation
of the COM server (it's Outlook in this example). Say, not releasing the COM object used in this example makes Outlook 2000 - 2002 hang in processes and
produces a delay in Outlook 2003 - 2007 when you close Outlook; it isn't that hard to hang Outlook 2003 and 2007, though. In Outlook 2010, they introduced
the feature called Fast Shutdown. With that feature enabled, your add-in developed for Outlook 2000 - 2007 doesn't have a chance to hang Outlook. But that
feature comes at its price: your add-in isn't notified that Outlook is shutting down. Find more details about that feature and how to deal with it in
Outlook 2010 Fast Shutdown feature published on Add-in Express blog.
To release the COM object above, you need to use the Marshal.ReleaseComObject method (System.Runtime.InteropServices namespace) as follows:
C#:
if (explorer != null) Marshal.ReleaseComObject(explorer);
VB.NET:
If explorer IsNot Nothing Then Marshal.ReleaseComObject(explorer)
An extensive review of typical problems (and solutions) related to releasing COM objects in Office add-ins is given in an article published on the
our technical blog - When to release COM objects
in Office add-ins?.
Wait-a-little
Some things aren't possible to do right at the moment; say, you can't close the inspector of an Outlook item in the Send
event of that item. A widespread approach is to use a timer. Add-in Express provides a way to do this by using the
<SendMessage> method and <OnSendMessage> event; when you call <SendMessage>, it posts the Windows
message that you specified in the methods' parameters and the execution continues. When Windows delivers this message
to an internal Add-in Express window, the <OnSendMessage> event is raised. Make sure that you filter incoming messages;
there will be quite a lot of them.
The actual names of the <SendMessage> method and <OnSendMessage> event are listed below:
<SendMessage>
- ADXAddinModule.SendMessage
- ADXOlForm.ADXPostMessage
- ADXExcelTaskPane.ADXPostMessage
- ADXWordTaskPane.ADXPostMessage
- ADXPowerPointTaskPane.ADXPostMessage
<OnSendMessage>
- ADXAddinModule.OnSendMessage
- ADXOlForm.ADXPostMessageReceived
- ADXExcelTaskPane.ADXPostMessageReceived
- ADXWordTaskPane.ADXPostMessageReceived
- ADXPowerPointTaskPane.ADXPostMessageReceived
Developing multiple Office extensions in the same project
Add-in Express supports adding several modules in a project, every module representing an Office extension. That means you can create an assembly
containing a combination of several Office extensions. Having several modules in an assembly is a common approach to developing Excel extensions;
say you can implement a COM add-in providing some settings for your Excel UDF.
What is essential is that all Office extensions will be loaded into the same AppDomain. The only exception is Excel Automation add-ins - they are
loaded into the Default AppDomain (but see What Excel UDF type to choose?).
If several Office extensions are gathered in one assembly, Office loads the assembly once but initializes the extensions in the assembly one at a time.
That is, if you have two COM add-ins in the same assembly, one of them may be still not initialized when the first one is ready to work. See also
HowTo: Create a COM add-in, XLL UDF and RTD server in one assembly.
See also Deploying Office extensions and
Accessing public members of your COM add-in from another add-in or application.
Note. If you didn't find the answer to your questions on this page, please see
the HOWTOs section:
Back to Add-in Express for Office and .NET homepage |