Office Developer Blog
The definitive blog for finding the latest news and code tricks for Office developers.
 

  • Office Developer Blog

    Insert database query results as a table programmatically in Word 2010

    • 0 Comments

    An astute user recently pointed out that buried on the Customize Ribbon tab of the Word Options dialog box is an otherwise hidden command, Insert Database, that lets you create a table in a Word document and populate that table with the results of a database query:

    image

    You can do all this by making a few selections in the Database dialog box that opens when you choose that command from the customized ribbon:

    image

    You might also not be aware that you can accomplish the same thing programmatically. The following code sample shows how to insert a table into a Word document that displays the contents of the Category table from the Northwind sample database (Microsoft Access):

    Sub InsertCategoriesTable()
    '
    ' Insert database table into document
    '
        Selection.Range.InsertDatabase Format:=11, Style:=191, LinkToSource:=False,  _  
            SQLStatement:="SELECT * FROM `Categories`" & "",  _ 
            DataSource:="C:\Users\username\Documents\Access Databases\Northwind.accdb", _
            From:=-1, To:=-1, IncludeFields:=True

    End Sub

    The sample uses the InsertDatabase method of the Range object to insert the results of a database query into a table at the selected location in Word. The InsertDatabase method takes a number of optional parameters that let you customize both the database query and the format of the table to be inserted, as shown in the following table:

    image

    In the sample, I’ve passed values for the Format and Style parameters that result in the table looking like this:

    image

    The value passed for the SQLStatement parameter, "SELECT * FROM `Categories`", tells Word to query all the records in the Categories table in the Northwind database. The values I’ve passed for the From and To parameters, 1 and –1, tell Word to display all the records in the database table.

    Because I’m querying data from Access, it is not necessary for me to pass a value for the optional Connection parameter. See the InsertDatabase topic for more information about this parameter.

  • Office Developer Blog

    Microsoft announces "Office 15" Technical Preview

    • 0 Comments

    PJ Hough, Corporate VP of Office Division, recently announced the beginning of the "Office 15" Technical Preview program. We are extremely excited about Office 15. As mentioned in PJ’s post, the Technical Preview is shared with a select group of customers under non-disclosure agreements. We plan to work closely with these Technical Preview participants and incorporate their feedback into the product. Later this summer, we hope to be able to offer everyone an opportunity to try the Office 15 public beta. Thank you for your continued support; we will release more exciting information about Office 15 then.

  • Office Developer Blog

    New blog direction for "Office Developer Blog"

    • 0 Comments

    The Office Client Developer Content Resources blog has embarked on a new, broader direction - we are now Office Developer Blog! We hope to continue to serve our Office developer customers with news, tips, product and content release announcements in this new year!

  • Office Developer Blog

    Referencing Outlook field and property names in non-English locales

    • 0 Comments

    In Microsoft Outlook, fields store values in forms and properties store values in macros or add-ins. If you use forms, macros, or add-ins that reference standard or custom fields in non-English locales, you should be aware that the forms or code should reference standard and custom fields using their locale-dependent field names. Also, if your macro or add-in uses Jet queries to filter on built-in properties, regardless of the locale, your Jet queries should always reference the built-in properties using their English names.

    Outlook fields and properties

    In Outlook, fields apply to forms pages in the Outlook forms designer, and properties apply to extending Outlook using the object model. Fields are used to display values in forms, and properties are used to store values pertaining to their parent objects. There are standard fields that are built into Outlook, for example, the [Subject] field in an appointment form. Some of these fields map to properties of objects in the Outlook object model. In particular, there are fields that apply to Outlook items, and many of these fields map to properties of corresponding item objects in the object model. Using the afore-mentioned [Subject] field as an example, that [Subject] field is mapped to the Subject property of the AppointmentItem object in the object model. As another example, the [Total Work] and [Actual Work] fields are standard Task fields available in the forms designer. They map to respectively the TotalWork and ActualWork properties of the TaskItem object in the object model.

    Using the Outlook forms designer, you can create custom formula fields for a custom form page. For example, you can create a field called [Accumulated time] as the sum of the [Total Work] and [Actual Work] fields. See figure 1.

    Figure 1. Creating a custom formula field for the task item in the Outlook forms designer.

    A custom property of the formula type in the object model is similar to a custom formula field. Along the same lines as the preceding [Accumulated time] field example, you can create a macro that uses the UserProperty and  UserProperties objects to create a custom property for the TaskItem object. The custom property is called AccumulatedTime and is of the formula type. Note that formula fields and formula properties have their calculations based on standard or custom fields. So when you assign a formula to a custom formula property, the formula references field names instead of property names.

    The following is a VBA function, CustomPropertyFormula, that creates an AccumulatedTime custom formula property for the TaskItem object. The AccumulatedTime property is assigned the formula which is the sum of the [Total Work] and [Actual Work] fields.

    Sub CustomPropertyFormula()

        Dim task As Outlook.TaskItem

        Dim customProp As UserProperty

     

        Set task = Outlook.CreateItem(olTaskItem)

        task.TotalWork = 4

        task.ActualWork = 3

       

        ' Create a custom property for the TaskItem.

        ' The custom property is of the formula type, called AccumulatedTime.

        Set customProp = task.UserProperties.Add("AccumulatedTime", olFormula)

     

        ' Assign the formula which is the sum of the [Total Work] and [Actual Work] fields.

        ' [Total Work] field maps to the TaskItem.TotalWork property, and

        ' [Actual Work] maps to the TaskItem.ActualWork property.

        customProp.Formula = "[Total Work] + [Actual Work]"

       

        MsgBox customProp.Value

       

        customProp.Delete

        task.Delete

    End Sub

     

     

    All is well if you are using the custom form or macro in the English locale. However, fields are locale-dependent and in some scenarios – forms and custom formula properties, fields must be referenced by the appropriate field names corresponding to each locale. In the case of Jet queries, built-in properties must be referenced in their English names regardless of the locale.

    Referencing standard or custom fields in custom forms for different locales

    If you plan to run a custom form that references standard fields or custom fields in different locales, you should first create a form for each locale. Each such form would reference standard fields and custom fields using the locale-specific field names.

    For example, if you are using a custom form for the Japanese locale, you should first do the following to switch to using Japanese as the display language in Outlook:

    1. Install the Japanese language pack for Office.
    2. In Outlook, select File, Options, and then Language.
    3. Select Japanese under Display Language.
    4. Select Set as Default.

     

    Then in the forms designer, you should be able to see locale-dependent names for standard fields in the Field Chooser.

    To use custom fields in your custom form, you should use the Field Chooser to first create the custom fields in the specific locale to get the locale-specific names, before referencing the custom fields.

     

    Referencing standard or custom fields in a custom formula property for different locales

     

    If you plan to run in different locales a macro that references standard or custom fields in a formula property, you must first modify the formula to reference the fields using their locale-specific names. Using the Japanese locale and the previous macro as an example, you must
    replace in the macro the names of the standard fields [Total Work] and [Actual Work] by their Japanese names. That is, in place of:

    customProp.Formula = "[Total Work] + [Actual Work]"

    Do:

    customProp.Formula = "[予測時間] + [実働時間]"

    Otherwise, your macro will return a runtime error.

    You can verify the localized names of standard fields and custom fields by switching the Outlook display language to the corresponding locale and then looking for the localized field names in the Field Chooser in the Outlook forms designer.

    Referencing properties in Jet queries

    Outlook supports filtering by using queries in the Microsoft Jet query language syntax and DASL Searching and Locating (DASL) syntax. In Jet query syntax, you can filter on a property by enclosing the property name with square brackets in the query, similar to the way you would reference a field name. For example, you can create a query for the ContactItem.CompanyName property being “Microsoft”. To express this query in Jet syntax, you can enclose the property with square brackets, as in [CompanyName], and specify the filter, sFilter, as follows:

    sFilter = "[CompanyName] = 'Microsoft'"

    Note that if the property is a built-in property in the object model, then in a Jet query, you must reference the field in its English name regardless of the locale. If on the other hand, the property is a custom property, then in a non-English locale, you can reference the property in the Jet query using either its English name or its locale-specific name.

    Summary

    The following table summarizes the necessary actions in English and non-English locales in the different scenarios.

     

     

     

    You can find more information about fields, custom forms, properties, and Jet queries in the following topics:

    Customizing Form Pages and Form Regions

    Standard Fields Overview

    Outlook Fields and Equivalent Properties

    Using the Field Chooser

    Properties Overview

    Filtering Items

     

  • Office Developer Blog

    Creating a helper class in C# to access common Outlook item members

    • 0 Comments

    In Microsoft Outlook, items such as MailItem, ContactItem and AppointmentItem have similar properties and methods. For example, the Application, Attachments, Body, Categories, and Class properties, and Close, Copy, and Display methods are common to all Outlook item objects. The COM-based Outlook object model returns the generic Visual Basic Object instead of the exact item type for many members. For instance, the _Inspector.CurrentItem property returns a generic Object. On the other hand, the strongly typed managed code environment requires you to cast the Object representing an Outlook item to the exact Outlook type such as MailItem. You can create a helper class to use reflection to expose properties and methods that are common to all items. This blog describes an OutlookItem helper class that helps you cast the object to the exact type  and provides the convenience of directly using common item properties or methods on the OutlookItem object.

    The OutlookItem helper class is a very useful technique that is described in the book Programming Applications for Microsoft Office Outlook 2007 by Randy Byrne and Ryan Gregg, from Microsoft Press (ISBN 9780735622494, copyright Microsoft Press 2007, all rights reserved). A few examples in the Outlook 2010 Primary Interop Assembly Reference make use of this helper class, and the next refresh of that Reference will also include this helper class. See the following how-to topics that use the OutlookItem class:

    How to: Open and Display the Contents of an iCalendar File

    How to: Use SetColumns to Efficiently Enumerate Items in a Folder

    How to: Assign Categories to an Item

    How to: Implement a Wrapper for Inspectors and Track Item-Level Events in Each Inspector

    The following lists the OutlookItem class, as excerpted from the Programming Applications for Microsoft Office Outlook 2007 book.

    using System;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Diagnostics;

    namespace SampleCodeAddinCS
    {
        class OutlookItem
        {
            private object m_item;  // the wrapped Outlook item
            private Type m_type;  // type for the Outlook item
            private object[] m_args;  // dummy argument array
            private System.Type m_typeOlObjectClass;

            #region OutlookItem Constants

            private const string OlActions = "Actions";
            private const string OlApplication = "Application";
            private const string OlAttachments = "Attachments";
            private const string OlBillingInformation = "BillingInformation";
            private const string OlBody = "Body";
            private const string OlCategories = "Categories";
            private const string OlClass = "Class";
            private const string OlClose = "Close";
            private const string OlCompanies = "Companies";
            private const string OlConversationIndex = "ConversationIndex";
            private const string OlConversationTopic = "ConversationTopic";
            private const string OlCopy = "Copy";
            private const string OlCreationTime = "CreationTime";
            private const string OlDisplay = "Display";
            private const string OlDownloadState = "DownloadState";
            private const string OlEntryID = "EntryID";
            private const string OlFormDescription = "FormDescription";
            private const string OlGetInspector = "GetInspector";
            private const string OlImportance = "Importance";
            private const string OlIsConflict = "IsConflict";
            private const string OlItemProperties = "ItemProperties";
            private const string OlLastModificationTime = "LastModificationTime";
            private const string OlLinks = "Links";
            private const string OlMarkForDownload = "MarkForDownload";
            private const string OlMessageClass = "MessageClass";
            private const string OlMileage = "Mileage";
            private const string OlMove = "Move";
            private const string OlNoAging = "NoAging";
            private const string OlOutlookInternalVersion = "OutlookInternalVersion";
            private const string OlOutlookVersion = "OutlookVersion";
            private const string OlParent = "Parent";
            private const string OlPrintOut = "PrintOut";
            private const string OlPropertyAccessor = "PropertyAccessor";
            private const string OlSave = "Save";
            private const string OlSaveAs = "SaveAs";
            private const string OlSaved = "Saved";
            private const string OlSensitivity = "Sensitivity";
            private const string OlSession = "Session";
            private const string OlShowCategoriesDialog = "ShowCategoriesDialog";
            private const string OlSize = "Size";
            private const string OlSubject = "Subject";
            private const string OlUnRead = "UnRead";
            private const string OlUserProperties = "UserProperties";
            #endregion

            #region Constructor
            public OutlookItem(object item)
            {
                m_item = item;
                m_type = m_item.GetType();
                m_args = new Object[] { };
            }
            #endregion

            #region Public Methods and Properties
            public Outlook.Actions Actions
            {
                get
                {
                    return this.GetPropertyValue(OlActions) as Outlook.Actions;
                }
            }

            public Outlook.Application Application
            {
                get
                {
                    return this.GetPropertyValue(OlApplication) as Outlook.Application;
                }
            }

            public Outlook.Attachments Attachments
            {
                get
                {
                    return this.GetPropertyValue(OlAttachments) as Outlook.Attachments;
                }
            }

            public string BillingInformation
            {
                get
                {
                    return this.GetPropertyValue(OlBillingInformation).ToString();
                }
                set
                {
                    SetPropertyValue(OlBillingInformation, value);
                }
            }

            public string Body
            {
                get
                {
                    return this.GetPropertyValue(OlBody).ToString();
                }
                set
                {
                    SetPropertyValue(OlBody, value);
                }
            }

            public string Categories
            {
                get
                {
                    return this.GetPropertyValue(OlCategories).ToString();
                }
                set
                {
                    SetPropertyValue(OlCategories, value);
                }
            }

            public void Close(Outlook.OlInspectorClose SaveMode)
            {
                object[] MyArgs = { SaveMode };
                this.CallMethod(OlClose);
            }

            public string Companies
            {
                get
                {
                    return this.GetPropertyValue(OlCompanies).ToString();
                }
                set
                {
                    SetPropertyValue(OlCompanies, value);
                }
            }

            public Outlook.OlObjectClass Class
            {
                get
                {
                    if (m_typeOlObjectClass == null)
                    {
                        // Note: instantiate dummy ObjectClass enumeration to get type.
                        //       type = System.Type.GetType("Outlook.OlObjectClass") doesn't seem to work
                        Outlook.OlObjectClass objClass = Outlook.OlObjectClass.olAction;
                        m_typeOlObjectClass = objClass.GetType();
                    }
                    return (Outlook.OlObjectClass)System.Enum.ToObject(m_typeOlObjectClass, this.GetPropertyValue(OlClass));
                }
            }

            public string ConversationIndex
            {
                get
                {
                    return this.GetPropertyValue(OlConversationIndex).ToString();
                }
            }

            public string ConversationTopic
            {
                get
                {
                    return this.GetPropertyValue(OlConversationTopic).ToString();
                }
            }

            public object Copy()
            {
                return (this.CallMethod(OlCopy));
            }

            public System.DateTime CreationTime
            {
                get
                {
                    return (System.DateTime)this.GetPropertyValue(OlCreationTime);
                }
            }

            public void Display()
            {
                this.CallMethod(OlDisplay);
            }

            public Outlook.OlDownloadState DownloadState
            {
                get
                {
                    return (Outlook.OlDownloadState)this.GetPropertyValue(OlDownloadState);
                }
            }

            public string EntryID
            {
                get
                {
                    return this.GetPropertyValue(OlEntryID).ToString();
                }
            }

            public Outlook.FormDescription FormDescription
            {
                get
                {
                    return (Outlook.FormDescription)this.GetPropertyValue(OlFormDescription);
                }
            }

            public Object InnerObject
            {
                get
                {
                    return this.m_item;
                }
            }

            public Outlook.Inspector GetInspector
            {
                get
                {
                    return this.GetPropertyValue(OlGetInspector) as Outlook.Inspector;
                }
            }

            public Outlook.OlImportance Importance
            {
                get
                {
                    return (Outlook.OlImportance)this.GetPropertyValue(OlImportance);
                }
                set
                {
                    SetPropertyValue(OlImportance, value);
                }
            }

            public bool IsConflict
            {
                get
                {
                    return (bool)this.GetPropertyValue(OlIsConflict);
                }
            }

            public Outlook.ItemProperties ItemProperties
            {
                get
                {
                    return (Outlook.ItemProperties)this.GetPropertyValue(OlItemProperties);
                }
            }

            public System.DateTime LastModificationTime
            {
                get
                {
                    return (System.DateTime)this.GetPropertyValue(OlLastModificationTime);
                }
            }

            public Outlook.Links Links
            {
                get
                {
                    return this.GetPropertyValue(OlLinks) as Outlook.Links;
                }
            }

            public Outlook.OlRemoteStatus MarkForDownload
            {
                get
                {
                    return (Outlook.OlRemoteStatus)this.GetPropertyValue(OlMarkForDownload);
                }
                set
                {
                    SetPropertyValue(OlMarkForDownload, value);
                }
            }

            public string MessageClass
            {
                get
                {
                    return this.GetPropertyValue(OlMessageClass).ToString();
                }
                set
                {
                    SetPropertyValue(OlMessageClass, value);
                }
            }

            public string Mileage
            {
                get
                {
                    return this.GetPropertyValue(OlMileage).ToString();
                }
                set
                {
                    SetPropertyValue(OlMileage, value);
                }
            }

            public object Move(Outlook.Folder DestinationFolder)
            {
                object[] myArgs = { DestinationFolder };
                return this.CallMethod(OlMove, myArgs);
            }

            public bool NoAging
            {
                get
                {
                    return (bool)this.GetPropertyValue(OlNoAging);
                }
                set
                {
                    SetPropertyValue(OlNoAging, value);
                }
            }

            public long OutlookInternalVersion
            {
                get
                {
                    return (long)this.GetPropertyValue(OlOutlookInternalVersion);
                }
            }

            public string OutlookVersion
            {
                get
                {
                    return this.GetPropertyValue(OlOutlookVersion).ToString();
                }
            }

            public Outlook.Folder Parent
            {
                get
                {
                    return this.GetPropertyValue(OlParent) as Outlook.Folder;
                }
            }

            public Outlook.PropertyAccessor PropertyAccessor
            {
                get
                {
                    return this.GetPropertyValue(OlPropertyAccessor) as Outlook.PropertyAccessor;
                }
            }

            public void PrintOut()
            {
                this.CallMethod(OlPrintOut);
            }

            public void Save()
            {
                this.CallMethod(OlSave);
            }

            public void SaveAs(string path, Outlook.OlSaveAsType type)
            {
                object[] myArgs = { path, type };
                this.CallMethod(OlSaveAs, myArgs);
            }

            public bool Saved
            {
                get
                {
                    return (bool)this.GetPropertyValue(OlSaved);
                }
            }

            public Outlook.OlSensitivity Sensitivity
            {
                get
                {
                    return (Outlook.OlSensitivity)this.GetPropertyValue(OlSensitivity);
                }
                set
                {
                    SetPropertyValue(OlSensitivity, value);
                }
            }

            public Outlook.NameSpace Session
            {
                get
                {
                    return this.GetPropertyValue(OlSession) as Outlook.NameSpace;
                }
            }

            public void ShowCategoriesDialog()
            {
                this.CallMethod(OlShowCategoriesDialog);
            }

            public long Size
            {
                get
                {
                    return (long)this.GetPropertyValue(OlSize);
                }
            }

            public string Subject
            {
                get
                {
                    return this.GetPropertyValue(OlSubject).ToString();
                }
                set
                {
                    SetPropertyValue(OlSubject, value);
                }
            }

            public bool UnRead
            {
                get
                {
                    return (bool)this.GetPropertyValue(OlUnRead);
                }
                set
                {
                    SetPropertyValue(OlUnRead, value);
                }
            }

            public Outlook.UserProperties UserProperties
            {
                get
                {
                    return this.GetPropertyValue(OlUserProperties) as Outlook.UserProperties;
                }
            }

            #endregion

            #region Private Helper Functions
            private object GetPropertyValue(string propertyName)
            {
                try
                {
                    // An invalid property name exception is propagated to client
                    return m_type.InvokeMember(
                        propertyName,
                        BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty,
                        null,
                        m_item,
                        m_args);
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine(
                        string.Format(
                        "OutlookItem: GetPropertyValue for {0} Exception: {1} ",
                        propertyName, ex.Message));
                    throw;
                }
            }

            private void SetPropertyValue(string propertyName, object propertyValue)
            {
                try
                {
                    m_type.InvokeMember(
                        propertyName,
                        BindingFlags.Public | BindingFlags.SetField | BindingFlags.SetProperty,
                        null,
                        m_item,
                        new object[] { propertyValue });
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine(
                       string.Format(
                       "OutlookItem: SetPropertyValue for {0} Exception: {1} ",
                       propertyName, ex.Message));
                    throw;
                }
            }

            private object CallMethod(string methodName)
            {
                try
                {
                    // An invalid property name exception is propagated to client
                    return m_type.InvokeMember(
                        methodName,
                        BindingFlags.Public | BindingFlags.InvokeMethod,
                        null,
                        m_item,
                        m_args);
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine(
                        string.Format(
                        "OutlookItem: CallMethod for {0} Exception: {1} ",
                        methodName, ex.Message));
                    throw;
                }
            }

            private object CallMethod(string methodName, object[] args)
            {
                try
                {
                    // An invalid property name exception is propagated to client
                    return m_type.InvokeMember(
                        methodName,
                        BindingFlags.Public | BindingFlags.InvokeMethod,
                        null,
                        m_item,
                        args);
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine(
                        string.Format(
                        "OutlookItem: CallMethod for {0} Exception: {1} ",
                        methodName, ex.Message));
                    throw;
                }
            }
            #endregion

        }
    }

     

  • Office Developer Blog

    ExcelMashup.com debuts!

    • 12 Comments

    In Oct of this year, I blogged about the awesome new offering from the Excel team that gives developers the ability to create cool apps (like mashups) using an embedded Excel workbook on a host web page. Just using the Excel Services JavaScript API, a workbook stored on a public SkyDrive folder, and standard web technologies, you can create some really powerful apps that run in the browser (for example an app that combines Excel and Bing Maps to create a “Destination Explorer” mashup that shows stats on specific travel locations). As if having that capability wasn’t enough, in this blog post I’m going one better by announcing the debut of the ExcelMashup.com site!

    The ExcelMashup.com web site is a one-stop-shop for learning about how to get started developing rich, interactive mashups on your web site quickly using Excel Web App and the power of Excel formulas for calculation. At the heart of the site is the Get Started tab that should have you up and ready to start coding in minutes. There are also tabs to learn more about the technology, connect with the Excel development community, and find more information about related Excel development technologies. But by far, my favorite feature is the Interactive Code Snippets page.

    Code Snippets page

    image

    The Interactive Code Snippets page lets you try out code on a “live” embedded workbook, so you can play with and explore the code real-time, in action. The page is split into 3 sections: Tasks pane, Code Snippets pane, and the Output pane.

    1. The Tasks pane holds a list of the tasks you can try out. These are broken out into Basic Tasks and Full Examples:

    Tasks pane

    image

    2. The Code Snippets pane holds the code snippet for the selected task. Also, the Code Snippets pane has additional tabs: one for API reference material that’s tailored to the object model used in the code snippet; and one for comments from the community.

    Below the tabs for API References and Comments, there are 3 other small buttons shown in the Code Snippets pane.

    • Execute – Click this button to run the code in the code snippet
    • Reset – If you’ve altered the code in the code snippet, click this button to set the code snippet back to the original snippet
    • Parameters – If the code snippet takes parameters, this button will light up, indicating you can use it to enter the parameter(s)

    There’s also a copy code link so you can copy the code snippet for the task and paste it into your web page.

    But wait…there’s more! As if your thrill meter wasn’t already pegged, you can also alter the code in the code snippets pane and run that as well! That is, you can change a line of code—even add a whole function!--and then run the altered code snippet. As long as the code you added has the proper references and makes sense in the context, it should run.

    DISCLAIMER: The code used in the Code Snippets pane is for instructional purposes only and is not intended for any other purpose.

    Code Snippets pane

    image

    3. The Output pane displays the results of running the code snippet. One very cool feature of the Output pane is that it allows you to copy the code for the ENTIRE example web page using the HTML button. In this case, you don’t just copy the code snippet by itself; you copy all the code for the whole page, JavaScript and HTML. You could then paste that into a blank web page of your own and run it in the context of your own web site.

    Output pane

    image

     

    Output pane HTML

    image

     

    We want to hear from you!

    ExcelMashup.com is designed to be interactive with the user community. Visitors to the site can use the feedback button and the Comments pane on any of the code snippets to ask for more/different code snippets, suggest changes to site content, report bugs on the site, or even a kudos or two. New content will be posted to the site on a regular basis and some of it in response to user request. But why take just my word for it? Check out the ExcelMashup.com today!

  • Office Developer Blog

    Finding your way around Office developer documentation

    • 2 Comments

    I’d like to share with those of you who are new to Office solutions development a few tips about using Office developer documentation.

    Where

    Like most Microsoft products, our most up-to-date Office developer documentation is published on MSDN Library. The most common ways to find content is to use a search engine or the Table of Contents in the MSDN Library.

    Use roadmaps and developer centers to get a comprehensive view of available resources for each Office product, including code samples, videos, API references, blog posts by our writers, MVPs, and other community experts. For example:

    Consult product team blogs for a regular feed of best practices and tips, for example, Access Blog, Excel Blog, Outlook Blog, and Word Blog.

    MSDN Samples Gallery, CodePlex, and Channel 9 support Microsoft and community members sharing code examples, projects, videos, and articles.

     

    The rest of this post are tips about viewing documentation on MSDN.

    MSDN views

    MSDN Library offers three views: Lightweight, ScriptFree, and Classic. Use the default Lightweight view for a faster page load, particularly if you have relatively low Internet bandwidth. Use the Lightweight View to enjoy the fullest spectrum of features, for example, viewing a video in a Visual How To. The following screenshot shows a video player in the Lightweight View.

     

    If Internet performance is generally not an issue for you and being able to access a full Table of Contents to identify available content is a priority, for the time being, you can still use the Classic View. The following screenshot shows the Table of Contents in the Classic View.  


      

    In the longer term, more improvements will go only to the Lightweight View so that it will become the view of choice for all customers.

    Preferred programming language

    If a topic provides code in multiple languages, with one click, you can switch to display all code on that page to the programming language you choose. The following screenshot shows the Lightweight View of a topic that provides code in two managed languages, and clicking the VB tab displays all the code in Visual Basic.

     

     

    Sharing code samples

    On MSDN Library, use Community Content to share your code and related content. The preceding screenshot highlights one entry point to Community Content that is below the Table of Contents.

    Providing feedback

    We welcome feedback about our documentation or help experience. In Lightweight View, click the feedback icon at the end of a topic.

     

    In Classic View, use the Click to Rate and Give Feedback link at the top of the topic.

     

    In Scriptfree View, click the Feedback link at the top of the topic.

    Questions about your code

    Many Office MVPs and experts are active in MSDN forums that correspond to their areas of specialty. Share your code questions in the respective forums and learn from the community!

     

  • Office Developer Blog

    Using the Excel Services JavaScript API to Work with Embedded Excel Workbooks

    • 0 Comments

    In SharePoint 2010, Excel Services added support for ECMAScript (JavaScript, JScript). This enabled developers to automate, customize, and interact with an Excel Web Access Web Part control on a SharePoint page, but it was only available in SharePoint.

    Now, you can embed a workbook stored on Windows® Live® SkyDrive™ into a <div> element on your host web page  and then manipulate the workbook programmatically, using the same Excel Services JavaScript API that is available for SharePoint 2010. So just using an Excel workbook stored on SkyDrive, your web site, and the Excel Services JavaScript API, you can create cool apps like mashups using Bing Maps and embedded Excel workbooks!

    To get started with this:

    1. Store an Excel workbook on SkyDrive in a Public folder.

    2. Get the JavaScript embed code for embedding a workbook from the SkyDrive Embed dialog box. (The Embed dialog is available from the Share button on the Excel ribbon when you open the workbook in browser view.)

    3. Insert the embed code into the HTML of the host web page where you want to embed and manipulate the workbook.

    4. Add your custom code to the host web page.

    Embedded Excel + your web page + Excel Services JavaScript API == goodness!

    For more information about how to accomplish this solution and more, see Using the Excel Services JavaScript API to Work with Embedded Excel Workbooks.


  • Office Developer Blog

    Survey: What kind of Access, Excel, Outlook, and Word developer documentation helps you?

    • 2 Comments

    Our Office Dev Docs Team blog has been laying low while the team is heads-down authoring new content for our developers.

    Would you like to indicate the top 4 types of documentation that you find most helpful to you?

    1. Conceptual - what is the feature for, how does it work, why would one want to extend this feature?
    2. Conceptual - gives the basic info enough to get one started
    3. Conceptual - best practices for extending the feature
    4. Code samples - step by step walkthrough for how to create a simple example that extends the feature
    5. Code samples - short samples that show how to use specific facets of the feature
    6. Code samples - complex code samples for very specific scenarios
    7. Code samples - videos describing specific examples
    8. Reference - individual topics for each API

    You can reply with a prioritized list, from most useful to least useful to you. For example, you are just interested in seeing how things work and trying it out before you do any more reading, you can reply: 4,5,7,8. Let's see if we can use some of your responses in the next month to help us plan for future documentation!

     

  • Office Developer Blog

    Outlook 2010 MAPI Reference has been updated!

    • 0 Comments

    The Outlook 2010 MAPI Reference has recently been updated on MSDN. The Nickname Cache topic is now in sync with my earlier blog post Programmatically Accessing the Nickname Cache in Outlook 2010What's New in This Edition lists the following updates:

    • Using Microsoft Outlook 2010 and 64-bit MAPI requires more than the traditional 32-bit API for full implementation. The MAPI Stub Library, posted on the CodePlex website, provides a drop-in replacement for Mapi32.lib that supports building both 32-bit and 64-bit MAPI applications. For more information, see How to: Link to MAPI Functions and CodePlex.

    • The section Getting Started with the Outlook 2010 MAPI Reference has been updated to reference comprehensive information about programming models for your Outlook and MAPI functionality to help you identify the APIs and technologies that are most appropriate for your needs.

    • Autocomplete Stream—The Nickname cache topic, formerly the Nk2 File Format, has been updated to reflect changes in Outlook 2010. Information such as the autocomplete list, which is the list of names that displays in the To, Cc, and Bcc edit boxes while a user is composing an email, is now saved to the Autocomplete Stream of a message on the local computer rather than saving it to a file as in Outlook 2007.

      • Interacting with the Autocomplete Stream

      • Loading the Autocomplete Stream

      • Saving the Autocomplete Stream

    • MAPI Constants—The MAPI Constants have been consolidated. In previous releases they were distributed in a number of topics and now they are collected in a single topic to make them easier to discover and use.

    • Personal Store Override—The following interfaces and their respective methods have been added to support overriding the Personal Folders file (PST) store providers PSTDisableGrow policy.

      IPSTOVERRIDEREQ::IUnknown

      IPSTOVERRIDE1::IUnknown

    • Properties—The following tagged properties have been added:

    Enjoy MAPI!

  • Office Developer Blog

    Running Sample Outlook Add-in's

    • 0 Comments

    A few customers have asked about how to run the time-reporting add-in that was published on MSDN as Creating a Simple Time-Reporting Tool Based on the Outlook 2010 Calendar, and discussed in the blog post Time-Reporting Tool now Available as an Outlook Add-in!

    In general, because the main reason for us to provide code samples is to demonstrate programming techniques that use our object models, we typically provide only the source code for add-ins. For those of you interested in further customizing the add-ins, you are welcome to do so by downloading the source code, and using Microsoft Visual Studio to modify the code for your specific purposes.

    For those of you who have Microsoft Visual Studio 2010 and would like to run a sample add-in, you can start the add-in from Visual Studio by following this process:

    1. Download the source code from the indicated site. For example, for the time-reporting add-in, you can download the source files from Outlook 2010: Time-Reporting Tool Based on the Outlook 2010 Calendar.
    2. Unzip the set of source files, and double-click the solution file (.sln) of the add-in. This opens the solution in Visual Studio.
    3. In Visual Studio, build the solution by clicking Build and then Build Solution. The build action should succeed.
    4. Close Outlook if it is opened.
    5. Start the add-in by clicking Debug and then Start without Debugging. This opens Outlook and starts the add-in.

    As an example, to run the time-reporting add-in, you would need to have Microsoft Outlook 2010 installed. After running the above procedure in Visual Studio, Outlook opens and you should see the Add-Ins tab on the explorer ribbon in Outlook. Click the Add-Ins tab, and you can proceed to use the add-in as described in the article “Creating a Simple Time-Reporting Tool Based on the Outlook 2010 Calendar”.

    For those of you who do not have Visual Studio 2010 but would like to try the time-reporting add-in, I have attached an installation package in a zip file to this blog post for your convenience.

    Note: The time-reporting add-in was developed to illustrate programming techniques and is not intended to be a commercial product. The installation package was created using Visual Studio 2010 and the same add-in source code that is available for download. The package is provided for convenience, and has not been code-signed. After you run Setup in step 3 of the process below, you will see a dialog box that says “Publisher cannot be verified. Are you sure you want to install this customization.” Click Install if you want to proceed to try running the add-in.

    Follow these steps to use the attached installation package to install and run the time-reporting add-in:

    1. Close Outlook.
    2. Save a copy of the attached zip file for the installation package on your local drive.
    3. Unzip the installation package.
    4. Double-click the Setup.exe file to install the add-in.
    5. Open Outlook.
    6. You should see the Add-Ins tab on the explorer ribbon in Outlook. Click the Add-Ins tab, and you can proceed to use the add-in.

    If you are interested in creating your own installation package, you can see Deploying Office Solutions for more information.

  • Office Developer Blog

    Attaching a File or an Outlook Item to an Outlook Message

    • 0 Comments

    Attaching a file to a Microsoft Outlook mail item is one of the most popular customer actions in Outlook.

     

    Naturally, many power users also ask how to do this programmatically. The Outlook object model provides the Attachment object, Attachments.Add method, and an Attachments property for each of the Outlook item objects (for example, mail, appointment, contact, meeting, and task items), to support adding an attachment to an Outlook item. You can attach a copy of a file, an Outlook item like a message or contact, or an Object Linking and Embedding (OLE) object to an Outlook item. In particular, if you are attaching a file to a mail item that uses Rich Text Format (RTF), you can also specify the location to place the attachment in the body of the mail message, and the display name of the attachment.

    Ken Getz, a Microsoft MVP and an expert in a multitude of technologies including Microsoft Office, Microsoft Visual Studio, Visual Basic, and C#, recently contributed a set of four code samples to illustrate a few tasks around attachments.

    • How to: Attach a File to an Outlook Email Message illustrates the basic attachment task of programmatically attaching one or more files to an outgoing email message in Outlook. In order to send a mail message from a given SMTP email address, you also need to identify the corresponding Outlook account. This topic also shows the secondary tasks of finding the corresponding Account object given the SMTP address of the sender, creating the mail message, setting the recipients, subject, and body properties of the mail message, and finally sending the message that contains the attachments.
    • How to: Attach an Outlook Contact Item to an Email Message shows another basic attachment task of attaching an Outlook contact item to an outgoing mail message. This topic includes a secondary task of creating a contact item before attaching it and sending it along with the mail message.
    • How to: Limit the Size of an Attachment to an Outlook Email Message shows a practical task of how to programmatically check the total size of attachment files before actually sending a mail message. The topic shows a custom event handler for the Application.ItemSend event. The custom event handler uses the Size property of each attachment to sum up the total size of all attachments, compares the total size with the size limit, and cancels the send event if the total size exceeds the limit.
    • How to: Modify an Attachment of an Outlook Email Message is a slightly more advanced topic that shows how to use the MAPI property PidTagAttachDataBinary and the PropertyAccessor object to programmatically modify an attachment file before sending it along with the mail message. This technique is useful if, for example, you want to systematically convert text file attachments to upper case, before actually sending the mail message. This topic also makes use of the Application.ItemSend event.

    The sample code in these topics is presented in both C# and Visual Basic. Hope you can adapt the code to suit your scenarios.

  • Office Developer Blog

    Excel Services JavaScript Object Model (JSOM) Documentation Updated on MSDN

    • 0 Comments

    “When are they EVER going to revise the Excel Services JavaScript Object Model documentation for SharePoint Server 2010?"

    Well, as a member of "they," I'm glad you asked!

    The SharePoint Server 2010 Software Development Kit (SDK) online documentation was refreshed on June 28 and I'm happy to announce that as part of the refresh, the Excel Services JSOM documentation was also updated--in fact, it's been completely revised.

    Now, the topics for each object and function in the JSOM have full documentation, including Parameter info, Return Types, and  Remarks. We even tossed in Code Samples for good measure!

    MSDN_View

    Note to aspiring developers reading this: you no longer have an excuse not to create amazing solutions using the Excel Services JSOM!

    The Excel Services JSOM documentation is here. Make sure to leave feedback! You can do so using the feedback control at the top of each topic:

    MSDN_Feedback

    P.S. Why are you still reading this? Shouldn't you be looking at the revised Excel Services JSOM content? Smile

  • Office Developer Blog

    Importing Charts, Customizing the Ribbon, Starting Excel from Outlook

    • 0 Comments

    Often I see customers on forums asking how to display custom user interface in the Office Fluent ribbon under some specific conditions. For example, how to display a custom ribbon only for mail inspectors, or, how would one tell the inspector is in compose mode and not read mode. Browsing just the titles and summaries of existing code samples, such as those under Office UI Customization and Extending the User Interface in Outlook 2010, may not yield those samples that actually answer to such scenarios as well. Because of length restrictions, titles and summaries typically focus only on the core scenarios. So I think it’s worthwhile to point out some useful techniques in one of my recently published Visual How To, that you can easily apply in other common scenarios as well - customizing the ribbon, starting one Office application from another (in C#), and extending the status report automation scenario.

    The Visual How To, Automating Chart Importation from Excel to an Email Message in Outlook 2010, describes a simple, core scenario of programmatically copying a chart from an Excel worksheet to an email message that’s being composed in Outlook. The sample code uses the Outlook, Excel, and Word object models. The automation is useful if you have to regularly create status email messages that involve charts in Excel workbooks. You can have an add-in that creates an email message, opens the workbook in Excel, then copies and pastes a chart into the email message.

    Aside from showing the core scenario, there are a few secondary aspects of the Visual How To that I would like to highlight.

    Customizing the ribbon

    The custom user interface is a button “Copy Exel Chart” in its own group “MyGroup” and own tab “MyTab” in the Office Fluent ribbon.

     

    In this example, I want the custom tab to be displayed in the Outlook inspector ribbon, only when the user is composing an email message in an inspector.

    To do that, first, implement a custom even handler for the NewInspector event of the Inspectors object, to refresh the inspector ribbon before a new inspector is opened, by calling the IRibbonUI.Invalidate method.

    Second, implement the IRibbonExtensibility.GetCustomUI method so that Outlook loads the XML for the custom ribbon only when the context is the mail inspector in compose mode. The context is reflected by the ribbon identifier value Microsoft.Outlook.Mail.Compose. For more information about ribbon identifiers, see Extending the User Interface in Outlook 2010.

    Third, in the XML that specifies the custom UI, set the getVisible attribute of the custom tab to a callback method, MyTabInspector_GetVisible.

    Lastly, implement the MyTabInspector_GetVisible callback method to make sure that the custom UI is indeed displayed in the following conditions:

    • The Context property of the tab control, which represents the current window, is an Outlook Inspector object.
    • The item in the current inspector is a MailItem object.
    • The Sent property of the MailItem object in the current inspector is false, indicating that the mail is in compose mode.

    Starting Excel from Outlook in C#

    Before copying a chart from Excel, the sample code first checks if Excel is running. If Excel is running, the sample code uses that instance of Excel. If Excel is not already running, then the sample code starts Excel by creating an instance.

    To check if Excel is running on the customer’s computer, the code uses the GetActiveObject method of the Marhsal class. If Excel is not already running, the code uses the C# new keyword to create a new instance of Excel. Note that in Visual Basic, you can call the CreateObject function to start one Office application from another; however, C# does not support a CreateObject function.

    Extending the automation in Excel

    If the core scenario of automating chart importation interests you, you might also want to read the “Practical Extensions” section of the Visual How To, to see how you can use the Excel object model to update PivotTable data from an OLAP or SQL data source, and then update a PivotChart in Excel before copying the chart to Outlook.

  • Office Developer Blog

    Programmatically Accessing the Nickname Cache in Outlook 2010

    • 0 Comments

    I recently chatted with our MAPI expert Stephen Griffin and would like to share what I learned about the Outlook nickname cache.

    The nickname cache is the list of recipient names that is displayed when you insert names in the To, Cc, or Bcc field in an Outlook email or meeting request. The nickname cache expedites completing a recipient’s name, and is also known as the autocomplete stream.

    In Outlook 2010, the autocomplete stream is stored as a MAPI property, PidTagRoamingBinary, of a hidden message in the Associated Contents table of the Inbox of the mail account’s delivery store. This hidden message has a message class and subject of IPM.Configuration.Autocomplete.

    In an Outlook session, Outlook only loads and saves the autocomplete stream as a property of the hidden message at most once, and interacts with a copy in memory during the Outlook session. Outlook loads the autocomplete stream into memory when the user, for the first time in that Outlook session, attempts to insert recipients in an email or meeting request. Outlook reads all of the contents of the PidTagRoamingBinary property as a binary stream into a structure in memory. After loading the stream into memory, Outlook only accesses the copy in memory. If the copy is modified during that session, upon Outlook shutdown, Outlook saves the copy back to the hidden message in the Associated Contents table of the Inbox of the mail account’s delivery store.

    During an Outlook session, the autocomplete stream in memory can be modified in various ways including the following:

    • The user indirectly adds a new autocomplete entry, through resolving a name, picking a recipient from the address book dialog, or sending mail to a recipient that was not already in the list.
    • The user modifies an entry by sending mail to an existing recipient in the list.
    • The user removes an entry through the autocomplete drop-down list user interface.

    Only if the in-memory copy of the autocomplete stream has been modified does Outlook save the copy back to that hidden message on the mail account’s delivery store on Outlook shutdown.

    Follow the guidelines below if you want to programmatically access the autocomplete stream:

    • Interact with the autocomplete stream only while Outlook is not running. If you modify the stream while Outlook is running, Outlook will likely overwrite your changes when it shuts down.
    • Never partially modify the autocomplete stream. Always carry out the following process when updating:

                               i.          Read the whole stream into memory

                              ii.          Modify the memory structure

                             iii.          Write out the whole stream when the modifications are finished.

    • Only introduce properties to the stream that are of the supported types. The list of supported property types is as follows:
      • Static property values of the following types: PT_I2, PT_LONG, PT_R4, PT_DOUBLE, PT_BOOLEAN, PT_SYSTIME, PT_I8
      • Dynamic property values of the following types: PT_STRING8, PT_UNICODE, PT_CLSID, PT_BINARY, PT_MV_BINARY, PT_MV_STRING8, PT_MV_UNICODE

    To access the PidTagRoamingBinary property, you can use MAPI or the PropertyAccessor of the Outlook object model. The binary format of the autocomplete stream in Outlook 2010 is the same as that of the .nk2 file in Outlook 2007. For details about the binary stream format, see the document Outlook 2003/2007 NK2 File Format and Developer Guidelines. Note that this document was originally written for Outlook 2007 and Outlook 2003, and in Outlook 2010, the nickname cache is no longer stored in a .nk2 file, but in the MAPI property PidTagRoamingBinary, so you should disregard discussions of the .nk2 file and refer to the part of the document starting from the section “File Visualization”.

  • Office Developer Blog

    New Developer Roadmaps for Outlook, Visio, and Excel

    • 0 Comments

    Are you interested in learning to develop solutions for Outlook? The Outlook Developer Roadmap puts the the building blocks in clearer perspective. The Outlook Developer Roadmap is the latest in a series of Office developer roadmaps to help developers learn about available APIs and technologies supported by an Office application. Use the Outlook Developer Roadmap to explore one or more of its development technologies: Primary Interop Assembly, object model, MAPI, Auxiliary API, Outlook Social Connector provider extensibility, and Office Mobile Service.

     

    Interested in seeing the available APIs for Excel or Visio? Visit the Excel Developer Roadmap and Visio Developer Roadmap as well!

  • Office Developer Blog

    Office Client Content Published in April 2011: Excel, Open XML, Outlook, and Visio

    • 0 Comments

    Just wanted to provide a quick summary of content published on MSDN for Office client applications in April, 2011:

     API References
    and SDKs
     

     

     Technical Articles 

     Sample Code and Downloads 

     

     

    Visual How Tos

     

     

    Blog Posts

     

  • Office Developer Blog

    New Excel Macro Training Videos for Beginners!

    • 0 Comments

    Developers and power users new to programming with the Excel object model take note: there is a new series of videos that show how to create, edit, and run macros in Excel 2010: Save time by creating and running macros in Excel 2010!

     

    This set of 4 videos ranges in length from 3 to 5 minutes each. For our purpose of learning an object model, I'd like to call out the first two videos in the set: the first video in the series shows how to record a macro that fills a series of cells in a workbook. The second video shows how to view and edit the Visual Basic for Applications (VBA) code for the recorded macro in the Visual Basic editor. In general, for Office client applications that support macro recording (Excel, Visio, Word), using the Visual Basic editor to look at the code of a recorded macro is a convenient way to learn the application's object model, and how to write the code for a task that maps to a series of actions in the application's user interface. You can use the code for the recorded macro as a baseline, and extend its functionality by writing further code to achieve your purpose.  Recently I used a similar approach to learn how to use the Word object model to search for a string in an email message. I tried recording a Word macro of searching for a string in a Word document. Then I adapted the code and wrote the macro for the blog post  How to Search for a String in an Outlook Email Message and Automate a Reply that Contains the String.

    If you are new to programming with the Excel object model, or even Visio or Word, do take a look at the training videos and consider approaching the object models through recorded macros!

    
  • Office Developer Blog

    Nice Roll-up of Recent Publications: Access, Excel, Office, OneNote, Outlook, Visio, Word

    • 0 Comments

     

    API References
    and SDKs
     

     

      

    Technical Articles 

     

     

      

    Sample Code and Downloads 

     

     

     

     

     

    Visual How Tos

     

      

     

    Book Excerpts

     

     

    Blog Posts

     

  • Office Developer Blog

    New Content on Excel Services and Word Automation Services Development for SharePoint Server 2010

    • 0 Comments

    In addition to delivering developer-oriented content for the Office client applications such as Access, Excel, Outlook, Word, and Visio, the Office Client Developer Content team is also responsible for providing documentation on SharePoint Server service applications, such as Excel Services and Word Automation Services.

    Recently, we’ve published 3 Visual How To videos (with associated articles) that showcase how to create interactive solutions around Excel Services in SharePoint Server 2010. In addition to the videos, we’ve also made a superb book excerpt available that covers nearly the entire range of the Excel Services development landscape, including: client-side JavaScript; Excel Web Services; Excel REST; UDF; and Using Data Connection Libraries.

    For Word Automation Services, we’ve also included a new book excerpt that is a welcome addition to the content already available in the SharePoint Server 2010 SDK.

    Check it out!

    Excel Services

    Videos

    Using the Calculation Power of Excel Using Excel Services in SharePoint Server 2010

    Using the Excel Services REST API to Access Excel Data in SharePoint Server 2010

    Creating an Excel Services and Bing Maps Mashup for SharePoint 2010 Using the Excel Services ECMAScript Object Model

    Book Excerpt

    Microsoft SharePoint 2010 Web Applications: The Complete Reference - Chapter 12: Excel Services

     

    Word Automation Services

    Book Excerpt

    Microsoft SharePoint 2010 Web Applications: The Complete Reference - Chapter 10: Word Automation Services

  • Office Developer Blog

    Time-Reporting Tool now Available as an Outlook Add-in!

    • 0 Comments

    The time reporting macro that I blogged about a few months ago has been implemented as a C# Outlook 2010 add-in. The add-in's Visual Studio project is now available for download as part of the Visual How To Creating a Simple Time-Reporting Tool Based on the Outlook 2010 Calendar. This add-in has significant improvements in the input interface, and based on your input parameters, generates a time report file in Comma-Separated Values (csv) format.

    This add-in uses the same principles as the earlier macro to track time you spend on tasks -

    • You create an appointment in the Outlook default calendar to identify the time you spend on a task.
    • You assign one or more categories to an appointment to qualify the task. (Note: if you multitask during a period of time, it is fine to assign multiple categories for that appointment. Do not, instead, create appointments that have one category each and overlap them with one another.)

    For example:

    1. You can set up the two Outlook categories "Check email" and "Customer visit".
    2. You create a recurring appointment for 9-10am every morning, as this is the time you regularly spend on reading and responding to email.
    3. You assign that recurring appointment the category "Check email".
    4. Suppose you visited a customer today from 11-5pm. You then create an appointment for that period and assign it the "Customer visit" category.
    5. At the end of today, you can start the add-in, specify today's date as the time range to report on, select the categories that you'd like to report on, and generate the time-tracking report.

    This add-in has significant improvements in the following areas:

    A user-friendly interface allows you to select a date range and categories you'd like to report on, and whether you'd like a summary or detailed report

     

    A dialog box for you to specify the location and time report file.

    A resultant time report file in CSV format that you can conveniently view or edit in Microsoft Excel.

    The accompanying article for this add-in presents considerations for further business logic. Download the code, build the add-in in Visual Studio, and try it to help track your time!

  • Office Developer Blog

    Automating Highlighting of Search Results in an Outlook Message

    • 0 Comments

    Do you know about the new Outlook add-in that automates highlighting of your search string in an email message? The Visual How To, Automating Search Highlighting in Outlook 2010, provides a real add-in that you can build in Visual Studio and run with Outlook 2010, and that improves your experience searching for email content. Read on to also learn about doing programmatic searches and customizing the ribbon in Outlook!

    Improving Search Experience

    In Outlook, you can use Instant Search to search for items in a folder that contain a string of your choice. For example, you can search for “office”. Instant Search returns items that contain “office” in the subject or body, in the Outlook explorer. However, when you open a returned item in an inspector, the search string is not highlighted in the email body, as shown in the following screen shot.

    You will have to click Find in the Editing group of the Message tab, enter the search string again, and then click Find Next in order to see the occurrences within that email. These extra steps can be tedious if you are looking through multiple returned results to compare their content in inspectors.

    This add-in allows you to use just a single click to open a returned result, and all occurrences in the email body would be automatically highlighted in the mail inspector. See the following screen shot.

     

     

     

    The next screen shot shows the custom interface to use this custom search, and the regular user interface of Instant Search provided by Outlook.

     

    The custom search interface contains a text box, a search icon, and an Open Message with Highlights button.

     

    The text box plays a similar role as the Instant Search text box, and is there just to provide the search string entered by the user to the add-in.

    The following is the typical user search scenario:

    1.      Enter a search string in the text box adjacent to Search for.

    2.      Click Enter or the search icon to initiate the Instant Search.

    3.      From the list of search results returned by Instant Search, single-click a result item.

    4.      Click the Open Message with Highlights button.

    5.      The add-in opens the item in an inspector with all occurrences of the search string in the item’s body highlighted. 

     

    Programmatic Search

    Aside from improving the search experience with automatic highlighting, this add-in shows 2 ways of performing programmatic search in Outlook:

    ·        Using Explorer.Search to perform Instant Search on items in a folder

    ·        Using the Microsoft Word object model to search in a mail or meeting item in an inspector. That is, use the Inspector.WordEditor property to obtain the Word Document object, then get the Range object that represents the entire email body, and use the Find object to search and highlight occurrences of the original search string.

    Note: In Outlook, because a mail folder can contain mail items as well as other item types such as meeting item responses, before opening a search result item in an inspector, the add-in first has to identify the type of the selected item, and then uses the appropriate inspector to open the item. For example, the add-in uses MailItem.Display if the item is a mail item, and MeetingItem.Display if the item is a meeting item.

    There are other ways to perform searches in Outlook, see Enumerating, Searching, and Filtering Items in a Folder for details.

    Customizing the Ribbon

    This add-in also provides a useful example of how to customize the ribbon to meet its specific needs:

    ·        In order to search only mail folders, this add-in adds a custom tab to the ribbon on the mail explorer, but not to the ribbon for the other explorers such as the contacts explorer. To do that, in the ribbon XML, only specify idMso as TabMail, as shown below:

    <ribbon>

        <tabs>

        <tab idMso="TabMail">

            <group id="CustomSearch" label="Custom Search">

    ·        When you initiate Instant Search and when Instant Search returns, Outlook defaults to the Search Tools contextual tab in the explorer. In this scenario, after returning from Instant Search, the user should return to the Custom Search tab in order to use the custom button to open the message with highlighting. To achieve that, after returning from Explorer.Search, do the following:

    ribbonUI.ActivateTabMso("TabMail")

    ·        If the user switches to a different folder to do a new search, the add-in should clear the search text box to prepare for a new search. The add-in listens to the Explorer.FolderSwitch event and calls the IRibbonUI.Invalidate method to refresh the custom UI

    See the video, and view the code for more details!

     

     

  • Office Developer Blog

    How Do I Extend Outlook to Do…

    • 1 Comments

    Frequently we come across the question “How do I extend Outlook to do <a task>”. Depending on how extensive the task is, you might look for your answer in one or more of the following ways:

    • Use a search engine to see if someone has posted a solution to a similar question on the Internet.
    • Post your question on a forum such as Outlook for Developers or Visual Studio Tools for Office.
    • Post your question on a social network site, such as the MSDN Office and SharePoint Developer Centers fan page on Facebook.

    You can browse and get clues from code samples listed in the following locations on MSDN:

    There are close to 100 managed code samples listed on this page in the Outlook 2010 Primary Interop Assembly Reference. For example, How to: Create a Meeting Request, Add Recipients, and Specify a Location.

    There are many managed code samples in Visual Basic and C# under this folder and its subfolders, that use the Outlook Primary Interop Assembly (PIA), and are part of Office Development in Visual Studio 2010. For example, How to: Perform Actions When an E-Mail Message Is Received.

    There are code samples in Visual Basic for Applications and C# listed on this page in the Outlook 2010 Developer Reference. For example, How to: List the Name and Office Location of Each Manager Belonging to an Exchange Distribution List.

    You can download the MFCMAPI sample source files to examine example usage cases for many of the MAPI interfaces, as documented in the Outlook 2010 MAPI Reference.

    This topic lists sample tasks that use the APIs available in the Microsoft Outlook 2010 Auxiliary Reference.

    Often, you can choose to achieve a task by using the Outlook PIA, object model, Messaging API (MAPI), or Outlook Auxiliary API, or, a combination of these APIs. Other than API support and feasibility, there exists other criteria that you should consider when deciding how you should implement a solution. The following questions may come to mind:

    ·         Apart from the goals of the solution, the target market, and available resources, what other criteria should you consider to select the appropriate API?

    ·         If your solution has to run on earlier versions of Outlook, including Outlook 2003, how does that affect your API choice?

    ·         If your solution has to iterate through Outlook folders that contain thousands of items, and you need to be able to modify those items, which API would work best?

    ·         If your solution relies heavily on Outlook business logic and interacts with other Office applications, is the Outlook object model the best choice?

    ·         What do the object model and MAPI allow you to extend in Outlook?

    ·         If you can use either the object model or MAPI to achieve your task, how should you decide which API to use?

    ·         Do you use a managed or unmanaged language, and do you implement the solution in the same thread as Outlook or as a separate thread?

    ·         What’s the level of technical expertise required to use a certain API?

    To determine the best API or technology for your solution, you must first define the goals of your solution:

    ·         The versions of Outlook you intend your solution to support.

    ·         The high-priority scenarios of your solution and, in particular, whether these scenarios involve enumerating, filtering, or modifying folders that contain many Outlook items.

    Try to match your scenarios with those that the Outlook object model or the PIA supports. Before, this question required combing through the object model. Now you can refer to Decision Factors for the Object Model or PIA which contains a graphical listing of baseline scenarios supported by all versions of Outlook, followed by additional scenarios supported by Outlook 2007 and Outlook 2010. If the object model (or PIA) of your target Outlook versions supports your scenarios, and your solution does not manipulate folders with many items, you should implement your solution as an add-in, in either a managed or unmanaged language.

    If the object model (or PIA) of a target Outlook version does not support some of your scenarios, verify whether MAPI or the Auxiliary APIs meet your needs. You can refer to Decision Factors for MAPI or Decision Factors for the Auxiliary APIs. If MAPI meets your needs, you should implement your solution in unmanaged code. If an auxiliary API solves one of your scenarios, you can use managed or unmanaged code.

    If your solution uses MAPI, you must implement it in unmanaged code, such as C++. Otherwise, the decision to use managed or unmanaged code to create the solution generally depends on your available resources and their expertise. As for deciding whether to implement the solution as an add-in or standalone application, choose an add-in to avoid the user constantly invoking the Outlook Object Model Guard, unless your scenario requires manipulation of folders that contain numerous items. In the latter scenario, implementing the solution to run as a background thread can optimize Outlook performance.

    If your scenarios include showing social network information or updates in Outlook, you should use the Outlook Social Connector provider extensibility to create a COM-visible DLL. You can do this in either a managed or unmanaged language.

    Refer to Selecting an API or Technology for Developing Outlook Solutions for an in-depth analysis of how to determine the appropriate API or APIs for your Outlook scenario. Once you have decided on the APIs or technology to use in your solution, you can refer to additional documentation and code samples, as listed in the earlier part of this article.

  • Office Developer Blog

    Passing the correct units to Visio VBA methods

    • 1 Comments

    [Revised, thanks to suggestions from Eric Schmidt!]

    Certain methods in the Visio VBA object model take parameters that specify screen positions, typically for dropping new shapes or positioning existing ones. For example, the Page.DrawLine method takes four Double parameters-xBegin, yBegin, xEnd, and yEnd-that specify the x-axis and y–axis page coordinates of the beginning and end of the line you want to draw on the page. That’s all pretty straightforward. If your drawing uses US units (inches), the values you pass for these parameters will correspond exactly to the page coordinates where the beginning and end of the resulting line appear on your drawing page.

    So, let’s say you pass the method the following values: 3, 3, 8, 8, and that your drawing uses US units (inches). Remember that the coordinate origin (0,0) of the page in Visio is in the lower left-hand corner. Here’s what the result should look like:

    image

    But  now let’s say you want to draw a line in the same relative position on the page in a drawing that uses metric units (millimeters). Consider this page (note the metric units on the rulers):

    image

    You might expect to have to pass the method coordinates something like 50, 200, 100, 260. (Those numbers are not intended to be exact metric equivalents of the US units, but merely to represent points in the same general area of the page.) Try it and see what happens. Apparently, nothing happens! Your drawing will look exactly like the lower figure above—that is, an empty page. That’s unless you scroll around off the surface of the drawing page until, perhaps, you stumble upon the line you drew.

    The explanation is that despite the fact that your drawing is in metric units, Visio expects you to pass US units (inches) for the parameters of the DrawLine method. So, in fact, you told Visio to draw a line from the point 50, 200 to the point 100, 260—all in inches! No wonder it’s off the drawing page!

    DrawLine is just one of many methods that work this way. Others include the following:

    Page Object:

    • AddGuide
    • BoundingBox
    • DrawArcByThreePoints
    • DrawBezier
    • DrawCircularArc
    • DrawLine
    • DrawNURBS
    • DrawOval
    • DrawPolyline
    • DrawQuarterArc
    • DrawRectangle
    • DrawSpline
    • Drop
    • DropLinked
    • DropMany
    • DropManyLinked
    • DropManyU
    • PasteToLocation

    Shape Object:

    • AddGuide
    • BoundingBox
    • DrawArcByThreePoints
    • DrawBezier
    • DrawCircularArc
    • DrawLine
    • DrawNURBS
    • DrawOval
    • DrawPolyline
    • DrawQuarterArc
    • DrawRectangle
    • DrawSpline
    • Drop
    • DropLinked
    • DropMany
    • DropManyLinked
    • DropManyU
    • SetBegin
    • SetCenter
    • SetEnd

    Window object:

    • SetViewRect
    • SetWindowRect
    • ScrollViewTo

    Some methods of the Curve and Master objects also fall into this category.

    There is a Visio enumeration, VisMeasurementSystem, that contains constants that allow you to specify the measurement specify. But that enumeration is typically used only for methods whose purpose is to open a stencil; for example, the Documents.AddEx method. To the best of my knowledge, it isn’t used for methods like the position-related ones listed above. If you know of an example to the contrary, please let me know.

  • Office Developer Blog

    Use the Page.DropCallout method to add callouts to shapes programmatically in Visio 2010

    • 0 Comments

    [Note: This is the fourth in a series of blog posts that highlight some of the new members of the Visio 2010 VBA object model.]

    In the first post in this series, I talked about the Page.DropConnected method. In the second post, I featured the Page.LayoutChangeDirection method, which is another new method on the Page object of the Visio 2010 VBA object model that you might not yet have encountered. The Page.LayoutChangeDirection method makes it possible to rotate or flip a set of two or more connected shapes on the page as a unit, without having to rotate or flip the individual shapes. In the most recent post, I featured the Page.AutoConnectMany method, which you can use to automatically connect multiple shapes as you drop them on the drawing page.

    This post focuses on yet another new method on the Page object, the Page.DropCallout method, which creates a new callout shape on the page and associates the callout with the target shape you specify.

    The syntax for this method is as follows:

    Page.DropCallout(ObjectToDrop As Unknown, TargetShape As Shape)

    The DropCallout method operates on a Page object and takes two required parameters:

    • ObjectToDrop, which represents the callout shape to use.  This parameter is specified as [Unknown], which means that you can pass a Master, MasterShortcut, Shape, or IDataObject object.
    • TargetShape, which represents the existing shape on the page with which you want to associate the callout. If you don’t pass anything for this parameter, Visio puts the resulting callout at the center of the page and does not associate it with any shape in particular.

    The method returns a Shape object that represents the callout added to the page.

    The DropCallout method corresponds to the Callout command on the Insert tab in the Visio 2010 user interface:

    image

    When you click Callout, the Callout Gallery appears:

    image

    This gallery displays the various built-in callout shapes available in Visio 2010. When you pause the mouse over a callout shape, Visio both displays the name of the callout and previews its appearance. For example, here’s what the Word balloon callout looks like in preview:

    image

    It takes two steps to access these callout shapes programmatically:

    1. First, you get the hidden stencil that contains them. To do so, you use the Application.GetBuiltInStencilFile method, passing it the constants visBuiltInStencilCallouts (from the VisBuiltInStencilTypes enumeration, to specify the hidden stencil that contains callouts), and visMSUS (from the VisMeasurementSystem enumeration, to specify US units, assuming those are the units you want).
    2. Then you pass that hidden stencil to the Documents.OpenEx method, as well as the visOpenHidden constant (from the VisOpenSaveArgs enumeration, to specify that you don’t want to display the opened stencil in the stencil window).

    In the example code that follows, both of these steps happen in the same line of code, as you will see.

    Here’s an example of how the DropCallout method works. Suppose you have a blank Visio drawing and you want to first add a rectangle to the page and then add a Word balloon callout associated with the rectangle. Paste the following code into the Visual Basic Editor code window (to open it, press ALT+F11) and then run it:

    Public Sub DropCallout_Example()

    Dim vsoDocument As Visio.Document

    Dim vsoTargetShape as Visio.Shape

    Set vsoDocument = Application.Documents.OpenEx(Application.GetBuiltInStencilFile(visBuiltInStencilCallouts, visMSUS), visOpenHidden)

    Set vsoTargetShape =  ActivePage.DrawRectangle(3, 4, 6, 7)

    Application.ActivePage.DropCallout vsoDocument.Masters.ItemU("Word balloon"), vsoTargetShape

    vsoDocument.Close


    End Sub

    Your diagram should now look like this:

    image

    Additionally, you can access callout information about shapes and specify callout relationships between shapes by using three new properties on the Shape object:

    • The CalloutsAssociated property returns an array of Long values that contains the collection of IDs of the callout shapes associated with a specified target shape, or nothing if there are no callout shapes associated with the shape.
    • The CalloutTarget property gets or sets the target shape associated with a callout shape.
    • The Boolean IsCallout property returns True if the shape it’s called on is a callout shape.
Page 1 of 4 (79 items) 1234