Delphi-Version: 5
C++ DLL in Delphi unter Linux verwenden
Kann man eine DLL, die zur Verwendung von C++ Builder gedacht ist, auch unter Delphi verwenden, wenn ja wie?
Ich würde das mal grundsätzlich annehmen. Aber bevor ich da was versuche, frage ich zur Sicherheit mal nach. [ Möchte vorausschicken, dass ich C-Code ein wenig lesen kann, aber ansonsten mit C-Programmierung Null-Erfahrung habe ] Ich habe halt hier eine DLL (libQPLLinux1612-86_64.so) für Linux, die für den Aufruf von C++-Programmen gedacht ist (es handelt sich hier um die DEBENU bzw. Foxit QuickPDF-Library). Hier habe ich neben der .so-Datei folgende Dateien: FoxitQPLLinuxDPP1612.h datei (C++ Import Header) (ca. 2000 Zeilen) FoxitQPLLinuxDPP1612.cpp datei (C++ import Class) (ca. 7000 Zeilen) Ich würde wahrscheinlich nur 1-2 Dutzend Funktionen aus der DLL benötigen. In der .h -(Header) Datei stehen Dinge wie
Code:
in der cpp stehen dann die Funktionen, wie z.B.:
"int UnlockKey(const std::wstring& LicenseKey);"
Code:
Für die Windows-Version gibt es auch eine Delphi-Import-Datei für eine Windows-QPDF-DLL. Interessanterweise steht dort: "// This file was generated by an automated process".
"int FoxitQPLLinuxCPP1612::UnlockKey(const std::wstring& LicenseKey)
{ if (loadError) return 0; return FoxitQPLUnlockKey(instanceID, WideStringParm(LicenseKey)); }" Man kann da mit Delphi also auch die DLL verwenden (statt der auch existierenden DCU-Version). Für die Linux-DLL-Version gibt es sowas leider nicht. Aber vom Grundsatz müsste ich doch einfach den C++Code in Pascal umschreiben können (und mich da an der DLL-Implementierung für Windows orientieren) und dann sollte die .so doch auch mit Delphi nutzbar sein, oder? Geht ja zumindest mit FMX-Linux auch, wo ja auch eine .so-Datei zum Einsatz kommen. Gibt es da evtl. irgendwelche Generatoren, die einem den C++Code in Delphi-Pascal umwandeln? |
AW: C++ DLL in Delphi verwenden
Das sollte klappen, ja.
Ja, es gibt automatische Konverter, aber an einer manuellen Nachbearbeitung geht meistens kein Weg vorbei. Oft geht es manuell auch schneller. Dafür gibt es aber einen per Package in Delphi integrierbaren Helper: http://rvelthuis.de/programs/convertpack.html |
AW: C++ DLL in Delphi unter Linux verwenden
OK, danke.
Ich habe mal mit der Umsetzung für Linux / Delphi angefangen. Die DLL lädt man unter Linux per "dlopen", das funktioniert soweit auch, ich erhalte ein gültiges handle. Die Entsprechung von GetProcAdress ist unter Linux "dlsym", aber da habe ich ein Problem. Unter Delphi (Windows) siehts so aus (verkürzt):
Delphi-Quellcode:
Unter C++ findet aber wohl so eine Art Typecast statt, da sieht es so aus:procedure AssignProc(var Proc: Pointer; ProcName: PAnsiChar); begin Proc := GetProcAddress(FDLLHandle, ProcName); end; ... AssignProc(@DebenuPDFLibraryUnlockKey, 'DPLUnlockKey');
Code:
Die Zuweisung in der AttachFunction sieht so aus (leicht gekürzt):
FoxitQPLUnlockKey = (FoxitQPLFuncType121)AttachFunction("DPLUnlockKey");
Code:
FoxItQPLFunctType ist in der .h-Datei so deklariert:
void* FoxitQPLLinuxCPP1612::AttachFunction(const char* funcName, bool ignoreError)
{ void* address = dlsym(soHandle, funcName); return address; }
Code:
Was bedeutet das für die Übernahme nach Delphi? So hätte ich es mal angenommen, funktioniert aber nicht:
typedef int (*FoxitQPLFuncType121)(int, wchar_t*);
Delphi-Quellcode:
Proc := dlsym (FDLLHandle, ProcName); // Hier erhalte ich einen Fehler "Segmentations fault (11).
In der Klasse habe ich das so deklariert, muss das evtl. anders sein (C-Paramenter-Reihenfolge, etc?):
Delphi-Quellcode:
In der C++-Klasse ist es so definiert:type TDebenuPDFLibraryDLL1612 = class private FLibraryLoaded: Boolean; FDLLHandle: Cardinal; FInstanceID: Integer; ... DebenuPDFLibraryUnlockKey: function(InstanceID: Integer; LicenseKey: PWideChar): Integer; stdcall; ... end;
Code:
Jemand eine Idee, was ich hier ändern müsste?
typedef int (*FoxitQPLFuncType121)(int, wchar_t*);
FoxitQPLFuncType121 FoxitQPLUnlockKey; |
AW: C++ DLL in Delphi unter Linux verwenden
Zitat:
Delphi-Quellcode:
auf einen validen nullterminierten String zeigt? Anders kann ich mir den SegFault hier beim Aufruf eigentlich nicht erklären. Deine Type Definitions und der ganze Rest haben hier eigentlich noch gar keinen Einfluss auf irgendwas.
ProcName
|
AW: C++ DLL in Delphi unter Linux verwenden
OK, danke, der Tipp war gut. Da stimmte ein Bezug zum DLL-Namen nicht, so dass die Datei gar nicht geladen werden konnte.
Interessanterweise hatte ich das gedebugt, der Debugger zeigte mir aber einen Wert <> 0 für das Handle an (obwohl tatsächlich null). Da scheint es ein kleines Debug-Problem unter Linux zu geben? Wie auch immer, jetzt funktioniert es... Was mir allerdings nicht gelingt, ist der richtige Aufruf der Unlockkey-Function, ich erhalte (trotz richtigem Key) immer Null zurück, müsste aber 1 sein. Muss ich evtl. DebenuPDFLibraryUnlockKey: function(InstanceID: Integer; LicenseKey: PWideChar): Integer; stdcall; ändern in DebenuPDFLibraryUnlockKey: function(InstanceID: Integer; LicenseKey: PWideChar): Integer; cdecl; Oder noch was anderes (denn diese Änderung allein bringt es leider auch nicht)... |
AW: C++ DLL in Delphi unter Linux verwenden
Char* auf C-Seite ist im Normalfall ein PAnsiChar in Delphi.
|
AW: C++ DLL in Delphi unter Linux verwenden
Nein, mit PAnsiChar komme ich leider auch nicht weiter
In C++ ist die Funktion wie folgt deklariert:
Code:
Also das sieht für mich eindeutig nach Widestring aus. In der Windows-Unit, welche den Zugriff auf die Windows-QPDF-Dll ermöglicht, geht es auch per Widechar...
int FoxitQPLLinuxCPP1611::UnlockKey(const std::wstring& LicenseKey)
{ if (loadError) return 0; return FoxitQPLUnlockKey(instanceID, WideStringParm(LicenseKey)); } |
AW: C++ DLL in Delphi unter Linux verwenden
|
AW: C++ DLL in Delphi unter Linux verwenden
Zitat:
wie ist die function WideStringParm deklariert? Wo ich mir nicht sicher bin ist die calling convention, ich denke es müsste cdecl sein...... |
AW: C++ DLL in Delphi unter Linux verwenden
.. kommt es nicht zu Problemen weil wchar_t unter Linux 4 Byte groß ist.
wstring basiert auf wchar_t. Delphi hat meines Wissens keinen (String)character type der 4 Byte groß ist. Grüße Klaus |
AW: C++ DLL in Delphi unter Linux verwenden
Ich denke da hat Klaus recht,
Benutze zum trappen der wchar_t Parameter die MarshaledAString typen. Genau so wie es Embarcadero letztendlich in der runtime macht, scheu einfach in die source....... Ich mache nichts mit Delphi Linux deshalb, weiss ich da auch nicht mehr aber denke die Source der Runtime sollte helfen |
AW: C++ DLL in Delphi unter Linux verwenden
In C++ ist WideStringParam so deklariert:
Code:
In der Unit für den Zugriff auf die Windows-Version-DLL ist es so deklariert:
wchar_t* WideStringParm(const std::wstring& strParm)
{ wchar_t* sp; int length = (int)strParm.length(); if (length == 0) { sp = NULL; } else { wchar_t wordArray[length]; for (int charX = 0; charX < length; charX++) { wordArray[charX] = (wchar_t)(strParm[charX]); } sp = (wchar_t*)FoxitQPLCreateBuffer(instanceID, length * 4); FoxitQPLAddToBuffer(instanceID, (char*)sp, (char*)wordArray, length * 4); } return sp; }
Delphi-Quellcode:
Hier fällt natürlich in der Tat auf, dass der Buffer P * 2 ist, in der C++-Variante für die Linux-Version P * 4;
function StringParm(const ParmValue: WideString; var HasNulls: Boolean): PWideChar;
var P: Integer; begin HasNulls := False; if ParmValue = '' then begin Result := nil; end else begin HasNulls := True; P := Length(ParmValue); Result := PWideChar(DebenuPDFLibraryCreateBuffer(FInstanceID, P * 2)); DebenuPDFLibraryAddToBuffer(FInstanceID, Pointer(Result), @ParmValue[1], P * 2); end; end; @FritzeW: Kann denn MarshaledA wirklich richtig sein, das ist doch letztlich nur ein Pointer auf Ansistring? |
AW: C++ DLL in Delphi unter Linux verwenden
Zitat:
|
AW: C++ DLL in Delphi unter Linux verwenden
OK, das mit dem Hinweis des 4-Byte Char-Typs unter Linux war der richtige Tipp:
Wenn ich die Strings derart manipuliere, dass jeweils nach einem Char ein #0 folgt, kann ich die Aufrufe, wo Strings übergeben müssen, tätigen und es funktioniert. stdcall war übrigens doch richtig. Gibt es dafür vielleicht schon eine fertige Systemfunktion (für die oben beschriebene Manipulation der Strings)? |
AW: C++ DLL in Delphi unter Linux verwenden
Zitat:
eventuell auch mit varianten Records. Oder mal bei Embacadero nachfragen wann Delphi (!=C++) char32_t unterstützen wird. Auf eine ältere .so Datei (vor c++ 11) kannst Du nicht zugreifen -oder? Da sollte wchar_t noch 16 Bit haben. Grüße Klaus |
AW: C++ DLL in Delphi unter Linux verwenden
Liste der Anhänge anzeigen (Anzahl: 2)
Ich habe jetzt einfach eine einfache Funktion ("StringTo4") geschrieben, welche einen String wie im vorherigen Beitrag beschrieben umwandelt und immer wenn die DLL mit Stringwerten angesprochen werden soll, wird der über diesen Aufruf der Funktion übergeben.
Das funktioniert soweit ganz gut, ich kann die QPDF-Library öffnen, Informationen auslesen, etc. Nur wenn ich Strings zurück erhalte, da muss ich noch was anpassen (eben im umgekehrten Sinne), da sonst wegen der #0 Zeichen immer nur ein Zeichen zurückgeliefert wird (z.B. beim Auslesen des Inhaltsverzeichnisses aus der PDF-Datei). Anliegend mal ein Screenshot, der belegt, dass ich nun mit der Quick-PDF-Library unter Linux eine PDF-Datei mit meinem PDF-Manager-Programm einlesen und anzeigen kann (Nachtrag: Auslesen des IV funktioniert auch schon, siehe Screenshot 2). Ich werde das Programm kurzerhand für Linux fertig stellen und wenn ich das erledigt habe, werde ich einen kurzen Blog-Beitrag erstellen, wo ich genau beschreiben werde, was man machen muss, damit man als Delphi-Anwender diese .so-Library auch mit Delphi unter Linux verwenden kann. Danke schon mal für alle Hilfestellungen hier.:thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:02 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