Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upgrading C code to VB.NET - Unioned Structures

Tags:

c

vb.net

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;    // 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!

like image 329
Wolfmarsh Avatar asked Mar 22 '26 16:03

Wolfmarsh


1 Answers

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.

like image 166
Adam Robinson Avatar answered Mar 25 '26 06:03

Adam Robinson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!