Dynamically load and use COM object in C#
Asked Answered
M

2

4

I have a C# project, where I would like to access MS outlook, if it is installed on a client´s machine. The "access outlook" part has been done by referencing the outlook COM object, and going from there. My problem is now the "if it is installed" part. At the moment, my project doesn´t compile on machines without outlook installed, so I assume that I will have to not reference the outlook component, and instead load and use it dynamically, after detecting that outlook is present, but I haven´t found a way to do this. Am I correct, and does anybody have any hints on how to do this?

Thanks.

Edit: Resolved. Following the advice given by Hans Passant in one of the comments about using the office PIAs, proved to be the path of least resistance. I had a little difficulty getting the PIAs on my office-less machine, but it was overcome using the accepted answer to this question.

Moisten answered 18/2, 2011 at 12:45 Comment(4)
Ciao Boris, I fear you are mixing development environment with deployment env. in Development you should reference proper assemblies and these assemblies should be available to build the code. In production you don't have to build anything but your program will require outlook to be installed.Canonical
@Davide Piras: I think you are overusing your edit and re-tag privileges...King
I had done some tag cleanup because for example in this case, I believe we do not need both com and com-interop tags... sorry if I was wrong Boris.Canonical
@Davide Piras: No problem. I am not entirely sure what tags I started out giving this, but I don´t think I had com-interop, as I also do not see a need for both. I do not object to the current four tags, but I would like to add some tag that indicated that the question was specifically about loading a COM object based on its availability. I don't know which tag this should be, though.Moisten
M
1

Following Hans Passant's advice, I now answer my own question with details of my solution. I was able to both compile and run my project on a computer without office installed. The primary problem was to let visual studio know, which interface it could expect from the COM object. This was solved by finding a primary interface assembly (PIA) file for outlook. That process is better described in this question, but the short story is that I already had the office PIAs on my computer, in this location:

C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA

I use VS2010 pro, I don't know if the files are included with other versions. It was then a matter of copying the relevant file to my project source folder, including it in my project and source control, and making a reference to it. After that, I was able to use Outlook COM types in my project and compile it without error. I am also able to run my project without office installed. This is achieved by trying to instantiate the relevant COM objects, and catching the exception if office is not installed. The following sample code shows how:

using Outlook = Microsoft.Office.Interop.Outlook;

namespace Foo
{
    public class Bar
    {
        public void Quux()
        {
            try
            {
                // try to instantiate outlook COM object.
                Outlook.Application outlookApp = new Outlook.Application();

                // if it works, fine. Proceed
                ...
            }
            // If we catch a COMException, assume no office installed. Deal accordingly.
            catch (System.Runtime.InteropServices.COMException)
            {
                ...
            }
        }
    }
}
Moisten answered 14/3, 2011 at 12:48 Comment(1)
You can even work without using Outlook = Microsoft.Office.Interop.Outlook; I've been doing that with Excel and Access. That way there will be absolutely no installation of MS Office needed. You will of course have to work completely blind. No code completion (for Outlook objects), no usefull compile errors etc.Hedonic
I
2

You definitely won't be able to compile your assembly on a machine without the Outlook COM object being present, but that doesn't mean that your application will completely fail to work on a machine without Outlook - just that attempting to create or use the Outlook COM object will result in a failure / exception being thrown.

According to this question the best way of detecting whether or not a COM object is present is simply attempting to instantiate it and catching the resulting exception in the case where it is not installed.

Insider answered 18/2, 2011 at 13:37 Comment(3)
Thanks. I was unsure of when the COM object was actually loaded, but vaguely believing that the code for the object would be loaded at program load time, not at object instantiation time, and so in my mind, I wasn´t sure how to catch that. Just to be sure, is it behavior standard for COM objects and assemblies to be loaded only when one of their classes are used?Moisten
You definitely can, that's what type libraries are meant to do. Pretty essential, you might not want to target the version you've got installed for example. MSOutl.olb from the Office install directory, copy it to your project directory. Or install the Office PIA.Collide
@Hans Passant: Thanks, your advice was what I ended up following. If you make this an answer, I will accept it.Moisten
M
1

Following Hans Passant's advice, I now answer my own question with details of my solution. I was able to both compile and run my project on a computer without office installed. The primary problem was to let visual studio know, which interface it could expect from the COM object. This was solved by finding a primary interface assembly (PIA) file for outlook. That process is better described in this question, but the short story is that I already had the office PIAs on my computer, in this location:

C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA

I use VS2010 pro, I don't know if the files are included with other versions. It was then a matter of copying the relevant file to my project source folder, including it in my project and source control, and making a reference to it. After that, I was able to use Outlook COM types in my project and compile it without error. I am also able to run my project without office installed. This is achieved by trying to instantiate the relevant COM objects, and catching the exception if office is not installed. The following sample code shows how:

using Outlook = Microsoft.Office.Interop.Outlook;

namespace Foo
{
    public class Bar
    {
        public void Quux()
        {
            try
            {
                // try to instantiate outlook COM object.
                Outlook.Application outlookApp = new Outlook.Application();

                // if it works, fine. Proceed
                ...
            }
            // If we catch a COMException, assume no office installed. Deal accordingly.
            catch (System.Runtime.InteropServices.COMException)
            {
                ...
            }
        }
    }
}
Moisten answered 14/3, 2011 at 12:48 Comment(1)
You can even work without using Outlook = Microsoft.Office.Interop.Outlook; I've been doing that with Excel and Access. That way there will be absolutely no installation of MS Office needed. You will of course have to work completely blind. No code completion (for Outlook objects), no usefull compile errors etc.Hedonic

© 2022 - 2024 — McMap. All rights reserved.