Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Variablen unter Programmen austauschen
HenryHux - Sa 06.11.10 19:16
Titel: Variablen unter Programmen austauschen
Hi,
wie der Titel schon sagt, suche ich einen Weg unter Programmen eine Variable auszutauschen.
Die Programme sind alle von mir selber geschrieben, und sind alle recht umfangreich, deswegen auch lieber ein Austausch,
als alles in ein Projekt mit mehreren Formen zu stecken.
Lg
Henry
jaenicke - Sa 06.11.10 19:31
Der Möglichkeiten gibt es viele, je nach Anwendungszweck. Das Stichwort hier ist IPC (Interprozesskommunikation).
Möglichkeiten:
- Integervariablen z.B. via normaler Messages in wParam oder lParam
- WM_COPYDATA
- Pipes
- MMFs
- ...
Tranx - Sa 06.11.10 20:33
Eine Möglichkeit ist auch die Inifiles-Datei. Du schreibst in dem einen Programm eine Prozedur zur Speicherung der Daten in ein Inifile und mit dem anderen Programm lädst Du die Daten wieder ein.
Sicher, etwas antiquiert, aber es funktioniert.
uall@ogc - Sa 06.11.10 22:16
mit MemoryMappedFiles relativ einfach gemeinsamen Speicherbereich verwenden
HenryHux - Sa 06.11.10 22:21
Ok, danke erstmal für die ganzen Möglichkeiten, ich werd mich noch mal melden,
ggf. mit der Lösung, mit der ichs geschafft hab, dank euch=)
Lg
Henry
Implementation - Sa 06.11.10 22:21
Du könntest dir eigene Messages deklarieren.
Auf den ersten Blick geh'n damit nur Zahlen, aber mit etwas Nachdenken ...
Hab' mir damit mal eine kleine IPC-Bibliothek (NRDE) geschrieben, mit der auch Strings möglich waren.
NRDE ist aber leider so fest in ein Framework (NWL) verankert, dass ich es nicht so einfach herauslösen kann.
jaenicke - Sa 06.11.10 23:40
Tranx hat folgendes geschrieben : |
Sicher, etwas antiquiert, aber es funktioniert. |
Aber nur so lange wie keine parallelen Zugriffe erfolgen usw. :roll:
Ob nun INIs oder andere Dateien, wie willst du die Zugriffe synchronisieren?
Da sind andere Lösungen sehr sehr viel einfacher.
HenryHux - So 07.11.10 12:12
Ok, also vom anderen Thread wieder back.
Meine Empfehlung probiert das Synchronisieren nicht mit MMF :D
Ich bin jetzt dabei es mit messages zu versuchen, sieht immoment doch etwas erfolgverpsrechender aus.
Meine Funktion:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| function action1() : integer; var MyRecord: PMyRecord; cds: TCopyDataStruct; hWnd1, hWnd2, hWnd3, hWnd4: THandle; begin repeat GetMem(MyRecord, sizeof(TMyRecord)); until myrecord.b=false; myrecord.b:=true; cds.dwData := 0; cds.cbData := sizeof(TMyRecord); cds.lpData := MyRecord; hWnd1 := FindWindow(nil, 'QND1'); hWnd2 := FindWindow(nil, 'QND2'); hWnd3 := FindWindow(nil, 'QND3'); hWnd4 := FindWindow(nil, 'QND4'); SendMessage(hWnd1, WM_COPYDATA, Handle, Integer(@cds)); SendMessage(hWnd2, WM_COPYDATA, Handle, Integer(@cds)); SendMessage(hWnd3, WM_COPYDATA, Handle, Integer(@cds)); SendMessage(hWnd4, WM_COPYDATA, Handle, Integer(@cds)); end; |
(Werde noch rausnehmen, dass sich das eigene Fenster ne Meldung schickt)
Und der Empfänger:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TMain.WMCOPYDATA(var msg: TWMCopyData); var MyRecord: PMyRecord; b: Boolean; s: String[255]; begin b := PMyRecord(msg.CopyDataStruct.lpData)^.b; CheckBox1.Checked := b; Edit1.Text := s; end; |
Kann das damit gut klappen?
Habe die befürchtung, dass wenn 1 oder 2 Fenster absürzen dann die anderen automatisch untergehen.
Lg
Henry
bummi - So 07.11.10 12:19
er erkennt es nicht weil Du:
Delphi-Quelltext
1:
| function action1() : integer; |
Deklariert hast
als entweder
Delphi-Quelltext
1:
| function Form1.action1() : integer; |
oder besser gleich
Delphi-Quelltext
1:
| function action1(HWND:THandel) : integer; |
LG
Thomas
jaenicke - So 07.11.10 12:21
Mit WM_COPYDATA habe ich selbst noch nie gearbeitet. Ich persönlich finde es zu umständlich. ;-)
Was mir aber auffällt ist, dass du den Speicher nirgends wieder freigibst.
bummi - So 07.11.10 12:27
@jaenicke
Ich verwende es sehr gern, man muss es nur etwas Kapseln dann wird es handlicher.
HenryHux - So 07.11.10 14:39
So, denke habe es jetzt so hinbekommen, dass es einigermaßen gut läuft.
Hier ein Teil der Funktion:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| begin try repeat GetMem(MyRecord, sizeof(TMyRecord)); until myrecord.b=false; myrecord.b:=true; cds.dwData := 0; cds.cbData := sizeof(TMyRecord); cds.lpData := MyRecord; wincaption(); wait(1000); myrecord.b:=false; cds.dwData := 0; cds.cbData := sizeof(TMyRecord); cds.lpData := MyRecord; wincaption(); finally FreeMem(MyRecord, sizeof(TMyRecord)); end; end; |
Wincaption is ne andere Funktion:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| function wincaption() : integer; begin if main.Caption='QND 1' then begin hWnd2 := FindWindow(nil, 'QND 2'); hWnd3 := FindWindow(nil, 'QND 3'); hWnd4 := FindWindow(nil, 'QND 4'); SendMessage(hWnd2, WM_COPYDATA, hWnd2, Integer(@cds)); SendMessage(hWnd3, WM_COPYDATA, hWnd3, Integer(@cds)); SendMessage(hWnd4, WM_COPYDATA, hWnd4, Integer(@cds)); end else if main.Caption='QND 2' then begin hWnd1 := FindWindow(nil, 'QND 1'); hWnd3 := FindWindow(nil, 'QND 3'); hWnd4 := FindWindow(nil, 'QND 4'); SendMessage(hWnd1, WM_COPYDATA, hWnd1, Integer(@cds)); SendMessage(hWnd3, WM_COPYDATA, hWnd3, Integer(@cds)); SendMessage(hWnd4, WM_COPYDATA, hWnd4, Integer(@cds)); end else if main.Caption='QND 3' then begin hWnd1 := FindWindow(nil, 'QND 1'); hWnd2 := FindWindow(nil, 'QND 2'); hWnd4 := FindWindow(nil, 'QND 4'); SendMessage(hWnd1, WM_COPYDATA, hWnd1, Integer(@cds)); SendMessage(hWnd2, WM_COPYDATA, hWnd2, Integer(@cds)); SendMessage(hWnd4, WM_COPYDATA, hWnd4, Integer(@cds)); end else if main.Caption='QND 4' then begin hWnd1 := FindWindow(nil, 'QND 1'); hWnd2 := FindWindow(nil, 'QND 2'); hWnd3 := FindWindow(nil, 'QND 3'); SendMessage(hWnd1, WM_COPYDATA, hWnd1, Integer(@cds)); SendMessage(hWnd2, WM_COPYDATA, hWnd2, Integer(@cds)); SendMessage(hWnd3, WM_COPYDATA, hWnd3, Integer(@cds)); end; end; |
Was haltet ihr davon?
Gut gelöst, fehlerhaft, verbesserungswürdig?
Danke,
Lg
Henry
bummi - So 07.11.10 14:57
Ich würde erstens prüfen ob das Handle gültig ist
und zweitens als Senderhandle nicht das Reciverhandle verwednen.
LG
Thomas
jaenicke - So 07.11.10 15:43
Also das sieht alles sehr sehr komisch aus. :hair:
Schon alleine das
HenryHux hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| begin try repeat GetMem(MyRecord, sizeof(TMyRecord)); until myrecord.b=false; myrecord.b:=true; | |
Du bekommst einen neuen Speicherplatz reserviert und statt den zu füllen schaust du was drin ist und holst du dir ggf. einen neuen? :shock:
(Ohne den zuerst reservierten wieder freizugeben wohlgemerkt.)
Das ist wie wenn du einen Gebrauchtwagen kaufst, in das Handschuhfach schaust und siehst, dass da ein Fensterkratzer drin ist und deshalb ein neues kaufst (und beim ersten einfach den Schlüssel wegwirfst und es damit unbenutzbar stehen lässt).
Also ich verstehe nicht was das eigentlich werden soll. SendMessage wartet bis die Message abgearbeitet ist. Und du bekommst da auch ein Ergebnis (das du einfach wegwirfst). Warum wertest du das nicht aus? Und wartest stattdessen
nach der Abarbeitung der Messages durch das Zielprogramm eine Sekunde? :gruebel: :nixweiss:
Delete - So 07.11.10 15:49
Ich habe doch einen Link zu funktionierenden Beispielcode gepostet. Warum wird da jetzt wieder wild ohne Sinn und Verstand rumgebastelt?
HenryHux - So 07.11.10 16:03
Hmm, ok.
Habe mir das so überlegt, dass er prüft ob die Variable true ist, wenn ja dann erstmal wieder besetzt und dann am ende wieder freigibt.
Dachte, wenn ich keine Schleife reinsetze, dann macht er einfach gar nichts, wenn die Variable besetzt ist.
An das Beispiel habe ich mich eig gehalten, nur dass das nichts ständig synchronisiert, sondern einfach ne Nachricht schreibt.
Wie sollte denn der Programmablauf dann sonst aussehen?
Kann ich die Schleife weglassen?
Lg
Henry
delfiphan - So 07.11.10 16:29
Wie wär's z. B. mit SOAP?
Man muss sich heutzutage nicht mehr mit lowest level Dingern wie named pipe, MMF oder WM_COPYDATA rumschlagen.
jaenicke - So 07.11.10 16:39
Ich finde aber man sollte es zuerst machen. Denn sonst hat man kein Verständnis für das was da alles passiert. Und daraus resultieren dann schlechtere Ergebnisse.
Wenn man Pipes, XML und TCP-Verbindungen schon einzeln benutzt hat, kann man (finde ich) viel besser mit SOAP usw. arbeiten.
Delete - So 07.11.10 16:47
Ich weiß nicht, was ihr für ein Problem mit WM_COPYDATA habt. Es ist doch ohne Probleme zu Hand haben und wenn man mal schnell kleine Datenmengen austauschen will bestens geeignet. Mit MMFs und Pipes muss man da schon einen wesentlich höheren Aufwand treiben. Hinzukommt, das man zum Synchronisieren auch noch eine Nachricht schicken muss. Da kann ich die Daten doch auch gleich mit der Nachricht verschicken.
delfiphan - So 07.11.10 17:19
Luckie hat folgendes geschrieben : |
Ich weiß nicht, was ihr für ein Problem mit WM_COPYDATA habt. |
Das erkläre ich dir gern. WM_COPYDATA ist low-evel, platformabhängig, proprietär (das Datenformat) und architektonisch aus der Steinzeit. Mit WM_COPYDATA kannst du vielleicht schnell ein record mit Integers und ShortStrings (non-Unicode) rüberschicken. Sobald es etwas weiter gehen soll und du z. B. Request-Reponse haben willst, schreibst du erst mal ein eigenes Protokoll, ein eigenes Message Format und schreibst auch noch das ganze Mapping von deinem Service Contract und Data Contracts selbst - vorausgesetzt du hast überhaupt eines. Da du auch hoffentlich nicht nach dem Prinzip Fire & Forget arbeitest, möchtest du bestimmt auch detaillierte Rückmeldungen über mögliche Fehler auf der Gegenseite haben. Ausserdem möchtest du vielleicht synchrone Aufrufe tätigen können und nicht auf eine (eventuelle) Antwort per WM_COPYDATA warten. Wenn Morgen das Requirement reinflattert, dass du das ganze auch noch bitte über pipes und tcp zugänglich machen sollst, wirst du erst mal ein paar Tage oder Wochen beschäftigt sein. Mit den richtigen Entscheidungen hast du das alles in 5 Minuten gemacht, denn das Rad muss man nicht mehr neu erfinden.
HenryHux - So 07.11.10 17:45
Isn die Methode die oben so steht in Ordnung, oder gibts da größere Fehler?
Lg
HenryHux - Mo 08.11.10 17:06
Hat sich alles geklärt,danke.
Mit dem Synchronisieren habe ich es letzendlich nicht hinbekommen, ist mir noch zu schwer, hatte bis jetzt noch kaum Kontakt mit der Win API.
Habe es jetzt anders geregelt, ich lese die Sekunden aus und habe jedem Fenster eine feste Anzahl von Sekunden zugeordnet.
Damit klappt es denke noch effizienter und besser als mit irgendeinem Synchronisieren.
Danke trotzdem.
Lg
Henry
BenBE - Di 09.11.10 07:30
@Luckie: Du klingst ja fast so, als wäre ein kleiner Semaphor oder Mutex zu viel Aufwand!
@HenryHux: Spätestens, wenn Dir dein Programm auf einem System mal gewaltig um die Ohren fliegt, weil Windows2 Programmen gleichzeitig den Zugriff auf die Daten gibt, die da unsynchronisiert rumflattern, weißt Du, dass Du das hättest vermeiden können.
Und SOOOOO schwer ist das auch nicht:
Programminitialisierung:
Alle Programme legen (den gleichen!!!) Semaphor/Mutex an (holen sich da ein Handle, bei Mutexen handhabt Windows das etwas anders als POSIX, ACHTUNG!)
Lesen von Daten:
- Programm X sperrt den Semaphor/Mutex
- Programm X schaut, ob's Änderungen gab
- Programm X KOPIERT sich seinen Status
- Programm X gibt den Semaphor/Mutex wieder frei
- Programm X verarbeitet das Änderungsereignis (falls vorhanden)
Schreiben von Daten:
- Programm X sperrt den Semaphor/Mutex
- Programm X schreibt die neuen Daten
- Programm X gibt den Semaphor/Mutex wieder frei
- Programm X Signalisiert anderen Prozessen Änderungen (oder andere Programme pollen)
In Code sind das bei richtiger Implementierung kaum mehr als 20 Zeilen je Routine. Spart einem RICHTIG viel Arbeit beim Debugging!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!