vb.net中的C ++ DLL Wrapper传递字节数组的字节数组?

Posted

技术标签:

【中文标题】vb.net中的C ++ DLL Wrapper传递字节数组的字节数组?【英文标题】:C++ DLL Wrapper in vb.net Passing byte array of a byte array? 【发布时间】:2018-03-04 06:02:37 【问题描述】:

我正在调用一个函数,但我陷入了我必须通过的参数:

这就是我得到的。

函数定义:

DWORD  dllexp_SetLedData(PBYTE bytArray, int arySize)

这来自 SDK:

参数

姓名 |类型 |说明

字节数组 |输入 |指向从 LEDSETTING 转换的字节数组的指针 结构数组。 arySize |输入 |由 byteArray 指示的缓冲区的大小(以字节为单位)。

返回值 价值 |说明

ERROR_SUCCESS(0x0) |成功 ERROR_INVALID_OPERATION(0x10DD) |失败

VB.NET

<DllImport("GLedApi.dll", setLastError:=False, callingConvention:=CallingConvention.Cdecl)> _
Public Shared Function dllexp_SetLedData(bytArray As Byte(), arySize As Int32) As Integer
End Function

C++中LEDSETTING的结构

typedef struct tagLedSettingData 
   BYTE Reserve0;
   BYTE Mode_Sel;           //LED Mode
   BYTE MaxBrightness;      //default set to 100
   BYTE MinBrightness;      //defautl set to 0
   DWORD dwColor;          //0xWWRRGGBB, WW:0 -> WLED turn off, WW:0xFF -> WLED turn on
   WORD wTime_base0;      //light on time, in millisecond
   WORD wTime_base1;      //Interval time, in millisecond
   WORD wTime_base2;      //Cycle time, light on + light off <= Cycle time, this for Flash mode only
   BYTE CtrlVal0;
   BYTE CtrlVal1;
    LedSettingData, *LedSettingData_Ptr;

我在 vb.net 中编写的结构

Public Structure GLEDSETTINGS
    Public Sub New(LedMod1 As ModeSelOptions, MaxB As Byte, MinB As Byte, dwColor1 As UInteger, aWtime0 As UShort, _
                   awtime1 As UShort, awtime2 As UShort, actrlVal0 As Byte, actrlVal1 As Byte)

        Reserved0 = &H0
        LedMod = LedMod1
        MaxBrightness = MaxB
        MinBrightness = MinB
        dwColor = dwColor1
        wTime0 = aWtime0
        wTime1 = awtime1
        wTime2 = awtime2
        CtrlVal0 = actrlVal0
        CtrlVal1 = actrlVal1

    End Sub

    Private Reserved0 As Byte
    Public LedMod As ModeSelOptions
    Public MaxBrightness As Byte  ' max 100
    Public MinBrightness As Byte
    Public dwColor As UInteger  ' &h0FFFFFF
    Public wTime0 As UShort
    Public wTime1 As UShort
    Public wTime2 As UShort
    Public CtrlVal0 As Byte
    Public CtrlVal1 As Byte

    Public Enum ModeSelOptions As Byte
        Defecto = 0
        Pulse
        Music
        ColorCycle
        Statico
        Flash
        Transition
        DigiModA
        DigiModB
        DigiModC
        DigiModD
        DigiModE
        DigiModF
        DigiModG
        DigiModH
        DigiModi
    End Enum
    Public Enum LedType As Integer
        NA
        A_LED
        D_LED_TYPE1
        D_LED_TYPE2
    End Enum

    Function ToByteArray() As Byte()

        Dim size As Integer = Marshal.SizeOf(Me)
        Dim arr As Byte() = New Byte(size - 1) 
        Dim ptr As IntPtr = Marshal.AllocHGlobal(size)
        Marshal.StructureToPtr(Me, ptr, True)
        Marshal.Copy(ptr, arr, 0, size)
        Marshal.FreeHGlobal(ptr)
        Return arr

    End Function

End Structure

到目前为止,一切都很好,但是......我认为该函数需要一个字节数组的数组......但我不知道如何在 vb.net 中做到这一点。

我唯一能做的就是:

Dim LD(iMaxDivs - 1) As GLEDSETTINGS

    For I = 0 To iMaxDivs - 1
        Dim L As New GLEDSETTINGS(GLEDSETTINGS.ModeSelOptions.Statico, 100, 0, &HFFFF11FFUI, 1000, 100, 0, &H0, &H0)
        LD(I) = L


    Next

    'Dim LDParam(LDTama) As Byte

    Dim LDTbrr As Byte() = LD(0).ToByteArray
    Dim LDTama As Integer = Marshal.SizeOf(LD(0))


    resp3 = GLed.dllexp_SetLedData(LDTbrr, LDTama)
    Debug.WriteLine("SetLedData: " & resp3)
    If resp3 = GLed.ERROR_INVALID_OPERATION Then
        Exit Sub

    End If

