Cascade Skyline - with Microsoft Logo and Project Support header - author Brian Smith

TechEd 2008 Preview – Part 4 – COM Add-in from Project Professional making PSI calls

TechEd 2008 Preview – Part 4 – COM Add-in from Project Professional making PSI calls

  • Comments 1

This is the last TechEd sample and is a very simple example of a PSI call from Project Pro (or Standard for that matter).  It shows how a user of the client not connected to the server can still make PSI calls.  Obviously they need an account in the PWA they are communicating with.  The sample shows a PSI call to check that the local project name (or any text you want to enter manually) is in use on the Project Server.  The response is shown on the form for the add-in and also put into the text1 field of the project – just to show how local data can also be updated with VSTO applications. 

The details for creating a VSTO add-in for project were very well covered in Jack Dahlgren's posting http://zo-d.com/blog/archives/programming/making-the-move-from-vba-to-vsto-in-microsoft-project.html posting recently – thanks Jack – so I will just give samples of my code and not repeat the “how to” section.  I also needed web references to the Project and LoginWindows web services.  My code is also in C# so some differences to Jack’s posting. 

The ThisAddIn.cs file looks like this and is adding a toolbar button and setting the for to show when the button is clicked:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using MSProject = Microsoft.Office.Interop.MSProject;
using Office = Microsoft.Office.Core;
using System.Windows.Forms;

namespace TechEdComAddIn
{
    public partial class ThisAddIn
    {
        private Office.CommandBar commandBar;
        private Office.CommandBarButton importButton;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            
            if (commandBar == null)
            {
                int barPosition = 1;
                bool isMenuBar = false;
                bool isTemporary = true;
                commandBar = Application.CommandBars.Add("ValidateBar", barPosition,
                                                         isMenuBar, isTemporary);
            }
            
            try
            {
                importButton = (Office.CommandBarButton)commandBar.Controls.Add(
                    Office.MsoControlType.msoControlButton, missing, missing, missing, missing);
                importButton.Style = Office.MsoButtonStyle.msoButtonCaption;
                importButton.Caption = "Validate Project Name";
                importButton.Tag = "Validate Project Name";
                importButton.TooltipText = "Validates a name for later use in Project Server.";
                importButton.Click +=
                    new Office._CommandBarButtonEvents_ClickEventHandler(ImportButtonClick);

                commandBar.Visible = true;
            }
            catch (ArgumentException ex)
            {
                MessageBox.Show(ex.Message, "Error adding toolbar button",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }

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

        private void ImportButtonClick(Office.CommandBarButton ctrl, ref bool cancel)
        {
            //ImportDialogBox importDialog = new ImportDialogBox();
            //importDialog.Show();
            
            ProjNameValidate myForm = new ProjNameValidate(); ;
            myForm.Show();
        }
        
       
        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion
    }
}
 
The form looks like this:-
 
image 
And the code behind:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace TechEdComAddIn
{
    public partial class ProjNameValidate : Form
    {
        private const string URLPREFIX = "http://";
        private const string LOGINWINDOWSWEBSERVICE = "_vti_bin/PSI/LoginWindows.asmx";
        private const string PROJECTWEBSERVICE = "_vti_bin/PSI/Project.asmx";

        private string baseUrl = "http://brismithwfe/cal/";


  
        private static WebSvcLoginWindows.LoginWindows loginWindows =
            new WebSvcLoginWindows.LoginWindows();
        private static WebSvcProject.Project project =
            new WebSvcProject.Project();

        public ProjNameValidate()
        {
            InitializeComponent();
            string projName = Globals.ThisAddIn.Application.ActiveProject.Name.ToString();
            int extLocation = projName.LastIndexOf(".mpp");
            textBoxProjectName.Text = projName.Substring(0, extLocation);
        }

        private void btnValidateName_Click(object sender, EventArgs e)
        {
            try
            {
                loginWindows.Url = baseUrl + LOGINWINDOWSWEBSERVICE;
                loginWindows.Credentials = CredentialCache.DefaultCredentials;
                project.Url = baseUrl + PROJECTWEBSERVICE;
                project.Credentials = CredentialCache.DefaultCredentials;

               
                WebSvcProject.ProjectDataSet dsProject =
                        new WebSvcProject.ProjectDataSet();
                dsProject = project.ReadProjectList();
                foreach (WebSvcProject.ProjectDataSet.ProjectRow rowProject in dsProject.Project)
                    if (rowProject.PROJ_NAME == textBoxProjectName.Text.ToString())
                    {
                        lblResponse.Text = "Project name already in use";
                        lblResponse.Visible = true;
                        break;
                    }
                    else
                    {
                        lblResponse.Text = "Project name is OK to use.";
                    }
                Globals.ThisAddIn.Application.ActiveProject.Text1 = lblResponse.Text;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }
}
I don’t think there is anything too complicated.  I trim the .mpp off the local filename and then see if it exists on the server.  Globals is the way to interact with the local application object.
Once you have that available most of the VBA developers out there should be on home territory.  Take a look at the VSTO stuff – it is very simple to deploy too – as Jack’s article outlines.
Technorati Tags: , ,
 
 
 
 
 
 
 
Leave a Comment
  • Please add 5 and 5 and type the answer here:
  • Post
  • Hi Brian,

    when I run thee AddIn i receive the 401 unathorize error.

    After some debugging I find out that the CredentialCache.DefaultCredentials contains my network access credential, but I don't access Project Server with my network access credential.

    To log on Project Server I check the "Enter User Credential" flag and input the Username and password of my Project Server User.

    There is a way, from the add-in, to find the username and password I use for log on Project Server?

    Thanks

    Valerio

Page 1 of 1 (1 items)