Консультация № 180612
08.11.2010, 02:43
0.00 руб.
0 5 1
Добрый день! Подскажите, как можно обработать нажатие кнопки «Далее >», чтобы появлялось не MessageBox, как у меня сейчас в программе, а такое же зарегистрированное в WinMain proc окно, но с другим заголовком окна и другим текстом вопроса? Кнопка и поле ввода в новом окне остаются прежними. Не знаю, насколько это правильно, но пытался после нажатия кнопки:
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
вызвать второе окно с помощью
INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName2,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,\
540,480,NULL,NULL,hInst,NULL
но компилятору чем-то не понравился хендл программного модуля hInst, мне пришлось ввести переменную MYhInst dd ? и заменить hInst на MYhInst. Потом создавал на новом окне новую кнопку, текст, поле ввода, заголовок. При работе программы получалось почти всё, кроме текста: во втором окне он был таким же, как и в первом. Вдобавок второе окно перекрывало первое, а мне нужно, чтобы было всегда только одно окно: или первое, или второе, но не оба вместе. Вот как переделать эту нижеприведённую программу?


Приложение:
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
ClassName db "SimpleWinClass",0
AppName1 db "Окно № 1",0
AppName2 db "Окно № 2",0 ; заголовок для второго окна
ButtonClassName db "button",0
ButtonText db "Далее >",0
EditClassName db "edit",0
TestString db "Test!",0
String db "Сообщение",0
OurText1 db 10,13," Вопрос №1:",0
OurText2 db 10,13," Вопрос №2:",0 ; текст для второго окна

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?)

.const
ButtonID equ 1
EditID equ 2

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,17
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName1,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,540,480,NULL,NULL,\
hInst,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,50,50,160,25,\
hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
95,95,80,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
invoke GetClientRect,hWnd, ADDR rect
invoke DrawText, hdc,ADDR OurText1,-1, ADDR rect, NULL
invoke EndPaint,hWnd, ADDR ps
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke MessageBox,NULL,ADDR TestString,ADDR String,MB_OK
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start

Обсуждение

давно
Посетитель
7438
7205
08.11.2010, 05:13
общий
это ответ
Здравствуйте, Adsorores!
Вы избрали порочный путь...
1) У Вас текст вопроса рисуется в общей отработке WM_PAINT, поэтому он будет одинаков во всех окнах
2) Если создаете новое окно, то для него надо создавать свою отработку очереди сообщений.
Придется также разграничивать функцию окна...
Это все можно сделать, но зачем идти этим путем, зачем усложнять себе жизнь?!
Гораздо проще работать в одном окне. Просто рисуем новый вопрос и все! В Вашем случае это можно
сделать, например, введя переменную с адресом строки вопроса. И следим, с каким вопросом работаем...

Кстати, переменная hInst действительна только внутри подпрограммы WinMain, Вы же хотели ее использовать внутри WndProc,
что, естественно, является ошибкой. Надо было использовать глобальную переменную hInstance

Код:
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

.data
ClassName db "SimpleWinClass",0
AppName1 db "Окно № 1",0
AppName2 db "Окно № 2",0 ; заголовок для второго окна
ButtonClassName db "button",0
ButtonText db "Далее >",0
EditClassName db "edit",0

OurText dd OurText1, OurText2, OurText3
MAX_IDX equ ($-OurText)/4 - 1

OurText1 db 10,13," Вопрос №1:",0
OurText2 db 10,13," Вопрос №2: ",0 ; текст для второго окна
OurText3 db 10,13," Вопрос №3: ",0 ; текст для третьего окна

TestString db " Программа успешно завершена!",0
String db "End",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?

idxAsk dd ?

buffer db 512 dup(?)

.const
COLOR equ COLOR_BTNSHADOW
ButtonID equ 1
EditID equ 2

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground, COLOR+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc

mov idxAsk, 0

INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName1,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,540,480,NULL,NULL,\
hInst,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT

.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,50,50,160,25,\
hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
95,95,80,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax

invoke SetBkMode, hdc, OPAQUE ;зададим тип замещения старого содержимого :)

invoke GetSysColor, COLOR
invoke SetBkColor, hdc, eax

