CObject* p;
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
Вызов диалога из потока
Код:
Судя по заметке передача объектов между потоками запрещена (но я то ничего не передаю я создаю объект в потоке). Кроме того предлагается передавать HWND Тогда как потом этот диалог создавать?
Кто сию проблему знает?
Код:
CDialog* pDlg= (CDialog*)CWnd::FromHandle(pHWND);
...
pDlg->DoModal();
...
...
pDlg->DoModal();
...
Возможно я чего-то не понял...
В примере в классе CPassHwnd имеется стринговая переменная TestSave. При первом вызове диалога его название отображает содержание переменной занесенное в эту переменную конструктором. далее по ходу выполнения программы но до запуска потока в эту переменную заносим новое содержание. Необходимо вызвать из потока этот диалог и в названии отобразить новое содержание переменной. Если объявить экземпляр этого диалога как глобальную переменную, то программа вылетит, как описано в вопросе темы (в примере это можно увидеть нажав на кнопку "Failthread").
Я переписал немного вот таким вот образом, и все работает:
(и не фига с HWND париться)
Как было раньше:
Код:
void CThreadTestDlg::OnHwnd()
{
CPassHwnd *Dlg;
Dlg = new CPassHwnd;
Dlg->DoModal(); //отображаем диалог. чтоб посмотреть, что название диалога было записано из конструктора
PassDlgHwnd = Dlg->m_hWnd; //здесь почему то 0 [COLOR="Lime"]<- эта глобальная переменная нафик не нужна, избегай глобальных функций и переменных[/COLOR]
Dlg->TestSave = _T("OnHwndCall");
DWORD ThreadID;
HANDLE hThread = CreateThread(NULL,0,PassHwnd,0,0,&ThreadID);
CloseHandle(hThread); // [COLOR="lime"]<- а вот это ты зря... зачем раньше времени закрывать поток? вообще рекомендуется, чтобы поток выходил сам из себя... функции типа TerminateThread() и CloseHandle() - это уже на крайний случай...[/COLOR]
}
{
CPassHwnd *Dlg;
Dlg = new CPassHwnd;
Dlg->DoModal(); //отображаем диалог. чтоб посмотреть, что название диалога было записано из конструктора
PassDlgHwnd = Dlg->m_hWnd; //здесь почему то 0 [COLOR="Lime"]<- эта глобальная переменная нафик не нужна, избегай глобальных функций и переменных[/COLOR]
Dlg->TestSave = _T("OnHwndCall");
DWORD ThreadID;
HANDLE hThread = CreateThread(NULL,0,PassHwnd,0,0,&ThreadID);
CloseHandle(hThread); // [COLOR="lime"]<- а вот это ты зря... зачем раньше времени закрывать поток? вообще рекомендуется, чтобы поток выходил сам из себя... функции типа TerminateThread() и CloseHandle() - это уже на крайний случай...[/COLOR]
}
Вот как стало:
Код:
void CThreadTestDlg::OnHwnd()
{
CPassHwnd *Dlg;
Dlg = new CPassHwnd;
Dlg->DoModal(); //отображаем диалог. чтоб посмотреть, что название диалога было записано из конструктора
Dlg->TestSave = _T("OnHwndCall");
DWORD ThreadID;
HANDLE hThread = CreateThread(NULL,0,PassHwnd,Dlg,0,&ThreadID);
}
{
CPassHwnd *Dlg;
Dlg = new CPassHwnd;
Dlg->DoModal(); //отображаем диалог. чтоб посмотреть, что название диалога было записано из конструктора
Dlg->TestSave = _T("OnHwndCall");
DWORD ThreadID;
HANDLE hThread = CreateThread(NULL,0,PassHwnd,Dlg,0,&ThreadID);
}
+ переделать немного саму функцию потока:
Код:
DWORD WINAPI PassHwnd(void* lPar)
{
CPassHwnd* pDlg= (CPassHwnd*) lPar;
pDlg->DoModal();
return 0;
}
{
CPassHwnd* pDlg= (CPassHwnd*) lPar;
pDlg->DoModal();
return 0;
}
Протестил... у меня работает...
ЗЫ 1) Кстати, у тебя Винда какая? А то меня коммент убил: "//такой вызов чуть винду не повесил".
2) А чуть не повесил потому, что у тебя хендл PassDlgHwnd был нулевой, поэтому и указатель на диалог получился нулевым...
3) С многопоточностью осторожнее, особенно если будешь использовать какие-то шаренные ресурсы... если их используешь, то необходимо будет использовать средства синхронизации (типа, семафоров, критических секций, мьютексы исчо)
Да и хотелось бы все таки разобраться с FromHandle... Откуда мне HWND моего диалога брать и как он будет создаваться снова или HWND это и есть экземпляр диалога? В общем HWND можно взять в OnInitDialog только FromHandle все равно диалог не создает.
З.Ы. У меня ХP подвисает после нажатия кнопки "PassHwnd"