#c_sharp #delphi #dll
Встала задача дергать C# методы из Pascal кода.
Основным условием решения является:
все должно быть переносным, без необходимости регистрировать какие-либо COM объекты
и работать с Delphi 7 + KOL.
К сожалению с Pascal/Delphi не знаком, беглое чтение мануалов результатов не дает,
а изучать язык - катастрофически не хватает времени.
Задача частично решилась после ознакомления с:
Экспорт функций из dll .NET Framework в Metatrader
Как открыть мир C# из MQL5 путем экспорта неуправляемого кода
C# Project Template for Unmanaged Exports
Export Managed Code as Unmanaged
Unmanaged Exports ".NET DllExport"
Вызов Pascal методов из C#-кода работает, претензий пока не имею.
C# (dll)
...
static int test = 0;
[System.Reflection.Obfuscation(Feature = "DllExport")]
static int Get(){
return test;
}
[System.Reflection.Obfuscation(Feature = "DllExport")]
static void Set(int val){
test = val;
}
...
Pascal
...
function Get(): integer; stdcall; external 'UnmanagedExport.dll';
procedure Set(vl:integer ); stdcall; external 'UnmanagedExport.dll';
...
А вот с вызовами Pascal функций из C# - пока пусто.
Попробовал незамысловатый велосипед
C# (dll)
...
delegate void del(int val);
...
[System.Reflection.Obfuscation(Feature = "DllExport")]
static void Test(del proc){
proc(1234);
}
...
Pascal
...
type
myProc=procedure(val: integer);
...
function Test(fn: myProc): integer; stdcall; external 'UnmanagedExport.dll';
procedure mycall(val: integer);
...
procedure mycall(val: integer);
ShowMessage(Int2Str(val));
end;
...
Test(mycall);
...
...
Взаимодействие из C# вполне реализуемо, поскольку месседж
срабатывает, правда с мусором.
А вот как правильно все реализовать - является вопросом.
Помимо вызовов, интересует также, возможность(и как правильно)
подписаться в Pascal-коде на C # события.
11.10.2016
Доброго времени суток.
Задача уже решилась, я не стал дожидаться ответа и решил самостоятельно поковыряться.
А отписаться все руки никак не доходили.
Поскольку в задачу не входила тесная интеграция, то полученных результатов вполне
хватило.
С помощью описанного способа в Экспорт функций из Net dll в Metatrader
получился мост ввиде дополнительной dll.
Из имеющихся под рукой delphi 4,7 + Kol 1.9, FPC 3.0(Lazarus) и FPC 2.6 + Kol 3.2
приведенный участок кода показал разные результаты. Хотя в целом, после небольших
правок, шаблон применим
ко всем подопытным.
Это всего лишь эксперимент, чтобы понять куда двигаться.
Для указанных версий delphi 4,7 + Kol 1.9(является основным условием) со своими(не
известными мне) опциями и правками в kol-е, данный код работоспособен, хотя и не использовался
мною в приведенном масштабе.
Коротко, в общих чертах, эксперимент выглядит примерно так
C#
public class Class1
{
public delegate void del([MarshalAs(UnmanagedType.AnsiBStr)]string _string);
[System.Reflection.Obfuscation(Feature = "DllExport")]
public static unsafe int Test(int value1, string value2, [MarshalAs(UnmanagedType.AnsiBStr)]
ref string value3, del value4, byte* value5)
{
MessageBox.Show("value1: " + value1.ToString()+ "\r\n" +
"value2: " + value2 + "\r\n" +
"value3: " + value3 + "\r\n" +
"value5: " + value5[1].ToString(), "C#");
value3 = "C# йцукен";
value4("bla-bla бла-бла");
value5[1] = 123;
return 54321;
}
}
Pascal
...
type
myProc=procedure(val: String); StdCall;
function Test(val1: integer; val2: string; var val3: string; val4: myProc; val5:
pointer): integer; stdcall; external 'ClassLibrary1.dll';
procedure myCall(val: String); StdCall;
...
var vl1: string;
vl2: array [0..5] of byte;
vl3: integer;
begin
vl1:= 'ytrewq некуцй';
vl2[1]:= 10;
vl3:= Test(12345, 'qwerty йцукен', vl1, @myCall, @vl2);
ShowMessage('vl1: ' + vl1 + #13#10 +
'vl2: ' + int2str(vl2[1]) + #13#10 +
'vl3: ' + int2str(vl3));
...
procedure myCall(val: String); StdCall;
begin
ShowMessage('myCall: ' + val);
end;
...
P.S.
Хотя цель и достигнута, вопрос пока еще остается в силе, особенно взаимодействие
из pascal без "мостов", отдельный интерес касательно событий.
@Pavel Mayorov. Попробуйте все же изучить COM...
К сожалению мои знания в Pascal сильно ограничены, а учить чтото новое не имея начальных
знаний - бессмысленно. Этот вариант не исключен, а отложен до лучших времен(пока не
появится больше свободного времени)
Ответы
Ответ 1
Во второй статье приведён пример с C, который можно перевести на Pascal: #include#include typedef void (__stdcall *callback)(wchar_t * str); extern "C" __declspec(dllexport) void __stdcall caller(wchar_t * input, int count, callback call) { for(int i = 0; i < count; i++) { call(input); } } А вот как это выглядит в Pascal: type TCallback = procedure(str: ^Char); stdcall; procedure caller(input: ^Char, count: Integer; call: TCallback); stdcall; var i: Integer; begin for i := 1 to count do call(input); end; В вашем коде практически то же самое, но вызывающая функция реализована на C#, в то время как по статье она должна быть реализована на Pascal (здесь она называется caller и в терминологии Pascal является процедурой). P.S. На Pascal не писал 200 лет, поэтому в коде возможны синтаксические огрехи. Ответ 2
Для не кроссплатформенного взаимодействия есть Хостинг CLR в неуправляемом приложении Вот кстати вопрос о взаимодействии на Delphi https://stackoverflow.com/questions/39918962/get-value-of-property-of-type-struct Но Host CLR как бы там ни было использует COM. Поэтому проще использовать COM обертку для доступа к любым .Net Классам Как вызвать метод из C# в 1С? На Delphi это будет выглядеть так Wrapp:= CreateoieObject('NetObjectToIDispatch45'); Infrascturcture:=Wrapp.ПолучитьТипИзСборки("HelloWorldLibrary.Infrascturcture",ПутьКСборке_Или_Имя_ДЛЛ_Если_В_GAС); Foo:=Infrascturcture.Foo(); Для кроссплатформенного есть возможность использования статических методов сборок .Net через CoreClr.Dll Кроссплатформенное использование классов .Net из неуправляемого кода. Или аналог IDispatch на Linux Ну а здесь все мои статьи по использованию CoreClr в 1С https://habrahabr.ru/users/serginio1/topics/
Комментариев нет:
Отправить комментарий