开发者

Upgrading C code to VB.NET - Unioned Structures

I am trying to upgrade the btrieve code written by Jim Kyle in the early 90's to VB.NET and am running into a problem with unioned structures. The old C code is as follows:

    typedef struct {
      union {
        struct {
          PGPTR   PgSeq;    // 00 - page number
          int     Usage; 开发者_如何学Python   // 04 - match with usage count
          int     Version;  // 06 - version code, <0 if owned
        } v5;
        struct {
          int     RecSig;   // 00 - 'FC'
          int     SeqNbr;   // 02 - always binary zeroes
          long    Usage;    // 04 - usage count
        } v6;
      } r1;
      int     PagSize;  // 08 - in bytes
    } FCRTOP;

So far, I had:

    <StructLayout(LayoutKind.Explicit)> _
Structure FCRTOP
    <FieldOffset(0)> Public PgSeq As PGPTR
    <FieldOffset(4)> Public Usage As Short
    <FieldOffset(6)> Public Version As Short

    <FieldOffset(0)> Public RecSig As Short
    <FieldOffset(2)> Public SeqNbr As Short
    <FieldOffset(4)> Public Usage As Integer
End Structure

One issue I am running into is that VB.NET doesnt like two struct variables with the same name (Usage). What am I missing to group the overlapping fields with a unique struct name as is done in the C example (v5 and v6)?

Thanks for any help!


The answer to this depends entirely on what you're doing:

  • If you're attempting to create a managed interface to your existing unmanaged library (in other words, write code in VB.NET or some other .NET language that calls code in an existing non-.NET .dll), then you're doing the right thing. I'll address that in a second
  • If you're attempting to create a managed implementation of your existing unmanaged library (i.e. rewrite the existing .dll in .NET and get rid of the existing .dll entirely), then you should spend the time necessary to refactor the code into something object-oriented rather than trying to duplicate structures and such. In general structures (which are value types) should be used only if you have a particularly convincing reason to do so; otherwise, you should be using classes (reference types) and properly migrate the code from procedural into object-oriented.

If you're creating a managed interface, you should know that the naming of structure members is ignored. It's the order and size of the elements that's important. However, that's not really your issue here, as you're just dealing with an impedance mismatch between the way C defines structures and the way VB.NET (and other .NET languages) do. Since the union keyword just allows you to break up a larger structure into logical blocks of variables without defining the substruct as a standalone data structure, some massaging is required to get it into .NET, which doesn't allow such things (again, structs are not the primary means of encapsulating information in reference-based object-oriented languages like VB.NET and C#). You'll have to take the substructure(s) and define them as structures on their own, then define a variable typed as the substructure as a regular member on the outer structure.

(Incidentally, there's no need to use StructLayoutKind.Explicit if you're declaring the members in order; using Sequential will make it easier to read if they're already in the right order.)

After that somewhat long-winded response, you're looking for something like this:

<StructLayout(LayoutKind.Sequential)> _ 
Structure StructV5
    Public PgSeq As PGPTR
    Public Usage As Short
    Public Version As Short
End Structure 

<StructLayout(LayoutKind.Sequential)> _ 
Structure StructV6
    Public RecSig As Short
    Public SeqNbr As Short
    Public Usage As Integer
End Structure 

<StructLayout(LayoutKind.Explicit)> _ 
Structure FCRTOP
    <FieldOffset(0)>Public V5 as StructV5
    <FieldOffset(0)>Public V6 as StructV6
    <FieldOffset(8)>Public PagSize as Short
End Structure

Your other option would be to keep your structure as-is (and add the member for PagSize, of course) and simply change the name of Usage within v6. However, taking this approach (with explicit struct declaration) will give you more meaningful syntax.


VB.NET definitely does not have a feature exactly like this so I think your best bet is to try and capture the "spirit" of the idea of unions in a way that is compatible with .NET's type system.

Disclaimer: I have very little knowledge of C, so it's possible I misunderstand what the purpose of unions in C is. If that's the case, it should be apparent from my suggestion.

So, I think what you essentially want is a Structure comprising 64 bits which can represent either v5 or v6 from your example C code, plus another 16 for PageSize. What I'd do to make this possible is store 4 Short values and combine them as necessary (note: what I have sketched out below would be an immutable type; if you would need the use of public read/write fields then I'm at a loss as to how that could be accomplished, if it's even possible):

Structure FCRTOP
    Private a As Short
    Private b As Short
    Private c As Short
    Private d As Short

    Public ReadOnly PageSize As Short

    ' Possibly two constructors, one accepting PGTR, Short Short, Short, '
    ' the other accepting Short, Short, Integer, Short '

    Public ReadOnly Property V5 As V5
        Get
            Return New V5(a, b, c, d)
        End Get
    End Property

    Public ReadOnly Property V6 As V6
        Get
            Return New V5(a, b, c, d)
        End Get
    End Property
End Structure

Structure V5
    ' Constructor accepting 4 Short values '
    ' Properties that expose these values as PGTR, Short, Short'
End Structure

Stucture V6
    ' Constructor similar to V5 above '
    ' Properties that expose these values as Short, Short, Integer'
End Structure
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