private bool ApplyFirewallRules(DataTable dtRules, TrafficDirectionTypeEnum direction)
        {
            INetFwPolicy2 policyObj = Extensions.InstantiateTypeFromProgID("HNetCfg.FwPolicy2");//Not valid for Windows XP.  Use INetFwMgr (HNetCfg.FwMgr)

            for (int i = 0; i < dtRules.Rows.Count; i++)
            {
                INetFwRule potentialNewRule = FirewallObjectHelper.NewFirewallRule(
                    dtRules.Cell<string>(i, "Name"),
                    dtRules.Cell<FirewallActionTypeEnum>(i, "Allow"),
                    dtRules.Cell<ProfileTypeEnum>(i, "Profile"),
                    dtRules.Cell<ProtocolTypeEnum>(i, "Protocol"),
                    dtRules.Cell<string>(i, "Local IP"),
                    dtRules.Cell<string>(i, "Remote IP"),
                    dtRules.Cell<string>(i, "Local Ports"),
                    dtRules.Cell<string>(i, "Remote Ports"),
                    dtRules.Cell<string>(i, "Program"),
                    dtRules.Cell<string>(i, "Allowed Users"),
                    dtRules.Cell<string>(i, "Allowed Computers"),
                    dtRules.Cell<string>(i, "Group"),
                    dtRules.Cell<bool>(i, "On"),
                    dtRules.Cell<bool>(i, "Override"),
                    direction);

                bool RuleIsPresent = false;
                foreach (INetFwRule ruleObj in policyObj.Rules)
                {
                    if (potentialNewRule.Same(ruleObj))//TODO: Support Interfaces comparison, too.
                        RuleIsPresent = true;
                }
                if (!RuleIsPresent)
                {

                    policyObj.Rules.Add(potentialNewRule);
                    Marshal.FinalReleaseComObject(potentialNewRule);
                    potentialNewRule = null;
                }
            }
            return true;
        }
        //http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework/2007-06/msg00458.html - Discusses grouping on the firewall rules.
        /// <summary>
        /// 
        /// </summary>
        /// <param name="RuleName">
        /// Note: Must not contain the '|' character.</param>
        /// <param name="actionType"></param>
        /// <param name="profileType"></param>
        /// <param name="protocol">Export rules.  Only doing UDP and TCP show in the referenced enum.  Additional protocols that are possibly supported:
        /// http://go.microsoft.com/fwlink/p/?linkid=89889 </param>
        /// <param name="localAddresses">
        /// "*" indicates any local address. If present, this must be the only token included.
        /// "Defaultgateway"
        /// "DHCP"
        /// "WINS"
        /// "LocalSubnet" indicates any local address on the local subnet. This token is not case-sensitive.
        /// A subnet can be specified using either the subnet mask or network prefix notation. If neither a subnet mask not a network prefix is specified, the subnet mask defaults to 255.255.255.255.
        /// A valid IPv6 address.
        /// An IPv4 address range in the format of "start address - end address" with no spaces included.
        /// An IPv6 address range in the format of "start address - end address" with no spaces included.
        /// </param>
        /// <param name="remoteAddresses">
        /// "*" indicates any remote address. If present, this must be the only token included.
        /// "Defaultgateway"
        /// "DHCP"
        /// "DNS"
        /// "WINS"
        /// "LocalSubnet" indicates any local address on the local subnet. This token is not case-sensitive.
        /// A subnet can be specified using either the subnet mask or network prefix notation. If neither a subnet mask not a network prefix is specified, the subnet mask defaults to 255.255.255.255.
        /// A valid IPv6 address.
        /// An IPv4 address range in the format of "start address - end address" with no spaces included.
        /// An IPv6 address range in the format of "start address - end address" with no spaces included.
        /// </param>
        /// <param name="localPorts"></param>
        /// <param name="remotePorts">
        /// </param>
        /// <param name="Program">The path to the program for which an exception is being added.
        /// Note: If there are environment variables, they will be expanded when the rule is saved.</param>
        /// <param name="AllowedUsers"></param>
        /// <param name="AllowedComputers"></param>
        /// <param name="Group">
        /// Using the Grouping property is highly recommended, as it groups multiple rules into a single line in the
        /// Windows Firewall control panel. This allows the user to enable or disable multiple rules with a single click.
        /// The Grouping property can also be specified using indirect strings. In this case, a group description can
        /// also be specified that will appear in the rule group properties in the Windows Firewall control panel. For
        /// example, if the group string is specified by an indirect string at index 1005 ("@yourresources.dll,-1005"),
        /// the group description can be specified at a resource string higher by 10000 "@youresources.dll,-11005."
        /// 
        /// When indirect strings in the form of "h" are passed as parameters to the Windows Firewall with Advanced
        /// Security APIs, they should either be placed under the System32 Windows directory or specified by a full
        /// path. Further, the file should have a secure access that permits the Local Service account read acces
        /// to allow the Windows Firewall Service to read the strings. To avoid non-privileged security principals
        /// from modifying the strings, the DLLs should only allow write access to the Administrator account.</param>
        /// <param name="Enabled"></param>
        /// <param name="Override"></param>
        /// <param name="TrafficDirection"></param>
        /// //Description: Describes the rule.  Must not contiain the '|' character.
        /// //Interfaces: Represented by their friendly names.  http://msdn.microsoft.com/en-us/library/windows/desktop/dd339603(v=vs.85).aspx
        /// //InterfaceTypes: Acceptable values for this property are "RemoteAccess", "Wireless", "Lan", and "All". If more than one interface type is specified, the strings must be separated by a comma.
        /// //ServiceName property: A serviceName value of "*" indicates that a service, not an application, must be sending or receiving traffic.
        /// <returns></returns>
        internal static INetFwRule NewFirewallRule(string RuleName, FirewallActionTypeEnum actionType, ProfileTypeEnum profileType, ProtocolTypeEnum protocol,
			string localAddresses, string remoteAddresses, string localPorts, string remotePorts,
			string Program,
			string AllowedUsers, string AllowedComputers,//Not yet supported.
			string Group,
			bool Enabled,
			bool Override,
			TrafficDirectionTypeEnum TrafficDirection = TrafficDirectionTypeEnum.Incoming)
        {
            INetFwRule firewallRule = Extensions.InstantiateTypeFromProgID("HNetCfg.FWRule");
            //Don't count on the property list at http://msdn.microsoft.com/en-us/library/windows/desktop/aa365344(v=vs.85).aspx being in the correct order...
            firewallRule.Name = RuleName;
            //Description
            firewallRule.Enabled = Enabled;

            if (!string.IsNullOrWhiteSpace(Program) && !Program.Matches("Any"))
                firewallRule.ApplicationName = Program;
            //ServiceName
            firewallRule.Protocol = (int)protocol;
            #region Addresses and ports
            if (string.IsNullOrWhiteSpace(Program) ||  Program.Matches("Any"))
            {
                if (localPorts.Matches("Any"))
                    firewallRule.LocalPorts = "*";
                else
                    firewallRule.LocalPorts = localPorts.Replace(" ", "");
                if (remotePorts.Matches("Any"))
                    firewallRule.RemotePorts = "*";
                else
                    firewallRule.RemotePorts = remotePorts.Replace(" ", "");
                if (localAddresses.Matches("Any"))
                    firewallRule.LocalAddresses = "*";
                else
                    firewallRule.LocalAddresses = localAddresses.Replace(" ", "");
                if (remoteAddresses.Matches("Any"))
                    firewallRule.RemoteAddresses = "*";
                else
                    firewallRule.RemoteAddresses = remoteAddresses.Replace(" ", "");
            }
            #endregion
            firewallRule.Profiles = (int)profileType;
            //Interfaces
            //InterfaceTypes
            firewallRule.Direction = TrafficDirection.GetCOMEnum();
            firewallRule.Action = actionType.GetCOMEnum();
            //Edge Traversal
            //Set either scope or remote addresses, but not both.  - http://msdn.microsoft.com/en-us/library/aa366436(v=vs.85).aspx
            #region AllowedSettings
            //TODO: Find settings for Allowed Users and Allowed Computers
            #endregion
            firewallRule.Grouping = Group;
            //firewallRule.InterfaceTypes = "All";
            return firewallRule;
            //Additional data: http://msdn.microsoft.com/en-us/library/aa366447(v=vs.85).aspx
            //Interfaces: http://msdn.microsoft.com/en-us/library/aa366449(v=vs.85).aspx
        }