Callbackfunktionen für Windowssubfensterereignisse

Gibt es einen professionellen Windows-Programmierer, der weiss, wie ohne Definition einer speziellen neuen Fensterklasse für ein als Dialogelement nur per Create-Befehl erzeugtes Fenster Ereignisse wie das Klicken eines Buttons an die Hauptfensterklasse durchgereicht werden können?

Oder können solche Ereignisse ohne aufwändige neue Klassendeklaration mit einer Callback-Funktion verknüpft werden, die jedesmal bei einem bestimmten Ereignis eines Subdialogfensters eine entsprechende Meldung verarbeitet und insbesondere das Betätigen bestimmter Buttons zuverlässig in entsprechende Aktionen umsetzt wie etwa das Auswerten und Aktualisieren des ganzen Dialoges einschließlich Datenaustausch?

Vielen Dank
Gerald

Hallo Gerald,

ich versteh zwar deine Frage nicht wirklich aber ich versuch mal das zu beantworten was ich denke :smile:

In der Windows API gibt es die Funktion „GetParent()“ welcher du als ersten Parameter dein aktuelles Fenster Handle (HWND) gibst, die dir dann das Handle des übergeordneten Fensters zurückgibt.

Du kannst also im Window Proc des Hauptfensters(?) eine selbstdefinierte Nachricht abfangen (z. B. WM_DIALOG_BLUB).

Im Dialog, der natürlich als Parent dein Hauptfenster(?) hat kannst du nun einfach SendMessage(GetParent(hWnd), WM_DIALOG_BLUB, 0, (LPARAM)„Hallo“) aufrufen.

Buttons im allgemeinen senden WM_COMMAND an ihr Parentfenster(das Fenster, auf dem sie zu sehen sind).

Gruss,
Christoph

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Zuweisung von Callbackfunktion an Fenster

ich versuch mal das zu beantworten was ich denke :smile:

In der Windows API gibt es die Funktion „GetParent()“ welcher
du als ersten Parameter dein aktuelles Fenster Handle (HWND)
gibst, die dir dann das Handle des übergeordneten Fensters
zurückgibt.

Dies ist nicht das eigentliche Problem, da diese Aufgabe ohne weiteres durch SendMessage oder auch PostMessage bewältigt werden kann mit entsprechender Identifizierung durch Parameter. Aber wie kann ich ein Dialogfenster, für das keine spezielle Klassendeklaration vorgenommen wurde und dessen Klasse an sich keine solche SendMessage-Ereignisbehandlung enthält, auf andere Weise veranlassen ein Ereignis wie einen Buttonklick seinem Parentfenster oder dem ganzen Programm mitzuteilen? Gibt es hier keinen Funktionsbefehl oder zu setzenden Parameter der allgemeinen Windowsklasse CWnd oder Dialogklasse CDialog, der sicherstellt, dass bei bestimmten Aktionen auch übergeordnete Programmstrukturen sofort informiert werden und nicht etwa bei Datenübergabe nach Abarbeitung eines modalen Dialogfeldes?
Eine andere denkbare Möglichkeit hierfür wäre, dass dem Fenster eine Ereignisbehandlungsfunktion irgendwie zugewiesen werden könnte, ohne dass dies wie üblich bei der Definition einer speziellen Fensterklasse geschehen muss. Oder sind alle Ereignisbehandlungsfunktionen für Windowsfenster doch immer so sehr in der Klassendefinition eingekapselt, dass durch Befehle an einzelne Instanzen der Klasse hier keine grundlegende Änderung mehr möglich sein soll?

Gibt es irgendwelche Hinweise oder Erfahrungen, wie bei einem Fenster oder auch nur einem Dialogelement wie einem Button die Ereignisbehandlungsfunktion aus dem Programm heraus abgerufen oder gar ausgetauscht werden kann? Unter welchen speziellen Voraussetzungen könnte dies möglich sein und gibt es dafür Musterprogramme?

Du kannst also im Window Proc des Hauptfensters(?) eine
selbstdefinierte Nachricht abfangen (z. B. WM_DIALOG_BLUB).
Im Dialog, der natürlich als Parent dein Hauptfenster(?) hat
kannst du nun einfach SendMessage(GetParent(hWnd),
WM_DIALOG_BLUB, 0, (LPARAM)„Hallo“) aufrufen.

Hier ist die entscheidende Frage, ob eine Selbstdefinition solcher Nachrichten einfach aus dem Programm heraus beim Aufbau eines Subfensters möglich ist, ohne dafür für das Subfenster zuvor in einer eigenen Fensterklasse eine solche Ereignisbehandlung zuweisen zu müssen.

