开发者

C# command to get struct offset?

Suppose I have a C# struct like this:

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(60)] public int e_lfanew;
}

Now suppose I read in data from a file, like this:

byte[] data = new byte[4096];
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read);
int n = f.Read(data, 0, 4096);

Now I want to test n to make sure I've read enough bytes to get the value of e_lfanew. Is there any way I can get the value 60 (the FieldOffset) without retyping it? I'm looking for something like this:

if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) {
    ...
}

Is there any such command? In my actual code, I have to make several of these tests, and it seems tedious and error-prone to type the numbers in by hand, either by adding up the prior fields in the struct or by copying values out of the FieldOffset a开发者_如何学Gottributes. Is there a better way?


Use Marshal.OffsetOf:

Marshal.OffsetOf(typeof(IMAGE_DOS_HEADER), "e_lfanew")


Yes you can do this using reflection.

FieldOffsetAttribute fieldOffset = 
    (FieldOffsetAttribute)typeof(IMAGE_DOS_HEADER)
        .GetField("e_lfanew")
        .GetCustomAttributes(
            typeof(FieldOffsetAttribute),
            true
        )[0];
Console.WriteLine(fieldOffset.Value);

You can even turn this into a nice method:

static int FieldOffset<T>(string fieldName) {
    if (typeof(T).IsValueType == false) {
        throw new ArgumentOutOfRangeException("T");
    }
    FieldInfo field = typeof(T).GetField(fieldName);
    if (field == null) {
        throw new ArgumentOutOfRangeException("fieldName");
    }
    object[] attributes = field.GetCustomAttributes(
        typeof(FieldOffsetAttribute),
        true
    );
    if (attributes.Length == 0) {
        throw new ArgumentException();
    }
    FieldOffsetAttribute fieldOffset = (FieldOffsetAttribute)attributes[0];
    return fieldOffset.Value;
}

Usage:

Console.WriteLine(FieldOffset<IMAGE_DOS_HEADER>("e_lfanew"));


Well, you already used a magic number in the structure declaration. Might as well do this:

private const int LfaNewOffset = 60;

[StructLayout(LayoutKind.Explicit)]
struct IMAGE_DOS_HEADER {
    [FieldOffset(LfaNewOffset)] public int e_lfanew;
}
...
if (n >= LfaNewOffset + sizeof(int)) {
    ...
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