/// <summary>
        /// Adds/updates or deletes an http(s) URL namespace reservation for a specified Windows user or group.
        /// </summary>
        /// <param name="url">The http(s) URL to modify the reservation for.</param>
        /// <param name="windowsAccountName">The Windows account name (user or group) to modify the reservation for.</param>
        /// <param name="configurationAction">The configuration action to perform (e.g. add/update or delete).</param>
        /// <remarks>
        /// This method must be called under a user context with local administrative privledges.  See
        /// <a href="http://msdn.microsoft.com/en-us/magazine/cc163531.aspx">http://msdn.microsoft.com/en-us/magazine/cc163531.aspx</a> about why this is necessary.
        /// </remarks>
        public static void ModifyNamespaceReservation(Uri url, string windowsAccountName, HttpServerApiConfigurationAction configurationAction)
        {
            if ((false == url.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)) &&
                (false == url.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)))
            {
                throw new ArgumentException("Invalid scheme.  Only http and https are supported.", "url");
            }

            uint retVal = NativeMethods.HttpInitialize(NativeMethods.HTTPAPI_VERSION_1, (uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);

            if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal)
            {
                string urlPrefix = BuildStrongWildcardUrlPrefixFromUrl(url);
                var    keyDesc   = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_KEY(urlPrefix);

                string securityDescriptor = BuildGenericExecuteSecurityDescriptorFromWindowsAccount(windowsAccountName);
                var    paramDesc          = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_PARAM(securityDescriptor);

                var inputConfigInfoSet = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_SET
                {
                    KeyDesc   = keyDesc,
                    ParamDesc = paramDesc
                };

                IntPtr unmanagedConfigInformation = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NativeMethods.HTTP_SERVICE_CONFIG_URLACL_SET)));
                Marshal.StructureToPtr(inputConfigInfoSet, unmanagedConfigInformation, false);

                if (configurationAction == HttpServerApiConfigurationAction.Delete)
                {
                    retVal = NativeMethods.HttpDeleteServiceConfiguration(
                        IntPtr.Zero,
                        NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                        unmanagedConfigInformation,
                        Marshal.SizeOf(inputConfigInfoSet),
                        IntPtr.Zero);

                    if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_FILE_NOT_FOUND == retVal)
                    {
                        // OK -- nothing to delete...
                        retVal = (uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR;
                    }
                }
                else
                {
                    retVal = NativeMethods.HttpSetServiceConfiguration(
                        IntPtr.Zero,
                        NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                        unmanagedConfigInformation,
                        Marshal.SizeOf(inputConfigInfoSet),
                        IntPtr.Zero);

                    if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_ALREADY_EXISTS == retVal)
                    {
                        retVal = NativeMethods.HttpDeleteServiceConfiguration(
                            IntPtr.Zero,
                            NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                            unmanagedConfigInformation,
                            Marshal.SizeOf(inputConfigInfoSet),
                            IntPtr.Zero);

                        if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal)
                        {
                            retVal = NativeMethods.HttpSetServiceConfiguration(
                                IntPtr.Zero,
                                NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo,
                                unmanagedConfigInformation,
                                Marshal.SizeOf(inputConfigInfoSet),
                                IntPtr.Zero);
                        }
                    }
                }

                Marshal.FreeCoTaskMem(unmanagedConfigInformation);
                NativeMethods.HttpTerminate((uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }

            if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR != retVal)
            {
                throw Marshal.GetExceptionForHR(HResultFromWin32(retVal));
            }
        }
        /// <summary>Add/updates or deletes an SSL certificate binding for a specified IP address/port.</summary>
        /// <remarks>
        /// The provided SSL certificate data in <paramref name="sslHash"/> is added/updated/deleted in the certificate
        /// store specified by <paramref name="targetSslCertStoreName"/>.
        /// </remarks>
        /// <param name="address">The IP address to bind the SSL certificate to.</param>
        /// <param name="port">The port to bind the SSL certificate to.</param>
        /// <param name="sslHash">The hash of the SSL certificate to bind.</param>
        /// <param name="targetSslCertStoreName">The target certificate store for the SSL certificate.</param>
        /// <param name="configurationAction">The configuration action to perform (e.g. add/update or delete).</param>
        public static void ModifySslCertificateToAddressBinding(string address, int port, byte[] sslHash, StoreName targetSslCertStoreName, HttpServerApiConfigurationAction configurationAction)
        {
            uint retVal = NativeMethods.HttpInitialize(NativeMethods.HTTPAPI_VERSION_1, (uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);

            if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal)
            {
                var configSslSet            = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_SET();
                var httpServiceConfigSslKey = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_KEY();
                var configSslParam          = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_PARAM();

                IPAddress ip = IPAddress.Parse(address);
                var       addressEndPoint = new IPEndPoint(ip, port);

                // serialize the endpoint to a SocketAddress and create an array to hold the values.  Pin the array.
                SocketAddress socketAddress       = addressEndPoint.Serialize();
                var           socketBytes         = new byte[socketAddress.Size];
                GCHandle      handleSocketAddress = GCHandle.Alloc(socketBytes, GCHandleType.Pinned);

                // Should copy the first 16 bytes (the SocketAddress has a 32 byte buffer, the size will only be 16,
                // which is what the SOCKADDR accepts
                for (int i = 0; i < socketAddress.Size; ++i)
                {
                    socketBytes[i] = socketAddress[i];
                }

                httpServiceConfigSslKey.pIpPort = handleSocketAddress.AddrOfPinnedObject();

                GCHandle handleHash = GCHandle.Alloc(sslHash, GCHandleType.Pinned);
                configSslParam.AppId = Guid.NewGuid();
                configSslParam.DefaultCertCheckMode                 = 0;
                configSslParam.DefaultFlags                         = (uint)NativeMethods.HTTP_SERVICE_CONFIG_SSL_FLAG.HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT;
                configSslParam.DefaultRevocationFreshnessTime       = 0;
                configSslParam.DefaultRevocationUrlRetrievalTimeout = 0;
                configSslParam.pSslCertStoreName                    = targetSslCertStoreName.ToString();
                configSslParam.pSslHash      = handleHash.AddrOfPinnedObject();
                configSslParam.SslHashLength = sslHash.Length;
                configSslSet.ParamDesc       = configSslParam;
                configSslSet.KeyDesc         = httpServiceConfigSslKey;

                IntPtr unmanagedConfigInformation = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NativeMethods.HTTP_SERVICE_CONFIG_SSL_SET)));
                Marshal.StructureToPtr(configSslSet, unmanagedConfigInformation, false);

                if (configurationAction == HttpServerApiConfigurationAction.Delete)
                {
                    retVal = NativeMethods.HttpDeleteServiceConfiguration(
                        IntPtr.Zero,
                        NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        unmanagedConfigInformation,
                        Marshal.SizeOf(configSslSet),
                        IntPtr.Zero);

                    if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_FILE_NOT_FOUND == retVal)
                    {
                        // OK -- nothing to delete...
                        retVal = (uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR;
                    }
                }
                else
                {
                    retVal = NativeMethods.HttpSetServiceConfiguration(
                        IntPtr.Zero,
                        NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                        unmanagedConfigInformation,
                        Marshal.SizeOf(configSslSet),
                        IntPtr.Zero);

                    if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_ALREADY_EXISTS == retVal)
                    {
                        retVal = NativeMethods.HttpDeleteServiceConfiguration(
                            IntPtr.Zero,
                            NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                            unmanagedConfigInformation,
                            Marshal.SizeOf(configSslSet),
                            IntPtr.Zero);

                        if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal)
                        {
                            retVal = NativeMethods.HttpSetServiceConfiguration(
                                IntPtr.Zero,
                                NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
                                unmanagedConfigInformation,
                                Marshal.SizeOf(configSslSet),
                                IntPtr.Zero);
                        }
                    }
                }

                Marshal.FreeCoTaskMem(unmanagedConfigInformation);
                NativeMethods.HttpTerminate((uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero);
            }

            if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR != retVal)
            {
                throw Marshal.GetExceptionForHR(HResultFromWin32(retVal));
            }
        }