4

In a recent question, Import a VB6 structure into C#, the code contained a fixed-length string similar to this:

Name As String *10

There was some discussion in the question about how to implement a fixed-length string in C#, and I provided a possible method (though I recommended against using fixed-length strings in any form). However, one of the answers mentioned VBFixedStringAttribute, without further explanation and I was intrigued to find out what that was about. However, when I went looking for some information on it, I could find very little on MSDN or even in a Bing search. The question then is "How does one actually use this?"

I could find no C# code examples, and though there was a mimimal example of VB.NET on MSDN, my VB.NET skills are insufficient to figure out what was going on with it so I could translate it to C#.

Can someone provide a little code and explanation of what is going on with VBFixedStringAttribute?

Community
  • 1
  • 1
Cyberherbalist
  • 12,061
  • 17
  • 83
  • 121

4 Answers4

2

I think the important thing to notice from the link VBFixedStringAttribute Class is

The VBFixedStringAttribute is informational and cannot be used to convert a variable length string to a fixed string. The purpose of this attribute is to modify how strings in structures and non-local variables are used by methods or API calls that recognize the VBFixedStringAttribute. Keep in mind that this attribute does not change the actual length of the string itself.

From VB.Net to C#

Structure Person
    Public ID As Integer 
    Public MonthlySalary As Decimal 
    Public LastReviewDate As Long
    <VBFixedString(15)> Public FirstName As String
    <VBFixedString(15)> Public LastName As String
    <VBFixedString(15)> Public Title As String
    <VBFixedString(150)> Public ReviewComments As String 
End Structure

is the same as

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
struct Person
{
    public int ID;
    public decimal MonthlySalary;
    public long LastReviewDate;
    [VBFixedString(15)]
    public string FirstName;
    [VBFixedString(15)]
    public string LastName;
    [VBFixedString(15)]
    public string Title;
    [VBFixedString(150)]
    public string ReviewComments;
}
Adriaan Stander
  • 162,879
  • 31
  • 289
  • 284
2

Any attribute requires code somewhere else that calls GetCustomAttributes() to retrieve it. That code lives in the Microsoft.VisualBasic namespace, the place where the legacy VB6 I/O support methods are located. Specifically the FileSystem.FileGetObject() and FilePutObject() methods which map to the static FileGet and FilePut functions. Using these methods directly from a C# program is not a problem, just add a reference to the Microsoft.VisualBasic assembly.

From the FileGetObject() MSDN Library article:

FileGetObject reads elements of structures as if each were being read individually, except that there is no padding between elements. On disk, a dynamic array in a user-defined type (written with FilePutObject) is prefixed by a descriptor whose length equals 2 plus 8 times the number of dimensions: 2 + 8 * NumberOfDimensions. The record length specified by the RecordLength clause in the FileOpen function must be greater than or equal to the sum of all the bytes required to read the individual elements, including any arrays and their descriptors. The VBFixedStringAttribute Class can be applied to string fields in the structures to indicate the size of string when written to disk.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
2

The VBFixedStringAttribute is nothing special. It is defined like this:

namespace Microsoft.VisualBasic
{
  [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
  public sealed class VBFixedStringAttribute : Attribute
  {
    private int m_Length;

    public int Length
    {
      get
      {
        return this.m_Length;
      }
    }

    public VBFixedStringAttribute(int Length)
    {
       if (Length < 1 || Length > (int) short.MaxValue)
            throw new ArgumentException(Utils.GetResourceString("Invalid_VBFixedString"));
       this.m_Length = Length;
    }
  }
}

The main purpose for using this attribute is for reflection purposes. If you are using reflection and you are searching for a property returning a string, you can check for this attribute to see if its a fixed string and you can call the Length property to get the size. This attribute really does nothing, even in VB.NET.

Icemanind
  • 47,519
  • 50
  • 171
  • 296
1

In order to use language-specific features of VB.NET (like My namespace, or in your case - VBFixedStringAttribute), you have to add reference to Microsoft.VisualBasic.dll

After that, you can simply use it as any other attribute. but remember that this attribute doesn't really affect on the string - like most of the attributes, it's just give information to anyone who is going to use the field that the string should be in specific length. So, keep that in mind. If we already talking about string length and validation, it's recommended to read about code contracts: http://msdn.microsoft.com/en-us/library/dd264808.aspx

Shahar Gvirtz
  • 2,418
  • 1
  • 14
  • 17