我没有收到错误,但是ERROR_INVALID_OPERATION

我将结构转换为字节数组。在我的结构中使用ToByteArray 函数,可以正常工作,但我不能将此数组放入字节数组中,例如:dim Array(10) as Byte() 是不允许的。

我在使用我正在使用的 DLL 的 SDK C++ 示例中看到了这一点。但我无法将其“翻译”到 vb.net。

pSettingData = new LedSettingData[iMaxDivs];
int dLen = iMaxDivs * sizeof(LedSettingData);
//ZeroMemory(pSettingData, dLen);

for (int i = 0; i < iMaxDivs; i++)

    (pSettingData + i)->Mode_Sel = sd.Mode_Sel;
    (pSettingData + i)->MaxBrightness = sd.MaxBrightness;
    (pSettingData + i)->MinBrightness = sd.MinBrightness;
    (pSettingData + i)->dwColor = sd.dwColor;
    (pSettingData + i)->wTime_base0 = sd.wTime_base0;
    (pSettingData + i)->wTime_base1 = sd.wTime_base1;
    (pSettingData + i)->wTime_base2 = sd.wTime_base2;
    (pSettingData + i)->CtrlVal0 = sd.CtrlVal0;
    (pSettingData + i)->CtrlVal1 = sd.CtrlVal1;


pfSetLedData((PBYTE)pSettingData, dLen);

对此有何启示?.. 非常感谢!

【问题讨论】:

奇怪的函数,因为它在正确声明时更容易使用。您可以自行修复,只需声明参数 GLEDSETTING() 而不是 byte()。对于长度参数传递 Marshal.SizeOf(GLEDSETTING.GetType() * yourarr.Length)。你的结构声明看起来不错,所以这应该很容易工作。 你是对的。这也有效。我使用Marshal.SizeOf(LD(0).GetType) * LD.Length 作为第二个参数。看起来还可以。我认为仍然有些东西不合时宜,因为功能有效,但不要将 LED 应用到应该在的地方.. 仍在分析.. 已解决。奇怪的功能。强制我“申请”两次以确保正常运行,但我正在使用您的方法。谢谢。 @HansPassant 【参考方案1】:

你几乎是正确的。 C++ 函数需要 GLEDSETTINGS 数组的字节数组。

要将整个 GLEDSETTINGS 数组转换为字节数组,您必须创建一个新函数并调整您现有的代码以使用整个数组。

为此,我建议创建一个Extension method。在您的项目中添加一个新的Module

Imports System.Runtime.CompilerServices

Public Module Extensions
    <Extension()>
    Public Function ToByteArray(ByVal LedSettings As GLEDSETTINGS()) As Byte()
        Dim StructSize As Integer = Marshal.SizeOf(GetType(GLEDSETTINGS))
        Dim Length As Integer = LedSettings.Length * StructSize 'The total amount of memory that our LedSettings array requires.
        Dim Bytes As Byte() = New Byte(Length - 1) 
        Dim ptr As IntPtr = Marshal.AllocHGlobal(Length) 'Allocate a memory section for our data.

        'Iterate through every GLEDSETTINGS structure and put it in our memory section.
        For i = 0 To LedSettings.Length - 1
            Marshal.StructureToPtr(LedSettings(i), ptr + i * StructSize, True)
        Next

        Marshal.Copy(ptr, Bytes, 0, Length) 'Copy the data from our memory section into our byte array.
        Return Bytes
    End Function
End Module

现在你可以这样称呼它:

Dim LDTbrr As Byte() = LD.ToByteArray()
resp3 = GLed.dllexp_SetLedData(LDTbrr, LDTbrr.Length)

【讨论】:

喜欢 extension 方法。实现这一点的好方法。 我觉得还是有些不正常,因为功能有效,但不要在应有的地方应用 LED ......仍在分析...... 已解决。非常感谢!.,您的回答是我要求的最准确的。 @MickMaister :很高兴我能帮上忙!祝你好运!

以上是关于vb.net中的C ++ DLL Wrapper传递字节数组的字节数组?的主要内容,如果未能解决你的问题,请参考以下文章

VB.net调用VC.net写的DLL出现“当前不会命中断点,还没有为该文档加载任何符号”!!急!急急!!!

C# Dll 注入器、VB.Net Dll 注入器

用C语言如何写DLL动态链接库?VB.net 又如何调用其生成的DLL库?急急急!!!!在线等!!

vb.net如何调用dll(动态链接库)

VB.net编写的dll,供vb6调用时dll中的函数不可见?

从 Visual Studio 2017 中的现有 VB.NET 项目创建 dll