【问题标题】:Passing method pointer from C# to Delphi DLL将方法指针从 C# 传递给 Delphi DLL
【发布时间】:2010-11-11 10:43:03
【问题描述】:

我在将字符串作为 PChar 传递给 Delphi 构建的 DLL 时遇到了一些问题,感谢 Jens Mühlenhoff。

现在我有另一个问题 -

如果 Delphi 声明是常规类型过程,当传递给 DLL 时,我已成功回调 c# 方法,但如果 Delphi 声明是方法类型过程,我会收到“尝试读取或写入受保护内存”错误。

我试过搜索...

这是 Delphi 声明

TCallBack = procedure ( s : String) of object;stdcall;

这里是 C# 代码

[DllImport(
    "DLLTest.dll",
    CallingConvention = CallingConvention.StdCall,
    CharSet = CharSet.Ansi,
    EntryPoint = "DLL_Test"
)]
public static extern void DLL_Test(IntPtr p, [MarshalAs(UnmanagedType.LPStr)] string Location, int AIntValue);

public delegate void MethodCallBackEvent(string s);
public event MethodCallBackEvent Info;

public void GetInfo(string s)
{
    MessageBox.Show("Info: " + s);
}

用作

            Info = GetInfo; //or Info = new MethodCallBackEvent(GetInfo);
            IntPtr p = Marshal.GetFunctionPointerForDelegate(Info);

            DLL_Test(p, "location message", 10);

【问题讨论】:

    标签: c# delphi pointers methods dllimport


    【解决方案1】:

    这是一个工作示例。 DllTest1 正在使用正常的函数回调。 DllTest2 期望回调是一个直接的 C# 函数指针(需要在 Delphi 端进行小改动),而 DllTest3 需要一个 Delphi 方法回调指针(需要在 C# 端进行小改动)。

    // 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);
            }
        }
    }
    

    【讨论】:

    • 谢谢 TOndrej,DllTest3 案例正是我所需要的!我开始认为这是不可能的。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多