nicht modalen Dialog mit eigener Messagepump ausstatten
-
RedrawWindow war meine Idee wenn Du nicht2 Threads verwendest.
Wieso vermischt Du das jetzt hier?Ich vermisch das nicht. Ich weiß dass es zwei Themen sind. Mich interessieren beide Wege. Und sagte ja nur dass ich auf die Frage wo ich RedrawWindow aufrufen soll auch noch keine Antwort erhalten habe.
Wenn InitInstance wirlich zweimal aufgerufen wird, dann wird die DLL auch zweimal geladen
Es wird nicht InitInstance der DLL 2-mal aufgerufen sondern InitInstance der Threadklasse. Das habe ich aber genau dargestellt!
y-vonne schrieb:
Das liegt wohl daran dass InitInstance 2 mal aufgerufen wird. Oder?
BOOL CMyThread::InitInstance()
{
if( m_dlgMy.GetSafeHwnd() == NULL)
m_dlgMy.Create(CMyDlg::IDD);return TRUE;
}
-
1. Nein! Wenn Initinstance der Threadklasse zweimal aufgerufen wird, dann werden auch zwei Threads gestartet!... InitInstance wird für jeden Thread genau einmal aufgerufen.
2. Wenn Du nur einen Thread hast, und Du nur einen Feedback geben möchtest (keinen Abbruch Button. etc.) dann baust Du eine loop mit z.b. 1Mio Iterationen. Alle 1000 Zyklen oder ausgerchenten 1% setzt Du in dem Progressbar neue Werte und erzwingst mit RedrawWindow einen Rferesh des Fensters. Es ist zwar nicht "bedienbar" aber es zeigt einen Fortschritt. Bedienbar ist es nicht weil es eben keine Messagepump gibt...Hinweis:
Gefährlich ist es (kann es sein) im selben Thread in dieser Loops Messages zu pumpem. Dann wird das Programm reentrant. Soetwas sollte man tunlichst vermeiden.
-
Du hast recht. InitInstance wird nur einmal aufgerufen. Das Problem liegt woanders. InitInstance wird nicht ganz zu Ende ausgeführt bevor die Funkion die den Thread anlegt endet. Und springt sozusagen danach wieder in Initinstance zurück.
Trotzdem liegt hier das Problem. Der Dialog wird nicht fertig gestellt bevor der Threaderzeuger endet. Wenn ich wie gesagt warte bis der Dialog fertig erstellt wurde und dass dann dem Threaderzeuger über ein Event mitteile klappt das.
Doch ich benötige eine Rückmeldung. Somit fällt das mit dem RedrawWindow weg.
-
Was für ein Parent gibst Du denn an? Evtl. versucht Dein Dialog an Dein anderes Fenster eine Nachricht zu senden und steht.
Mach doch mal einen Break-All in diesem Moment.Was macht Dein Worker-Thread?, Wo steht er im Callstack?
-
Was für ein Parent gibst Du denn an?
Ist doch in meinen Beiträgen zu erkennen. Ich gebe gar kein Parent an.
BOOL CMyThread::InitInstance() { if( m_dlgMy.GetSafeHwnd() == NULL) m_dlgMy.Create(CMyDlg::IDD); return TRUE; }
Was macht Dein Worker-Thread?, Wo steht er im Callstack?
In welchem Moment?
-
1. Wenn Du kein Parent angibst, sucht sich die MFC evtl. eines.
2. In dem Moment wo Du sagst, der Dialog erscheint erst, wenn der Thread fertig ist. Also in dem Moment in dem Du meinst hier müsste bereits eine Aktion passieren. Also bleibt vermutlich im Create stehen.
-
1. Was bedeutet dass dann für den Fall. Muß ich ein Parent angeben?
2. Ich erklär mal den Ablauf.Es wird die Exportfunktion Show aufgerufen
extern "C" DLLEXPIMP void Show(int time) { // AFX_MANAGE_STATE-Makro AFX_MANAGE_STATE(AfxGetStaticModuleState()); CMyThread *thread = theApp.GetThread(); PostThreadMessage(thread->m_nThreadID,SW_SHOW,time,0); }
Dazu wird wenn nötig der Thread erzeugt.
CMyThread* CMyApp::GetThread() { if( m_thread == NULL ) { m_thread = (CMyThread*)AfxBeginThread(RUNTIME_CLASS(CMyThread)); //m_evtWaitForDlg.Lock(); } return m_thread; }
Bei Threaderzeugung wird kurz in InitInstance gesprungen. Debugger steht bei der ersten geschweiften Klammer.
BOOL CMyThread::InitInstance() { if( m_dlgMy.GetSafeHwnd() == NULL) m_dlgMy.Create(CMyCDlg::IDD); //theApp.m_evtWaitForDlg.SetEvent(); //return CWinThread::InitInstance(); return TRUE; }
Danach springt der Debugger wieder in die Funktion GetThread und arbeitet diese zu Ende. Jetzt wird wieder in Initinstance gesprungen und die nächste Zeile abgearbeitet. Danach springt der Debugger an die Stelle an der eine Nachricht an den Thread gesendet wird:
PostThreadMessage(thread->m_nThreadID,SW_SHOW,time,0);
Und wieder zurück zu InitInstance nächste Zeile abarbeiten.
Danach endet die Exportfunktion und Initinstance wird auch zu Ende abgearbeitet.Die Message die gesendet wurde wird nicht abgefangen.
Und wie gesagt warte ich bis der Dialog fertig erstellt wurde mit:
m_evtWaitForDlg.Lock();
und
theApp.m_evtWaitForDlg.SetEvent();
funktioniert das ganze.
-
Du kannst so nicht sequentiell Debuggen. Die beiden Threads laufen parallel!
Wo hast Du den Handler für die Threadmessage eingebaut?
Threadmessage müssen im WinThread abgefangen werden. Siehe MSDN on_thread_message...Wieso sendest Du SW_SHOW als Nachricht. Das müsste sicherlich mit einer reservierten Nachricht kollidieren? Der Wert 5 steht für WM_SIZE!
Sorry aber Dein Vorgehen kommt mir vor wie stochern im Nebel.
-
Du kannst so nicht sequentiell Debuggen. Die beiden Threads laufen parallel!
Klar laufen Sie parallel. Darum kann es ja passieren dass schon die Nachricht zum anzeigen des Dialogs aufgerufen wird bevor er überhaupt erzeugt ist. Darum warte ich ja mit dem Event.
Wo hast Du den Handler für die Threadmessage eingebaut?
Threadmessage müssen im WinThread abgefangen werden. Siehe MSDN on_thread_message...Ja habe ich:
BEGIN_MESSAGE_MAP(CMyThread, CWinThread)
ON_THREAD_MESSAGE(SW_SHOW_DIALOG, ShowDialog)
ON_THREAD_MESSAGE(SW_HIDE_DIALOG, HideDialog)
...
END_MESSAGE_MAP()Wieso sendest Du SW_SHOW als Nachricht.
Ups das war natürlich falsch. Habe natürlich meine eigenen Nachrichten definiert. Da ist mir wohl ein Tippfehler unterlaufen.
Sorry aber Dein Vorgehen kommt mir vor wie stochern im Nebel.
Na ganz so schlimm würde ich das nun nicht bezeichnen. Aber dass ich nicht alles richtig mache weiß ich. Deshalb such ich ja hier die Hilfe.
-
Nein die Nachricht kann nicht vorher ankommen. Wie kommst Du bitte darauf.
- PostThreadMessage stellt die Nachricht in die Queue des anderen Threads.
Was gibt die Funktion denn zurück?
- Diese Nachrichten werden nur gelesen (ausschließlich) wenn eine Messageloop läuft.
- Erst wnen InitInstance mit TRUE verlassen wird. läuft das System in die CWinThread::Run Schleife und erst hier beginnt die Message-Loop...
_ Ich weiß nicht mehr genau wann für einen Thread eine MessaageQuee erzeugt wird. Evtl. erst wenn der Run läuft.
Evtl. genügt es enfach PostThreadMessage zu wiederholen bis es eben klappt, weil die Queue vorhanden ist.
-
Nein die Nachricht kann nicht vorher ankommen. Wie kommst Du bitte darauf.
Klar kann die Nachricht nicht vorher ankommen. Wo habe ich das behauptet? Ich habe nur gesagt dass sie vorher gesendet wird.
- PostThreadMessage stellt die Nachricht in die Queue des anderen Threads.
Was gibt die Funktion denn zurück?Sie gibt 0 zurück wenn ich nicht mit meinem Event warte. 1 wenn ich warte.
Evtl. genügt es enfach PostThreadMessage zu wiederholen bis es eben klappt, weil die Queue vorhanden ist.
Klar wenn ich PostThreadMessage wiederhole dann klappt es auch. Ich kann natürlich so lange PostThreadMessage wiederholen bis ich eine 1 zurück bekomme. Aber dann kann ich doch genau so gut mit meinem Event warten. Oder etwa nicht?
-
Jo!
-
Jo!
Ja das hätten wir ja schon früher haben können
Dank dir auf jeden Fall für deine Hilfe und dass du dir so viel Zeit genommen hast.