Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.143.214.230] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здорово коллеги!
пытаюсь понять детали MFC, я знаю что есть такая функция CWnd::Detach(), но не могу понять почему след код не пашет: BOOL CInsideMFCDlg::OnInitDialog() { CDialog::OnInitDialog(); CEdit edit; edit.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, CRect(100, 50, 160, 73), this, 1001); edit.SetWindowText(_T("run-time created")); HWND hEdit = edit.Detach(); //<-- ASSERT TRACE("edit.m_hWnd = 0x%X, hEdit = 0x%X\n", edit.m_hWnd, hEdit); return TRUE; // return TRUE unless you set the focus to a control } Выхлоп : edit.m_hWnd = 0x0, hEdit = 0x250608 Program: C:\WINDOWS\SYSTEM32\mfc120ud.dll File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp Line: 430 там я обнаружил след: LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { // special message which identifies the window as using AfxWndProc if (nMsg == WM_QUERYAFXWNDPROC) return 1; // all other messages route through message map CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); ASSERT(pWnd != NULL); //<------------------------ это строка 430 ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd); if (pWnd == NULL || pWnd->m_hWnd != hWnd) return ::DefWindowProc(hWnd, nMsg, wParam, lParam); return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); } ясно что вызов FromHandlePermanent() возвращает 0, т.о. нельзя юзать Detach для контролов? пс. я знаю что можно сделать так: BOOL CInsideMFCDlg::OnInitDialog() { CDialog::OnInitDialog(); CEdit* edit = new CEdit; edit->Create(....); или так: BOOL CInsideMFCDlg::OnInitDialog() { CDialog::OnInitDialog(); // сделать mEdit членом класса mEdit.Create(....); но мне не понятно почему нельзя юзать Detach в первом примере. |
Сообщ.
#2
,
|
|
|
Там для этих классов, по-моему, нужно делать что-то типа UnsubclassWindow
|
Сообщ.
#3
,
|
|
|
Цитата Олег М @ Там для этих классов, по-моему, нужно делать что-то типа UnsubclassWindow надо по гуглить позже отпишусь. Добавлено спс! работает Detach заменил на UnsubclassWindow BOOL CInsideMFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); static HWND hEdit; if (hEdit != NULL) { TRACE("DestroyWindow\n"); ::DestroyWindow(hEdit); //<--- надо ли его удалять? } CEdit edit; edit.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, CRect(100, 50, 160, 73), this, 1001); edit.SetWindowText(_T("run-time created")); //hEdit = edit.Detach(); hEdit = edit.UnsubclassWindow(); //<--- все пучком TRACE("edit.m_hWnd = 0x%08X, hEdit = 0x%08X\n", edit.m_hWnd, hEdit); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } Выхлоп edit.m_hWnd = 0x00000000, hEdit = 0x001507C4 DestroyWindow edit.m_hWnd = 0x00000000, hEdit = 0x001A0100 DestroyWindow edit.m_hWnd = 0x00000000, hEdit = 0x0022073A Кстати в приведенном выше примере надо ли удалять окно созданого конторла? оно вообще еще существует? возможно при закрытии диалога также удаляются все окна контролов? что там с сохраненным дескриптором hEdit он валиден? возможно это лишнее телодвижение? я не силен в WinAPI имеет ли вызов DestroyWindow в моем случае профит? или все уже сделано при закрытии родительского окна диалога? сама функция DestroyWindow не падает, чтобы я туда не передал, передаю разный мусор ей похер ::DestroyWindow((HWND)0x100000); думаю она проверяет валидность дескриптора и уже потом делает зачистку, так что я не уверен в необходимости вызова в моем случае DestroyWindow. |
Сообщ.
#4
,
|
|
|
А что ты вообще пытаешься сделать?
|
Сообщ.
#5
,
|
|
|
Ничего
Так что DestroyWindow тут нужен или лишнее это? |
Сообщ.
#6
,
|
|
|
Ну, удалять ресурсы всегда нужно. Как правильно удалять окно не скажу, не помню. Вполне возможно, что DestroyWindow достаточно.
Просто я посмотрел свой древний код и нигде не нашел, чтоб использовался UnsubclassWindow. Наоборот, SubclassWindow и SubclassDlgItem - довольно много. Чтоб привязать свои классы к контролам. Поэтому и спросил. Добавлено Цитата Cfon @ static HWND hEdit; if (hEdit != NULL) { Кстати, ты бы здесь хотя бы вот так сделал static HWND hEdit = NULL; |
Сообщ.
#7
,
|
|
|
Цитата Олег М @ Ну, удалять ресурсы всегда нужно. Как правильно удалять окно не скажу, не помню. Вполне возможно, что DestroyWindow достаточно. Просто я посмотрел свой древний код и нигде не нашел, чтоб использовался UnsubclassWindow. Наоборот, SubclassWindow и SubclassDlgItem - довольно много. Чтоб привязать свои классы к контролам. Поэтому и спросил. Добавлено Цитата Cfon @ static HWND hEdit; if (hEdit != NULL) { Кстати, ты бы здесь хотя бы вот так сделал static HWND hEdit = NULL; ну да в данном случае вообще лучше сделать Эдит членом класса и не париться. я просто изучаю MFC и UnsubclassWindow здесь чисто для понимания взаимодействия компонентов MFC да и я сомневаюсь что здесь надо явно удалять окно эдит, вроде как при создании здесь указывается родитель а когда он удаляеься то удаляются все дочерние окна так? и разве статик переменная не иниц нулевым значением не явно? Добавлено кажется понял почему нельзя юзать Detach в случае окон ответ нашёл в этой статье: https://www.codeproject.com/Articles/535/Attaching-and-Detaching-Objects см раздел "When Detach is not good enough: CDialog and modeless dialogs". |
Сообщ.
#8
,
|
|
|
Цитата Cfon @ да и я сомневаюсь что здесь надо явно удалять окно эдит, вроде как при создании здесь указывается родитель а когда он удаляеься то удаляются все дочерние окна так? Я предпочитаю не закладываться на такие сомнения. Удаление любых ресурсов, которые создал, должно быть на уровне рефлексов. Тогда и проблем будет меньше. Добавлено Цитата Cfon @ и разве статик переменная не иниц нулевым значением не явно? То же самое. Может и явно, не знаю, но читабельности твоему коду не добавляет. |
Сообщ.
#9
,
|
|
|
Цитата Олег М @ Цитата Cfon @ да и я сомневаюсь что здесь надо явно удалять окно эдит, вроде как при создании здесь указывается родитель а когда он удаляеься то удаляются все дочерние окна так? Я предпочитаю не закладываться на такие сомнения. Удаление любых ресурсов, которые создал, должно быть на уровне рефлексов. Тогда и проблем будет меньше. Добавлено Цитата Cfon @ и разве статик переменная не иниц нулевым значением не явно? То же самое. Может и явно, не знаю, но читабельности твоему коду не добавляет. да это понятно, но хотелось бы ясно представлять всю картину происходящего |
Сообщ.
#10
,
|
|
|
Цитата Cfon @ да это понятно, но хотелось бы ясно представлять всю картину происходящего Картина, я так понимаю, это когда ты вызываешь функцию, например DestroyWindow, со случайном параметром? Попробуй проделать подобные действия в линуксе. Там твоя программа просто свалится нахрен. Винды они очень дружественны как для пользователя, так и для разработчика. Но, привыкать не советую. |
Сообщ.
#11
,
|
|
|
Цитата Олег М @ Цитата Cfon @ да это понятно, но хотелось бы ясно представлять всю картину происходящего Картина, я так понимаю, это когда ты вызываешь функцию, например DestroyWindow, со случайном параметром? Попробуй проделать подобные действия в линуксе. Там твоя программа просто свалится нахрен. Винды они очень дружественны как для пользователя, так и для разработчика. Но, привыкать не советую. я и не думал, это тестовый пример |
Сообщ.
#12
,
|
|
|
ну как я и предполагал DestroyWindow здесь не требуется, сделал проверку возврата:
static HWND hEdit; if (hEdit != NULL) { TRACE("DestroyWindow\n"); BOOL ret = ::DestroyWindow(hEdit); TRACE("ret = %d\n", ret); } Выхлоп edit.m_hWnd = 0x00000000, hEdit = 0x00190728 DestroyWindow ret = 0 edit.m_hWnd = 0x00000000, hEdit = 0x003507C2 DestroyWindow ret = 0 edit.m_hWnd = 0x00000000, hEdit = 0x001B0728 согласно описанию функции DestroyWindow https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms632682(v=vs.85).aspx Цитата If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. т.е. я делаю вывод что что эдит, а именно его окно, при повторном входе в OnInitDialog был уже удален Вопросы? в догонку код возврата GetLastError - 1400: "Invalid window handle" |
Сообщ.
#13
,
|
|
|
Цитата Cfon @ т.е. я делаю вывод что что эдит, а именно его окно, при повторном входе в OnInitDialog был уже удален Так и есть Цитата If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window. Только эти вещи лучше выяснять не таким, несколько диковатым, способом. Я обычно смотрел какие сообщения приходят окну, при помощи Spy++ |
Сообщ.
#14
,
|
|
|
Цитата Олег М @ Только эти вещи лучше выяснять не таким, несколько диковатым, способом. Я обычно смотрел какие сообщения приходят окну, при помощи Spy++ а я люблю дикий TRACE а все понял |
Сообщ.
#15
,
|
|
|
Цитата Cfon @ да это понятно, но хотелось бы ясно представлять всю картину происходящего Цитата Cfon @ вроде как при создании здесь указывается родитель а когда он удаляеься то удаляются все дочерние окна так? Всегда читай документацию по функциям, которые ты изучаешь, и вопросы все отпадут сами собой: https://msdn.microsoft.com/ru-ru/library/wi...2(v=vs.85).aspx Цитата If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window. |