Threads mit Fenster PostMessage ich blick nicht durch....



  • Ich teste derzeit eine Win32 Anwendung mit einem Thread.

    int WINAPI WinMain (HINSTANCE hThisInstance,
                         HINSTANCE UNUSED(hPrevInstance),
                         LPSTR UNUSED(lpszArgument),
                         int nCmdShow)
    

    in dem Einsprungspunkt des primären Threads erzeuge ich ein Fenster mit einer globalen Fensterprozedur. Also nix besonderes.
    Der primäre Thread benutzt folgende "Messageloop"

    while(GetMessage(&messages,NULL,0,0))
        {
            TranslateMessage( &messages );
            DispatchMessage( &messages );
        }
    

    Die soll den primären Thread blockieren, weil der sich genauso verhalten soll wie "normnale" Win32 Anwnendungen.
    Dann erzeuge vor der Loop einen Thread (mit Fenster).

    rt = new RenderThread( hThisInstance, hwnd );
    rt->Create();
    rt->CreateThreadWindow( nCmdShow );
    ThreadHwnd = rt->GetHwnd();
    PostMessage( ThreadHwnd, WM_DOSOMETHING, 0, 0 );
    rt->Run();
    

    In der globalen Fensterprozedur:

    RESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  /* handle the messages */
        {
    
            case WM_SYSKEYDOWN: //Alt + some_key
                break;
    
             case WM_RENDERTHREADFINISHED:
                std::cout << "Renderthread hat fertig...." << std::endl;
                CloseHandle( rt->GetThreadHandle() );
                break;
             case WM_KEYDOWN:  //Ctrl + Alt + some_key or some_key
                switch( wParam )
                {
                    ...
                     case VK_ESCAPE:
                        std::cout << "Versuche stop...." << std::endl;
                        SendMessage( ThreadHwnd, WM_RENDERTHREADSTOP, 0, 0 );
                        break;
                    ...
                     case VK_RETURN:
                        SendMessage( ThreadHwnd, WM_RENDERTHREADRESTART, 0, 0 );    
               }
            ...
             default:
                return DefWindowProc (hwnd, message, wParam, lParam);  
     return 0;
    }
    

    Der RenderThread...

    Das erzeugen des Fensters...

    void RenderThread::CreateThreadWindow( int nCmdShow )
    {
        WNDCLASSEX wincl;        /* Data structure for the windowclass */
    
        /* The Window structure */
        wincl.hInstance = m_hInstance;
        wincl.lpszClassName = szThreadClassName;
        wincl.lpfnWndProc = &RenderThread::StaticWndProcProxy;      /* This function is called by windows */
        wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
        wincl.cbSize = sizeof (WNDCLASSEX);
    
        /* Use default icon and mouse-pointer */
        wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.lpszMenuName = NULL;                 /* No menu */
        wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
        wincl.cbWndExtra = 0;                      /* structure or the window instance */
        /* Use Windows's default colour as the background of the window */
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    
        /* Register the window class, and if it fails quit the program */
        if (!RegisterClassEx (&wincl))
            return;
    
        /* The class is registered, let's create the program*/
        m_hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szThreadClassName,         /* Classname */
               "Code::Blocks Template Thread Window",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               m_hInstance,       /* Program Instance handler */
               this                 /* No Window Creation data */
               );
    
        /* Make the window visible on the screen */
        ShowWindow (m_hwnd, nCmdShow);
    }
    

    Der statische Callback...

    LRESULT CALLBACK RenderThread::StaticWndProcProxy(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if( message ==  WM_NCCREATE )
        {
            SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>( ( reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams ) ) );
        }
    
        RenderThread *target = reinterpret_cast<RenderThread*>( GetWindowLongPtr( hwnd, GWLP_USERDATA ) );;
    
        if ( target )
        {
            return target->ThreadWndProc( hwnd, message, wParam, lParam );
        }
    
        return DefWindowProc (hwnd, message, wParam, lParam);
    }
    

    Die Create und die Run

    void Thread::Create( unsigned int stackSize )
    {
        m_hThread = reinterpret_cast<HANDLE>(
                                        _beginthreadex(
                                                        NULL,
                                                        stackSize,
                                                        StaticEntry,
                                                        this,
                                                        CREATE_SUSPENDED,
                                                        &m_dwThreadID
                                                        )
                                           );
        m_ThreadState = CREATE_SUSPENDED;
    }
    ...
    
    void Thread::Run()
    {
        if( m_ThreadState == CREATE_SUSPENDED )
        {
            ResumeThread( m_hThread );
            m_ThreadState = CREATE_RUNNING;
        }
    }
    

    der Klassencallback

    LRESULT CALLBACK RenderThread::ThreadWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch( message )
        {
            case WM_DOSOMETHING:
                    std::cout << "Ich soooolll was tun!!!!!!!!!!!!!!!!!!" << std::endl;
                break;
            case WM_RENDERTHREADSTOP:
                m_bRun = false;
                break;
            case WM_RENDERTHREADRESTART:
                if( !m_bRun )
                {
                    m_bRun = true;
                    Create();
                    Run();
                }
                break;
            default: // for messages that we don't deal with
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
        return 0;
    }
    

    Die Entry...

    unsigned RenderThread::Entry( LPVOID UNUSED(pArg) )
    {
    
        while( m_bRun )
        {
            std::cout << "Thread....................." << std::endl;
        }
    
        std::cout << "Sende Nachricht....................." << std::endl;
    
        PostMessage( m_hWndParent, WM_RENDERTHREADFINISHED, 0, 0 );
    
        _endthreadex( 0 );
    
        return 0;
    }
    

    Wieso werden vom Hautpthread Nachrichten an die Fensterprozedur des RenderThreads weitergegeben. Obwohl ich im Hauptthread SendMessage benutze funktioniert das ganze auch mit PostMessage.

    Ich dachte das PostMessage die Nachrichten in die Queue des Threads einpflegt und diese dann mit nur an die Fensterprozedur des Threads gelangen, wenn der Thread eine Messagepump besitzt. Hat meiner nicht! Trotzdem gelangen die Nachrichten in die Fensterprozedur des RenderThreads?????



  • DispatchMessage() verteilt unabhängig vom Thread -> hWnd-Parameter von GetMessage() benutzen.



  • Jo,

    ...Any application can post and send messages. Like the system, an application posts a message by copying it to a message queue and sends a message by passing the message data as arguments to a window procedure...
    ...
    An application typically posts a message to notify a specific window to perform a task...

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx

    Tja, nur dachte ich bislang immer das es pro UIThread eine Queue gibt und das nur SendMessage direkt die WndProc ansteuern und PostMessage die Queue und ohne MessageLoop keine Nachricht an den Thread, da die Loop die Messages weiter an die WndProc des Threads leitet. Auch Dialoge, MDIParent- oder MDIChild-Fenster besitzen eigene Callbacks und deshalb auch eingene Queues. Aber das scheint so nicht zu sein. Im Code sind zwar SendMessage angegeben aber das klappt auch mit PostMessage. Hmm.

    Gruß


  • Mod

    Also ich verstehe Deinen Code nicht ganz.
    Aber:
    1. Fanster sind Thead bezogen.
    2. Fenster gehören zu dem Thread in dem CreateWndow aufgerufen wurde.
    3. Man kann also nicht ein CreateWindow machen und damit ein Fenster "in" einem fremden Thead erzeugen.
    4. Snd Fenster in einem Thread erzeugt worden benötigt der Thread eine eigene Message Loop
    5. GetMessage/PeekMessage holt nur Nachrichten ab für Fenster die auch in dem Thread liegen in dem GetMessage/PeekMessage ausgefüht wird.
    6. Wird SendMessage aus einem anderen Thread ausgeführt, wird die Nachricht in die MessageQueue des anderen Thread gestellt und erst ausgeführt wenn auch dort GetMessaage/PeekMessage ausgeführt wird. Der Thread der SendMessage ausführt blockiert solange.

    Wie ich das sehe erzeugst Du aus Thead 1 einen Thread 2, aber in Thread 1 erzeugst Du auch ein Fenster. Dasgehörtnatürlich zu Thread 1!


Anmelden zum Antworten