【问题标题】:Convert vb6 Type to VB.net or C# Struct将 vb6 类型转换为 VB.net 或 C# Struct
【发布时间】:2023-04-02 22:40:02
【问题描述】:

我正在将最初用 vb6 编写的应用程序转换为 vb.net。该应用程序所做的其中一件事是将“类型”对象发送到 dll。我尝试将类型转换为结构并 p/调用 dll,但它似乎不起作用。我已经被困了一个星期了,任何帮助都将不胜感激

这是该类型的 vb6 代码

'Define WICS Communications Control Block (CCB).
Type WicsCCBType ' Create user-defined type.
    CCBNum As String * 1
    CCBVer As String * 1
    Resp1  As String * 4
    Resp2  As String * 4
    PLUA   As String * 8
    LLUA   As String * 8
    Mode   As String * 8
    ReqMax As String * 5
    ResMax As String * 5
End Type      

下面是调用 dll 的方式

Private Declare Sub WICSRASP Lib "wicsrasp.dll" (MyWicsCCB As WicsCCBType)
WICSRASP MyWicsCCB

这是我在 vb.net 上尝试过的,但它不起作用

'Define WICS Communications Control Block (CCB).
    <System.Runtime.InteropServices.StructLayoutAttribute( _
            System.Runtime.InteropServices.LayoutKind.Sequential, _
            CharSet:=System.Runtime.InteropServices.CharSet.[Unicode])> _
    Structure WicsCCBType ' Create user-defined type.
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=1)> Dim CCBNum As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=1)> Dim CCBVer As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=4)> Dim Resp1 As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=4)> Dim Resp2 As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=8)> Dim PLUA As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=8)> Dim LLUA As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=8)> Dim Mode As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=5)> Dim ReqMax As String
        <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=5)> Dim ResMax As String
    End Structure

这就是我试图称呼它的地方

<System.Runtime.InteropServices.DllImportAttribute("C:\windows\system32\wicsrasp.dll")> _
    Public Shared Sub WICSRASP(
                    ByRef CCB As WicsCCBType,
                    ByRef Request As DAWicsRequestType,
                    ByRef Response As DAWicsResponseType)
    End Sub

 Dim CCB As New modWICSDiary.WicsCCBType()
 CCB.CCBNum = "B"
            CCB.CCBVer = "2"
            CCB.LLUA = "        "
            CCB.Mode = "CICSMO2 "
            CCB.ReqMax = "2100 "
            CCB.ResMax = "2100 "
            CCB.Resp1 = "0   "
            CCB.Resp2 = "0   "
            CCB.PLUA = "WICSPLU "

  NativeMethods.WICSRASP(CCB)

对于值,相同的值适用于 vb6 类型

再次提前感谢您

【问题讨论】:

  • 你需要更加努力。提供它是如何失败的。
  • 老实说,您不应该尝试创建 .NET 版本的 VB6 结构,而应该创建传递给 WICSRASP 的 C 数据结构的 .NET 版本。如果您有该文档(例如头文件),那么这会更容易。

标签: c# .net vb.net vb6


【解决方案1】:

我不知道 OP 是否已经解决了这个问题,但这是我的看法。

VB6 中 UDT 内的固定长度字符串不作为指针编组,而是内联到结构中。此外,VB6 在编组之前将 Unicode 转换为 Ansi。而VB6使用4字节对齐。

该类型将在内存中使用填充看起来这个,每个连续的字段在插图中命名为 A 到 I,并且由于对齐,_ 是一个填充字节。

CCBNum As String * 1     
|
|+-CCBVer As String * 1     
||
||  Resp1  As String * 4
||  |
||  |   Resp2  As String * 4     
||  |   |
||  |   |   PLUA   As String * 8     
||  |   |   |
||  |   |   |       LLUA   As String * 8     
||  |   |   |       |
||  |   |   |       |       Mode   As String * 8     
||  |   |   |       |       |
||  |   |   |       |       |       ReqMax As String * 5     
||  |   |   |       |       |       |
||  |   |   |       |       |       |       ResMax As String * 5 
||  |   |   |       |       |       |       |
||  |   |   |       |       |       |       |
VV  V   V   V       V       V       V       V

AB__CCCCDDDDEEEEEEEEFFFFFFFFGGGGGGGGHHHHH___IIIII___

因此 CharSet 应该是 Ansi,StructAlignment 应该是 4。使用 ByValTString 很好,使用 SizeConst 也是如此。

【讨论】:

    【解决方案2】:

    VB6 会将所有这些字符串元素“编组”为 ANSI 字符串。相应地更改 Vb.Net 编组代码。

    • 在那些MarshalAs 属性中尝试UnmanagedType.LPStr
    • 尝试将 CharSet 从 Unicode 更改为 Ansi?
    • StructLayoutAttribute 中尝试Pack=4

    解释 VB6 Declare 所做假设的有用链接

    【讨论】:

    • 当我尝试得到一个异常(当我调用 dll 方法时)“尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”
    • 我想我在您发布该评论时正在编辑答案!您是否也尝试过更改字符集?
    • 尝试在您的StructLayoutAttribute 中包含Pack=4
    • 我做了所有 3 项更改,但我仍然收到“尝试读取或写入受保护的内存。这通常表明其他内存已损坏”错误
    • @user889829 结构中的固定长度字符串不会编组为指向缓冲区的指针,而是作为连续内存块的一部分内联。您的原始代码更接近,但 VB6 会使用 Ansi 字符串,并且可能还会进行 4 字节对齐。
    【解决方案3】:

    VB6 使用了 BSTR,不是吗?你不应该编组为 BSTR 吗?

    【讨论】:

    • 没有。 VB6 在使用 Declare 调用 DLL 时将 Unicode 转换为 ANSI。 vb.mvps.org/tips/vb5dll.asp
    • 刚刚查阅了 Dan Appleman 的“Moving to VB.NET”。他说:“几乎在所有调用带字符串参数的 Win32 API 函数的情况下,您都会将字符串 ByVal 声明为字符串……VB.NET 在 Declare 语句中拉得很快……换句话说,这是VB.NET 保持与 VB6 语法兼容的地方。”
    • 总结他更详细的解释,显然 VB.NET 在传递之前复制了字符串,即使你已经声明了 ByVal。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-01
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    相关资源
    最近更新 更多