Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Dll Problem (https://www.delphipraxis.net/94299-dll-problem.html)

mr.unbekannt 19. Jun 2007 17:40


Dll Problem
 
Hi @all,

ih habe ein Problem beim laden einer dll. nachfolgend erstmal den quelltext der dll und des projectes:
Delphi-Quellcode:
unit main;

interface

uses
  sharemem,Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, extctrls;

type
  Tfmmain = class(TForm)
    PageControl1: TPageControl;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public

    { Public declarations }
  end;
  TShow_DLLForm = procedure; stdcall;

var
  fmmain: Tfmmain;
  Show_DLLForm: TShow_DLLForm;

implementation


{$R *.dfm}

procedure Tfmmain.Button1Click(Sender: TObject);
var
  dllhandle: Thandle;

begin
  dllhandle := 0;
  try
    dllhandle := LoadLibrary('Project1.dll');
    @Show_DLLForm := GetProcAddress(dllhandle,'startdll');
    if @Show_DLLForm <> nil then
      Show_DLLForm;              
  finally
    FreeLibrary(dllhandle);
    showmessage('fertsch');
  end;

end;


end.
Delphi-Quellcode:
library Project1;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }


uses
  sharemem,
  SysUtils,
  Classes,
  dialogs,
  comctrls,
  main in 'main.pas';




{$R *.res}





procedure startdll;
begin
  fmmain.Button1.Caption := 'test';
end;

begin


end.
mein problem ist nun, dass ich die dll lade, aber die procedure Show_DLLForm nil ist und somit nicht ausgeführt wird. wo liegt der fehler? Habe leider bis jetzt keine Erfahrungen mit Dll's

Muetze1 19. Jun 2007 17:58

Re: Dll Problem
 
1. ShareMem in der DPR des Projektes als erste Unit eintragen und nicht in der Formulardatei des Projektes.
2. Überprüfen des LoadLibrary() Rückgabewertes und nicht fest daran glauben, dass es schon klappen wird.
3. Die DLL sollte auch die Funktion exportieren, dies tut sie bisher noch gar nicht. Von daher ist sie auch nicht in der DLL zu finden.

Ich gebe keine Codebeispiele, da alles dazu in der Hilfe zu finden ist.

Apollonius 19. Jun 2007 18:04

Re: Dll Problem
 
Es kann natürlich sein, dass ich mich täusche, aber für mich sieht es irgendwie ungesund aus, dass die Unit Main in der DLL eingebaut ist. Das heißt doch, dass es jetzt im Projekt und in der DLL zwei verschiedene Formulare gibt, und das ist wahrscheinlich nicht, was du erreichen willst.

Luckie 19. Jun 2007 18:20

Re: Dll Problem
 
Das ist nicht nur ungesund, sondern wiedrspricht auch den Prinzipien einer DLL, die eigentlich programmunabhägig Funktionen bereitstellen sollte.

mr.unbekannt 19. Jun 2007 18:24

Re: Dll Problem
 
wie funktioniert diese exportfunktion in diesem beispiel? die dll findet er.

Apollonius 19. Jun 2007 18:26

Re: Dll Problem
 
Vor begin...end. gibt es einen Exports-Abschnitt. Ich verlinke hier einfach mal auf dsdt, da wird es erklärt.

nitschchedu 19. Jun 2007 18:29

Re: Dll Problem
 
1. Du kannst in der Dll nicht auf was zugreifen was er nicht kennt !!!
2. Lass ja diese ShareMem Unit weg die ist sinloss !!!

Ich kann dir ne Beispiel machen wenn du willst wie das geht ;-)

Luckie 19. Jun 2007 18:36

Re: Dll Problem
 
Zitat:

Zitat von nitschchedu
2. Lass ja diese ShareMem Unit weg die ist sinloss !!!

Kannst du diese Aussage auch begründen?

nitschchedu 19. Jun 2007 18:45

Re: Dll Problem
 
Natürlich ;-) also wenn ich die Unit einbinde kann ich String übergeben (Tolle sache), wenn ich dabei berücksichtige das die DLL um einige Byts größer würd.
Das geht viel leichter in dem ich PChar nehme gibts null Probleme.

Ich mache hier gleich mal das Bsp:

DLL :
Delphi-Quellcode:
library Project1;

