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

March, 2011

  • 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.
  • Office Developer Blog

    How to Search for a String in an Outlook Email Message and Automate a Reply that Contains the String

    • 0 Comments

    I’d like to demonstrate a technique that helps automating email replies – when creating a reply to a message, search for a specific string, such as a reference number or item number, from the original message; dynamically create a greeting using the search result, and then automatically insert the greeting in the reply. This technique uses the object models of both Microsoft Outlook and Microsoft Word.

    The Scenario

    The example scenario assumes Microsoft Office 2010 (Microsoft Outlook 2010 and Microsoft Word 2010), or Microsoft Office 2007 (Outlook 2007 and Word 2007), and that you include the original email message when replying to it in an Outlook inspector. I also assume the following flow of actions:

    1.      Click Reply on an email message that may or may not contain an item number that matches the format “Item number: “ followed by 10 characters. See Figure 1.

    Figure 1. Create a reply email message in an inspector in compose mode.

    2.      Run the macro.

    The macro behaves in the following manner:

    1.      The macro looks for a string that follows this format: “item number: xxxxxxxxxx”, where “xxxxxxxxxx” matches any 10 characters following “item number: “.

    2.      If the original email message contains a string that follows the format: “item number: xxxxxxxxxx”, then the macro does the following:

    a.      Forms a default greeting phrase, “With reference to item number: xxxxxxxxxx”.

    b.      Inserts the greeting phrase as the first sentence in the reply.

    See figure 2.

    Figure 2. Outlook inserts in the reply a greeting phrase that contains a search result

    3.      If the original email message does not contain a string that follows the assumed format, then the macro displays a message “There is no item number in this message”.

     

    The Macro

    The following is the macro. I also attached a copy to this blog, so that you can conveniently copy and paste it in the Visual Basic Editor to try it out.

     

    Sub AutomateReplyWithSearchString()

        Dim myInspector As Outlook.Inspector

        Dim myObject As Object

        Dim myItem As Outlook.MailItem

        Dim myDoc As Word.Document

        Dim mySelection As Word.Selection

        Dim strItem As String

        Dim strGreeting As String

               

        Set myInspector = Application.ActiveInspector

        Set myObject = myInspector.CurrentItem

       

        'The active inspector is displaying a mail item.

        If myObject.MessageClass = "IPM.Note" And _

            myInspector.IsWordMail = True Then

            Set myItem = myInspector.CurrentItem

            'Grab the body of the message using a Word Document object.

            Set myDoc = myInspector.WordEditor

            myDoc.Range.Find.ClearFormatting

            Set mySelection = myDoc.Application.Selection

            With mySelection.Find

                .Text = "item number: ??????????"

                .Replacement.Text = ""

                .Forward = True

                .Wrap = wdFindContinue

                .Format = False

                .MatchCase = False

                .MatchWholeWord = False

                .MatchAllWordForms = False

                .MatchSoundsLike = False

                .MatchWildcards = True

            End With

            If mySelection.Find.Execute = True Then

                strItem = mySelection.Text

               

                'Mail item is in compose mode in the inspector

                If myItem.Sent = False Then

                    strGreeting = "With reference to " + strItem

                    myDoc.Range.InsertBefore (strGreeting)

                End If

            Else

                MsgBox "There is no item number in this message."

            End If

        End If

    End Sub

     

    Follow the steps below to use the macro that looks for a string that follows this format: “item number: xxxxxxxxxx”.

    1.      In Outlook, make sure the Developer tab is displayed in the ribbon.

    The Developer tab is hidden by default. To display the Developer tab:

    a.      Click File, then Options.

    b.      Click Customize Ribbon.

    c.      Click the check box adjacent to Developer.

    d.      Click Developer in the ribbon.

    e.      Click OK.

    2.      Click Visual Basic to start the Visual Basic Editor.

    3.      On the left, expand Project1 and then Microsoft Outlook Objects.

    4.      Double-click ThisOutlookSession.

    5.      Copy and paste the macro in the Project1 – ThisOutlookSession (Code) window. See figure 3. 

     

     Figure 3. Paste macro into the Visual Basic Editor.

    6.      Click Tools and then References.

    7.      Scroll down the list of Available References and click the type library for Word 2010, Microsoft Word 14.0 Object Library, to add it as a reference. (If you are using Microsoft Office 2007, you would be adding a reference to Microsoft Office Word 12.0 Object Library.)

    8.      Click OK.

    9.      Return to the Outlook explorer, and open an email message that you’d like to run the macro on.

    10.   Click Reply in the inspector ribbon, to create your reply email message in an inspector in compose mode. This is shown in figure 1.

    Note: make sure you do not select any text at this point.

    11.      Go back to the Visual Basic Editor.

    12.      Run the macro by clicking F5.

    13.      Return to the inspector in compose mode.

    If the original email message contains a string with the assumed format, you will see a greeting phrase “With reference to the item number: xxxxxxxxxx” inserted at the beginning of the reply. (“xxxxxxxxxx” is the first 10 characters following the string “item number: “ in the original email message.) See Figure 2. You can proceed to further modify the reply message before sending it.

    14.      If the original email message does not contain a string of the assumed format, then you will see a message “There is no item number in this message.” 

    The Solution

    The solution proposed in the last section assumes you are running Outlook 2007 or a later version, and that you have a reply window for an email message open as the current Outlook window. There are several checks for this condition.

    In Outlook, there are different inspectors for different types of items, a folder like the Inbox can technically contain items of different types, even though most commonly, items in the Inbox are email messages. Use the MessageClass property of an item to verify if the item is a mail item, contact item, and so on. The following lines of code check if the current Outlook inspector is displaying an email message:

    Set myInspector = Application.ActiveInspector

    Set myObject = myInspector.CurrentItem

    If myObject.MessageClass = "IPM.Note"…

    In the case that the item in the current inspector is an email message, because the solution will automatically write a phrase to the reply if the search returns a result, use the MailItem.Sent property, as shown in the following line of code, to check if the current inspector is displaying an email message in compose mode:

    If myItem.Sent = False Then…

    Prior to Outlook 2007, Outlook supported Word as one type of mail editors. Since Outlook 2007, Outlook uses Word as the only editor for all email messages. Outlook uses the Document object in the Word object model to facilitate all programmatic editing and formatting of the body of an email message.

    In order to use the Word object model, you need to do two things:

    ·        Add the Word type library, Microsoft Word 14.0 Object Library, as a reference in the Visual Basic Editor (see steps #6 through #8 above.)

    ·        And, use the following check to make sure the email editor is Word:

    myInspector.IsWordMail = True

    If the current inspector contains an email message and uses the Word editor, then, use the Inspector.WordEditor property to obtain the Word Document object that contains the body of the original email message:

    Set myDoc = myInspector.WordEditor

    To prepare to do a search in the Document object, use the myDoc.Range method that returns a Range object. This Range object represents the entire body of the original email message. Then use the Find.ClearFormatting method to remove text and paragraph formatting for the content in the Document object:

    myDoc.Range.Find.ClearFormatting

    Next, obtain another Find object from the Word application’s Selection object, and initialize the properties of this Find object:

    Set mySelection = myDoc.Application.Selection

    With mySelection.Find

        .Text = "item number: ??????????"

        .Replacement.Text = ""

        .Forward = True

        .Wrap = wdFindContinue

        .Format = False

        .MatchCase = False

        .MatchWholeWord = False

        .MatchAllWordForms = False

        .MatchSoundsLike = False

        .MatchWildcards = True

    End With

    Note the ‘?’ character is used as a wildcard symbol for any character. Setting mySelection.Find.Text to “item number: ??????????” requires Word to look for a string that contains “item number: “ followed by the next 10 characters.

    Also, as noted in step # 10 in the section, The Macro, make sure you do not have any text selected in the inspector at this point. Because of this empty selection, a subsequent call to Find.Execute will search the entire document.

    Find.Execute returns True if it finds the first occurrence that matches the specified string “item number: ??????????”. When Find.Execute returns True, Word also selects this first matching string. Using the returned string, construct a greeting phrase:

    strItem = mySelection.Text

    strGreeting = "With reference to " + strItem

    Lastly, use the InsertBefore method of the Range object returned by myDoc.Range to insert the greeting phrase at the beginning of the email reply:

    myDoc.Range.InsertBefore (strGreeting)

    Customizing the Macro

    You can use the described technique to customize the macro for your needs: by assigning a different search string to the Find.Text property, setting other properties as necessary for the Find object, constructing custom text, and inserting the custom text in appropriate locations in the reply email.

    For more information in using the Word object model to customize the format or content in an Outlook email messages as displayed in an inspector, see the Word 2010 Developer Reference. For more information about using the Outlook object model, including code samples and the Outlook 2010 Developer Reference, see the Outlook Developer Center.

     

     

     

     

Page 1 of 1 (3 items)