VSTO Outlook Addin - Why doesn't my Property Page show up?
-
Tuesday, May 23, 2006 3:32 PMWhen I click Tools|Options here's what happens:
1. The following event handler executes:
void ThisApplication_OptionsPagesAdd(Outlook.PropertyPages pages)
{
pages.Add(new ViewPoint.PropertyTab(), "");
}
2. bool m_Dirty = false;
OK, class is obviously initializing...
3. Then InitializeComponent();
OK, class is obviously initializing...
But then, that's it! No call into the TabCaption method as I would expect, to get the tab caption for the property page. And the tab doesn't appear! I have no idea what I'm doing wrong. I copied this code (see below) straight out of Visual Studio Tools for Office by Eric Carter and Eric Lippert, but I just can't get this to work!
Thanks for your help!
- Joseph Geretz -
public partial class PropertyTab : UserControl, Outlook.PropertyPage
{
const int C_CaptionDispID = -518;
bool m_Dirty = false;
public PropertyTab()
{
InitializeComponent();
}
void Outlook.PropertyPage.Apply()
{
}
void Outlook.PropertyPage.GetPageInfo(ref string helpFile, ref int helpContext)
{
}
bool Outlook.PropertyPage.Dirty
{
get
{
return m_Dirty;
}
}
[DispId(C_CaptionDispID)]
public string TabCaption
{
get
{
return "ViewPoint";
}
}
}
All Replies
-
Tuesday, May 23, 2006 11:17 PMI've tracked this down to an exception on the following line of code:pages.Add(new ViewPoint.PropertyTab(), "");Here's the error:System.Runtime.InteropServices.COMException was caught
Message="The operation failed."
Source="Microsoft Office Outlook"
ErrorCode=-1802485758
StackTrace:
at Microsoft.Office.Interop.Outlook.PropertyPages.Add(Object Page, String Title)
at ViewPoint.ThisApplication.ThisApplication_OptionsPagesAdd(PropertyPages pages) in C:\Documents and Settings\Administrator.INTERNAL\My Documents\Visual Studio 2005\Projects\ViewPoint\ViewPoint\ThisApplication.cs:line 51Not much information. Where do I go from here?Thanks for your help. -
Tuesday, May 23, 2006 11:49 PMAnother thing I notice is that in the following event:void ThisApplication_OptionsPagesAdd(Outlook.PropertyPages pages)
{
pages.Add(new ViewPoint.PropertyTab(), "");
}the pages parameter is passed in with a count of 0. Is this correct? Does this reflect the number of custom property pages (in which case 0 is probably correct) or should it reflect the number of 'built in' property pages, in which case 0 would not be the expected value?Thanks for your help, -
Thursday, May 25, 2006 12:58 AM
I'm at my wits end with this. Clearly, there are going to be some differences between ny project, which uses the VSTO approach and the sample project whch uses Extensibility.
http://www.codeproject.com/dotnet/PropertyPages.asp
Other than that though, I've done my utmost to implement a common codebase between both my project and the sample project which establishes a workable baseline. Here's what i'm looking at:
Inside ThisApplication_Startup, which excutes when Outlook starts and my AddIn loads, I execute the following code:
this.OptionsPagesAdd +=
new ApplicationEvents_11_OptionsPagesAddEventHandler
(ThisApplication_OptionsPagesAdd);Clearly, this is effective, since subsequently, when I click on Tools|Options inside Outlook, control jumps into my event handler:
private void ThisApplication_OptionsPagesAdd(PropertyPages pages)
{
try
{
pages.Add(new PropertyTab(), "ViewPoint");
}
catch (System.Exception e)
{
MessageBox.Show("Hmm, an error occurred!");
}
}Having gotten this far, the only two relevant objects at this point will be the pages object and the PropertyTab UserControl. These are the only objects which are relevant to the statement which is failing:
pages.Add(new PropertyTab(), "ViewPoint");
the object 'pages' which is passed in as a parameter is formally defined as Microsoft.Office.Interop.Outlook.PropertyPages. This is correct, as far as I know.
As for the PropertyTab class, I copied this entirely from the sample project into a blank class file and simply made the following minimal changes.
1. Changed the namespace to ViewPoint
2. Changed the name of the class to PropertyTab3a. Added: using Microsoft.Office.Interop.Outlook;
3b. Changed:
public class MyOptionPage : System.Windows.Forms.UserControl, Outlook.PropertyPage
to
public class PropertyTab : System.Windows.Forms.UserControl, PropertyPageThis bothers me just a bit. Without these changes I get compile errors - The type or namespace name 'Outlook' could not be found (are you missing a using directive or an assembly reference?). I do not fully understand this as my project is utilizing the same references as the sample project. I attempted to add a using directive for Microsoft.Office.Interop, thinking that this would legalize the syntax Outlook.PropertyPage, but it did not. Ultimately, I simply added the fully qualified using directive, using Microsoft.Office.Interop.Outlook and removed the Outlook qualifier from the Interface definition. This led to a clean compile. I'm assuming this is correct, because if I look for a definition of PropertyPage, I get the following:
using System;
using System.Runtime.InteropServices;namespace Microsoft.Office.Interop.Outlook
{
[TypeLibType(4096)]
[Guid("0006307E-0000-0000-C000-000000000046")]
public interface PropertyPage
{
[DispId(8449)]
bool Dirty { get; }void Apply();
void GetPageInfo(ref string HelpFile, ref int HelpContext);
}
}This is the exact same definition I see when I inspect the definition of this interface in the sample project.
I know that when executing pages.Add(new PropertyTab(), "ViewPoint"); a new instance of PropertyTab is created because I sccessfully step through the following code in the debugger:
public PropertyTab()
{
InitializeComponent();
isDirty = false;
}
ultimately though, after all this work, pages.Add(new PropertyTab(), "ViewPoint"); trips the exact same same error: The operation failed.I'm baffled. The pages collection is passed in to the event handler. I'm attempting the Add method, supplying a User Control which meets the required definition (copied from another project in which it works) yet in my project I get 'The operation failed'.
Where do I go from here?
For completeness, I'm pasting the entire property page user control class below my signature.
Thanks for any help which you can provide!
- Joe Geretz -
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;namespace ViewPoint
{
public class PropertyTab : System.Windows.Forms.UserControl, PropertyPage
{private bool isDirty;
private System.Windows.Forms.Button button1;
private PropertyPageSite ppSite;private System.ComponentModel.Container components = null;
public PropertyTab()
{
InitializeComponent();
isDirty = false;
}protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(32, 56);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// MyOptionPage
//
this.Controls.Add(this.button1);
this.Name = "MyOptionPage";
this.Load += new System.EventHandler(this.MyOptionPage_Load);
this.ResumeLayout(false);}
#endregion#region PropertyPage Members
public bool Dirty
{
get
{
return isDirty;
}
}public void GetPageInfo(ref string HelpFile, ref int HelpContext)
{
// TODO: Add MyOptionPage.GetPageInfo implementation
}public void Apply()
{
MessageBox.Show("Hello World");}
#endregion
private void button1_Click(object sender, System.EventArgs e)
{
isDirty = true;
ppSite.OnStatusChange();
}private void MyOptionPage_Load(object sender, System.EventArgs e)
{
Type myType = typeof(System.Object);
string assembly =
System.Text.RegularExpressions.Regex.Replace(myType.Assembly.CodeBase, "mscorlib.dll", "System.Windows.Forms.dll");
assembly = System.Text.RegularExpressions.Regex.Replace(assembly, "file:///", "");
assembly = System.Reflection.AssemblyName.GetAssemblyName(assembly).FullName;
Type unmanaged =
Type.GetType(System.Reflection.Assembly.CreateQualifiedName
(assembly, "System.Windows.Forms.UnsafeNativeMethods"));
Type oleObj = unmanaged.GetNestedType("IOleObject");
System.Reflection.MethodInfo mi = oleObj.GetMethod("GetClientSite");
object myppSite = mi.Invoke(this, null);
this.ppSite = (PropertyPageSite)myppSite;
}[DispId(-518)]
public string Caption
{
get { return "ViewPoint"; }
}
}
} -
Friday, May 26, 2006 2:47 AM
Here's the problem:VSTO projects require the following attribute preceding the UserControl class definition:[ComVisible(true)]
'Be nice if the book I'm working from, Visual Studio Tools for Office by Carter and Lippert, would have gotten this right. You'd think that two authors collaborating together could turn out accurate documentation! I guess they couldn't be bothered to actually write the sample code - easier to copy and paste it from the last book they wrote on Extensibility AddIns. Grrrrr - cost me 4 days :-(Hope this helps someone else out there with the same problem.- Joe Geretz - -
Monday, June 12, 2006 8:36 AMJust to let you know.... It did help somebody else...
Thanks to your four day effort, i solved this in 10 minutes just reading this thread.
Thanks for posting the solution as well.. ;-)
best regards
Anders -
Thursday, October 05, 2006 2:53 PM
Thanks Joe for writting the solution as well. It helped me too to find the solution.
Nikolas -
Tuesday, November 14, 2006 8:26 PM
This post was a great help to me as well - thanks for figuring it out.
-Andrew
-
Wednesday, December 20, 2006 10:06 AMThanks! Helped me too, unfortunately, it took me 2 hours to find this page... google didnt do a very good job indexing it! (blame it on the tools (c;)
-
Wednesday, November 11, 2009 9:53 PMThanks mate. It helped me too to solve an error with too less information...
-- Marino -
Friday, October 05, 2012 9:34 AM
Thanks so much Joe.. Even i spent two days to find this simple solution :)
-- Sanjay BK
-
Friday, October 05, 2012 9:37 AM
Thanks so much Joe.. Even i spent two days to find this simple solution :)
-- Sanjay BK
Below is the working property page:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Outlook_PropertyPage
{
[ComVisible(true)]
public class MyOptionPage : System.Windows.Forms.UserControl , Microsoft.Office.Interop.Outlook.PropertyPage
{
private bool isDirty;
private System.Windows.Forms.Button button1;
private Microsoft.Office.Interop.Outlook.PropertyPageSite ppSite;
private System.ComponentModel.Container components = null;
public MyOptionPage()
{
InitializeComponent();
isDirty = false;
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(32, 56);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// MyOptionPage
//
this.Controls.Add(this.button1);
this.Name = "MyOptionPage";
this.Load += new System.EventHandler(this.MyOptionPage_Load);
this.ResumeLayout();
}
#endregion
#region PropertyPage Members
public bool Dirty
{
get
{
return isDirty;
}
}
public void GetPageInfo(ref string HelpFile, ref int HelpContext)
{
// TODO: Add MyOptionPage.GetPageInfo implementation
}
public void Apply()
{
MessageBox.Show("Hello World");
}
#endregion
private void button1_Click(object sender, System.EventArgs e)
{
isDirty = true;
ppSite.OnStatusChange();
}
private void MyOptionPage_Load(object sender, System.EventArgs e)
{
Type myType = typeof(System.Object);
string assembly =
System.Text.RegularExpressions.Regex.Replace(myType.Assembly.CodeBase, "mscorlib.dll", "System.Windows.Forms.dll");
assembly = System.Text.RegularExpressions.Regex.Replace(assembly, "file:///", "");
assembly = System.Reflection.AssemblyName.GetAssemblyName(assembly).FullName;
Type unmanaged =
Type.GetType(System.Reflection.Assembly.CreateQualifiedName
(assembly, "System.Windows.Forms.UnsafeNativeMethods"));
Type oleObj = unmanaged.GetNestedType("IOleObject");
System.Reflection.MethodInfo mi = oleObj.GetMethod("GetClientSite");
object myppSite = mi.Invoke(this, null);
this.ppSite = (Microsoft.Office.Interop.Outlook.PropertyPageSite)myppSite;
}
[DispId(-517)]
public string Caption
{
get{return "Attachment Manager";}
}
}
}