uses
  SysUtils,
  Classes,
  dialogs,
  comctrls;




{$R *.res} 





function startdll: PChar;
var
 Test: String;
begin
  Test := 'test';
  Result := PChar(Test);
end;

begin

exports
 startdll;

end.
So und nun das Programm:

Delphi-Quellcode:
type
 TTest = function: PChar;

procedure Tfmmain.Button1Click(Sender: TObject);
var
  dllhandle: Thandle;
  myFunc: TTest;
begin
  dllhandle := 0;
  try
    dllhandle := LoadLibrary('Project1.dll');
    @myFunc := GetProcAddress(dllhandle,'startdll');
    if @myFunc <> nil then
      form1.edit.text := myFunc;
  finally
    FreeLibrary(dllhandle);
    showmessage('fertsch');
  end;

end;
So habs jetzt aber noch nicht getestet ;-)

Muetze1 20. Jun 2007 23:48

Re: Dll Problem
 
Zitat:

Zitat von nitschchedu
Das geht viel leichter in dem ich PChar nehme gibts null Probleme.

Das gibt bei einem solchen kleinen Prog wohl keine Probleme, aber trotzdem ist das Beispiel murks. Du gibst als Result einen PChar zurück. Diesen erhälst du aus einer temporären Umwandlung eines Strings. Der String wiederrum ist eine lokale Variable und verliert somit ihre Gültigkeit mit verlassen der Procedure. Damit wird mit dem Rücksprung aus deiner DLL Procedure der String "test" ungültig und damit die von der temporären Umwandlung erzeugte PChar. Das der PChar vllt. noch richtig im Hauptprogramm ausgegeben wird bedeutet einfach nur, dass der Speicher wo die Daten des Strings "test" lagen noch nicht wieder erneut verwendet wurden. Das ist aber ein Spiel mit dem Feuer - da empfehle ich dir lieber Lotto, da sind die Gewinnchancen nicht so hoch, aber man hat bei einem Gewinn länger was davon als von dem Result deiner Funktion.

Der Code ist ein sehr gutes Beispiel wie man es nicht macht.

Frage dazu an dich, nitschchedu: Wenn dies so einfach ist, warum gibt es keine WinAPI Funktion welche einen PChar zurück gibt sondern alle wollen einen Buffer und dessen Grösse haben, den sie dann vollschreiben.

Grundlegend könntest du deinen Code auch schnell und simpel richtig gestalten: Deklariere die Variable "test" global in der DLL (somit verliert sie ihre Gültigkeit erst mit entladen der DLL).

EDIT: Ein Tutorial dazu welches alles nötige erklärt und aufzeigt wie man es machen könnte: Luckie's DLL String Artikel

nitschchedu 21. Jun 2007 19:01

Re: Dll Problem
 
Geh weg mit Luckis Anleitung damit kannste Anfänger behängen. Stimmt schon das das Falsch war,
natürlich sollte man sich vor ne Speicher beantragen "GetMem" und dann das ganze übergeben.
Das Problem ist nemlich das
1. Man darauf achten muss das man keine Dyn. Speicher bereiche Übergibt.
2. Speicher übergibt der nicht schon wieder freigeben wurden ist.

Im klar text jede Seite muss den Speicher erreichen und muss auch wiessen wie groß der Bereich ist.

Der Fehler hat sich in der Eile eingeschlichen und dann hatte ich schon lange nicht mehr mit einer DLL gearbeitet.

brechi 21. Jun 2007 19:42

Re: Dll Problem
 
@nitschchedu: nachdem du deine Kenntnisse in der Sprache Deutsch aufgebessert hast, darfst du dich gerne nochmal mit den Grundlagen der Sprache Pascal beschäftigen
(wer nämlich mit mit h schreibt ist dämlich [und wer es auch noch mit e schreibt ist ... :) ])

nitschchedu 21. Jun 2007 20:22

Re: Dll Problem
 
:x So biste zufrieden !!! ? Fühlste dich jetzt besser das du jemanden gezeigt hast der LRS hat und der ganz schnell Posten wollte wie man Deutsch schreibt ? Jetzt weiß ich wieder warum ich es hier vermeide leuten zuhelfen. :|

SirThornberry 21. Jun 2007 21:18

Re: Dll Problem
 
