Глава 5. Разрешение некоторых проблем программирования в Windows
Признаться, данная глава стала для меня некоторым компромиссом. Вопросов программирования в Windows еще так много, что не хотелось бы их опускать. А если писать на каждый вопрос целую главу - книга станет непомерно большой. И я решил отвести на все оставшееся (но далеко не все, однако) одну главу, где постараюсь, насколько это возможно, подробно осветить ряд интересных вопросов. Глава будет построена в виде вопросов гипотетического собеседника и ответов на них Вашего покорного слуги. Итак, приступим.
I
В. Как сделать так, чтобы при минимизации окна значок его помещался бы на системную панель?
Эта проблема решается с использованием системной функции
Shell_NotifyIcon
. Причем решение это столь просто и прозрачно, что
приходится удивляться тому, что большинство для этих целей привлекают какие-то
библиотеки. Вот параметры этой функции:
- 1-й параметр. Действие, которое необходимо произвести:
NIM_ADD equ 0h
; добавить иконку на системную панельNIM_MODIFY equ 1h
; удалить иконкуNIM_DELETE equ 2h
; модифицировать иконку
- 2-й параметр. Указатель на структуру, где содержится информация, необходимая
для реализации указанного действия.
NOTI_ICON STRUC cbSize DWORD ? hWnd DWORD ? uID DWORD ? uFlags DWORD ? uCallbackMessage DWORD ? hIcon DWORD ? szTip DB 64 DUP (?) NOTI_ICON ENDS
cbSize
- размер структуры.hWnd
— дескриптор окна, куда будет посылаться сообщение (см. ниже)uID
- идентификатор иконкиuFlags
- комбинация следующих флаговNIF_MESSAGE equ 1h
; использовать полеhIcon
NIF_ICON equ 2h
; использовать полеuCallbackMessage
NIF_TIP equ 4h
; использовать полеszTip
uCallbackMessage
- сообщение, которое приходит на окно, определяемое дескрипторомhWnd
, в случае возникновения некого события вблизи иконки на системной панели. Значение сообщения должно быть больше, чем 1024. При приходе этого сообщенияWPARAM
содержит идентификатор иконки, aLPARAM
- событие, т.е. то, что произошло с иконкой.hIcon
- дескриптор иконки.szTip
- текст всплывающей подсказки.
Давайте рассмотрим, как работает весь механизм. В случае минимизации окна на
функцию окна приходит сообщение WM_SIZE
. Причем wParam
должен содержать значение SIZE_MINIMIZED
. Вот тогда то и следует
воспользоваться функцией Shell_NotifyIcon
, которая поместит иконку
на системную панель. Любые же события с мышью, когда ее курсор находится на
иконке, вызовут приход на функцию окна сообщения uCallbackMessage
,
которое, естественно, мы сами и определи. При этом младшее слово
wParam
будет содержать идентификатор иконки, а по младшему слову
lParam
можно определить, что же приключилось (см. ниже). Ниже (Рис.
3.5.1) Вы увидите, как все это работает.
// файл tray.rc // определение констант #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x0001OOOOL #define DS_3DLOOK 0x0004L // идентификаторы #define IDI_ICON1 1 // определили иконку IDI_ICON1 ICON "ico1.ico" //определение диалогового окна DIAL1 DIALOG 0, 0, 250, 110 STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK CAPTION "Поместить иконку на системную панель" FONT 8, "Arial" { } ; файл tray.inc ; константы NIM_ADD equ 0h ; добавить иконку на системную панель NIM_MODIFY equ 1h ; удалить иконку NIM_DELETE equ 2h ; модифицировать иконку NIF_MESSAGE equ 1h ; использовать поле hIcon NIF_ICON equ 2h ; использовать поле uCallbackMessage NIF_TIP equ 4h ; использовать поле szTip FLAG equ NIF_MESSAGE or NIF_ICON or NIF_TIP SIZE_MINIMIZED equ 1h SW_HIDE equ 0 SW_SHOWNORMAL equ 1 ; сообщение приходит при закрытии окна WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_SIZE equ 5h WM_LBUTTONDBLCLK equ 203h WM_LBUTTONDOWN equ 201h ; прототипы внешних процедур IFDEF MASM EXTERN ShowWindow@8:NEAR EXTERN LoadIconA@8:NEAR EXTERN lstrcpy@8:NEAR EXTERN Shell_NotifyIconA@8:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN EndDialog@8:NEAR EXTERN SendDlgItemMessageA@20:NEAR ELSE EXTERN ShowWindow:NEAR EXTERN LoadIconA:NEAR EXTERN lstrcpy:NEAR EXTERN Shell_NotifyIconA:NEAR EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN SendDlgItemMessageA:NEAR ShowWindow@8 = ShowWindow LoadIconA@8 = LoadIconA lstrcpy@8 = lstrcpy Shell_NotifyIconA@8 = Shell_NotifyIconA ExitProcess@4 = ExitProcess GetModuleHandleA@4 = GetModuleHandleA DialogBoxParamA@20 = DialogBoxParamA EndDialog@8 = EndDialog SendDlgItemMessageA@20 = SendDlgItemMessageA ENDIF ; структуры ; структура сообщения MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS ; структура для функции Shell_NotifyIcon NOTI_ICON STRUC cbSize DWORD ? hWnd DWORD ? uID DWORD ? uFlags DWORD ? uCallbackMessage DWORD ? hIcon DWORD ? szTip DB 64 DUP (?) NOTI_ICON ENDS ; файл tray.asm .386P ; плоская модель .MODEL FLAT, stdcall include tray.inc ; директивы компоновщику для подключения библиотек IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\shell32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;————————----------------------------------------- ; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' MSG MSGSTRUCT <?> HINST DD 0 ; дескриптор приложения PA DB "DIAL1",0 NOTI NOTI_ICON <0> TIP DB "Пример использования функции" DB "Shell_NotifyIcon",0 _DATA ENDS;сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; получить дескриптор приложения PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX ;-------------------------------------- PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 CMP EAX,-1 JNE KOL ; сообщение об ошибке KOL: ;-------------------------------------- PUSH 0 CALL ExitProcess@4 ;-------------------------------------- ; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10Н] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP,ESP PUSH EBX PUSH ESI PUSH EDI ;--------------- CMP DWORD PTR [EBP+0CH],WM_CLOSE JNE L1 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH],WM_INITDIALOG JNE L2 JMP FINISH L2: CMP DWORD PTR [EBP+0CH],WM_SIZE JNE L3 CMP DWORD PTR [EBP+10H],SIZE_MINIMIZED JNE L3 ; здесь работа по установке иконки на системную панель MOV NOTI.cbSize,88 MOV EAX,DWORD PTR [EBP+8H] MOV NOTI.hWnd,EAX MOV NOTI.uFlags,FLAG MOV NOTI.uID,12 ; идентификатор иконки MOV NOTI.uCallbackMessage,2000 ; сообщение ; загрузить иконку из ресурсов PUSH 1 PUSH [HINST] CALL LoadIconA@8 ; скопировать текст всплывающего сообщения MOV NOTI.hIcon,EAX PUSH OFFSET TIP PUSH OFFSET NOTI.szTip CALL lstrcpy@8 ; поместить иконку PUSH OFFSET NOTI PUSH NIM_ADD CALL Shell_NotifyIconA@8 ; спрятать минимизированное окно PUSH SW_HIDE PUSH DWORD PTR [EBP+08H] CALL ShowWindow@8 JMP FINISH L3: ; сообщение от иконки на системной панели? CMP DWORD PTR [EBP+0CH],2000 JNE FINISH ; идентификатор нашей иконки? CMP WORD PTR [EBP+10H],12 JNE FINISH ; что произошло? двойной щелчок? CMP WORD PTR [EBP+14H],WM_LBUTTONDBLCLK JNE FINISH ; заполнить структуру MOV NOTI.cbSize,88 MOV EAX,DWORD PTR [EBP+8H] MOV NOTI.hWnd,EAX MOV NOTI.uFlags,NIF_ICON MOV NOTI.uID,12 ; идентификатор иконки MOV NOTI.uCallbackMessage,1000 ; сообщение ; удалить иконку PUSH OFFSET NOTI PUSH NIM_DELETE CALL Shell_NotifyIconA@8 ; восстановить окно PUSH SW_SHOWNORMAL PUSH DWORD PTR [EBP+08H] CALL ShowWindow@8 FINISH: MOV EAX,0 POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP _TEXT ENDS END START
Рис. 3.5.1. Демонстрация процедуры помещения иконки на системную панель.