【问题标题】:How do I successfully work with structures and nested structures within a cpp dll in VB.NET/C#?如何在 VB.NET/C# 的 cpp dll 中成功使用结构和嵌套结构?
【发布时间】:2023-03-17 17:10:01
【问题描述】:

我想调用一个需要结构的 DLL 函数,并且在该结构中是另一个结构。 Dll 应该将值返回给我的结构,但我只得到错误代码。有一次(以前的一些编码)我在函数调用中成功返回“True”,但我的结构中没有值。

我对编组等不是很熟悉,但如果有人可以请给我一个关于如何做到这一点的例子!

DLL 代码如下所示:


bXaarScorpionGetPrintDataParametersUpdated(struct UpdatedPrintDataParameters &DataParams);

第一个结构:

struct UpdatedPrintDataParameters
{
struct PrintDataParameters OriginalParameters;
DWORD RowTrailChannels[MAXROWS];        // The number of unused channels at end of print head per row
DWORD RowLeadChannels[MAXROWS];         // The number of unused channels at start of print head per row
DWORD CopyCount[MAXROWS];               // The number of repeated copies
DWORD XPMSEPDSetup[4];                  // XPM - bits to control shaft encoder and product detect configuration 
DWORD PDFilter;                         // XPM - Product Detect Filter, pass value through
DWORD Spare[13];                        // Spare

这是第二个结构:

struct PrintDataParameters
{
// Head Setup parameters
DWORD Head;                             // This printhead number
DWORD HeadType;                         // Code indicating type of printhead connected
DWORD HeadIndex[MAXROWS];               // The index of the printhead in the array of actually connected printhead
DWORD NumberOfRows;                     // The number of rows on the printhead
DWORD SeparateRows;                     // If true, treat each row as an individual head
DWORD ImageLength[MAXROWS];             // The number of strokes in an image
DWORD ImageSize[MAXROWS];               // The number of bytes in an image
DWORD ProductOffset;                    // Number of strokes of Offset after the product and before the print starts
DWORD InterGap;                         // Gap used between continuous prints
DWORD FirstSwatheBlock;                 // The memory address where 1st swathe control block is stored
DWORD SwatheBlock;                      // The memory address to store this particular swathe control block
DWORD ThisSwathe;                       // The number of the active swathe
DWORD NextSwatheBlock;                  // The memory address where the next swathe block will be stored
DWORD MemoryBlock[MAXROWS];             // The memory address to store this image block
DWORD FirstMemoryBlock[MAXROWS];        // The memory address where 1st image swathe is stored
DWORD MemoryBlocksNeeded[MAXROWS];      // The number of memory blocks needed to store the image swathe
DWORD PreLoadSwatheBlock;               // The number of memory blocks that the pre-load strokes requires
DWORD PrintMode;                        // The print mode e.g. single shot etc.
bool  PrintOnce;                        // If true only one complete print is required
DWORD CycleMode;                        // Cycle Mode (e.g. set to PIXELMODE, CYCLEMODE)
bool ForwardBuffer;                     // Print direction i.e. forward or reverse
DWORD StartDir[MAXROWS];                // The starting head direction bit for each row 
DWORD DirBlock;                         // The direction to use for this swathe

// System setup parameters
DWORD SubPixelDivide;                   // The subpixel divide value
DWORD SaveSubPixelOffset[2][MAXROWS];   // The subpixeloffsets to use, 1st index is for forward or reverse offsets, 2nd index = row
DWORD SubPixelOffset;                   // The sub pixel offset to use for this swathe
DWORD EncoderDivide;                    // A copy of the encoder divide

// Image control parameters
DWORD TrailChannels;                    // The number of unused channels at end of print head - same value currently used for both rows, max 31
DWORD LeadChannels;                     // The number of unused channels at start of print head - same value currently used for both rows, max 31
DWORD DataChannels;                     // The total number of printing channels
DWORD HeadChannels;                     // The number of printing channels per side
bool BufferReverse[MAXROWS];            // The direction to read the data from the image buffer eg for 760, [0] = true, [1] = false
DWORD NibbleControl[MAXROWS];           // For each row defines if the even/odd/both nibbles of image data is used for printing
DWORD NibbleIndex;                      // Used to defines if we are using row 1 or row 2
DWORD LoopCount;                        // Set this to 1

LPSTR lpDIBBits;                        // Pointer to the bitmap in (screen) memory
DWORD TotalImageWidth[MAXROWS];         // The total width of the image
DWORD BitDifference;                    // The number of bits to store .... this needs to be set to 4

// Swathe control parameters
DWORD NumberSwathes[MAXROWS];           // The number of swathes to print entire image
DWORD SwatheMemoryCount[MAXROWS];       // The total number of swathes that will fit into memory for this head
DWORD StoredSwathes[MAXROWS];           // The total number of swathes that have been stored to the XUSB box
DWORD PreviousPrintSwathe[MAXROWS];     // The number of the previous swathe that was stored
bool AllSwathesFit[MAXROWS];            // True if all the swathes fit in memory at once
bool Binary;                            // True if binary or false if greyscale head?
DWORD GreyLevel;                        // The number of grey levels
bool FirstSwathe[MAXROWS];              // This should be set to true for each row for the 1st swathe of a print (doesn't need to be set again for repeat print swathes)
bool LastSwathe[MAXROWS];               // This should be set for last swathe - specifies if the image is only required to be printed once
bool LastSwatheInMemory[MAXROWS];       // This indicates that this swathe is at the end of the swathe memory
DWORD SendID[MAXROWS];                  // Id of the swathe that has been setup for sending to xusb box
bool BiPrintKeepOdd;                    // Defines if, when in bi-directional printing the number of swathes are rounded up

// These 2 values are used when a print head is only required to print part of an image
DWORD SwatheStartIndex;                 // The offset into the swathe to start printing from
DWORD SwatheIncrement;                  // The amount to add to locate the next swathe

DWORD SourceStrokeWidth;                // The number of blocks required for each image stroke

// print parameters
DWORD PrintTransportMode;               // Used to determine if bi-directional printing is required
bool bReverseSwatheOrder;               // Define if the 1st or last swathe should be printed first
bool bReverseImageOrder;                // Specify if the 1st or last stroke of the image is printed first
bool bPaletteRemap;                     // True if palette remap required
bool bBinaryBackgroundInvert;           // Invert the background for a binary image
DWORD SaveProductOffset[2][MAXROWS];    // 1st index if to forward or reverse offsets
bool bSelectHead[MAXROWS];              // This printhead is selected for print

DWORD GuardValue;                       // Set guard channels to this value

DWORD SEPDSetup;                        // Bits to control SE and PD configuration. Effectively the ID of the shaftencoder/product detect pair
bool Enable2Bit;                        // True if 2 bit mode is enabled
BYTE SysClock;                          // Encoder mode i.e. Internal, external or absolute
BYTE VLDPHCount;                        // The number of 16 nozzle VLDPH print units
BYTE Spare;                             // Spare

我的 VB.Net 声明如下所示:

