Passing method pointer from C# to Delphi DLL

雨燕双飞 提交于 2019-12-04 13:52:59

Here is a working example. DllTest1 is using a normal function callback. DllTest2 expects the callback as a direct C# function pointer (requires a small hack on the Delphi side), and DllTest3 expects a Delphi method callback pointer (requires a small hack on the C# side).

// Delphi
library test;

uses
  SysUtils;

{$R *.res}

type
  TCallback = procedure (P: PChar); stdcall;
  TMethodCallback = procedure (P: PChar) of object; stdcall;

procedure DllTest1(Callback: TCallback; P: PChar; I: Integer); stdcall;
var
  S: string;
begin
  S := Format('DllTest1 ''%s'' %d', [P, I]);
  if Assigned(Callback) then
    Callback(PChar(S));
end;

procedure DllTest2(_Callback: Pointer; P: PChar; I: Integer); stdcall;
var
  Callback: TMethodCallback absolute _Callback;
  S: string;
begin
  S := Format('DllTest2 ''%s'' %d', [P, I]);
  if Assigned(Callback) then
    Callback(PChar(S));
end;

procedure DllTest3(Callback: TMethodCallback; P: PChar; I: Integer); stdcall;
var
  S: string;
begin
  S := Format('DllTest3 ''%s'' %d', [P, I]);
  if Assigned(Callback) then
    Callback(PChar(S));
end;

exports
  DllTest1,
  DllTest2,
  DllTest3;

begin
end.

// C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace DllTest
{
    class Program
    {
        public struct Method
        {
            public IntPtr code;
            public IntPtr data;
        }
        [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "DllTest1")]
        public static extern void DllTest1(IntPtr p, [MarshalAs(UnmanagedType.LPStr)] string s, int i);
        [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "DllTest2")]
        public static extern void DllTest2(IntPtr p, [MarshalAs(UnmanagedType.LPStr)] string s, int i);
        [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "DllTest3")]
        public static extern void DllTest3(Method m, [MarshalAs(UnmanagedType.LPStr)] string s, int i);

        public delegate void Callback([MarshalAs(UnmanagedType.LPStr)] string s);
        public delegate void MethodCallback(IntPtr self, [MarshalAs(UnmanagedType.LPStr)] string s);
        public static void ShowInfo(string s)
        {
            Console.WriteLine("Info: " + s);
        }
        public static void ShowMethodInfo(IntPtr self, string s)
        {
            Console.WriteLine("Info: " + s);
        }


        static void Main(string[] args)
        {
            Method m;
            Callback info = ShowInfo;
            MethodCallback methodInfo = ShowMethodInfo;
            IntPtr p = Marshal.GetFunctionPointerForDelegate(info);
            IntPtr pm = Marshal.GetFunctionPointerForDelegate(methodInfo);

            // function callback example
            DllTest1(p, "test", 42);
            // method callback example 1
            DllTest2(pm, "test", 42);
            // method callback example 2
            m.code = pm;
            m.data = IntPtr.Zero;
            DllTest3(m, "test", 42);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!