RegisterClassEx для собственного окна

Тема в разделе "WASM.BEGINNERS", создана пользователем Sturgeon, 20 июл 2007.

  1. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    Вот, возник очередной вопрос.
    Пытаюсь разобраться с дочерними и собственными окнами. Как они между собой общаются, тусуются и т.д. Но попытки создать собственное окно заканчиваются неудачно.
    Что я делаю: создаю окно с кнопкой. По нажатию на кнопку вызывается функция. В этой функции регистрируется класс собственного окна, и создается собственное окно с кнопкой. По нажатию на кнопку на собств. окне, оно должно закрываться.
    Проблемы возникают при регистрации класса собственного окна. GetLastError возвратила, что передаются неправильные аргументы. Хотя вроде все аргументы передались те, что нужно.
    Вот, ниже кусочек кода:

    Код (Text):
    1. mov   wc.style, CS_HREDRAW or CS_VREDRAW
    2.     mov   wc.lpfnWndProc, OFFSET AboutProc
    3.     mov   wc.cbClsExtra,NULL
    4.     mov   wc.cbWndExtra,NULL
    5.     push  hInstance
    6.     pop   wc.hInstance
    7.     mov   wc.hbrBackground,COLOR_WINDOW+1   ;Системный фон окна (белый)
    8.     mov   wc.lpszMenuName,NULL
    9.     mov   wc.lpszClassName,OFFSET AboutClass
    10.     invoke RegisterClassEx, addr wc
    В чем может быть причина?
    Может ли быть дело в том, что я не заполняю структуру полностью? Но это вроде бы и не обязательно? Остальные параметры тогда будут по умолчанию? Это я В.Пирогова начитался...
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    структура хранится в локальной или глобальной переменной?
    если в лоакльной, то никто не гарат\нтирует что она нулями будет заполнена.
     
  3. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    IMHO, Пирогов SUXX. Есть у меня книжка его 'Ассемблер для Windows'. Так вот там для начинающих слишком сложно написано. Каждый раз переопределяются константы из windows.inc, параметры функций и локальные переменные зачем-то через ebp, никаких if-while-repeat и т.д. и т.п. Возьми лучше IcZelion'а, есть на русском.
    По теме - выше обозначено. Дело в том, что если переменная локальная (в теле функции) она инициализируется чем попало.
     
  4. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    1. RegisterClassEx - ERROR_INVALID_PARAMETER.
    Надо до конца проинициализировать wc:
    Код (Text):
    1.     mov wc.cbSize, sizeof WNDCLASSEX
    2.     mov   wc.style, CS_HREDRAW or CS_VREDRAW
    3.     mov   wc.lpfnWndProc, OFFSET AboutProc
    4.     mov   wc.cbClsExtra,NULL
    5.     mov   wc.cbWndExtra,NULL
    6.     push  hInstance
    7.     pop   wc.hInstance
    8.     mov   wc.hbrBackground,COLOR_WINDOW+1   ;Системный фон окна (белый)
    9.     mov   wc.lpszMenuName,NULL
    10.     mov   wc.lpszClassName,OFFSET AboutClass
    11.     invoke  LoadIcon, 0, IDI_APPLICATION
    12.     mov wc.hIcon, eax
    13.     mov wc.hIconSm, eax
    14.     invoke  LoadCursor, 0, IDC_ARROW
    15.     mov wc.hCursor, eax
    16.     invoke RegisterClassEx, addr wc
    Тогда регистрация класса проходит нормально. Но вот засада:
    2. CreateWindowEx - ERROR_CANNOT_FIND_WND_CLASS
    Предпоследний параметр - hInst - хэндл приложения, возвращаемый GetModuleHandle, 0, а не хэндл родительского окна. Так что параметром about должен быть hInstance.
    3. Ну и декоративное замечание: при создании второй кнопки надо указать lpszWindowName, а то кнопка пустая.
     
  5. 6eJIko

    6eJIko New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2007
    Сообщения:
    12
    KeSqueer прав!! Пирогов сакс) Действительно оч сложно для начинаюших, а вот IcZelion'а эт да, эт то, что надо начинаещему кодеру на Асме))
     
  6. Mental_Mirror

    Mental_Mirror New Member

    Публикаций:
    0
    Регистрация:
    7 май 2007
    Сообщения:
    431
    она просто не инициализируется :) там остается мусор от разных стековых фреймов, данных и адресов возврата.

    кстати имхо это самое замечательно. когда новичок воткнет как адресуются локальные переменные внутри функции, тогда можно и LOCAL использовать. Но это не сразу!
     
  7. Mikl_

    Mikl_ New Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2006
    Сообщения:
    907
    Sturgeon
    "Зачем делать сложное из того что проще простого?..." Nau
    Сорц и exe в аттаче:)
     
  8. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    Прошу прощения, что не отвечал так долго. Были проблемы с компом.

    Mikl__
    Бутусова я очень люблю, но цитатка не совсем точная:)
    А если серьезно, то пример этот совершенно абстрагированный, и никакой полезной нагрузки не несет. Просто я пытаюсь освоить некоторые основы программирования. Вот сейчас я пытаюсь разобраться с собственными и дочерними окнами, как они живут и общаются друг с другом.
    То, что мне ответили за время моего вынужденного отсутствия, помогло мне разобраться с моим вопросом. Особое спасибо JAPH. Также про инициализацию локальных переменных интересный момент. Я раньше этого не знал.

    В продолжение темы.
    С регистрацией окон вроде разобрался. Следующий вопрос такой. Та же самая ситуация. Окно с кнопкой. При нажатии на кнопку, создается собственное окно с кнопкой. При нажатии на кнопку во втором окне, второе окно закрывается.
    Отличие в следующем. Насколько я знаю, на основе зарегистрированного класса можно создавать сколько угодно окон. Так вот, первое и второе окно я создаю на основе одного класса. Соответственно, процедура окна у них будет общая? Только получается заморочка с обработкой нажатия кнопки на втором окне. При нажатии на нее закрываются оба окна, хотя должно закрываться только второе.

    Код (Text):
    1.     .IF uMsg == WM_COMMAND 
    2.         mov eax, wParam        
    3.         .IF eax == 0   
    4.                 mov eax,lParam
    5.             .IF eax == Button1
    6.                 invoke about,hwnd
    7.             .ELSEIF eax == hClose                          ;Если нажата кнопка "Exit",
    8.                 invoke DestroyWindow, hAbout      ;то закрыть окно Эбаут
    9.             .ENDIF
    10.         .ENDIF
    Гонял под отладчиком. В функцию DestroyWindow передается хэндл того окна, которое нужно закрыть, но закрываются почему то оба окна. Если послать в функцию хэндлы, например, кнопок, то закрываются кнопки те которые нужно. А с окнами заморочка.
    На всякий случай цепляю исходник.
     
  9. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    С DestroyWindow всё нормально, но смотрите дальше: дочернему окну (hAbout) посылается WM_DESTROY, а там... PostQuitMessage! Вот вам и выход из программы с закрытием всех окон.
    Обойти можно проверкой, какое окно закрылось:
    Код (Text):
    1. mov     eax, hWnd ; окно, которому досталось WM_DESTROY
    2. .if eax == hwnd ; только если это главное окно
    3.        invoke  PostQuitMessage, 0 ; то выйти из проги
    4. .endif
     
  10. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    JAPH ой, а ведь и правда =)

    И, наверное, последний вопрос в этой теме. Он немного не соответствует названию, но все же спрошу здесь, чтобы не клепать кучу тем.
    У меня получается так, что при нажатии на кнопку в первом окне, может создаваться хоть сотня собственных окон. Это в принципе понятно, потому что я нигде это не проверяю и не ограничиваю. Но все же хучу сделать так, чтобы создавалось только одно окно. Думаю после создания второго окна сделать первое окно неактивным с помощью SetWindowLong:

    Код (Text):
    1. invoke SetWindowLong,hwnd,GWL_EXSTYLE,WS_EX_NOACTIVATE
    Чего-то не получается. И вопрос у меня такой: почитав форум, понял, что на каждое свойство окна можно изменять "на лету". Где можно узнать каие свойства меняются "на лету", а какие нет. В MSDN это есть? Я искал но не нашел. Где можно это посмотреть.
     
  11. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Насчёт размножения окон.. Можно делать так:
    Код (Text):
    1. hChild dd 0
    2.  
    3. .if hChild == 0
    4.     invoke CreateWindowEx, ...  ;Честно создаём окно
    5.     mov hChild, eax
    6. .else
    7.     invoke ShowWindow, hChild, SW_SHOWDEFAULT
    8. .endif
    Но только если основное окно одно. Иначе вместо глобальной переменной надо юзать Get/SetWindowLong и хранить hChild в области, резервируемой cbWindowExtra.
    Насчёт изменения свойств окна - SetWindowLong, hw, GWL_STYLE, value? SetClassLong...?
     
  12. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    То, что не находите на MSDN - ищите на wasm.ru.

    О том, какие меняются, а какие нет - кое-что здесь: CreateWindowEx, особливо пост #30.
    А чтоб самому проверять "на лету" - вот вам HTSpy
     
  13. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    Интересный пример, спасибо.
    Я делал немного по-другому.
    Первый способ почти такой же. Я заводил переменную (типа булевской), и в зависимости от присутствия окна выставлял ее в ноль или единицу. А при создании окна проверял ее. И второй способ это использование FindWindow. Так что вопрос о размножении окон можно считать решенным.
    Но, тем не менее, хотелось бы разобраться с функцией SetWindowLong. В пресловутом MSDN вроде все понятно написано. Но например здесь же на форуме весьма неоднозначно трактуется ее использование. Опять же здесь на форуме прочитал, что может быть необходимо обновить окно после изменения его стилей. Пробовал, не получилось.
    JAPH
    Вы написали:
    SetWindowLong, hw, GWL_STYLE, value?
    Из прочтения того же форума я понял, что параметром надо передавать точную числовую константу всех новых стилей, а не ее символьный эквивалент, во избежание разночтений?
    Далее, использование SetClassLong, как я понимаю нужно для изменения класса окна. Это разве необходимо? И опять же, если я создаю два окна на основе одного класса это разве не затронет оба окна?
     
  14. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Каких разночтений? Вообще не въехал, какие символьные эквиваленты?
    Код (Text):
    1. invoke  GetWindowLong, hw, GWL_STYLE
    2. or      eax, WS_HSCROLL or WS_VSCROLL
    3. invoke  SetWindowLong, hw, GWL_STYLE, eax
    PS
    В 13 строке опечатка :)
     
  15. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    kero
    Да, я как раз эту ветку и имел ввиду. Весьма познавательно, хотя и излишне эмоционально:)

    Это я имел ввиду, что вместо допустим WS_EX_NOACTIVATE надо передавать 040000001. Хотя потом понял, что это я уже запутал сам себя.
    Ну, вроде разобрался. Я передавал WS_EX_NOACTIVATE, а для делания окна неактивным надо было передавать WS_DISABLED/
    Сейчас делаю так, и вроде получается. Вот, посмотрите, пожалуйста, насколько это правильно:

    Код (Text):
    1. При создании второго, окна первое делаю неактивным
    2. invoke  GetWindowLong, hwnd, GWL_STYLE
    3. or      eax, WS_DISABLED
    4. invoke  SetWindowLong, hwnd, GWL_STYLE, eax
    Код (Text):
    1. При закрытии второго окна, в обработчике WM_DESTROY, убираю WS_DISABLED
    2. invoke  GetWindowLong, hwnd, GWL_STYLE
    3. xor      eax, WS_DISABLED
    4. invoke  SetWindowLong, hwnd, GWL_STYLE, eax
     
  16. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Я бы написал (чёрт знает почему)
    Код (Text):
    1. and eax, not WS_DISABLED
    Можно взглянуть на параметры CreateWindowEx создания второго окна?

    А так вроде правильно делаете. Хотя disabled overlapped window мне лично не нравится :) Я б лучше кнопку делал disabled.
    Код (Text):
    1. .if ms == WM_DESTROY
    2.     mov eax, hw
    3.     .if eax == hwMain
    4.         invoke  PostQuitMessage, 0
    5.     .else
    6.         invoke  GetWindowLong, hwMain, GWL_USERDATA
    7.         push    ebx
    8.         mov ebx, eax
    9.         invoke  ShowWindow, ebx, SW_HIDE
    10.         invoke  GetWindowLong, ebx, GWL_STYLE
    11.         and eax, not WS_DISABLED
    12.         invoke  SetWindowLong, ebx, GWL_STYLE, eax
    13.         invoke  ShowWindow, ebx, SW_SHOWDEFAULT
    14.         pop ebx
    15.     .endif
    16.     xor eax, eax
    17. .elseif ms == WM_COMMAND
    18.     mov eax, hw
    19.     .if eax == hwMain
    20.         invoke  GetWindowLong, hw, GWL_USERDATA
    21.         push    ebx
    22.         mov ebx, eax
    23.         invoke  ShowWindow, ebx, SW_HIDE
    24.         invoke  GetWindowLong, ebx, GWL_STYLE
    25.         or  eax, WS_DISABLED
    26.         invoke  SetWindowLong, ebx, GWL_STYLE, eax
    27.         invoke  ShowWindow, ebx, SW_SHOWDEFAULT
    28.         pop ebx
    29.         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
    30.     .else
    31.         invoke  DestroyWindow, hw
    32.     .endif
    33.     xor eax, eax
    34. .elseif ms == WM_CREATE
    35.     invoke  CreateWindowEx, 0, offset bcn, offset mwcn, WS_CHILD or WS_VISIBLE or BS_PUSHBUTTON, 10, 10, 80, 20, hw, 0, wcx.hInstance, 0
    36.     invoke  SetWindowLong, hw, GWL_USERDATA, eax
    37.     xor eax, eax
    38. .else
    39.     invoke  DefWindowProc, hw, ms, wp, lp
    40. .endif
    41. ret
     
  17. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    Да, конечно. А что, есть какие-то принципиальные отличия у разных стилей?

    Код (Text):
    1.     invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AboutClass,
    2.                           WS_VISIBLE or WS_OVERLAPPEDWINDOW,
    3.                           Aboutx,Abouty,AboutW,AboutH,hInst,NULL,hInstance,NULL
    Я тоже уже пробовал так делать. Получается, что первое окно можно таскать за заголовок. А если делать ДИЗАЙБЛ всему окну, то оно вообще стоит смирненько себе и не рыпается. Можно, конечно, Но тут уже надо выбирать, наверное, исходя из поставленных целей.
    Прикрепляю код. Вроде рабочий.
     
  18. Twister

    Twister New Member

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    720
    Адрес:
    Алматы
    Заметочка:
    JAPH
    Нет, не надо. Ее перед заполнением необходимо просто "обнулить" (RtlZeroMemory)
     
  19. JAPH

    JAPH New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2007
    Сообщения:
    124
    Twister
    Проинициализировать нулями. А затем ещё и перезаписать нужные значения. Итог всё равно один.

    Sturgeon
    Просто я сначала делал второе окно со стилем WS_CHILD и долго удивлялся, как у вас "получается"... Попробуйте :)
     
  20. Sturgeon

    Sturgeon New Member

    Публикаций:
    0
    Регистрация:
    17 окт 2006
    Сообщения:
    111
    Попробовал:)
    Но, тогда, когда мы создаем второе окно и делаем первое DISABLED, получается, что и второе окно (как дочернее) делается неактивным.
    Или я опять чего-то напортачил?