0

I am creating a CWinThread that will have it's own GUI. When I create a CWnd on that thread, it displays, but I can't move the window. I am sure that the message pump is running, because I can performn MoveWindow from another thread, and the window moves.

UIThread.h

#pragma once

class CUIThread : public CWinThread
{
public:
    DECLARE_DYNCREATE(CUIThread)
    CUIThread();

    // Attributes
public:
    HWND hwnd;
    // Operations
public:
    void KillThread();

    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CGDIThread)
    //}}AFX_VIRTUAL

    // Implementation
public:
    virtual ~CUIThread();

protected:
    virtual BOOL InitInstance();

    // Generated message map functions
    //{{AFX_MSG(CUIThread)
    // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

UIThread.cpp

#include "stdafx.h"
#include "UIThread.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CUIThread

IMPLEMENT_DYNCREATE(CUIThread, CWinThread)

BEGIN_MESSAGE_MAP(CUIThread, CWinThread)
    //{{AFX_MSG_MAP(CUIThread)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CUIThread::CUIThread() : hwnd(NULL)
{
    m_bAutoDelete = FALSE;
}

BOOL CUIThread::InitInstance()
{
    this->m_pMainWnd = new CWnd;
    m_pMainWnd->Create(_T("STATIC"), _T("Hi"), WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        CRect(0, 0, 500, 500), CWnd::GetDesktopWindow(), 1234);

    this->hwnd = m_pMainWnd->GetSafeHwnd();

    return TRUE;
}

CUIThread::~CUIThread()
{

}

void CUIThread::KillThread()
{
    // Note: this function is called in the context of 
    // other threads, not the thread itself.
    this->PostThreadMessage(WM_QUIT, 0, 0);

    // allow thread to run at higher priority during 
    // kill process
    SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
    WaitForSingleObject(m_hThread, INFINITE);
}

main.cpp

...
CUIThread* pUIThread = static_cast< CUIThread*>(AfxBeginThread(RUNTIME_CLASS(CUIThread)));
getchar();
MoveWindow(pUIThread->hwnd, 100, 100, 500, 500, true); // works
getchar();
CloseWindow(pUIThread->hwnd); // works
getchar();
pUIThread->KillThread(); // works
delete pUIThread;
getchar();
...

I can see the window, I just can't move/maximize/resize it.

Visible window

Paul Knopf
  • 9,568
  • 23
  • 77
  • 142
  • You need to understand the concept of _message loop/message pump_. You cannot use naively `getchar()`. I don't see any message pumpe here. – Jabberwocky Apr 26 '16 at 08:30
  • 1
    Your design is wrong. There should be only one GUI thread in any windows app (Win32/MFC). What's the point of calling `getchar()`? – Andrew Komiagin Apr 26 '16 at 08:33
  • @MichaelWalz Please see https://msdn.microsoft.com/de-de/library/b807sta6.aspx and check the link for Run. CWinThread provides a default message pump. – Werner Henze Apr 26 '16 at 08:38
  • 1
    @AndrewKomiagin I agree that the design is unnecessarily complex, just one main GUI thread is needed, but can you please give more details why this design cannot work? Also it looks to me like Paul create a console application and wants to add a GUI. Regarding the `getchar`: it is called in the main thread. So totally legit in my opinion: it blocks the main thread, but the additional UI thread should be running. – Werner Henze Apr 26 '16 at 08:40
  • I have to manage my own thread, because I have an multi-threaded/thread-safe API which has auxiliary popups that I don't want to be handled by the implementation's thread pump. – Paul Knopf Apr 26 '16 at 08:57
  • Historically, Windows allows UI elements to be accessed only by the thread that created them. This means that a background thread in charge of some long-running task cannot update a text box when it is finished. Windows does this to ensure the integrity of UI components. A list box could look strange if its contents were updated by a background thread during painting. – Andrew Komiagin Apr 26 '16 at 09:10
  • @AndrewKomiagin: *"A list box could look strange if its contents were updated by a background thread during painting."* - This won't ever happen. Even if you are sending messages to a listbox from another thread, those messages are only dispatched, when the owning thread calls one of the message retrieval functions (`GetMessage`, etc.). So contents never change, **while** a control is in the middle of painting its visual representation. – IInspectable Apr 26 '16 at 17:43

1 Answers1

0

I believe you are creating the window the wrong way. You are creating a child window with the desktop as parent window. This should work:

LPCSTR strClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE);
VERIFY(m_pMainWnd->CreateEx(0, strClass, _T("title"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(0, 0, 500, 500), NULL, 0));
Paul Knopf
  • 9,568
  • 23
  • 77
  • 142
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
  • That was it! Care to explain why I can't use the ```CWnd::GetDesktopWindow()```. If my window required no user interaction, would it have been safe to use? – Paul Knopf Apr 26 '16 at 13:11
  • Child windows have no title bar and are not movable by the user. Top level Windows do. – Werner Henze Apr 26 '16 at 13:13