![]() |
DLL einbinden, in Klasse oder global
Hallo zusammen
ich habe eine DLL bekommen und ein beispiel code für delphi der auch gut funktioniert. In der .pas datei wird die Funktionalität der DLL bereitgestellt. in etwas so delphi7!
Delphi-Quellcode:
wie gesagt so funktioniert es wunderbar
unit SpsIo;
interface uses Classes; const spsDll = 'IPS7LNK.DLL'; function IPS7Open (IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord) : LongInt; stdcall; implementation function IPS7Open; external spsDll name 'IPS7Open'; end. wenn ich diese funktionen in eine klasse einbinden will hab ich mir das in etwa so vorgestellt
Delphi-Quellcode:
so gekapselt gibt es bei genau dieser funktion eine Access Violation bei andren funktionen auch mal ein EPrivilege error.
unit SpsIo;
interface uses Classes; const spsDll = 'IPS7LNK.DLL'; type TspsIo = class Address : string; handle : longInt; constructor create(Addr : String); private function IPS7Open (IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord) : LongInt; stdcall; end; implementation function TspsIo.IPS7Open; external spsDll name 'IPS7Open'; constructor TSpsIo.create(Addr: String); begin handle := -1; handle := IPS7Open(pChar(Addr),0,2,0,0,0); Address := Addr; end; .end wo ist da der Unterschied beim Aufrufen der Funktion IPS7Open. Meiner Meinug nach habe ich die Funktionen doch nur in der Klasse gekapselt! Oder bin ich da falsch gewickelt? Wäre schön wenn da mal jemand ein Auge draufwerfen könnte. Im vorraus schon mal vielen Dank Gruß Stefan |
Re: DLL einbinden, in Klasse oder global
Schau dir mal den Unterschied von Funktion und Methode an!
Du hast nix gekapselt, und warum willst du es überhaupt so machen? Das bringt doch gar nix. Wo willst du hin? |
Re: DLL einbinden, in Klasse oder global
hm ich wollte die code Vervollständigung nutzen. also dass ich bei Programm schreiben die klasse+'.' schreibe und das pullup menu mit den ganzen Klassen member aufgeht.
Aber du hast recht mir ist der Unterschied zwischen Methoden und Funktionen nicht so richtig klar! |
Re: DLL einbinden, in Klasse oder global
Dieses Menu bekommst du auch, wenn du die Unit hinschreibst:
Delphi-Quellcode:
Was du halt amchen kannst, ist den Aufruf in einer Klasse kapseln (also eine Methode nehmen und intern dann die Funktion aufrufen), und die Parameter mittels property setzen. Hilft aber im Programm nur, wenn du den Aufruf mehrmals (an verschiedenen Stellen) benötigst, oder noch andere DLL Aufrufe stattfinden. Oder bei dynamischen einbinden der DLL.
SpsIo. //--> jetzt kommt dieses Pulldown-Menu
Ganz abwegig ist die Kapselung nicht, aber eben anders machen. |
Re: DLL einbinden, in Klasse oder global
Zitat:
Uli. |
Re: DLL einbinden, in Klasse oder global
Hi,
Du kannst das Kapseln, aber dann nicht so, sondern:
Delphi-Quellcode:
TspsIo = class
public constructor create(Addr : String); function IPSOpen(IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord): LongInt; end; implementation const spsDll = 'IPS7LNK.DLL'; function IPS7Open (IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord) : LongInt; stdcall; external spsDll name 'IPS7Open'; function TSPSIO.IPSOpen(IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord): LongInt; begin Result := IPS7Open(IPAdr,Rack,Slot,RxTimeout,TxTimeout,ConnectTimeout); end; |
Re: DLL einbinden, in Klasse oder global
Das ganze hat nur ein paar Probleme/Hindernisse.
1. geht es witziger Weise teilweise, daß man Methoden so ex-/importieren kann, aber beim Erstellen und der Speicherverwaltung der Klasse kann man sich super leicht gravierende Probleme einfangen. (aber zum Glück willst du hier ja eine Funktion in eine Methode umwandeln und nicht eine Klassen-Methode ex- und importieren) Du kannst dir ja gern mal von meinem himXML die DLL-Version ansehn. - diese ist zwar offiziell nicht wirklich freigegeben, da sie einige kleine Macken hat, aber im Download isse mit drinnen. Alleine an dem Code siehst du schon, daß da so einiges an Drumrum gibt, damit es überhaupt geht. Abgesehn davon ist eine Methode keine Prozedur/Funktion, denn deine Methode hat einen "unsichtbaren" Parameter, welcher in der importierten Funktion fehlt. siehe #10 > ![]() |
Re: DLL einbinden, in Klasse oder global
TspsIo.IPS7Open
Wenn Du das so machst, ist das ein 8-Byte Pointer, nicht 4 byte, wie erwartet. Der Grund ist ein einfacher : Delphi braucht 4 Byte für die funktion (die nur einmal im Peicher ist und von allen erstellten Objekten diesen Typs verwendet wird und 4 Byte sind für das "Datensegment" deines Objekts, da der Code ja nicht weiss, wo deine Variablen sind für jede Instanz des Objektes. Solche 8-Byte pointer kann man afaik nicht exportieren. Dies ist ja auch sehr Delphi spezifisch und DLL sind dazu gedacht, mit allen Programmiersprachen zu funktionieren |
Re: DLL einbinden, in Klasse oder global
So was ähnliches wie Stefans Versuch geht tatsächlich:
Delphi-Quellcode:
Aufruf:
unit WindowsX;
interface uses Windows; function MessageBoxX(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; type TWindowsX = class class function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; static; end; implementation function MessageBoxX; external user32 name 'MessageBoxA'; class function TWindowsX.MessageBox; external user32 name 'MessageBoxA'; end.
Delphi-Quellcode:
Ist natürlich nicht wirklich OO, aber man könnte die importierten Routinen zumindest gruppieren und privat machen.
begin
MessageBoxX(0, 'Direkt', 'Direkt', 0); TWindowsX.MessageBox(0, 'Per Klasse', 'Per Klasse', 0); end. Edit: Das static hinterm stdcall ist wichtig - es beseitigt den Self-Pointer aus ![]() |
Re: DLL einbinden, in Klasse oder global
Ist eine class function nicht sowieso immer statisch?
|
Re: DLL einbinden, in Klasse oder global
@uligerhardt: auch einen Class-Procedur hat diesen versteckten Parameter Namens Self.
@General: Nein, nur wenn man sie auch zusätzlich noch als statisch deklariert |
Re: DLL einbinden, in Klasse oder global
Zitat:
Delphi-Quellcode:
type
TBaseClass = class of TBase; TBase = class class procedure Bla; virtual; end; TDerived = class(TBase) class procedure Bla; override; end; implementation { TBase } class procedure TBase.Bla; begin Writeln('TBase.Bla'); end; { TDerived } class procedure TDerived.Bla; begin Writeln('TDerived.Bla'); end;
Delphi-Quellcode:
Dazu wird der implizite Self-Pointer benötigt, den das static entfernt. Das Schlüsselwort wurde für Kompatibilität mit .NET eingeführt, weil das nur die Variante ohne Self beherrscht.
var
c: TBaseClass; begin c := TDerived; c.Bla; end; |
Re: DLL einbinden, in Klasse oder global
Zitat:
|
Re: DLL einbinden, in Klasse oder global
Bevor ihr hier solche Verrenkungen macht:
In folgendem Beispiel kann sich so eine Klasse erst lohnen:
Delphi-Quellcode:
Damit hat man auch gleich einen Container für die Parameter und kann hier noch weitere Funktionen kapseln. Bringt natürlich nur etwas, wenn man diesen Container auch benötigt.
unit Unit2;
interface uses Windows, Sysutils; type IPS7Exception = class(Exception); IPS7Open=function(IPAdr : PChar; Rack : LongWord; Slot : LongWord; RxTimeout : LongWord; TxTimeout : LongWord ; ConnectTimeout : LongWord) : LongInt; stdcall; TIPS7 = class Constructor Create; Destructor Destroy; override; private FDLL:THandle; FIPS7Open:IPS7Open; FConnectTimeout: LongWord; FRack: LongWord; FSlot: LongWord; FRxTimeOut: Longword; FTxTimeout: LongWord; FIPAdr: AnsiString; procedure SetConnectTimeout(const Value: LongWord); procedure SetIPAdr(const Value: AnsiString); procedure SetRack(const Value: LongWord); procedure SetRxTimeOut(const Value: Longword); procedure SetSlot(const Value: LongWord); procedure SetTxTimeout(const Value: LongWord); public property IPAdr:AnsiString read FIPAdr write SetIPAdr; property Rack :LongWord read FRack write SetRack; property Slot :LongWord read FSlot write SetSlot; property RxTimeOut:Longword read FRxTimeOut write SetRxTimeOut; property TxTimeout:LongWord read FTxTimeout write SetTxTimeout; property ConnectTimeout:LongWord read FConnectTimeout write SetConnectTimeout; function Open:Longword; end; implementation const spsDll = 'IPS7LNK.DLL'; { TIPS7 } constructor TIPS7.Create; begin FDLL:=Loadlibrary(spsDLL); if FDLL=0 then raise IPS7Exception.CreateFmt('Fehler beim Laden der DLL: %s', [syserrormessage(getlasterror)]); FIPS7Open:=GetProcAddress(FDLL,'IPS7Open'); if not assigned(FIPS7Open) then raise IPS7Exception.CreateFmt('Fehler beim LAden der Funktionsadresse: %s', [syserrormessage(getlasterror)]); end; destructor TIPS7.Destroy; begin FreeLibrary(FDLL); inherited; end; function TIPS7.Open: Longword; begin result:=FIPS7Open(PAnsiChar(FIPAdr),FRack,FSlot,FRxTimeout, FTxTimeout,FConnectTimeout); end; procedure TIPS7.SetConnectTimeout(const Value: LongWord); begin FConnectTimeout := Value; end; procedure TIPS7.SetIPAdr(const Value: String); begin FIPAdr := Value; end; procedure TIPS7.SetRack(const Value: LongWord); begin FRack := Value; end; procedure TIPS7.SetRxTimeOut(const Value: Longword); begin FRxTimeOut := Value; end; procedure TIPS7.SetSlot(const Value: LongWord); begin FSlot := Value; end; procedure TIPS7.SetTxTimeout(const Value: LongWord); begin FTxTimeout := Value; end; end. Zudem habe ich DLL noch dynamisch eingebunden. Dadurch führt ein Fehlen der DLL nicht gleich zum Nichtstarten des Programms. Bringt auch nur etwas, wenn das Programm auch ohne diese DLL einen Sinn macht. |
Re: DLL einbinden, in Klasse oder global
So, wie es Sirius gezeigt hat isses richtig! :thumb:
Vielleicht noch zwei kleine Kritikpunkte bzw. Verbesserungen: 1.) Die Open-Funktion gibt ein Handle (Referenz) zurück. Dieses Handle sollte im Objekt gespeichert werden und beim Freigeben des Objekts wird dann automatisch die Close-Funktion aufgerufen. Das Handle braucht der Anwender der Klasse wahrscheinlich gar nie zu Gesicht bekommen; das vereinfacht den Umgang mit der Klasse. 2.) Man könnte den Code in zwei Klassen splitten: Eine Klasse (Name: TIPS7_DLL) ist zuständig für das DLL-Handle und die Funktionszeiger in die DLL. Die andere Klasse (Name: TIPS7) stellt sozusagen eine Verbindung zur S7 dar. Der Anwender sieht nur die Klasse TIPS7. Intern verwendet TIPS7 ein Objekt der Klasse TIPS7_DLL (als Singleton implementiert) um die DLL-Funktionen aufzurufen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:37 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