| Autor |
Nachricht |
Xion
       

Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Hi,
hier ein kleines Tutorial darüber, wie man zwei Programme miteinander kommunizieren lassen kann.
Zuerst erstellen wir zwei neue Projekte in Delphi. Die Namen der Form ändern wir auf "TutorialForm1" bzw. "TutorialForm2", die Caption auf "Window of TutorialForm1" bzw "Window of TutorialForm2".
Anmerkung: Bei all den Beispielen die wir im folgenden machen, müssen (logischerweise) zum testen beide Programm laufen, damit sie sich unterhalten können
Kapitel 1 - Befehle
Die einfachste Nachricht ist die, die keine Erklärung benötigt. Diese entspricht in etwa einer procedure ohne Parameter.
Zuerst müssen wir uns auf einen Namen einigen, damit beide Seiten wissen was denn überhaupt gemeint ist.
Dafür deklarieren wir const WM_HELLO=WM_USER+1; in beiden Programmen.
WM_USER stellt einen Bereich dar, der für den Programmierer freigehalten wird, so dass wir nicht in Konflikt mit den systeminternen Messages kommen (wie WM_KEYDOWN z.B.). Eine Liste der reservierten Messages ist in der Unit "messages" zu finden.
In Programm1 fügen wir einen Button und ein Memo-Feld ein und zudem folgenden Code für Button1.OnClick:
Dieser Code sucht erstmal nach dem Fenster, dass wir ansprechen möchten (Klasse "TTutorialForm2"). Wird es gefunden (h<>0), dann schicken wir die Nachricht "WM_HELLO" zu ihm.
In Programm2 fügen wir ein Memo-Feld ein. Jetzt fehlt nur noch die Empfangs-procedure.
Dieser Code ist auch sehr einfach. Die procedure SomeoneSaysHello wird immer dann aufgerufen, wenn die message WM_HELLO empfangen wird.
Moderiert von Christian S.: Topic aus Windows API verschoben am Mi 10.02.2010 um 20:14
Einloggen, um Attachments anzusehen!
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
Zuletzt bearbeitet von Xion am Sa 13.02.10 17:12, insgesamt 4-mal bearbeitet
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Kapitel 2 - Informationen austauschen
Die erweiterte Version besteht jetzt darin, den messages noch Informationen beizupacken. Dazu erweitern wir das vorherige Beispiel um die Funktion, dass Programm2 eine Antwort als String an Programm1 verschickt.
Dazu erweitern wir die Empfangs-Funktion in Programm2
cds ist das record, dass unsren String aufnimmt. Danach schicken wir eine message mit Pointer auf diesem Record an Programm1. Dem aufmerksamen Leser ist vielleicht aufgefallen, dieses mal wurde FindWindow mit dem zweiten Parameter verwendet, dieser verlangt statt der Klasse den Fenster-Titel.
Jetzt brauchen wir in Programm1 noch eine Empfangs-Procedure:
Hier wird die Information wieder extrahiert.
Einloggen, um Attachments anzusehen!
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
Zuletzt bearbeitet von Xion am Sa 13.02.10 17:13, insgesamt 2-mal bearbeitet
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Kapitel 3 - Unfreiwillige Zugriffe
Machmal möchte man in einem fremden Programm Knöpfe drücken, Felder ausfüllen oder Edit-Felder auslesen. Dazu muss man allerdings die Struktur des fremden Programms zumindest grob kennen. Versuchen wir nun, ohne Programm2 abzuändern, in das Memo-Feld von Programm2 zu schreiben.
Dazu fügen wir erstmal einen zweiten Button in Programm1 ein und verwenden folgenden Code:
Das handle finden wir über das Caption des Fensters, das man ja bei fremden Fenstern leicht sieht. Soweit so gut. Jetzt benötigen wir aber Informationen, wie es in Programm2 aussieht (angenommen wir würden den SourceCode davon nicht kennen). Dazu verwende ich das Programm "WinSpector", das ist kostenlos und ziemlich gut.
Der zeigt mir für Programm2 folgendes:
FindWindowEx findet ein Sub-Handle von dem Fenster mit Handle H. Leider kann man Labels deshalb (soweit ich weiß) nicht auslesen, da sie kein eigenes Handle haben. Mit PostMessage schicken wir dann ein WM_KeyDown mit dem Zeichen 190 (=Punkt) an das Memo.
Statt einen Tastendruck zu simulieren ist es oft besser, besonders wenn man mehrere Zeichen einfügen will, den Text direkt zu setzen. Da jedoch WM_SETTEXT den alten Text ersetzen, lesen wir zuerst den Text aus, fügen dann in diesem Beispiel die Uhrzeit hinzu und schreiben es zurück.
Mit WM_GETTEXTLENGTH lesen wir zuerst die Länge des bereits im Memo vorhandenen Textes. Danach holen wir diesen Text mit WM_GETTEXT, hängen die Uhrzeit an und setzen den Text des Memos mit WM_SETTEXT.
Wir fragen übrigens bei WM_GETTEXT ein Zeichen mehr ab, als wir abgefragt haben. Dieses Zeichen ist das abschließende #0 Zeichen. Dieses entfernen wir anschließend mit TrimRight().
Einloggen, um Attachments anzusehen!
Zuletzt bearbeitet von Xion am Sa 13.02.10 17:14, insgesamt 10-mal bearbeitet
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Xion hat folgendes geschrieben : | | Die Namen der Form ändern wir auf "TutorialForm1" bzw. "TutorialForm2", die Caption auf "Window of TutorialForm1" bzw "Window of TutorialForm2". |
Wenn du dir schon die Mühe machst und die Formulare umbenennst, dann mach es auch richtig und gib ihnen aussagekräftige namen wie Sender und Empfaenger oder so.
Den Rest werde ich mir wahrscheinlich nachher noch mal durchlesen.
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Das mit dem Empfänger und Sender ist so ne tricky Sache...das Problem hatte ich in nem andren Posting schon, weil letztenendes senden ja beide (in Kapitel 2) und dann verwirrt das irgendwie total.
Edit:
Wenn du zufällig weißt, wie ich aus der Message rausbekomme, wer sie geschickt hat, würde ich das nocht mit einbauen...wäre sehr sinnvoll, wenn ein Programm von mehreren andren Programmen angesprochen werden kann und antworten soll
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Überleg dir ein Protokoll. Und verschick mit WM_COPYDATA einen Record mit deinen Daten.
www.michael-puff.de/...ts/WM_COPYDATA.shtml
Wenn ich zwei Programme über Nachrichten kommunizieren lassen würde, dann übrigens mit WM_COPYDATA, weil man damit auch Daten austauschen kann.
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Jo, das mache ich ja auch in Kapitel 2
Ach, das mit dem record ist ja einfach  cool, danke 
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Ok, ich habe mir die Quellcodes mal angeguckt, die Erklärungen habe ich nicht gelesen.
Bei WM_COPYDATA gibst du als wParam Application.Handle an. Da würde ich das Fensterhandle, also TForm.Handle angeben. Application ist das unsichtbare Fenster der VCL.
Text schreibt man mit WM_SETTEXT in ein Memo und mit den anderen entsprechenden Nachrichten in Listboxen usw.
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Boldar
        
Beiträge: 1262 Dabei seit: 14.06.2008 Wohnort: root
Win7 Enterprise 64bit, Win XP SP2 Turbo Delphi
|
Das kann man sich ja vorher mit WM_GETTEXT holen.
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Hol dir den text, häng eine Zeile an und setzt den Text wieder. Dann hast du auch gleich gezeigt, wie man Text ausliest.
Warum braucht man WM_KEYDOWN häufiger? Schaltflächen klickt man an, in dem man die entsprechende Nachricht an das Fenster oder die Schaltfläche schickt.
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Finde ich nicht. Du simulierst einen Menschen, aber warum? Mach es doch so, wie Windows es macht. das ist wesentlich zuverlässiger. Ein Industrieroboter macht ja auch menschliche Tätigkeit, sieht aber eher nicht wie ein Mensch aus, sondern ist an seine Tätigkeit perfekt angepasst.
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Musste erst bisschen recherchieren, bin Pointer-technisch ganz schlecht  Warum muss ich denn bei WM_GETTEXT eins mehr als die Länge des Strings abfragen? Die Dokumentation von Microsoft sagt dazu nichts aus.
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Luckie
        
Beiträge: 11066 Erhaltene Danke: 2 Dabei seit: 30.08.2002
WindowsXP Professional SP2 BDS2006, VS C++ Express, Eclipse (Java), Flex (Flash, AS)
|
Das abschließende #0 Zeichen.
Aber du hast keinerlei Fehlerbehandlung drin:
_________________ Gruß Michael
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Ok, habs geändert. (Posting 3, letzter Code)
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Kapitel 4 - RegisterWindowMessage
(Danke an BenBE für den Hinweis auf diese Funktion)
Nachdem wir jetzt wissen wie man messages verwendet müssen wir aufpassen, dass wir kein durcheinander anrichten, da die messages WM_USER+x von mehreren Programmen mit unterschiedlichster Bedeutung verwendet werden. Mit RegisterWindowMessage können wir uns für die Kommunikation unsrer zwei Programme eine eindeutige ID für unsre Message holen.
Erweitern wir die in Kapitel1 verwendete Funktion so, dass wir RegisterWindowMessage verwenden.
Zuerst benötigen wir eine Variable (in beiden Programmen):
Im Gegensatz zu vorher ist dieser Wert nicht konstant, da wir den vom System erst zugewiesen bekommen.
Schreiben wir in den Konstruktor (in beiden Programmen):
RegisterWindowMessage weißt uns eine ID für unsre message zu. Ist sie schon registriert (z.B. wenn Programm1 vor Programm2 gestartet wurde), bekommen wir trotzdem die ID zurück. Beide Programme haben also jetzt die gleiche ID für die message, und diese message-ID ist im ganzen System einmalig.
Platzieren wir jetzt noch einen weiteren Button in Programm1. Das senden funktioniert analog Kapitel1:
Das empfangen jedoch ist etwas anders...da wir keine konstante haben, können wir nicht direkt eine procedure deklarieren, die immer aufgerufen wird, wenn die message ankommt.
Wir müssen also die procedure, die alle messages empfängt so verändern, dass wir dort auf unsre message reagieren können.
Die entsprechende procedure heißt WndProc(TMessage); Wir überschreiben (ersetzen) diese in Programm2 mit eigenem Code:
(kurze Erklärung, was überschreiben bedeuted):
Das override überschreibt die procedure WndProc. Vereinfacht erklärt: Angenommen eine Person hat einen Zettel in der Hand und macht immer das was dort drauf steht. Wir nehmen ihr jetzt einfach den Zettel ab und geben ihr einen neuen. Die Person macht jetzt das, was auf dem neuen Zettel steht. Jetzt können wir aber (mit inherited) auch noch auf den alten Zettel zugreifen. Das passiert in dem Stückchen Code.
Wir haben uns sozusagen eine Abzweigung eingebaut. Ist die msg=WM_HELLOregistered, dann "biegen" wir ab in unsre procedure. Sonst wird einfach die original WndProc aufgerufen.
Einloggen, um Attachments anzusehen!
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
Zuletzt bearbeitet von Xion am Sa 13.02.10 17:14, insgesamt 2-mal bearbeitet
|

|
|
Xion
       

(Threadstarter)
Beiträge: 1343 Erhaltene Danke: 2 Dabei seit: 23.02.2006 Wohnort: Mitte Deutschlands / A**** der Welt
Windoof 2000, XP Delphi 6 Enterprise / Delphi 2005 Prof
|
Kapitel 5 - Strukturierte Datenmengen verschicken
(Dank an Luckie für sein Code-Snippet auf seiner Website)
Manchmal möchte man mehrere Werte übertragen. Jetzt könnte man natürlich mehrere messages verschicken. Man kann aber auch ein ganzes record auf einmal verschicken.
Erstellen wir zuerst ein packed record (in beiden Programmen)
Ein normales record funktioniert auch, allerdings ist das packed record speichereffizienter.
Wir werden diesesmal zusätzlich zum String noch das Handle unsrer Form mitschicken. Damit könnte man schon eine Art Server/Client Struktur bauen, wobei der Server immer genau weiß, welche Anfrage von welcher Form kam.
Platzieren wir jetzt einen weiteren Button auf die Form von Programm1
Dieser Code füllt das CopyDataStruct mit den Record-Daten und schickt es dann via WM_COPYDATA zu Programm2.
Fügen wir jetzt in Programm2 den Empfangsteil ein
Erst lesen wir das Array aus, dann lesen wir noch aus dem mitgelieferten handle den Fenstertext aus.
Einloggen, um Attachments anzusehen!
_________________ a broken heart is like a broken window - it'll never heal
F steht für Feuer das wütet und lodert U steht für unfairer Kampf N steht für nukleares Waffenarsenal (Plankton)
|

|
|
Werbung ausblenden? Dann registriere Dich kostenlos.
Weitere Gründe für eine Registrierung.
Werbung ausblenden? Dann registriere Dich kostenlos.
Weitere Gründe für eine Registrierung.
|
|
|
|
|