32 bit DLL Beispielcode

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
king558
Beiträge: 25
Registriert: So 27. Aug 2023, 16:44

32 bit DLL Beispielcode

Beitrag von king558 »

Ich wollte einen Test mit Freelibrary durchführen. Was mache ich falsch bzw, wie ändere ich es korrekt. Wenn das folgende Projekt mit Defaulteinstellung in der Projektoption kompiliere, funktioniert es. Wenn ich diese Projekt -> Projektoption -> Compiler option -> Config and Target -> Target OS auf Win32 und Target CPU family auf i386 ändere, dann bekomme ich Datensalat anstatt Hello World. Es spielt doch keine Rolle, wie es geändert wird, string entweder AnsiString oder Widestring automatisch geändert wird, PChar wird dann etweder zu PAnsiChar oder PWideChar sein, daher würde es auf jeden Fall funktioniert, dies ist leider nicht wie erwartet.

Code: Alles auswählen

library DynamicLibrary;


{$mode objfpc}{$H+}
(*{$modeswitch UNICODESTRINGS}*)


uses
  SysUtils
  { you can add units after this };


// Das Unterprogramm der DLL
function convertToUppercase( data: string ): PChar;
var
  upperData : string;
begin
     upperData := UpperCase( data );
     Result := PChar( upperData );
end;


// export function
exports
  convertToUppercase;


begin
end.

Code: Alles auswählen

program DllTester;


{$mode objfpc}{$H+}
(*{$modeswitch UNICODESTRINGS}*)


uses
  Windows;


function dllFunc: string;
type
  // Definition des aufzurufenden Unterprogramms, wie es in der einzubindenden DLL definiert ist
  PConvertToUppercase = function( data: string ): PChar; stdcall;

var
  // Legt eine passende Variable (Datenfeld) für das DLL-Unterprogramm an
  convertToUppercase: PConvertToUppercase;
  // Legt einen Handle für den Handle der DLL an
  dllHandle: THandle;

begin
    // Ermittelt den Handle der zuverwendenden Library
    dllHandle := LoadLibrary( PChar( 'DynamicLibrary.dll' ) );

    // Prüft, ob das Laden der DLL erfolgreich war
    if dllHandle <> 0 then
    begin
         // Weisst der Variablen funStringZurueck die Adresse des Unterprogrammaufrufs zu
         // 'convertToUppercase' aus der DLL DLLTest.dll zu.
         Pointer( convertToUppercase ) := GetProcAddress( dllHandle, 'convertToUppercase' );

         // Prüft, ob eine gültige Adresse zurück gegeben wurde
         if @convertToUppercase <> nil then Result := convertToUppercase( PChar( 'hallo welt' ) );
    end;

    // Freigabe des Arbeitsspeichers
    convertToUppercase := nil;
    FreeLibrary( dllHandle );

end;

begin
     WriteLn( dllFunc );
     ReadLn;
end.

Benutzeravatar
KodeZwerg
Beiträge: 103
Registriert: Mo 6. Feb 2023, 11:04

Re: 32 bit DLL Beispielcode

Beitrag von KodeZwerg »

die library:

Code: Alles auswählen

library TheDll;
{$mode objfpc}{$H+}

uses
  SysUtils;

function ConvertToUppercase(const AString: string): string; stdcall; export;
begin
  Result := UpperCase(AString);
end;

exports
  ConvertToUppercase;

begin
end.
das programm:

Code: Alles auswählen

program TestDll;
{$IFDEF MSWINDOWS}{$APPTYPE CONSOLE}{$ENDIF}

uses
  SysUtils;

function ConvertToUppercase(const AString: string): string; stdcall; external 'TheDLL.dll' name 'ConvertToUppercase';

begin
  WriteLn(ConvertToUppercase('hello world'));
  ReadLn;
end.
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

king558
Beiträge: 25
Registriert: So 27. Aug 2023, 16:44

Re: 32 bit DLL Beispielcode

Beitrag von king558 »

KodeZwerg hat geschrieben:
So 27. Aug 2023, 18:15
die library:

Code: Alles auswählen

library TheDll;
{$mode objfpc}{$H+}

uses
  SysUtils;

function ConvertToUppercase(const AString: string): string; stdcall; export;
begin
  Result := UpperCase(AString);
end;

exports
  ConvertToUppercase;

begin
end.
das programm:

Code: Alles auswählen

program TestDll;
{$IFDEF MSWINDOWS}{$APPTYPE CONSOLE}{$ENDIF}

uses
  SysUtils;

function ConvertToUppercase(const AString: string): string; stdcall; external 'TheDLL.dll' name 'ConvertToUppercase';

begin
  WriteLn(ConvertToUppercase('hello world'));
  ReadLn;
end.
VIelen Danke für deine Hilfe, aber deinen Vorschlag ist ja, statisch linking, ich wollte es als dynamisch gelinkte haben.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 170
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: 32 bit DLL Beispielcode

Beitrag von Jorg3000 »

Moin!
Ich denke das Problem ist einfach nur, dass man nicht einfach einen String an einen DLL-Funktion übergeben kann, oder?
Füge einfach mal "const" vor dem String-Parameter ein. Das führt dazu, dass nur der String-Pointer übergeben wird. Vielleicht funktioniert das schon.
Alternativ: Klassischerweise würde man keinen String, sondern ein PChar übergeben. In der DLL muss es dann aus dem PChar-Zeiger erst wieder in einen String kopiert werden, z.B. mittels s:=String(APChar);
Grüße, Jörg

Benutzeravatar
KodeZwerg
Beiträge: 103
Registriert: Mo 6. Feb 2023, 11:04

Re: 32 bit DLL Beispielcode

Beitrag von KodeZwerg »

Da Du als Typ PChar verwendest, muss, soweit ich weiß, in der Library und auch in dem Programm Speicher reserviert und nach Abschluß freigegeben werden.
Du solltest allerdings PChar zu PAnsiChar oder PWideChar abändern um Zukunft-sicher zu sein falls sich mal der Typ von PChar ändert.
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

Mathias
Beiträge: 6210
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: 32 bit DLL Beispielcode

Beitrag von Mathias »

Alternativ: Klassischerweise würde man keinen String, sondern ein PChar übergeben.
cdecl würde ich auch noch einfügen, so wird deine lib kompatibel zu C.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

PascalDragon
Beiträge: 834
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: 32 bit DLL Beispielcode

Beitrag von PascalDragon »

king558 hat geschrieben:
So 27. Aug 2023, 16:56
Ich wollte einen Test mit Freelibrary durchführen. Was mache ich falsch bzw, wie ändere ich es korrekt. Wenn das folgende Projekt mit Defaulteinstellung in der Projektoption kompiliere, funktioniert es. Wenn ich diese Projekt -> Projektoption -> Compiler option -> Config and Target -> Target OS auf Win32 und Target CPU family auf i386 ändere, dann bekomme ich Datensalat anstatt Hello World. Es spielt doch keine Rolle, wie es geändert wird, string entweder AnsiString oder Widestring automatisch geändert wird, PChar wird dann etweder zu PAnsiChar oder PWideChar sein, daher würde es auf jeden Fall funktioniert, dies ist leider nicht wie erwartet.
Wenn du String-Typen zwischen Modulen ausstauscht, dann musst du sichergehen, dass du einen geteilten MemoryManager einsetzt, da dies sonst früher oder später zu Problemen führen wird.

Besser ist es komplett nur PChar oder WideString zu verwenden (letzterer geht nämlich auch über geteilte Verwaltungsfunktionen von Windows).
KodeZwerg hat geschrieben:
Mo 28. Aug 2023, 18:20
Da Du als Typ PChar verwendest, muss, soweit ich weiß, in der Library und auch in dem Programm Speicher reserviert und nach Abschluß freigegeben werden.
Du solltest allerdings PChar zu PAnsiChar oder PWideChar abändern um Zukunft-sicher zu sein falls sich mal der Typ von PChar ändert.
Im aktuellen main kann dies bereits je nach Kompilationseinstellung der Fall sein. Man kann jedoch seinen Code auch so aufbauen, dass sie bezüglich diesen Unterschieds agnostisch sind.
Mathias hat geschrieben:
Mo 28. Aug 2023, 19:08
Alternativ: Klassischerweise würde man keinen String, sondern ein PChar übergeben.
cdecl würde ich auch noch einfügen, so wird deine lib kompatibel zu C.
Unter Windows wird normal stdcall genutzt. Es kann aber auch winapi genutzt werden, welcher unter Windows (mit Ausnahme von Windows CE) equivalent zu stdcall ist und auf anderen System equivalent zu cdecl (ja, der Name ist nicht optimal, aber er ist Delphi-kompatibel).
FPC Compiler Entwickler

