Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вызов диалога из потока

4.5K
25 августа 2006 года
e-XperT
127 / / 04.07.2006
В MFC создаю диалог, создаю класс с помощью визарда. В потоке создаю экземпляр диалога и вызываю DoModal. В релиз версии все проходит нормально, но под отладчиком происходит Debug Assertion failed если нажать "продолжить" то выкинет на следующий участок кода мелкосовтовской библиотеки:
Код:
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 Тогда как потом этот диалог создавать?
Кто сию проблему знает?
20K
27 августа 2006 года
YouRLex
5 / / 18.08.2006
Вот примерно как из HWND получать, допустим, CDialog:

 
Код:
CDialog* pDlg= (CDialog*)CWnd::FromHandle(pHWND);
...
pDlg->DoModal();
...


Возможно я чего-то не понял...
4.5K
27 августа 2006 года
e-XperT
127 / / 04.07.2006
Чо то у меня не получается. Ниже приведен небольшой пример этой ошибке, которую я выше описал. Суть вот в чем: в потоке необходимо два раза вызвать диалог при первом вызове пользователь вводит в диалог некоторые числа, далее поток эти числа обрабатывает и в конце обработки из потока опять выводится диалог с введенными числами и результатом обработки.
В примере в классе CPassHwnd имеется стринговая переменная TestSave. При первом вызове диалога его название отображает содержание переменной занесенное в эту переменную конструктором. далее по ходу выполнения программы но до запуска потока в эту переменную заносим новое содержание. Необходимо вызвать из потока этот диалог и в названии отобразить новое содержание переменной. Если объявить экземпляр этого диалога как глобальную переменную, то программа вылетит, как описано в вопросе темы (в примере это можно увидеть нажав на кнопку "Failthread").
20K
28 августа 2006 года
YouRLex
5 / / 18.08.2006
Не понимаю почему низя передать указатель на диалог...

Я переписал немного вот таким вот образом, и все работает:
(и не фига с 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]
}


Вот как стало:
 
Код:
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);
}

+ переделать немного саму функцию потока:
 
Код:
DWORD WINAPI PassHwnd(void* lPar)
{
    CPassHwnd* pDlg= (CPassHwnd*) lPar;
    pDlg->DoModal();
    return 0;
}

Протестил... у меня работает...

ЗЫ 1) Кстати, у тебя Винда какая? А то меня коммент убил: "//такой вызов чуть винду не повесил".
2) А чуть не повесил потому, что у тебя хендл PassDlgHwnd был нулевой, поэтому и указатель на диалог получился нулевым...
3) С многопоточностью осторожнее, особенно если будешь использовать какие-то шаренные ресурсы... если их используешь, то необходимо будет использовать средства синхронизации (типа, семафоров, критических секций, мьютексы исчо)
4.5K
28 августа 2006 года
e-XperT
127 / / 04.07.2006
Да передать объект класса как параметр можно, только у меня уже передается в функцию потока переменная double. А значит надо будет эти переменные создавать таким образом, чтоб их адреса располагались друг за другом, чтоб в потоковой функции их можно было различить. Кроме того по моему коду CloseHandle закрывает объект ядра, а поток не трогает (хотя может я чо то не понимаю). Вот кусок из книги Рихтера:"После вызова CloseHandle Вы больше не получите доступ к этому объекту ядра; но, если его счетчик не обнулен, объект остается в памяти Тут все нормально, это означает лишь то, что объект используется другим процессом (или процессами). Когда и остальные процессы завершат свою работу с этим объектом (тоже вызвав CloseHandle), он будет разрушен.".
Да и хотелось бы все таки разобраться с FromHandle... Откуда мне HWND моего диалога брать и как он будет создаваться снова или HWND это и есть экземпляр диалога? В общем HWND можно взять в OnInitDialog только FromHandle все равно диалог не создает.
З.Ы. У меня ХP подвисает после нажатия кнопки "PassHwnd"
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог