![]() |
| If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below. |
|
|||||||
| Tags: addin, code, outlook, review |
|
|
Thread Tools | Display Modes |
|
#1
|
|||
|
|||
|
Hi.
It's my first time ever writing an add-in. It's for Outlook 2003 using VSTO SE. It works well. However, we're about to deploy this to about 1000 users, and before we do, I'd like to see if anyone can catch any gaping holes in my code. It's a single C# class called ThisAddin.cs. It does the following: - Adds a control to the standard toolbar of each Appointment Inspector - Clicking the control grabs the values of some of the inspectors ItemProperties, opens a IE window, and passes them in a URL - Closing the inspector removes the control and releases the objects and related events Warnings, gotchas, best practices: all comments welcome. Here it is. Thanks in advance. ----------- using System; using System.Windows.Forms; using Diagnostics = System.Diagnostics; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Outlook = Microsoft.Office.Interop.Outlook; using Office = Microsoft.Office.Core; using SHDocVw; namespace OutlookConfCallerBtn { public partial class ThisAddIn { Diagnostics.Process newIE; Office.CommandBars cmdBars; Office.CommandBar stdBar; Office.CommandBarButton Btn_ConfRoomSchdlr; Outlook.Inspectors openInspectors; Outlook.AppointmentItem item; /// summary /// Do the setup on add-in startup /// /summary private void ThisAddIn_Startup(object sender, System.EventArgs e) { openInspectors = this.Application.Inspectors; openInspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler( newInspector_Event); } /// summary /// Release the objects on shutdown /// /summary private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { // Drop the NewInspector and Btn_ConfRoomSchdlr event handlers openInspectors.NewInspector -= new Microsoft.Office.Interop.Outlook.InspectorsEvents_ NewInspectorEventHandler(newInspector_Event); // Kill the class-level objects in play openInspectors = null; cmdBars = null; stdBar = null; Btn_ConfRoomSchdlr = null; item = null; newIE = null; } /// summary /// Handle the Inspector.NewInspector event /// This adds the command bar control to all Appointment inspectors /// /summary private void newInspector_Event(Outlook.Inspector new_Inspector) { // Check what type of inspector we have Outlook.AppointmentItem item = new_Inspector.CurrentItem as Outlook.AppointmentItem; // For appointment items, add a custom control if (item != null) { try { // Get the standard toolbar for this inspector cmdBars = new_Inspector.CommandBars; stdBar = cmdBars["standard"]; // Add the control Btn_ConfRoomSchdlr = (Office.CommandBarButton)stdBar.Controls.Add(1, missing, missing, 12, true); Btn_ConfRoomSchdlr.Style = Office.MsoButtonStyle.msoButtonIconAndCaption; Btn_ConfRoomSchdlr.Caption = "Reserve Room(s)"; Btn_ConfRoomSchdlr.Tag = "Reserve Room(s)"; Btn_ConfRoomSchdlr.BeginGroup = true; Btn_ConfRoomSchdlr.Picture = getImage(); // Set the event handlers for the button click and Inspector.Close ((Outlook.InspectorEvents_Event)new_Inspector).Clo se += new Outlook.InspectorEvents_CloseEventHandler(closeIns pector_Event); Btn_ConfRoomSchdlr.Click += new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } /// summary /// Handle the Button.Click event. This opens the conference room scheduler /// /summary private void clickButton_Event(Office.CommandBarButton ctrl, ref bool cancel) { // Set up the reference time data System.Collections.Hashtable timeHash = new System.Collections.Hashtable(); int hr = 5; String min = "00"; String mdn = "am"; // Build the times on the fly, from 5:00 am - 9:30 pm for (int i = 1; i = 34; i++) { String tKey = "_" + hr.ToString() + min + mdn; timeHash.Add(tKey, i.ToString()); if (i % 2 != 0) { min = "30"; } else { min = "00"; if (hr == 12) { hr = 1; } else { hr++; if (hr == 11) { mdn = "pm"; } } } } // Assemble the Start Time and End Time values and open a URL item = this.Application.ActiveInspector().CurrentItem as Outlook.AppointmentItem; String [] StartGroup = item.ItemProperties["Start"].Value.ToString().Split(new Char[] {' '}); String [] EndGroup = item.ItemProperties["End"].Value.ToString().Split(new Char[] { ' ' }); String [] StartTime = StartGroup[1].Split(new Char[] { ':' }); String [] EndTime = EndGroup[1].Split(new Char[] { ':' }); String selDate = StartGroup[0]; String sTimeKey = ("_" + StartTime[0] + StartTime[1] + StartGroup[2]).ToLower(); String eTimeKey = ("_" + EndTime[0] + EndTime[1] + EndGroup[2]).ToLower(); // Get the time values from timeHash, otherwise use -1 String sTimeID = (timeHash.ContainsKey(sTimeKey) ? timeHash[sTimeKey].ToString() : "-1"); String eTimeID = (timeHash.ContainsKey(eTimeKey) ? timeHash[eTimeKey].ToString() : "-1"); String ConfSchdURL = "http://devapps/confroom/index.cfm?event=wizard"; ConfSchdURL += "&StartTime=" + sTimeID + "&EndTime=" + eTimeID + "&SelDate=" + selDate; // MessageBox.Show(sTimeKey + ":" + sTimeID + " " + eTimeKey + ":" + eTimeID); newIE = System.Diagnostics.Process.Start("IExplore.exe", ConfSchdURL); } /// summary /// Handle the Inspector.Close event /// /summary void closeInspector_Event() { // Drop the Btn_ConfRoomSchdlr event handler Btn_ConfRoomSchdlr.Click -= new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } /// summary /// Add the converted image to an ImageList /// /summary private stdole.IPictureDisp getImage() { stdole.IPictureDisp tempImage = null; try { System.Drawing.Icon newIcon = Properties.Resources.confchair; ImageList newImageList = new ImageList(); newImageList.Images.Add(newIcon); tempImage = ConvertImage.Convert(newImageList.Images[0]); } catch (Exception ex) { MessageBox.Show(ex.Message); } return tempImage; } #region VSTO generated code /// summary /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// /summary private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } // Convert the icon file to an Image object sealed public class ConvertImage : System.Windows.Forms.AxHost { private ConvertImage() : base(null) { } public static stdole.IPictureDisp Convert(System.Drawing.Image image) { return (stdole.IPictureDisp)System.Windows.Forms.AxHost.G etIPictureDispFromPicture(image); } } } -- Tip: Never eat yellow snow. |
| Ads |
|
#2
|
|||
|
|||
|
I see 2 things offhand.
If you intend to ever support Outlook 2007 you will need to move your UI creation to the Inspector.Activate() event, in NewInspector() the object reference passed is a weak object reference and not good for much else other than checking Inspector.CurrentItem.Class or .MessageClass. In most cases Inspector.CommandBars is not valid in NewInspector in Outlook 2007 (of course for Outlook 2007 you'd really want to support the ribbon instead of using the CommandBars interface). Second, your code will not correctly handle cases where more than 1 Inspector is open at a time. For cases like that the best practice is to create a collection (list, hashtable, etc.) of wrapper classes. Each wrapper class encapsulates an open Inspector and has event handlers for the Inspector events. That allows each Inspector's UI and events to be handled individually. There are many examples of Inspector wrapper classes and collections on my Web site and on www.outlookcode.com among other places. -- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Professional Programming Outlook 2007 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm "JRomeo" wrote in message ... Hi. It's my first time ever writing an add-in. It's for Outlook 2003 using VSTO SE. It works well. However, we're about to deploy this to about 1000 users, and before we do, I'd like to see if anyone can catch any gaping holes in my code. It's a single C# class called ThisAddin.cs. It does the following: - Adds a control to the standard toolbar of each Appointment Inspector - Clicking the control grabs the values of some of the inspectors ItemProperties, opens a IE window, and passes them in a URL - Closing the inspector removes the control and releases the objects and related events Warnings, gotchas, best practices: all comments welcome. Here it is. Thanks in advance. ----------- using System; using System.Windows.Forms; using Diagnostics = System.Diagnostics; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Outlook = Microsoft.Office.Interop.Outlook; using Office = Microsoft.Office.Core; using SHDocVw; namespace OutlookConfCallerBtn { public partial class ThisAddIn { Diagnostics.Process newIE; Office.CommandBars cmdBars; Office.CommandBar stdBar; Office.CommandBarButton Btn_ConfRoomSchdlr; Outlook.Inspectors openInspectors; Outlook.AppointmentItem item; /// summary /// Do the setup on add-in startup /// /summary private void ThisAddIn_Startup(object sender, System.EventArgs e) { openInspectors = this.Application.Inspectors; openInspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler( newInspector_Event); } /// summary /// Release the objects on shutdown /// /summary private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { // Drop the NewInspector and Btn_ConfRoomSchdlr event handlers openInspectors.NewInspector -= new Microsoft.Office.Interop.Outlook.InspectorsEvents_ NewInspectorEventHandler(newInspector_Event); // Kill the class-level objects in play openInspectors = null; cmdBars = null; stdBar = null; Btn_ConfRoomSchdlr = null; item = null; newIE = null; } /// summary /// Handle the Inspector.NewInspector event /// This adds the command bar control to all Appointment inspectors /// /summary private void newInspector_Event(Outlook.Inspector new_Inspector) { // Check what type of inspector we have Outlook.AppointmentItem item = new_Inspector.CurrentItem as Outlook.AppointmentItem; // For appointment items, add a custom control if (item != null) { try { // Get the standard toolbar for this inspector cmdBars = new_Inspector.CommandBars; stdBar = cmdBars["standard"]; // Add the control Btn_ConfRoomSchdlr = (Office.CommandBarButton)stdBar.Controls.Add(1, missing, missing, 12, true); Btn_ConfRoomSchdlr.Style = Office.MsoButtonStyle.msoButtonIconAndCaption; Btn_ConfRoomSchdlr.Caption = "Reserve Room(s)"; Btn_ConfRoomSchdlr.Tag = "Reserve Room(s)"; Btn_ConfRoomSchdlr.BeginGroup = true; Btn_ConfRoomSchdlr.Picture = getImage(); // Set the event handlers for the button click and Inspector.Close ((Outlook.InspectorEvents_Event)new_Inspector).Clo se += new Outlook.InspectorEvents_CloseEventHandler(closeIns pector_Event); Btn_ConfRoomSchdlr.Click += new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } /// summary /// Handle the Button.Click event. This opens the conference room scheduler /// /summary private void clickButton_Event(Office.CommandBarButton ctrl, ref bool cancel) { // Set up the reference time data System.Collections.Hashtable timeHash = new System.Collections.Hashtable(); int hr = 5; String min = "00"; String mdn = "am"; // Build the times on the fly, from 5:00 am - 9:30 pm for (int i = 1; i = 34; i++) { String tKey = "_" + hr.ToString() + min + mdn; timeHash.Add(tKey, i.ToString()); if (i % 2 != 0) { min = "30"; } else { min = "00"; if (hr == 12) { hr = 1; } else { hr++; if (hr == 11) { mdn = "pm"; } } } } // Assemble the Start Time and End Time values and open a URL item = this.Application.ActiveInspector().CurrentItem as Outlook.AppointmentItem; String [] StartGroup = item.ItemProperties["Start"].Value.ToString().Split(new Char[] {' '}); String [] EndGroup = item.ItemProperties["End"].Value.ToString().Split(new Char[] { ' ' }); String [] StartTime = StartGroup[1].Split(new Char[] { ':' }); String [] EndTime = EndGroup[1].Split(new Char[] { ':' }); String selDate = StartGroup[0]; String sTimeKey = ("_" + StartTime[0] + StartTime[1] + StartGroup[2]).ToLower(); String eTimeKey = ("_" + EndTime[0] + EndTime[1] + EndGroup[2]).ToLower(); // Get the time values from timeHash, otherwise use -1 String sTimeID = (timeHash.ContainsKey(sTimeKey) ? timeHash[sTimeKey].ToString() : "-1"); String eTimeID = (timeHash.ContainsKey(eTimeKey) ? timeHash[eTimeKey].ToString() : "-1"); String ConfSchdURL = "http://devapps/confroom/index.cfm?event=wizard"; ConfSchdURL += "&StartTime=" + sTimeID + "&EndTime=" + eTimeID + "&SelDate=" + selDate; // MessageBox.Show(sTimeKey + ":" + sTimeID + " " + eTimeKey + ":" + eTimeID); newIE = System.Diagnostics.Process.Start("IExplore.exe", ConfSchdURL); } /// summary /// Handle the Inspector.Close event /// /summary void closeInspector_Event() { // Drop the Btn_ConfRoomSchdlr event handler Btn_ConfRoomSchdlr.Click -= new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } /// summary /// Add the converted image to an ImageList /// /summary private stdole.IPictureDisp getImage() { stdole.IPictureDisp tempImage = null; try { System.Drawing.Icon newIcon = Properties.Resources.confchair; ImageList newImageList = new ImageList(); newImageList.Images.Add(newIcon); tempImage = ConvertImage.Convert(newImageList.Images[0]); } catch (Exception ex) { MessageBox.Show(ex.Message); } return tempImage; } #region VSTO generated code /// summary /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// /summary private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } // Convert the icon file to an Image object sealed public class ConvertImage : System.Windows.Forms.AxHost { private ConvertImage() : base(null) { } public static stdole.IPictureDisp Convert(System.Drawing.Image image) { return (stdole.IPictureDisp)System.Windows.Forms.AxHost.G etIPictureDispFromPicture(image); } } } -- Tip: Never eat yellow snow. |
|
#3
|
|||
|
|||
|
Nice. That's what I was looking for. Thx.
-- Tip: Never eat yellow snow. "Ken Slovak - [MVP - Outlook]" wrote: I see 2 things offhand. If you intend to ever support Outlook 2007 you will need to move your UI creation to the Inspector.Activate() event, in NewInspector() the object reference passed is a weak object reference and not good for much else other than checking Inspector.CurrentItem.Class or .MessageClass. In most cases Inspector.CommandBars is not valid in NewInspector in Outlook 2007 (of course for Outlook 2007 you'd really want to support the ribbon instead of using the CommandBars interface). Second, your code will not correctly handle cases where more than 1 Inspector is open at a time. For cases like that the best practice is to create a collection (list, hashtable, etc.) of wrapper classes. Each wrapper class encapsulates an open Inspector and has event handlers for the Inspector events. That allows each Inspector's UI and events to be handled individually. There are many examples of Inspector wrapper classes and collections on my Web site and on www.outlookcode.com among other places. -- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Professional Programming Outlook 2007 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm "JRomeo" wrote in message ... Hi. It's my first time ever writing an add-in. It's for Outlook 2003 using VSTO SE. It works well. However, we're about to deploy this to about 1000 users, and before we do, I'd like to see if anyone can catch any gaping holes in my code. It's a single C# class called ThisAddin.cs. It does the following: - Adds a control to the standard toolbar of each Appointment Inspector - Clicking the control grabs the values of some of the inspectors ItemProperties, opens a IE window, and passes them in a URL - Closing the inspector removes the control and releases the objects and related events Warnings, gotchas, best practices: all comments welcome. Here it is. Thanks in advance. ----------- using System; using System.Windows.Forms; using Diagnostics = System.Diagnostics; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Outlook = Microsoft.Office.Interop.Outlook; using Office = Microsoft.Office.Core; using SHDocVw; namespace OutlookConfCallerBtn { public partial class ThisAddIn { Diagnostics.Process newIE; Office.CommandBars cmdBars; Office.CommandBar stdBar; Office.CommandBarButton Btn_ConfRoomSchdlr; Outlook.Inspectors openInspectors; Outlook.AppointmentItem item; /// summary /// Do the setup on add-in startup /// /summary private void ThisAddIn_Startup(object sender, System.EventArgs e) { openInspectors = this.Application.Inspectors; openInspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler( newInspector_Event); } /// summary /// Release the objects on shutdown /// /summary private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { // Drop the NewInspector and Btn_ConfRoomSchdlr event handlers openInspectors.NewInspector -= new Microsoft.Office.Interop.Outlook.InspectorsEvents_ NewInspectorEventHandler(newInspector_Event); // Kill the class-level objects in play openInspectors = null; cmdBars = null; stdBar = null; Btn_ConfRoomSchdlr = null; item = null; newIE = null; } /// summary /// Handle the Inspector.NewInspector event /// This adds the command bar control to all Appointment inspectors /// /summary private void newInspector_Event(Outlook.Inspector new_Inspector) { // Check what type of inspector we have Outlook.AppointmentItem item = new_Inspector.CurrentItem as Outlook.AppointmentItem; // For appointment items, add a custom control if (item != null) { try { // Get the standard toolbar for this inspector cmdBars = new_Inspector.CommandBars; stdBar = cmdBars["standard"]; // Add the control Btn_ConfRoomSchdlr = (Office.CommandBarButton)stdBar.Controls.Add(1, missing, missing, 12, true); Btn_ConfRoomSchdlr.Style = Office.MsoButtonStyle.msoButtonIconAndCaption; Btn_ConfRoomSchdlr.Caption = "Reserve Room(s)"; Btn_ConfRoomSchdlr.Tag = "Reserve Room(s)"; Btn_ConfRoomSchdlr.BeginGroup = true; Btn_ConfRoomSchdlr.Picture = getImage(); // Set the event handlers for the button click and Inspector.Close ((Outlook.InspectorEvents_Event)new_Inspector).Clo se += new Outlook.InspectorEvents_CloseEventHandler(closeIns pector_Event); Btn_ConfRoomSchdlr.Click += new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } /// summary /// Handle the Button.Click event. This opens the conference room scheduler /// /summary private void clickButton_Event(Office.CommandBarButton ctrl, ref bool cancel) { // Set up the reference time data System.Collections.Hashtable timeHash = new System.Collections.Hashtable(); int hr = 5; String min = "00"; String mdn = "am"; // Build the times on the fly, from 5:00 am - 9:30 pm for (int i = 1; i = 34; i++) { String tKey = "_" + hr.ToString() + min + mdn; timeHash.Add(tKey, i.ToString()); if (i % 2 != 0) { min = "30"; } else { min = "00"; if (hr == 12) { hr = 1; } else { hr++; if (hr == 11) { mdn = "pm"; } } } } // Assemble the Start Time and End Time values and open a URL item = this.Application.ActiveInspector().CurrentItem as Outlook.AppointmentItem; String [] StartGroup = item.ItemProperties["Start"].Value.ToString().Split(new Char[] {' '}); String [] EndGroup = item.ItemProperties["End"].Value.ToString().Split(new Char[] { ' ' }); String [] StartTime = StartGroup[1].Split(new Char[] { ':' }); String [] EndTime = EndGroup[1].Split(new Char[] { ':' }); String selDate = StartGroup[0]; String sTimeKey = ("_" + StartTime[0] + StartTime[1] + StartGroup[2]).ToLower(); String eTimeKey = ("_" + EndTime[0] + EndTime[1] + EndGroup[2]).ToLower(); // Get the time values from timeHash, otherwise use -1 String sTimeID = (timeHash.ContainsKey(sTimeKey) ? timeHash[sTimeKey].ToString() : "-1"); String eTimeID = (timeHash.ContainsKey(eTimeKey) ? timeHash[eTimeKey].ToString() : "-1"); String ConfSchdURL = "http://devapps/confroom/index.cfm?event=wizard"; ConfSchdURL += "&StartTime=" + sTimeID + "&EndTime=" + eTimeID + "&SelDate=" + selDate; // MessageBox.Show(sTimeKey + ":" + sTimeID + " " + eTimeKey + ":" + eTimeID); newIE = System.Diagnostics.Process.Start("IExplore.exe", ConfSchdURL); } /// summary /// Handle the Inspector.Close event /// /summary void closeInspector_Event() { // Drop the Btn_ConfRoomSchdlr event handler Btn_ConfRoomSchdlr.Click -= new Office._CommandBarButtonEvents_ClickEventHandler(c lickButton_Event); } /// summary /// Add the converted image to an ImageList /// /summary private stdole.IPictureDisp getImage() { stdole.IPictureDisp tempImage = null; try { System.Drawing.Icon newIcon = Properties.Resources.confchair; ImageList newImageList = new ImageList(); newImageList.Images.Add(newIcon); tempImage = ConvertImage.Convert(newImageList.Images[0]); } catch (Exception ex) { MessageBox.Show(ex.Message); } return tempImage; } #region VSTO generated code /// summary /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// /summary private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion } // Convert the icon file to an Image object sealed public class ConvertImage : System.Windows.Forms.AxHost { private ConvertImage() : base(null) { } public static stdole.IPictureDisp Convert(System.Drawing.Image image) { return (stdole.IPictureDisp)System.Windows.Forms.AxHost.G etIPictureDispFromPicture(image); } } } -- Tip: Never eat yellow snow. |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| email formatting disappears on review | Mayr | Outlook - General Queries | 0 | November 27th 07 12:11 AM |
| Review of code to send all draft messages ... | M100C | Outlook and VBA | 2 | September 13th 07 05:36 PM |
| Why do I have to hit send/receive to review new messages? | No3Sista | Outlook - Calandaring | 1 | October 12th 06 05:06 AM |
| Meeting requests are not showing up in inbox for review. | spotmesil | Outlook - Calandaring | 1 | August 8th 06 03:55 AM |
| Using Calendar to Remind people about Documentation Review Due Dat | writertech | Outlook - Calandaring | 0 | January 24th 06 08:40 PM |