Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi C# callback von Delphi-dll (https://www.delphipraxis.net/147175-c-callback-von-delphi-dll.html)

bert7 3. Feb 2010 07:40


C# callback von Delphi-dll
 
hallo,

im Rahmen einer C#-Anwendung soll eine Delphi-dll eine C#-Methode mit Parametern aufrufen, also ein "callback" Thema.
Dazu wird von der C# Anwendung die aufzurufende C#-Funktion in der Delphi-Dll registriert, ein Funktionspointer ("delegate") übergeben. Dazu wird noch ein Testparameter übergeben.

Der testparamter wird korrekt nach Delphi übertragen, aber beim Aufruf der callback -Methode von Delphi aus nach C# klappts nicht:
In C# kommt irgendein 8-stelliger Zufallswert an, meistens derselbe, aber nicht immer.

Hier der Code der Delphi-dll:

Code:

type TCallback = procedure(val: integer);
var callback : TCallback;



procedure RegisterCallback(aCallback : TCallback; value: integer); stdcall;
begin
  callback:= aCallback; // registrieren...
  ShowMessage('In Delphi:'+ IntToStr(value)); // erfolgreich wird "10" ausgegeben

  callback(value); // ...und gleich testen
end;

exports
  RegisterCallback;
Und hier der C#-Code

Code:

    public partial class Form1 : Form
    {
        public delegate void ProcDelegate(int value);

        [DllImport("DLLTest.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void RegisterCallback(ProcDelegate callBackHandle, int value);


        public Form1()
        {
            InitializeComponent();

            RegisterCallback(CalledFromDelphi,10);// in delphi registrieren, "10" als test mitgeben

        }

        public static void CalledFromDelphi(int value)
        {
            MessageBox.Show("Wert:" + value); // kommt leider nicht "10" an, sondern ein "Zufalls?"-Wert

        }
    }
Erwähnenswert ist noch dass die Messagebox in C# zweimal aufgerufen wird, beidesmal mit großen "Zufalls?"-zahlen, obwohl offensichtlich der callback nur einmal von Delphi aus aufgerufen wird.

Weiss leider nicht , auf welcher Seite die Fehler liegen, vermutlich eher auf C#-Seite ?

Danke.
Bert

Chris.R 3. Feb 2010 08:54

Re: C# callback von Delphi-dll
 
Hallo,

kannst du nicht über ein Interface, dass die C# Anwendung herausgibt einen Callback realisieren?

Ciao Chris

Phoenix 3. Feb 2010 09:34

Re: C# callback von Delphi-dll
 
Die CallingConvention des Callbacks ist falsch. Auch der müsste Stdcall sein. C# erlaubt Dir blöderweise nicht, auf der Callback-Methode die Calling Convention festzulegen.

Eine Lösung für VB(native) gibt es hier:
http://www.codeproject.com/KB/dotnet...CSharp_VB.aspx
Die kannst Du analog anpassen. Weitere Details siehe hier.

Viel Erfolg.

bert7 6. Feb 2010 10:35

Re: C# callback von Delphi-dll
 
hallo,

sorry für die verspätete reaktion (dachte die email-benachrichtiging ist aktiv).

@Phoenix: danke für die Links, aber die beziehen sich anscheinend auf .NET 1.1.

Wie ich herausgefunden habe, gibt es ab .NET 2.0 das Attribut:

[UnmanagedFunctionPointer(CallingConvention.StdCall )]
public delegate void ProcDelegate(int value);

Habe jetzt bei RegisterCallback u. bei ProcDelegate beides je mit "Cdecl" und "StdCall" probiert. Bei "StdCall" beendet die Anwendung mit Zugriffsverletzung (0x0000005), bei "Cdecl" nicht. Doch bei beiden kommt nach wie vor eine falsche Zahl in C# an.

@Chris.R: Was würden mir Interfaces bringen bzw. was ändert das bei der Callback Registrierung bzw. am korrekten Aufruf von der dll aus ?

Bert

Khabarakh 6. Feb 2010 11:59

Re: C# callback von Delphi-dll
 
Afaik benutzt P/Invoke beim Marshallen von Delegates standardmäßig bereits stdcall. Hast du denn auch TCallback als stdcall deklariert?
Und ich glaube nicht, dass es in diesem Fall technisch möglich ist ;) , aber wenn die Delphi-DLL den Funktionszeiger länger behalten will, musst du auf C#-Seite den delegate vor dem GC schützen:
Code:
var callback = new ProcDelegate(CalledFromDelphi);
RegisterCallback(CalledFromDelphi,10);
GC.KeepAlive(callback);

bert7 6. Feb 2010 13:25

Re: C# callback von Delphi-dll
 
Jetzt läufts !

Khabarakh, das war der entscheidende Tip: hatte "stdcall" hinter TCallback vergessen!

Delphi-Quellcode:
type TCallback = procedure(val: integer); stdcall;
Und statt
Code:
GC.KeepAlive(procDelegate);
verwende ich ne statische Referenz:

Code:
public static ProcDelegate procDelegate;
und dann

Code:
procDelegate = new ProcDelegate(CalledFromDelphi)
RegisterCallback(procDelegate, 10);
Danke
Bert


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz