BUG: The ByValTStr attribute is incorrectly applied to the fixed-length string member when you upgrade a Visual Basic 6.0 project to a Visual Basic .NET project (834056)



The information in this article applies to:

  • Microsoft Visual Studio .NET (2003), Professional Edition
  • Microsoft Visual Studio .NET (2003), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2003), Enterprise Developer Edition
  • Microsoft Visual Studio .NET (2003), Academic Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Developer Edition
  • Microsoft Visual Studio .NET (2002), Professional Edition
  • Microsoft Visual Studio .NET (2002), Academic Edition

Microsoft Visual Studio .NET changes the ByValTStr attribute to ByValArray when you upgrade a Microsoft Visual Basic 6.0 project to a Microsoft Visual Basic .NET project. The ByValTStr attribute is incorrectly applied in Visual Basic .NET.

SYMPTOMS

When you upgrade a Visual Basic 6.0 project application that passes a structure to an API to a Visual Basic .NET project application, the ByValTStr attribute is incorrectly applied to the fixed-length string member.

CAUSE

This bug occurs because the ByValTStr attribute in Visual Basic .NET is incorrectly applied after you upgrade your project application from Visual Basic 6.0 to Visual Basic .NET. The size of the fixed-length string member of the string buffer that is marshaled includes the NULL termination character.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.

MORE INFORMATION

When you upgrade Visual Basic 6.0 to Visual Basic .NET, Microsoft Visual Studio .NET produces the following two changes in the Visual Basic .NET code:
  • Visual Studio .NET changes the ByValTStr attribute to ByValArray.
  • Visual Studio .NET changes the MyString type from the String data type to a Char data type array.
The following code exists in the Visual Basic .NET Module1.vb file:
Option Strict Off
Option Explicit On
Module Module1
Private Structure MyStruct
 <VBFixedString(5), _
 System.Runtime.InteropServices.MarshalAs _
 (System.Runtime.InteropServices.UnmanagedType.ByValArray, _
 SizeConst:=5)> Public MyString() As Char
End Structure
'UPGRADE_WARNING: Structure MyStruct may require marshaling 
'attributes to be passed as an argument in this Declare statement. 
'Click for more: 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="vbup1050"'
Private Declare Sub TestStructByRef Lib "C:\Test\StructTest.dll" (ByRef ms As MyStruct)
'UPGRADE_WARNING: Application will quit when Sub Main() finishes. 
'Click for more: 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="vbup1047"'
  Public Sub Main()
    Dim ms As MyStruct
    ms.MyString = "12345"
    TestStructByRef(ms)
    MsgBox(ms.MyString)
  End Sub
End Module
Note In this code, Test is a placeholder for a folder in your local hard disk drive.

The potential issues with the changes that occur when you upgrade Visual Basic 6.0 to Visual Basic .NET are the following:
  • You must set the MyString value to exactly five characters in length when MyString is passed to the API function that accepts the structure. You must do this because the SizeConst field value is set to five characters in length.
  • A Component Object Model (COM) exception occurs if the size of the Char data type array does not match the SizeConst field value when the MyString value is set to less than five characters in length.

    To avoid the COM exception, replace this code
    MyStruct.MyString = "123"
    with the following code:
    MyStruct.MyString = "123  "
    Notice that there are two spaces after the string value 123 to make it five characters in length. Therefore, the string value matches the SizeConst field value.

