2010-11-11 33 views
3

我已經有一些問題傳遞字符串作爲PChar到德爾福建立的DLL,並解決它感謝延斯Mühlenhoff。從C#傳遞方法指針到Delphi DLL

現在我有另一個問題 -

我通過對DLL如果德爾福聲明是一個普通類型的程序時所做的C#方法的成功回調,但如果德爾福聲明是一個方法類型的程序,我得到「試圖讀取或寫入受保護的內存「錯誤。

我試圖尋找...

這裏是德爾福聲明

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

這裏被用作

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

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

回答

7

這裏的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); 
} 

的工作示例。 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); 
     } 
    } 
} 
+0

看到我編輯的答案。 – 2010-11-11 12:26:00

+0

謝謝!TOndrej,DllTest3案件正是我所需要的!我開始覺得這是不可能的。再感謝一次。 – Sofija 2010-11-11 13:27:56