Interop Delphi dll/C# – неправильное распределение или маршалинг памятиC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Interop Delphi dll/C# – неправильное распределение или маршалинг памяти

Сообщение Anonymous »

Я создаю оболочку для вызова библиотеки DLL Delphi в приложении C# и изо всех сил пытаюсь заставить ее работать. Сбой не происходит, но возвращаемый результат представляет собой случайные данные из памяти.
Я не знаю, связана ли проблема с моими структурами или это проблема маршалинга/демаршалинга данных, или что-то еще.
Примечание: я не являюсь владельцем Delphi DLL, у меня нет доступа к исходному коду. Все, что у меня есть, это определение структуры и подпись процедуры:
{ ////////////////////////////////////////////////////////////////////////////// }
{ ****************************************************************************** }
{ ////////////////////////////////////////////////////////////////////////////// }

TSVADParameterInOut = record
// Grundeinstellungen
Sprache: Byte; { 0:deutsch 1: }
Daten_Path: shortstring { wo die textDatei ist };
BlendrahmenSpaltmas: integer; { Intern festgelegt auf 12,0mm. Wird nicht beachtet }
// Kosten einstellungen
Rabattstufensaetze: array [0 .. 8] of integer; { 0:ohne 1 Rabatt 29 /2:34 / 3:37 / 4:38 5:47 6:49 7:51 8:93 }
// Ausgabe Daten
Error: integer;
Systemgrenze: integer;
end;

PTSVADParameterInOut = ^TSVADParameterInOut;

{ ////////////////////////////////////////////////////////////////////////////// }
{ ****************************************************************************** }
{ ////////////////////////////////////////////////////////////////////////////// }

TSVABauteil = record
B_Anzahl: integer;
B_VE_Anzahl: integer;
B_Art: integer;
B_Preis: real;
B_Artnr: longint;
B_Bezeichnung: shortstring;
B_Bezeichnung_nr: shortstring;
B_Rabattstuffe: integer;
B_VE_einheit: Byte;
end;

PTSVABauteil = ^TSVABauteil;

TSVABauteile = array [0 .. 255] of TSVABauteil;
PTSVABauteile = ^TSVABauteile;

TSVABlendBauteile = array [0 .. 255] of TSVABauteil;
PTSVABlendBauteile = ^TSVABlendBauteile;


procedure GetBauteilPreisListe(
paramerterString: PCHAR;
var infoParameter: TSVADParameterInOut;
var aPGesamtBauteile: PTSVABauteile); stdcall; external 'something.dll';

А вот код C#:
internal class Program
{
static void Main(string[] args)
{
IDataProvider provider = new DataProvider();
var qrCode = "1001214350062700643000000143501943119471030000000400010101121001010010100000010000000210001011000000010110001000000000000000000000";

provider.GetComponentsPriceList(qrCode);
}
}

namespace Example
{
public interface IDataProvider
{
void GetComponentsPriceList(string qrCode);
}
}

namespace Example
{
public class DataProvider : IDataProvider
{
private const string DLL_PATH = "something.dll";

[DllImport(DLL_PATH, CallingConvention = CallingConvention.StdCall)]
private static extern void VAD_GetBauteilPreisListe(string parameterString, ref TSVADParameterInOut infoParameter, ref IntPtr aPGesamtBauteile);

public void GetComponentsPriceList(string qrCode)
{
var infoParameter = new TSVADParameterInOut();
infoParameter.Sprache = 1;
infoParameter.Rabattstufensaetze = new int[9];

// Allocate unmanaged memory for the array of TSVABauteile.
IntPtr ptrBauteile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TSVABauteile)));

try
{
// Call the Delphi procedure.
VAD_GetBauteilPreisListe(qrCode, ref infoParameter, ref ptrBauteile);

// Marshal the unmanaged memory to managed structure.
TSVABauteile bauteile = (TSVABauteile)Marshal.PtrToStructure(ptrBauteile, typeof(TSVABauteile));

// Access the bauteile array.
var results = new List();
foreach (var item in bauteile.Bauteile)
{
if (item.B_Artnr != 0)
{
results.Add(item);
Console.WriteLine($"Art.: {item.B_Artnr} | Price: {item.B_Preis} | Desc.: {item.B_Bezeichnung}");
}
}
Console.WriteLine($"\n> Count: {results.Count}"); // should return 14 elements.
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(ptrBauteile);
}

Console.ReadKey();
}
}
}

Мои структуры C# (
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct TSVADParameterInOut
{
public byte Sprache;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
public string Daten_Path;
public int BlendrahmenSpaltmas;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public int[] Rabattstufensaetze;
public int Error;
public int Systemgrenze;
}

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct TSVABauteil
{
public int B_Anzahl;
public int B_VE_Anzahl;
public int B_Art;
public double B_Preis;
public int B_Artnr;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string B_Bezeichnung;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string B_Bezeichnung_nr;

public int B_Rabattstuffe;
public byte B_VE_einheit;
}

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct TSVABauteile
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public TSVABauteil[] Bauteile;
}

Я прошел через множество ошибок (нарушение памяти, переполнение стека, ошибки неуправляемой памяти и т. д.), чтобы наконец прийти к этому коду, который не дает сбоев, но теперь я могу' никакого прогресса.
Кто-нибудь может понять, что не так в этом коде?

Я попробовал:
  • возможны все комбинации размеров упаковки структур от 0 до 128 для каждого
  • определить кодировку как charset.Ansi< /li>
    сопоставить короткую строку Delphi с IntPtr
  • использовать небезопасные блоки
  • не использовать ref для параметра aPGesamtBauteile< /li>
    Маршалинг параметраString
  • множество вариантов кода, например:
IntPtr ptrBauteile = Marshal.AllocHGlobal(sizeOfBauteileArray);

try
{
// Initialize the memory with zeroes
for (int i = 0; i < sizeOfBauteileArray; i++)
{
Marshal.WriteByte(ptrBauteile, i, 0);
}

// Call the Delphi procedure
GetBauteilPreisListe(paramerterString, ref infoParameter, ref ptrBauteile);

// Marshal the unmanaged memory to managed structure
TSVABauteil[] managedBauteileArray = new TSVABauteil[256];
IntPtr current = ptrBauteile;

for (int i = 0; i < 256; i++)
{
managedBauteileArray = (TSVABauteil)Marshal.PtrToStructure(current, typeof(TSVABauteil));
current = IntPtr.Add(current, sizeOfBauteil);
}

// access the bauteile array
foreach (var item in managedBauteileArray)
{
if (item.B_Artnr != 0)
{
Console.WriteLine($"B_Anzahl: {item.B_Anzahl}, B_Preis: {item.B_Preis}, B_Bezeichnung: {item.B_Bezeichnung}");
}
}
}
finally
{
// Free the unmanaged memory
Marshal.FreeHGlobal(ptrBauteile);
}


Подробнее здесь: https://stackoverflow.com/questions/786 ... marshaling
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»