Steps to reproduce the behavior

  1. Create a DLL, as follows:
    1. Start Visual Studio .NET.
    2. On the File menu, point to New, and then click Project.

      The New Project dialog box appears.
    3. Under Project Types, click Visual C++ Projects.
    4. Under Templates, click Win32 Project.
    5. In the Location box, type C:\MyFolder.

      Note In this step, MyFolder is a placeholder for the name of the folder where you want to save your application.
    6. In the Name box, type StructTest as the name of your application, and then click OK.

      The Win32 Application Wizard - StructTest dialog box appears.
    7. In the Win32 Application Wizard - StructTest dialog box, click Application Settings.
    8. In the Application Settings section, click DLL under Application type.
    9. Under Additional options, click to select the Empty Project check box. Click Finish.
    10. In the Solution Explorer pane, right-click Source Files, point to Add, and then click Add New Item.

      The Add New Item - StructTest dialog box appears.
    11. Under Templates, click C++ File (.cpp).
    12. In the Name box, type StructTest, and then click Open.
    13. Add the following code to the StructTest.cpp file:
      #include <windows.h>
      
      struct MyStruct
      {
      	char MyString[5];
      };
      
      BOOL WINAPI DllMain(
        HINSTANCE hinstDLL,  // handle to DLL module
        DWORD fdwReason,     // reason for calling function
        LPVOID lpvReserved   // reserved
      )
      {
      	return TRUE;
      }
      
      void __declspec(dllexport) __stdcall TestStructByRef(MyStruct *inObj)
      {
      	MyStruct *ms1 = (MyStruct*)inObj;
      }
      
      void __declspec(dllexport) __stdcall TestStructByVal(MyStruct inObj)
      {
      	MyStruct ms1 = inObj;
      }
    14. In the Solution Explorer pane, right-click Source Files, point to Add, and then click Add New Item.

      The Add New Item - StructTest dialog box appears.
    15. Under Templates, click Module-Definition File (.def).
    16. In the Name box, type StructTest, and then click Open.
    17. Replace the code in the StructTest.def file with the following code:
      LIBRARY	StructTest
      
      EXPORTS
      
      	TestStructByRef
      	TestStructByVal
      
    18. On the Build menu, click Build Solution.

      The StructTest.dll file is created in the C:\MyFolder\Debug folder.

      Note In this step, MyFolder is a placeholder for the name of your folder.
  2. Add the DLL that you created in step 1 to the project application, as follows:
    1. Start Visual Basic 6.0.
    2. Create a Standard EXE project.

      By default, the Form1 form is added to your project.
    3. In Project Explorer, right-click the project, point to Add, and then click Module.

      The Add Module dialog box appears.
    4. Click the New tab, click Module, and then click Open.
    5. Add the following code to the Module1.bas file:
      Private Type MyStruct
          MyString As String * 5
      End Type
      
      Private Declare Sub TestStructByRef Lib "C:\Test\StructTest.dll"" (ByRef ms As MyStruct)
      
      Sub Main()
          Dim ms As MyStruct
          ms.MyString = "12345"
          TestStructByRef ms
          MsgBox ms.MyString
      End Sub
      Note In this step, Test is a placeholder for the path of the DLL that you created in step 1.
    6. On the File menu, click Save Project As.

      The Save Project As dialog box appears.
    7. In the File name box, type TestStructTest.
    8. Copy the StructTest.dll file that you built in step 1 to the Test folder.

      Note In this step, Test is a placeholder for a folder on your local hard disk drive.
    9. On the Project menu, click Project1 Properties.
    10. In the Project1 - Project Properties dialog box, click the General tab, set the value of the Startup Object box to Sub Main, and then click OK.
    11. On the Run menu, click Start.

      You receive a message with a value of 12345.
  3. In Visual Studio .NET, open the Visual Basic 6.0 project that you created in step 2, as follows:
    1. Start Visual Studio .NET.
    2. On the File menu, point to Open, and then click Project.

      The Open Project dialog box appears.
    3. In the Open Project dialog box, click the TestStructTest.vbp project file that you created in step 2, and then click Open.

      The Visual Basic Upgrade Wizard - Page 1 of 5 dialog box appears.
    4. In the Visual Basic Upgrade Wizard - Page 1 of 5 dialog box, click Next.

      The Visual Basic Upgrade Wizard - Page 2 of 5 dialog box appears.
    5. In the Visual Basic Upgrade Wizard - Page 2 of 5 dialog box, click EXE, and then click Next.

      The Visual Basic Upgrade Wizard - Page 3 of 5 dialog box appears.
    6. In the Visual Basic Upgrade Wizard - Page 3 of 5 dialog box, type C:\Test\DotNetProject in the Where do you want your new project created box, and then click Next.

      The Visual Basic Upgrade Wizard - Page 4 of 5 dialog box appears.

      If the DotNetProject folder does not exist in the Test folder, create the DotNetProject folder.

      Note In this step, Test is a placeholder for a folder in your local hard disk drive.
    7. In the Visual Basic Upgrade Wizard - Page 4 of 5 dialog box, click Next.

      The Visual Basic Upgrade Wizard - Page 5 of 5 dialog box appears.
    8. Upgrade your project.

      The Visual Basic Upgrade Wizard- Page 5 of 5 dialog box closes after you upgrade your project from Visual Basic 6.0 to Visual Studio .NET.
    9. In the Solution Explorer pane, double-click the Module1.vb file. Notice the following code:
      Option Strict Off
      Option Explicit On
      Module Module1
      Private Structure MyStruct
      <VBFixedString(5),System.Runtime.InteropServices.MarshalAs _
      (System.Runtime.InteropServices.UnmanagedType.ByValTStr,SizeConst:=5)> Public MyString As String
      End Structure
      
      'UPGRADE_WARNING: Structure MyStruct may require marshaling attributes to be passed as an 
      'argument in this Declare statement. Click for more: 
      'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="vbup1050"'
      Private Declare Sub TestStructByRef Lib "C:\Test\StructTest.dll" (ByRef ms As MyStruct)
       'UPGRADE_WARNING: Application will quit when Sub Main() finishes. Click for more: 
       'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="vbup1047"'
       Public Sub Main()
        Dim ms As MyStruct
        ms.MyString = "12345"
        TestStructByRef(ms)
        MsgBox(ms.MyString)
       End Sub
      End Module
      
      Note In this code, Test is a placeholder for a folder in your local hard disk drive.
    10. Save the Visual Studio .NET project to the C:\Test\DotNetProject folder.

      Note In this step, Test is a placeholder for a folder in your local hard disk drive.
    11. On the Project menu, click TestStructTest Properties.
    12. In the General section of the TestStructTest Property Pages dialog box, set the value of the Startup object box to Sub Main under Common Properties.
    13. On the Debug menu, click Start.

      You receive a message with a value of 1234.

REFERENCES

For more information, visit the following Microsoft Web sites:

Preparing your Visual Basic 6.0 applications for the upgrade to Visual Basic .NET
http://msdn.microsoft.com/library/en-us/dnvb600/html/vb6tovbdotnet.asp


Modification Type:MinorLast Reviewed:2/1/2006
Keywords:kbvs2005swept kbvs2005doesnotapply kbvs2002sp1sweep kbString kbDLL kbMarshal kbbug KB834056 kbAudDeveloper