Lazarus Programm soll Delphi Berlin DLL einbinden.

Lazarus Programm soll Delphi Berlin DLL einbinden.

Beitragvon af0815 » 24. Feb 2017, 16:44 Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon theo » 24. Feb 2017, 18:41 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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
theo
 
Beiträge: 7880
Registriert: 11. Sep 2006, 18:01

Beitragvon af0815 » 24. Feb 2017, 18:56 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon theo » 24. Feb 2017, 19:52 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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.
theo
 
Beiträge: 7880
Registriert: 11. Sep 2006, 18:01

Beitragvon af0815 » 24. Feb 2017, 20:21 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon marcov » 24. Feb 2017, 20:54 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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.
marcov
 
Beiträge: 999
Registriert: 5. Aug 2008, 08:37
Wohnort: Eindhoven (Niederlande)
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk) | 
CPU-Target: 32/64,PPC(+64), ARM
Nach oben

Beitragvon theo » 24. Feb 2017, 21:32 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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.
theo
 
Beiträge: 7880
Registriert: 11. Sep 2006, 18:01

Beitragvon mschnell » 25. Feb 2017, 13:01 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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 26. Feb 2017, 11:20, insgesamt 1-mal geändert.
mschnell
 
Beiträge: 3157
Registriert: 11. Sep 2006, 09:24
Wohnort: Krefeld
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ) | 
CPU-Target: X32 / X64 / ARMv5
Nach oben

Beitragvon af0815 » 25. Feb 2017, 13:43 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon wp_xyz » 25. Feb 2017, 13:54 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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;
wp_xyz
 
Beiträge: 2249
Registriert: 8. Apr 2011, 08:01

Beitragvon af0815 » 25. Feb 2017, 16:26 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon mschnell » 26. Feb 2017, 11:25 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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
mschnell
 
Beiträge: 3157
Registriert: 11. Sep 2006, 09:24
Wohnort: Krefeld
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ) | 
CPU-Target: X32 / X64 / ARMv5
Nach oben

Beitragvon af0815 » 28. Feb 2017, 15:20 Re: Lazarus Programm soll Delphi Berlin DLL einbinden.

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).
af0815
 
Beiträge: 3257
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

• Themenende •

Zurück zu Windows



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

porpoises-institution
accuracy-worried