/// <summary>
        /// Returns a list of all known security package providers and their properties.
        /// </summary>
        /// <returns></returns>
        public static CSecPkgInfo[] EnumeratePackages()
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgInfo[] packages = null;
            IntPtr        pkgArrayPtr;
            IntPtr        pkgPtr;
            int           numPackages = 0;
            int           pkgSize     = Marshal.SizeOf(typeof(CSecPkgInfo));

            pkgArrayPtr = new IntPtr();

            RuntimeHelpers.PrepareConstrainedRegions();
            try { }
            finally
            {
                status = CNativeMethods.EnumerateSecurityPackages(ref numPackages, ref pkgArrayPtr);

                if (pkgArrayPtr != IntPtr.Zero)
                {
                    try
                    {
                        if (status == CSecurityStatus.OK)
                        {
                            // Bwooop Bwooop Alocation Alert
                            // 1) We allocate the array
                            // 2) We allocate the individual elements in the array (they're class objects).
                            // 3) We allocate the strings in the individual elements in the array when we
                            //    call Marshal.PtrToStructure()

                            packages = new CSecPkgInfo[numPackages];

                            for (int i = 0; i < numPackages; i++)
                            {
                                packages[i] = new CSecPkgInfo();
                            }

                            for (int i = 0; i < numPackages; i++)
                            {
                                pkgPtr = IntPtr.Add(pkgArrayPtr, i * pkgSize);

                                Marshal.PtrToStructure(pkgPtr, packages[i]);
                            }
                        }
                    }
                    finally
                    {
                        CNativeMethods.FreeContextBuffer(pkgArrayPtr);
                    }
                }
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to enumerate security package providers", status);
            }

            return(packages);
        }
        /// <summary>
        /// Returns the properties of the named package.
        /// </summary>
        /// <param name="packageName">The name of the package.</param>
        /// <returns></returns>
        public static CSecPkgInfo GetPackageCapabilities(string packageName)
        {
            CSecPkgInfo     info;
            CSecurityStatus status = CSecurityStatus.InternalError;

            IntPtr rawInfoPtr;

            rawInfoPtr = new IntPtr();
            info       = new CSecPkgInfo();

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            { }
            finally
            {
                status = CNativeMethods.QuerySecurityPackageInfo(packageName, ref rawInfoPtr);

                if (rawInfoPtr != IntPtr.Zero)
                {
                    try
                    {
                        if (status == CSecurityStatus.OK)
                        {
                            // This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
                            Marshal.PtrToStructure(rawInfoPtr, info);
                        }
                    }
                    finally
                    {
                        CNativeMethods.FreeContextBuffer(rawInfoPtr);
                    }
                }
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to query security package provider details", status);
            }

            return(info);
        }