invoke GetClientRect,hWnd, ADDR rect
mov ecx, idxAsk
invoke DrawText, hdc, OurText[ecx*4], -1, ADDR rect, NULL
invoke EndPaint,hWnd, ADDR ps
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
.IF idxAsk < MAX_IDX
inc idxAsk
invoke InvalidateRect, hWnd, NULL, 0
invoke SetFocus, hwndEdit
.ELSE
invoke MessageBox,NULL,ADDR TestString,ADDR String,MB_OK
invoke SendMessage,hWnd,WM_DESTROY,0,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
08.11.2010, 21:03
общий
Адресаты:
Спасибо за переделку программы!
«Вы избрали порочный путь». Это вынужденно, от незнания. Сначала хотел с помощью диалоговых окон сделать вызов, но во всех примерах, что я видел, в качестве примера диалогового окна вызывается MessageBox, что меня не устраивало, потому и выбрал более трудоёмкий путь: другого не знал.
Постарался в Вашей программе добавить ещё одно, третье по счёту, окно и вызвать его из второго окна. Добавил переменную OurText3 и скопировал ваш код для обработки клавиши, но из окна с первым вопросом вызывается или окно со вторым вопросом, или с третьим, но никак из второго не вызывается третье. Я и .ELSEIF uMsg==WM_COMMAND добавлял, и сохранял wParam в стеке, чтоб потом использовать для третьего окна – не получается вызов третьего окна из второго.
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
mov pAsk, offset OurText2
invoke InvalidateRect, hWnd, NULL, 0
.ENDIF
.ENDIF
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
mov pAsk, offset OurText3
invoke InvalidateRect, hWnd, NULL, 0
.ENDIF
.ENDIF
Ещё вопрос появился, как мне сделать, чтобы текст размещался на общем сером фоне, а не в белом прямоугольнике. Я только знаю, что за этот прямоугольник отвечает переменная rect.
давно
Посетитель
7438
7205
09.11.2010, 04:18
общий
Я немного подправил код программы.
Сравните тексты, чтобы найти все отличия
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
10.11.2010, 04:48
общий
Адресаты:
Всё хорошо, только при замене текста вопросов, когда второй текст меньше первого, то второй текст накладывается на первый.
Вообще-то мне хотелось бы, чтобы каждое последующее окно не повторяло предыдущее не только в тексте, но и частично в дочерних окнах. Не могли бы Вы глянуть программу и исправить ошибки. У меня дочерние окна первого окна накладываются на окна второго окна, первое окно тоже не исчезает. Вместе со вторым окном одновременно появляется MessageBox, который по логике событий должен появиться только после нажатия кнопки второго окна. Текст одинаков, что в первом, что во втором окне. Не знаю, как не рисовать тексты в общей отработке WM_PAINT, вводил переменные hdc2 и rect2, но безрезультатно. Пусть моя программа несколько длиннее Вашей, но мне так пока привычней изучать её, потом все дочерние окна постараюсь оформлить в файле ресурсов.

.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
ClassName db "SimpleWinClass",0
AppName1 db "Первое окно",0
AppName2 db "Второе окно",0
ButtonClassName db "button",0
ButtonText1 db "First Button",0
ButtonText2 db "Second Button",0
EditClassName db "edit",0
TestString db " Программа успешно завершена!",0
String db "End",0
OurText1 db 10,13," Текст 1",0
OurText2 db 10,13 ;Вывод текста с 3-ей строки
db 10,13
db 10,13," Здесь должен текст 2",0
.data?
hInstance HINSTANCE ?
hwndButton HWND ?
hwndEdit1 HWND ?
hwndEdit2 HWND ?
hwndEdit3 HWND ?
buffer db 512 dup(?)
hWnd2 dd ? ; предполагается, что это хэндл 2-го окна
.const
ButtonID equ 1
EditID equ 2

.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,17
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName1,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,\
540,480,NULL,NULL,\
hInst,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
;;; Первый Edit первого окна ;;;;;;;;;;;;;;;;;;;;;
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,50,50,160,25,\
hWnd,EditID,hInstance,NULL
mov hwndEdit1,eax
invoke SetFocus, hwndEdit1
;;; Второй Edit первого окна ;;;;;;;;;;;;;;;;;;;;;;
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,50,85,160,25,\
hWnd,EditID,hInstance,NULL
mov hwndEdit2,eax
;;; Button первого окна ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText1,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
95,120,100,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
;;; Текст в первом окне ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
invoke GetClientRect,hWnd, ADDR rect
invoke DrawText, hdc,ADDR OurText1,-1, ADDR rect, NULL
invoke EndPaint,hWnd, ADDR ps

.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED

;;; ВТОРОЕ ОКНО - hInst заменено на hInstance ;;;;;;
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName2,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,540,480,NULL,NULL,\
hInstance,NULL
mov hWnd2,eax
invoke ShowWindow, hWnd2,SW_SHOWNORMAL
invoke UpdateWindow, hWnd2
;;; Edit второго окна ;;;;;;;;;;;;;;;;;;;;;;;
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,50,160,160,25,\
hWnd2,EditID,hInstance,NULL
mov hwndEdit3,eax
invoke SetFocus, hwndEdit3
;;; Button второго окна ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText2,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,200,100,25,hWnd2,ButtonID,hInstance,NULL
mov hwndButton,eax
;;; Текст во втором окне ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
invoke BeginPaint,hWnd2, ADDR ps
mov hdc,eax
invoke GetClientRect,hWnd, ADDR rect
invoke DrawText, hdc,ADDR OurText2,-1, ADDR rect, NULL
invoke EndPaint,hWnd, ADDR ps
.ENDIF
.ENDIF
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke MessageBox,NULL,ADDR TestString,ADDR String,MB_OK
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
давно
Посетитель
7438
7205
10.11.2010, 10:57
общий
Вы не поняли сути проблемы...
Когда Вы создаете новое окно класса, которому принадлежит другое окно,
то у этих окон автоматически будут одинаковые функции окна, в частности, поэтому у Вас отработка WM_PAINT будет везде выводить первую строку.
Вам следует анализировать номер окна и брать адрес нужной строки. И я не уверен, что это единственная проблема. Слишком все переплетается...

Кроме того, пара BeginPaint и EndPaint работает только в отработке WM_PAINT
Во всех остальных местах следует пользоваться GetDC и ReleaseDC.

Почему Вам не нравится мой вариант? Я подправил, чтобы строка заменяла предыдущую, и сделал выход с MessageBox...
Если длина строки будет одинаковой (дополнить можно пробелами), то все будет, как надо.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа