Есть ли способ переопределить поведение курсора через winapi в VBA?

#excel #vba #winapi

#excel #vba #winapi

Вопрос:

Я хотел бы изменить изображение курсора во время выполнения моего макроса Excel. Мне удалось изменить курсор с помощью этих функций winapi: setCursor и LoadCursorFromFileA.

Вот пример :

 Option Explicit

Declare Function LoadCursorFromFileA Lib "user32" (ByVal lpFileName As String) As Long
Declare Function SetCursor Lib "user32" (ByVal hCursor As Long) As Long

Sub TestCursor()
     Call SetCursor(LoadCursorFromFileA("C:Tempcursor2.cur"))
    ' Waits 5 seconds, any movement of the mouse will revert the cursor back to default
    Application.Wait Now   TimeValue("00:00:05")
    ' Cursor is back to default at the end of the sub
End Sub
  

Однако курсор вернется к значению по умолчанию, если произойдет событие (например, диалоговое окно) или если курсор будет перемещен.

Из этой ссылки кажется, что Excel обновляет курсор при наведении курсора на элементы.

Я нашел решение, но это мешает запуску моего макроса, потому что он использует бесконечный цикл.

Есть ли способ переопределить, как Excel взаимодействует с курсором?

Комментарии:

1. Что вы конкретно пытаетесь сделать? Мне кажется, перехватывать сообщения WM для получения полного контроля над указателем мыши — это вааааай перебор. МНОЖЕСТВО вещей, находящихся вне вашего контроля, отправят сообщения WM в цикл сообщений, чтобы изменить внешний вид курсора. Бесконечный цикл несколько разумен, поскольку альтернатива включает в себя создание подклассов (т. Е. Самостоятельный ввод цикла обмена сообщениями Windows)… это не то, что вы обычно делаете в повседневном коде VBA. «Во время выполнения моего макроса» не очень понятно .. вы пытаетесь изменить курсор на песочные часы? Смотрите Application.Cursor тогда. В противном случае… удачи!

2. Самым простым способом, который я могу выразить: я хотел бы использовать пользовательское изображение для замены курсора во время работы моего макроса (в основном вычисления и форматирование). Мне удалось изменить курсор на пользовательское изображение, но в Excel есть некоторые обновления, возвращающие его к курсору по умолчанию. Я знаю о Application.Cursor , но он не обеспечивает поддержку пользовательских изображений. Я знаю, что это, вероятно, будет излишеством, но на данный момент это просто из любопытства и изучения более сложного способа использования VBA.

3. Хм. Это одна из битв, в которой я бы предпочел не участвовать (в VBA с подклассами довольно сложно), и просто продолжайте Application.Cursor = xlWait во время выполнения макроса. Если курсор нужен вам только для UserForm , рассмотрите возможность настройки MousePointer свойства, как предложено в разделе «использование пользовательского указателя мыши» в этой статье .

Ответ №1:

Это некоторый пример кода подкласса. В Excel Application.hWnd есть hWnd, который вы хотите.

 Public Const WM_SETCURSOR = amp;H20
  

Когда вы получите вышеуказанное сообщение, верните True (-1), чтобы остановить дальнейшие изменения в курсоре.

 gWindowProc = true
  

 Public Sub Hook()
   lpPrevWndProc = SetWindowLong(EditNote.gRtfHwnd, GWL_WNDPROC, _
   AddressOf gWindowProc)
End Sub

Public Sub Unhook()
   Dim temp As Long
   temp = SetWindowLong(EditNote.gRtfHwnd, GWL_WNDPROC, lpPrevWndProc)
End Sub

Public Function gWindowProc(ByVal hwnd As Long, ByVal Msg As Long, _
                 ByVal wParam As Long, ByVal lParam As Long) As Long
   If Msg = WM_CONTEXTMENU Then
        If EditNote.mnuViewEditContextMenu.Checked Then EditNote.PopupMenu EditNote.mnuEdit
'        gWindowProc = CallWindowProc(lpPrevWndProc, hWnd, Msg, wParam, _
         lParam)
   Else ' Send all other messages to the default message handler
      gWindowProc = CallWindowProc(lpPrevWndProc, hwnd, Msg, wParam, _
         lParam)
   End If
End Function
  

Примечания

Слово старшего порядка в lParam равно нулю, когда окно переходит в режим меню. Функция DefWindowProc передает сообщение WM_SETCURSOR в родительское окно перед обработкой. Если родительское окно возвращает значение TRUE, дальнейшая обработка приостанавливается. Передача сообщения в родительское окно window дает родительскому окну контроль над настройками курсора в дочернем окне. Функция DefWindowProc также использует это сообщение для установки курсора в положение стрелки, если его нет в клиентской области, или в положение курсора зарегистрированного класса, если он находится в клиентской области. Если младшим словом параметра lParam является HTERROR, а старшим словом параметра lParam указывается, что нажата одна из кнопок мыши, DefWindowProc вызывает функцию MessageBeep.

MSDN 2001

Комментарии:

1. Спасибо, это очень полезно и почти работает. Это отлично работает, если мой курсор находится над лентой, но если курсор находится над окном (внутренними окнами Excel), курсор вернется к значению по умолчанию. Похоже, что Windows отправляет свое собственное сообщение, и я не могу перехватить его с помощью дескриптора приложения. Я пытался использовать дескриптор окна, но получаю error 438 : object doesn't support this property or method .

2. Смотрите learn.microsoft.com/en-au/windows/desktop/winmsg / … о PeekMessage() работе. Или создайте таймер на 100 мс, который устанавливает курсор.