As the title suggests, this article will describe how you can utilize Microsoft Project to Design your overall Project Layout and Manage it with Axosoft's OnTime 2007. Provided with this article is complete source, written against the Office .NET Assemblies and the OnTime 2007 SDK.
As usual, let's see some eye candy first, then we'll go into details ...
Here's the actual startup form, the source provided allows for a
single command-line parameter to be passed, which is the path
to the MS Project (*.mpp) file to import

Here's a standard .NET 'OpenFileDialog', and we're selecting the example project
Here we are, selecting the OnTime 2007 Project
to import the MS Project items into
After selecting 'Convert', you'll see MS Project launch and open the Project (*.mpp) file you selected --
and look, is that a Gantt Chart?
Here, we disable all the form controls, and show
a progress bar (this bar cycles twice, and I'll
explain why in a minute)
Here's a nice "Complete!"
notification popup
And here's what the tool looks like after it's complete ...
Ok, now after seeing all that, your probably sitting there going ... "Huh?". Trust me, I wasn't too impressed with the screenshots either, and I wrote the thing ... BUT, you want to know why this is so cool?
You do? Good ... picture this, one thing I've come across in my various positions over the years is a Project Manager using Microsoft Project to design a general time-line and work schedule, almost every one of these Project Managers turns around and spends just about as much time as they did designing the MS Project layout as they do trying to convert it into something that their employee's can work with, in this case, a Project Management Tool such as Axosoft's OnTime. Why do Project Managers like to use Project, simple, it's got Gantt Charts and all sorts of other nifty scheduling functionalities that allows the Project Manager to design an efficient schedule. Why do the spend so much time converting Project layouts into tools like OnTime, again, quite simple, OnTime has the tools and functionality to get things done.
The Technical Details
Requirements:
- Visual Studio 2005
- Microsoft Project 2003
- Microsoft Office .NET Interop Assemblies
- OnTime Client
- OnTime SDK
Time Invested: 4 work hours (2 hours research, 2 hours code)
Now, onto the more technical details, and this time, I'll actually get into some source in the post, since in all honesty, this example is quite simple and contains very little source.
First, we create a new Windows Application in Visual Studio, and after the solution has been created your going to add a reference to a few things, and they are;
- COM -> Microsoft Office 11.0 Object Library
- COM -> Microsoft Project 11.0 Object Library
- Web -> OnTime SDK Task Service
- Web -> OnTime SDK Feature Service
- Web -> OnTime SDK Project Service
- Web -> OnTime SDK RelatedItems Server
Once you've added all the above references, add a form Windows Form to the project (or open the default form if one exists in the project) and drop two Labels, one TextBox control and one ComboBox control, two Button controls and a progress bar. Also, while your at it, toss an OpenFileDialog into the form as well. We'll name the first TextBox "txtMSProject" and the ComboBox will be called mbProjects. We'll put the first label to the left of the TextBox and put "MS Project:" as it's Text, and the second label next to the ComboBox and give it the value of "OnTime Project:".
Place the first Button to the right of the TextBox, and give it the value Text value of "..." and assign the following code to the Click event:
private void bBrowse_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
txtMSProject.Text = openFileDialog1.FileName;
}
Now, for the Forms Load event, we're going to grab a list of all the Projects available in OnTime and add them as objects to the ComboBox. To do this, I created a custom 'OnTimeProject' class which contains the ProjectId and ProjectName and an override for the ToString() method so that the ComboBox displays the Project's Name rather then the Class Name.
Here's the code for the OnTimeProject class;
public class OnTimeProject
{
public string Name;
public int ProjectId;
public override string ToString()
{
return Name;
}
}
Now, to get a list of all the projects from the OnTime SDK, we create a ProjectHandler object instance and then call the projectHandler.getAllProjects(Guid SecurityToken) method. This will return a DataSet, containing all the information you'll need to know about your OnTime Projects, we then do a 'foreach' loop through this DataSet (more specifically, the first tables DataRow collection, 'Rows') and create a new OnTimeProject instance and assign the Name and ProjectId and add it to the ComboBox's Items, here's the code for that;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
OnTimeProjects.ProjectHandler projectHandler =
new OnTimeProjects.ProjectHandler();
DataSet otProjects = projectHandler.GetAllProjects(securityToken);
foreach (DataRow dr in otProjects.Tables[0].Rows)
{
OnTimeProject p = new OnTimeProject();
p.Name = (string)dr["Name"];
p.ProjectId = (int)dr["ProjectId"];
cbProjects.Items.Add(p);
}
}
For clarification, the 'securityToken' parameter passed to GetAllProjects() is a Guid defined in the source that contains the same Guid value as the OnTime SDK's Web.config SecurityToken value -- this is used as a security measure, to prevent unwanted users from accessing data from your OnTime SDK without authorization.
Now, with what we have so far, you should be able to test-run your code and your ComboBox should be pre-populated with your projects from OnTime and your 'Browse' button should allow you to locate and reference a file, storing it's value in the txtMSProject TextBox.
Now for the fun part, let's do some Microsoft Project Automation!
To launch an instance of Microsoft Project, or reference the currently running instance, you need the following code;
ApplicationClass prjApp = new ApplicationClass();
This prjApp has a number of properties available, and were going to set the Visible property to true. This is not necessary, but is helpful for debugging, by default the Application is hidden, unless it's referencing an already running instance of Microsoft Project.
To open an MS Project File (*.mpp), you use the FileOpen() method in the ApplicationClass, for this example, were not really concerned about most of the parameters passed to this method, so we pass Type.Missing rather then null.
string fName = txtMSProject.Text;
prjApp.FileOpen(fName, true, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, PjPoolOpen.pjPoolReadOnly, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
You'll notice the PjPoolOpen.pjPoolReadOnly value passed, this prevents our code from altering the MS Project file in any way, as the file is opened in Read-Only mode (again, not absolutely necessary, but a nice safe guard). Once you've opened your Project file, it becomes the ActiveProject and can be referenced by the prjApp.ActiveProject, which is a Project object instance.
Now that we have a Project reference, we can begin going through all of it's tasks, which are in the Tasks collection, a property of the Project class.
foreach(Task task in project.Tasks) { }
So far, we've got the skeleton structure of our converter, now let's create some OnTime Tasks and introduce them into our OnTime database, ok?
Let's create an instance of the TaskHandler class, this will allow us to call the AddTask() method.
OnTimeTasks.TaskHandler taskHandler = new OnTimeTasks.TaskHandler();
Now, to create an OnTime Task, we have to create an OnTimeTasks.Task object, set our values, and then call the taskHandler.AddTask(Guid SecurityToken, OnTimeTasks.Task) method (FYI - OnTimeTasks is what I called my Web Reference to the OnTime Task Service), let's look at some sample code;
OnTimeTasks otTask = new OnTimeTasks.Task();
otTask.Name = task.Name; // sets the OnTime Task Name to the Project Task Name
onTask.StartDate = (DateTime)task.Start;
otTask.DueDate = (DateTime)task.Finish;
otTask.Notes = task.Notes;
// 60 minutes, 8 hours in a day
int days = (int)task.Duration / 60 / 8;
otTask.EstimatedDuration = days;
// Days (select * from OnTimeDB..TimeUnitTypes)
otTask.DurationUnitTypeId = 1;
otTask.ProjectId = (cbProjects.SelectedItem as OnTimeProject).ProjectId;
otTask.TaskId = taskHandler.AddTask(otTask);
Ok, most of that should be fairly obvious, but the stuff toward the end might not be, the EstimationDuration and DurationUnitTypeId are probably the two most obscure properties were going to work with. The EstimatedDuration property stores a System.Int32 which represents the number of Minutes that the task is estimated to take, however, in OnTime we want to display this as a much smaller number, since presumably we'll spend much more then a few minutes on a single task (remember, MS Project is for setting up the 'Big Picture'). The DurationUnitTypeId is another System.Int32, whose value needs to match a value from the TimeUnitTypes table in the OnTime Database. The SQL Query needed to look at this tables data is provided in the preceeding comment. Once you've found the value for the 'Days' type, put it in the DurationUnitTypeId.
After we set all our of Task values, and have added the Task into OnTime, we can switch over to our favorite OnTime Client (Web, Windows or VS.NET) and Refresh our view and your Task(s) should now be present.
Now, your probably thinking to yourself, "What good is this if I can't go back?". Your right, this tool is fairly useless, as it is now, because all it does is convert an MS Project to an OnTime Project -- but, with little work, you can have a completely customized Synchronization Tool written in a matter of hours. Why didn't I include this ability in the sample? Well, it's a tad beyond the scope of a "sample" for one, but mainly because such a tool would need to be tailored to your specific needs and usage of both applications and there is no hard-set standard for this, so I simply omitted that functionality.
In short though, if you want to introduce tasks into Microsoft Project from OnTime, you can more or less just completely flip the logic used in this sample, and create tasks in Project from tasks in OnTime -- you can even, using Custom Fields to store meta-data (OnTime TaskId and Project TaskId) perform synchronization, so that your Project Manager can quickly say "Sychronize" from a pre-defined Macro which launches a Shell (VBA, gotta love to hate it ... I mean, hate to love it ... err ... its there, just use it ;p) that executes your custom synchronization app -- an example VBA macro would be:
Sub SynchronizeOnTime()
Dim i as Double
i = Shell("path\to\your\exe" & " " & ActiveProject.Path & "\" & ActiveProject.Name, vbNormalFocus)
End Sub
Which could easily launch your tool and pass the current Projects File path to it, so that a synchronization could be performed -- storing additional meta-data in your Project's Properties using Custom Fields, you can determine the OnTime project to lookup, and the Tasks to keep in sync --
For the complete source to this example, please goto the download page.
To discuss this sample, please refer to this forum thread.