Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

29.07.2011, 01:30

[WinAPI] Events in paralleler Verarbeitung?? !!

Moin,

ich bin soeben auf ein Problem gestoßen, wenn ich ein Fenster mit der WinAPI registrierte, den entstehenden handle speichere und ihn danach meinem EventHandler zugänglich mache.
Nun gibt es Events an das Fenster (aus der Nachrichtenschleife) schon bevor der EventHandler eine Registrierung des Fensterhandles erhält. Ergebnis ist ein ratloser EventHandler, der kein passendes Fenster findet.
Das Problem trat bisher bei mir nicht auf, weil ich schlichtweg alle Events ohne passendes Fenster ignoriert habe. Das tue ich jetzt prinzipiell auch, aber diesmal mit try-catch ^^

Was haben sich die Micropoft-Entwickler dabei gedacht? Habe ich hier einen Denkfehler? Wie soll ich allgemein Events zu einem Fensterhandle fangen, wenn der direkt auf die Fensterregistrierung folgende Befehl möglicherweise noch nach den ersten Events für dieses Fenster ausgeführt wird?
Klar lässt sich das über Threads und einen lock regeln, aber es kann doch nicht Sinn und Zweck dieses Designs sein, dass man zu sowas gezwungen wird.


MfG
dispy

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

29.07.2011, 01:45

Erklär vielleicht mal was genau du da treibst. Ich werd aus der Beschreibung da oben jedenfalls nicht wirklich schlau.

Databyte

Alter Hase

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

3

29.07.2011, 09:25

Also ich kann jetzt leider auch nur spekulieren was du machen willst, aber ich nehme mal an, dass du fensterevents in zugehörigen Klassen verarbeiten willst.

Ich hab mal was aus einem Alten projekt kopiert :)
Dabei ist Panel eine Klasse, die so zu sagen einen Eventhandler darstellt (also als oberklasse, der Eventhandler muss dann noch abgeleitet werden):

C-/C++-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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Von dieser KLasse wird geerbt
class Panel
{
public:
    Panel();
    virtual ~Panel();

    inline HWND getHandle() const { return (m_HWnd); }
    virtual LRESULT windowPorc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) =0;                        // <-- das wird dann später aufgerufen und soll das Event behandeln

// Static
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

protected:
    void init();

    HWND    m_HWnd;
};


//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Panel::Panel()
{
}


Panel::~Panel()
{
}

void Panel::init()
{
    if(!m_HWnd)
        throw InitException("Was not able to create window !");
}


LRESULT CALLBACK Panel::WindowProc( HWND    hwnd,
                                    UINT    msg,
                                    WPARAM  wParam,
                                    LPARAM  lParam)
{
    Panel* p = NULL;

    try
    {
        // Wir müssen nur den Pointer auf das Panel-Objekt bekommen
        if(msg == WM_CREATE)
        {
            // Wir nehmen den this-pointer aus CreateWindow und setzen ihn als Userdata
            CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
            p = (Panel*)cs->lpCreateParams;
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)p);
        }else{
            // Wir holen den this-pointer direkt aus der userdata
            p = (Panel*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

            if(!p)
                return DefWindowProc(hwnd, msg, wParam, lParam);   // Wenn kein this-pointer gesetzt ist, standardmäßig fortfahren (muss ja nicht jedes Fenster so nen Panel haben)
        }
    
        // Und schon können wir den Objekthandler (Panel) aufrufen, welches zum WindowHandle gehört
        return p->windowPorc(hwnd, msg, wParam, lParam);

    }catch(std::exception& e)
    {
        // Fehler abfangen (Exceptions die hier nicht gefangen werden gehen in der WinApi unter, werden ignoriert)
        MessageBox(NULL, e.what(), "Exception !", MB_OK | MB_ICONERROR);

    }catch(...)
    {
        MessageBox(hwnd, "Unknown error occured !", "Exception !", MB_OK | MB_ICONERROR);
    }

    return 0;
}


Und dann kann man ganz einfach davon ableiten:

C-/C++-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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class SimpleWindow
    : public Panel
{
public:
    SimpleWindow();
    ~SimpleWindow();

    LRESULT windowPorc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
};

///////////////////////////////////////////////////////////////////////////////////////////////


SimpleWindow::SimpleWindow()
{
    // Das hier kann man bestimmt auch sehr gut in die Panelklasse verlegen
    m_HWnd = CreateWindowEx(    WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
                                /* .... */,
                                "Abgeleitet von Panel",
                                WS_POPUP,
                                0, 0,
                                100, 100,
                                NULL,
                                NULL,
                                extInstance,
                                this);                 // <---- das hier ist besonders wichtig, denn hier wird der Pointer auf dieses Objekt WM_CREATE überreicht

    init();
}

StatusBar::~StatusBar()
{

}

LRESULT StatusBar::windowPorc(  HWND    hwnd,
                                UINT    msg,
                                WPARAM  wParam,
                                LPARAM  lParam)
{

    switch(msg)
    {
    case WM_CREATE:
        {

        }break;

    case WM_PAINT:
        {
            /* ...*/

        }return 0;
    case WM_DESTROY:
        {
            PostQuitMessage(0);
        }break;

    case WM_CLOSE:
        {

        }return 0;
    default:
        break;
    };

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

29.07.2011, 10:34

Wie soll ich allgemein Events zu einem Fensterhandle fangen, wenn der direkt auf die Fensterregistrierung folgende Befehl möglicherweise noch nach den ersten Events für dieses Fenster ausgeführt wird?

Du fängst die Events in einem anderen Thread?
Dann halte den Thread einfach an, bevor Du das Fenster erzeugst und setze ihn fort, nachdem Du ihm das Fenster bekannt gemacht hast.
(hast Du ja selbst schon geschrieben)

Wie sollte Microsoft das denn anders machen?
Sollen sie 100 ms warten, bis die ersten Events kommen?

Weitere Möglichkeit: im Thread die Events puffern, wenn das Fenster noch nicht bekannt ist.

Databyte

Alter Hase

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

5

29.07.2011, 14:30

Du fängst die Events in einem anderen Thread?


Hö ? sowas geht doch gar nicht oder ? es bekommt immer der Thread die Events, wo das Fenster (also auch das Handle) erstellt wurden.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

6

29.07.2011, 14:37

Es geht definitiv (Google).
Und scheinbar macht dispy das, denn sonst hätte er das Problem ja nicht.

7

31.07.2011, 21:10

Fehlannahme: es wird nicht parallel abgearbeitet, aber es gibt fensterlose Events.
Events, die keinem Fenster zugeordnet werden, erhalten als HWND 0xcccccccc. Dementsprechend müssen die gesondert behandelt werden, weil ein EventHandler dazu kein Fenster finden kann.

MfG
dispy

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

31.07.2011, 21:40

Äh..... wie genau kann es Fenster-Events zu einem nicht existenten Fenster geben und auf einen mit Debug-Werten markierten Speicher-Bereich zeigen? Das riecht für mich eher danach, dass Du da was falsch ausliest.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

01.08.2011, 01:14

Ich vermute mal dein Problem ist dass Windows schon Nachrichten (z.B. WM_CREATE) an das Fenster schickt bevor CreateWindowEx() returned.

10

01.08.2011, 18:30

Ich vermute mal dein Problem ist dass Windows schon Nachrichten (z.B. WM_CREATE) an das Fenster schickt bevor CreateWindowEx() returned.
Genau.

Der Vorschlag von David funktioniert wunderbar und löst damit das Problem.
Vielen Dank!


MfG
dispy

Werbeanzeige