Adding the Office 2003 Primary Interop Assembly (PIAs) as a prerequisite to a Visual Studo 2005 Setup Project October 27, 2006
Posted by codinglifestyle in C#, Office.Tags: interop, Office, PIA
5 comments
Assuming you have wronged someone and karma has dictated you will write an Office Add-in a nicety, nay necessity, for your setup file is the PIA 2003 prerequisite. Interestingly you may google for information and find multiple hits that go something like: simply go to setup properties and “in the list of prerequisites, select Microsoft Office 2003 Primary Interop Assemblies and Microsoft Visual Studio Tools for Office Runtime“. I was not so lucky and my install of VS2005 Team Edition did not seem to include this for me. As I mentioned, if you are writing an Office add-in chances are you’re not very lucky to begin with. So I had to find out how to so this manually and want to share this information with my unlucky brethren.
Luck aside; let’s manually add a prerequisite for 2003 PIA to our setup project.
In this fantastically memorable directory you will find your pre-installed prerequisites: C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages
You will be pleased to know that you may generate your own prerequisite packages with the Bootstrapper Manifest Generator. However, it’s a bit much to explain that tool here plus, in this case, it doesn’t do everything we need it to (although it comes close).
So let’s do this thing manually.
- Create a directory called “Office 2003 PIA”
- In this directory create a subdirectory called “en”
- In \Office 2003 PIA\en create a file called package.xml
<?xml version=“1.0“ encoding=“utf-8“?>
<Package Name=“DisplayName“ Culture=“Culture“ xmlns=“http://schemas.microsoft.com/developer/2004/01/bootstrapper“>
<Strings>
<String Name=“Culture“>en</String>
<String Name=“DisplayName“>Office 2003 PIAs</String>
<String Name=“Anunexpected“>An unexpected exit code was returned from the installer. The installation failed.</String>
</Strings>
</Package>
- Back in \Office 2003 PIA create a file called product.xml
<?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.PIA.2003“
>
<RelatedProducts>
<DependsOnProduct Code=“Microsoft.Net.Framework.2.0“ />
</RelatedProducts>
<!– Defines the list of files to be copied on build. –>
<PackageFiles>
<PackageFile Name=“O2003PIA.msi“/>
<PackageFile Name=“PIACheck.exe“/>
</PackageFiles>
<InstallChecks>
<!– External check for primary interop assemblies (PIAs). –>
<!–
PIACheck.exe checks whether primary interop assemblies (PIAs) are installed.
PIACheck.exe returns 0 if the PIA components specified at the command line are installed.
For example, use the following command lines to check for a certain PIA component:
Microsoft Office Excel PIA : PIACheck.exe {A1FE0698-609D-400F-BF10-F52238DD6475}
Microsoft Office Word PIA : PIACheck.exe {1C8772BD-6E6F-4C9D-8FF8-B5EA072F86EF}
Microsoft Office Outlook PIA : PIACheck.exe {14D3E42A-A318-4D77-9895-A7EE585EFC3B}
Microsoft Office Smart Tag PIA : PIACheck.exe {53C65973-D89D-4EA0-8567-8788C14E0A02}
This product.xml sample checks for the Microsoft Office Excel PIA, the Microsoft Office Word PIA,
the Microsoft Office Outlook PIA, and the Microsoft Office Smart Tag PIA.
To check for only one or two Microsoft Office PIAs, remove one or more of the arguments passed to
the PIACheck.exe application.
To check for another PIA, add the corresponding component code to the arguments passed to the
PIACheck.exe application.
–>
<ExternalCheck
Property=“PIAsRegistered“
PackageFile=“PIACheck.exe“
Arguments=“{A1FE0698-609D-400F-BF10-F52238DD6475} {1C8772BD-6E6F-4C9D-8FF8-B5EA072F86EF} {14D3E42A-A318-4D77-9895-A7EE585EFC3B}“/>
</InstallChecks>
<!– Defines how to run the Setup package. –>
<Commands Reboot=“Defer“>
<Command PackageFile=“O2003PIA.msi“
Arguments=“”
EstimatedInstalledBytes=“30000000“
EstimatedInstallSeconds=“60“
>
<InstallConditions>
<!–
This sample product.xml file checks for Microsoft Office Excel, Microsoft Office Word, and
Microsoft Office Outlook applications.
Remove one or more of the following lines to check for only one or two Microsoft Office
applications.
–>
<BypassIf Property=“PIAsRegistered“ Compare=“ValueEqualTo“ Value=“0“/>
<FailIf Property=“AdminUser“ Compare=“ValueEqualTo“ Value=“false“ String=“AdminRequired“/>
</InstallConditions>
<ExitCodes>
<ExitCode Value=“0“ Result=“Success“/>
<DefaultExitCode Result=“Fail“ FormatMessageFromSystem=“true“ String=“GeneralFailure“ />
</ExitCodes>
</Command>
</Commands>
</Product>
- Start VS2005 and create a new C++ console application called PIACheck.exe (or copy the text below to a file called PIACheck.cpp and from the VS2005 command line run: cl.exe PIACheck.cpp)
//———————————————————————–
//
// 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.
//———————————————————————–
#define WIN32_LEAN_AND_MEAN
// Windows header files.
#include
#include
// C runtime header files.
#include
#include
// Functions used from msi.dll.
typedef INSTALLSTATE (WINAPI *FMsiLocateComponent) (LPCTSTR, LPTSTR, DWORD*);
#ifdef UNICODE
#define FUNCNAME_MsiLocateComponent “MsiLocateComponentW”
#else
#define FUNCNAME_MsiLocateComponent “MsiLocateComponentA”
#endif
// The application checks whether primary interop assemblies (PIAs) are installed.
// Returns 0 if the PIA components specified at the command line are installed.
// For example, use the following command lines to check for a certain product:
// – ‘PIACheck.exe {A1FE0698-609D-400F-BF10-F52238DD6475}’ // Microsoft Office Excel PIA component
// – ‘PIACheck.exe {1C8772BD-6E6F-4C9D-8FF8-B5EA072F86EF}’ // Microsoft Office Word PIA component
// – ‘PIACheck.exe {14D3E42A-A318-4D77-9895-A7EE585EFC3B}’ // Microsoft Office Outlook PIA component
int APIENTRY _tWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UINT errCode = 0;
HMODULE hMsiLib = LoadLibrary(_T(“MSI.DLL”));
if (hMsiLib == NULL)
{
errCode = GetLastError();
if (errCode == 0) // make sure the error code is not 0
errCode = ERROR_MOD_NOT_FOUND;
}
else
{
FMsiLocateComponent pfnMsiLocateComponent = (FMsiLocateComponent)GetProcAddress(hMsiLib, FUNCNAME_MsiLocateComponent);
if (pfnMsiLocateComponent == NULL)
{
errCode = GetLastError();
if (errCode == 0) // make sure the error code is not 0
errCode = ERROR_PROC_NOT_FOUND;
}
else
{
// Loop through the specified components in the arguments.
for (int i = 1; i < __argc; i++)
{
LPCTSTR szComponentCode = __targv[i];
INSTALLSTATE state = (*pfnMsiLocateComponent)(szComponentCode, NULL, 0);
if (state != INSTALLSTATE_LOCAL)
{
errCode = ERROR_UNKNOWN_COMPONENT;
break;
}
}
}
}
if (hMsiLib != NULL)
{
FreeLibrary(hMsiLib);
}
return errCode;
}
- Copy PIACheck.exe to \Office 2003 PIA
- Lastly download o2003pia.msi and put a copy in \Office 2003 PIA
The download containing much of this information can be obtained here.
Looks painful, but really read through this slowly and with a little cut and paste you will have this installed in 10 minutes. Now you will be able to right click the project, select Prerequisites, and simply check Office 2003 PIAs. What this will do it ensure the PIAs are installed given the user runs the setup.exe from your setup. What it won’t do is anything at all if they run the msi file directly. Remember, setup.exe is our bootstrapper which runs these wonderful prerequisites. So if you want to be absolutely sure all your bases are covered and there is no room for error you will want to also add launch conditions to your setup project which will prohibit installation if the PIAs aren’t installed even if they run the msi file directly. There is an article on this here and another here, but for ease I will simply copy the necessary steps so everything is in one place.
Adding Launch Conditions to the .msi File
Recall that when the user runs Setup.exe, Windows Installer checks for the prerequisites and installs them if necessary. Alternatively, the user can double-click the .msi file to install the solution. In that case, the prerequisites are not installed and the solution cannot run. In other cases, Setup might fail because resources it needs are not present; for example, custom actions might require the .NET Framework.
This section shows you how to use the Launch Conditions editor to add launch conditions to the .msi file to prevent installation, if certain dependencies are not installed.
To view the Launch Conditions editor
1. In Solution Explorer, right-click [your Office Add-In Setup] node.
2. Point to View on the shortcut menu, and then click Launch Conditions.
To create a launch condition to search for four primary interop assemblies, you must create four separate search conditions (one for each primary interop assembly), and then one launch condition that logically combines the four search conditions.
To add a search condition for the Excel 2003 primary interop assembly
1. In the Launch Conditions editor, right-click Search Target Machine, and then select Add Windows Installer Search.
2. Select the newly added search condition, Search for Component1.
3. Rename the search condition to Search for Excel 2003 PIA.
4. In the Properties window, type {A1FE0698-609D-400F-BF10-F52238DD6475} into the ComponentId property.
5. In the Properties window, change the value of Property to COMPONENTEXISTS_EXCEL_PIA.
To add a search condition for the Outlook 2003 primary interop assembly
1. In the Launch Conditions editor, right-click Search Target Machine, and then select Add Windows Installer Search.
2. Select the newly added search condition, Search for Component1.
3. Rename the search condition to Search for Outlook 2003 PIA.
4. In the Properties window, type {14D3E42A-A318-4D77-9895-A7EE585EFC3B} into the ComponentId property.
5. Change the value of Property to COMPONENTEXISTS_OUTLOOK_PIA.
To add a search condition for the Word 2003 primary interop assembly
1. In the Launch Conditions editor, right-click Search Target Machine, and then select Add Windows Installer Search.
2. Select the newly added search condition, Search for Component1.
3. Rename the search condition to Search for Word 2003 PIA.
4. In the Properties window, type {1C8772BD-6E6F-4C9D-8FF8-B5EA072F86EF} into the ComponentId property.
5. Change the value of Property to COMPONENTEXISTS_WORD_PIA.
To add a search condition for the Smart Tag primary interop assembly
1. In the Launch Conditions editor, right-click Search Target Machine, and then select Add Windows Installer Search.
2. Select the newly added search condition, Search for Component1.
3. Rename the search condition to Search for Smart Tag PIA.
4. In the Properties window, type {53C65973-D89D-4EA0-8567-8788C14E0A02} into the ComponentId property.
5. Change the value of Property to COMPONENTEXISTS_SMART_TAG_PIA.
To create a launch condition for the primary interop assemblies
1. In the Launch Conditions editor, right-click Launch Conditions, and then select Add Launch Condition.
2. Select the newly added launch condition, (Condition1).
3. Rename it to Display message if the Primary Interop Assemblies are not installed.
4. In the Properties window, change the value of the Condition property to COMPONENTEXISTS_EXCEL_PIA AND COMPONENTEXISTS_OUTLOOK_PIA AND COMPONENTEXISTS_WORD_PIA AND COMPONENTEXISTS_SMART_TAG_PIA.
5. In the Properties window, [set the InstallURL to http://www.microsoft.com/downloads/details.aspx?familyid=3c9a983a-ac14-4125-8ba0-d36d67e0f4ad&displaylang=en].
6. Change the value of the Message property to [The Office 2003 Primary Interop Assemblies have not yet been installed. Please click ‘Yes’ to download them now or click ‘No’ to exit. ]
At long last, you have a bullet proof installer for your Office Add-in. And the good news is you’ll be able to add the prerequisite to setup.exe next time with just a simple click.
PS: If anyone knows of a simple download to install this prerequisite or perhaps where I went wrong and why mine wasn’t there in the first place please let me know.
Outlook 2003 Add-in and ActiveSync July 5, 2006
Posted by codinglifestyle in C#, Office.Tags: interop, multiple instances, Office, OnConnection
add a comment
Recently I found myself doing emergency maintenance on an Outlook 2003 add-in. The add-in did little more than add a button to the standard toolbar when certain conditions were met. One issue I discovered purely by accident was the effect on ActiveSync on such an add-in. I discovered this when I shut down Outlook in-between debugging sessions and plugged in my Windows mobile phone for a recharge. When I brought Outlook back up my add-in was nowhere to be found. The issue is when another program, such as ActiveSync, initializes a headless instance of Outlook via COM (aka no GUI). The result is the add-in is already loaded in memory from the COM instance so initialization which was looking for some GUI component, in my case a toolbar, fails. It is necessary to reevaluate our initialization code in order to handle the case of these GUI-less instances of Outlook. Most standard examples show adding toolbar buttons during the OnConnection event. If a headless COM instance of Outlook is running ActiveExplorer will return null and most likely the initialization will fail. As this event is only fired once, subsequent instances will never be initialized. In order to catch new instances of Outlook we need to register for the NewExplorer event in OnConnection. Then, in case this first instance is the Outlook we’re looking for try our initialization. Last, when catching new explorers attempt to initialize those as well. The end result is initialization is run for every instance of Outlook and you can guarantee your add-in will be initialized.
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
m_appObj = (Microsoft.Office.Interop.Outlook.Application)application;
m_addInInstance = addInInst;
Trace.WriteLine(“Outlook add-in: OnConnection”);
try
{
Outlook.ExplorersClass explorers = (Outlook.ExplorersClass )m_appObj.Explorers;
explorers.NewExplorer +=new Microsoft.Office.Interop.Outlook.ExplorersEvents_NewExplorerEventHandler(explorers_NewExplorer);
m_appObj.Startup +=new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_StartupEventHandler(m_appObj_Startup);
//Try to initialize
InitAddIn(m_appObj.ActiveExplorer());
}
catch (Exception ex)
{
Trace.WriteLine(“Outlook add-in error: ” + ex.Message);
}
}
private void explorers_NewExplorer(Microsoft.Office.Interop.Outlook.Explorer Explorer)
{
Explorer.Activate();
InitAddIn(Explorer);
}