1

I am trying to dump data from a C# structure and then loading the data to a VB6 structure. This is the current code: C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;

namespace MarshalTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct myStruct
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
            public string str;
            [MarshalAs(UnmanagedType.I4)]
            public int integer; // VB6 long
            [MarshalAs(UnmanagedType.I2)]
            public Int16 int16; // VB6 Integer
            [MarshalAs(UnmanagedType.I1)]
            public byte b;
            [MarshalAs(UnmanagedType.VariantBool)]
            public bool flag;

        }

        private void button1_Click(object sender, EventArgs e)
        {
            myStruct strc = new myStruct();
            //String.Format("{0,6}", strc.str);
            strc.str = "Abhi";
            strc.integer = 49125071;
            strc.int16 = 0491;
            strc.b = 4;
            strc.flag = true;
            Type outputType = typeof(myStruct).IsEnum ? Enum.GetUnderlyingType(typeof(myStruct)) : typeof(myStruct);

            byte[] bArr = new byte[Marshal.SizeOf(strc)];
            IntPtr ptr = IntPtr.Zero;
            try
            {
                ptr = Marshal.AllocHGlobal(Marshal.SizeOf(strc));
                Marshal.StructureToPtr(strc, ptr, false);
                Marshal.Copy(ptr, bArr, 0, Marshal.SizeOf(strc));
                    
                using (FileStream fs =  File.Create("C:\\users\\abhijeet\\desktop\\data.dat"))
                {
                    fs.Write(bArr, 0, bArr.Length);
                    fs.Close();
                }

                // WM_APP is 0x8000
                //IntPtr retval = SendMessage(m_HostWindow, 0x8000, IntPtr.Zero, ptr);
            }
            finally
            {
                if (ptr != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(ptr, typeof(myStruct));
                    Marshal.FreeHGlobal(ptr);
                }
            }
        }

        private string checkFixedLength(string str, int length)
        {
            if (str.Length > length)
            {
                return str.Substring(0, length); 
            }
            return str;
        }

    }
}

VB6

    Option Explicit
    'Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal ByteLen As Long)
    Private Declare Function GetProcessHeap Lib "kernel32" () As Long
    Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
    Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As                                  Any, Source As Any, ByVal Length As Long)
        str As String
        l As Long
        i As Integer
        b As Byte
        flag As Boolean
    End Type

    Private Sub cmdCommand1_Click()
        Dim t As myType, f As Long
        Dim bArr() As Byte
    
        Debug.Print LenB(t)
   
        ReDim bArr(LenB(t) - 1)
        f = FreeFile
        Open "c:\users\abhijeet\desktop\data.dat" For Binary As #f
        Get #f, , bArr()
        Close #f
    
        Dim ptr As Long, hHeap As Long
        hHeap = GetProcessHeap
        ptr = HeapAlloc(hHeap, 0, LenB(t))
    
        CopyMemory ByVal VarPtr(t), ByVal VarPtr(bArr(0)), LenB(t)
   
        Debug.Print t.str
        Debug.Print t.l
        Debug.Print t.i
        Debug.Print t.b
        Debug.Print t.flag
    End Sub

For some reason the size of the structure always return 16 even though the size constant has been set. Am I missing something for the structure?

Thanks

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
abhijeetviswa
  • 113
  • 3
  • 12
  • 1
    That is some seriously low-level code! Why not use the VB6 native file I/O support, and then in C# add a reference to `Microsoft.VisualBasic` and use `FileOpen`, `FileGet`, `FilePut` etc.? Those .Net features are [designed](http://msdn.microsoft.com/en-us/library/0s9sa1ab.aspx) to allow file interoperability with VB6 programs. E.g. see [this question](http://stackoverflow.com/questions/7290976/vb6-how-are-binary-files-encoded-using-put-statement) – MarkJ Feb 20 '14 at 13:42
  • While I agree with @MarkJ, this isn't always practical if you want to use any other form of IPC. – Deanna Feb 20 '14 at 13:54
  • The only reason I used the C#'s file I/O was for testing purposes. – abhijeetviswa Feb 20 '14 at 14:14

1 Answers1

4

The structure size won't include the string contents unless it is a fixed size and not a pointer.

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=6)]
public string str;

(Note that the documentation for ByValTStr says it differs from Vb6 with null terminators)

On the VB6 side, you'll also want to make it a fixed length string to include the contents inline

str As String * 6
Deanna
  • 23,876
  • 7
  • 71
  • 156
  • I tried it and the size increased but for some reason the sizes of the structure in C# is different from the VB6 by 4bytes. – abhijeetviswa Feb 20 '14 at 13:47
  • VB6 packs on 2 byte boundaries (with some exceptions that I can't remember). As far as I can tell, the structure should be 18 bytes in total (6, 4, 2, 1+1, 4). A pack of 4 would result in 22 bytes (6, 4, 2+2, 1+3, 4). – Deanna Feb 20 '14 at 13:52
  • The pack doesn't result in a change of bytes. – abhijeetviswa Feb 20 '14 at 14:14
  • What sizes does it come out as? What is the raw data written to your data file? – Deanna Feb 20 '14 at 14:20
  • I have made some tests. I'll edit the code above. The sizes now align but the problem is that the string isn't being read properly on the VB6 side! – abhijeetviswa Feb 20 '14 at 14:32
  • I have made some tests. I'll edit the code above. The sizes now align but the problem is that the string isn't being read properly on the VB6 side! And also because the sizes align the first digit from the left is now removed. – abhijeetviswa Feb 20 '14 at 14:38
  • How is it in the data file? First digit of what is missing? Oh, and the `ByValTStr` documentation says it differs from VB6 in a null terminator. – Deanna Feb 20 '14 at 16:08
  • "Abhi Ï–íë ÿÿ " This is the string representation of the data. Soon after the string Abhi there is many null characters which is the problem. – abhijeetviswa Feb 21 '14 at 13:53
  • The problem with ByvalTStr is that it is terminated with a null char which put the length of the structure length of string. VB6 Fixed length string doesn't include the null char at the end. So, if anyone could help me find another string just Like ByValTStr without the null char at the end. – abhijeetviswa Feb 22 '14 at 06:31
  • I couldn't see any other `UnmanagedType` member that would marshal as a fixed length string. Maybe a (ansi) char array? – Deanna Feb 22 '14 at 10:02
  • I tried using a char array but the sizes are offsynced. Should I use the char array on the VB6 side as well? – abhijeetviswa Feb 22 '14 at 11:43