Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
[Win32] Виндос программеры - рассудите спор 13.02.02 17:55
Автор: PS <PS> Статус: Elderman Отредактировано 13.02.02 17:55 Количество правок: 1
|
С коллегами спор возник.
Есть алгоритм:
1.Создаем окно
2.Запоминаем его hwnd
3.тра ля ля
4.закрываем окно по запомненому hwnd
Они утверждают, что алгоритм валиден. Я же говорю, что во время тра ла ла пользователь может закрыть окно, открыть какое нибудь другое и (внимание!) виндос даст новому окну тот же hwnd ! И тогда в п.4 мы закроем совсем не то окно какое следует.
Кто прав ?
|
 |
[Win32] Обратимся к истокам 16.02.02 12:42
Автор: 1blin Статус: Незарегистрированный пользователь
|
Platform SDK: Windows User Interface
IsWindow:
Remarks
An application should not use IsWindow for a window that it did not create because the window could be destroyed after this function was called. Further, because window handles are recycled the handle could even point to a different window.
|
 |  |
[Win32] А алгоритм тем не менее валиден (в рамках области процесса)... 16.02.02 20:40
Автор: LiNX Статус: Незарегистрированный пользователь
|
|
|
 |  |  |
А по русски ? 17.02.02 22:35
Автор: PS <PS> Статус: Elderman
|
В смысле в чем валидность ?
Этажем выше сказано было как раз то на чам я настаивал, - повторяться будут - закроем другое. Нет, зря я на пиво не спорил :)
|
 |  |  |  |
резюме всего 17.02.02 22:57
Автор: z0 <z0> Статус: Member
|
рассмотрим два понимания ВАЛИДНОСТИ: теоретическую и практическую
теоретически алгоритм ИНВАЛИДЕН в принципе
чтобы не тратить попусту время приведу тестовую прожку,
доказывающую теоретическую ИНВАЛИДНОСТЬ алгоритма
--------------------------------- test.cpp ------------------------------
#include <windows.h>
#include <stdio.h>
#include "test.h"
HINSTANCE Instance;
HWND MainWindow;
HWND TestCreateWindow(void); // форвард
HWND CreateAnotherWindow(void); // форвард
char TestWNDCLASSName [] = "Test WNDCLASS name";
WNDCLASS TestWNDCLASS;
char TestWindowTitle [] = "Test window";
char AnotherWNDCLASSName [] = "Some WNDCLASS name";
WNDCLASS AnotherWNDCLASS;
char AnotherWindowTitle [] = "Some another window";
long WINAPI CALLBACK MainWindowProc
(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
HWND HWNDSavedByCoder;
switch (msg)
{
case WM_COMMAND:
{
switch (wParam)
{
case MWM_FILE_EXIT:
{
PostQuitMessage(0);
return 0;
}
case MWM_ACTION_TEST1_CREATEWINDOW:
{
// 1.Создаем окно
HWNDSavedByCoder = TestCreateWindow();
// 2.Запоминаем его hwnd
if (NULL != HWNDSavedByCoder)
{
// 3.тра ля ля
MessageBox(hWnd, "Please close manually [TEST WINDOW] and press OK to continue", "Your action here", MB_OK);
FILE* file = fopen("test.log", "wb");
fprintf(file,"HWNDSavedByCoder = %x\n", HWNDSavedByCoder);
for (;;)
{
HWND tempHWND = CreateAnotherWindow();
fprintf(file,"tempHWND = %x\n", tempHWND);
if (HWNDSavedByCoder == tempHWND)
{
MessageBox(tempHWND, "This really innocent window will now be destroyed", "look!", MB_OK);
break;
}
fflush(file);
}
// 4.закрываем окно по запомненому hwnd
DestroyWindow(HWNDSavedByCoder);
fclose(file);
Sleep(1000);
for(;;)
{
HWND tempHWND = GetForegroundWindow();
if (tempHWND == MainWindow) break;
DestroyWindow(tempHWND);
}
}
break;
}
case MWM_ACTION_TEST2_CREATEWINDOW:
{
// 1.Создаем окно
HWNDSavedByCoder = TestCreateWindow();
// 2.Запоминаем его hwnd
if (NULL != HWNDSavedByCoder)
{
// 3.тра ля ля
MessageBox(hWnd, "Please close manually [TEST WINDOW] and press OK to continue", "Your action here", MB_OK);
FILE* file = fopen("test.log", "wb");
fprintf(file,"HWNDSavedByCoder = %x\n", HWNDSavedByCoder);
for (;;)
{
HWND tempHWND = CreateAnotherWindow();
fprintf(file,"tempHWND = %x\n", tempHWND);
if (HWNDSavedByCoder == tempHWND)
{
MessageBox(tempHWND, "This really innocent window will now be destroyed", "look!", MB_OK);
break;
}
DestroyWindow(tempHWND);
fflush(file);
}
// 4.закрываем окно по запомненому hwnd
DestroyWindow(HWNDSavedByCoder);
fclose(file);
}
break;
}
case MWM_HELP_ABOUT:
{
MessageBox(hWnd, "www.BugTraq.ru/forum\ntest proggy by [z0]", "About", MB_OK);
break;
}
}
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
long WINAPI CALLBACK DummyWindowProc
(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain
(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
Instance = hInstance;
char SomeWNDCLASSName [] = "Main WNDCLASS name";
WNDCLASS SomeWNDCLASS;
char MainWindowTitle [] = "Main window";
SomeWNDCLASS.style = CS_HREDRAW | CS_VREDRAW;
SomeWNDCLASS.lpfnWndProc = MainWindowProc;
SomeWNDCLASS.cbClsExtra = 0;
SomeWNDCLASS.cbWndExtra = 0;
SomeWNDCLASS.hInstance = Instance;
SomeWNDCLASS.hIcon = NULL;
SomeWNDCLASS.hCursor = NULL;
SomeWNDCLASS.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
SomeWNDCLASS.lpszMenuName = "MainWindowMenu";
SomeWNDCLASS.lpszClassName = SomeWNDCLASSName;
if ( !RegisterClass(&SomeWNDCLASS) )
{
MessageBox(NULL, "RegisterClass(&SomeWNDCLASS) failed", "Error!", MB_OK);
return FALSE;
}
TestWNDCLASS.style = CS_HREDRAW | CS_VREDRAW;
TestWNDCLASS.lpfnWndProc = DummyWindowProc;
TestWNDCLASS.cbClsExtra = 0;
TestWNDCLASS.cbWndExtra = 0;
TestWNDCLASS.hInstance = Instance;
TestWNDCLASS.hIcon = NULL;
TestWNDCLASS.hCursor = NULL;
TestWNDCLASS.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
TestWNDCLASS.lpszMenuName = NULL;
TestWNDCLASS.lpszClassName = TestWNDCLASSName;
if ( !RegisterClass(&TestWNDCLASS) )
{
MessageBox(NULL, "RegisterClass(&TestWNDCLASS) failed", "Error!", MB_OK);
return FALSE;
}
AnotherWNDCLASS.style = CS_HREDRAW | CS_VREDRAW;
AnotherWNDCLASS.lpfnWndProc = DummyWindowProc;
AnotherWNDCLASS.cbClsExtra = 0;
AnotherWNDCLASS.cbWndExtra = 0;
AnotherWNDCLASS.hInstance = Instance;
AnotherWNDCLASS.hIcon = NULL;
AnotherWNDCLASS.hCursor = NULL;
AnotherWNDCLASS.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
AnotherWNDCLASS.lpszMenuName = NULL;
AnotherWNDCLASS.lpszClassName = AnotherWNDCLASSName;
if ( !RegisterClass(&AnotherWNDCLASS) )
{
MessageBox(NULL, "RegisterClass(&AnotherWNDCLASS) failed", "Error!", MB_OK);
return FALSE;
}
MainWindow = CreateWindow
(
SomeWNDCLASSName,
MainWindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
Instance,
0
);
if ( !MainWindow )
{
MessageBox(NULL, "CreateWindow() failed", "Error!", MB_OK);
return FALSE;
}
ShowWindow(MainWindow, nCmdShow);
UpdateWindow(MainWindow);
MSG msg;
while ( GetMessage(&msg, 0, 0, 0) )
{
DispatchMessage(&msg);
}
return TRUE;
}
HWND TestCreateWindow(void)
{
HWND TestWindow = CreateWindow
(
TestWNDCLASSName,
TestWindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
Instance,
0
);
if ( !TestWindow )
{
return NULL;
}
ShowWindow(TestWindow, SW_SHOWNORMAL);
UpdateWindow(TestWindow);
return TestWindow;
}
HWND CreateAnotherWindow(void)
{
HWND AnotherWindow = CreateWindow
(
AnotherWNDCLASSName,
AnotherWindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
Instance,
0
);
if ( !AnotherWindow )
{
return NULL;
}
ShowWindow(AnotherWindow, SW_SHOWNORMAL);
UpdateWindow(AnotherWindow);
return AnotherWindow;
}
---------------------------------- test.rc ----------------------------
#include <windows.h>
#include "test.h"
MainWindowMenu MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit" MWM_FILE_EXIT
END
POPUP "&Action"
BEGIN
MENUITEM "Test CreateWindow() &1" MWM_ACTION_TEST1_CREATEWINDOW
MENUITEM "Test CreateWindow() &2" MWM_ACTION_TEST2_CREATEWINDOW
END
POPUP "&Help"
BEGIN
MENUITEM "&About" MWM_HELP_ABOUT
END
END
------------------------------------ test.h -----------------------------
#define MWM_FILE_EXIT 0x0301
#define MWM_ACTION_TEST1_CREATEWINDOW 0x0401
#define MWM_ACTION_TEST2_CREATEWINDOW 0x0402
#define MWM_HELP_ABOUT 0x0501
-------------------------------------------------------------------------
результат работы данной прожки можно считать резюмой топика:
1) для win9x оба теста дают быстрый предсказанный результат -
повторяется использование хендла и закрывается НЕ ТО окно
2) при разработке NT-шной USER32.DLL эта ошибка видимо была учтена
добавлением случайного числа в старшее слово HWND и учете значения
этого слова при дальнейшей работе с HWND
я не дождался завала под NT4 - видимо практическая валидность под
этой системой высока
конкретную практическую валидность считайте для себя сами
зы: можно еще вспомнить такую штуку как PID - тоже ведь recycled и
reused и не где-нибудь а в хороших юниксах типа netBSD, Solaris etc.
программеры конечное же исходят из практической валидности числа
но надо только правильно ее оценивать
|
 |
[Win32] Виндос программеры - рассудите спор 15.02.02 14:43
Автор: z0 <z0> Статус: Member
|
> С коллегами спор возник. > Есть алгоритм: > 1.Создаем окно > 2.Запоминаем его hwnd > 3.тра ля ля > 4.закрываем окно по запомненому hwnd > > Они утверждают, что алгоритм валиден. Я же говорю, что во > время тра ла ла пользователь может закрыть окно, открыть > какое нибудь другое и (внимание!) виндос даст новому окну > тот же hwnd ! И тогда в п.4 мы закроем совсем не то окно > какое следует. > > Кто прав ?
нет не копались твои коллеги в виндах не понимают их специфики
линейные алгоритмы при работе с виндовс апи надо исключить напрочь
и кстати сами винды даже в ядре работают не по линейным а по спагетти-алгоритмам
в любой книжонке по программированию на первом же "хелло винды" видно как надо это делать:
1.создаем окно и прочую инициализацию проводим
2.входим в цикл обработки сообщений
и дальше все равно кто и как окно закроет - мышою, альт-ф4 или closewindow
там только написано что-то типа "смотрите как теперь удобно и просто стало" а надо было так сказать - "и попробуйте только по-другому..."
забавно что чем проще вещь тем труднее доходит
а вот отход от этого способа уже не забавен - действительно ведь не то окно совсем закроется
зы: ну конечно это не везде так - файловые операции например подчиняются линейности и хендлы там локальные
но в большинстве... все же это оболочка дешевая...
|
 |
[Win32] Виндос программеры - рассудите спор 14.02.02 00:23
Автор: ih8u <i hate you> Статус: Member
|
када приходит @#$%ец окну - HWND тоже приходит @#$%ец!
если такое случилось, то нихуя работать не будет,
чего тут не ясного!!
|
 |  |
[Win32] Виндос программеры - рассудите спор 15.02.02 14:52
Автор: z0 <z0> Статус: Member
|
> када приходит @#$%ец окну - HWND тоже приходит @#$%ец! > если такое случилось, то нихуя работать не будет, > чего тут не ясного!!
ну @#$%ец окну это допустим еще можно понять
а вот @#$%ец номеру записи в таблице окошек - честно скажу - не ясно
объяснишь?
|
 |  |  |
[Win32] Виндос программеры - рассудите спор 17.02.02 12:45
Автор: ih8u <i hate you> Статус: Member
|
|
мля, когда окно умирает, HWND не будет принадлежать к какому либо окну, соответсвенно ты не сможешь его использовать, например, в SendMessage
|
 |
[Win32] Виндос программеры - рассудите спор 13.02.02 22:24
Автор: + <Mikhail> Статус: Elderman
|
> С коллегами спор возник. > Есть алгоритм: > 1.Создаем окно > 2.Запоминаем его hwnd > 3.тра ля ля > 4.закрываем окно по запомненому hwnd > > Они утверждают, что алгоритм валиден. Я же говорю, что во > время тра ла ла пользователь может закрыть окно, открыть > какое нибудь другое и (внимание!) виндос даст новому окну > тот же hwnd ! И тогда в п.4 мы закроем совсем не то окно > какое следует. > > Кто прав ? I dumau chto kollegi pravy:
Tak kak window handle global , to kogda okno destroyed eta handle invalid i tolko odin sposob dlia drugogo processa uznat` valid ili ne valid handle ispolzua IsWindow(hwnd). i esli pri sozdanii drugogo window mozhet ispolzovat`sia starai handle togda teriaetsia integriti WIndows.
Predstav` situaciu neskolko raznyh threads rabotaut s odnoi i toi zhe window, i esli Windows bydut recycle window handle togda bolshaia veroiatnost` chto chasto windows bydut putatsia, chego ne proishodit (mozhesh napisat` test application chtoby ubeditsia)
|
 |  |
Я не в чем не ошибся ? 14.02.02 00:14
Автор: PS <PS> Статус: Elderman Отредактировано 14.02.02 00:15 Количество правок: 1
|
> I dumau chto kollegi pravy: > Tak kak window handle global , to kogda okno destroyed eta > handle invalid i tolko odin sposob dlia drugogo processa > uznat` valid ili ne valid handle ispolzua IsWindow(hwnd). > i esli pri sozdanii drugogo window mozhet ispolzovat`sia > starai handle togda teriaetsia integriti WIndows. > Predstav` situaciu neskolko raznyh threads rabotaut s odnoi > i toi zhe window, i esli Windows bydut recycle window > handle togda bolshaia veroiatnost` chto chasto windows > bydut putatsia, chego ne proishodit (mozhesh napisat` test > application chtoby ubeditsia)
Допустим одно окно создается за секунду. Тогда ((2^32)/60)/60 = 1193046 часов, Это 138 лет. Уменьшим создания окна с секунды. до 10мс, Тогда что бы выбрать все hwnd нам потребуется всего лишь год. Т.е. через год hwnd начнут повторяться... что-то многова-то...
Мда... вот что значит спорить не на трезвую голову. Хорошо хоть не на пиво.... :)
|
 |  |  |
Windows 9X: The system can support a maximum of 16,364 window handles. 15.02.02 15:23
Автор: z0 <z0> Статус: Member
|
|
|
 |  |  |
Там не 2^32, а много меньше 14.02.02 11:10
Автор: ukv Статус: Незарегистрированный пользователь
|
> Допустим одно окно создается за секунду. Тогда > ((2^32)/60)/60 = 1193046 часов, Это 138 лет. Уменьшим > создания окна с секунды. до 10мс, Тогда что бы выбрать все > hwnd нам потребуется всего лишь год.
Не помню точно, но на 2^16 по-моему расчитывать можно, а больше - зависит от системы. Но 2^32 - и близко не будет.
Правильное решение - поставить hook на это окно и отслеживать его закрытие. Еще проще было бы получить нотификацию при закрытии окна, но по-моему нотификации идут только в parent.
|
 |  |  |  |
2^16 14.02.02 11:56
Автор: PS <PS> Статус: Elderman
|
|
Это 18 минут... значит я был прав. А правильно уже не сделаешь... Это огромный проект - фиг перепишишь. Остаеться только плеваться.
|
 |  |  |  |  |
А по-моему хендёл у окна пожизненный 15.02.02 04:20
Автор: Zef <Alloo Zef> Статус: Elderman
|
Во первых: тот же Spy идентифицирует окна хендлами и я еще не замечал, чтобы в процессе жизни они менялись.
Во вторых: цикл обработки сообщений идентифицирует окна-адресаты по хендлам, и эти хендлы - СТАТИК.
В третьих: я где - то (чуть ли не у Питтрека) читал, что 2^16 хендлов - это мало, и я сам, похоже сталкивался с такой ситуацией: если какой-нит сайт начинает сыпать новые окна, как из пулемета - винда падает.
|
 |  |  |
Я не в чем не ошибся ? 14.02.02 01:35
Автор: Sandy <Alexander Stepanov> Статус: Elderman
|
> Допустим одно окно создается за секунду. Тогда > ((2^32)/60)/60 = 1193046 часов, Это 138 лет. Уменьшим > создания окна с секунды. до 10мс, Тогда что бы выбрать все > hwnd нам потребуется всего лишь год. Т.е. через год hwnd > начнут повторяться... что-то многова-то... > Мда... вот что значит спорить не на трезвую голову. Хорошо > хоть не на пиво.... :)
Насколько я помню, хэндл (любой) - это смещение. Т.е., хэндл окна - смещение в таблице, описывающей ВСЕ имеющиеся окна в системе. На мой взгляд, нет ничего невозможного в ситуации, когда РАЗНЫМ окнам, существующим в РАЗНОЕ время, присваивается один и тот же хэндл.
|
|
|