如何在 VB.NET/C# 中成功地使用 cpp dll 中的结构和嵌套结构?
How do I successfully work with structures and nested structures within a cpp dll in VB.NET/C#?
我想调用一个需要结构的 DLL 函数,而在该结构中是另一个结构。 Dll 应该 return 值到我的结构,但除了错误代码,我什么也没得到。有一次(以前编码)我在我的函数调用中成功 returned "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
您在 dllimport 上使用了 Out 属性。如果您想查看 DLL 对您的结构所做的任何更改,请不要这样做。
至于您的其他错误,如果我们不知道它们是什么,我们将无法帮助您。
... they are all "0"... What can be the cause of that?
您得到的答案没有帮助。您实际上确实需要 <Out>
属性,由于数组和布尔成员,结构不是 "blittable"。一百美元的话,这意味着 pinvoke 编组器不能只将指针传递给托管变量,因为非托管布局与托管布局不同。默认情况下,pinvoke 编组器不会复制回结构,需要 OutAttribute 来改变它的想法。
您是否也需要 <[In]>
属性并不明显。可能不会,但是包含它不会有太大的伤害,反正这段代码不会很快。
<System.Runtime.InteropServices.StructLayoutAttribute(..., Size:=66)>
这是一个怪物结构,您的 VB.NET 声明与 C 声明完全不匹配。它的大小甚至远不接近 66 字节。不仅大小必须匹配,字段在 C++ 和 VB.NET 代码中也需要具有相同的偏移量。如果存在不匹配,则 C 代码可能会随机失败并出现 AccessViolationException,并且编组器注定要将数据复制到完全错误的字段中。我将描述一个通用的 trouble-shooting 查找错误的策略。
您需要编写一个小的 C++ 程序,用 sizeof
运算符测量结构的大小。它的值需要 与 Marshal.SizeOf()
的 return 值完全 匹配。如果不匹配,则永远无法正确编组。您通过使用 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
运行此代码as-is,C++程序将报告长度为312字节,SubPixelOffset字段的偏移量为140。VB.NET程序报告339和132。差别很大,多次出错,永远无法正常工作。
从 SubPixelOffset 字段向后查找第一个 trouble-maker。修复声明,使 ofs 值匹配,然后继续查找下一个错误。
至少 Boolean
成员是错误的,它们默认编组为 32 位整数,但 bool
在 C++ 程序中采用单个字节。它们需要 Byte
或需要 <MarshalAs(UnmanagedType.U1)>
属性。
我想调用一个需要结构的 DLL 函数,而在该结构中是另一个结构。 Dll 应该 return 值到我的结构,但除了错误代码,我什么也没得到。有一次(以前编码)我在我的函数调用中成功 returned "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
您在 dllimport 上使用了 Out 属性。如果您想查看 DLL 对您的结构所做的任何更改,请不要这样做。
至于您的其他错误,如果我们不知道它们是什么,我们将无法帮助您。
... they are all "0"... What can be the cause of that?
您得到的答案没有帮助。您实际上确实需要 <Out>
属性,由于数组和布尔成员,结构不是 "blittable"。一百美元的话,这意味着 pinvoke 编组器不能只将指针传递给托管变量,因为非托管布局与托管布局不同。默认情况下,pinvoke 编组器不会复制回结构,需要 OutAttribute 来改变它的想法。
您是否也需要 <[In]>
属性并不明显。可能不会,但是包含它不会有太大的伤害,反正这段代码不会很快。
<System.Runtime.InteropServices.StructLayoutAttribute(..., Size:=66)>
这是一个怪物结构,您的 VB.NET 声明与 C 声明完全不匹配。它的大小甚至远不接近 66 字节。不仅大小必须匹配,字段在 C++ 和 VB.NET 代码中也需要具有相同的偏移量。如果存在不匹配,则 C 代码可能会随机失败并出现 AccessViolationException,并且编组器注定要将数据复制到完全错误的字段中。我将描述一个通用的 trouble-shooting 查找错误的策略。
您需要编写一个小的 C++ 程序,用 sizeof
运算符测量结构的大小。它的值需要 与 Marshal.SizeOf()
的 return 值完全 匹配。如果不匹配,则永远无法正确编组。您通过使用 C++ 中的 offsetof
宏和 VB.NET.
开始的一些示例代码。 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
运行此代码as-is,C++程序将报告长度为312字节,SubPixelOffset字段的偏移量为140。VB.NET程序报告339和132。差别很大,多次出错,永远无法正常工作。
从 SubPixelOffset 字段向后查找第一个 trouble-maker。修复声明,使 ofs 值匹配,然后继续查找下一个错误。
至少 Boolean
成员是错误的,它们默认编组为 32 位整数,但 bool
在 C++ 程序中采用单个字节。它们需要 Byte
或需要 <MarshalAs(UnmanagedType.U1)>
属性。