es geht eigentlich darum das du die ShareMem schlecht gemacht hast (was ja generell nicht falsch ist sondern eben Ansichtssache) aber deine Begründung dann total daneben ging. Denn deine Alternative zur ShareMem war Fehlerhaft und nicht brauchbar.

nitschchedu 21. Jun 2007 21:40

Re: Dll Problem
 
Das ich von ShareMem nichts halte ist eine Sache. Aber da ich versucht habe zuhelfen und dann mir gegen über sich auch noch im Ton vergriefen würd, finde ich zum Kotzen. Desweiteren auch die Leute die mehr Wiessen und dann so herrablassend zu einen sind. (Dies ist mir im Forum ihr schon mehrmals aufgefallen.)

Übrigens ist das hier auch Murks:
Zitat:

Du gibst als Result einen PChar zurück. Diesen erhälst du aus einer temporären Umwandlung eines Strings. Der String wiederrum ist eine lokale Variable und verliert somit ihre Gültigkeit mit verlassen der Procedure.
Der String wurde in den Result Speicher geladen, das bedeudet das PChar keine Verbindung mit String mehr hat.
Nun kann der String freigeben werden wie er will. Der Result Speicher ist dann drotzdem noch da und immer noch der Selber.
Und der Resultspeicher würd erst freigeben wenn das Programm ein Befehlsatzt weiter ist als der Aufruf der funktion.

Desweiteren kann man das ganze noch sichern in dem man die funktion in eine Klasse legt und die Klasse zurückgibt oder eben GetMem nihmt.

Luckie 21. Jun 2007 22:03

Re: Dll Problem
 
Zitat:

Zitat von nitschchedu
Geh weg mit Luckis Anleitung damit kannste Anfänger behängen.

Bitte was? :shock: Kannst du die Aussage mal begründen, warum meine Lösung angeblich nur was für Anfänger sei?


Zitat:

Zitat von nitschchedu
Aber da ich versucht habe zuhelfen und dann mir gegen über sich auch noch im Ton vergriefen würd, finde ich zum Kotzen.

Motzi hat es etwas blumig ausgedrück, in dem er das Wort "murks" benutzt hat, er hätte auch einfach "schlecht" sagen können. Meiner Meinung nach hat sich hier niemand dir gegenüber im Ton vergriffen. Einzig du hast überreagiert. Und dass du meinen Artikel als Anleitung für Anfänger abtust, ohne Begründung oder einen Vorschlag, wie es besser geht, finde ich auch nicht sehr gut.

Muetze1 21. Jun 2007 22:42

Re: Dll Problem
 
Zitat:

Zitat von nitschchedu
... und dann mir gegen über sich auch noch im Ton vergriefen würd, finde ich zum Kotzen. Desweiteren auch die Leute die mehr Wiessen und dann so herrablassend zu einen sind.

Ich hatte es nicht so dramatisch gemeint, aber warum ich es so bezeichnet habe (weil als Lösung gegenüber ShareMem angepriesen, aber komplett nicht nutzbar) wurde schon geschrieben. Herablassend oder beleidigen wollte ich trotzdem keinen, schliesslich geht es hier um das Programmieren und somit um Lösungen, u.a. in Codeform. Dazu will ich beitragen und keinen direkt ansprechen.

Auch weiss ich schon länger, dass du LRS hast und habe auch nie etwas dazu geschrieben und nehme darauf genauso Rücksicht. Genauso wenig will ich herablassend wirken. Und das ich mehr Wissen haben sollte, würde ich niemals behaupten und da ich deins nicht kenne, würde ich sowas nicht schreiben (siehe meine Signatur).

Zitat:

Zitat von nitschchedu
Übrigens ist das hier auch Murks:
Zitat:

Du gibst als Result einen PChar zurück. Diesen erhälst du aus einer temporären Umwandlung eines Strings. Der String wiederrum ist eine lokale Variable und verliert somit ihre Gültigkeit mit verlassen der Procedure.
Der String wurde in den Result Speicher geladen, das bedeudet das PChar keine Verbindung mit String mehr hat.
Nun kann der String freigeben werden wie er will. Der Result Speicher ist dann drotzdem noch da und immer noch der Selber.
Und der Resultspeicher würd erst freigeben wenn das Programm ein Befehlsatzt weiter ist als der Aufruf der funktion.

Der temporäre Typecast von dem String auf einen PChar macht nur folgendes:

-> Überprüfen das der String nicht leer ist und wenn nicht, einfach die Adresse des AnsiStrings für den PChar zurück geben (siehe LStrToPChar) - ansonsten gibt er die Adresse eines bei ihm fest abgelegten Nullbytes zurück.

Dann ist Ende der Procedure und er räumt den AnsiString ab. Sprich: er fügt eine Null bei der Länge ein und dekrementiert den Reference Counter (siehe LStrClr). Sonst passiert nichts weiter, es wird nichts kopiert und gar nichts. Von daher gibt es keinen "Result Speicher" - der PChar ist dann genauso tot wie der String.

Zitat:

Zitat von nitschchedu
Desweiteren kann man das ganze noch sichern in dem man die funktion in eine Klasse legt und die Klasse zurückgibt oder eben GetMem nihmt.

Die Klasse zurück geben? Du sagst selber, dass du kein ShareMem benutzt. Du sagst dann auch, dass dann keine Speicherbereiche (dynamischen) übertragen/übergeben werden sollen. Die Klasseninstanz liegt in genau einem solchen Speicher und ist davon genauso betroffen wie alles andere was du angemerkt hattest. Ausserdem ist die Frage der Typen bei der DLL und Delphi. Dies ist leider nicht so einfach und schön möglich wie bei C++.

Und GetMem() in der DLL? Und dann in der App freigeben? Dies würde nicht hinhauen, da es unterschiedliche Speicherverwalter sind (siehe Luckie's "Anfänger Tutorial"). Und wenn du das FreeMem() zum GetMem() in die DLL holst: Wann willst du denn FreeMem() aufrufen? Wann weisst du, dass die App den Speicher nicht braucht? Willst du dir eine immer länger werdende Liste in der DLL halten mit Speicher zum freigeben den du beim entladen der DLL freigegeben willst?

Bitte erkläre das nochmal genauer.

Zitat:

Zitat von Luckie
Motzi hat es etwas blumig ausgedrück, in dem er das Wort "murks" benutzt hat, er hätte auch einfach "schlecht" sagen können.

Ich weiß, dass du mich nicht magst, aber das du mich bisher wirklich jedesmal anders nennst, nur nicht bei meinem Nicknamen, fällt so langsam auf - oder sollte das "Motzi" eine Wertung mit beinhalten? :zwinker: :gruebel:

Luckie 21. Jun 2007 23:45

Re: Dll Problem
 
Ach mist, ich habe dich verwechselt. Ich meinte natürlich Muetze1. Und was heißt ich dich nicht mögen? Du bist mein Lieblings-DP-Mitglied. :kiss: :mrgreen:

nitschchedu 22. Jun 2007 16:04

Re: Dll Problem
 
Der Rechtschreibevorwurf ging an brechi !
So Anleitungen sind für Leute die es noch nicht wiessen (über das Thema) und es nun wiessen wollen.
Getest habe ich vieles und auch Überprüft mit deiner Anleitung (Die mal vor 2 Jahren in der Hand hatte) aber auch mit anderen.

Mutze1 würde ich es vorschlagen das er es mal Test und dann sich wundern Darf warum der Speicher nicht Frei ist auch wenn er den String Freigibt vor der Übergabe ;-).

Des weiteren werde ich zu den Thema nix mehr sagen.

Muetze1 22. Jun 2007 16:11

Re: Dll Problem
 
Zitat:

Zitat von nitschchedu
Mutze1 würde ich es vorschlagen das er es mal Test und dann sich wundern Darf warum der Speicher nicht Frei ist auch wenn er den String Freigibt vor der Übergabe ;-).

Habe ich getan, auf der Basis mit daneben laufendem Delphi mit einem Testprojekt ist der Beitrag entstanden...

nitschchedu 22. Jun 2007 16:35

Re: Dll Problem
 
Dann begründe mal warum es trotzdem geht ;-) Und ne aussage das es ein Spiel mit den Feuer ist akzeptiere ich nicht. (Dazu das geht bei mir jedes mal auch in Großen projekten und ohne Fehler).

Zitat:

Die Klasse zurück geben? Du sagst selber, dass du kein ShareMem benutzt.
Ist das ne frage wie das in einer Klasse geht oder was ?


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:12 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz