【问题标题】:C# Structs to VB6 and vice versaC# Structs 到 VB6,反之亦然
【发布时间】:2014-03-21 00:40:20
【问题描述】:

我正在尝试从 C# 结构中转储数据,然后将数据加载到 VB6 结构中。 这是当前代码: 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 作为字符串 l 只要 i 作为整数 b 作为字节 标记为布尔值 结束类型

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

由于某种原因,结构的大小总是返回 16,即使已经设置了大小常量。我错过了结构的东西吗?

谢谢

【问题讨论】:

  • 那是一些严重的低级代码!为什么不使用 VB6 原生文件 I/O 支持,然后在 C# 中添加对Microsoft.VisualBasic 的引用并使用FileOpenFileGetFilePut 等?这些 .Net 功能是designed,以允许与 VB6 程序进行文件互操作。例如。见this question
  • 虽然我同意@MarkJ,但如果您想使用任何其他形式的 IPC,这并不总是可行的。
  • 我使用 C# 的文件 I/O 的唯一原因是为了测试目的。

标签: c# vb6 marshalling


【解决方案1】:

结构大小不包括字符串内容,除非它是固定大小而不是指针。

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

(请注意,documentation for ByValTStr 表示它与带有空终止符的 Vb6 不同)

在 VB6 方面,您还需要将其设为固定长度的字符串以包含内联内容

str As String * 6

【讨论】:

  • 我试过了,大小增加了,但由于某种原因,C# 中结构的大小与 VB6 相差 4 个字节。
  • VB6 打包在 2 字节边界上(有一些我不记得的例外情况)。据我所知,该结构总共应为 18 个字节(6、4、2、1+1、4)。一包 4 将产生 22 个字节(6、4、2+2、1+3、4)。
  • 打包不会导致字节变化。
  • 它的尺寸是多少?写入数据文件的原始数据是什么?
  • 我做了一些测试。我将编辑上面的代码。大小现在对齐,但问题是在 VB6 端没有正确读取字符串!
猜你喜欢
  • 2012-06-27
  • 1970-01-01
  • 2014-11-08
  • 2012-02-16
  • 2013-08-16
  • 2017-02-05
  • 2012-12-01
  • 2012-02-05
  • 1970-01-01
相关资源
最近更新 更多