  <DllImport("ScorpionDLL.dll", CallingConvention:=CallingConvention.StdCall)>
Public Shared Function bXaarScorpionGetPrintDataParametersUpdated(ByRef UDataParams As UpdatedPrintDataParameters) As IntPtr
End Function

第一个结构:

   <System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Public Structure UpdatedPrintDataParameters

    '''PrintDataParameters
    Public OriginalParameters As PrintDataParameters

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public RowTrailChannels() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public RowLeadChannels() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public CopyCount() As UInteger

    '''DWORD[4]
    <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=4, ArraySubType:=System.Runtime.InteropServices.UnmanagedType.U4)>
    Public XPMSEPDSetup() As UInteger

    '''DWORD->unsigned int
    Public PDFilter As UInteger

    '''DWORD[13]
    <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=13, ArraySubType:=System.Runtime.InteropServices.UnmanagedType.U4)>
    Public Spare() As UInteger
    '7
End Structure

第二个结构

<System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet:=CharSet.Auto, Size:=66)>
Public Structure PrintDataParameters
    '''DWORD->unsigned int
    Public Head As UInteger

    '''DWORD->unsigned int
    Public HeadType As UInteger

    '''DWORD[]
    <MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst:=2)> Public HeadIndex() As UInteger

    '''DWORD->unsigned int
    Public NumberOfRows As UInteger

    '''DWORD->unsigned int
    Public SeparateRows As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public ImageLength() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public ImageSize() As UInteger

    '''DWORD->unsigned int
    Public ProductOffset As UInteger

    '''DWORD->unsigned int
    Public InterGap As UInteger

    '''DWORD->unsigned int
    Public FirstSwatheBlock As UInteger

    '''DWORD->unsigned int
    Public SwatheBlock As UInteger

    '''DWORD->unsigned int
    Public ThisSwathe As UInteger

    '''DWORD->unsigned int
    Public NextSwatheBlock As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public MemoryBlock() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public FirstMemoryBlock() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public MemoryBlocksNeeded() As UInteger

    '''DWORD->unsigned int
    Public PreLoadSwatheBlock As UInteger

    '''DWORD->unsigned int
    Public PrintMode As UInteger

    '''boolean
    <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.I1)>
    Public PrintOnce As Boolean

    '''DWORD->unsigned int
    Public CycleMode As UInteger

    '''boolean
    <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.I1)>
    Public ForwardBuffer As Boolean

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public StartDir() As UInteger

    '''DWORD->unsigned int
    Public DirBlock As UInteger

    '''DWORD->unsigned int
    Public SubPixelDivide As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public SaveSubPixelOffset(,) As UInteger

    '''DWORD->unsigned int
    Public SubPixelOffset As UInteger

    '''DWORD->unsigned int
    Public EncoderDivide As UInteger

    '''DWORD->unsigned int
    Public TrailChannels As UInteger

    '''DWORD->unsigned int
    Public LeadChannels As UInteger

    '''DWORD->unsigned int
    Public DataChannels As UInteger

    '''DWORD->unsigned int
    Public HeadChannels As UInteger

    '''boolean[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public BufferReverse() As Boolean

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public NibbleControl() As UInteger

    '''DWORD->unsigned int
    Public NibbleIndex As UInteger

    '''DWORD->unsigned int
    Public LoopCount As UInteger

    '''LPSTR->CHAR*
    <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)>
    Public lpDIBBits As String

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public TotalImageWidth() As UInteger

    '''DWORD->unsigned int
    Public BitDifference As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public NumberSwathes() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public SwatheMemoryCount() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public StoredSwathes() As UInteger

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public PreviousPrintSwathe() As UInteger

    '''boolean[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public AllSwathesFit() As Boolean

    '''boolean
    Public Binary As Boolean

    '''DWORD->unsigned int
    Public GreyLevel As UInteger

    '''boolean[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public FirstSwathe() As Boolean

    '''boolean[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public LastSwathe() As Boolean

    '''boolean[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public LastSwatheInMemory() As Boolean

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public SendID() As UInteger

    '''boolean
    Public BiPrintKeepOdd As Boolean

    '''DWORD->unsigned int
    Public SwatheStartIndex As UInteger

    '''DWORD->unsigned int
    Public SwatheIncrement As UInteger

    '''DWORD->unsigned int
    Public SourceStrokeWidth As UInteger

    '''DWORD->unsigned int
    Public PrintTransportMode As UInteger

    '''boolean
    Public bReverseSwatheOrder As Boolean

    '''boolean
    Public bReverseImageOrder As Boolean

    '''boolean
    Public bPaletteRemap As Boolean

    '''boolean
    Public bBinaryBackgroundInvert As Boolean

    '''DWORD[]
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Public SaveProductOffset(,) As UInteger

    '''boolean[]
    Public bSelectHead() As Boolean

    '''DWORD->unsigned int
    Public GuardValue As UInteger

    '''DWORD->unsigned int
    Public SEPDSetup As UInteger

    '''boolean
    Public Enable2Bit As Boolean

    '''BYTE->unsigned char
    Public SysClock As Byte

    '''BYTE->unsigned char
    Public VLDPHCount As Byte

    '''BYTE->unsigned char
    Public Spare As Byte
    '66
End Structure

【问题讨论】:

  • 请提供简洁代码以附上您的问题
  • 我向丹尼尔道歉,我对这个话题一无所知。我想调用我的 api 函数,但我不知道如何“准备”它......如您所见,我已经根据 Dll 在 VB.net 端设置了我的结构,但我只是不知道从这里去哪里......
  • MAXROWS 的值是多少?如果您提供,我们可以尽最大努力猜测 VB.NET 代码。我们还需要 Hans 要求的 sizeof 结果,因为这将提供包装信息。
  • MAXROWS 的值为 2 @hoodaticus。 UpdatedPrintDataParameters 的大小是 408,PrintDataParameters 是 312。

标签: c# vb.net dll structure marshalling


【解决方案1】:

...它们都是“0”...这可能是什么原因?

你得到的答案没有帮助。实际上,您确实需要 &lt;Out&gt; 属性,由于数组和布尔成员,该结构不是“可blittable”的。一百美元的单词意味着 pinvoke marshaller 不能只传递指向托管变量的指针,因为非托管布局与托管布局不同。默认情况下,pinvoke marshaller 不会复制回结构,需要 OutAttribute 来改变主意。

您是否也需要&lt;[In]&gt; 属性并不明显。可能不会,但包含它不会有太大的伤害,反正这段代码不会很快。

&lt;System.Runtime.InteropServices.StructLayoutAttribute(..., Size:=66)&gt;

这是一个怪物结构,您的 VB.NET 声明与 C 声明完全不匹配。它的大小甚至远不接近 66 字节。不仅大小必须匹配,字段在 C++ 和 VB.NET 代码中的偏移量也必须相同。如果存在不匹配,则 C 代码可能会随机失败并出现 AccessViolationException,并且编组器注定将数据复制到完全错误的字段中。我将描述一个查找错误的通用故障排除策略。

您需要编写一个小型 C++ 程序,使用 sizeof 运算符测量结构的大小。它的值需要与Marshal.SizeOf() 的返回值精确 匹配。如果它不匹配,则它永远无法正确编组。通过使用 C++ 中的 offsetof 宏和 VB.NET 中的 Marshal.OffsetOf() 方法,您可以找到错误的声明。

一些示例代码可以开始。先上C++代码:

#include "stdafx.h"
#include <stdlib.h>
#include <Windows.h>
#define MAXROWS 2

struct PrintDataParameters
{
   // etc..
};

int main()
{
    auto len = sizeof(PrintDataParameters);
    auto ofs = offsetof(PrintDataParameters, SubPixelOffset);
    return 0;   // Set a breakpoint here, inspect len and ofs
}

以及等效的 VB.NET 代码:

Imports System.Runtime.InteropServices

Module Module1

    Sub Main()
        Dim len = Marshal.SizeOf(GetType(PrintDataParameters))
        Dim ofs = Marshal.OffsetOf(GetType(PrintDataParameters), "SubPixelOffset")
        Console.ReadLine()    '' Set breakpoint here, inspect len and ofs
End Sub

    <StructLayoutAttribute(LayoutKind.Sequential, CharSet:=CharSet.Ansi)>
    Public Structure PrintDataParameters
       '' etc...
    End Structure
End Module

按原样运行此代码,C++ 程序将报告 312 字节的长度和 140 的 SubPixelOffset 字段的偏移量。VB.NET 程序报告 339 和 132。差别很大,有多个错误,它永远不会正常工作。

从 SubPixelOffset 字段向后查找第一个麻烦制造者。修复声明,使 ofs 值匹配,然后继续查找下一个错误。

至少 Boolean 成员是错误的,它们默认编组为 32 位整数,但 bool 在 C++ 程序中占用单个字节。它们需要是Byte 或需要&lt;MarshalAs(UnmanagedType.U1)&gt; 属性。

【讨论】:

  • 非常感谢 Hans 的详细说明!
  • 我浏览了我的代码并根据您的建议/解决方案进行了更改。我尝试这样做: Dim uDataParams As New UpdatedPrintDataParameters bXaarScorpionGetPrintDataParametersUpdated(uDataParams) 我没有收到任何错误,但我的结构中也没有任何值...我是否必须设置“IntPtr”等?
【解决方案2】:

您在 dllimport 上使用了 Out 属性。如果您想查看 DLL 对您的结构所做的任何更改,请不要这样做。

至于您的其他错误,如果我们不知道它们是什么,我们将无法帮助您。

【讨论】:

  • 感谢您的回复!我删除了“Out”属性。您将如何使用函数:“bXaarScorpionGetPrintDataParametersUpdated(ByRef UDataParams As UpdatedPrintDataParameters)”?
  • 只需创建一个UpdatedPrintDataParameters 类型的局部变量并将其传递给DLL 方法。一旦方法返回,它应该已经填充了你的局部变量。
  • 所以我按照你说的做了,方法返回“True”,但是当我检查结构中的局部变量时,它们都是“0”......这可能是什么原因?
  • 汉斯当然是对的。我的方向性倒退了。
猜你喜欢
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 2022-01-08
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
相关资源
最近更新 更多