2017-01-24 2 views
1

Я хочу вызвать функцию DLL, которая хочет структуру, и внутри этой структуры есть другая структура. Dll должен возвращать значения моим структурам, но я получаю только коды ошибок. Однажды (некоторая кодировка назад) я успешно вернул «True» в мой вызов функции, но в моих структурах не было значений.Как успешно работать со структурами и вложенными структурами в dll cpp в VB.NET/C#?

Я не очень хорошо знаком с маршалингом и таким, но если кто-то может предоставить мне пример о том, как это сделать!

DLL, код выглядит следующим образом:


bXaarScorpionGetPrintDataParametersUpdated(struct UpdatedPrintDataParameters &DataParams); 

Первый STRUCT:

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 

+0

Пожалуйста, пожалуйста, предоставьте код _succinct_, чтобы сопровождать ваш вопрос –

+0

Прошу прощения за Даниэля, я не знаю эту тему. Я хочу назвать свою функцию api, но я не знаю, как ее «подготовить». Как вы можете видеть, я настроил свои структуры на стороне VB.net в соответствии с Dll, но я просто не знаю где идти отсюда ... – Tojanarm

+0

Какова ценность MAXROWS? Мы могли бы приложить максимум усилий, чтобы узнать код VB.NET, если вы это предоставили. Также нам нужен результат sizeof, который запросил Ганс, поскольку это предоставит информацию о упаковке. – hoodaticus

ответ

1

... все они «0» ... Что может быть причиной этого?

Ответ, который вы получили, не помог. Фактически вам нужен атрибут <Out>, структура не является «blittable» из-за массивов и булевых членов. Сто долларовое слово означает, что маркерщик pinvoke не может просто передать указатель на управляемую переменную, потому что неуправляемый макет не совпадает с управляемым макетом. По умолчанию маркерщик pinvoke не копирует структуру, OutAttribute требуется, чтобы изменить свое мнение.

Если вам нужен атрибут <[In]>, это не очевидно. Наверное, нет, но это не повредит, чтобы включить его, этот код в любом случае не будет быстрым.

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

Это чудовище структура и ваша декларация VB.NET не соответствует декларации C на всех. Его размер даже не удаленно близко к 66 байтам. Не только размер должен совпадать, поля должны быть с одинаковым смещением как в коде C++, так и в коде VB.NET. Если есть несоответствие, то код C может случайно сбой с AccessViolationException, и маршаллер обречен на копирование данных в совершенно неправильные поля. Я опишу общую стратегию устранения ошибок, чтобы найти ошибки.

Вам нужно написать небольшую программу на C++, которая измеряет размер структуры с помощью оператора sizeof. Его значение должно быть точным совпадением с возвратным значением Marshal.SizeOf(). Если это не совпадение, то он не может быть правильно настроен. Вы нашли неправильное объявление (ы), используя макрос offsetof в C++ и метод Marshal.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 

Выполнение этого кода как есть, программа C++ сообщит длина 312 байт и смещение для SubPixelOffset поле 140. Программа VB.NET сообщает 339 и 132. Большая разница, с несколькими ошибками, она никогда не сможет работать правильно.

Отправляйтесь в поле SubPixelOffset, чтобы найти первого неисправного. Исправьте объявление так, чтобы значение ofs совпадало, а затем переходите к следующей ошибке.

По крайней мере, члены Boolean ошибочны, они маршалируют по умолчанию как 32-разрядное целое число, но bool принимает один байт в программе на C++. Они должны быть Byte или нужен атрибут <MarshalAs(UnmanagedType.U1)>.

+0

Большое спасибо Хансу за подробные инструкции! – Tojanarm

+0

Я просмотрел свой код и внес изменения в соответствии с вашим предложением/решением. Я попытался сделать это: Dim uDataParams As New updatedPrintDataParameters bXaarScorpionGetPrintDataParametersUpdated (uDataParams) Я не получаю никаких ошибок, но ни каких значений в моих структурах ... Должен ли я настраивать «IntPtr» и т. Д.? – Tojanarm

0

Вы использовали Out атрибут на вашем DllImport. Не делайте этого, если вы хотите увидеть все изменения, внесенные DLL в вашу структуру.

Что касается других ошибок, мы не можем помочь вам с ними, если мы не знаем, что они собой представляют.

+0

Спасибо за ваш ответ! Я удалил атрибут «Out». Как бы вы могли использовать эту функцию: «bXaarScorpionGetPrintDataParametersUpdated (ByRef UDataParams As UpdPrintDataParameters)»? – Tojanarm

+0

Просто создайте локальную переменную типа UpdatePrintDataParameters и передайте ее в DLL-метод. Как только метод вернется, он должен заполнить вашу локальную переменную. – hoodaticus

+0

Итак, я сделал то, что вы сказали, и метод вернул «True», но когда я проверяю локальные переменные внутри структур, все они «0» ... Что может быть причиной этого? – Tojanarm

Смежные вопросы