Buttons im allgemeinen senden WM_COMMAND an ihr
Parentfenster(das Fenster, auf dem sie zu sehen sind).

Gibt es einen professionellen Windows-Programmierer, der
weiss, wie ohne Definition einer speziellen neuen
Fensterklasse für ein als Dialogelement nur per Create-Befehl
erzeugtes Fenster Ereignisse wie das Klicken eines Buttons an
die Hauptfensterklasse durchgereicht werden können?

Grüße
Gerald

Hallo!

Sowas geht so:
Eine Fensterklasse aus Sicht der Windows API hat nichts mit einer MFC Klasse (CWnd,CDialog…) zu tun.
Vielmehr wird damit der Typ eines Fensters gemeint.
Von Hause aus bringt Windows mehrere solcher Klassen/Typen mit (z.b. Button,ListView usw.)
Du kannst dir die Fensterklasse (nochmal hat nichts mit einer MFC Klasse zu tun!) mal mit SPY+ (ist beim VisualStudio dabei) anschauen.
Jede Fensterklasse hat ihre eigene (CaallBack) Funktion die vom Betriebssystem zwecks bearbeitung von Nachrichten angehüpft wird.

Du müsstest zur lösung deines Problems also eine eigene Fensterklasse im System registrieren mit:

//register and open process link window
WNDCLASS wc ;
TCHAR className[]=TEXT(GERALDFENSTERKLASSE);
wc.lpszClassName = className ;
wc.hInstance = AfxGetApp()->m_hInstance;
wc.lpfnWndProc = GeraldWndProc ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hIcon = 0;//LoadIcon(m_hInst, IDI_APPLICATION) ;
wc.lpszMenuName = 0 ;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;
wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
if(!::RegisterClass(&wc))
{
AfxMessageBox(„error registering GRIDPROCESSLINKWND!\n“
„exitting application…“);
exit(0);
}

Die GeraldWndProc ist dabei die Funktion die vom BS angesprungen wird.
einse solche Funktion kann so aussehen:

//////////////////////////////////////////////////////////////////////////////
LONG FAR PASCAL GeraldWndProc(HWND hWnd, UINT Message, UINT wParam, LONG lParam)
//////////////////////////////////////////////////////////////////////////////
{
if(Message==WM_COPYDATA)
{
//tu irgend was…
}
return DefWindowProc(hWnd,Message,wParam,lParam);
}

Am Schluss musst du noch ein Fenster dieser Klasse öffnen.
Das Parentfenster kann jetzt ein CDialog Fenster sein.
Das geht so:

m_hGeraldWnd= ::CreateWindow(
className,
className,
WS_POPUP,
0, 0,
320,200,
m_hWnd,//der parent ist dein Dialog!!!
NULL,
AfxGetApp()->m_hInstance,
NULL) ;

Du musst jetzt noch bei CreateWindow bzw. RegisterClass die Parameter so setzen dass das erzeugte Fenster so aussieht wie du möchtest (z.b. wie ein Button).

Wenn du jetzt in irgend einem Modalen Dialog ein Fenster von deinem Typ öffnest wird immer in die GeraldWndProc gesprungen, dort kannst du dann alle deine Dialoge aktualisieren usw.

Ich hoffe es war das was du gemeint hast, gruß Pauli!

ps. copy and paste vom VisualStudio hierhin geht nicht gescheit, keine Farben, keine Formatierung, warum das? , wir haben 2004!

viele Probleme gelöst! wichtiges Lehrmuster

Sowas geht so:
Eine Fensterklasse aus Sicht der Windows API hat nichts mit
einer MFC Klasse (CWnd,CDialog…) zu tun.

Ja, dies ist bei all den Klassen manchmal schwer zu unterscheiden und kaum zu überschauen, da es in der Hilfe zu wenig ausführliche systematische Anleitungen gibt und die knappen Musterbeispiele schwer zu wünschen lassen.

Vielmehr wird damit der Typ eines Fensters gemeint.
Von Hause aus bringt Windows mehrere solcher Klassen/Typen mit
(z.b. Button,ListView usw.)
Du kannst dir die Fensterklasse (nochmal hat nichts mit einer
MFC Klasse zu tun!) mal mit SPY+ (ist beim VisualStudio dabei)
anschauen.

Dies war eine wichtige Hilfe, vor allem bei der wichtigen Aufgabe, das Problem zu lösen, dass meine neu kreierten Fenster trotz Spezifikation des aktuellen View-Objekts kein Parentfenster hatten, sondern nur das Hauptfenster der Anwendung als Owner. Dies war möglicherweise auch eine wichtiger Grund, warum ich die Aufgabe nicht auf andere Weise lösen konnte und alle Versuche versagten, ein Ereignis von einem Dialogfenster direkt in die aktuelle Dokumentendarstellungsinstanz durchzureichen.

