Search code examples
c#comvisual-sourcesafe

Marshalling C# com items when using recursion


I am using the SourceSafe COM object (SourceSafeTypeLib) from C# to automate a SourceSafe recursive get (part of a larger build process). The recursive function is shown below. How do I ensure that all the COM objects created in the foreach loop get released correctly?

   /// <summary>
        /// Recursively gets files/projects from SourceSafe (this is a recursive function).
        /// </summary>
        /// <param name="vssItem">The VSSItem to get</param>
        private void GetChangedFiles(VSSItem vssItem)
        {

            //  'If the object is a file perform the diff,
            //  'If not, it is a project, so use recursion to go through it
            if(vssItem.Type == (int)VSSItemType.VSSITEM_FILE)
            {
                bool bDifferent = false; //file is different
                bool bNew = false; //file is new

                //Surround the diff in a try-catch block. If a file is new(doesn't exist on
                //the local filesystem) an error will be thrown.  Catch this error and record it
                //as a new file.
                try
                {
                    bDifferent = vssItem.get_IsDifferent(vssItem.LocalSpec);
                }
                catch
                {
                    //File doesn't exist
                    bDifferent = true;
                    bNew = true;
                }

                //If the File is different(or new), get it and log the message
                if(bDifferent)
                {
                    if(bNew)
                    {
                        clsLog.WriteLine("Getting " + vssItem.Spec);
                    }
                    else
                    {
                        clsLog.WriteLine("Replacing " + vssItem.Spec);
                    }

                    string strGetPath = vssItem.LocalSpec;
                    vssItem.Get(ref strGetPath, (int)VSSFlags.VSSFLAG_REPREPLACE);
                }

            }
            else //Item is a project, recurse through its sub items
            {
                foreach(VSSItem fileItem in vssItem.get_Items(false))
                {
                    GetChangedFiles(fileItem);
                }

            }

        }

Solution

  • If it is a short running program and there is nothing to "commit" on the COM side, it is ok to let them go, believe it or not. The GC will come and properly release the interfaces when it needs to.

    If it is a long running program (like a server component or takes hours and hours to complete), or you need to "commit" or "save" changes the best bet would be to release them as you would any VSSItem right after your call to GetChangedFiles(fileItem); in your foreach loop.

    Example:

    foreach (VSSItem fileItem in vssItem.get_Items(false))
    {
        GetChangedFiles(fileItem);
        // fileItem.Release(); or fileItem.Dispose();
        // or even Marshal.ReleaseComObject(fileItem);
    }