В данной статье мы рассмотрим проблему, связанную с взаимодействием Delphi и C# через DLL, и почему для передачи строковых данных между этими языками лучше использовать PWideString, а не WideString. Мы также рассмотрим, как правильно организовать взаимодействие между Delphi и C# для обеспечения корректной передачи данных.
Введение
В современных системах программирования часто возникает необходимость интегрировать компоненты, написанные на разных языках программирования. В данном случае мы рассматриваем взаимодействие между Delphi и C#. Delphi и C# используют разные подходы к работе с памятью и типами данных, что может привести к проблемам при взаимодействии между ними.
Проблема
В вашем примере вы пытаетесь использовать WideString для передачи строк между Delphi и C#. Однако при этом возникают проблемы с передачей параметров. В частности, параметры version и pstr1 оказываются поврежденными, а pstr2 передается корректно. Это связано с тем, что WideString в Delphi и BSTR в C# имеют разные внутренние представления и механизмы управления памятью.
Решение
Для решения этой проблемы необходимо использовать PWideString вместо WideString при передаче строк между Delphi и C#. PWideString представляет собой указатель на строку, что позволяет корректно передавать данные между языками. В C# строковые данные передаются в виде BSTR, а в Delphi — в виде указателя на строку (PWideString).
Вот как можно изменить ваш код, чтобы он работал корректно:
Delphi:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
PAttachToDLL = procedure();
PTest = function(version : Integer; str1: PWideString; str2 : PWideString; version2 : integer): PWideString; stdcall;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
dllAttachToDLL: PAttachToDLL;
dllTest : PTest;
procedure makeTestCall;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
dllhandle: THandle;
str1: PWideString;
str2: PWideString;
result: PWideString;
begin
dllhandle := SafeLoadLibrary('C:pathtoDNNETestsbinDebugnet8.0-windows7.0DNNETestsNE.dll');
@dllAttachToDLL := GetProcAddress(dllhandle, 'Attach');
@dllTest := GetProcAddress(dllhandle, 'Test');
dllAttachToDLL();
makeTestCall();
Application.Terminate();
end;
procedure TForm1.makeTestCall;
var
str1: PWideString;
str2: PWideString;
result: PWideString;
begin
str1 := PWideString(WideString('normal widestring'));
str2 := PWideString(WideString('and here pwidestring'));
result := dllTest(8, str1, str2, 7);
try
ShowMessage(result);
finally
if Assigned(result) then
Dispose(result);
end;
end;
end.
C#:
using System.Runtime.InteropServices;
using System.Windows;
namespace DNNETests
{
public class Class1
{
[UnmanagedCallersOnly]
public static void Attach()
{
MessageBox.Show("Hallo c# debugger");
}
[StructLayout(LayoutKind.Sequential)]
public struct IsInputFileVersionCompatibleResult
{
public int resultCode;
public IntPtr msg;
public IntPtr mostRecentRelatedPPPVersion;
}
[UnmanagedCallersOnly]
public static IntPtr Test(int version, IntPtr pstr1, IntPtr pstr2, int version2)
{
string str1 = Marshal.PtrToStringBSTR(pstr1) ?? string.Empty;
string str2 = Marshal.PtrToStringBSTR(pstr2) ?? string.Empty;
MessageBox.Show("parameter: " + version + Environment.NewLine +
str1 + Environment.NewLine +
str2 + Environment.NewLine +
version2);
return Marshal.StringToBSTR("return value");
}
}
}
Объяснение
Параметры передачи строк: В Delphi строки передаются в виде указателей на строки (PWideString), а не самих строк (WideString). Это позволяет корректно передавать данные между языками.
Calling Convention: В Delphi необходимо указать stdcall как соглашение о вызове для функций, которые будут вызваны из C#. Это соглашение о вызове используется в Windows API и гарантирует корректную передачу параметров и управление стеком.
Управление памятью: В Delphi строки, переданные в виде указателей (PWideString), должны быть освобождены после использования. Это можно сделать с помощью функции Dispose.
Альтернативное решение
Если вы хотите избежать использования PWideString и Dispose, можно использовать TBStr, который является оберткой для BSTR и автоматически управляет памятью. Вот как можно изменить ваш код для использования TBStr:
Delphi:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
PAttachToDLL = procedure();
PTest = function(version : Integer; str1: TBStr; str2 : TBStr; version2 : integer): TBStr; stdcall;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
dllAttachToDLL: PAttachToDLL;
dllTest : PTest;
procedure makeTestCall;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
dllhandle: THandle;
str1: TBStr;
str2: TBStr;
result: TBStr;
begin
dllhandle := SafeLoadLibrary('C:pathtoDNNETestsbinDebugnet8.0-windows7.0DNNETestsNE.dll');
@dllAttachToDLL := GetProcAddress(dllhandle, 'Attach');
@dllTest := GetProcAddress(dllhandle, 'Test');
dllAttachToDLL();
makeTestCall();
Application.Terminate();
end;
procedure TForm1.makeTestCall;
var
str1: TBStr;
str2: TBStr;
result: TBStr;
begin
str1 := SysAllocString(PWideChar('normal widestring'));
str2 := SysAllocString(PWideChar('and here pwidestring'));
result := dllTest(8, str1, str2, 7);
try
ShowMessage(result);
finally
if Assigned(result) then
SysFreeString(result);
end;
end;
end.
Заключение
В данной статье мы рассмотрели проблему, связанную с передачей строк между Delphi и C# через DLL, и предложили несколько решений для ее решения. Использование PWideString или TBStr позволяет корректно передавать строки между языками и избежать проблем с управлением памятью.
Статья рассматривает проблему взаимодействия Delphi и C# через DLL, и предлагает использовать `PWideString` вместо `WideString` для корректной передачи строковых данных между этими языками.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.