Jede Fensterklasse hat ihre eigene (CaallBack) Funktion die
vom Betriebssystem zwecks bearbeitung von Nachrichten
angeknüpft wird.

Dies wusste ich schon. Trotzdem ist es nicht ganz einfach mit so einer neuen Klasse und es fehlte ein vollständiges Musterbeispiel ohne Stolpersteine. Weiter bleibt die Frage, ob so eine Funktion auch später nach dem Aufruf einer Fensterklasseninstanz noch irgendwie abgeändert und angepasst werden kann.

Du müsstest zur lösung deines Problems also eine eigene
Fensterklasse im System registrieren mit:

Dies hatte ich schon mal versucht, aber ohne eine neue WndProc-Funktion, eine sehr eigenartige Konstruktion. Leider lassen sich von dieser aus auch keine der üblichen nichtstatischen Memberfunktionen der anderen Klassenobjekte aufrufen, sondern nur Messages versenden, etwa durch SendMessage, so dass auch hier noch beträchtlicher Anpassungsaufwand erforderlich war.

//register and open process link window
WNDCLASS wc ;
TCHAR className[]=TEXT(GERALDFENSTERKLASSE);

TEXT funktionierte bei mir mit Studio 97 hier nicht, sondern nur „…“;

wc.lpszClassName = className ;
wc.hInstance = AfxGetApp()->m_hInstance;

//hier fragt sich, für was dies gut sein soll!

wc.lpfnWndProc = GeraldWndProc ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hIcon = 0;//LoadIcon(m_hInst, IDI_APPLICATION) ;
wc.lpszMenuName = 0 ;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;

besser zur freien Farbwahl etwa:
wc.hbrBackground = (HBRUSH)CreateSolidBrush(0x00d0ff) ;
Dies ist auch eine ganz kritische Funktion, deren Bedeutung schwer zu ermitteln ist. So fragt sich, wie man sonst bei einer aufgerufenen Instanz eines Klassenfensters die Hintergrundfarbe noch am problemlosesten ändern kann, falls dies überhaupt ohne große Umständlichkeiten möglich ist.

wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
if(!::RegisterClass(&wc))
{
AfxMessageBox(„error registering GRIDPROCESSLINKWND!\n“
„exitting application…“);
exit(0);
}

hier Problem bei wiederholtem Funktionsaufruf aufgetreten,
dann kein Abbruch angebracht;

Die GeraldWndProc ist dabei die Funktion die vom BS
angesprungen wird.
eine solche Funktion kann so aussehen:

//////////////////////////////////////////////////////////////////////////////
LONG FAR PASCAL GeraldWndProc(HWND hWnd, UINT Message, UINT
wParam, LONG lParam)
//////////////////////////////////////////////////////////////////////////////
{
if(Message==WM_COPYDATA)
{
//tu irgend was…
}
return DefWindowProc(hWnd,Message,wParam,lParam);
}

Am Schluss musst du noch ein Fenster dieser Klasse öffnen.
Das Parentfenster kann jetzt ein CDialog Fenster sein.
Das geht so:

m_hGeraldWnd= ::CreateWindow(
className,
className,
WS_POPUP,

//hier muss bei mir WS_VISIBLE|WS_BORDER|WS_CAPTION stehen;

0, 0,
320,200,
m_hWnd,//der parent ist dein Dialog!!!

//Diese Zuordnung ist nicht zuverlässig und eine Schwachstelle,
//die genau zu überprüfen ist, etwa auf Hauptfenster;
//so etwa für Zugriff auf richtiges Fenster folgendes wichtig:
/*
CMDIFrameWnd* whandle = (CMDIFrameWnd*) AfxGetMainWnd( );
CMDIChildWnd* chandle = whandle->MDIGetActive(NULL );
CBildverarbeitungView *vhandle = (CBildverarbeitungView *) chandle->GetActiveView();
SendMessage(vhandle->m_hWnd,WM_SWAP, 0, 0);
*/

NULL,
AfxGetApp()->m_hInstance,
NULL) ;

Du musst jetzt noch bei CreateWindow bzw. RegisterClass die
Parameter so setzen dass das erzeugte Fenster so aussieht wie
du möchtest (z.b. wie ein Button).

//Um hier das richtige funktionsfähige zu finden, war nochmals einiges an Experimenten nötig mit Suche der richtigen Typspezifikationsparameter.

Wenn du jetzt in irgend einem Modalen Dialog ein Fenster von
deinem Typ öffnest wird immer in die GeraldWndProc gesprungen,
dort kannst du dann alle deine Dialoge aktualisieren usw.

//leider nur über Umwege der Ermittlung von Fensterhandles und
SendMessage-Anweisungen!

Ich hoffe es war das was du gemeint hast, gruß Pauli!

Ja, dies ist im Wesentlichen das, was ich brauchte und nun auch einen gewissen Durchbruch brachte. Zuvor war es aber auch schon mit einigen Aufwand verbunden, überhaupt herauszufinden, dass es hierfür keine einfachere Alternative der Manipulation fertiger Instanzen der üblichen Klassen gibt.

Daher frage ich auch gerne, wodurch Sie hier so gut informiert sind oder wie Sie zu diesen detaillierten Erfahrungen gekommen sind. Dies ist mir leider trotz langem Wühlen durch den Wust der Windowshilfen und dürftigen Musterprogramme noch nicht so gut gelungen.

Und erst jetzt ist damit der Weg frei zu höchst funktionalen Programmen, wo zu jedem Bild einer Bildverarbeitung noch intelligente Kommandozeilenfenster nach Bedarf eingeblendet werden können. Leider unterstützt Microsoft wie auch die übliche Literatur solche sehr praktischen Lösungen so gut wie nicht, sondern führt den Systementwickler mit den aufwändigen unflexiblen Klassenhierarchiearchitekturen zu oft nur an der Nase herum. Dies gilt auch generell für den Bereich der Bildverarbeitung, wo so gut wie jeder Ansatz für einen Aufbau anspruchsvoller Anwendungen fehlt und der Umgang mit allen Eigenheiten von Bitmapstrukturen einschließlich schnellem effektivem Low-Level-Byte-Zugriff in einem zuverlässigen geschlossenem System vergeblich zu suchen ist.

ps. copy and paste vom VisualStudio hierhin geht nicht
gescheit, keine Farben, keine Formatierung, warum das? , wir
haben 2004! (Dies liegt am eigenartigen RichEdit-Textformat. Ähnliche Probleme sind besonders schlimm beim Abspeichern und Sichern von Mails aus Outlook-Express.)

Ich arbeite noch mit VisualStudio97, obwohl ich auf einem schnelleren Rechner die Edition von 2003 habe und vielleicht einige Neuigkeiten noch nicht kenne. Aber auch sonst könnte vieles noch besser sein, etwa zur Videoprogrammierung, wo bei der älteren Version leider noch jegliches Musterbeispiel fehlte und ich erst später ich auf diesen wichtigen Ansatz stieß. Microsoft bietet bis heute hier nicht mal eine Schnittfunktion. Ähnliches gilt für Systeme der räumlichen Objektmodellierung.

Danke
Gerald

Weiter bleibt die Frage, ob
so eine Funktion auch später nach dem Aufruf einer
Fensterklasseninstanz noch irgendwie abgeändert und angepasst
werden kann.

Ja das geht mit SetWindowLong(…).

Dies hatte ich schon mal versucht, aber ohne eine neue
WndProc-Funktion, eine sehr eigenartige Konstruktion. Leider
lassen sich von dieser aus auch keine der üblichen
nichtstatischen Memberfunktionen der anderen Klassenobjekte
aufrufen, sondern nur Messages versenden, etwa durch
SendMessage, so dass auch hier noch beträchtlicher
Anpassungsaufwand erforderlich war.

Eben nicht!
Ich würde die WndProc in einer Klasse verkapseln.
Im Konstruktor der Klasse würde ich dann einen Pointer auf das Objekt übergeben auf das zugegriffen werden muss.
Über den kann man dann auf die public Methoden und Variablen zugreifen.
Mit SendMessage würde ich auf nicht arbeiten, weil das viel zu Umständlich ist…

//register and open process link window
WNDCLASS wc ;
TCHAR className[]=TEXT(GERALDFENSTERKLASSE);

TEXT funktionierte bei mir mit Studio 97 hier nicht, sondern
nur „…“;

wc.lpszClassName = className ;
wc.hInstance = AfxGetApp()->m_hInstance;

//hier fragt sich, für was dies gut sein soll!

wc.lpfnWndProc = GeraldWndProc ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hIcon = 0;//LoadIcon(m_hInst, IDI_APPLICATION) ;
wc.lpszMenuName = 0 ;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;

besser zur freien Farbwahl etwa:
wc.hbrBackground = (HBRUSH)CreateSolidBrush(0x00d0ff) ;
Dies ist auch eine ganz kritische Funktion, deren Bedeutung
schwer zu ermitteln ist. So fragt sich, wie man sonst bei
einer aufgerufenen Instanz eines Klassenfensters die
Hintergrundfarbe noch am problemlosesten ändern kann, falls
dies überhaupt ohne große Umständlichkeiten möglich ist.

Klar doch, du musst die WM_CTLMESSAGE abfangen, dort kannst du Hintergrundfarbe, Brush usw setzen.

wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
if(!::RegisterClass(&wc))
{
AfxMessageBox(„error registering GRIDPROCESSLINKWND!\n“
„exitting application…“);
exit(0);
}

hier Problem bei wiederholtem Funktionsaufruf aufgetreten,
dann kein Abbruch angebracht;

Es ist nur ein Beispiel und muss an dein Projekt angepasst werden.

//Diese Zuordnung ist nicht zuverlässig und eine
Schwachstelle,
//die genau zu überprüfen ist, etwa auf Hauptfenster;
//so etwa für Zugriff auf richtiges Fenster folgendes wichtig:
/*
CMDIFrameWnd* whandle = (CMDIFrameWnd*) AfxGetMainWnd( );
CMDIChildWnd* chandle = whandle->MDIGetActive(NULL );
CBildverarbeitungView *vhandle = (CBildverarbeitungView *)
chandle->GetActiveView();
SendMessage(vhandle->m_hWnd,WM_SWAP, 0, 0);
*/

Auch hier gilt: ist nur ein Beispiel.

Wenn du jetzt in irgend einem Modalen Dialog ein Fenster von
deinem Typ öffnest wird immer in die GeraldWndProc gesprungen,
dort kannst du dann alle deine Dialoge aktualisieren usw.

//leider nur über Umwege der Ermittlung von Fensterhandles und
SendMessage-Anweisungen!

Eben nicht (siehe Oben)!

Ich hoffe es war das was du gemeint hast, gruß Pauli!

Ja, dies ist im Wesentlichen das, was ich brauchte und nun
auch einen gewissen Durchbruch brachte. Zuvor war es aber auch
schon mit einigen Aufwand verbunden, überhaupt herauszufinden,
dass es hierfür keine einfachere Alternative der Manipulation
fertiger Instanzen der üblichen Klassen gibt.

Es gibt noch andere Möglichkeiten, schau dir mal SubclassWindow in der Hilfe an.

Daher frage ich auch gerne, wodurch Sie hier so gut informiert
sind oder wie Sie zu diesen detaillierten Erfahrungen gekommen
sind. Dies ist mir leider trotz langem Wühlen durch den Wust
der Windowshilfen und dürftigen Musterprogramme noch nicht so
gut gelungen.

Aus der MSDN

Und erst jetzt ist damit der Weg frei zu höchst funktionalen
Programmen, wo zu jedem Bild einer Bildverarbeitung noch
intelligente Kommandozeilenfenster nach Bedarf eingeblendet
werden können. Leider unterstützt Microsoft wie auch die
übliche Literatur solche sehr praktischen Lösungen so gut wie
nicht, sondern führt den Systementwickler mit den aufwändigen
unflexiblen Klassenhierarchiearchitekturen zu oft nur an der
Nase herum. Dies gilt auch generell für den Bereich der
Bildverarbeitung, wo so gut wie jeder Ansatz für einen Aufbau
anspruchsvoller Anwendungen fehlt und der Umgang mit allen
Eigenheiten von Bitmapstrukturen einschließlich schnellem
effektivem Low-Level-Byte-Zugriff in einem zuverlässigen
geschlossenem System vergeblich zu suchen ist.

Der Byteweise zugriff auf eine Bitmap ist ganz einfach mit GetDIBits zu realisieren…

ps. copy and paste vom VisualStudio hierhin geht nicht
gescheit, keine Farben, keine Formatierung, warum das? , wir
haben 2004! (Dies liegt am eigenartigen RichEdit-Textformat. Ähnliche Probleme sind besonders schlimm beim Abspeichern und Sichern von Mails aus Outlook-Express.)

Ich arbeite noch mit VisualStudio97, obwohl ich auf einem
schnelleren Rechner die Edition von 2003 habe und vielleicht
einige Neuigkeiten noch nicht kenne. Aber auch sonst könnte
vieles noch besser sein, etwa zur Videoprogrammierung, wo bei
der älteren Version leider noch jegliches Musterbeispiel
fehlte und ich erst später ich auf diesen wichtigen Ansatz
stieß. Microsoft bietet bis heute hier nicht mal eine
Schnittfunktion. Ähnliches gilt für Systeme der räumlichen
Objektmodellierung.

Für Video verwende ich DirectShow und für 3d Visualisierung Direct3D.

Danke
Gerald