Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   [Delphi/C#] Eigenes PlugIn System übersetzen nach C# (https://www.delphipraxis.net/173317-%5Bdelphi-c-%5D-eigenes-plugin-system-uebersetzen-nach-c.html)

RWarnecke 17. Feb 2013 08:19


[Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Hallo zusammen,

ich habe für mein Programm Code-Orakel ein PlugIn-System erstellt. Dieses funktioniert auch hervorragend mit Delphi. Nun habe ich aus der Entwickler-Ecke die Anfrage erhalten, ob ich auch ein SDK für C# erstellen kann.

Da ich aber C# nicht so gut kenne wie Delphi ist meine erste Frage, ob ich das jetzige PlugIn-SDK von Delphi einfach übersetzen kann oder ob ich mein PlugIn-System nochmal komplett überarbeiten muss ?

Reicht Visual C# Express für die Übersetzung völlig aus oder brauche ich eine höhere Version ?

Elvis 17. Feb 2013 08:51

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Deine Interfaces nutzen Register als Aufrufskonvention, IOW die wohl mit Abstand schlechteste Wahl, die du hättest nehmen können.
Damit kannst natürlich alle Compiler außer Delphi, BCB und FPC vergessen.

Fix das lieber solange es noch geht.
Außer es gibt schon zu viele nicht mehr aktiv gepflegte Plugins für dein Programm.
Hier konnte ich mir irgendwann mal von einigen sehr weitsichtigen Leuten anhören wie sinnlos es ist das gleich von Anfang an richtig zu machen... :roll:

RWarnecke 17. Feb 2013 09:14

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Hallo Robert,

irgendwie verstehe ich Deinen Post noch nicht. Ich glaube, ich habe da noch Nachholbedarf was Interfaces angeht. Ich habe mir den Thread aus Deinem Link durchgelesen, aber so richtig verstanden habe ich es nicht. Kannst Du es mir vielleicht anhand eines kleinen Beispiels erklären bitte. Mein Verständnis von Interfaces war bis jetzt, dass ich damit eine externe Schnittstelle für ein Programm schaffen kann um zum Beispiel PlugIns zuzulassen.

Zitat:

Zitat von Elvis (Beitrag 1203918)
Fix das lieber solange es noch geht.
Außer es gibt schon zu viele nicht mehr aktiv gepflegte Plugins für dein Programm.
Hier konnte ich mir irgendwann mal von einigen sehr weitsichtigen Leuten anhören wie sinnlos es ist das gleich von Anfang an richtig zu machen... :roll:

Wie viele PlugIns es gibt weiß ich nicht. Aber die jetzige PlugIn-Schnittstelle gibt es erst seit Version 1.2.0. Deshalb weiß ich nicht, ob es noch machbar ist umzubauen. Aber ich interessiere mich trotzdem für beide Varianten.

jfheins 17. Feb 2013 09:22

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Mein Verständnis von Interfaces war bis jetzt, dass ich damit eine externe Schnittstelle für ein Programm schaffen kann um zum Beispiel PlugIns zuzulassen.
Das sit ja auc richtig. Aber nur Funktionen aufrufen reicht nicht, der Computer muss auch wissen wie er die Funktionen aufrufen muss. dazu gehören solche Sachen wie "In welcher reihenfolge werden die Parameter übergeben?" und "Wer räumt nachher auf? Der Aufrufer oder die Funktion?" also grob: "In welchen Zustand wird die CPU zurückgelassen nachdem die Funktion beendet ist?"

Da das Problem natürlich überall aufgetaucht ist, haben sich Konventionen gebildet (ja, Plural) und Pascal hatte eben eine andere als C. Die von pascal heißt register, die von C heißt stdcall.

Pascal kann auch Funktionen erzeugen die sich an die stdcall-Konvention halten, die müssen aber gekennzeichnet werden. Umgekehrt kann C keine Funktionen erzeugen oder aufrufen, die sich an die register-Konvention halten.

Ergo: Die interfaces ermöglichen zwar Plugins. Da du aber keine Konvention explizit geschrieben hast, nimmt der Delphi-Compiler register als Aufrufkonvention. Da er das tut, kannst du diese Funktionen wieder nur aus Pascalcode aufrufen. Die Plugins müssen also zwangsläufig in Pascal geschrieben sein!

Robotiker 17. Feb 2013 09:32

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von jfheins (Beitrag 1203920)
die von C heißt stdcall.

Als Konvention bei Interfaces, insbesondere COM, ja. Die standard Aufrufkonvention ist aber sowohl beim BCB als auch VC++ cdecl, nicht stdcall. Die Unterschiede liegen im Aufräumen des Stacks
http://msdn.microsoft.com/en-us/libr...vs.100%29.aspx

Phoenix 17. Feb 2013 10:00

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von RWarnecke (Beitrag 1203916)
ich habe für mein Programm Code-Orakel ein PlugIn-System erstellt. Dieses funktioniert auch hervorragend mit Delphi. Nun habe ich aus der Entwickler-Ecke die Anfrage erhalten, ob ich auch ein SDK für C# erstellen kann.

Hat derjenige Ahnung von .NET?
Sorry, aber ein taugliches Plugin-System kann ich für .NET in 10 Minuten herzaubern und habe das schon mehrfach gemacht. Wieso sollte man dazu ein SDK nutzen? Assembly laden, bestimmte für das Plugin-System definierte Interfaces mit Reflection rausziehen und go. Dazu braucht man nicht mehr als die Hausmittel liefern, und alles andere geht vermutlich stark am eigenen Use-Case vorbei.

RWarnecke 17. Feb 2013 10:07

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von Phoenix (Beitrag 1203929)
Hat derjenige Ahnung von .NET?
Sorry, aber ein taugliches Plugin-System kann ich für .NET in 10 Minuten herzaubern und habe das schon mehrfach gemacht. Wieso sollte man dazu ein SDK nutzen? Assembly laden, bestimmte für das Plugin-System definierte Interfaces mit Reflection rausziehen und go. Dazu braucht man nicht mehr als die Hausmittel liefern, und alles andere geht vermutlich stark am eigenen Use-Case vorbei.

Das Wort SDK habe ich selber dazu geschrieben. Verstehe ich Deine Aussage richtig, dass ich in C# einfach eine Unit schreibe, womit dann das PlugIn erstellt werden kann, so wie mit dem Beispiel aus meinem Download ?

Furtbichler 17. Feb 2013 10:44

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Ja, Du musst nur eine C#-Klasse erstellen, die dein COM-Interface implementiert.

Hier steht, wie das geht.

BlackSeven 17. Feb 2013 11:57

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von Phoenix (Beitrag 1203929)
Sorry, aber ein taugliches Plugin-System kann ich für .NET in 10 Minuten herzaubern und habe das schon mehrfach gemacht.

Hast Du dazu ein Beispiel? Würde mich brennend interessieren.

Furtbichler 17. Feb 2013 12:04

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Na, ich glaube er meint: Deklariere dein IPlugin-Interface, erzeuge ein paar DLL mit jeweils einer Klasse, die das IPlugin-Interface implementieren, schmeiss die DLL in ein Verzeichnis und zum dynamischen laden lädst Du die Assemble und fragst mit Reflection, ob die exportierte Klasse in der DLL das IPlugin-Interface implementiert.

Code:
...
  Assembly assembly = Assembly.LoadFile(fullFilename);
  foreach (Type type in assembly.GetTypes())
    if (type.IsClass && type.IsPublic)
       if (type.GetInterfaces().Contains(typeof(IPlugin)))
          // type ist eine Plugin-Klasse und kann jetzt verwendet werden.
...

Elvis 17. Feb 2013 15:11

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Deine Interface-Methoden sollten stdcall oder safecall sein. (letzteres wäre vllt. besser)
Bei den Datentypen solltest du auch auf Interop achten. Strings sollten zum Beispiel WideString sein.

Danach sollte man Plugins in allen möglichen Sprachen schreiben können.
Für alle MSBuild-kompatiblen .Net-Sprachen ginge mein Nuget Package.

Du könntest auch ein eigenes Plugin SDK für .Net schaffen.
In .Net hat sich über die Jahre das Service locator pattern ganz gut für sowas bewährt. Schaue dir dazu mal Beispiele für IServiceProviver an.
Lasse dir kein Ohr wegen MEF abkauen. Das wäre für deine Zwecke viel zu frickelig.

geskill 17. Feb 2013 17:21

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Und statt Boolean nimmt man WordBool.

Und statt
Delphi-Quellcode:
OnClick: TOnMenuClick
lieber so:

Delphi-Quellcode:
  INotifyEvent = interface(IUnknown)
    ['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
    procedure OnNotify(const Sender: IUnknown); stdcall;
  end;


    function InsertMenuItem(AIndex: Integer; const aCaption: WideString; const AHint: WideString; aShortCut: Word; aImageIndex: Integer; aTag: Integer; const aOnClick: INotifyEvent): IMenuItem; stdcall;

RWarnecke 17. Feb 2013 17:35

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Hallo zusammen,

danke für die vielen zahlreichen Antworten. Da habe ich jetzt eine Menge zum ausprobieren. Jetzt ist nur noch die Frage offen, kann ich das ganze mit Visual Studio Express durchführen ?

Furtbichler 17. Feb 2013 18:44

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Sollte gehen.

Elvis 17. Feb 2013 22:29

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von geskill (Beitrag 1204018)
Und statt
Delphi-Quellcode:
OnClick: TOnMenuClick
lieber so:

:thumb: Cool, dass jmd. das gesehen hat.
Als ich das in einer PlugIn API gesehen habe, hat gleich meine Augenbraue nervös gezuckt.
Aber ich hatte vorhin ein paar Softkeyboards für mein neues Tablet ausprobiert, deshalb war noch mehr Text, besonders Codebleistifte, ein bissel jenseits meiner Leidensfähigkeit.

Allerdings, wie ich bereits schrieb: safecall ist ein bissel besser.
Standardmäßig werden Interface Methoden in .Net per sdtcall mit HResult durch den COM/Interop Layer geschleust.
Dieser Layer wird auch bei P/Invoke (klassische DLLs in .Net) verwendet.
Das entspricht dem was safecall in Delphi macht.

Und mal ganz ehrlich: Wer hat Lust bei Exceptions aus einer DLL gleich alles zum Explodieren zu bringen, ohne eine richtige Meldung liefern zu können? :zwinker:
safecall ist eines dieser sehr coolen Features von Delphi, die gerne übersehen werden. Delphi hat nicht wirklich viele Features, die wirklich cool sind. Die Art wie es Exception-Handling zwischen DLLs vereinfacht ist IMO extrem cool.

Das hier:
Delphi-Quellcode:
  INotifyEvent = interface(IUnknown)
    ['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
    procedure OnNotify(const Sender: IUnknown); safecall;
  end;
entspricht dem hier:
Delphi-Quellcode:
  INotifyEvent = interface(IUnknown)
    ['...']
    function OnNotify(const Sender: IUnknown) : HResult; stdcall;
  end;
Delphi setzt nicht nur beim Implementieren von diesen Methoden schön das HResult falls eine Exception geworfen wird, sondern führt auch SetErrorInfo aus, so dass .Net, VB, C++, ... auf der anderen Seite eine passende Exception erzeugen können.
Klappt auch supi andersrum.

Code, der in C# implementiert ist und eine Exception wirft, kann dann dort wieder ein HResult zurückgeben, und SetErrorInfo setzen. In Delphi kriegt man dann eine Delphi Exception, mit der richtigen Message.

Ich würde aber Events in 2 Typen aufteilen: Den eigentlichen Event und einen Subscriber:
Delphi-Quellcode:
INotifyEvent = interface(IUnknown)
  ['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
  procedure Add(const hanlder: INotifyEventHandler); safecall;
  procedure Remove(const hanlder: INotifyEventHandler); safecall;
end;

INotifyEventHandler = interface(IUnknown)
  ['...']
  procedure Invoke(const sender : IUnknown); safecall;
end;
Das hat den Vorteil, dass sich viele benachrichtigen lassen können, und diese Benachrichtigung auch wieder abbestellen können.
Aber andere wissen nicht, wer sonst noch benachrichtigt wird, und können erst recht keine fremden Benachrichtigungen stören.

Das würde in C# so aussehen:
Code:
[ComVisible(true),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 Guid("EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7")]
public interface INotifyEvent
{
   void Add([MarshalAs(UnmanagedType.Interface)]INotifyEventHandler handler);
   void Remove([MarshalAs(UnmanagedType.Interface)]INotifyEventHandler handler);
}

[ComVisible(true),
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 Guid("...")]
public interface INotifyEventHandler
{
   void Invoke([MarshalAs(UnmanagedType.IUnknown)]object sender);
}

public class NotifyEventHandler : INotifyEventHandler
{
   readonly Action<object> _EventHandler;
   
   public NotifyEventHandler(Action<object> eventHandler)
   {
      if(eventHandler == null)
         throw new ArgumentNullException("eventHandler");
      _EventHandler = eventHandler;
   }
   
   public void Invoke(object sender)
   {
      _EventHandler(sender);
   }
}
Noch mehr Marshaling Bleistifte

geskill 17. Feb 2013 23:22

AW: [Delphi/C#] Eigenes PlugIn System übersetzen nach C#
 
Zitat:

Zitat von Elvis (Beitrag 1204056)
Allerdings, wie ich bereits schrieb: safecall ist ein bissel besser.
Standardmäßig werden Interface Methoden in .Net per sdtcall mit HResult durch den COM/Interop Layer geschleust.
Dieser Layer wird auch bei P/Invoke (klassische DLLs in .Net) verwendet.
Das entspricht dem was safecall in Delphi macht.

Man lernt immer noch dazu ;) Danke für die detaillierte Beschreibung =)

Zitat:

Zitat von Elvis (Beitrag 1204056)
Ich würde aber Events in 2 Typen aufteilen: Den eigentlichen Event und einen Subscriber:
Delphi-Quellcode:
INotifyEvent = interface(IUnknown)
  ['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
  procedure Add(const hanlder: INotifyEventHandler); safecall;
  procedure Remove(const hanlder: INotifyEventHandler); safecall;
end;

INotifyEventHandler = interface(IUnknown)
  ['...']
  procedure Invoke(const sender : IUnknown); safecall;
end;

Das Konzept ist bei Java z.B. gang und gebe.

Ich hatte das auch hier schonmal angeschnitten, aber ich sehe das Bedarf bald einer Überarbeitung ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:28 Uhr.

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