Страницы

Поиск по вопросам

суббота, 21 декабря 2019 г.

Взаимодействие управляемого (C#) и неуправляемого (Pascal) кодов

#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/

Комментариев нет:

Отправить комментарий