загрузить пример к статье
Введение
Часто, команды строки
меню могут быть запутаны и непонятны новому
пользователю Вашего приложения. В то время
как стандартные команды Windows, типа File, Open,
или Close знакомы, другие команды могут
казаться непонятными . К счастью, с помощью
subclassing и нескольких функций API, Вы можете
иметь больше возможностей.
Используя эти инструментальные средства, Ваше
приложение может отображать текст
подсказки, когда пользователь выбирает
пункт меню. Например, заголовок текущего
окна или строка состояния могли бы кратко
объяснять выбранный пункт меню. В этой
статье, мы покажем Вам, как создать callback
функцию, чтобы использовать эту
особенность.
Подключение callback функции к
оконной процедуре
Чтобы создать систему
подсказок для строки меню, мы будем
использовать SetWindowLong функцию API. Эта функция API
объявляется следующим образом:
Declare Function SetWindowLong Lib
"user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex
As Long, ByVal dwNewLong As Long) As Long
Чтобы заменить
стандартную оконную процедуру, мы
установим nIndex параметр в GWL_WNDPROC, и dwNewLong к
адресу нашей новой функции. Функция SetWindowLong
возвращает значение типа Long, которое указывает на
предыдущую оконную процедуру. Поскольку
каждое окно имеет только одну оконную
процедуру, которая обрабатывает все
сообщения, посланные ему Windows, то наша новая функция станет
единственной, которая будет их получать и
обрабатывать.
После подключения наша функция
может определит, когда приложению было
послано сообщение WM_MENUSELECT,
которое происходит, когда Вы выбираете
пункт меню. Если это имеет, то функция
отобразит соответствующий текст Help в
заголовке окна. Во всех остальных случаях, процедура передаст сообщения
первоначальной функции обработки
сообщений окна для их обычной обработки.
Это гарантирует, что
все другие операции окна (изменение
размеров, отображение меню, перерисовка
содержимого и т.д.) будут выполнены.
Чтобы обслуживать все остальные сообщения окна, мы
объявим API функцию CallWindowProc.
Единственная цель этой функции состоит в
том, чтобы передать сообщения окну в
указанную процедуру. Эта функция
объявляется следующим образом:
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As
Long, ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal
lParam As Long) As Long
Где lpPrevWndFunc содержит указатель на
предыдущую оконную процедуру. В нашем
случае, мы будем хранить указатель на
первоначальную оконную процедуру,
полученную от SetWindowLong, и затем
передавать это значение указателя в этом
параметре.
Восстановление старой процедуры
Чтобы восстановить первоначальную оконную процедуру
окна, мы
будем еще раз использовать функцию SetWindowLong с установкой GWL_WNDPROC. На сей раз, мы
передадим адрес первоначальной оконной
процедуры в dwNewLong параметре. Теперь, когда
мы описали основные функции API, мы
будем использовать их в нашей работе.
Давайте помещать это все вместе в программу.
Вывод подсказки для строки меню
Для начала создайте новый
проект Visual Basic и сохраните его как Minihelp.
Форму переименуйте в frmCallbacks. Затем, в меню Visual Basic,
выберите Add Module. Когда VB добавит Module1.BAS,
добавьте в него объявления API:
Declare Function SetWindowLong Lib "user32" Alias _
"SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex
_
As Long, ByVal dwNewLong As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias _
"CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam _
As Long, ByVal lParam As Long) As Long
Public Const GWL_WNDPROC = -4
Private Const WM_MENUSELECT = &H11F
Public gWH As Long
Public OldWndProc As Long
Теперь, давайте добавлять
процедуру, которая будет принимать сообщения.
Добавьте в модуль следующий код:
Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As
Long) As Long
On Error Resume Next
Dim X As Long
Dim MenuText(0 To 7) As String
X = CallWindowProc(OldWndProc, hwnd, Msg, wParam, lParam)
Select Case Msg
Case WM_MENUSELECT
MenuText(0) = "This helps catch a big one!"
MenuText(1) = "Help Options"
MenuText(2) = "Operatin a callbacks 'n rod"
MenuText(3) = "Findin a deep API pond"
MenuText(4) = "Creatin a good fish story"
MenuText(5) = "Gettin the proper bait"
MenuText(6) = "Unhook it now that you got it."
MenuText(7) = "Exit the program"
frmCallbacks.Caption = MenuText(LowOrd(wParam))
End Select
WindowProc = X
End Function
Function LowOrd(DbleWord As Long) As Integer
If DbleWord And &H8000& Then
LowOrd = &H8000 Or (DbleWord And &H7FFF&)
Else
LowOrd = DbleWord And &HFFFF&
End If
End Function
Обратите внимание, что там есть также
функция LowOrd, которую мы объясним позже.
Теперь давайте добавим меню. Чтобы
это сделать,
выберите Tools | Menu Editor. Добавьте следующие
пункты в меню:
Caption |
Name |
&Fishin |
mnuFishin |
=>&Operatin |
menuOperatin |
=>F&indin |
mnuFindin |
=>&Creatin |
mnuCreatin |
&Help |
mnuHelp |
=>Help Off |
mnuHelpOff |
&Exitin |
mnuExitin |
Наконец, мы можем добавить код, чтобы
подключить процедуру WindowProc. Добавьте
следующий код к окну кода формы.
Private Sub Form_Load()
gWH = Me.hwnd
OldWndProc = SetWindowLong(gWH, GWL_WNDPROC, _
AddressOf WindowProc)
End Sub
Private Sub mnuExitin_Click()
Unload Me
End Sub
Private Sub mnuHelpOff_Click()
SetWindowLong gWH, GWL_WNDPROC, OldWndProc
End Sub
Private Sub mnuOperatin_Click()
MsgBox "Hook, line, and sinker."
End Sub
Функция callback в
действии
Нажмите [F5], чтобы выполнить
программу и выберите пункт меню Fishin. Когда Вы
это делаете, Windows использует
функцию WindowProc, чтобы обработать сообщение.
Сначала всё происходит как и раньше, затем, как
только входящее сообщение содержит
значение WM_MENUSELECT, функция определяет какой текст
нужно разместить в заголовке.
Всякий раз, когда Windows
обрабатывает WM_MENUSELECT сообщение, wParam
параметр содержит значение, которое
указывает выбранный пункт меню. Функция передает
это значение к функции LowOrd, которая
обрабатывает его и получает реальное
значение, в котором мы нуждаемся. Функция
после использует это значение, чтобы
определить какой текст подсказки нужно
отобразить.
Чтобы закрыть форму
выберите опцию Exitin, или щелкните кнопку Close
формы. Когда Вы делаете, Visual Basic отключает функцию WindowProc от окна и
восстанавливает первоначальную оконную
процедуру.
Заключение
В этой статье, мы
показали Вам, как использовать оператор
AddressOf для создания подкласса окна Windows. Кроме того,
мы показали Вам, как использовать свою callback функцию
для обработки сообщений Windows.