Вот, возник очередной вопрос. Пытаюсь разобраться с дочерними и собственными окнами. Как они между собой общаются, тусуются и т.д. Но попытки создать собственное окно заканчиваются неудачно. Что я делаю: создаю окно с кнопкой. По нажатию на кнопку вызывается функция. В этой функции регистрируется класс собственного окна, и создается собственное окно с кнопкой. По нажатию на кнопку на собств. окне, оно должно закрываться. Проблемы возникают при регистрации класса собственного окна. GetLastError возвратила, что передаются неправильные аргументы. Хотя вроде все аргументы передались те, что нужно. Вот, ниже кусочек кода: Code (Text): mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET AboutProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW+1 ;Системный фон окна (белый) mov wc.lpszMenuName,NULL mov wc.lpszClassName,OFFSET AboutClass invoke RegisterClassEx, addr wc В чем может быть причина? Может ли быть дело в том, что я не заполняю структуру полностью? Но это вроде бы и не обязательно? Остальные параметры тогда будут по умолчанию? Это я В.Пирогова начитался...
структура хранится в локальной или глобальной переменной? если в лоакльной, то никто не гарат\нтирует что она нулями будет заполнена.
IMHO, Пирогов SUXX. Есть у меня книжка его 'Ассемблер для Windows'. Так вот там для начинающих слишком сложно написано. Каждый раз переопределяются константы из windows.inc, параметры функций и локальные переменные зачем-то через ebp, никаких if-while-repeat и т.д. и т.п. Возьми лучше IcZelion'а, есть на русском. По теме - выше обозначено. Дело в том, что если переменная локальная (в теле функции) она инициализируется чем попало.
1. RegisterClassEx - ERROR_INVALID_PARAMETER. Надо до конца проинициализировать wc: Code (Text): mov wc.cbSize, sizeof WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET AboutProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW+1 ;Системный фон окна (белый) mov wc.lpszMenuName,NULL mov wc.lpszClassName,OFFSET AboutClass invoke LoadIcon, 0, IDI_APPLICATION mov wc.hIcon, eax mov wc.hIconSm, eax invoke LoadCursor, 0, IDC_ARROW mov wc.hCursor, eax invoke RegisterClassEx, addr wc Тогда регистрация класса проходит нормально. Но вот засада: 2. CreateWindowEx - ERROR_CANNOT_FIND_WND_CLASS Предпоследний параметр - hInst - хэндл приложения, возвращаемый GetModuleHandle, 0, а не хэндл родительского окна. Так что параметром about должен быть hInstance. 3. Ну и декоративное замечание: при создании второй кнопки надо указать lpszWindowName, а то кнопка пустая.
KeSqueer прав!! Пирогов сакс) Действительно оч сложно для начинаюших, а вот IcZelion'а эт да, эт то, что надо начинаещему кодеру на Асме))
она просто не инициализируется там остается мусор от разных стековых фреймов, данных и адресов возврата. кстати имхо это самое замечательно. когда новичок воткнет как адресуются локальные переменные внутри функции, тогда можно и LOCAL использовать. Но это не сразу!
Прошу прощения, что не отвечал так долго. Были проблемы с компом. Mikl__ Бутусова я очень люблю, но цитатка не совсем точная А если серьезно, то пример этот совершенно абстрагированный, и никакой полезной нагрузки не несет. Просто я пытаюсь освоить некоторые основы программирования. Вот сейчас я пытаюсь разобраться с собственными и дочерними окнами, как они живут и общаются друг с другом. То, что мне ответили за время моего вынужденного отсутствия, помогло мне разобраться с моим вопросом. Особое спасибо JAPH. Также про инициализацию локальных переменных интересный момент. Я раньше этого не знал. В продолжение темы. С регистрацией окон вроде разобрался. Следующий вопрос такой. Та же самая ситуация. Окно с кнопкой. При нажатии на кнопку, создается собственное окно с кнопкой. При нажатии на кнопку во втором окне, второе окно закрывается. Отличие в следующем. Насколько я знаю, на основе зарегистрированного класса можно создавать сколько угодно окон. Так вот, первое и второе окно я создаю на основе одного класса. Соответственно, процедура окна у них будет общая? Только получается заморочка с обработкой нажатия кнопки на втором окне. При нажатии на нее закрываются оба окна, хотя должно закрываться только второе. Code (Text): .IF uMsg == WM_COMMAND mov eax, wParam .IF eax == 0 mov eax,lParam .IF eax == Button1 invoke about,hwnd .ELSEIF eax == hClose ;Если нажата кнопка "Exit", invoke DestroyWindow, hAbout ;то закрыть окно Эбаут .ENDIF .ENDIF Гонял под отладчиком. В функцию DestroyWindow передается хэндл того окна, которое нужно закрыть, но закрываются почему то оба окна. Если послать в функцию хэндлы, например, кнопок, то закрываются кнопки те которые нужно. А с окнами заморочка. На всякий случай цепляю исходник.
С DestroyWindow всё нормально, но смотрите дальше: дочернему окну (hAbout) посылается WM_DESTROY, а там... PostQuitMessage! Вот вам и выход из программы с закрытием всех окон. Обойти можно проверкой, какое окно закрылось: Code (Text): mov eax, hWnd ; окно, которому досталось WM_DESTROY .if eax == hwnd ; только если это главное окно invoke PostQuitMessage, 0 ; то выйти из проги .endif
JAPH ой, а ведь и правда =) И, наверное, последний вопрос в этой теме. Он немного не соответствует названию, но все же спрошу здесь, чтобы не клепать кучу тем. У меня получается так, что при нажатии на кнопку в первом окне, может создаваться хоть сотня собственных окон. Это в принципе понятно, потому что я нигде это не проверяю и не ограничиваю. Но все же хучу сделать так, чтобы создавалось только одно окно. Думаю после создания второго окна сделать первое окно неактивным с помощью SetWindowLong: Code (Text): invoke SetWindowLong,hwnd,GWL_EXSTYLE,WS_EX_NOACTIVATE Чего-то не получается. И вопрос у меня такой: почитав форум, понял, что на каждое свойство окна можно изменять "на лету". Где можно узнать каие свойства меняются "на лету", а какие нет. В MSDN это есть? Я искал но не нашел. Где можно это посмотреть.
Насчёт размножения окон.. Можно делать так: Code (Text): hChild dd 0 .if hChild == 0 invoke CreateWindowEx, ... ;Честно создаём окно mov hChild, eax .else invoke ShowWindow, hChild, SW_SHOWDEFAULT .endif Но только если основное окно одно. Иначе вместо глобальной переменной надо юзать Get/SetWindowLong и хранить hChild в области, резервируемой cbWindowExtra. Насчёт изменения свойств окна - SetWindowLong, hw, GWL_STYLE, value? SetClassLong...?
То, что не находите на MSDN - ищите на wasm.ru. О том, какие меняются, а какие нет - кое-что здесь: CreateWindowEx, особливо пост #30. А чтоб самому проверять "на лету" - вот вам HTSpy
Интересный пример, спасибо. Я делал немного по-другому. Первый способ почти такой же. Я заводил переменную (типа булевской), и в зависимости от присутствия окна выставлял ее в ноль или единицу. А при создании окна проверял ее. И второй способ это использование FindWindow. Так что вопрос о размножении окон можно считать решенным. Но, тем не менее, хотелось бы разобраться с функцией SetWindowLong. В пресловутом MSDN вроде все понятно написано. Но например здесь же на форуме весьма неоднозначно трактуется ее использование. Опять же здесь на форуме прочитал, что может быть необходимо обновить окно после изменения его стилей. Пробовал, не получилось. JAPH Вы написали: SetWindowLong, hw, GWL_STYLE, value? Из прочтения того же форума я понял, что параметром надо передавать точную числовую константу всех новых стилей, а не ее символьный эквивалент, во избежание разночтений? Далее, использование SetClassLong, как я понимаю нужно для изменения класса окна. Это разве необходимо? И опять же, если я создаю два окна на основе одного класса это разве не затронет оба окна?
Каких разночтений? Вообще не въехал, какие символьные эквиваленты? Code (Text): invoke GetWindowLong, hw, GWL_STYLE or eax, WS_HSCROLL or WS_VSCROLL invoke SetWindowLong, hw, GWL_STYLE, eax PS В 13 строке опечатка
kero Да, я как раз эту ветку и имел ввиду. Весьма познавательно, хотя и излишне эмоционально Это я имел ввиду, что вместо допустим WS_EX_NOACTIVATE надо передавать 040000001. Хотя потом понял, что это я уже запутал сам себя. Ну, вроде разобрался. Я передавал WS_EX_NOACTIVATE, а для делания окна неактивным надо было передавать WS_DISABLED/ Сейчас делаю так, и вроде получается. Вот, посмотрите, пожалуйста, насколько это правильно: Code (Text): При создании второго, окна первое делаю неактивным invoke GetWindowLong, hwnd, GWL_STYLE or eax, WS_DISABLED invoke SetWindowLong, hwnd, GWL_STYLE, eax Code (Text): При закрытии второго окна, в обработчике WM_DESTROY, убираю WS_DISABLED invoke GetWindowLong, hwnd, GWL_STYLE xor eax, WS_DISABLED invoke SetWindowLong, hwnd, GWL_STYLE, eax
Я бы написал (чёрт знает почему) Code (Text): and eax, not WS_DISABLED Можно взглянуть на параметры CreateWindowEx создания второго окна? А так вроде правильно делаете. Хотя disabled overlapped window мне лично не нравится Я б лучше кнопку делал disabled. Code (Text): .if ms == WM_DESTROY mov eax, hw .if eax == hwMain invoke PostQuitMessage, 0 .else invoke GetWindowLong, hwMain, GWL_USERDATA push ebx mov ebx, eax invoke ShowWindow, ebx, SW_HIDE invoke GetWindowLong, ebx, GWL_STYLE and eax, not WS_DISABLED invoke SetWindowLong, ebx, GWL_STYLE, eax invoke ShowWindow, ebx, SW_SHOWDEFAULT pop ebx .endif xor eax, eax .elseif ms == WM_COMMAND mov eax, hw .if eax == hwMain invoke GetWindowLong, hw, GWL_USERDATA push ebx mov ebx, eax invoke ShowWindow, ebx, SW_HIDE invoke GetWindowLong, ebx, GWL_STYLE or eax, WS_DISABLED invoke SetWindowLong, ebx, GWL_STYLE, eax invoke ShowWindow, ebx, SW_SHOWDEFAULT pop ebx invoke CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, offset mwcn, offset mwcn, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hw, 0, wcx.hInstance, 0 .else invoke DestroyWindow, hw .endif xor eax, eax .elseif ms == WM_CREATE invoke CreateWindowEx, 0, offset bcn, offset mwcn, WS_CHILD or WS_VISIBLE or BS_PUSHBUTTON, 10, 10, 80, 20, hw, 0, wcx.hInstance, 0 invoke SetWindowLong, hw, GWL_USERDATA, eax xor eax, eax .else invoke DefWindowProc, hw, ms, wp, lp .endif ret
Да, конечно. А что, есть какие-то принципиальные отличия у разных стилей? Code (Text): invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AboutClass, WS_VISIBLE or WS_OVERLAPPEDWINDOW, Aboutx,Abouty,AboutW,AboutH,hInst,NULL,hInstance,NULL Я тоже уже пробовал так делать. Получается, что первое окно можно таскать за заголовок. А если делать ДИЗАЙБЛ всему окну, то оно вообще стоит смирненько себе и не рыпается. Можно, конечно, Но тут уже надо выбирать, наверное, исходя из поставленных целей. Прикрепляю код. Вроде рабочий.
Twister Проинициализировать нулями. А затем ещё и перезаписать нужные значения. Итог всё равно один. Sturgeon Просто я сначала делал второе окно со стилем WS_CHILD и долго удивлялся, как у вас "получается"... Попробуйте
Попробовал Но, тогда, когда мы создаем второе окно и делаем первое DISABLED, получается, что и второе окно (как дочернее) делается неактивным. Или я опять чего-то напортачил?