![]() |
Eindeutiger Callback bei mehreren Instanzen des selben Programms
Hallo Forum,
ich habe ein Problem mit der Eindeutigkeit von Callbacks, wenn man mehrere Instanzen des selben Programms öffnet. Ich hatte hier bereits einen anderen Beitrag der in diesem Thema: "Delphi-DLL in C++ benutzen" beschrieben wurde. Nur kurz: - Die DLL existiert jetzt und funktioniert mit Delphi und C++. Es ging dabei darum, das mehrere Programme Daten miteinander austauschen und dazu eine DLL verwenden. Dabei meldet sich ein Programm bei der DLL an und kann dann mit anderen Teilnehmern Daten austauschen. Die Daten werden in ein Memory Mapped File ausgetauscht und wenn neue Daten eingetagen werden wird per Windows-Botschaft eine Nachricht gesendet so dass man darauf reagieren kann. Damit alle Teilnehmer an der DLL voneinander wissen tragen sie ihr Fenster-Handle ebenfalls in ein MMF ein, so daß jeder vom anderen weis. - Die grundlegenden Techniken sind also Memory Mapped Files, Botschaften senden und empfangen. - Ich würde dies gerne vereinfachen und das senden und empfangen von Botschaften durch die Verwendung von Callbacks ersetzen. - Ein kleiner Test mit einer DLL der ein Callback übergeben wird und ihn dann auslöst und einer Delphi-Applikation hat toll geklappt. - Jetzt wollte ich die Kommunikations-DLL entsprechend umbauen. Botschaften raus und statt dessen Adressen der Callbacks der einzelnen Applikationen im MMF einlagern, ABER wenn ich zwei Instanzen meiner Delphi-Test-Applikation öffne und den Funktionszeiger übergebe dann hat der Funktionszeiger beider Applikationen exakt die selbe Adresse. Das kann nicht gut gehen. Hat jemand eine Idee wie man das trotzdem mit Callbacks hinkriegt, denn ich würde meine Kommunikations-DLL gerne noch für Kommunikation mit anderen Programmiersprachen oder vielleicht sogar OpenOffice-Basic nutzen. Vielen Dank im voraus. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Die Adresse ist Relativ zum Speicherbereich der Anwendung .... ist auch schnell getestet
Delphi-Quellcode:
library callMe;
uses SysUtils, Classes,Dialogs; type TCallback=Procedure(I:Integer); var aCallBack:TCallback; aNr:Integer; {$R *.res} Procedure Init(Callback:TCallback;Nr:Integer); begin aCallBack := Callback; Showmessage(IntToStr(Integer(@Callback))); aNr := Nr; aCallBack(aNr); end; exports Init; begin end. TestUnit zum mehrfachstarten
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TCallback=Procedure(I:Integer); TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; Procedure DLLInit(cb:TCallback;Nr:Integer); external 'callme.dll' name 'Init'; implementation {$R *.dfm} Procedure myCallback(I:Integer); begin Form1.Caption := IntToStr(i); end; procedure TForm1.Button1Click(Sender: TObject); begin DLLInit(@myCallback,StrToInt(Edit1.Text)); end; end. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
@Bummi
Danke für die Antwort. (Der Quellcode sieht fast genau so aus wie meiner zum Testen!!). ABER. Nehmen wir an es gäbe drei Instanzen der Testanwendung, ich will sie mal mit EINS, ZWEI und DREI bezeichnen um sie auseinanderhalten zu können. Wie kann ich von EINS aus gezielt eine Callback an ZWEI oder DREI schicken? Wie muss die Adresse aussehen? Muss ich sie mit der Adresse der Anwendung kombinieren? Wie bekomme ich die Basis-Adresse beispielsweise von EINS heraus? Danke im voraus. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Delphi-Quellcode:
Wie macht sie es denn?
Dabei meldet sich ein Programm bei der DLL an und kann dann
Mit LoadLibrary und allem, was darüber abläuft, bekommt jeder Prozess seine eigene DLL-Instanz und derartige Callbacks (also Adresszeiger) gelten immer nur für den entsprechenden Prozess. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Die Frage dürfte eher sein wie Du die anderen Anwendungen überhaupt ansprechen sollst aus einer an eine Anwendung gebundene DLL.
Alle Adressen die Du speichern könntest befinden sich ja im Adressbereich der Hauptanwendung, die DLL hat so gesehen keinen eigenen Speicher wo sie beispielsweise Listen aller registrierten Anwendungen und sei es nur die HWND der Application verwalten könnte.... |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
@himitsu
@Bummi Es ist korrekt und war anfänglich auch mein Problem, das obwohl mehrere Anwendungen auf ein und die selbe DLL zugreifen damit noch kein Datenaustausch zwischen den Anwendungen möglich ist. Der Trick liegt darin, das die DLL auf gemeinsam genutzten Speicher auch unter shared memory oder memory mapped files bekannt zurückgreift. Den kann jede Instanz der DLL beschreiben und lesen. Meine DLL benutzt für unterschiedliche Zwecke mehrere MMFs. Eine dieser MMFs ist der Header in dem die wichtigsten Informationen über die Struktur der anderen MMFs und die bekannten Teilnehmer in Form einer Liste von Fenster-Handles hinterlegt sind. Mit Hilfe der Fenster-Handles und PostMessage können jetzt über jede Instanz der DLL die anderen Teilnehmer angefunkt werden wenn sich was getan hat. Damit erstmal die Funktionsweise (und das ist komplett durchgetestet in Delphi und in C++). Für mich ist die DLL sehr wichtig, deshalb möchte ich bevor sie richtig zum Einsatz kommt noch möglichst vereinfachen, auch dahin gehend das andere Programmiersprachen damit zurechtkommen. Es wird immer Grenzen geben, aber ich sehe ein Problem im abfangen der Windows-Botschaften und herausfinden des eigenen Fenster-Handles. Deshalb möchte ich die DLL gerne auf Callbacks umstellen, dabei sollten die Addressen der Callback-Funktionen anstatt der Fenster-Handles im oben beschriebenen MMF abgelegt werden. Und jetzt nochmal die Frage: Ist es möglich, das ein Programm ein anderes (oder eine zweite Instanz des selben) Programm über einen Callback erreicht? Wie müßten die Addressen dann aussehen? Nochmals Danke im voraus. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
IMHO dürfte es allein aus Sicherheitsgründen nicht möglich sein so zu arbeiten, aber vielleicht kennt jemand einen Trick ....
|
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Nur weil der Programmcode der DLL in einer MMF liegt, ist sie dennoch nicht "funktional" geshared, denn der sonstige arbeitspeicher bleibt dennoch getrennt.
PS: DLL und EXE sind sowieso schon imm er (mindestens seit WinNT) auf sowas ähnlichen, wie eine MMF verteilt, damit Windows sich den RAM erspart, da diese dann nur einmal in den speicher geladen werden muß. Allerdings mit der option CopyOnWrite ... also wenn eine anwendung was ändert, wird der Speicher kopiert, die anwendung bekommt das eigene Stück RAM und bei den anderen bleibt es unverändert. So, aber da dennoch der Speicher der restlichen Anwendungen getrennt ist, selbst wenn man die DLL via MMF überall reingequetscht hat, wird sie dennoch im Kontext der Anwendungen ausgeführt und "externe" Zeiger sind bleiben nur im entsprechenden Programmkontext gültig. Der einzige Weg für sowas ist z.B. ein OutOfProcess-COM-Server. Dieser läuft in einem getrennten Prozess (meist einem DLL-Host), die vielen Programme greifen via COM-Lib auf dessen Funktionen zu, aber da die Funktionen in dem gemeinsam genutzen DLL-Host laufen, haben alle wirklich mit der selben DLL zu zun. PS: Botschaften (Messages) werden ja an die anderen Prozesse gesendet und dann auch dort drüben verarbeitet. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
@himitsu
Erst mal Danke für die Antwort, aber ich scheine mich nicht klar ausgedrückt zu haben. Es wird nicht die ganze DLL in ein MMF ausgelagert und es geht auch nicht darum dass alle Anwendungen auf die selben Funktionen zurückgreifen, sondern um die Möglichkeit dass sich Prozesse gegenseitig eine Nachricht zukommen lassen wenn Daten ausgetauscht werden. 1. Eine Anwendung ruft die DLL auf und nutzt die Funktion INIT mit dem Parameter Hnd in dem sich der Fenster-Handle der aufrufenden Anwendung befindet. 2. Der Handle wird in ein Array eingetragen und in ein MMF geschrieben. 3. Alle bekannten Mitglieder (siehe Array) erhalten eine Windows-Botschaft und sollten jetzt dieses MMF mit dem Array neu einlesen -> damit wissen wieder alle voneinander. 4. Die Anwendungen müssen selbstverständlich Windows-Botschaften verarbeiten können. Das ist im Grossen und Ganzen der Mechanismus über den die Kommunikation realisiert wird. Mein Ansinnen ist es Anwendern der DLL die Arbeit zu erleichtern -> kein Fenster-Handle heraussuchen und keine Botschaftsverarbeitung. Ich weiß auch gar nicht ob das alle Programmier- oder Skriptsprachen können. Die Wahrscheinlichkeit der Portierbarkeit scheint jedoch zu steigen wenn ich eine Callback verwenden kann. Das ist bisher gescheitert! Lösungsansatz: - Der Mechanismus mit den Botschaften klappt, hab ich ja getestet. - DLLs können direkt keine Botschaften verarbeiten, ABER wenn man ihnen ein TForm mitgibt, die unsichtbar bleibt .... - ... kann man sich deren Fenster-Handle und Botschafts-Verarbeitung zu nutze machen. - Wenn dann eine Botschaft eintrifft, kann man ja immer noch einen prozeduralen Zeiger (Callback) benutzen um der Anwendungsinstanz der die DLL angehört eine Nachricht zukommen zu lassen. Das werde ich jetzt mal ausprobieren, wenn's klappt poste ich den Quell-Code. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Du kannst innerhalb der DLL ein MessageOnlyWindow erstellen, dem schickst du die Messages.
Das Ganze in einer Klasse/Interface gepapselt, wo der Benuter einen Callback registrieren kann. Wird nun die Message empfangen, dann rufst du den Callback auf. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
@himitsu
In der Kürze liegt die Würze, du hast die von mir umrissene Idee schön zusammengefaßt. Hier jetzt der versprochene Quell-Code und Hinweise: Man muss das Test-Programm mindestens zweimal aufrufen. Es zeigt dann den Handle aus der DLL an. Man muss dann diesen Handle über kreuz in den jeweiligen Target-Eingabefeldern eintragen. Danach kann man: - Die LED direkt ein- und ausschalten. - Die LED über Callback ein- und ausschalten. - Die LED des Targets umschalten. Achtung die Handles der anderen Anwendungen werden noch nicht über MMF verwaltet!! Quellcode der DLL:
Delphi-Quellcode:
Quellcode der Testanwendung:
library cbDLL;
uses JclSysInfo, SysUtils ,Classes ,Forms ,Windows ,Messages ; {$R *.res} type // Definition des Callbacks TMyCallback = procedure (State: Integer); stdcall; // Klasse zum Senden und Empfangen von Botschaften. TMyForm = class(TCustomForm) private procedure MsgHandler(var Msg : TMessage); message WM_USER; end; var TheCallback : TMyCallback; MyForm : TMyForm; State: Boolean; SaveExit: Pointer; // Auslösen des Callbacks procedure OnOff(State: Integer); begin if assigned(TheCallback) then TheCallback(State); end; // Einschalten procedure CallOn; stdcall; begin OnOff(1); end; // Ausschalten procedure CallOff; stdcall; begin OnOff(0); end; // Botschaft empfangen procedure TMyForm.MsgHandler(var Msg : TMessage); begin State := not State; if State then CallOn else CallOff; end; // Callback Initialisieren. procedure Init(cb: TMyCallback); stdcall; begin TheCallback := cb; end; // Eigenen Handle ermitteln; Adresse an die man senden kann. function GetHandle: Longword; stdcall; begin result := MyForm.Handle; end; // Botschaft senden. procedure Post(Target: Longword); stdcall; begin PostMessage(Target, WM_USER, 0, 0); end; // Freigeben von Ressourcen procedure LibExit; begin MyForm.Free; // ... als letzte Anweisung ExitProc := SaveExit; // Kette der Exit-Prozeduren wiederherstellen end; // Export-Tabelle exports Init ,CallOn ,CallOff ,GetHandle ,Post ; // Initialisierung begin // ... als erste Anweisungen SaveExit := ExitProc; // Kette der Exit-Prozeduren speichern ExitProc := @LibExit; // Exit-Prozedur LibExit installieren State := False; MyForm := TMyForm.CreateNew(nil); end.
Delphi-Quellcode:
Damit sehe ich das Thema hiermit für mich als gelöst an.
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TFunc = procedure(State: Integer); stdcall; TStdProcProt = procedure; stdcall; TInitProcProt = procedure (AFunc: TFunc); stdcall; TGetHndProcProt = function : Longword; stdcall; TPostProcProt = procedure (Target: Longword); stdcall; TForm1 = class(TForm) shpLED: TShape; btnOn: TButton; btnOff: TButton; btnROn: TButton; btnROff: TButton; Label1: TLabel; lblMyHnd: TLabel; GroupBox1: TGroupBox; GroupBox2: TGroupBox; GroupBox3: TGroupBox; Label2: TLabel; edtTrgt: TEdit; btnToggle: TButton; procedure btnOnClick(Sender: TObject); procedure btnOffClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnROnClick(Sender: TObject); procedure btnROffClick(Sender: TObject); procedure btnToggleClick(Sender: TObject); private { Private-Deklarationen } fDLLInstance : THandle; fDLLInit : TInitProcProt; fDLLOn : TStdProcProt; fDLLOff : TStdProcProt; fDLLGetHandle : TGetHndProcProt; fDLLPost : TPostProcProt; public { Public-Deklarationen } end; procedure SetLED(State: Integer); stdcall; var Form1: TForm1; implementation {$R *.dfm} procedure SetLED(State: Integer); stdcall; begin if State = 0 then Form1.shpLED.Brush.Color := clGreen else Form1.shpLED.Brush.Color := clLime; end; procedure TForm1.btnOnClick(Sender: TObject); begin SetLED(1); end; procedure TForm1.btnOffClick(Sender: TObject); begin SetLED(0); end; procedure TForm1.FormCreate(Sender: TObject); begin fDLLInstance := 0; @fDLLInit := nil; @fDLLOn := nil; @fDLLOff := nil; @fDLLGetHandle := nil; @fDLLPost := nil; fDllInstance := LoadLibrary('cbDLL.dll'); if fDllInstance <> 0 then begin @fDLLInit := GetProcAddress(fDLLInstance, 'Init'); @fDLLOn := GetProcAddress(fDLLInstance, 'CallOn'); @fDLLOff := GetProcAddress(fDLLInstance, 'CallOff'); @fDLLGetHandle := GetProcAddress(fDLLInstance, 'GetHandle'); @fDLLPost := GetProcAddress(fDLLInstance, 'Post'); end; fDLLInit(SetLED); lblMyHnd.Caption := IntToStr(fDLLGetHandle); end; procedure TForm1.btnROnClick(Sender: TObject); begin fDLLOn; end; procedure TForm1.btnROffClick(Sender: TObject); begin fDLLOff; end; procedure TForm1.btnToggleClick(Sender: TObject); begin fDLLPost(StrToInt(edtTrgt.Text)); end; end. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Wieder mal ein Beispiel das für andere User nicht zu gebrauchen ist.
Die Unit JclSysInfo kennt warscheinlich nur der Ersteller. |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
JCL = JEDI Code Library
![]() ![]() ![]() ![]() ... ![]() PS: ![]() |
AW: Eindeutiger Callback bei mehreren Instanzen des selben Programms
Erster Treffer bei Google:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:25 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 by Thomas Breitkreuz