Chapter 9. SharePoint and Microsoft Office

Throughout this book, I have shown you the integration points between SharePoint and various Microsoft Office products. Generally, I have demonstrated integration points in context when those capabilities were related to the topic at hand. In this chapter, I will cover any additional integration points that have not been presented previously. I will also cover several aspects of custom development with Microsoft Office 2007 including the new open file formats and Visual Studio Tools for Office (VSTO). At the end of this chapter, you should have a strong understanding of all the techniques you can use to leverage Office in your SharePoint solutions.

Managing Document Information

At this point, you should be well-versed in the basic integration points between Office 2007 and SharePoint. You have seen and worked with both the Document Information Panel (DIP) and the Document Action Panel (DAP) in several places throughout the book. In this section, I cover some additional capabilities that you can use to enhance the integration between Office and SharePoint. I show you how to view related site data with the Document Management Information panel (which is different from the DIP), fill in document metadata values with Quick Parts, and customize the DIP with InfoPath.

Utilizing the Document Management Information Panel

The Document Management Information panel is a display present in Office 2003 that has been carried over to Office 2007. In Office 2003, this panel was called the Shared Workspace and presented information about the currently open document and the SharePoint site from which it originated. Although the panel has been renamed, it still presents the information as a series of five tabs named Status, Member, Tasks, Documents, and Links. Figure 9-1 shows a typical Document Management Information panel open in Word 2007.

A Document Management Information panel

Figure 9.1. A Document Management Information panel

The Status tab in the Document Management Information panel is used to present document status such as whether it is checked out and by whom. The Members tab lists all the users and groups that have access to the document. Additionally, if the members are running Microsoft Communicator or MSN Messenger, the tab will show presence information. Presence information indicates whether a user is online. Additionally, you can send e-mail and schedule meetings with members using the presence information interface. If a task list exists on the site, the Tasks tab will display the list. The Documents tab shows a list of documents that are in the same library as the currently open document. Finally, if there is a links list on the site, those links will appear in the Links tab.

The Document Management Information panel does not open by default. If you want to see it, you can select Server

A Document Management Information panel

Although the Document Management Information panel contains some useful information, you may be confused at first as to why you would see things such as tasks and links. These tabs appear primarily because the Document Management Information panel is actually designed to be used with a specific type of site called a Document Workspace. A Document Workspace is a site that is dedicated to the creation of a single document. You can create a Document Workspace directly from Word, Excel, or PowerPoint and then use it as a way to collaborate.

Follow these steps to create a Document Workspace:

  1. Log in to VSCLIENT.

  2. Select Start

    A Document Management Information panel
  3. In Word 2007, select Publish

    A Document Management Information panel
  4. In the Document Workspace creation panel, select My Site from the drop-down list labeled Location for New Workspace.

  5. Click the Create button.

  6. When prompted, save the new document locally on VSCLIENT. You do not have to worry about the exact location because the document will be uploaded automatically to the new Document Workspace.

  7. After the new Document Workspace is created, verify that the Document Management Information panel opens and click the link titled Open Site in Browser.

  8. When the Site opens, verify that your document has been uploaded to the Shared Documents library. You can now invite others to this site to work on the document with you.

Using the Research Library

Using document workspaces through SharePoint helps end users assign tasks and assemble documents more easily when those documents are primarily built by teams. However, these collaboration features do not help the individual locate the actual information required to create the document. What is missing from the solution is a general tool that can bring back various types of information. This is where the Research Library comes into play. The Research Library is a general-purpose search tool that can search for information in reference books, line-of-business systems, the Internet, and even SharePoint. Out of the box, the Research Library provides access to several sources of information such as a dictionary and thesaurus.

The Research Library is accessible from the ribbon on the Review tab. On the Review tab, you'll find the Research button located in the Proofing group. Using the Research Library is straightforward regardless of the source you want to search. The end user simply selects a service and types a search string into the task pane. The Research Library then searches the selected service for responses to the search string. The responses vary depending upon the service. The Research Library might display definitions, alternative word choices, Internet hyperlinks, or any other kind of appropriate information. In many cases, you can then insert the information directly into your document.

The initial set of services that ship with Office 2003 are only moderately interesting, but the true value of the Research Library lies in the fact that you can extend the library to include SharePoint sites and other services. This is possible because the Research Library architecture is based on web services, and SharePoint web services can be used as a source for the Research Library.

To search a SharePoint Services site, follow these steps:

  1. Open the Research Library in Microsoft Word by clicking the Review tab and then clicking the Research button.

  2. At the bottom of the Research pane, click the Research Options link.

  3. In the Research Options dialog, click the Add Services button.

  4. In the Address box, type the URL http://vsmoss/_vti_bin/search.asmx.

  5. Click Add.

  6. In the Confirmation and Options dialog, click the Install button.

  7. Close the Research Options dialog.

  8. In the Research pane, select the SharePoint source from under the All Intranet Sites and Portals section of the drop-down list.

  9. Type a search string into the Search For box and click the green arrow.

Working with Quick Parts

You have already seen in several examples how the DIP makes it easier for end users to fill in metadata for a document. The DIP presents the metadata fields in the document so that they can be filled in whenever the user knows the values. Additionally, the DIP can support elements such as lists to make it even easier to fill in valid data. While this approach is good, it certainly does not guarantee that good metadata is entered; after all, the end user could just simply type nonsense into the fields.

The solution to getting good metadata out of end users is to automatically populate the metadata from information in the document. This is where Quick Parts come into play. Quick Parts are a way to map the metadata fields in the DIP to text in the document template. In order to utilize Quick Parts, you should start with an existing content type for which you have already defined a template. Then you can enhance the content type with Quick Parts. As an example, you could take the Invoice content type you created in the exercise in Chapter 6 and enhance it to use Quick Parts.

If you completed Exercise 6-1, follow these steps to use Quick Parts:

  1. Log in to VSCLIENT as a SharePoint administrator.

  2. Navigate to the home page of the intranet site you created in Chapter 2.

  3. Click the Document Center tab.

  4. In the Document Center, click the Financial Documents library that you created in Exercise 6.1 in Chapter 6.

  5. In the Financial Documents library, select New

    Working with Quick Parts
  6. When the new Invoice document opens in Word, select the [Company Name] field in the body of the document and delete it.

  7. Click the Insert tab.

  8. On the Insert tab, select Quick Parts

    Working with Quick Parts
  9. Click in the Job cell of the table in the Invoice document.

  10. On the Insert tab, select Quick Parts

    Working with Quick Parts
  11. Select File

    Working with Quick Parts
  12. Close Word and return to the home page of the intranet site you created in Chapter 2.

  13. Select Site Settings

    Working with Quick Parts
  14. On the Site Settings page, click the Site Content Types link.

  15. In the Site Content Type Gallery, click the Create link.

  16. On the New Site Content Type page, enter Enhanced Invoice in the Name field.

  17. Select Custom Financial Documents from the drop-down list labeled Select Parent Content Type From.

  18. Select Invoice in the drop-down box labeled Parent Content Type.

  19. Select Custom Financial Documents in the drop-down list labeled Existing Group.

  20. Click the OK button to create the new content type.

  21. In the Site Content Type Gallery, click the link for the new Enhanced Invoice.

  22. On the Site Content Type page, click the Advanced Settings link.

  23. On the Site Content Type Advanced Settings page, select the option to Upload a New Document Template and click the Browse button.

  24. In the Choose File dialog, navigate to the My Documents folder and select the Enhanced Invoice template you saved earlier.

  25. In the Choose File dialog, click the OK button.

  26. On the Site Content Type Advanced Settings page, click the OK button.

  27. Click the Document Center tab.

  28. In the Document Center, click the Financial Documents library in the Quick Launch area.

  29. Select Settings

    Working with Quick Parts
  30. On the Customize page, click the link titled Add from Existing Content Types.

  31. On the Add Content Types page, select the Enhanced Invoice from the list labeled Available Site Content Types.

  32. Click the OK button to add the content type to the Financial Documents library.

  33. Return to the Financial Documents library and select New

    Working with Quick Parts
  34. When the new document opens, type a name in the Client Name metadata field in the Document Information Panel. Verify that the name appears in the document after you move the focus away.

  35. Enter some text in the [Title] field in the Job cell of the document and verify that it appears in the Document Information Panel after you move the focus away.

Creating Custom Document Information Panels

Although SharePoint provides a default DIP for your content types, there may be times when you want to customize the DIP. Customizing the DIP is possible because the DIP is nothing more than an InfoPath form; therefore, you can add validation rules, format, graphics, or other elements to enhance the DIP. You may use any available InfoPath elements and functionality to create your custom DIP, but if you use elements that require full trust, the DIP must be signed just like any other InfoPath form.

Follow these steps to create a custom DIP:

  1. Log in to VSCLIENT as a SharePoint administrator.

  2. Navigate to the home page of the intranet site you created in Chapter 2.

  3. Select Site Settings

    Creating Custom Document Information Panels
  4. On the Site Settings page, click the Site Content Types link.

  5. In the Site Content Type Gallery, click the link for the Financial Document content type.

  6. On the Site Content Type page, click the Document Information Panel Settings link.

  7. On the Document Information Panel Settings page, click the link titled Create a New Custom Template.

  8. When InfoPath starts, click the Finish button in the Data Source wizard.

  9. When the DIP form appears, right-click the Amount field and select Text Box Properties from the context menu.

  10. In the Text Box Properties dialog, click the Data Validation button.

  11. In the Data Validation dialog, click the Add button.

  12. In the Data Validation Condition dialog, select Is Less Than from the operator drop-down list.

  13. Select Type a Number from the Argument list and enter 0.

  14. Enter Value must be a positive number in the Screen Tip field.

  15. Click the OK button.

  16. In the Data Validation dialog, click the OK button.

  17. In the Text Box Properties dialog, click the Format button.

  18. In the Decimal Format dialog, select 2 in the Decimal Places drop-down list.

  19. Click the OK button.

  20. In the Text Box Properties dialog, click the OK button.

  21. Select File

    Creating Custom Document Information Panels
  22. In the Save As dialog, save the form as CustomDIP.xsn to the My Documents folder. The location is not critical because publishing the form will automatically upload it to SharePoint.

  23. After the form is saved, click the Publish Form Template link in the Design Tasks pane.

  24. In the Publishing Wizard, select to publish the form As a Document Information Panel Template for a SharePoint Site Content Type or List Content Type.

  25. Click the Next button.

  26. On the next screen, verify that the correct content type appears, and click the Publish button.

  27. After the form is published, click the Close button and exit InfoPath.

  28. In the browser, click the link titled Go Back to the Document Information Panel Settings Page.

  29. On the Document Information Panel Settings page, click the OK button.

Now you should be able to return to the Financial Documents library, open any existing document, and see the custom DIP in action. Figure 9-2 shows the custom DIP identifying a validation error caused by a negative value and formatting the number to have two decimal places.

A custom DIP

Figure 9.2. A custom DIP

Going Offline

Although the SharePoint interface could be used to access all manner of information and documents within an organization, most users still think of Microsoft Outlook as their "home base." Because the information in Outlook is personal in nature, it is the most logical choice to function as the center of a person's day. This means that many end users will want to leverage Outlook as much as possible for consuming information and only leave when it is absolutely necessary.

To this end, Outlook 2007 provides strong integration with SharePoint. In Chapter 3, I describe several of the key integration points between lists and Outlook. In particular, I show that you can synchronize lists with Outlook by selecting Actions

Going Offline

When you take a document library offline, the list of available documents appears inside of Microsoft Outlook and is downloaded to an Outlook PST file named SharePoint Lists.pst. Outlook will allow you to preview the documents, but they are stored in the PST file as read-only copies. In order to make changes to the documents, they must be opened in the appropriate Office product and then edited offline.

Selecting to edit the document offline will save it into the folder My DocumentsSharePoint Drafts. Office keeps track of the fact that the document is being edited offline and allows you to synchronize it with SharePoint the next time you are online. Although you can check out a document before taking it offline, nothing prevents you from editing a document offline that you did not check out. In these cases, you may have several people making changes to the same document offline, resulting in conflicts that must be resolved during synchronization. Document conflicts such as these are handled by the Office product itself using the Document Updates pane. This pane allows you to merge conflicting changes, open both conflicting documents, and make manual changes, or simply write your changes over the saved changes. Figure 9-3 shows the Document Updates pane.

Resolving document conflicts

Figure 9.3. Resolving document conflicts

Note

There is no way to prevent Outlook from downloading all of the documents in a library when you go offline. While this makes it easy to grab a library and run, it also means that you can be downloading a significant amount of information. Documents that are candidates for offline use should be segregated into separate smaller libraries to make downloading efficient.

Going Mobile

Support for mobile devices is now built in to SharePoint through a set of pages located in the folder C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTSMOBILE. The pages support a default mobile view for any site in SharePoint by simply navigating to the address of the home page with /_layouts/mobile/default.aspx appended. For example, you can view the home page of your intranet by navigating to http://vsmoss/intranet/_layouts/mobile/default.aspx.

While you can certainly view the mobile pages in your desktop browser, it is much more useful to view them as they will actually appear in a device. In order to accomplish this, you can utilize the device emulator that is part of Visual Studio 2005. This emulator simulates several different devices on your desktop so you can target your development. In order to get the emulator working, however, you have to set it up as if you were synchronizing an actual mobile device.

Follow these steps to view your sites in the device emulator:

  1. Log in to VSMOSS as a local administrator.

  2. Download and install the ActiveSync 4.2 software from http://www.microsoft.com/windowsmobile/downloads/activesync42.mspx. This software is used to connect mobile devices to your desktop.

  3. Select Start

    Going Mobile
  4. Select Tools

    Going Mobile
  5. In the Device Emulator Manager dialog, select Pocket PC 2003 SE Emulator.

  6. Select Actions

    Going Mobile
  7. Select Start

    Going Mobile
  8. In the Device Emulator Manager dialog, make sure that the Pocket PC 2003 SE Emulator is selected. Select Actions

    Going Mobile
  9. In the New Partnership wizard, select Guest Partnership and click the Next button.

  10. When the Microsoft ActiveSync dialog indicates that the device is connected, select Start

    Going Mobile
  11. Enter http://vsmoss/intranet/_layouts/mobile/default.aspx in the address bar and click the green arrow to open the page. You should now see the mobile version of the intranet home page.

When you first view a site through the emulator, you'll see a page with links to the standard lists and libraries such as Announcements, Tasks, and Shared Documents. If you want to add other lists to the mobile view, you must explicitly designate a list view as mobile. This is accomplished from the Edit View page associated with the view you want to display. The Mobile section contains options that you can select to make the view mobile as well as make it the default mobile view for the list. Figure 9-4 shows the Mobile section on the Edit View page.

Designating mobile views

Figure 9.4. Designating mobile views

In addition to exposing lists for mobile consumption, you can also create your own custom pages for use with mobile devices. When you create your own custom pages, you can tailor them for display on a specific device. Additionally, you can utilize SharePoint object model code in the page. Developing for mobile devices is another broad category that goes beyond the scope of this book, but you can create some simple pages for mobile devices quite easily in Visual Studio.

Follow these steps to create a home page for a mobile device that displays all the sites in a collection:

  1. With Visual Studio 2005 still open from the previous example, select File

    Designating mobile views
  2. In the New Web Site dialog, select ASP.NET Web Site from the list of templates.

  3. Select File System from the Location drop-down list.

  4. Select Visual C# from the Language list.

  5. Click the OK button.

  6. When the new project opens, select the Default.aspx page in the Solution Explorer and delete it.

  7. Right-click the project in the Solution Explorer and select Add New Item from the context menu.

  8. In the Add New Item dialog, select Mobile Web Form.

  9. Name the new form Home.aspx.

  10. Make sure the box labeled Place Code in a Separate File is not checked. You cannot use code-behind in this solution.

  11. Click the Add button.

  12. When the new page opens, add the bolded code in Listing 9-1 to the page. This code adds references to the SharePoint object model and then uses the object model to get the address for each site in the collection. The address is then displayed in a new instance of a mobile Link control. I cover the SharePoint object model in detail in Chapter 11.

    Example 9.1. A Mobile Home Page

    <%@ Page Language="C#" Inherits="System.Web.UI.MobileControls.MobilePage" %>
    <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0,
               Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
    <%@ Import Namespace="Microsoft.SharePoint" %>
    <%@ Import Namespace="Microsoft.SharePoint.WebControls" %>
    <%@ Import Namespace="System.Web.UI.MobileControls" %>
    <%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls"
        Assembly="System.Web.Mobile" %>
    
    <script language="c#" runat="server">
    
        public void Page_Load()
        {
            SPSite site = SPControl.GetContextSite(Context);
            SPWebCollection webs = site.AllWebs;
    
            foreach (SPWeb web in webs)
            {
                Link webLink = new Link();
                webLink.NavigateUrl = web.Url +
                  "/_layouts/mobile/default.aspx";
                webLink.Text = web.Title;
                welcomeForm.Controls.Add(webLink);
    
            }
        }
    
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <body>
        <mobile:Form ID="welcomeForm" Runat="server">
            <mobile:Image ID="bannerImage" Runat="server"
            ImageUrl="../images/addtofavorites.gif">
            </mobile:Image>List of Sites<br />
        </mobile:Form>
    </body>
    </html>
  13. Once you have edited the code, save your work.

  14. Open the File Explorer and locate the Home.aspx page. Copy this page in to the LAYOUTSMOBILE directory.

  15. Using the mobile emulator that you opened earlier, navigate to the address http://vsmoss/intranet/_layouts/mobile/home.aspx. You should now see a list of available sites with links. Figure 9-5 shows the resulting page displaying various sites.

A custom mobile welcome page

Figure 9.5. A custom mobile welcome page

Using the Office Open XML File Formats

Microsoft Word, Excel, and PowerPoint have new default XML file formats designed to make Office 2007 more extensible and interoperable. Throughout the book, you have made documents in these new formats, saved them to libraries, and used them for content types. As a user, you might not have even realized that a new file format was in use unless you noticed the new DOCX, XLSX, or PPTX file extensions.

The new file formats are based on the XML Paper Specification written by Microsoft. The idea is to create an open standard for document definitions so that they may be viewed in different tools and transformed between systems. All of this is intended to support interoperability between systems. Saving documents in the older format is still supported as an option, but you must explicitly select it in the Save dialog. As SharePoint developers, we care about these new file formats because they allow us to manipulate documents outside of Word, Excel, and PowerPoint.

In earlier versions of Office, the file format was a proprietary binary format that was completely undocumented. From a development perspective, the only way to manipulate a document was to use the object model through automation. This meant starting Word or Excel programmatically and then executing operations against it, such as creating new documents, importing data, or printing reports.

The problem with automating Word and Excel is that they were never intended to function as server products, but they were often deployed on servers to centralize the automation. Furthermore, the instances started in automation never really seemed to shut down. I have seen many Word and Excel automation applications that left countless copies running on the server. Generally, no one realized this was happening until the server ground to a crawl from lack of resources.

As Office moved forward, Microsoft tried to better this situation by introducing various levels of XML support and new ways to develop with Office applications. While these efforts improved some aspects of development, we were still never able to completely divorce ourselves from Word and Excel. The new XML file formats finally change that situation. Now we can write document-based applications without ever starting a copy of Word or Excel.

Understanding Document Packages

The new Office file formats consist of many different XML files all contained in a compressed ZIP file. This compressed ZIP file is called a document package and contains all of the content in a document including text, images, comments, change tracking, properties, and so on. Word, Excel, and PowerPoint all employ this same basic format but utilize different file extensions to designate documents, templates, and macros. Table 9-1 lists all of the file extensions for Word, Excel, and PowerPoint, and the associated document type.

Table 9.1. Office 2007 File Extensions

Extension

Document Type

DOCX

Word 2007 document

DOTX

Word 2007 template

DOCM

Word 2007 document containing macros

DOTM

Word 2007 template containing macros

XLSX

Excel 2007 document

XLTX

Excel 2007 template

XLSM

Excel 2007 document containing macros

XLTM

Excel 2007 template containing macros

PPTX

PowerPoint 2007 document

POTX

PowerPoint 2007 template

PPTM

PowerPoint 2007 document containing macros

POTM

PowerPoint 2007 template containing macros

The simplest way to become familiar with the file formats is to create a new document and then extract the package contents. This is possible because the package is simply a ZIP file. You can use standard ZIP utilities to open the package and view its contents.

Follow these steps to extract package contents:

  1. Log in to VSCLIENT.

  2. Select Start

    Office 2007 File Extensions
  3. In Word 2007, select New from the File menu.

  4. In the New Document dialog, select memos from the Templates list.

  5. Select Memo (Contemporary Design) from the Memos list view.

  6. Click the Download button to download the new template from the Microsoft site.

  7. When the new memo appears, click the Insert tab.

  8. On the Insert tab, click the Picture button.

  9. In the Insert Picture dialog, open the Sample Pictures folder.

  10. Select a sample picture from the folder and click the Insert button.

  11. Select Save from the File menu.

  12. Save the document as Memorandum.docx to the My Documents folder.

  13. Exit Word 2007.

  14. Open the File Explorer and navigate to the My Documents folder.

  15. In the My Documents folder, create a new folder named Package.

  16. Right-click the Memorandum.docx file and select Rename from the context menu.

  17. Rename the file to Memorandum.docx.zip.

  18. Right-click the Memorandum.docx.zip file and select Open With

    Office 2007 File Extensions
  19. Copy the contents from the open ZIP folder into the Package folder.

Once you have the file extracted, you will see that the package is made up of many files with XML extensions, one file with a JPEG extension, and several files with RELS extensions. Each of the XML files in the package is referred to as a Part Item. Resource files stored in the package, such as images, are referred to as Content Type Items (not to be confused with content types in SharePoint). The files with the RELS extensions are referred to as Relationship Items because they define the relationships between the Part Items and Content Type Items.

You'll also notice in the File Explorer that the package files have a certain folder structure. Initially, this may lead you to believe that the folder structure is specified as part of the package file format. However, this is not the case. The parts and content types are held together by the relationships, which are independent of any particular file folder structure.

Understanding the package structure begins by examining the [Content_Types].xml file. This file lists all of the parts in the package and their associated content type. If you examine this file, you'll see references to various parts of the document, including the document body, headers, footers, and styles. Listing 9-2 shows some sample entries from the [Content_Types].xml file.

Example 9.2. The [Content_Type].xml File

<Override PartName="/word/document.xml"
ContentType="application/vnd.openxmlformats-
The [Content_Type].xml File
officedocument.wordprocessingml.document.main+xml"/> <Override PartName="/word/styles.xml" ContentType= "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/> <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats- officedocument.wordprocessingml.settings+xml"/> <Override PartName="/word/footer2.xml" ContentType="application/vnd.openxmlformats- officedocument.wordprocessingml.footer+xml"/>

The entries in the [Content_Types].xml file define names for the parts using the PartName attribute. These entries could be changed to any name and are not related to the package structure. The ContentType attribute specifies the actual type of information that is found in the part item. The +xml suffix designates the part item as an XML file.

Because the part items are all XML files, you can open these and examine the contents as well. For example, the document.xml file contains the bulk of the content for the memorandum document. If you open this document in Visual Studio, you'll see that the XML file has text from the memo and a reference to the picture that you inserted into the body. Any changes made to this file will impact the document as it appears in Word.

Follow these steps to make a document change:

  1. With the Memorandum.docx.zip file still open in the My Documents window, drag the document.xml file onto the desktop. Be sure to take this file from the compressed files and not the files you extracted earlier.

  2. Right-click the document.xml file and select Open With

    The [Content_Type].xml File
  3. Select Edit

    The [Content_Type].xml File
  4. In the Find dialog, type How to Use This Memo Template and click the Find Next button.

  5. In the Find dialog, click the Cancel button to close it after the search text is located.

  6. Change the selected text to read How to Change the Text in a Document.

  7. Select File

    The [Content_Type].xml File
  8. Carefully drag the document.xml file from your desktop back into the open Memorandum.docx.zip file.

  9. In the File Explorer, rename the file Memorandum.docx and open it in Word 2007. You should now see your changes.

The structure of the package is defined by the relationship files. Relationship files are XML files that map content types to specific directories within the structure. This is what allows Word to assemble the document from the part items. Each entry in the file uses a Type attribute for a content type, and a Target attribute to reference a file. Listing 9-3 shows a relationship file from the sample in this chapter. Note how it maps the document.xml file you edited earlier.

Example 9.3. A Relationship File

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">

<Relationship Id="rId3"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships
A Relationship File
/extended-properties" Target="docProps/app.xml"/> <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships
A Relationship File
/metadata/core-properties" Target="docProps/core.xml"/> <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships
A Relationship File
/officeDocument" Target="word/document.xml"/> <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships
A Relationship File
/custom-properties" Target="docProps/custom.xml"/> </Relationships>

Using System.IO.Packaging

While making changes to part items in a package is a neat trick, it's definitely not the way that you want to go about creating production applications with Office 2007. If you did, your application would have to parse countless lines of XML, searching for key elements to replace. That would be maddening to say the least. Fortunately, Microsoft has provided us with an additional layer of abstraction for working with packages in the form of the System.IO.Packaging namespace.

The Packaging namespace provides a set of classes that allow you to deal with the constituent parts of a package instead of the raw XML. The Package class represents the entire package file created by Word, Excel, or PowerPoint. You can use this class to open existing files or create new ones. The PackagePart class represents all of the part items inside the package file. You can use this class to add or edit part items. The PackageRelationship class represents all of the relationships in the package file. You can use this class to locate dependent parts.

The System.IO.Packaging namespace is part of the .NET Framework 3.0. You installed the .NET Framework 3.0 on VSMOSS (or VSWSS) when you created the development environment outlined in Chapter 2. In order to use the Packaging namespace, you must set a reference to it in Visual Studio 2005. However, the assembly containing the namespace is not easy to find initially. That's because it is located at C:Program FilesReference AssembliesMicrosoftFrameworkv3.0WindowsBase.dll, which is an odd place to put an assembly. Nonetheless, you can browse there and set a reference.

Once you set a reference to the WindowsBase assembly, you can add some using statements to your code to make the appropriate namespaces available. You'll want to add not only the System.IO.Packaging namespace, but also the System.Xml namespace. Although the Packaging namespace makes development easier, it does not completely eliminate the need to deal with XML.

If you are going to read a file, the first thing you need to do is open it with the Package class. The Open method of the Package class allows you to open files for reading or writing. Listing 9-4 shows some simple code to open a file passed in as an argument to a console application.

Example 9.4. Opening an Office 2007 File

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.IO.Packaging;

namespace PackageItems
{
    class Program
    {
        private const string wordSpace =
          @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";

        static void Main(string[] args)
        {
            try
            {
                using (Package package = Package.Open
                      (args[0], FileMode.Open, FileAccess.ReadWrite))
{
                    //Work is done here on the file
                }
            }
            catch (Exception x)
            {
                Console.WriteLine(x.Message);
            }
        }
    }
}

Once the document is open, the next thing you want to do is locate the part items that you want to manipulate. In this example, I will simply print out all of the lines of text in the open document. In order to print out the text, I need to load the document.xml part into a stream and then use XPath to return all of the elements named <w:t> in the file, which is the element Word 2007 uses to mark text. Listing 9-5 shows the code that would be placed inside of Listing 9-4 as designated by the comment in that listing.

Example 9.5. Printing Out Text Elements from a Word File

//Get the document part and load it into XML document
Uri uriDocument = new Uri("/word/document.xml", UriKind.Relative);
PackagePart documentPart = package.GetPart(uriDocument);

Stream partStream = package.GetPart(uriDocument).GetStream(
    FileMode.Open, FileAccess.ReadWrite);

NameTable nameTable = new NameTable();
XmlNamespaceManager manager = new XmlNamespaceManager(nameTable);
manager.AddNamespace("w", wordSpace);

XmlDocument document = new XmlDocument(nameTable);
document.Load(partStream);

XmlNodeList textNodes = document.SelectNodes("//w:t", manager);
foreach (XmlNode textNode in textNodes)
    {
        Console.WriteLine(textNode.InnerText);
    }

In Listing 9-5 notice that you can locate a part in the package by using the relative URI. You can obtain the URI by examining the relation parts in the package. Once you have a PackagePart object, you can open the XML file into a Stream object. Along with the Stream object, you'll want to create an XmlNamespaceManager object so that you can load the stream into an XmlDocument object and use XPath to access the elements. At that point, you simply process the XmlNode objects.

When you want to process all the nodes of a certain type, you can simply return them all through XPath. If you only want to process a single node, however, then you need some way to identify it in the file. Marking elements in the file can be accomplished by inserting a bookmark near the text of interest, using a field as a placeholder, or by superimposing your own XML schema over the Word document as you could do in Office 2003.

If you want to create a file from scratch, you have to create the part items, the relationships, and the package itself. This process is simple in concept but challenging and tedious in practice. This is because you must first create the part items in accordance with the proper schema for Word, Excel, or PowerPoint. Then you must create relationships for these parts. Finally, you create the package and place the parts and relationships inside.

Listing 9-6 shows a complete example of a console application that creates a Word document with a file name specified by the first argument and containing text specified in the second argument. There is also a complete exercise at the end of this chapter that uses the Open XML file formats to create a SharePoint feature that removes tracked changes and comments from a document.

Tip

To get help with schema documentation, visit the XML in Office Developer Portal at http://msdn2.microsoft.com/en-us/office/aa905545.aspx. Here you will find documentation, blogs, and video presentations about using the Open XML file formats.

Example 9.6. Creating a Word Document Programmatically

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.IO.Packaging;

namespace MakePackage
{
  class Program
  {
    private const string wordSpace =
    @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
    private const string partType = @"application/vnd.openxmlformats-
Creating a Word Document Programmatically
officedocument.wordprocessingml.document.main+xml"; private const string partUri = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships
Creating a Word Document Programmatically
/officeDocument"; private const string partId = "rId1"; static void Main(string[] args) {
try
      {
        using (Package package = Package.Open(
          args[0], FileMode.CreateNew, FileAccess.ReadWrite))
        {

          //Build the document.xml file with text in it
          XmlDocument documentXml = new XmlDocument();

          XmlElement documentElement = documentXml.CreateElement(
            "w:document", wordSpace);
          documentXml.AppendChild(documentElement);

          XmlElement bodyElement = documentXml.CreateElement(
            "w:body", wordSpace);
          documentElement.AppendChild(bodyElement);

          XmlElement pElement = documentXml.CreateElement("w:p", wordSpace);
          bodyElement.AppendChild(pElement);

          XmlElement rElement = documentXml.CreateElement("w:r", wordSpace);
          pElement.AppendChild(rElement);

          XmlElement tElement = documentXml.CreateElement("w:t", wordSpace);
          rElement.AppendChild(tElement);

          XmlNode tNode = documentXml.CreateNode(
            XmlNodeType.Text, "w:t", wordSpace);
          tNode.Value = args[1];
          tElement.AppendChild(tNode);

          //Create the part item for document.xml
          Uri Uri = new Uri("/word/document.xml", UriKind.Relative);
          PackagePart partDocumentXML = package.CreatePart(Uri,partType);
          StreamWriter stream = new
          StreamWriter(partDocumentXML.GetStream(
            FileMode.Create, FileAccess.Write));
          documentXml.Save(stream);
          stream.Close();
          package.Flush();

          //Create relationship for document.xml
          package.CreateRelationship(Uri, TargetMode.Internal, partUri, partId);

          package.Flush();
package.Close();
        }
      }
      catch (Exception x)
      {
        Console.WriteLine(x.Message);
      }
    }
  }
}

Developing with Visual Studio Tools for Office

Although Office 2007 and SharePoint have many powerful integration points that require little or no effort on your part, if you want complete control over the appearance and functionality of Office 2007 products you should investigate the Visual Studio 2005 Tools for the 2007 Office System. This release of the Visual Studio Tools for Office is sometimes referred to as Second Edition to differentiate it from the first edition that primarily targeted Office 2003. Therefore, you'll often see the acronym VSTO 2005 SE associated with these tools.

VSTO 2005 SE is important because it brings the managed code development model to Office 2007 and lets you create add-ins, custom tabs, and custom task panes using Visual Studio as the development environment. Furthermore, you can deploy these customized documents as templates for content types in SharePoint. This experience stands in contrast to the Visual Basic for Applications (VBA) programming model, which is still available within Office products but does not support the .NET Framework. In this section, I show you how to get up and running with VSTO 2005 SE and give you some ideas of ways to use it with SharePoint.

Creating a Development Environment

In order to create VSTO 2005 SE solutions, you must Install Microsoft Office 2007 on the machine where you will be developing. Additionally, you must be sure to install both Visual Basic for Applications (VBA) support and the Microsoft Office Primary Interop Assemblies (PIA). Installing VBA is required to support the development environment, while PIA are the COM assemblies required to integrate managed code with Office. Because your development environment was initially set up with a separate client, you'll need to install Microsoft Office on VSMOSS (or VSWSS) as part of the setup.

Follow these steps to install Microsoft Office 2007 in support of VSTO 2005 SE:

  1. Log in to VSMOSS (or VSWSS) as a local administrator.

  2. Start the installation for Microsoft Office 2007.

  3. When prompted, enter your product key and accept the license agreement as normal.

  4. On the Choose the Installation You Want screen, click the Customize button.

  5. In the Installation Options, select to only install Microsoft Excel, InfoPath, Outlook, PowerPoint, and Word.

  6. For each installed application, expand the options tree and ensure that the .NET Programmability Support option is enabled for installation. Figure 9-6 shows the Installation Options screen with the .NET Programmability option selected for Word.

  7. Expand the Office Shared Features tree and ensure that Visual Basic for Applications is selected to install.

  8. Click the Install Now button.

Installing Office 2007 to support VSTO 2005 SE

Figure 9.6. Installing Office 2007 to support VSTO 2005 SE

Once you have Microsoft Office 2007 installed, you can install VSTO 2005 SE. VSTO 2005 SE is available as a download from the Microsoft site. The simplest way to access the download is to visit the Visual Studio Tools for Office Developer Portal located at http://msdn2.microsoft.com/en-us/office/aa905543.aspx. Once you have the software downloaded, run the installation. The installation process is straightforward and requires no special configuration. Once you have completed the installation, you are ready to create projects.

All VSTO 2005 SE projects, whether they are add-ins, custom tabs, or custom task panes, are started in the same way. Inside of Visual Studio 2005, you select File

Installing Office 2007 to support VSTO 2005 SE
Starting a VSTO 2005 SE project

Figure 9.7. Starting a VSTO 2005 SE project

When you create a new project in VSTO 2005 SE, you get a new project template that has many of the components you need already stubbed out. The project itself comes with a class module that has several key namespaces referenced and some placeholders for code that should execute when the add-in starts up or shuts down. Additionally, the Add New Item dialog is populated with templates to support add-in development.

Along with the components and stubbed-out code, the new solution also contains a setup project. This setup project is suitable for deploying add-ins directly to client machines. Creating an add-in and making it available to clients using the project templates can be a fairly simple process.

Creating Office 2007 Add-Ins

Office 2007 supports the concept of an add-in that lets you add custom functionality to Office applications through the use of buttons that appear on the ribbon. Typically, add-ins are initiated by interacting with buttons on the ribbon that in turn exercise the application object model to achieve some functionality. For example, you could place a button on the Insert tab that adds a standard legal disclaimer to a document when it is pushed. The actual functionality of an add-in is limited only by what you can do with the .NET Framework and the object model of the targeted Office application.

Once you have started a new project in Visual Studio that targets a particular application, you can add buttons to the ribbon by using the Ribbon Support component. The Ribbon Support component is available in the Add New Item dialog. When you add this component, VSTO 2005 SE adds a new class to your project along with an XML file that holds button definitions.

Follow these steps to start a new add-in project:

  1. Select Start

    Creating Office 2007 Add-Ins
  2. In Visual Studio, select File

    Creating Office 2007 Add-Ins
  3. In the New Project dialog, select Visual C#

    Creating Office 2007 Add-Ins
  4. Select Word Add-In from the Visual Studio templates.

  5. Enter HelloAddIn in the Name field and click the OK button.

  6. In the Solution Explorer, right-click the HelloAddIn project and select Add

    Creating Office 2007 Add-Ins
  7. In the New Item dialog, select the Ribbon Support component.

  8. Name the new component MyAddInsTab.cs and click the Add button.

Loading the Ribbon Support Component

When the Ribbon Support component is added, it comes with some code to automatically add the new elements to the target application's ribbon, but this code is commented out. In order to load your new elements, you simply have to uncomment this code, which overrides the RequestService method of the add-in. This is the method that is called when the Office application loads your Ribbon Support component. The code in Listing 9-7 shows the uncommented code from the MyAddInsTab.cs file.

Example 9.7. The RequestService Method

public partial class ThisAddIn
{
    private MyAddInsTab ribbon;

    protected override object RequestService(Guid serviceGuid)
    {
        if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
        {
            if (ribbon == null)
                ribbon = new MyAddInsTab();
            return ribbon;
        }

        return base.RequestService(serviceGuid);
    }
}

Adding Buttons to a Tab

Along with the code file, the Ribbon Support component also provides an XML file that defines what buttons appear in the ribbon. By default, this file comes with a toggle button defined. This type of button has two states: up and down. You could use this type of button to enable and disable parts of your add-in. However, you can also use many other controls such as buttons, check boxes, and lists.

As with all XML editing, it can be difficult to correctly define the elements. Therefore, you'll want to set a schema reference to the CustomUI.xsd schema, which contains the definitions for the control types. This schema can be found at C:Program FilesMicrosoft Visual Studio 8XmlSchemas1033. In my example, I simply want to add a new button to the existing Insert tab. Therefore, I changed the MyAddInsTab.xml file to appear as shown in Listing 9-8.

Example 9.8. MyAddInsTab.xml Defining a Single Button

<customUI xmlns=http://schemas.microsoft.com/office/2006/01/customui
  onLoad="OnLoad">
  <ribbon>
    <tabs>
      <tab idMso="TabInsert">
        <group id="HelloGroup" label="My Add-In">
          <button id="helloButton" label="Insert Hello,World!"
                  screentip="Say Hello" onAction="helloButton_Click"
                  supertip="Inserts Hello, World into the document."/>
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

The customUI element contains the entire definition for the groups and controls that will be added to the ribbon. The onLoad attribute of this element references a callback method in the associated code file that runs when the controls are loaded. The ribbon element contains a tabs element with multiple tab elements for customizing any tab within the application. Each tab element contains an idMso attribute for designating the target tab. This attribute is always the word Tab plus the name of the tab as it appears in the application. Additionally, you can specify a tab element with a custom id attribute and custom label attribute that will generate a new tab on the ribbon. Listing 9-9 shows how you would modify Listing 9-8 to show the button on a new tab named My Tab.

Example 9.9. Creating a New Tab

<customUI xmlns=http://schemas.microsoft.com/office/2006/01/customui
  onLoad="OnLoad">
  <ribbon>
    <tabs>
      <tab id="MyTab" label="My Tab">
        <group id="HelloGroup" label="My Add-In">
          <button id="helloButton" label="Insert Hello,World!"
                  screentip="Say Hello" onAction="helloButton_Click"
                  supertip="Inserts Hello, World into the document."/>
</group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

The group element is used to create a new group within the targeted tab. Within the group, you can specify box, button, buttonGroup, checkbox, comboBox, control, dialogBoxLauncher, dropdown, dynamicMenu, editBox, label, labelControl, menu, separator, splitButton, or toggleButton, which all represent different UI elements. These elements support action attributes that let you specify a callback function to receive events for the element.

In my example, I defined a single button with a callback method named helloButton_Click. Therefore, I will need to define the callback function inside the code file of the Ribbon Support component. In the code file, you will find a region named Ribbon Callbacks. This is the region where the callback functions should be defined. By default, the region already contains a callback for OnLoad and a callback for the default toggle button that was defined in the template. You can simply delete the toggle button callback and add the code from Listing 9-10 to handle the button callback.

Example 9.10. The Button Callback Function

public void helloButton_Click(Office.IRibbonControl control)
{
  Microsoft.Office.Interop.Word.Range currentRange =
  Globals.ThisAddIn.Application.Selection.Range;
  currentRange.Text = "Hello, World!";
}

Notice that the basic approach for the add-in is to access the object model for the target application from the callback function. The root of the object model is obtained through the Globals.ThisAddIn.Application object. From here, you can go on to manipulate the application as necessary. You're not limited to simply using the object model because now you have the full capability of the .NET Framework to integrate with databases, SharePoint sites, or anything else.

Once you have coded the callback, you should be able to run the add-in directly in Visual Studio. VSTO 2005 SE will start the target application and your add-in will be loaded. When you push the button, text should be added to the document. Figure 9-8 shows the final example.

The Hello, World! add-in

Figure 9.8. The Hello, World! add-in

Creating Office 2007 Task Panes

In addition to customizing the ribbon, you can also add custom task panes to Office 2007. Custom task panes allow you to create a completely custom user interface that can be displayed to the user. Custom task panes are an excellent way to integrate other systems with Office applications. To create a custom task pane, you begin with an add-in project just as you did before.

Custom task panes are designed and built through UserControls. Therefore, once you have a new project started, you must add a UserControl component to the project. On the UserControl, you can add any user interface elements you want from the toolbox. As an example, I created a simple UserControl with a ListBox and a Button. Using these controls, I will load a list of product names and numbers from a database and then use the button to insert them into a Word document. Figure 9-9 shows my UserControl in Visual Studio.

A UserControl for a custom task pane

Figure 9.9. A UserControl for a custom task pane

Inside of the UserControl, you can add any code you want. In my example, I simply fill the list with product names and numbers from the AdventureWorks database when the UserControl is loaded. When the Insert button is clicked, I insert the selected product into the current Word document. Listing 9-11 shows the complete code for the UserControl.

Example 9.11. Code for the Custom UserControl

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using Word = Microsoft.Office.Interop.Word;

namespace Names
{
  public partial class NamePane : UserControl
  {
    public NamePane()
    {
      InitializeComponent();
    }

    private void NamePane_Load(object sender, EventArgs e)
    {
      try
      {
        string connString = "Data Source=win2k3template;
Code for the Custom UserControl
Initial Catalog=Adventureworks;Integrated Security=SSPI;"; string sqlString = "Select Name + ', ' +
Code for the Custom UserControl
ProductNumber as FullProduct FROM Production.Product ORDER BY Name"; using (SqlConnection connection = new SqlConnection(connString)) { connection.Open(); SqlCommand command = new SqlCommand(); command.CommandText = sqlString; command.CommandType = CommandType.Text; command.Connection = connection; SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
          {
             while (reader.Read())
             {
                namesList.Items.Add(reader.GetString(0));
              }
          }

          connection.Close();
        }
      }
      catch (Exception x)
      {
        MessageBox.Show(x.Message);
      }
    }

    private void insertButton_Click(object sender, EventArgs e)
    {
      Word.Range currentRange = Globals.ThisAddIn.Application.Selection.Range;
      currentRange.Text = namesList.SelectedItem.ToString();
    }

  }
}

Once the UserControl is designed and coded, all you need to do is create a task pane from the UserControl at run time and display it. This is done in the startup event of the add-in. In this event, you must create a CustomTaskPane object and add your UserControl. Once this is done, you can run the add-in from Visual Studio. Listing 9-12 shows the code for loading the task pane, and Figure 9-10 shows a picture of the solution in action.

Example 9.12. Loading the New Task Pane

using System;
using System.Windows.Forms;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;

namespace Names
{
  public partial class ThisAddIn
  {
    private NamePane namePane;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
      namePane = new NamePane();
      Microsoft.Office.Tools.CustomTaskPane newTaskPane =
        this.CustomTaskPanes.Add(namePane, "Names");
      newTaskPane.Visible = true;
    }

    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
    }

  }
}
The completed custom task pane

Figure 9.10. The completed custom task pane

Deploying VSTO 2005 SE Solutions

As I noted earlier, every VSTO 2005 SE solution template includes a setup project. This project can be used to deploy the solution directly to a client desktop. Additionally, you could deploy the solution from SharePoint library. In either case, there are several prerequisites that must be met on the client machine before the solution will run.

Follow these steps to prepare a client machine for VSTO solutions:

  1. Log in to VSCLIENT as an administrator.

  2. Download and install the .NET Framework 2.0 from http://www.microsoft.com/downloads/details.aspx?FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5&displaylang=en.

  3. Ensure that you have installed the Primary Interop Assemblies and Visual Basic for Applications Support from the Office 2007 setup. If you did a complete install, these components should already be present.

  4. Download and install the VSTO 2005 SE runtime from http://go.microsoft.com/fwlink/?linkid=49612.

Once you have the prerequisites on the client, you are ready to deploy the VSTO 2005 SE solution. If you are using the setup program created by the project, you can simply run the setup. If, however, you are deploying from SharePoint, the document and the assembly are going to be separated. The document will go into a document library or become the template for a content type while the associated assembly must be stored on a network location accessible through a UNC name. For example, you could create and share a directory on VSMOSS named Assemblies. In either case, the assemblies associated with the solution must be strongly named and you must explicitly trust them using the .NET Framework 2.0 Configuration utility.

Follow these steps to trust the solution assemblies:

  1. On VSCLIENT, select Start

    Deploying VSTO 2005 SE Solutions
  2. In the .NET Framework 2.0 Configuration dialog, expand the tree down the path Console Root

    Deploying VSTO 2005 SE Solutions
  3. Right-click the All_Code group and select New from the context menu.

  4. Enter VSTO Assemblies in the Name field and click the Next button.

  5. On the Choose a Condition Type screen, select URL from the drop-down list.

  6. Enter the complete path to the location where you will deploy the assemblies (e.g., (\VSMOSSAssemblies).

  7. Click the Next button.

  8. On the Assign a Permission Set to the Code Group screen, select Full Trust from the drop-down list labeled Use Existing Permission Set.

  9. Click the Next button.

  10. Click the Finish button to complete the wizard.

  11. In the .NET Framework 2.0 Configuration dialog, right-click the new VSTO Assemblies code group and select Properties from the context menu.

  12. In the Properties dialog, check the box labeled Policy Levels Below This Level Will Not Be Evaluated. This ensures that the policy cannot be modified by any other policy.

  13. Click the OK button.

Once you have trusted the assemblies, any project you install directly on the client computer using the setup project should run without trouble. However, if you intend to deploy the document into SharePoint, you must additionally trust the server location where the document will be stored. Trusting the documents is accomplished by creating another policy that is defined in the file MSOSEC.XML and contained in the assembly MSOSEC.DLL.

Follow these steps to trust a document location:

  1. On VSCLIENT, open the File Explorer and navigate to C:Program FilesMicrosoft OfficeOFFICE12ADDINS.

  2. Drag the assembly MSOSEC.DLL from this directory and drop it in C:Windowsassembly to install it in the Global Assembly Cache.

  3. Select Start

    Deploying VSTO 2005 SE Solutions
  4. In the .NET Framework 2.0 Configuration dialog, expand the tree down the path Console Root

    Deploying VSTO 2005 SE Solutions
  5. Right-click the All_Code group and select New from the context menu.

  6. Enter VSTO Documents in the Name field and click the Next button.

  7. On the Choose a Condition Type screen, select (custom) from the drop-down list.

  8. Click the Import button.

  9. In the Import Custom Membership from XML dialog, navigate to the C:Program FilesMicrosoft OfficeOFFICE12ADDINS directory.

  10. Select the file MSOSEC.XML and click the Open button.

  11. Click the Next button.

  12. On the Assign a Permission Set to the Code Group screen, select Full Trust from the drop-down list labeled Use Existing Permission Set.

  13. Click the Next button.

  14. Click the Finish button to complete the wizard.

  15. In the .NET Framework 2.0 Configuration dialog, right-click the new VSTO Documents code group and select Properties from the context menu.

  16. In the Properties dialog, check the box labeled Policy Levels Below This Level Will Not Be Evaluated. This ensures that the policy cannot be modified by any other policy.

  17. Click the OK button.

Once the assembly location is trusted and the documents are trusted, the last thing you have to do is modify the document so that it knows where the assembly is located. The document template created with a VSTO 2005 SE solution contains a deployment manifest that tells it where to find its associated assembly. Normally, the document simply looks in the same directory, but in the case of a SharePoint deployment, that is not possible. Fortunately, we can write a simple command-line application that modifies the deployment manifest. Listing 9-13 shows a complete command-line application that takes the document file name as the first argument and the assembly location as the second and updates the deployment manifest. Once that is done, you should be able to run the solution from a SharePoint library.

Example 9.13. Editing the Deployment Manifest

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Tools.Applications.Runtime;

namespace DeploymentManifestEditor
{
    class Program
    {
        static void Main(string[] args)
        {
            ServerDocument document = null;

                document = new ServerDocument(args[0]);
                document.AppManifest.DeployManifestPath = args[1];
                document.Save();
                document.Close();

        }
    }
}

Exercise 9.1. Using the Office Open File Formats

The Office Open XML file formats allow you to create and edit Word, Excel, and PowerPoint documents programmatically. This is an ideal approach for working with documents in SharePoint solutions because you can process documents on the server while using SharePoint libraries as a storage mechanism. In this exercise, you will create a feature for SharePoint that uses the Open XML file formats to purge Word documents of review comments and tracked changes. This kind of functionality is perfect for preparing a document for delivery to a customer.

Warning

This exercise is for learning purposes only. The code has not been tested in a wide variety of situations and is not intended to be production-ready. Incorrectly manipulating Office documents can render them unreadable.

Starting the Project

This exercise will combine what you have learned about SharePoint features and the Office Open XML file formats. The feature will consist of an assembly designed to purge Word documents that is triggered through a new item on the document drop-down menu in SharePoint. To begin the exercise, you'll need to create a new project in Visual Studio.

Follow these steps to start the new project:

  1. Log in to VSMOSS as a SharePoint administrator.

  2. Select Start

    Starting the Project
  3. When Visual Studio starts, select File

    Starting the Project
  4. In the New Project dialog, select Visual C# from the Project Types list.

  5. Select Class Library from the Visual Studio Templates list.

  6. Name the new project WordCleaner and click the OK button.

  7. Right-click Class1.cs in the Solution Explorer and select Rename from the context menu.

  8. Rename the file Worker.cs and hit the Enter key.

  9. Select Project

    Starting the Project
  10. In the Add Reference dialog, click the Browse tab.

  11. In the Browse tab, navigate to C:Program FilesReference AssembliesMicrosoftFrameworkv3.0.

  12. Select the WindowsBase.dll assembly and click the OK button.

  13. In the Worker.cs code window, add references to System.Xml, System.IO, and System.IO.Packaging. Listing 9-14 shows how your code should appear at this point.

Example 9.14. Starting the Project

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.IO.Packaging;

namespace WordCleaner
{
    public class Worker
    {
    }
}

Coding WordCleaner.Worker

After starting the project, the first thing to do is to create the assembly that will purge the Word documents. This is the part of the project that uses the Open XML file formats. This assembly will open the document to be purged, accept all of the changes made, and delete any comments. This will all be accomplished by manipulating the document part items and XML.

You'll start by creating a Sanitize and LogMessage method. The Sanitize method contains the main functionality, and you will code this over the next few sections. The LogMessage method is used to record errors in the event log. The code in Listing 9-15 shows the Sanitize method and the LogMessage method. Add the bolded code to your project as shown.

Example 9.15. The Sanitize and LogMessage Methods

namespace WordCleaner
{
  public class Worker
  {
    //Namespace and URI constants
    private const string wordSpace =
      @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
    private const string docUri = @"/word/document.xml";

    public void Sanitize(string packagePath)
    {
      //Code here
    }

    static void LogMessage(string message, EventLogEntryType entry)
    {
      if (!EventLog.SourceExists("Word Cleaner"))
        EventLog.CreateEventSource("Word Cleaner", "Application");
      EventLog.WriteEntry("Word Cleaner", message, entry);
    }
  }
}

Opening the Package

The Sanitize method begins by opening the Word document file represented by the packagePath argument passed in to the method. Once the package is opened, the document part is loaded into a stream for editing. The document part represents the main body of the Word document and is stored in the package in the file document.xml. In order to purge the document of comments and changes, you must load the document.xml file into a stream and manipulate the XML. Add the code from Listing 9-16 to the Sanitize method to open the package and load the document part into a stream.

Example 9.16. Loading the Document Part into a Stream

try
{
  //Open the package
  using (Package package = Package.Open(
                           packagePath, FileMode.Open, FileAccess.ReadWrite))
  {

    //Get the document part
    Uri uriDocument = new Uri(docUri, UriKind.Relative);
    PackagePart documentPart = package.GetPart(uriDocument);

    //Load the document part into a stream
    Stream partStream = documentPart.GetStream(
                        FileMode.Open, FileAccess.ReadWrite);

    //Add the namespace manager to reference the Word namespace
    NameTable nameTable = new NameTable();
    XmlNamespaceManager manager = new XmlNamespaceManager(nameTable);
    manager.AddNamespace("w", wordSpace);

    //Create a temporary XML document from the stream
    //so we can manipulate the XML elements
    XmlDocument tempDoc = new XmlDocument(nameTable);
    tempDoc.Load(partStream);

//More code will go here

  }
}
catch (Exception x)
{
    LogMessage(x.Message, EventLogEntryType.Error);
}

Removing Changes and Comments

Once the document part is loaded into a stream, you may use standard XML methods to manipulate the contents. In this exercise, you will remove all changed document text that is marked as deleted and all comments made during review. Additionally, you must promote inserted text changes so that they appear as accepted changes in the document. The whole process involves returning key nodes from the document part and deleting or modifying them.

Document text marked for deletion during a review is tracked in the document part with the element <w:del>. Inserted text is tracked with the element <w:ins>. Comments are tracked with three different elements: <w:commentRangeStart>, <w:commentRangeEnd>, and <w:commentReference>. Add the code from Listing 9-17 to the Sanitize method to manipulate the document elements.

Example 9.17. Modifying the Document Part

//Remove deleted text from temporary XML document
XmlNodeList delNodes = tempDoc.SelectNodes("//w:del", manager);
foreach (XmlNode delNode in delNodes)
{
  delNode.ParentNode.RemoveChild(delNode);
}

//Promote the inserted text in temporary XMl document
//so it appears normally in the Word document
XmlNodeList insNodes = tempDoc.SelectNodes("//w:ins", manager);
foreach (XmlNode insNode in insNodes)
{
  foreach (XmlNode childNode in insNode.ChildNodes)
  {
    insNode.ParentNode.InsertBefore(childNode, insNode);
  }

  insNode.ParentNode.RemoveChild(insNode);
}

//Remove comments text from temporary XML document
//Must remove several different elements to accomplish this
XmlNodeList commentStartNodes = tempDoc.SelectNodes(
                                "//w:commentRangeStart", manager);
foreach (XmlNode commentStartNode in commentStartNodes)
{
  commentStartNode.ParentNode.RemoveChild(commentStartNode);
}

XmlNodeList commentEndNodes = tempDoc.SelectNodes(
                              "//w:commentRangeEnd", manager);
foreach (XmlNode commentEndNode in commentEndNodes)
{
  commentEndNode.ParentNode.RemoveChild(commentEndNode);
}

XmlNodeList commentRefNodes = tempDoc.SelectNodes(
                              "//w:commentReference", manager);
foreach (XmlNode commentRefNode in commentRefNodes)
{
  commentRefNode.ParentNode.RemoveChild(commentRefNode);
}

//Save the temporary XMl document changes back to the document part
documentPart.GetStream().SetLength(0);
tempDoc.Save(documentPart.GetStream());
//More code will follow

Deleting the Comments Part

To finish processing the file, you must remove the comment text from the package. The comment text is saved in the comments.xml file in the package. You must remove the comments.xml file from the package and delete the relationship between the document part and the comments part. Add the code from Listing 9-18 to remove the comment text from the package.

Example 9.18. Removing Comments and Relationships

//delete the relationship with the comments part
Uri uriComments = new Uri("/word/comments.xml", UriKind.Relative);
PackagePart commentsPart = package.GetPart(uriComments);

PackageRelationshipCollection relationships = documentPart.GetRelationships();

foreach (PackageRelationship relationship in relationships)
{
  if (relationship.TargetUri.ToString() == "comments.xml")
  {
    documentPart.DeleteRelationship(relationship.Id);
    break;
  }
}

//Delete comments part from package
package.DeletePart(uriComments);

//Save the package changes
package.Flush();
package.Close();

Compiling the Assembly

Once the code is completed for the Worker class, it can be compiled. In this exercise, you will deploy the assembly to the Global Assembly Cache (GAC), so it must be digitally signed. Once signed, it can be built.

Follow these steps to build the assembly:

  1. In the Solution Explorer, right-click the WordCleaner project and select Properties from the context menu.

  2. In the Properties dialog, click the Signing tab.

  3. On the Signing tab, check the box labeled Sign the Assembly.

  4. Select <New...> from the drop-down list labeled Choose a Strong Name Key File.

  5. In the Create Strong Name Key dialog, uncheck the box labeled Protect My Key File with a Password.

  6. Enter WordCleanerKey in the Key File Name field.

  7. Click the OK button.

  8. Make sure that the configuration drop-down is set to release and select Build

    Removing Comments and Relationships

Creating the Worker.aspx Page

Although the basic purge functionality is contained in the assembly, we still need to create a mechanism for invoking the assembly. In this exercise, you'll invoke the assembly through an ASPX page that will be called from a new menu item in a document library. We could also have chosen to invoke the assembly as part of a workflow or in response to a list event. The point is that there are many options in SharePoint for implementing such functionality.

Follow these steps to create the ASPX page:

  1. In the Solution Explorer, right-click the WordCleaner project and select Add

    Creating the Worker.aspx Page
  2. In the Add New Item dialog, select Text File.

  3. Name the Text File Worker.aspx and click the Add button. You are adding the ASPX page in this manner because we are not creating a web application and will simply deploy the file to the TEMPLATES directory later.

  4. Add the code from Listing 9-19 to create the page. Notice that the page references both the Microsoft.SharePoint and the WordCleaner assemblies.

Example 9.19. The Worker.aspx Page

<%@ Page Language="C#" Debug="true" %>
<%@ Assembly Name="WordCleaner,
The Worker.aspx Page
Version=1.0.0.0,
The Worker.aspx Page
Culture=neutral,
The Worker.aspx Page
PublicKeyToken=0e47d66474f01e8d" %> <%@ Assembly Name="Microsoft.SharePoint,
The Worker.aspx Page
Version=12.0.0.0,
The Worker.aspx Page
Culture=neutral,
The Worker.aspx Page
PublicKeyToken=71e9bce111e9429c"%> <%@ Import Namespace="WordCleaner" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Import Namespace="Microsoft.SharePoint.WebControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>Word Cleaner Worker Page</title>
</head>
<body>
  <form id="form1" runat="server">
    <div>
     <%

      try
      {
        //Code will go here
      }
      catch (Exception x)
      {
        Response.Write(x.Message + "
");
      }

     %>
    </div>
  </form>
</body>
</html>

Coding the Worker.aspx Page

In order for the assembly to access a Word document, the document must be downloaded from SharePoint and manipulated locally. Once the changes are made, the document needs to be uploaded back to the document library. The Worker.aspx page performs the download of the file onto the server, invokes the cleaning assembly, and then uploads the file. After the page completes, it redirects back to the document library page. In this way, the user experiences a postback and then has a purged document in the library. Add the code from Listing 9-20 to the Worker.aspx page to download, purge, and upload the document.

Example 9.20. Downloading, Purging, and Uploading the Document

//Get top-level site
SPSite site = SPControl.GetContextSite(Context);

//Build the destination path
string source = "http://" + site.HostName + Request.QueryString["Item"];
string cache =
   System.Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
string downPath = cache + "\" + source.Substring(source.LastIndexOf("/") + 1);
string extension = source.Substring(source.LastIndexOf(".") + 1);
//Make sure it is a DOCX file
if(extension.ToUpper()!="DOCX")
  throw new Exception("Only DOCX files can be cleaned.");

//Download file
System.Net.WebClient client = new System.Net.WebClient();
client.Credentials = System.Net.CredentialCache.DefaultCredentials;
client.DownloadFile(source, downPath);

//Sanitize Document
WordCleaner.Worker worker = new WordCleaner.Worker();
worker.Sanitize(downPath);

//Upload File
FileStream stream = new FileStream(downPath, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(stream);
byte[] bytes = reader.ReadBytes((int)stream.Length);
reader.Close();
stream.Close();
client.UploadData(source, "PUT", bytes);


//Redirect back to library
Response.Redirect(source.Substring(0,source.LastIndexOf("/"))
                  + "/Forms/AllItems.aspx");

Creating the Feature.xml File

As I stated earlier, the Worker.aspx page will be invoked from a new item on the document's drop-down menu. In order to create this new item, you'll have to create a Feature.xml file to represent the new feature. The Feature.xml file is straightforward and created in a manner that should be familiar to you by now.

Follow these steps to create a Feature.xml file:

  1. In the Solution Explorer, right-click the WordCleaner project and select Add

    Creating the Feature.xml File
  2. In the Add New Item dialog, select XML File.

  3. Name the XML file Feature.xml and click the Add button.

  4. Add the code from Listing 9-21 to create the Feature.xml file.

Example 9.21. The Feature.xml File

<?xml version="1.0" encoding="utf-8" ?>
<Feature Title="Word Document Cleaner"
    Description="Accepts changes and removes comments from Word 2007 files."
    Scope="Site"
Id="C67EBE69-0372-425f-A939-23F8A74418AF"
    xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="Elements.xml" />
  </ElementManifests>
</Feature>

Creating the Elements.xml File

The Elements.xml file is the manifest file for the new feature. This file is used to define the new menu item and link it to the Worker.aspx page. In this section, you will create the manifest file and code it to add a new item to the document's drop-down menu.

Follow these steps to create the Elements.xml file:

  1. In the Solution Explorer, right-click the WordCleaner project and select Add

    Creating the Elements.xml File
  2. In the Add New Item dialog, select XML File.

  3. Name the XML file Elements.xml and click the Add button.

  4. Add the code from Listing 9-22 to create the Elements.xml file.

Example 9.22. The Elements.xml File

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="UserInterfaceLightUp.ECBItemToolbar"
    RegistrationType="List"
    RegistrationId="101"
    Location="EditControlBlock"
    Sequence="106"
    Title="Cleanse Document"
    ImageUrl="/_layouts/images/AddToFavorites.gif">
    <UrlAction Url="/_layouts/Worker.aspx?Item={ItemUrl}" />
  </CustomAction>
</Elements>

Creating the Install.bat File

In order to install the new feature, you must create a folder in the TEMPLATES directory and copy the Feature.xml and Elements.xml files to this location. Additionally, you must copy the Worker.aspx file to the LAYOUTS directory. Finally, you must install the assembly in the GAC. You could certainly do all this by hand, but you'll create a batch file to automate the process instead.

Follow these steps to create the batch file:

  1. In the Solution Explorer, right-click the WordCleaner project and select Add

    Creating the Install.bat File
  2. In the Add New Item dialog, select Text File.

  3. Name the text file Install.bat and click the Add button.

  4. Add the code from Listing 9-23 to create the Install.bat file. When you are done, run the batch file to install the feature.

Example 9.23. The Install.bat File

@SET FEATUREDIR="c:program filescommon filesmicrosoft shared
The Install.bat File
web server extensions12TemplateFeatures" @SET LAYOUTDIR="c:program filescommon filesmicrosoft shared\
The Install.bat File
web server extensions12TemplateLayouts" @SET STSADM="c:program filescommon filesmicrosoft shared\
The Install.bat File
web server extensions12instsadm.exe" @SET GACUTIL="C:Program FilesMicrosoft Visual Studio 8\
The Install.bat File
SDKv2.0BinGacUtil.exe" md %FEATUREDIR%WordCleaner xcopy /e /y Feature.xml %FEATUREDIR%WordCleaner xcopy /e /y Elements.xml %FEATUREDIR%WordCleaner xcopy /e /y Worker.aspx %LAYOUTDIR% %GACUTIL% -if bin eleaseWordCleaner.dll %STSADM% -o installfeature -filename WordCleanerfeature.xml -force IISRESET ECHO Finished PAUSE

Activating and Using the Feature

Once the feature is installed, you may activate it. This feature is defined at the site collection level, so you will go to the Site Settings page for the site collection to activate it. Once activated, the new menu item should show up for all documents in the site collection.

Follow these steps to activate the feature:

  1. Open the home page of the intranet site you created in Chapter 2.

  2. Select Site Settings

    Activating and Using the Feature
  3. On the Site Settings page, click the link titled Site Collection Features under the Site Collection Administration section.

  4. On the Site Collection Features page, click the Activate button associated with the Word Document Cleaner feature.

Once the feature is activated, navigate to any document library containing Word documents. If you drop the menu associated with a document, you should see the new Cleanse Document item. Before you select it, however, open the document in Word, turn on Track Changes, and add some comments. Then save the document and try purging it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.237.3