#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/
Комментариев нет:
Отправить комментарий