如何在VB.NET/C#中成功处理cpp dll中的结构和嵌套结构? [英] How do I successfully work with structures and nested structures within a cpp dll in VB.NET/C#?

查看:80
本文介绍了如何在VB.NET/C#中成功处理cpp dll中的结构和嵌套结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想调用一个需要结构的DLL函数,并且该结构内是另一个结构. Dll应该将值返回到我的结构,但是除了错误代码之外,我什么也没得到.一次(以前有一些编码),我在函数调用中成功返回了"True",但是结构中没有任何值.

I want to call a DLL function that wants a structure, and within that structure is another structure. The Dll should return values to my structures but I get nothing but error codes. One time (some coding back ago) I successfully returned "True" on my function call, but there were no values in my structures.

我对封送等不是很熟悉,但是如果有人可以,请给我提供有关如何执行此操作的示例!

I am not very familiar with marshaling and such, but if someone could please provide me an example on how to do this!

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声明如下:


My VB.Net declarations look like this:

  <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


推荐答案

...它们全为"0" ...是什么原因造成的?

... they are all "0"... What can be the cause of that?

您得到的答案没有帮助.实际上,您确实需要<Out>属性,由于数组和布尔成员的存在,该结构不是可拆分的".一百美元的单词表示pinvoke marshaller不能仅将指针传递给托管变量,因为非托管布局与托管布局不同.默认情况下,pinvoke marshaller不会复制回结构,需要OutAttribute改变主意.

The answer you got was not helpful. You do in fact need the <Out> attribute, the structure is not "blittable" because of the arrays and the Boolean members. A hundred dollar word that means that the pinvoke marshaller cannot just pass a pointer to the managed variable because the unmanaged layout is not the same as the managed layout. By default the pinvoke marshaller does not copy back a struct, the OutAttribute is required to change its mind.

是否还需要<[In]>属性并不明显.可能不会,但是包含它不会造成太大的伤害,此代码无论如何都不会很快.

Whether you need the <[In]> attribute as well is not obvious. Probably not, but it won't hurt that much to include it, this code is not going to be fast anyway.

<System.Runtime.InteropServices.StructLayoutAttribute(..., Size:=66)>

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

It is a monster struct and your VB.NET declaration does not match the C declaration at all. Its size is not even remotely close to 66 bytes. Not only the size must match, the fields need to be at the same offset both in the C++ and the VB.NET code. If there is a mismatch then the C code can randomly fail with an AccessViolationException and the marshaller is doomed to copy the data into the completely wrong fields. I'll describe a general trouble-shooting strategy to find the mistakes.

您需要编写一个小型C ++程序,该程序使用sizeof运算符测量结构的大小.它的值必须与返回值Marshal.SizeOf()完全精确匹配.如果这不是一场比赛,那么它将永远无法正确封送.通过使用C ++中的offsetof宏和VB.NET中的Marshal.OffsetOf()方法,可以找到错误的声明.

You need to write a small C++ program that measures the size of the struct with the sizeof operator. Its value needs to be an exact match with the return value of Marshal.SizeOf(). If it is not a match then it cannot ever marshal correctly. You find the wrong declaration(s) by using the offsetof macro in C++ and the Marshal.OffsetOf() method in VB.NET.

一些入门示例代码.首先使用C ++代码:

Some sample code to get that started. The C++ code first:

#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代码:

And the equivalent VB.NET code:

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个字节的长度,而SubPixelOffset字段的偏移量为140.VB.NET程序报告339和132.差异很大,有多个错误,所以它永远不会正常工作.

Running this code as-is, the C++ program will report a length of 312 bytes and an offset for the SubPixelOffset field of 140. The VB.NET program reports 339 and 132. Big difference, with multiple mistakes, it can never work correctly.

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

Work backwards from the SubPixelOffset field to find the first trouble-maker. Fix the declaration so the ofs value matches, then work forwards to find the next mistake.

至少Boolean个成员是错误的,默认情况下它们封送为32位Integer,但bool在C ++程序中仅占用一个字节.它们必须是Byte或需要<MarshalAs(UnmanagedType.U1)>属性.

At least the Boolean members are wrong, they marshal by default as a 32-bit Integer but a bool takes a single byte in a C++ program. They need to be Byte or need the <MarshalAs(UnmanagedType.U1)> attribute.

这篇关于如何在VB.NET/C#中成功处理cpp dll中的结构和嵌套结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