PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zwei Fenster, eine Aufgabe?


Matrix316
2003-12-28, 15:56:48
Wenn ich ein Programm zweimal öffne, wie bekomm ich das nicht aktive Fenster dazu (es kann ja immer nur ein Fenster aktiv sein) trotzdem etwas auszuführen (zum Beispiel den Bildaufbau)?

Woher bekomm ich die Handle-Nummer des nicht aktiven Windows?

Brauch ich die überhaupt?

Btw.: Wie funktioniert eigentlich Get- und SetWindowLong genau?

killermaster
2003-12-28, 18:40:42
welche sprache denn überhautp!?!?!?

Matrix316
2003-12-28, 19:16:26
Original geschrieben von rapmaster
welche sprache denn überhautp!?!?!?

C oder C++ bzw. win32 ohne MFC.

Demirug
2003-12-28, 19:52:36
Wenn du willst das ein nicht aktives Fenster was tut benutzt du am besten einen Timer der regelmässig kommt.

Siehe dazu: WM_TIMER SetTimer KillTimer

Matrix316
2003-12-28, 21:26:36
Also ich hab jetzt mal in der Callback "WndProcedure(..." Funktion drinnen:


//alles geklaut von msdn.microsoft.com :D

UINT uResult;

uResult=SetTimer(hWnd, // handle to main window
IDT_TIMER1, // timer identifier
10, // 0.1-second interval
(TIMERPROC) NULL); // no timer callback

if (uResult == 0)
{
ErrorHandler("No timer is available.");
}

[...]

case WM_TIMER:
switch (wParam)
{
case IDT_TIMER1:
InvalidateRect(hWnd,NULL,TRUE);
return 0;
}
break;

[...]

case WM_DESTROY:
KillTimer(hWnd, IDT_TIMER1);


Aber ich bekomm die Fehlermeldungen beim kompilieren:


error C2065: 'IDT_TIMER1' : nichtdeklarierter Bezeichner
error C2065: 'ErrorHandler' : nichtdeklarierter Bezeichner
error C2051: case-Ausdruck ist keine Konstante


Nur ich versteh noch nicht, woher man mit einem Timer genau weiß welches Fenster gemeint ist...

Demirug
2003-12-28, 21:54:09
IDT_TIMER1 musst du noch irgendwo als Konstante festlegen. Es muss irgendeine Nummer sein.

Das Fenster das die Nachricht bekommt legt man beim Aufruf von SetTimer fest. Dafür ist der erste Parameter zuständig.

Matrix316
2003-12-28, 22:10:28
Original geschrieben von Demirug
IDT_TIMER1 musst du noch irgendwo als Konstante festlegen. Es muss irgendeine Nummer sein.

Das Fenster das die Nachricht bekommt legt man beim Aufruf von SetTimer fest. Dafür ist der erste Parameter zuständig.

Aaaaalso...es geht. Aber jetzt zeichnet er alle ... das Bild neu, so dass es dauernd am Flackern ist...=)

Kann man das vielleicht auch mit GetModuleHandle machen, aber welche Nummer hat das nicht aktive Fenster? 1? 2?

Demirug
2003-12-28, 22:14:21
Original geschrieben von Matrix316
Aaaaalso...es geht. Aber jetzt zeichnet er alle ... das Bild neu, so dass es dauernd am Flackern ist...=)

Kann man das vielleicht auch mit GetModuleHandle machen, aber welche Nummer hat das nicht aktive Fenster? 1? 2?

Aktives Fenster? Eine Timernachricht wird zyklisch an das Fenster gschickt das man bei SetTimer angegeben hat. Da wird nicht zwischen aktiv und inaktiv unterschieden.

Wenn du das Flackern weg haben möchtest musst du entweder prüfen ob sich was geändert hat bevor du das Fenster neu zeichen lässt oder für das Zeichen einen Bitmap-Buffer benutzen.

Matrix316
2003-12-28, 22:32:02
Original geschrieben von Demirug
Aktives Fenster? Eine Timernachricht wird zyklisch an das Fenster gschickt das man bei SetTimer angegeben hat. Da wird nicht zwischen aktiv und inaktiv unterschieden.

Wenn du das Flackern weg haben möchtest musst du entweder prüfen ob sich was geändert hat bevor du das Fenster neu zeichen lässt oder für das Zeichen einen Bitmap-Buffer benutzen.

ja aber ich hab ja nur EINe hWnd Variable im Quelltext, egal wieviele Programm-Fenster ich öffne.

Man kann ja anstatt dem normalen hWnd auch mit einem anderen Handle (irgendwas mit Broadcast) an alle Fenster das Signal zum repaint geben, aber das bringt ja alles zum stehen, weils an ALLE Fenster geschickt wird.

Wie bekomm ich das Handle des nicht aktiven Fensters eines Programmes bzw. einer Anwendung?

Oder kann ich die Fenster anders unterscheiden?

