/// <summary>
        /// Attempts to find the document information for the specified file.
        /// </summary>
        /// <param name="absolutePath">The absolute path of the file to search for.</param>
        /// <returns>A <see cref="DocumentInfo"/> object if the file was found; otherwise, null.</returns>
        public DocumentInfo FindByPath(string absolutePath)
        {
            Tracer.VerifyStringArgument(absolutePath, "absolutePath");

            DocumentInfo documentInfo = null;

            // Make the call to IVsRunningDocumentTable.FindAndLockDocument to try to find the document.
            uint lockType = unchecked((uint)_VSRDTFLAGS.RDT_NoLock);
            IVsHierarchy vsHierarchy;
            uint hierarchyId;
            IntPtr punkDocData;
            uint cookie;
            int hr = this.Rdt.FindAndLockDocument(lockType, absolutePath, out vsHierarchy, out hierarchyId, out punkDocData, out cookie);
            NativeMethods.ThrowOnFailure(hr);

            if (punkDocData != IntPtr.Zero)
            {
                try
                {
                    object docData = Marshal.GetObjectForIUnknown(punkDocData);
                    Tracer.Assert(docData != null, "We should be getting something for punkDocData instead of null.");
                    if (docData != null)
                    {
                        documentInfo = new DocumentInfo(absolutePath, vsHierarchy, hierarchyId, docData, cookie);
                    }
                }
                finally
                {
                    Marshal.Release(punkDocData);
                }
            }

            return documentInfo;
        }
        //==========================================================================================
        // Methods
        //==========================================================================================
        /// <summary>
        /// Attempts to find the document information in the Running Document Table from the specified cookie.
        /// </summary>
        /// <param name="documentCookie">The cookie of the document to search for.</param>
        /// <returns>A <see cref="DocumentInfo"/> object if the file was found; otherwise, null.</returns>
        public DocumentInfo FindByCookie(uint documentCookie)
        {
            DocumentInfo docInfo = null;

            if (documentCookie == DocumentInfo.NullCookie)
            {
                return null;
            }

            // Get the document info.
            uint rdtFlags, readLocks, editLocks;
            string path;
            IVsHierarchy vsHierarchy;
            uint hierarchyId;
            IntPtr punkDocData;
            int hr = this.Rdt.GetDocumentInfo(documentCookie, out rdtFlags, out readLocks, out editLocks, out path, out vsHierarchy, out hierarchyId, out punkDocData);
            NativeMethods.ThrowOnFailure(hr);

            if (punkDocData != IntPtr.Zero)
            {
                try
                {
                    object docData = Marshal.GetObjectForIUnknown(punkDocData);
                    Tracer.Assert(docData != null, "We should be getting something for punkDocData instead of null.");
                    if (docData != null)
                    {
                        // Create the new object.
                        docInfo = new DocumentInfo(path, vsHierarchy, hierarchyId, docData, documentCookie);
                    }
                }
                finally
                {
                    Marshal.Release(punkDocData);
                }
            }

            return docInfo;
        }
        public static void TraceRunningDocuments()
        {
            // Get the RDT (Running Document Table)
            IVsRunningDocumentTable rdt = Package.Instance.Context.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable;

            if (rdt == null)
            {
                Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "Cannot get an instance of IVsRunningDocumentTable to use for enumerating the running documents.");
                return;
            }

            // Get the enumerator for the currently running documents.
            IEnumRunningDocuments enumerator;
            int hr = rdt.GetRunningDocumentsEnum(out enumerator);

            if (NativeMethods.Failed(hr))
            {
                Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "Cannot get an instance of IEnumRunningDocuments to use for enumerating the running documents.");
                return;
            }

            // Enumerate.
            StringCollection traceLines = new StringCollection();

            uint[] cookies = new uint[1];
            uint   fetchCount;

            while (true)
            {
                hr = enumerator.Next(1, cookies, out fetchCount);
                if (NativeMethods.Failed(hr))
                {
                    Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "The enumeration failed for the running documents. Hr=0x{0:X}", hr);
                    return;
                }

                if (fetchCount == 0)
                {
                    break;
                }

                uint cookie = cookies[0];

                // We shouldn't be getting a nil cookie.
                if (cookie == DocumentInfo.NullCookie)
                {
                    Tracer.WriteLineWarning(classType, "TraceRunningDocuments", "There is a null cookie value in the RDT, which shouldn't be happening.");
                }
                else
                {
                    // Now we have a document cookie, so let's get some information about it.
                    DocumentInfo docInfo = Package.Instance.Context.RunningDocumentTable.FindByCookie(cookie);
                    string       traceMessage;
                    if (docInfo == null)
                    {
                        traceMessage = PackageUtility.SafeStringFormatInvariant("The document with cookie '{0}' could not be found in the RDT. There's something weird going on.", cookie);
                    }
                    else
                    {
                        // Here's where we actually do the trace finally.
                        traceMessage = PackageUtility.SafeStringFormatInvariant("RDT document: Cookie={0} Path={1} IsOpen={2} IsDirty={3}", docInfo.Cookie, docInfo.AbsolutePath, docInfo.IsOpen, docInfo.IsDirty);
                    }

                    // We don't want to trace immediately because we want all of these lines to appear together. If we
                    // trace immediately, then the messages will be split up.
                    traceLines.Add(traceMessage);
                }
            }

            // Now trace all of the messages at once.
            foreach (string traceMessage in traceLines)
            {
                Tracer.WriteLine(classType, "TraceRunningDocuments", Tracer.Level.Information, traceMessage);
            }
        }