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 PropertyTab
3a. 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, PropertyPage
This 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"; } } } }
Joseph Geretz |