在支持Windows XP的C中获取和设置默认网关

在支持Windows XP的C中获取和设置默认网关,c,windows,winapi,winsock,C,Windows,Winapi,Winsock,我已经找到了用于管理IP相关信息的IP Helper接口,但是我没有找到使用Windows XP支持的接口获取和/或更改给定适配器的网关地址的方法。有什么想法吗?如果你可以使用WMI,那么就有这个类。如果您需要普通的旧C API,我发现(“设置默认网关地址”位于底部附近)。getAdapterInfo()和getAdapterAddresses()函数都返回每个适配器的网关信息。注:Win32\u NetworkAdapterConfiguration::SetGateways()将设置参数中指

我已经找到了用于管理IP相关信息的IP Helper接口,但是我没有找到使用Windows XP支持的接口获取和/或更改给定适配器的网关地址的方法。有什么想法吗?

如果你可以使用WMI,那么就有这个类。如果您需要普通的旧C API,我发现(“设置默认网关地址”位于底部附近)。
getAdapterInfo()和
getAdapterAddresses()函数都返回每个适配器的网关信息。

注:Win32\u NetworkAdapterConfiguration::SetGateways()将设置参数中指定的网关,其中现有网关将被覆盖

但是:在使用SetGateways()WMI调用时,删除网关似乎不起作用——在我的情况下,调用成功返回,但网关仍然存在。似乎有很多人已经看到了这一点(在StringArray中设置NULL字符串或为StringArray传递NULL没有帮助)

在我的例子中,我开始使用WMI方式(很可能是因为EnableDHCP()),但也需要实现Luke建议的WINAPI方式,以消除网关的灾难。非常感谢卢克

公共枚举转发类型
    public enum ForwardType
    {
        Other = 1,
        Invalid = 2,
        Direct = 3,
        Indirect = 4
    }

    public enum ForwardProtocol
    {
        Other = 1,
        Local = 2,
        NetMGMT = 3,
        ICMP = 4,
        EGP = 5,
        GGP = 6,
        Hello = 7,
        RIP = 8,
        IS_IS = 9,
        ES_IS = 10,
        CISCO = 11,
        BBN = 12,
        OSPF = 13,
        BGP = 14,
        NT_AUTOSTATIC = 10002,
        NT_STATIC = 10006,
        NT_STATIC_NON_DOD = 10007
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MIB_IPFORWARDROW
    {
        public uint dwForwardDest;
        public uint dwForwardMask;
        public int dwForwardPolicy;
        public uint dwForwardNextHop;
        public int dwForwardIfIndex;
        public ForwardType dwForwardType;
        public ForwardProtocol dwForwardProto;
        public int dwForwardAge;
        public int dwForwardNextHopAS;
        public int dwForwardMetric1;
        public int dwForwardMetric2;
        public int dwForwardMetric3;
        public int dwForwardMetric4;
        public int dwForwardMetric5;

        public static List<MIB_IPFORWARDROW> FromByteArray(byte[] buffer)
        {
            List<MIB_IPFORWARDROW> ret = new List<MIB_IPFORWARDROW>();

            int n =
                (buffer[3] << 24) +
                (buffer[2] << 16) +
                (buffer[1] << 8) +
                (buffer[0] << 0);

            int offset = sizeof(int);
            for (int i = 0; i < n; i++)
            {
                MIB_IPFORWARDROW map = new MIB_IPFORWARDROW();
                IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(map));
                Marshal.StructureToPtr(map, ptr, false);
                Marshal.Copy(buffer, offset, ptr, Marshal.SizeOf(map));
                map = (MIB_IPFORWARDROW)Marshal.PtrToStructure(ptr, typeof(MIB_IPFORWARDROW));
                Marshal.FreeHGlobal(ptr);
                ret.Add(map);
                offset += Marshal.SizeOf(map);
            }
            return ret;
        }
    }

    [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)]
    public static extern int GetIpForwardTable(byte[] pIpForwardTable, ref ulong pdwSize, bool bOrder);

    [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)]
    public static extern int DeleteIpForwardEntry(ref MIB_IPFORWARDROW pRoute);

    [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)]
    public static extern int SetIpForwardEntry(ref MIB_IPFORWARDROW pRoute);

    private static uint IPToUIntR(IPAddress ip)
    {
        uint ret = 0;
        byte[] ipBytes = ip.GetAddressBytes();

        ret += (uint)ipBytes[0] << 24;
        ret += (uint)ipBytes[1] << 16;
        ret += (uint)ipBytes[2] << 8;
        ret += (uint)ipBytes[3];

        return ret;
    }

    public static List<MIB_IPFORWARDROW> GetIPForwardTable(int index)
    {
        List<MIB_IPFORWARDROW> ret = new List<MIB_IPFORWARDROW>();
        ulong size = 0;
        int err = GetIpForwardTable(null, ref size, false);
        byte[] buffer = new byte[size];
        err = GetIpForwardTable(buffer, ref size, false);

        if (err != 0)
        {
            throw new System.ComponentModel.Win32Exception(err, $"GetIPForwardTable return with error code {err}");
        }

        foreach (MIB_IPFORWARDROW mipr in MIB_IPFORWARDROW.FromByteArray(buffer))
        {
            if (mipr.dwForwardIfIndex != index)
            {
                continue;
            }
            ret.Add(mipr);
        }
        return ret;
    }

    public static void SetDefaultGateway(int index, string gateway)
    {
        int err;
        int i;
        List<MIB_IPFORWARDROW> l = GetIPForwardTable(index);
        MIB_IPFORWARDROW mipr = new MIB_IPFORWARDROW();
        for (i = 0; i < l.Count; ++i)
        {
            // 0.0.0.0 default gateway
            if (l[i].dwForwardDest != 0)
            {
                continue;
            }

            mipr = l[i];
            err = DeleteIpForwardEntry(ref mipr);
            if (err != 0)
            {
                throw new System.ComponentModel.Win32Exception(err, $"DeleteIpForwardEntry return with error code {err}");
            }
            break;
        }
        mipr.dwForwardNextHop = IPToUIntR(IPAddress.Parse(gateway));

        err = SetIpForwardEntry(ref mipr);
        if (err != 0)
        {
            throw new System.ComponentModel.Win32Exception(err, $"DeleteIpForwardEntry return with error code {err}");
        }
    }
{ 其他=1, 无效=2, 直接=3, 间接=4 } 公共枚举转发协议 { 其他=1, 本地=2, 网络管理=3, ICMP=4, EGP=5, GGP=6, 你好=7, RIP=8, IS_IS=9, ES_=10, 思科=11, BBN=12, OSPF=13, BGP=14, NT_自动静态=10002, NT_静态=10006, NT\u静态\u非\u国防部=10007 } [StructLayout(LayoutKind.Sequential)] 公共结构MIB_IPFORWARDROW { 公共单位数据转发; 公共单位面具; 公共政策; 下一步的公共uint DWFORWARD; 公共国际数据转发索引; 公共转发类型dwForwardType; 公共转发协议dwForwardProto; 公共运输; 公共int DWFORWARD NEXTHOPAS; 公共国际计量中心1; 公共国际计量中心2; 公共国际计量3; 公共国际计量4; 公共国际计量中心5; ByteArray的公共静态列表(字节[]缓冲区) { List ret=新列表(); int n=
(缓冲区[3]如果编译到vista或更高版本,则会执行此操作。
GetAdapterInfo()
在XP SP3上为我返回网关信息。很抱歉,我的错误。这些函数也需要windows vista。只需从函数和结构名称中删除2;例如GetIpForwardTable(),DeleteIpForwardEntry()等。这些功能和结构可以追溯到Windows 2000。
    const int MAX_ADAPTER_ADDRESS_LENGTH = 8;
    const int MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
    const int MAX_ADAPTER_NAME_LENGTH = 256;
    const int MAX_ADAPTER_NAME = 128;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct IP_ADDRESS_STRING
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
        public string Address;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct IP_ADDR_STRING
    {
        public IntPtr Next;
        public IP_ADDRESS_STRING IpAddress;
        public IP_ADDRESS_STRING IpMask;
        public ulong Context;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct IP_ADAPTER_INFO
    {
        public IntPtr Next;
        public Int32 ComboIndex;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ADAPTER_NAME_LENGTH + 4)]
        public string AdapterName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ADAPTER_DESCRIPTION_LENGTH + 4)]
        public string AdapterDescription;
        public UInt32 AddressLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_ADAPTER_ADDRESS_LENGTH)]
        public byte[] Address;
        public Int32 Index;
        public UInt32 Type;
        public UInt32 DhcpEnabled;
        public IntPtr CurrentIpAddress;
        public IP_ADDR_STRING IpAddressList;
        public IP_ADDR_STRING GatewayList;
        public IP_ADDR_STRING DhcpServer;
        public bool HaveWins;
        public IP_ADDR_STRING PrimaryWinsServer;
        public IP_ADDR_STRING SecondaryWinsServer;
        public Int32 LeaseObtained;
        public Int32 LeaseExpires;
    }

    [DllImport("iphlpapi.dll", CharSet = CharSet.Ansi)]
    static extern int GetAdaptersInfo(byte[] pAdapterInfo, ref ulong pBufOutLen);

    public static List<IP_ADAPTER_INFO> GetAllAdapters()
    {
        List<IP_ADAPTER_INFO> ret = new List<IP_ADAPTER_INFO>();

        ulong size = 0;
        int err = GetAdaptersInfo(null, ref size);
        byte[] buffer = new byte[size];
        err = GetAdaptersInfo(buffer, ref size);

        if (err != 0)
        {
            throw new System.ComponentModel.Win32Exception(err, $"GetInterfaceInfo return with error code {err}");
        }

        GCHandle gc = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        IntPtr pEntry = gc.AddrOfPinnedObject();
        do
        {
            IP_ADAPTER_INFO entry = (IP_ADAPTER_INFO)Marshal.PtrToStructure(pEntry, typeof(IP_ADAPTER_INFO));

            ret.Add(entry);

            pEntry = entry.Next;
        }
        while (pEntry != IntPtr.Zero);

        gc.Free();

        return ret;
    }