最近一项目中要求显示网络流量,而且必须使用C#。
事实上,调用 IpHlpApi.dll 的 GetIfTable API 可以轻易获得网络信息和网络流量。只是要在C#中实现还是比较复杂。
先看看怎么定义该 API
[DllImport("IpHlpApi.dll")]
extern static public uint GetIfTable(byte[] pIfTable, ref uint pdwSize, bool bOrder);本来想把 pIfTable 定义为 IntPtr,但是这样的结果是,获取的信息是错误的(直到现在都不知是什么原因)。
但显然定义为 byte[] 是不能直接使用的。幸好在 Google Code Search 找到了三个类:

CustomtMarshaler.cs
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;

namespace Lemony.SystemInfo


{

/**//// <summary>
/// CustomMarshaler class implementation.
/// </summary>
public abstract class CustomMarshaler

{

Fields#region Fields
// The internal buffer
internal byte[] data;
private MemoryStream stream;
private BinaryReader binReader;
private BinaryWriter binWriter;
#endregion

constructors#region constructors

public CustomMarshaler()

{

}
#endregion


public methods#region public methods

public void Deserialize()

{
if (data != null)

{
if (binReader != null)

{
binReader.Close();
stream.Close();
}
// Create a steam from byte array
stream = new MemoryStream(data);
binReader = new BinaryReader(stream, System.Text.Encoding.Unicode);
ReadFromStream(binReader);
binReader.Close();
}

}

public void Serialize()

{
if (data != null)

{
stream = new MemoryStream(data);
binWriter = new BinaryWriter(stream, System.Text.Encoding.Unicode);
WriteToStream(binWriter);
binWriter.Close();
}
}

public int GetSize()

{
int size = 0;

FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);

foreach (FieldInfo field in fields )

{
if (field.FieldType.IsArray)

{
size += GetFieldSize(field);
}
else if (field.FieldType == typeof(string))

{
size += GetFieldSize(field)*2;
}
else if (field.FieldType.IsPrimitive)

{
size += Marshal.SizeOf(field.FieldType);
}
}

return size;
}

#endregion


properties#region properties

public byte[] ByteArray

{
get

{
return data;
}
}

#endregion


virtual and protected methods#region virtual and protected methods

public virtual void ReadFromStream(BinaryReader reader)

{
object[] param = null;

// Get all public fields
FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
// Loop through the fields
foreach(FieldInfo field in fields)

{
// Retrieve the read method from ReadMethods hashtable
MethodInfo method = (MethodInfo)MarshallingMethods.ReadMethods[field.FieldType];

if (field.FieldType.IsArray)

{
Type element = field.FieldType.GetElementType();
if (element.IsValueType && element.IsPrimitive)

{
if ((element == typeof(char)) || element == typeof(byte))

{
param = new object[1];
param[0] = GetFieldSize(field);
field.SetValue(this, method.Invoke(reader, param));
}
else // any other value type array

{
param = new object[2];
param[0] = reader;
param[1] = GetFieldSize(field);
field.SetValue(this, method.Invoke(null, param));
}
}
else // array of sub structures

{
int size = GetFieldSize(field);
method = (MethodInfo)MarshallingMethods.ReadMethods[typeof(CustomMarshaler)];
Array objArray = Array.CreateInstance(element, size);
for(int i=0;i<size;i++)

{
objArray.SetValue(Activator.CreateInstance(element), i);

method.Invoke(objArray.GetValue(i), new object[]
);
}
field.SetValue(this, objArray);
}
}
else if (field.FieldType == typeof(string))

{
param = new object[2];
param[0] = reader;
param[1] = GetFieldSize(field);
field.SetValue(this, method.Invoke(null, param));
}
else if (field.FieldType.IsValueType && field.FieldType.IsPrimitive)// regular value type

{
field.SetValue(this, method.Invoke(reader, null));
}
else //process substructure

{
CustomMarshaler subStruct = (CustomMarshaler)Activator.CreateInstance(field.FieldType);
subStruct.ReadFromStream(reader);
}
}
}

public virtual void WriteToStream(BinaryWriter writer)

{
object[] param = null;

FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach(FieldInfo field in fields)

{
// Check if we have any value
object value = field.GetValue(this);
MethodInfo method = (MethodInfo)MarshallingMethods.WriteMethods[field.FieldType];
if (field.FieldType.IsArray)

{
Type element = field.FieldType.GetElementType();
if (element.IsValueType && element.IsPrimitive)

{
//method.Invoke(writer, new object[] );
Array arrObject = (Array)field.GetValue(this);
param = new object[2];
param[0] = writer;
param[1] = arrObject;
method.Invoke(null, param);
}
else

{
//Get field size
int size = GetFieldSize(field);
//Get WriteToStream method
method = (MethodInfo)MarshallingMethods.WriteMethods[typeof(CustomMarshaler)];
Array arrObject = (Array)field.GetValue(this);
for(int i=0;i<size;i++)

{

method.Invoke(arrObject.GetValue(i), new object[]
);
}
}
}
else if (field.FieldType == typeof(string))

{
param = new object[3];
param[0] = writer;
param[1] = field.GetValue(this);
param[2] = GetFieldSize(field);
method.Invoke(null, param);

}
else if (field.FieldType.IsValueType && field.FieldType.IsPrimitive)// regular value type

{

method.Invoke(writer, new object[]
);
}
}
}

protected int GetFieldSize(FieldInfo field)

{
int size = 0;
CustomMarshalAsAttribute attrib = (CustomMarshalAsAttribute)field.GetCustomAttributes(typeof(CustomMarshalAsAttribute), true)[0];
if (attrib != null)

{
if (attrib.SizeField != null)

&n