Thema: Delphi DLL Parser Plugins

Einzelnen Beitrag anzeigen

Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#10

Re: DLL Parser Plugins

  Alt 15. Dez 2009, 18:14
Hehe, plugins + Interfaces sind so eine Pet-Disciplin von mir...

Generell ist es bei sowas immer gut, sich auf das u beschränken, was auch über COM funktioniert.
Also...
  • Keine Delphi-Stirng, dafür gehen WideStrings.
  • Keine Klassen, dfür gehen Interfaces.
  • Keine dynamischen Arrays, du kannst hierfür Listenklassen nehmen, die ein Interface implementieren.

Wenn du Interfaces nutzt[1], dann denke daran, dasss sie sich wenigstens ein bissel wie COM-Objekte benehmen sollten.
Das heißt alle Methoden sollte als Calling convention "safecall" nehmen, und alle sollten eine eindeutige GUID haben.


Hier mal ein Bleistift:
Solche eine DLL in Delphi, wäre so interoperabel, dass man sie sogar in C# nutzen könnte.

Delphi-Quellcode:
library SampleInterfaceDLL;

uses
  Dialogs;

type
  ISample = interface(IUnknown)
  ['{C9B334E4-BDAE-419E-9305-143B2C454CEA}']
    function Get_Value : WideString; safecall;
    procedure Set_Value(const value : WideString); safecall;

    procedure ShowValue; safecall;
    property Value : WideString
      read Get_Value
      write Set_Value;
  end;

  TSample = class(TInterfacedObject, ISample)
  private
    fValue : WideString;
    function Get_Value: WideString; safecall;
    procedure Set_Value(const aValue: WideString); safecall;
  public
    procedure ShowValue; safecall;
    property Value : WideString
      read Get_Value
      write Set_Value;
  end;

procedure CreateSample(out instance : ISample); stdcall;
begin
  instance := TSample.Create();
end;

function GetValueLength(const instance : ISample) : Integer; stdcall;
begin
  result := Length(instance.Value);
end;

exports
  GetValueLength,
  CreateSample;

{ TSample }

function TSample.Get_Value: WideString;
begin
  result := fValue;
end;

procedure TSample.Set_Value(const aValue: WideString);
begin
  fValue := aValue;
end;

procedure TSample.ShowValue;
begin
  ShowMessage('From Delphi: ' + Value);
end;

end.
Code:
[ComVisible(true)]
[Guid("C9B334E4-BDAE-419E-9305-143B2C454CEA")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ISample
{
   String Value
   {
      [return: MarshalAs(UnmanagedType.BStr)]
      get;
      [param: In, MarshalAs(UnmanagedType.BStr)]
      set;
   }

   void ShowValue();
}

class ManagedSample : ISample
{
   public String Value { get; set; }

   public int GetLength()
   {
      // Delphi wird mit hier mit "this" klarkommen, da es als ISample genutzt werden kann
      return DelphiImports.GetValueLength(this);
   }

   public void ShowValue()
   {
      Console.WriteLine("From .Net {0}", Value);
   }
}

static class DelphiImports
{
   [DllImport("SampleInterfaceDLL")]
   static extern void CreateSample([MarshalAs(UnmanagedType.Interface)]out ISample instance);

   public static ISample CreateSample()
   {
      ISample instance;
      CreateSample(out instance);
      return instance;
   }

   [DllImport("SampleInterfaceDLL")]
   public static extern int GetValueLength([MarshalAs(UnmanagedType.Interface)]ISample instance);
}

class Program
{
   static void Main(string[] args)
   {
      var delphiInstance = DelphiImports.CreateSample();

      delphiInstance.Value = "Test";
      var l1 = DelphiImports.GetValueLength(delphiInstance);

      var managedInstance = new ManagedSample { Value = "Def" };
      var l2 = managedInstance.GetLength();

      Array.ForEach(new[] { delphiInstance, managedInstance },
                    i => i.ShowValue());
   }
}
Hiermit könntest du sogar einen Parser in C# schreiben:
Code:
[ComVisible(true)]
[Guid("C9B334E4-BDAE-419E-9305-143B2C454CEA")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ISample
{
   String Value
   {
      [return: MarshalAs(UnmanagedType.BStr)]
      get;
      [param: In, MarshalAs(UnmanagedType.BStr)]
      set;
   }

   void ShowValue();
}

class ManagedPlugin : ISample
{
   public String Value { get; set; }

   public void ShowValue()
   {
      Console.WriteLine("From .Net {0}", Value);
   }
}

static class Exports
{
   [DllExport]
   static void CreateSample([MarshalAs(UnmanagedType.Interface)]out ISample instance)
   {
      instance = new ManagedPlugin { Value = "Managed Plugin!" };
   }

   [DllExport]
   public static int GetValueLength([MarshalAs(UnmanagedType.Interface)]ISample instance)
   {
      return (instance.Value ?? "").Length;
   }
}
[1]und das willst du weil platte C-kompatible DLLs bestenfalls als menschenverachtende Folter in Den Haag verhandelt werden sollten
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat