Lazarus Programm soll Delphi Berlin DLL einbinden.

Antworten
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

Ich habe eine interessante Herausforderung:
Eine Bitmap in Lazarus in eine DLL übergeben die mit Delphi Berlin geschrieben ist und dafür nach der Verarbeitung einen String zurückbekommt.

Was sind da die besten Datentypen um den Austausch zu machen ?

Delphi DLL

Code: Alles auswählen

Type
  TArrByte = array of Byte; // ? TArray<Byte>
....
function ReadBarcode(img: TArrByte ;
                     imgSize: integer;
                     outputStringBufferSize : integer;
                     var outputStringBuffer : PAnsiChar):ByteBool; stdcall; export;
 


Lazarus

Code: Alles auswählen

Type
  TArrByte = array of Byte; // ? TArray<Byte>
....
function ReadBarcode(img: TArrByte ;
                     imgSize: integer;
                     outputStringBufferSize : integer;
                     var outputStringBuffer : PAnsiChar):ByteBool;
 


Oder gibt es zum übertragen von Bildern und Strings bessere Möglichkeiten ?

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von theo »

Du könntest vielleicht OpBitnap verwenden.
Du kannst einlesen wie du möchtest (z.B. PNG), dann Pixelformat auf 1bit setzen
Dann wird die Grafik umgewandelt und du hast in RawArray das Bild als Byte Array.
Zum Zugriff afair bei TOpBitmap das Property Data typecasten auf TBitmapData1.

Code: Alles auswählen

  Pixel8 = Byte;
  APixel8 = array[0..MaxArr] of Pixel8;
  PAPixel8 = ^APixel8;     
,,,
  TBitmapData1 = class(TBitmapData)
  private
    fPixels: PAPixel8;
    function GetScanLine(Row: Integer): Pointer; override;
    function GetPixel(X, Y: Integer): TColor; override;
    procedure SetPixel(X, Y: Integer; const Value: TColor); override;
    function GetNativePixel(X, Y: Integer): Boolean;
    procedure SetNativePixel(X, Y: Integer; const Value: Boolean);
  protected
    procedure UpdateSize; override;
  public
    constructor Create(Parent: TOPBitmap); override;
    property RawArray: PAPixel8 read fPixels write fPixels;
    property NativePixels[X, Y: Integer]: Boolean read GetNativePixel write SetNativePixel;
  end


Falls das Package "opbitmapforlazcompat" nicht kompiliert, einfach uses LazFileUtils hinzufügen

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

Wenn ich jetzt das Bild als ByteArray habe, wie versteht die Delphi-Seite das ?

Da ist es doch besser ich schreibe das bmp in einen MemoryStream und wandle den ein Byte Array um und sende das an die DLL. Die kann das ganze ja umgekehrt machen und das Byte Array in einen Stream und den in ein bmp einlesen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von theo »

Naja, RawArray zeigt einfach auf ein Stück Speicher, welches ein 1bit Bitmap enthält.
Mmn ginge das leicht.
Aber mach es wie du möchtest.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

Ich habe auf der anderen Seite Delphi. Daher wenn es in Lazarus sinn macht, in Delphi Berlin habe ich OPBitmap nicht. Das ist mein Problem.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von marcov »

Eine FPC Klasse ist nicht automatisch Äquivalent zu die Delphi Klasse mit derselbe Namen. Genau so auch fuer ansistrings, dynamische arrays usw.

Prinzipiell soll man es auf reine Prozedurale Ebene halten, also pointer nach pixel data mit Dimensionen, oder pointer+size nach ein nach Speicher gestreamten Bild.

Ja es gibt gewissen Inkompatibilitäten zwischen FPC und Lazarus (weil sie beiden COM implementieren), und Dinge werden oft funktionieren. Lange Termin sicher ist das aber nicht.

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von theo »

af0815 hat geschrieben: in Delphi Berlin habe ich OPBitmap nicht. Das ist mein Problem.

OpBitmap ist reines Object Pascal. Ich habe es noch nie auf Berlin versucht, aber es gibt Chancen, dass die wesentlichen Teile dort laufen.
Natürlich nicht LazBridge etc.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von mschnell »

af0815 hat geschrieben: in Delphi Berlin habe ich OPBitmap nicht.

Ich glaube nicht, dass man ein Objekt aud FPC an eine Delphi dll übergeben kann. Das DLL - Interface ist "flat", d.h. Programmiersprachen-unabhängig und deshalb sind nur einfache "Hardware" Typen zugelassen (Integer, Real, Pointer). Sogar bei Bool gibt es ein Problem, wenn man nicht aufpasst, weil TRUE in Delphi als "alle Bits gesetzt" und in C (üblicherweise) als "1" codiert wird.

Für ein Bild geht "offiziell" also nur ein Pointer (auf einen Speicherbereich voller Bytes), der dann auf beiden Seiten in Compiler-spezifischer Weise auf einen entsprechenden Typ (Array, Record, ...) gecastet werden muss. Das passiert entweder manuell oder z.B. durch Importieren einer Type-Library.

Und Achtung !! die Heap-Verwaltung zwischen Hauptprogramm und DLL ist in fpc standardmäßig nicht synchronisiert. Also nichts auf einer Seite freigeben, das auf der anderen Seite angelegt wurde (u.a. deshalb gehen Strings nicht).

Zum Austausch von Objekten mit DLLs gibt es in Delphi die "Runtime Packages". Die gibt es in fpc aber (noch) nicht, und wenn ist die Frage in wie weit das Delphi-kompatibel sein wird.

-Michael
Zuletzt geändert von mschnell am So 26. Feb 2017, 11:20, insgesamt 1-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

mschnell hat geschrieben:Für ein Bild geht "offiziell" also nur ein Pointer (auf einen Speicherbereich voller Bytes), der dann auf beiden Seiten in Compiler-spezifischer Weise auf einen entsprechenden Typ (Array, Record, ...) gecastet werden muss.

-Michael


Das mit dem Pointer ist mir mittlerweile klar geworden, es gibt aber jede Menge (C oder irgendwas)-Libs die man in Lazarus einbinden kann und die Bilder entweder laden oder verarbeiten. Dort funktioniert es ja, somit muss ich das ja Nachbauen können. Aktuell kann ich nicht einmal ein bmp von einer Procedure in die ander Procedure übergeben.

Nicht lauffähig:
image, image1 = TImage, image ist die Source und image1 soll die Destination darstellen.

Code: Alles auswählen

 
Type
  TArrByte = array of Byte;
 
..........
 
 
procedure TForm1.Button3Click(Sender: TObject);
var
  bmp: TBitmap;
  img: PByte;
  img1: TArrByte;
  PBuffer: Pointer;
  PStrBuffer: Pointer;
  FMyMemoryStream: TMemoryStream;
  BufLen: integer;
  BRes: ByteBool;
begin
  bmp := nil;
  BufLen := 0;
  PBuffer:=nil;
  PStrBuffer:= nil;
  try
    FMyMemoryStream:= TMemoryStream.Create;
    bmp:= TBitmap.Create;
    bmp.assign (image.Picture.Graphic);
    bmp.SaveToStream(FMyMemoryStream);
    PBuffer := FMyMemoryStream.Memory;
    BRes:= CopyPic(PBuffer^,FMyMemoryStream.Size,PStrBuffer,0);
  finally
    bmp.Free;
    FMyMemoryStream.Free;
  end;
end;
 
function TForm1.CopyPic(const Buffer;
                        BufferSize: int64;
                        var StringBuffer: Pointer;
                        StringBufferSize : int64): ByteBool;
var
  bmp: TBitmap;
  PBuffer: Pointer;
  FMyMemoryStream: TMemoryStream;
begin
  Result:= False;
  bmp := nil;
  PBuffer:=nil;
  try
    FMyMemoryStream:= TMemoryStream.Create;
    bmp:= TBitmap.Create;
    FMyMemoryStream.Write(PByte(Buffer), BufferSize);
    bmp.LoadFromStream(FMyMemoryStream,FMyMemoryStream.Size);
    image1.Picture.Graphic.Assign(bmp);
    Result:= True;
  finally
    bmp.Free;
    FMyMemoryStream.Free;
  end;
end;
 
 


Weil, wenn ich es nicht von einer procedure zur anderen schaffe, dann brauche ich über ansprechen einer Dll gar nicht nachdenken.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von wp_xyz »

Du musst zwischen Schreiben und Lesen den Stream wieder an den Anfang setzen. In CopyPic steht MyMemoryStream.Position nach MyMemoryStream.Write(...) am Ende. Das folgende LoadfromStream verändert Position nicht. Das heißt, dass nichts gelesen werden kann. Setze einfach vor MyMemoryStream.LoadfromStream MyMemorystream.Positon auf 0:

Code: Alles auswählen

function TForm1.CopyPic(const Buffer;
                        BufferSize: int64;
                        var StringBuffer: Pointer;
                        StringBufferSize : int64): ByteBool;
var
  bmp: TBitmap;
  PBuffer: Pointer;
  FMyMemoryStream: TMemoryStream;
begin
  Result:= False;
  bmp := nil;
  PBuffer:=nil;
  try
    FMyMemoryStream:= TMemoryStream.Create;
    bmp:= TBitmap.Create;
    FMyMemoryStream.Write(PByte(Buffer), BufferSize);
    FMyMemoryStream.Position := 0;    // <-- neu
    bmp.LoadFromStream(FMyMemoryStream,FMyMemoryStream.Size);
    image1.Picture.Graphic.Assign(bmp);
    Result:= True;
  finally
    bmp.Free;
    FMyMemoryStream.Free;
  end;
end;

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

Danke für den Tip -> Das ist ja so logisch -> Eigentlich gehört das in das Anfängerforum, das man den Streamzeiger wieder auf den Anfang setzt.

Die Routine funktioniert jetzt. Dann kümmere ich mal um die Dll :-)

Code: Alles auswählen

 
function TForm1.CopyPic(const Buffer;
                        BufferSize: int64;
                        var StringBuffer: Pointer;
                        StringBufferSize : int64): ByteBool;
var
  PBuffer: Pointer;
  FMyMemoryStream: TMemoryStream;
begin
  Result:= False;
  PBuffer:=nil;
  try
    FMyMemoryStream:= TMemoryStream.Create;
    FMyMemoryStream.Write(PByte(Buffer), BufferSize);
    FMyMemoryStream.Position := 0;    // <-- neu
    Image1.Picture.LoadFromStream(FMyMemoryStream);
    Result:= True;
  finally
    FMyMemoryStream.Free;
  end;
end;
 
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von mschnell »

TStream über DLL - Grenze könnte sehr problematisch werden, weil ja zum Lesen und Schreiben Funktionen aufgerufen werden, die möglicherweise Speicher allocieren oder de-allocieren könnten.

Außerdem ist nicht sichergestellt, dass die Daten-Speicherung in TMemoryStream in Delphi und in Lazarus gleich funktioniert. (Aber man könnte ja auch Glück haben...)

Du solltest also vorsichtshalber Wrapper-Funktionen schreiben und die dann an die DLL übergeben.

-Michael

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitrag von af0815 »

mschnell hat geschrieben:Du solltest also vorsichtshalber Wrapper-Funktionen schreiben und die dann an die DLL übergeben.
-Michael

Genau deswegen das Beispiel. Ich greife dann mit FMyMemoryStream.Memory zu und kann das direkt mit Pointern handhaben. Geht mittlerweile auch. Fast wäre ich daran gescheitert, das Delphi ja UTF16 verwendet und im Debugger sieht das immer wie NUR ein Zeichen aus.

Code: Alles auswählen

function Decode(ABmp: TBitmap): String;
var
  bmp: Graphics.TBitmap;
  PBuffer: Pointer;
  FMyMemoryStream: TMemoryStream;
  BRes: ByteBool;
  StrRes: PChar;
begin
  bmp := nil;
  PBuffer:=nil;
  Result := '';
  try
    FMyMemoryStream:= TMemoryStream.Create;
    bmp:= Graphics.TBitmap.Create;
    bmp.assign (ABmp);
    bmp.SaveToStream(FMyMemoryStream);
    PBuffer := FMyMemoryStream.Memory;
    GetMem(StrRes,101);
    BRes:= CopyPicDll(PBuffer,FMyMemoryStream.Size,StrRes,100);
    if (BRes <> False) then
      Result := UTF16ToUTF8(PWideChar(StrRes),trunc(100/3))
    else
      Result := 'Nothing';
  finally
    FreeMem(StrRes, 101);
    bmp.Free;
    FMyMemoryStream.Free;
  end;
end;
 
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten