MS Project - How to avoid memory leak (or loss)?

Oct 24, 2013 at 3:25 PM
Edited Oct 24, 2013 at 3:26 PM
Hi all,

I make a simple code to test "memory leak" of NetOffice with MS Project. My code listing looks like following
using MSProject = NetOffice.MSProjectApi;

MSProject.Application msProjectApplication = new MSProject.Application();
msProjectApplication.Visible = false;
msProjectApplication.DisplayAlerts = false;
msProjectApplication.Calculation = PjCalculation.pjManual;
msProjectApplication.FileOpen(filePath, false, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, PjPoolOpen.pjPoolReadWrite, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
MSProject.Project project = msProjectApplication.ActiveProject;

for (int index = 1; index <= project.Tasks.Count; index++)
{
    Task task = proj.Tasks[index];
    if (task != null)
    {       
        Console.WriteLine("Do nothing");
    }
    task.Dispose();
}
When I let the code run and observe the memory. The memory keeps growing up. I would like to ask how I should "dispose" the object correctly to get "memory back"?

Thank you.
Coordinator
Oct 24, 2013 at 5:22 PM
Your code creates the Tasks enumerator intance more than on times.
This listing is more efficient:

var tasks = project.Tasks;
for (int index = 1; index <= tasks.Count; index++)
{
Task  task = tasks[index];
task .Dispose();
}
tasks.Dispose();

You can observe the count of open proxies in your application with:

int NetOffice.Factory.ProxyCount{get;}

and the ProxyCountChanged event.

'Sebastian
Oct 25, 2013 at 9:14 AM
Edited Oct 25, 2013 at 9:16 AM
Thank you Sebastian for your suggesstions. It really works. However I extend the example by reading/setting property of tasks as following
var tasks = project.Tasks;
foreach (MSProject.Task task in tasks)
{
    if (task != null)
    {
        Console.WriteLine(task.Name);                            //test for getting
        task.Start1 = DateTime.Now.Date;                       //test for setting

        //task.DisposeChildInstances();                           <-- I think this row is not necessary because Dipose() on main object will dispose all child instances
        task.Dispose();
    }
}

tasks.Dispose();
When I let code run, the memory still get growing up. I think when I access the properties, I create again a proxy to COM object. But I don't know how to correctly 'dispose' these objects (Name, Start1 objects in this example). Can you give me some hints?

Thank you.
Coordinator
Oct 25, 2013 at 1:48 PM
this code looks okay so far. when you access a property you create a proxy for com reference types(based on COMObject) you dont do this for value types(int, bool) and also string.

of course you dont have to call DisposeChildInstances explicitly. Dispose() relase all the childs too.

did you have more code for me? and please observe NetOffice.Factory.Proxy count, the last code listing (include open project application and open file) creates <10 com proxies simultaneously in your application.
Oct 28, 2013 at 9:10 AM
Thank you for your explanations. Until now I have just tried with reading therefore I don't have "more" codes. I will add feedbacks when I find anything "weird". Thank you again for your support.