April, 2011

  • Akash Blogging......

    Office 2010 PIA installer does not install the Word PIA if only Outlook 2010 is installed

    • 0 Comments

    A few days ago I ran into an issue where the customer had written an add-in for Outlook 2010 and was working with the WordEditor property of the Inspector. The add-in was to be deployed to machines which had ONLY Outlook 2010 installed. Would this work?

    Yes, It should! In this case we got an exception that says that the file Microsoft.Office.Interop.Word.dll could not be found. Digging deeper into the issue we found out that it was an issue with the PIA Installer for Office 2010. The Installed did not install the Microsoft.Office.Interop.Word.dll if Word was not installed on the machine.

    Is that what the installer should be doing? NO. The Office 2007 PIA installed worked just fine and even if only Outlook was installed on the machine it installed the PIA for Outlook as well as for Word. Yes, this is an issue with the Office 2010 PIA installer and will be fixed!

    Now what? What are my options to solve the problem?

    The only two that I see are:

    1) Distribute the Microsoft.Office.Interop.Word.dll along with the setup: This is not something that we recommend. It is recommended to always install the PIA using the Official Installer. Now since the installed is not doing it’s job, look at option 2

    2) Use Late Binding: I was able to get the add-in to work without the word PIA. Writing late binding code could be a pain but it is the only other solution that worked!

    In the sample code below we are setting the subject and the body of the message to “This text was set by the add-in”. Notice the code to insert the text “This text was set by the add-in” into the body of the message late binding and WordEditor object.

    if (activeInspector.CurrentItem is Outlook.MailItem)
    {
    Outlook.MailItem mail = ((Outlook.MailItem)activeInspector.CurrentItem);
    mail.Subject = "This text was set by the add-in";

    if (activeInspector.EditorType == Outlook.OlEditorType.olEditorWord)
    {
    object wordDoc = activeInspector.WordEditor;
    object wordWin = null;

    IEnumerator wordDocEnumerator = null;

    if (null != wordDoc)
    {
    object oWindows = wordDoc.GetType().InvokeMember("Windows", System.Reflection.BindingFlags.GetProperty, null, wordDoc, null);

    if (null != oWindows)
    {
    wordDocEnumerator = (IEnumerator)oWindows.GetType().InvokeMember("GetEnumerator", System.Reflection.BindingFlags.InvokeMethod, null, oWindows, null);
    }

    if (wordDocEnumerator.MoveNext())
    {
    wordWin = wordDocEnumerator.Current;

    object oSelection = wordWin.GetType().InvokeMember("Selection", System.Reflection.BindingFlags.GetProperty, null, wordWin, null);
    oSelection.GetType().InvokeMember("TypeText", System.Reflection.BindingFlags.InvokeMethod, null, oSelection, new object[] { "This text was set by the add-in" });
    }
    else
    {
    MessageBox.Show("Could not find the word editor window to insert the text body into");
    }
    }
    }
    else
    {
    MessageBox.Show("The editor type was not word, so the add-in cannot continue");
    }
    }

    Some good articles on binding

    I will let you know when the issue with the Office 2010 PIA installed is fixed. Enjoy!

  • Akash Blogging......

    Updating Recipients using Outlook Object Model

    • 0 Comments

    One of my customers was migrating his Exchange Client Extension code to an Outlook add-in for Outlook 2010 and wanted to modify the recipient using Outlook Object Model(OOM) and ran into issues. What is the problem? In Exchange Client Extension you could hook into events like IExchExtMessageEvents::OnCheckNames and IExchExtMessageEvents::OnChecknameComplete and then from this event you would get an IExchExtCallBack interface. Using the IExchExtCallBack interface you could use the functions GetRecipients and SetRecipients to modify the recipient collection.

    The BIG question is, how can this be done using OOM?

    Unfortunately there is nothing in the Outlook Object Model that allows you to modify a recipient. We do have a workaround of first reading the existing recipients, removing the existing recipients, building a new recipient list with the changes and then adding it back to the message.

    Below is some sample C# code that demonstrated this. In this sample I first delete all the recipients from the message, build a fresh list and then add them back to the message and finally a tweak to get the UI to update.

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
    this.Application.Inspectors.NewInspector +=
    new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
    }

    private Outlook::MailItem mailItem = null;

    void Inspectors_NewInspector(Outlook.Inspector Inspector)
    {
    mailItem = Inspector.CurrentItem as Outlook::MailItem;
    if (mailItem != null) {
    mailItem.BeforeCheckNames += new Outlook.ItemEvents_10_BeforeCheckNamesEventHandler(mailItem_BeforeCheckNames);
    }
    }

    void mailItem_BeforeCheckNames(ref bool Cancel)
    {
    // In order to be able to add recipients, set their addressEntries, and have them display, we need to
    // 1) Remove ALL recipients from the message
    // 2) Re-add them, and set their address entries
    // 3) To get the UI to update, add and remove a final recipient

    // Step 1: remove all recipients
    int Count = mailItem.Recipients.Count;
    while (Count > 0) {
    mailItem.Recipients.Remove(1);
    Count = mailItem.Recipients.Count;
    }

    // Step 2: re-add them, and set their address entries
    string[] RecipentAddresses = { "test1", "testdl", "test2" };

    for (int i = 0; i < RecipentAddresses.Length; i++)
    {
    Outlook::Recipient recip = mailItem.Recipients.Add("test2");
    int addrType = recip.Type;

    Outlook::AddressEntry ae = Application.Session.AddressLists["Global Address List"].AddressEntries[RecipentAddresses[i]];
    recip.AddressEntry = ae;

    // need to set recipient type back to old value after re-adding
    recip.Type = addrType;
    recip.Resolve();
    }

    // Step 3: (only needed in some event callbacks)
    // Now addresses have changed, but sometimes the UI doesn't update until
    // we add and remove a final recipient.
    // This workaround may not be needed in the BeforeCheckNames event, but is
    // needed in some other events if updating the recipients

    mailItem.Recipients.Add("pleaseIgnore");
    mailItem.Recipients.Remove(mailItem.Recipients.Count);
    }

    Enjoy!

  • Akash Blogging......

    Problems installing the Office 2010 PIA’s using the Microsoft Office 2010 Primary Interop Assemblies Bootstrapper Package

    • 0 Comments

    Have you tried using the Microsoft Office 2010 Primary Interop Assemblies Bootstrapper Package? Did you not run into any issues? Were you able to install the PIA’s with the default package? I was not so lucky!

    One of my customer had created an add-in for Outlook 2010 and had included the Microsoft Office 2010 Primary Interop Assemblies Bootstrapper Package as part of his prerequisites for the add-in.The machine on which the add-in was being installed on did not have the PIA’s for any of the Office product installed. When the Setup.exe for the add-in was run, it still did not install the PIA’s. Why?

    After banging my head for quite a while I discovered that the componentcheck.exe was causing the issue. It always returned a value of 1. What does that mean? It means that componentcheck.exe was finding a PIA component on the machine! What was it finding when none of the PIA’s were installed?

    Componentcheck.exe checks for the following components and if it finds any one of them it returns 1.

    • Excel
    • InfoPath
    • Outlook
    • PowerPoint
    • Visio
    • Word
    • Project
    • Forms 2.0
    • Graph
    • Smart Tag
    • Office Shared

    In my case Office.dll was always there on the machine and hence componentcheck.exe was returning a value of 1. How do I get my add-in setup to install the PIA’s?

    The easiest solution is not to use the componentcheck.exe and always force the installation of the PIA’s. How can that be done? Easy…just modify the product.xml and remove the nodes for 1) PackageFile that relates to ComponentCheck.exe 2) The entire InstallChecks section as it is not needed any more 3) The BypassIf  install Condition related to PIAInstallAction and then rebuild you setup.

    Below is how the altered product.xml would look after the modification:

    <?xml version="1.0" encoding="utf-8" ?>
    <!--
    ***********************************************************************

    Copyright (C) Microsoft Corporation. All rights reserved.

    THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    PARTICULAR PURPOSE.
    ***********************************************************************
    -->
    <Product xmlns="http://schemas.microsoft.com/developer/2004/01/bootstrapper" ProductCode="Microsoft.Office.PIARedist.2010">
    <RelatedProducts>
    <EitherProducts>
    <DependsOnProduct Code="Microsoft.Net.Client.3.5" />
    <DependsOnProduct Code=".NETFramework,Version=v4.0,Profile=Client" />
    </EitherProducts>
    </RelatedProducts>
    <PackageFiles>
    <PackageFile Name="o2010pia.msi" HomeSite="Office2010PIARedistMSI"
    PublicKey="3082010A0282010100A2DB0A8DCFC2C1499BCDAA3A34AD23596BDB6CBE2122B794C8EAAEBFC6D526C232118BBCDA5D2CFB36561E152BAE8F0DDD14A36E284C
    7F163F41AC8D40B146880DD98194AD9706D05744765CEAF1FC0EE27F74A333CB74E5EFE361A17E03B745FFD53E12D5B0CA5E0DD07BF2B7130DFC606A288575
    8CB7ADBC85E817B490BEF516B6625DED11DF3AEE215B8BAF8073C345E3958977609BE7AD77C1378D33142F13DB62C9AE1AA94F9867ADD420393071E08D6746
    E2C61CF40D5074412FE805246A216B49B092C4B239C742A56D5C184AAB8FD78E833E780A47D8A4B28423C3E2F27B66B14A74BD26414B9C6114604E30C882F3
    D00B707CEE554D77D2085576810203010001"
    />
    </PackageFiles>
    <Commands Reboot="Defer">
    <Command PackageFile="o2010pia.msi" Arguments="/quiet" EstimatedInstalledBytes="7000000"
    EstimatedInstallSeconds="60">
    <InstallConditions>
    <FailIf Property="AdminUser" Compare="ValueEqualTo" Value="false" String="AdminRequired" />
    </InstallConditions>
    <ExitCodes>
    <ExitCode Value="0" Result="Success" />
    <ExitCode Value="1641" Result="SuccessReboot" />
    <ExitCode Value="3010" Result="SuccessReboot" />
    <DefaultExitCode Result="Fail" FormatMessageFromSystem="true" String="GeneralFailure" />
    </ExitCodes>
    </Command>
    </Commands>
    </Product>

    The not so easy way to do it would be to write your own componentcheck.exe and build your own logic to return 1 or 0. The source for the componentcheck.exe for office 2010 is not available but as a starting point you can use something that was available for Office 2007. The Component IDs of the Redistributable Primary Interop Assemblies for Microsoft Office 2010 can be found here.
     
    Enjoy!

Page 1 of 1 (3 items)