king558
Beiträge: 25
Registriert: So 27. Aug 2023, 16:44

Re: 32 bit DLL Beispielcode

Beitrag von king558 »

PascalDragon hat geschrieben:
Di 29. Aug 2023, 21:42
king558 hat geschrieben:
So 27. Aug 2023, 16:56
Ich wollte einen Test mit Freelibrary durchführen. Was mache ich falsch bzw, wie ändere ich es korrekt. Wenn das folgende Projekt mit Defaulteinstellung in der Projektoption kompiliere, funktioniert es. Wenn ich diese Projekt -> Projektoption -> Compiler option -> Config and Target -> Target OS auf Win32 und Target CPU family auf i386 ändere, dann bekomme ich Datensalat anstatt Hello World. Es spielt doch keine Rolle, wie es geändert wird, string entweder AnsiString oder Widestring automatisch geändert wird, PChar wird dann etweder zu PAnsiChar oder PWideChar sein, daher würde es auf jeden Fall funktioniert, dies ist leider nicht wie erwartet.
Wenn du String-Typen zwischen Modulen ausstauscht, dann musst du sichergehen, dass du einen geteilten MemoryManager einsetzt, da dies sonst früher oder später zu Problemen führen wird.

Besser ist es komplett nur PChar oder WideString zu verwenden (letzterer geht nämlich auch über geteilte Verwaltungsfunktionen von Windows).
KodeZwerg hat geschrieben:
Mo 28. Aug 2023, 18:20
Da Du als Typ PChar verwendest, muss, soweit ich weiß, in der Library und auch in dem Programm Speicher reserviert und nach Abschluß freigegeben werden.
Du solltest allerdings PChar zu PAnsiChar oder PWideChar abändern um Zukunft-sicher zu sein falls sich mal der Typ von PChar ändert.
Im aktuellen main kann dies bereits je nach Kompilationseinstellung der Fall sein. Man kann jedoch seinen Code auch so aufbauen, dass sie bezüglich diesen Unterschieds agnostisch sind.
Mathias hat geschrieben:
Mo 28. Aug 2023, 19:08
Alternativ: Klassischerweise würde man keinen String, sondern ein PChar übergeben.
cdecl würde ich auch noch einfügen, so wird deine lib kompatibel zu C.
Unter Windows wird normal stdcall genutzt. Es kann aber auch winapi genutzt werden, welcher unter Windows (mit Ausnahme von Windows CE) equivalent zu stdcall ist und auf anderen System equivalent zu cdecl (ja, der Name ist nicht optimal, aber er ist Delphi-kompatibel).
Danke sehr für eure Hilfe. Lazarus bzw. Freepascal ist meines Gefühl nach um einiges instabiler als Delphi IDE. Viele Fehler sind nicht aussagekräftig und die Analyse führt zu mehr Zeitaufwand.

Benutzeravatar
KodeZwerg
Beiträge: 103
Registriert: Mo 6. Feb 2023, 11:04

Re: 32 bit DLL Beispielcode

Beitrag von KodeZwerg »

king558 hat geschrieben:
Di 29. Aug 2023, 23:23
Lazarus bzw. Freepascal ist meines Gefühl nach um einiges instabiler als Delphi IDE.
In wie fern instabil?
Wenn Du so eine Aussage machst bitte auch begründen oder exemplarisch ein Beispiel machen.
king558 hat geschrieben:
Di 29. Aug 2023, 23:23
Viele Fehler sind nicht aussagekräftig
Welche Fehler sind nicht aussagekräftig genug?
Wenn Du so eine Aussage machst bitte auch begründen oder exemplarisch ein Beispiel machen.
king558 hat geschrieben:
Di 29. Aug 2023, 23:23
die Analyse führt zu mehr Zeitaufwand.
Das liegt vielleicht an der Umstellung von Delphi zu Lazarus aber so genau kann ich das jetzt auch nicht kommentieren da bei mir weder die IDE noch der Compiler instabil sind und meist ein klick ausreicht um mich zu einer fehlerhaften Zeile springen zu lassen wobei dies analog zu Delphi ein identischer langer Zeitaufwand ist.
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

