Outlook Add-in project or C# class library?

J

JoelB

I've inherited an Outlook add-in that was originally created as a VB class
library project maybe eight years or so ago. It has evolved since then, but
is still in a VB class library project. We're standardizing on C# so we're
considering translating it, and as long as we're doing that anyway, I'm
wondering if we shouldn't do it as an Outlook 2007 Add-in project instead of
a Class Library project. Can anyone pipe in with any pros or cons to doing
that?

A few other considerations:

1. We're planning to add interaction with SQL Server 2008 (probably via
Linq/EF);
2. We're probably going to try interacting with MOSS lists/libraries as well
(still looking into how to do this); and,
3. Most of our users are on Outlook 2007, but we still have a few on 2003
(if that's a deal breaker for an otherwise ideal solution, we might be able
to force everyone to move to 2007).

TIA,
Joel
 
K

Ken Slovak - [MVP - Outlook]

All COM addins are DLL's so whatever you do will have to end up as an addin
dll explicitly supporting the Extensibility interface or using VSTO (which
uses that interface under the hood).

You can use the same addin, compiled under Outlook 2003 on that and 2007.
However you have to take special precautions then to handle the 2007 Ribbon.
Google for some blog entries by Andrew Whitechapel of the VSTO team on using
PIA-less addins, he has the information needed to do that without having to
reference the Office 2007 PIA's.

As a side note I've done many dual interface addins that support both 2003
and 2007 and use the CommandBars or Ribbon depending on Outlook version with
no problems.

There is more than just line by line translation to think of, that's almost
the least part of a port. Many things have changed in the last 8 years and
new ways of handling things have been discovered. In addition, managed code
is far less forgiving than VB6 code and will fire more exceptions and
requires special handling for exceptions, null entries and fields, release
of COM objects, etc.

I find that just porting any of my VB6 addins to C# (or any managed code)
usually ends up being 2x as many code lines as the old VB6 code.

No matter how you do it you also need to use shimming so your managed code
addin is in its own AppDomain. VSTO does that for you, the COM Shim Wizard
is used for shared addins.

If this is your first Outlook managed code addin figure on it taking about
4 - 5 times as long as you expect, to account for all that you will need to
learn and all the time it will take.
 
J

JoelB

Hi, Ken---thanks for your quick reply.

I'll continue my learning curve just working to understand the things you
brought up in your email! :) From what experience I have, your post seems
like a treasure trove; last month we put out a managed version targeting .NET
3.5:

- releasing COM objects was a huge issue (using Marshal.ReleaseComObject
and frequent garbage collection calls seems to have helped)
- the add-in wouldn't run on one user's machine, and the cause turned out
to be another add-in that was failing under mscoree (evidently we're not
using a shim)
- we're *still* getting sporadic null-exceptions

So, we've already done some of the work on moving to managed code. I guess
the main difference now is that it's using IDTExtensibility2 instead of VSTO.

Questions:

- Is there any question about whether we should move to VSTO, or is
definitely the way to go?

- I gather that using a C# add-in project implies moving from
IDTExtensibility2 to VSTO?

- Are there any cons to moving to a C# add-in project type, given what
we're working toward (SQL/SharePoint interaction, etc.)?

Thanks for your input.

Joel
 
K

Ken Slovak - [MVP - Outlook]

You can program any managed code addin (shared or VSTO) using C# (or
VB.NET), it's up to you as to language choice. My experience is customer
requests run about 90% C# and about 10% VB.NET.

VSTO is still going to use extensibility, it just handles that for you and
provides you with Startup() and Shutdown() events. It also builds in a shim
loader. A shared addin is more "naked", you write your own extensibility
event handlers and provide your own shim (using the shim wizard). Same
results in either case.

I prefer myself to use shared addins, but I like the "naked" approach that
gives me more control. Your mileage may vary. Unshimmed, any addins in that
AppDomain (the default) will end up disabling any others there if there are
unhandled exceptions or if one crashes or hangs Outlook. With your own
shimmed AppDomain you only disable your own addin in those cases and vice
versa.

When and how to release COM objects is confusing and there's lots of
contradictory information out there. When to just set an object == null and
when to use Marshal.ReleaseComObject() and how often to call it and if to
call GC.Collect() also depends on lots of things.

Calling ReleaseComObject() will release the RCW for that object. If the
object is being shared between modules or classes then once the RCW is
released any attempt to access the object will fire an exception unless you
instantiate that object all over again from scratch. So you have to be very
cognizant of where and how your objects are being used.

I've done lots of SQL and SharePoint stuff with both C# and VB.NET and with
both shared and VSTO addins. No difference to me other than language used,
that's up to what you're most comfortable with.
 
S

SvenC

Hi Joel,
Hi, Ken---thanks for your quick reply.

Ken answered almost everything.
- releasing COM objects was a huge issue (using Marshal.ReleaseComObject
and frequent garbage collection calls seems to have helped)

But here I'd like to add something:

Use ReleaseComObject calls like Dispose or Close, i.e. always call it when
you are done with a COM object. Also beware of not releasing temporary
COM objects which are easily created when exposed as properties or
return values. Something like ObjectX.SomeProp.AnyProp.Value.
SomeProp and AnyProp will create COM Objects which you did not
put in a variable hence you cannot call ReleaseComObject on them.
Another goodie is to call those properties over and over again instead
of calling them once and storing them in a separate variable (on which
you call ReleaseComObject when done).

I think it was a big oversight of Microsoft to not make the COM wrappers
inherit IDisposable. using blocks would have a big time/keyboard saver.

BUT: whenever you think you need a GC.Collect you should really think
harder if there is not some issue in your code which you should fix - like
forgetting to call Dispose and Close on objects which hold on to
resources. A manual call to GC.Collect should hardly ever be necessary.
It might be a workaround but it tends to hide your real bug
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top