In der Vorlesung hatten wir was mit SetWindowLong und GetWindowLong, so dass man irgendwie eine spezielle Nummer jedem Fenster übergeben kann. Aber wie das genau geht, weiß ich auch net (und die MSDN Hilfe ist auch nicht so der brüller...)

Wie müsste man es machen, wenn man zum Beispiel zweimal Word öffnet und man wenn man in einem Fenster was tippt, dasselbe automatisch im anderen Word-Fenster erscheint?

Demirug
2003-12-28, 22:45:37
Original geschrieben von Matrix316
ja aber ich hab ja nur EINe hWnd Variable im Quelltext, egal wieviele Programm-Fenster ich öffne.

Richtig und woher kommt der Wert dieser Variablen? Von einem CreateWindow, oder? CreateWindow wird dir dabei jedesmal einen anderen Wert zurückliefern das ist so üblich.

Man kann ja anstatt dem normalen hWnd auch mit einem anderen Handle (irgendwas mit Broadcast) an alle Fenster das Signal zum repaint geben, aber das bringt ja alles zum stehen, weils an ALLE Fenster geschickt wird.

Ja, von Broadcast nachrichten sollte man die Finger lassen ist schon schlimm genug das Windows selbst sowas verschickt.

Wie bekomm ich das Handle des nicht aktiven Fensters eines Programmes bzw. einer Anwendung?

Oder kann ich die Fenster anders unterscheiden?

Wenn du ein programm mehrfach startest haben die überhaupt nichts miteinader zu tun. Jede Instanz deines Programms ist unabhängig und sie sollten sich auch nicht gegenseitig an den Fenstern rumspielen. Sowas gibt nur Ärger. Nur der Prozess welcher ein Fenster erzeugt hat soll es auch bearbeiten und verändern.

In der Vorlesung hatten wir was mit SetWindowLong und GetWindowLong, so dass man irgendwie eine spezielle Nummer jedem Fenster übergeben kann. Aber wie das genau geht, weiß ich auch net (und die MSDN Hilfe ist auch nicht so der brüller...)

Mit Set und GetWindowLong kann man sich ein paar interne Fensterzuständen holen oder verändern. Aber auch hier gilt wieder du brauchst dazu schon das Fensterhandle und nur der Prozess der das Fenster erzeugt hat sollte es nutzen.

Wie müsste man es machen, wenn man zum Beispiel zweimal Word öffnet und man wenn man in einem Fenster was tippt, dasselbe automatisch im anderen Word-Fenster erscheint?

Ein geeignetes Verfahren aus der grossen weiten Welt der Interprozesskomnunikation nutzen. Sockets, Named Pipes, COM, ...

Matrix316
2003-12-29, 11:28:27
Ja aber wenns doch unsere Aufgabe ist sowas zu Programmieren...:...( :...( :...( ;)

Zitat:


b) Die DLL ist dahingehend zu erweiteren, dass ein Austausch über einen Shared Memory Bereich stattfinden kann.

- Die Übungsaufgabe 4 ist so abzuändern, dass beim Anklicken die Mauskoordinate alle derzeit offenen Fenster die Daten aus dem Shared Memory Bereich lesen und zeichnen.


Obs jetzt Sinnvoll ist oder nicht, das ist jetzt mir scheißegal. =)

Demirug
2003-12-29, 11:48:34
Original geschrieben von Matrix316
Ja aber wenns doch unsere Aufgabe ist sowas zu Programmieren...:...( :...( :...( ;)

Zitat:



Obs jetzt Sinnvoll ist oder nicht, das ist jetzt mir scheißegal. =)

1. Deiem Prof gehört in den Hintern getreten weil man ein solches Problem nicht auf diese Art löst.

2. Wenn ich das richtig verstehe sollen alle Fenster immer das gleiche Anzeigen. Ist das jetzt nur eine Linie mit den beiden Koordinaten oder ein Linienzug welcher sich verlängert? Im Prinzip ist es aber denoch ganz einfach ergänze in deiner DLL noch eine Variable die einen Zähler darstellt. Bei jedem mausklick trägst du die neuen Koordinaten ein und inkrementierst den Zähler. Die Timerfunktion überwacht dabei zyklisch den Zähler und jedesmal wenn er sich verändert hat wird gezeichnet.

Matrix316
2003-12-29, 11:56:47
Original geschrieben von Demirug
1. Deiem Prof gehört in den Hintern getreten weil man ein solches Problem nicht auf diese Art löst.

2. Wenn ich das richtig verstehe sollen alle Fenster immer das gleiche Anzeigen. Ist das jetzt nur eine Linie mit den beiden Koordinaten oder ein Linienzug welcher sich verlängert? Im Prinzip ist es aber denoch ganz einfach ergänze in deiner DLL noch eine Variable die einen Zähler darstellt. Bei jedem mausklick trägst du die neuen Koordinaten ein und inkrementierst den Zähler. Die Timerfunktion überwacht dabei zyklisch den Zähler und jedesmal wenn er sich verändert hat wird gezeichnet.

Und woher weiß der Timer, dass sich die Variable verändert hat? :| :kratz2:

Wenn du willst, kann ich dir auch eine Lösung (Programm) schicken!

PS.: Lustig ist auch, wenn ich nur die Koordinaten (also die Variablen) share, dann ähndert sich nur die Position die der Text anzeigt. Wenn ich den Struct share in dem die Koordinaten drinnen stehen, dann zeichnet er auch die Linien in beiden Fenstern. Nur wenn ich vom einen Fenster ins andere Fenster wechsle, dann zeichnet er nicht weiter, sondern irgendwie rückwärts ...=)

Demirug
2003-12-29, 12:49:40
Änderungen stellt man fest indem man den letzten Wert des Zählers in einer zusätzlichen Variable speichert die man nicht shared. Immer wen diese Variable und der Zähler unterschiedlich sind hat er sich verändert.

Matrix316
2003-12-29, 13:33:06
Ok, ich habs mal so gemacht. Wenn ich jetzt in einem Zeichne, dann macht ers in beiden nur wenn ich klicke (also so wie gewollt). Wenn ich in das andere Fenster wechsle, wird normal weiter gezeichnet. Aber sobald ich den Inhalt lösche, und in dem Fenster neu zeichne in dem ich das Löschen ausgelöst habe, flackert die Zeichnung im anderen Fenster! Aber wenn ich ins andere Fenster wechsle, und dort weiter Zeichne (was jetzt geht, er geht also nicht rückwärts) dann flackert es nicht mehr. Wenn ich aber im ANDEREN Fenster neu zu Zeichnen beginne, flackert es nicht (im anderen). :bonk:

(Wenn ich den Bildschirm lösche, setze ich beide Variablen auf 0)

Matrix316
2003-12-31, 13:35:47
Da das mit dem Timer etwas unbefriedigend war, hab ich nochmal das Probiert wie wir es machen "sollen".

Dazu hab ich mal bei WM_CREATE folgendes geschrieben:

SetWindowLong(hWnd, GWL_USERDATA, iUserNumber);

(Die iUserNumber ist geshared und bekommt in der WndProc einen bestimmten Wert zugewiesen)

In der DLL gibts jetzt folgende Funktion:


BOOL CALLBACK EnumCallback(HWND hWnd,LPARAM lParam)
{
int iUserData;

iUserData=GetWindowLong(hWnd, GWL_USERDATA);

if (iUserData==0110)
{
SendMessage(hWnd, WM_REPAINT,0,0);
}
return true;
}


Diese wird aufgerufen bei WM_LBUTTONUP


case WM_LBUTTONUP:
EnumCallback(hWnd,lParam);
.
.
.
break;


und soll auf die Folgende Option in der WndProc wirken:


case WM_REPAINT:

InvalidateRect(hWnd,NULL,TRUE);

break;


Die Funktion EnumCallback soll irgendwie alle Handles der Programme enthalten (so heißt es), und da ich mit SetWindowLong jedem Fenster die gleiche Nummer zuweise, soll den Fenstern mit dieser Nummer die InvalidateRect(...) Funktion ausgeführt werden! Aber es geht nicht...warum nicht?

Es wird nur in dem Fenster gezeichnet in dem ich anklicke, aber er zeichnet das in dem anderen nur, wenn ich dort weiter klicke.

BTW, wer das ganze Ausmaß dieses Problem erfahren will, soll mal die Threads "Hell on Earth oder Win32..." und "DLL und Shared Memory" lesen...

Demirug
2003-12-31, 15:16:39
Da versaut mir doch wiedermal ein Prof ein neue Generation von Leuten. Schrecklich.

Das kann so nicht funktionieren.

Damit dein EnumCallback auch wirklich für alle Fenster aufgerufen wird darfst du nicht


case WM_LBUTTONUP:
EnumCallback(hWnd,lParam);


ausführen sondern.


case WM_LBUTTONUP:
EnumWindows (EnumCallback, 0);


Aus dem SendMessage würde ich dann aber noch ein PostMessage machen. Ein SendMessage an Fenster zu senden die einem nicht gehören geht schnell in die Hose.

Alles in alle hat das Teil aber ein Design das in die Tonne gehört.

Matrix316
2003-12-31, 15:36:04
JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!

SIEG! (sogar mit SendMessage gehts)

:laola: :spritz: :party:

:massa:

Wie gesagt, mit dem Timer gings zwar auch, aber irgendwie nicht richtig, wenn man den Bildschirm löscht.

Das zwei Programme das gleiche machen, würde ich natürlich auch nie so Programmieren wollen. Warum sollte man auch das wollen? Aber du weißt ja, dass Lehrer und Professoren eh meistens anders ticken. ;)