Wieso wird ein Fenster zerstört, das in einem Thread erstellt wird, nach Threadende?
-
Hallo!
Ich habe ein Problem

Wenn ich aus einem Thread heraus mein Fenster erstelle, verschwindet dieses, soblad der Thread beendet wird (hier, wenn ich die MessageBox nach Threaderstellen schließe).
Hier mein Code, der ziemlich selbsterklärend ist:
(habe die Anwendung angefertigt um euch ein Beispiel zu liefern...brauche das dringend in einem anderen Projekt)CMyWindow:
#include "StdAfx.h" #include "mywindow.h" LRESULT CALLBACK DummyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); CMyWindow::CMyWindow(void) { } CMyWindow::~CMyWindow(void) { } void CMyWindow::CreateWnd(HWND hParent, HINSTANCE hInstance) { RegisterWindowClass(hInstance); hWnd = CreateWindow("MYWINDOW", "", WS_VISIBLE | WS_CHILD, 0, 0, 100, 100, hParent, 0, hInstance, this); if(!hWnd) return; ::ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } LRESULT CALLBACK CMyWindow::WndProc (HWND hWindow, UINT message, WPARAM wParam, LPARAM lParam) { RECT rc; PAINTSTRUCT ps; HBRUSH hBr; HDC hDC; switch(message) { case WM_PAINT: HDC hDC = BeginPaint(hWindow, &ps); GetClientRect(hWindow, &rc); hBr = CreateSolidBrush(RGB(255, 0, 0)); FillRect(hDC, &rc, hBr); EndPaint(hWindow, &ps); DeleteObject(hBr); break; } return DefWindowProc(hWindow, message, wParam, lParam); } LRESULT CALLBACK DummyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { CMyWindow* pWnd = (CMyWindow*)GetWindowLong(hWnd, GWL_USERDATA); switch(msg) { case WM_CREATE: pWnd = (CMyWindow*)(((LPCREATESTRUCT)lParam)->lpCreateParams); SetWindowLong(hWnd, GWL_USERDATA, (LONG)pWnd); break; } if(pWnd) return pWnd->WndProc(hWnd, msg, wParam, lParam); else return DefWindowProc(hWnd, msg, wParam, lParam); } void CMyWindow::RegisterWindowClass(HINSTANCE hInstance) { WNDCLASS wndc; ZeroMemory(&wndc, sizeof(WNDCLASS)); wndc.cbClsExtra = 0; wndc.cbWndExtra = 0; wndc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndc.hCursor = LoadCursor(hInstance, IDC_ARROW); wndc.hIcon = 0; wndc.hInstance = hInstance; wndc.lpfnWndProc = (WNDPROC)DummyWndProc; wndc.lpszClassName = "MYWINDOW"; wndc.lpszMenuName = 0; wndc.style = CS_VREDRAW | CS_HREDRAW; RegisterClass(&wndc); }Dialogklasse: (Die Dialogklasse DlgTest enhält eine Membervariable CMyWindow myWnd)
void _CreateThread(CDlgTestDlg* pDlg) { pDlg->myWnd.CreateWnd(pDlg->GetSafeHwnd(), AfxGetInstanceHandle()); MessageBox(0, "stop", 0, 0); } BOOL CDlgTestDlg::OnInitDialog() { CDialog::OnInitDialog(); // Hinzufügen des Menübefehls "Info..." zum Systemmenü. // IDM_ABOUTBOX muss sich im Bereich der Systembefehle befinden. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Symbol für dieses Dialogfeld festlegen. Wird automatisch erledigt // wenn das Hauptfenster der Anwendung kein Dialogfeld ist SetIcon(m_hIcon, TRUE); // Großes Symbol verwenden SetIcon(m_hIcon, FALSE); // Kleines Symbol verwenden // TODO: Hier zusätzliche Initialisierung einfügen CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_CreateThread, this, 0, 0); //myWnd.CreateWnd(this->GetSafeHwnd(), AfxGetInstanceHandle()); return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll den Fokus erhalten }Wenn ich statt der Threaderstellung das Fenster ohne den Thread erstelle (siehe Kommentar unter CreateThread), bleibt das Fenster erhalten.
Bitte um Hilfe!!
Danke,
Gruß,
Kevin
-
Surkevin schrieb:
Wenn ich aus einem Thread heraus mein Fenster erstelle, verschwindet dieses, soblad der Thread beendet wird (hier, wenn ich die MessageBox nach Threaderstellen schließe).
Fenster sind threadafin. D.h. ein Fenster lebt immer nur im Kontext eines Threads. Wird der Thread beendet sterben alle in ihm erzeugten Fenster mit ihm.
-
Hm scheiße.
Gibts keine Möglichkeiten das zu umgehen, außer das Fenster an den Mainthread per SendMessage zu übergeben oder den Thread mit while(GetMessage(X)) am Leben zu erhalten?
Danke für die Info!
-
Surkevin schrieb:
Gibts keine Möglichkeiten das zu umgehen, außer das Fenster an den Mainthread per SendMessage zu übergeben oder den Thread mit while(GetMessage(X)) am Leben zu erhalten?
Nein! Fenster sind und bleiben threadafin und daruf baut auch das ganze Windows multithreading auf!
Was meinst Du mit das Fenster an den Mainthread zu übergeben? Man kann den Threadcontext eines Fensters nicht nachträglich ändern!Was willst Du eigentlich damit erreichen? In meinen Augen macht so etwas NULL Sinn. Für was ein Fenster in einem anderen Thread erzeugen und dann sterben lassen?
-
In Windows-Anwendungen hat man meistens einen "main" thread, der das ganze Fenster-Gefrickel übernimmt. Warum glaubst du, ein Fenster aus einem anderen Thread heraus öffnen zu müssen?
-
Wenn es in deinen Augen NULL Sinn macht, ist das ja schön, allerdings gibt es Fälle in denen man so etwas braucht.
An den Mainthread kann man das Fenstererstellen aus einem anderen Thread heraus übergeben, in dem man einem Fenster, das mit dem Mainthread gekoppelt ist eine Nachricht (SendMessage) sendet, und der Mainthread dann das Fenster erstellt.
Damit ihr mal wisst, wo man so etwas zB braucht:
Outlookplugin sendet einen Event, wenn man die Email wechselt.
Nun sendet es leider den Event in bestimmten Fällen BEVOR die neue Email aufgebaut ist (ich brauche das Emailfenster).
Bevor ich den Event nicht zurückgebe (also den Mainthread "laufen lasse") baut sich das Fenster auch nicht auf.Deshalb muss ich den Event sofort zurückgeben und in einem Thread darauf warten, dass das Emailfenster fertig aufgebaut wird und DANN in meinem Thread das Childfenster erstellen.
Da dies ja wie gesagt wurde, nicht möglich ist, werde ich mir mit SendMessage weiterhelfen müssen.
Gruß,
Kevin
-
An den Mainthread kann man das Fenstererstellen aus einem anderen Thread heraus übergeben, in dem man einem Fenster, das mit dem Mainthread gekoppelt ist eine Nachricht (SendMessage) sendet, und der Mainthread dann das Fenster erstellt.
Ja, ist doch geil. Warum willst du das Fenster jetzt in einem anderen Thread erstellen?
Deshalb muss ich den Event sofort zurückgeben und in einem Thread darauf warten, dass das Emailfenster fertig aufgebaut wird und DANN in meinem Thread das Childfenster erstellen.
Wenn du etwas mehr Details zu deinen Plugin verrätst, können wir dir vielleicht helfen, eine schöne Lösung zu finden. Wie stellst du denn fest, wann das Emailfenster fertig aufgebaut ist? Gibt es dafür ein Event oder pollst du in regelmäßigen Abständen? Was hindert dich daran, wenn der andere Thread feststellt, dass es jetzt geil ist ein Fenster zu öffnen, dieses Fenster dann im main thread zu erstellen?
-
Nichts hindert mich daran

Wollte nur wissen ob es eine schönere Möglichkeit gibt als es mit SendMessage und dann im MainThread zu machen.