VB.NET中结构体交换值(题目说不清楚,请进来看)

时间:2022-09-21 13:59:49
如定义以下两个结构体

Structure s1
        <VBFixedString(1), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=1)> Public a() As Char
        <VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Public b() As Char
    End Structure

Structure s2
        <VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Public a() As Char
        <VBFixedString(1), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=1)> Public b() As Char
    End Structure


可以看出两个结构体虽然结构不一样,但是里面字符串的内容占用的总字节数相等(都为3),如果我有以下代码
Dim s As s1, t As s2
s.a = "A"
s.b = "BC"

我如何操作才能让
t.a = "AB"
t.b = "C"

这有点类似C里面的MEMCPY函数,VB6只需使用文件做中介即可,但是VB.NET却不知用什么办法好?

9 个解决方案

#1


自己顶一下,过去好几天了,没人回

#2


VB人学的少  我也不会
都4天了 帮你顶一下

#3


用s.a和s.b初始化一个字符串string. 然后调用string.CopyTo函数,可以类似memcpy函数指定拷贝起始位置和拷贝长度。

伪代码如下:

dim szTmp as string=new string(s.a + s.b)
szTmp.copyto(0,t.a,0,2)           '第一个0为从szTmp的第几个字符开始拷贝;t.a为目的字符数组;第二个0是拷贝到目的数组的起始索引;2是拷贝长度
szTmp.copyto(2,t.b,0,1)           '拷贝t.b


我这里没有vb.net,只能写伪代码,楼主自己调试一下试试。

#4


抱歉 VB 的不会,下面的代码是刚写的很热乎 赫赫
虽然是 C# 代码不过类都是一样的,这里是类似 MEMCPY 那种
也可以把这个结构体用二进制流对象写到内存流里,在用B 的类型读取出来
.net 平台下楼主要做的2种方式都是可以实现的,.net 比VC 可能比不了,不过和老 VB 比绝对是类库强大了n被

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication3
{
struct structA
{
[MarshalAs(UnmanagedType.ByValArray,  SizeConst=1)]
public byte[] a; //为了方便这里没有使用 char 抱歉
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] b;
}

struct structB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] a;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] b;
}

static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
structA aTest = new structA();
aTest.a = new byte[] { 0 };
aTest.b = new byte[] { 1, 2 };
int iStructSize = Marshal.SizeOf(aTest);

IntPtr buffer = Marshal.AllocCoTaskMem(iStructSize);
Marshal.StructureToPtr(aTest, buffer, true);

structB btest = (structB)Marshal.PtrToStructure(buffer, typeof(structB)); //这里完成后可以查看 btest 

Marshal.FreeHGlobal(buffer);
}
}
}

#5


结果是
btest.a = {0,1};
btest.b = {2};

#6


AllocCoTaskMem 是对com互相操作用的如果是对VC的api 不要使用这个换一个就在 Marshal 还有其他分配内存的方式

#7


楼主,

可以试试做一个 转换器,在2个类型间转换,因为类型已知了


另一个,方法,你可以用 stream 类的派生类
像是文件的Filestream , 或者 内存的 memorystream
这两个都在 System.IO 命名空间下

#8


大家好,我是楼主
    我用字符串做为结构体的字段是举个例子,实际中可能包含任何类型,包括值类型和引用类型(数组,还有结构体嵌套),所以不能只考虑STRING.

StructureToPtr我用过,但是当结构体中包含引用的情况时,会因为结构体在内存中不连续会导致转换出错.

我把我的代码贴出来,当然还是有问题的,仅供大家参考



Imports System.Runtime.InteropServices


Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _
        (ByVal lpvDest As IntPtr, ByVal lpvSource As IntPtr, ByVal cbCopy As Integer)

Public Sub CopyStruct(ByRef Dst As Object, ByRef Src As Object)
        Dim pSrc, pDst As New IntPtr

        pSrc = Marshal.AllocHGlobal(Marshal.SizeOf(Src))
        pDst = Marshal.AllocHGlobal(Marshal.SizeOf(Dst))
        Marshal.StructureToPtr(Src, pSrc, True)
        CopyMemory(pDst, pSrc, Marshal.SizeOf(Src))
        Dst = Marshal.PtrToStructure(pDst, Dst.GetType())
End Sub



继续期盼大家的帮助!

#9


你这个结构里,有值,有引用, 该怀疑是不是改成类比较好了

^_^,开个玩笑,这么做的话,开销是很大的。

你现在要制作一个副本,同时,还要转换类型,我还是建议你实现一个工厂方法,或者转换类, 来实现这个,
可以做一个,也可以2个,分别是浅复制和深复制,根据你的需求了。

不过这个是在知道结构的情况下(反射也可以不过就复杂了)

#1


自己顶一下,过去好几天了,没人回

#2


VB人学的少  我也不会
都4天了 帮你顶一下

#3


用s.a和s.b初始化一个字符串string. 然后调用string.CopyTo函数,可以类似memcpy函数指定拷贝起始位置和拷贝长度。

伪代码如下:

dim szTmp as string=new string(s.a + s.b)
szTmp.copyto(0,t.a,0,2)           '第一个0为从szTmp的第几个字符开始拷贝;t.a为目的字符数组;第二个0是拷贝到目的数组的起始索引;2是拷贝长度
szTmp.copyto(2,t.b,0,1)           '拷贝t.b


我这里没有vb.net,只能写伪代码,楼主自己调试一下试试。

#4


抱歉 VB 的不会,下面的代码是刚写的很热乎 赫赫
虽然是 C# 代码不过类都是一样的,这里是类似 MEMCPY 那种
也可以把这个结构体用二进制流对象写到内存流里,在用B 的类型读取出来
.net 平台下楼主要做的2种方式都是可以实现的,.net 比VC 可能比不了,不过和老 VB 比绝对是类库强大了n被

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication3
{
struct structA
{
[MarshalAs(UnmanagedType.ByValArray,  SizeConst=1)]
public byte[] a; //为了方便这里没有使用 char 抱歉
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] b;
}

struct structB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] a;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] b;
}

static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
structA aTest = new structA();
aTest.a = new byte[] { 0 };
aTest.b = new byte[] { 1, 2 };
int iStructSize = Marshal.SizeOf(aTest);

IntPtr buffer = Marshal.AllocCoTaskMem(iStructSize);
Marshal.StructureToPtr(aTest, buffer, true);

structB btest = (structB)Marshal.PtrToStructure(buffer, typeof(structB)); //这里完成后可以查看 btest 

Marshal.FreeHGlobal(buffer);
}
}
}

#5


结果是
btest.a = {0,1};
btest.b = {2};

#6


AllocCoTaskMem 是对com互相操作用的如果是对VC的api 不要使用这个换一个就在 Marshal 还有其他分配内存的方式

#7


楼主,

可以试试做一个 转换器,在2个类型间转换,因为类型已知了


另一个,方法,你可以用 stream 类的派生类
像是文件的Filestream , 或者 内存的 memorystream
这两个都在 System.IO 命名空间下

#8


大家好,我是楼主
    我用字符串做为结构体的字段是举个例子,实际中可能包含任何类型,包括值类型和引用类型(数组,还有结构体嵌套),所以不能只考虑STRING.

StructureToPtr我用过,但是当结构体中包含引用的情况时,会因为结构体在内存中不连续会导致转换出错.

我把我的代码贴出来,当然还是有问题的,仅供大家参考



Imports System.Runtime.InteropServices


Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _
        (ByVal lpvDest As IntPtr, ByVal lpvSource As IntPtr, ByVal cbCopy As Integer)

Public Sub CopyStruct(ByRef Dst As Object, ByRef Src As Object)
        Dim pSrc, pDst As New IntPtr

        pSrc = Marshal.AllocHGlobal(Marshal.SizeOf(Src))
        pDst = Marshal.AllocHGlobal(Marshal.SizeOf(Dst))
        Marshal.StructureToPtr(Src, pSrc, True)
        CopyMemory(pDst, pSrc, Marshal.SizeOf(Src))
        Dst = Marshal.PtrToStructure(pDst, Dst.GetType())
End Sub



继续期盼大家的帮助!

#9


你这个结构里,有值,有引用, 该怀疑是不是改成类比较好了

^_^,开个玩笑,这么做的话,开销是很大的。

你现在要制作一个副本,同时,还要转换类型,我还是建议你实现一个工厂方法,或者转换类, 来实现这个,
可以做一个,也可以2个,分别是浅复制和深复制,根据你的需求了。

不过这个是在知道结构的情况下(反射也可以不过就复杂了)