king558
Beiträge: 25
Registriert: So 27. Aug 2023, 16:44

Re: 32 bit DLL Beispielcode

Beitrag von king558 »

KodeZwerg hat geschrieben:
Mi 30. Aug 2023, 03:05
king558 hat geschrieben:
Di 29. Aug 2023, 23:23
Lazarus bzw. Freepascal ist meines Gefühl nach um einiges instabiler als Delphi IDE.
In wie fern instabil?
Wenn Du so eine Aussage machst bitte auch begründen oder exemplarisch ein Beispiel machen.
king558 hat geschrieben:
Di 29. Aug 2023, 23:23
Viele Fehler sind nicht aussagekräftig
Welche Fehler sind nicht aussagekräftig genug?
Wenn Du so eine Aussage machst bitte auch begründen oder exemplarisch ein Beispiel machen.
king558 hat geschrieben:
Di 29. Aug 2023, 23:23
die Analyse führt zu mehr Zeitaufwand.
Das liegt vielleicht an der Umstellung von Delphi zu Lazarus aber so genau kann ich das jetzt auch nicht kommentieren da bei mir weder die IDE noch der Compiler instabil sind und meist ein klick ausreicht um mich zu einer fehlerhaften Zeile springen zu lassen wobei dies analog zu Delphi ein identischer langer Zeitaufwand ist.
Du hast schon recht, ich habe früher nur Delphi programmiert, die IDE in Delphi ist um vielfach einfacher. z.B. In Lazarus wenn die in Projektoption allein Target OS auf Win32 ändere und Target CPU auf default belasse, bekomme ich nach Schließen dann die Warning. "The current FPC has no config file. It will probaly miss some units". Ich habe neben Win64 version auch 32 bit version installiert, für Neueinsteiger bzw. Umsteiger wäre diese Meldung misverstöndlich.

Besser wäre, "fpc.config for 32 bit version cannot be found, please locate the config file or create a new one. If 32 bit fpc is not installed, please download it." Dann weiss man ungefähr welche config Datei es sucht und was ich machen könnte. Ich nehme an, da Freepascal bzw. Lazarus eher kostenslos ist, wird hier die Benutzerfreundlichkeit eher zweirangig.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6217
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: 32 bit DLL Beispielcode

Beitrag von af0815 »

king558 hat geschrieben:
Mi 30. Aug 2023, 22:46
Besser wäre, "fpc.config for 32 bit version cannot be found, please locate the config file or create a new one. If 32 bit fpc is not installed, please download it." Dann weiss man ungefähr welche config Datei es sucht und was ich machen könnte. Ich nehme an, da Freepascal bzw. Lazarus eher kostenslos ist, wird hier die Benutzerfreundlichkeit eher zweirangig.
Das 'besser' wäre auch missverständlich, du musst dir bei Lazarus und den FPC immer vor Augen halten, das sehr viele Targets in allen möglichen und unmöglichen Kombinationen vorhanden sind. Und genaugenommen weis Lazarus nicht unbedingt von allen Targets die noch kommen werden im FPC. Vor allen muss man die Zweiteilung FPC/Lazarus immer im Hinterkopf haben, dagegen ist D monolitischer aufgebaut.

Ja es ist eine komplett andere IDE, die halt (großteils) Sourcecode kompatibel ist (auch alte Bugs/Features von D werden emuliert ! ). Ich habe früher viele Jahre in D gearbeitet und bin jetzt nicht mehr in der Lage ohne Einarbeitung noch ein Projekt in D zu erstellen. Ich habe es mal zum Spass versucht, mich aber über die Umständlichkeit bei D geärgert. Ja es kommt immer drauf an, was sein 'Hauptsystem' ist. Je nachdem empfindet man die anderen umständlich :-) Ist Natur der Sache.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten